#include <WiFi.h>
#include <PubSubClient.h>
#include <LiquidCrystal_I2C.h>
#include "DHT.h"
#include <HTTPClient.h>
// ===================
// WIFI SETTINGS
// ===================
const char* WIFI_SSID = "Wokwi-GUEST";
const char* WIFI_PASS = "";
// ===================
// MQTT SETTINGS
// ===================
const char* MQTT_BROKER = "test.mosquitto.org";
const int MQTT_PORT = 1883;
// MQTT Topics
const char* MQTT_ALERT = "home/security/alert";
const char* MQTT_RESET = "home/security/reset";
const char* MQTT_TEMP = "home/security/temperature";
const char* MQTT_HUM = "home/security/humidity";
const char* MQTT_ARM = "home/security/arm";
const char* MQTT_DISARM = "home/security/disarm";
// ===================
// TELEGRAM BOT
// ===================
String TELEGRAM_TOKEN = "8084100234:AAH1BqrTHzB9Qufmsc3VKp4XDjtqoZuy9iE";
String TELEGRAM_CHAT_ID = "5704271859";
// ===================
// PIN DEFINITIONS
// ===================
#define PIR_PIN 15
#define BUZZER_PIN 13
#define LED_RED 27
#define LED_GREEN 26
#define LDR_PIN 34
#define LIGHT_LED 25
// DHT22
#define DHTPIN 4
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);
// ===================
// LCD
// ===================
LiquidCrystal_I2C lcd(0x27, 16, 2);
// ===================
// GLOBALS
// ===================
WiFiClient espClient;
PubSubClient client(espClient);
bool alarmActive = false;
bool tempAlarmActive = false;
bool systemArmed = false;
bool pirReady = false;
unsigned long pirStartTime;
float TEMP_LIMIT = 28.0; // ✅ Lowered so Wokwi can trigger temp alert
// ===================
// LCD Flicker Fix
// ===================
String lastLCD1 = "";
String lastLCD2 = "";
void lcdUpdate(String l1, String l2 = "") {
if (l1 != lastLCD1 || l2 != lastLCD2) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(l1);
lcd.setCursor(0, 1);
lcd.print(l2);
lastLCD1 = l1;
lastLCD2 = l2;
}
}
// ===================
// TELEGRAM ALERT (with URL encoding fix)
// ===================
void sendTelegram(String message) {
if (WiFi.status() == WL_CONNECTED) {
HTTPClient http;
// ✅ Encode special characters
message.replace(" ", "%20");
message.replace("!", "%21");
message.replace("🔥", "%F0%9F%94%A5");
String url = "https://api.telegram.org/bot" + TELEGRAM_TOKEN +
"/sendMessage?chat_id=" + TELEGRAM_CHAT_ID +
"&text=" + message;
http.begin(url);
http.GET();
http.end();
}
}
// ===================
// MQTT CALLBACK
// ===================
void mqttCallback(char* topic, byte* payload, unsigned int length) {
String cmd;
for (int i = 0; i < length; i++) cmd += (char)payload[i];
cmd.trim();
cmd.toLowerCase();
String t = String(topic);
// RESET
if (t == MQTT_RESET && cmd == "reset") {
alarmActive = false;
tempAlarmActive = false;
noTone(BUZZER_PIN);
digitalWrite(LED_RED, LOW);
client.publish(MQTT_ALERT, "System Reset");
sendTelegram("System%20RESET");
lcdUpdate("System Reset");
delay(1500);
lcdUpdate(systemArmed ? "System Armed" : "System Disarmed");
}
// ARM
else if (t == MQTT_ARM && cmd == "arm") {
systemArmed = true;
alarmActive = false;
tempAlarmActive = false;
noTone(BUZZER_PIN);
digitalWrite(LED_RED, LOW);
client.publish(MQTT_ALERT, "System Armed");
sendTelegram("System%20ARMED");
lcdUpdate("System Armed");
}
// DISARM
else if (t == MQTT_DISARM && cmd == "disarm") {
systemArmed = false;
alarmActive = false;
tempAlarmActive = false;
noTone(BUZZER_PIN);
digitalWrite(LED_RED, LOW);
client.publish(MQTT_ALERT, "System Disarmed");
sendTelegram("System%20DISARMED");
lcdUpdate("System Disarmed");
}
}
// ===================
// WIFI + MQTT
// ===================
void connectWiFi() {
WiFi.begin(WIFI_SSID, WIFI_PASS);
while (WiFi.status() != WL_CONNECTED) delay(300);
}
void connectMQTT() {
while (!client.connected()) {
if (client.connect("ESP32-Security")) {
client.subscribe(MQTT_RESET);
client.subscribe(MQTT_ARM);
client.subscribe(MQTT_DISARM);
}
delay(500);
}
}
// ===================
// SETUP
// ===================
void setup() {
Serial.begin(115200);
pinMode(PIR_PIN, INPUT);
pinMode(BUZZER_PIN, OUTPUT);
pinMode(LED_RED, OUTPUT);
pinMode(LED_GREEN, OUTPUT);
pinMode(LDR_PIN, INPUT);
pinMode(LIGHT_LED, OUTPUT);
digitalWrite(LED_GREEN, HIGH);
dht.begin();
lcd.init();
lcd.backlight();
lcdUpdate("System Disarmed");
pirStartTime = millis();
connectWiFi();
client.setServer(MQTT_BROKER, MQTT_PORT);
client.setCallback(mqttCallback);
connectMQTT();
}
// ===================
// LOOP
// ===================
void loop() {
if (!client.connected()) connectMQTT();
client.loop();
// PIR warm-up
if (!pirReady && millis() - pirStartTime > 5000) pirReady = true;
// Read sensors
int motion = digitalRead(PIR_PIN);
float temp = dht.readTemperature();
float hum = dht.readHumidity();
int ldrValue = analogRead(LDR_PIN);
String lightStatus = (ldrValue < 2000) ? "Dark" : "Light";
// Light LED control
digitalWrite(LIGHT_LED, (lightStatus == "Dark") ? HIGH : LOW);
// Publish sensor data
client.publish(MQTT_TEMP, String(temp).c_str());
client.publish(MQTT_HUM, String(hum).c_str());
//================================
// Wait before publishing again
delay(3500); // Publish every 5 seconds
//=============================
// ✅ AUTO-CLEAR TEMP ALARM
if (tempAlarmActive && temp <= TEMP_LIMIT && systemArmed) {
tempAlarmActive = false;
alarmActive = false;
noTone(BUZZER_PIN);
digitalWrite(LED_RED, LOW);
client.publish(MQTT_ALERT, "Temperature Normal");
sendTelegram("Temperature%20Normal");
lcdUpdate("TEMP NORMAL");
delay(500);
}
// ✅ ALARM ACTIVE → freeze display
if (alarmActive) {
tone(BUZZER_PIN, 1000);
digitalWrite(LED_RED, HIGH);
if (tempAlarmActive)
lcdUpdate("TEMP ALERT!");
else
lcdUpdate("MOTION ALERT!");
return;
}
// ✅ DISARMED → normal display
if (!systemArmed) {
lcdUpdate("LDR:" + lightStatus + " D",
"T:" + String(temp) + " H:" + String(hum));
return;
}
// ✅ ARMED → normal display
lcdUpdate("LDR:" + lightStatus + " A",
"T:" + String(temp) + " H:" + String(hum));
// ✅ MOTION ALARM
if (pirReady && motion == HIGH) {
alarmActive = true;
tempAlarmActive = false;
client.publish(MQTT_ALERT, "Motion Detected!");
sendTelegram("%E2%9A%A0%EF%B8%8F%20Motion%20Detected");
lcdUpdate("MOTION ALERT!");
return;
}
// ✅ TEMP ALARM
if (temp > TEMP_LIMIT) {
alarmActive = true;
tempAlarmActive = true;
client.publish(MQTT_ALERT, "High Temperature!");
sendTelegram("%F0%9F%94%A5%20High%20Temperature");
lcdUpdate("TEMP ALERT!");
return;
}
}