#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <DHT.h>
#include <ESP32Servo.h>
// ── Pin Definitions ──────────────────────────────────────
#define DHTPIN 4
#define DHTTYPE DHT22
#define PIR_PIN 13
#define SERVO_PIN 14
#define LED_LIVING 26
#define LED_BEDROOM 27
#define LED_KITCHEN 32
#define LED_BATHROOM 33
#define BTN_LIVING 34
#define BTN_BEDROOM 35
#define BTN_KITCHEN 18
#define BTN_BATHROOM 19
// ── Objects ──────────────────────────────────────────────
DHT dht(DHTPIN, DHTTYPE);
Servo doorServo;
LiquidCrystal_I2C lcd(0x27, 16, 2);
// ── State Variables ───────────────────────────────────────
bool ledState[4] = {false, false, false, false};
bool lastBtn[4] = {HIGH, HIGH, HIGH, HIGH};
bool doorLocked = true;
bool motionDetected = false;
const int ledPins[4] = {LED_LIVING, LED_BEDROOM, LED_KITCHEN, LED_BATHROOM};
const int btnPins[4] = {BTN_LIVING, BTN_BEDROOM, BTN_KITCHEN, BTN_BATHROOM};
const char* roomNames[4] = {"Living Room", "Bedroom", "Kitchen", "Bathroom"};
unsigned long lastSensorRead = 0;
unsigned long lastSerialPrint = 0;
unsigned long lastLCDUpdate = 0;
unsigned long lastMotionCheck = 0;
int lcdPage = 0;
float temperature = 0, humidity = 0;
// ── Setup ─────────────────────────────────────────────────
void setup() {
Serial.begin(115200);
Serial.println("=================================");
Serial.println(" IoT Home Automation System");
Serial.println(" ESP32 | Wokwi Simulator");
Serial.println("=================================");
Serial.println("Commands via Serial Monitor:");
Serial.println(" 1-4 : Toggle room lights");
Serial.println(" d : Toggle door lock");
Serial.println(" a : All lights ON");
Serial.println(" o : All lights OFF");
Serial.println(" s : Show status");
Serial.println("=================================\n");
// LED & Button pins
for (int i = 0; i < 4; i++) {
pinMode(ledPins[i], OUTPUT);
digitalWrite(ledPins[i], LOW);
pinMode(btnPins[i], INPUT_PULLUP);
}
pinMode(PIR_PIN, INPUT);
// Servo
doorServo.attach(SERVO_PIN);
doorServo.write(0); // locked position
// DHT
dht.begin();
// LCD
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("Home Automation");
lcd.setCursor(0, 1);
lcd.print(" System Ready ");
delay(2000);
lcd.clear();
}
// ── Toggle LED Helper ─────────────────────────────────────
void toggleLED(int index) {
ledState[index] = !ledState[index];
digitalWrite(ledPins[index], ledState[index] ? HIGH : LOW);
Serial.print("[LIGHT] ");
Serial.print(roomNames[index]);
Serial.println(ledState[index] ? " → ON" : " → OFF");
}
// ── Door Control ──────────────────────────────────────────
void toggleDoor() {
doorLocked = !doorLocked;
doorServo.write(doorLocked ? 0 : 90);
Serial.print("[DOOR] ");
Serial.println(doorLocked ? "Locked 🔒" : "Unlocked 🔓");
}
// ── All Lights ────────────────────────────────────────────
void setAllLights(bool state) {
for (int i = 0; i < 4; i++) {
ledState[i] = state;
digitalWrite(ledPins[i], state ? HIGH : LOW);
}
Serial.print("[LIGHT] All lights → ");
Serial.println(state ? "ON" : "OFF");
}
// ── Print Status ──────────────────────────────────────────
void printStatus() {
Serial.println("\n──── System Status ────");
Serial.printf("Temperature : %.1f °C\n", temperature);
Serial.printf("Humidity : %.1f %%\n", humidity);
Serial.printf("Motion : %s\n", motionDetected ? "Detected" : "None");
Serial.printf("Door : %s\n", doorLocked ? "Locked" : "Unlocked");
for (int i = 0; i < 4; i++) {
Serial.printf("%-12s: %s\n", roomNames[i], ledState[i] ? "ON" : "OFF");
}
Serial.println("───────────────────────\n");
}
// ── Handle Serial Commands ────────────────────────────────
void handleSerial() {
if (!Serial.available()) return;
char cmd = Serial.read();
switch (cmd) {
case '1': toggleLED(0); break;
case '2': toggleLED(1); break;
case '3': toggleLED(2); break;
case '4': toggleLED(3); break;
case 'd': case 'D': toggleDoor(); break;
case 'a': case 'A': setAllLights(true); break;
case 'o': case 'O': setAllLights(false); break;
case 's': case 'S': printStatus(); break;
default: break;
}
}
// ── Handle Physical Buttons ───────────────────────────────
void handleButtons() {
for (int i = 0; i < 4; i++) {
bool current = digitalRead(btnPins[i]);
if (current == LOW && lastBtn[i] == HIGH) {
delay(50); // debounce
toggleLED(i);
}
lastBtn[i] = current;
}
}
// ── Read DHT Sensor ───────────────────────────────────────
void readSensors() {
if (millis() - lastSensorRead < 2000) return;
lastSensorRead = millis();
float t = dht.readTemperature();
float h = dht.readHumidity();
if (!isnan(t) && !isnan(h)) {
temperature = t;
humidity = h;
}
motionDetected = digitalRead(PIR_PIN);
// Auto-unlock door on motion (optional smart behaviour)
if (motionDetected && doorLocked) {
Serial.println("[PIR] Motion detected! Auto-unlocking door...");
doorLocked = false;
doorServo.write(90);
}
}
// ── Update LCD (alternating pages) ───────────────────────
void updateLCD() {
if (millis() - lastLCDUpdate < 3000) return;
lastLCDUpdate = millis();
lcd.clear();
if (lcdPage == 0) {
lcd.setCursor(0, 0);
lcd.print("Temp:");
lcd.print(temperature, 1);
lcd.print((char)223);
lcd.print("C");
lcd.setCursor(0, 1);
lcd.print("Humid:");
lcd.print(humidity, 1);
lcd.print("%");
} else if (lcdPage == 1) {
lcd.setCursor(0, 0);
lcd.print("Motion:");
lcd.print(motionDetected ? "YES" : "NO ");
lcd.setCursor(0, 1);
lcd.print("Door:");
lcd.print(doorLocked ? "LOCKED " : "UNLOCKED");
} else {
// Show light states compactly: L B K Ba
lcd.setCursor(0, 0);
lcd.print("L B K Ba");
lcd.setCursor(0, 1);
for (int i = 0; i < 4; i++) {
lcd.print(ledState[i] ? "ON " : "-- ");
}
}
lcdPage = (lcdPage + 1) % 3;
}
// ── Periodic Serial Dashboard ─────────────────────────────
void serialDashboard() {
if (millis() - lastSerialPrint < 5000) return;
lastSerialPrint = millis();
printStatus();
}
// ── Loop ──────────────────────────────────────────────────
void loop() {
handleSerial();
handleButtons();
readSensors();
updateLCD();
serialDashboard();
delay(10);
}