#define BLYNK_TEMPLATE_ID "TMPL68t2zp8yi"
#define BLYNK_TEMPLATE_NAME "GasFireSystem"
#define BLYNK_AUTH_TOKEN "IxwWWVL9SY4wQbcH60ybRCGlqEoC5WP8"
#include <WiFi.h>
#include <BlynkSimpleEsp32.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include "DHT.h"
#include <WiFiClientSecure.h>
// ===== TELEGRAM =====
WiFiClientSecure client;
String BOT_TOKEN = "8268103058:AAEBDAIBv2g2-DBXGJChE-WAkwMVpdGUTls";
String CHAT_ID = "6054055103";
// encode URL (fix lỗi xuống dòng + dấu cách)
String urlEncode(String str) {
String encoded = "";
char c;
char code0;
char code1;
for (int i = 0; i < str.length(); i++) {
c = str.charAt(i);
if (isalnum(c)) {
encoded += c;
} else {
code1 = (c & 0xf) + '0';
if ((c & 0xf) > 9) code1 = (c & 0xf) - 10 + 'A';
c = (c >> 4) & 0xf;
code0 = c + '0';
if (c > 9) code0 = c - 10 + 'A';
encoded += '%';
encoded += code0;
encoded += code1;
}
}
return encoded;
}
void sendTelegram(String message) {
client.setInsecure();
if (!client.connect("api.telegram.org", 443)) {
Serial.println("Telegram connect fail");
return;
}
String url = "/bot" + BOT_TOKEN + "/sendMessage?chat_id=" + CHAT_ID +
"&text=" + urlEncode(message);
client.print(String("GET ") + url + " HTTP/1.1\r\n" +
"Host: api.telegram.org\r\n" +
"Connection: close\r\n\r\n");
Serial.println("Telegram sent!");
client.stop();
}
// =====================
char ssid[] = "Wokwi-GUEST";
char pass[] = "";
#define DHTPIN 2
#define DHTTYPE DHT22
#define MQ2_PIN 1
#define BUZZER 3
#define LED 4
#define BUTTON 5
DHT dht(DHTPIN, DHTTYPE);
LiquidCrystal_I2C lcd(0x27, 20, 4);
bool alarmLatched = false;
float gasBaseline = 0;
unsigned long lastBeep = 0;
unsigned long lastBlink = 0;
bool toneState = false;
bool ledState = false;
bool muted = false;
float lastGas = 0;
// ===== AI =====
float predictAI(float gas, float temp, float hum) {
float z = 1.6284756 * gas
+ (-0.04628921 * temp)
+ (-0.51844626 * (hum / 100.0))
+ (-0.11581632);
return 1.0 / (1.0 + exp(-z));
}
// ===== NÚT APP =====
BLYNK_WRITE(V3) {
if (param.asInt() == 1) {
muted = true;
alarmLatched = false;
noTone(BUZZER);
digitalWrite(LED, LOW);
}
}
void setup() {
Serial.begin(115200);
pinMode(BUZZER, OUTPUT);
pinMode(LED, OUTPUT);
pinMode(BUTTON, INPUT_PULLUP);
digitalWrite(LED, LOW);
Wire.begin(8, 9);
lcd.init();
lcd.backlight();
dht.begin();
Blynk.begin(BLYNK_AUTH_TOKEN, ssid, pass);
lcd.setCursor(0, 0);
lcd.print("Calibrating...");
for (int i = 0; i < 50; i++) {
gasBaseline += analogRead(MQ2_PIN);
delay(20);
}
gasBaseline /= 50.0;
lcd.clear();
lcd.print("SYSTEM READY");
delay(1000);
lcd.clear();
}
void loop() {
// ===== ƯU TIÊN NÚT CAO NHẤT (KHÔNG DELAY) =====
if (digitalRead(BUTTON) == LOW) {
muted = true;
alarmLatched = false;
noTone(BUZZER);
digitalWrite(LED, LOW);
lcd.setCursor(0, 2);
lcd.print("MUTED ");
while (digitalRead(BUTTON) == LOW); // đợi nhả nút
return;
}
Blynk.run();
float temp = dht.readTemperature();
float humidity = dht.readHumidity();
int adc = analogRead(MQ2_PIN);
float gasValue = adc - gasBaseline;
if (gasValue < 0) gasValue = 0;
float gasScaled = gasValue / 200.0;
if (isnan(temp) || isnan(humidity)) return;
float prob = predictAI(gasScaled, temp, humidity);
bool isFire = (prob > 0.6 && gasValue > 80);
// ===== RE-ARM KHI GAS THAY ĐỔI =====
if (abs(gasValue - lastGas) > 20) {
muted = false;
}
lastGas = gasValue;
// ===== LOGIC CHÁY =====
static unsigned long lastSend = 0;
if (isFire && !muted) {
alarmLatched = true;
if (millis() - lastSend > 10000) {
lastSend = millis();
Blynk.logEvent("fire_alert", "Gas Leak Detected!");
String msg = "FIRE ALERT | Gas=" + String(gasValue) +
" Temp=" + String(temp) +
" Hum=" + String(humidity);
sendTelegram(msg);
}
} else if (!isFire) {
alarmLatched = false;
}
// ===== BLYNK =====
Blynk.virtualWrite(V0, temp);
Blynk.virtualWrite(V1, gasValue);
Blynk.virtualWrite(V2, prob);
Blynk.virtualWrite(V4, humidity);
Blynk.virtualWrite(V5, alarmLatched ? "FIRE" : "SAFE");
Blynk.virtualWrite(V6, alarmLatched);
// ===== LCD =====
lcd.setCursor(0, 0);
lcd.print("T:");
lcd.print(temp, 1);
lcd.print("C H:");
lcd.print(humidity, 0);
lcd.print("% ");
lcd.setCursor(0, 1);
lcd.print("Gas:");
lcd.print(gasValue, 0);
lcd.print(" ");
lcd.setCursor(0, 2);
if (muted) lcd.print("MUTED ");
else lcd.print(alarmLatched ? "!!! FIRE ALERT !!!" : "AI: SAFE ");
lcd.setCursor(0, 3);
lcd.print("P:");
lcd.print(prob, 2);
lcd.print(" ");
// ===== CÒI + LED =====
if (alarmLatched && !muted) {
if (millis() - lastBeep > 200) {
lastBeep = millis();
toneState = !toneState;
tone(BUZZER, toneState ? 1000 : 2000);
}
if (millis() - lastBlink > 500) {
lastBlink = millis();
ledState = !ledState;
digitalWrite(LED, ledState);
}
} else {
noTone(BUZZER);
digitalWrite(LED, LOW);
}
}