Які часи такі і поробки! В зв'язку з відсутністю опалення і світла через москальські обстріли нашої енергетики, мої батьки вимушені були придбати газовий обігрівач, щоб хоч якось зігрітися цієї зими. Тож я вирішив зробити декілька пристроїв: це детектор чадного газу (CO) та сенсор витоку газу, про останній сьогодні ми і поговоримо.
Тож нижче ви знайдете перелік всіх використаних компонентів та детальну схему підключення.
Список компонентів:
- Мікроконтролер ESP32 C3 super mini
- Детектор пропан/бутан MQ-6
- 0.93" oled дисплей
- UPS 5v модуль
- Акумулятор. Я особисто замовляв на Nkon 21700, але треба чекати пару тижнів. Якщо треба на вже, то можна пошукати на olx, там є і нові і вживані
- Пищалка
- Перемикач
- Червоний діод
- Резистор 330Ом
- Кнопка без статуса
- конектор dc5525 вихід
- конектор dc5525 вхід
- Корпус
- Дріт використовував від мережевого кабелю (звита пара)
Схема підключення

Програмний код
main.cpp for PlatformIO
#include
#include
#include
#include
#include "esp_bt.h"
// --- PINS (ESP32-C3 Super Mini) ---
#define PIN_MQ6_ANALOG 3
#define PIN_BUZZER 5
#define PIN_LED_RED 6
#define PIN_MUTE_BTN 10
// I2C Pins
#define OLED_SDA 8
#define OLED_SCL 9
// --- SETTINGS ---
#define GAS_THRESHOLD 1500
#define SCREEN_TIMEOUT 30000 // 30 Seconds until sleep
#define BLINK_SPEED 500
#define BUZZER_FREQ 4000 // Your tuned frequency
// --- DISPLAY DRIVER ---
U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C display(U8G2_R0, U8X8_PIN_NONE);
// --- VARIABLES ---
int valGas = 0;
bool isMuted = false;
bool alarmActive = false;
bool isScreenOn = true;
unsigned long lastInteraction = 0; // Tracks last button press or alarm
unsigned long lastBlinkTime = 0;
bool ledState = LOW;
void setup() {
// 1. Power Saving
WiFi.mode(WIFI_OFF);
btStop();
setCpuFrequencyMhz(80);
// 2. Pins
pinMode(PIN_LED_RED, OUTPUT);
pinMode(PIN_BUZZER, OUTPUT);
pinMode(PIN_MQ6_ANALOG, INPUT);
pinMode(PIN_MUTE_BTN, INPUT_PULLUP);
digitalWrite(PIN_LED_RED, LOW);
// 3. I2C Force
Wire.begin(OLED_SDA, OLED_SCL);
// 4. Display Start
display.setI2CAddress(0x3C * 2);
display.begin();
display.setContrast(255);
// Warmup
display.clearBuffer();
display.setFont(u8g2_font_helvB10_tr);
display.drawStr(5, 20, "Sensor Warmup");
display.sendBuffer();
delay(1000);
lastInteraction = millis(); // Reset timer
}
// --- LOGIC ---
void handleLed(bool isDanger) {
if (isDanger) {
if (millis() - lastBlinkTime >= BLINK_SPEED) {
lastBlinkTime = millis();
ledState = !ledState;
digitalWrite(PIN_LED_RED, ledState);
}
} else {
digitalWrite(PIN_LED_RED, LOW);
ledState = LOW;
}
}
void managePowerAndMute(bool isDanger) {
// 1. Check Button
if (digitalRead(PIN_MUTE_BTN) == LOW) {
lastInteraction = millis(); // Reset sleep timer
// If we are in danger, this button mutes the sound
if (isDanger) {
isMuted = true;
}
// If screen was off, just waking it up is enough (debounce)
delay(200);
}
// 2. Decide: Sleep or Wake?
// Stay Awake if: Danger OR (Time since last interaction < 30s)
bool shouldBeOn = isDanger || (millis() - lastInteraction < SCREEN_TIMEOUT);
if (shouldBeOn) {
if (!isScreenOn) {
display.setPowerSave(0); // Wake up
isScreenOn = true;
}
} else {
if (isScreenOn) {
display.setPowerSave(1); // Sleep (Screen goes black)
isScreenOn = false;
}
}
}
void handleSound(bool isDanger) {
if (!isDanger || isMuted) {
ledcDetachPin(PIN_BUZZER);
pinMode(PIN_BUZZER, OUTPUT);
digitalWrite(PIN_BUZZER, LOW);
return;
}
// Pulsing Alarm
if ((millis() / 500) % 2 == 0) {
if (!ledcRead(0)) {
ledcSetup(0, BUZZER_FREQ, 8);
ledcAttachPin(PIN_BUZZER, 0);
}
ledcWriteTone(0, BUZZER_FREQ);
} else {
ledcWriteTone(0, 0);
}
}
void drawScreen(int gasValue, bool isDanger) {
if (!isScreenOn) return;
display.clearBuffer();
if (isDanger) {
// --- DANGER UI ---
display.setFont(u8g2_font_helvB10_te);
display.drawStr(25, 12, "! DANGER !");
display.setFont(u8g2_font_logisoso16_tf);
display.setCursor(45, 32);
display.print(gasValue);
display.drawFrame(0, 0, 128, 32);
}
else {
// --- SAFE UI (SIDE-BY-SIDE) ---
// 1. The Label (Small, on the Left)
// Centered vertically around the middle
display.setFont(u8g2_font_helvB10_tf);
display.drawStr(0, 20, "GAS");
// 2. The Value (HUGE, on the Right)
// We use your preferred Size 24 font
display.setFont(u8g2_font_logisoso24_tf);
// Adjust X (35) based on how wide your number is
display.setCursor(35, 32);
display.print(gasValue);
// 3. The Checkmark (Far Right)
// We make it a bit smaller or move it to fit
display.setFont(u8g2_font_open_iconic_check_2x_t);
display.drawGlyph(110, 24, 64);
}
if (isMuted && isDanger) {
display.setFont(u8g2_font_open_iconic_embedded_1x_t);
display.drawGlyph(0, 32, 74);
}
display.sendBuffer();
}
void loop() {
valGas = analogRead(PIN_MQ6_ANALOG);
if (valGas > GAS_THRESHOLD) {
alarmActive = true;
} else {
alarmActive = false;
isMuted = false;
}
managePowerAndMute(alarmActive);
handleLed(alarmActive);
handleSound(alarmActive);
drawScreen(valGas, alarmActive);
delay(50);
}
Відео на youtube
Підтримка
