/*
* SMART HOME SYSTEM - ESP32 + Wokwi + Blynk + RTC + Custom MQ2 Chip
* Fitur: Fire Alarm, Motion Detector, Auto Light, Climate Control, Smart Lock, Energy Saver
*/
#define BLYNK_TEMPLATE_ID "TMPL6y5_nUYk7"
#define BLYNK_TEMPLATE_NAME "Smart Home"
#define BLYNK_AUTH_TOKEN "2_KhA7WjxP40bNbBc9xzEROQjXIodR0r"
#include <WiFi.h>
#include <BlynkSimpleEsp32.h>
#include <DHT.h>
#include <ESP32Servo.h>
#include <Wire.h>
#include <TimeLib.h>
// WiFi credentials
char ssid[] = "Wokwi-GUEST";
char pass[] = "";
// Pin definitions
#define MQ2_AO_PIN 4 // MQ2 analog output pin (sesuai dengan diagram)
#define MQ2_DO_PIN 5 // MQ2 digital output pin
#define PIR_DOOR_PIN 2 // PIR sensor pintu
#define PIR_ROOM_PIN 18 // PIR sensor ruangan (pindah dari pin 4)
#define DHT_PIN 15 // DHT22 sensor
#define BUZZER_PIN 12 // Buzzer
#define FIRE_LED_PIN 13 // LED fire alarm
#define CAMERA_LED_PIN 14 // LED kamera recording
#define LIGHT_LED_PIN 27 // LED lampu utama
#define FAN_LED_PIN 26 // LED kipas/AC
#define SERVO_PIN 25 // Servo smart lock
// I2C pins for RTC
#define SDA_PIN 21
#define SCL_PIN 22
// DHT sensor
#define DHT_TYPE DHT22
DHT dht(DHT_PIN, DHT_TYPE);
// Servo motor
Servo doorLock;
// RTC DS1307 I2C Address
#define DS1307_I2C_ADDRESS 0x68
// Function to convert decimal to BCD
byte decToBcd(byte val) {
return ((val/10*16) + (val%10));
}
// Function to convert BCD to decimal
byte bcdToDec(byte val) {
return ((val/16*10) + (val%16));
}
// Variables
bool fireAlarmActive = false;
bool motionDetected = false;
bool lightAutoMode = true;
bool fanAutoMode = true;
bool lockStatus = false; // false = unlocked, true = locked
unsigned long lastMotionTime = 0;
unsigned long lastFireCheck = 0;
unsigned long lastSensorRead = 0;
float temperature = 0;
float humidity = 0;
int gasLevel = 0;
float gasPPM = 0;
int currentHour = 12;
int currentMinute = 0;
String currentTimeString = "";
// MQ2 Sensor Variables
float gasVoltage = 0;
int gasPercentage = 0;
bool digitalGasDetected = false;
// Virtual pins for Blynk
#define V_FIRE_STATUS V0
#define V_MOTION_STATUS V1
#define V_TEMPERATURE V2
#define V_HUMIDITY V3
#define V_LIGHT_CONTROL V4
#define V_LIGHT_AUTO V5
#define V_FAN_CONTROL V6
#define V_FAN_AUTO V7
#define V_LOCK_CONTROL V8
#define V_LOCK_STATUS V9
#define V_GAS_LEVEL V10
#define V_NOTIFICATIONS V11
#define V_CURRENT_TIME V12
// Timer untuk update data
BlynkTimer timer;
void setup() {
Serial.begin(115200);
// Test buzzer saat startup
digitalWrite(BUZZER_PIN, HIGH);
delay(500);
digitalWrite(BUZZER_PIN, LOW);
// Initialize I2C
Wire.begin(SDA_PIN, SCL_PIN);
// Initialize pins
pinMode(MQ2_AO_PIN, INPUT);
pinMode(MQ2_DO_PIN, INPUT);
pinMode(PIR_DOOR_PIN, INPUT);
pinMode(PIR_ROOM_PIN, INPUT);
pinMode(BUZZER_PIN, OUTPUT);
pinMode(FIRE_LED_PIN, OUTPUT);
pinMode(CAMERA_LED_PIN, OUTPUT);
pinMode(LIGHT_LED_PIN, OUTPUT);
pinMode(FAN_LED_PIN, OUTPUT);
// Initialize DHT
dht.begin();
// Initialize Servo
doorLock.attach(SERVO_PIN);
doorLock.write(0); // Unlocked position
// Initialize RTC
Wire.begin(SDA_PIN, SCL_PIN);
setDS1307time(0, 30, 12, 1, 1, 1, 24); // Set initial time: 12:30:00, Day 1, Date 1, Month 1, Year 2024
// Initialize Blynk
Blynk.begin(BLYNK_AUTH_TOKEN, ssid, pass);
// Setup timers
timer.setInterval(1000L, checkSensors); // Check sensors every 1 second
timer.setInterval(5000L, updateBlynkData); // Update Blynk every 5 seconds
timer.setInterval(1000L, updateTime); // Update time every second
timer.setInterval(30000L, checkEnergyMode); // Check energy saving every 30 seconds
Serial.println("Smart Home System Started!");
Blynk.virtualWrite(V_NOTIFICATIONS, "Smart Home System Online");
}
void loop() {
Blynk.run();
timer.run();
}
// Function to check all sensors
void checkSensors() {
// Read MQ2 gas sensor
readMQ2Sensor();
checkFireAlarm();
// Read motion sensors
checkMotionSensors();
// Read temperature and humidity
if (millis() - lastSensorRead > 2000) {
temperature = dht.readTemperature();
humidity = dht.readHumidity();
if (isnan(temperature) || isnan(humidity)) {
temperature = 25.0; // Default value for simulation
humidity = 60.0;
}
// Auto fan control based on temperature
if (fanAutoMode) {
if (temperature > 28.0) {
digitalWrite(FAN_LED_PIN, HIGH);
Blynk.virtualWrite(V_FAN_CONTROL, 1);
} else if (temperature < 26.0) {
digitalWrite(FAN_LED_PIN, LOW);
Blynk.virtualWrite(V_FAN_CONTROL, 0);
}
}
lastSensorRead = millis();
}
// Auto light control based on time
autoLightControl();
}
// Function to read MQ2 sensor
void readMQ2Sensor() {
// Read analog value (0-4095 for ESP32)
gasLevel = analogRead(MQ2_AO_PIN);
// Convert to voltage (0-5V range dari custom chip)
gasVoltage = (gasLevel * 5.0) / 4095.0;
// Convert to percentage (0-100%)
gasPercentage = map(gasLevel, 0, 4095, 0, 100);
// Read digital output
digitalGasDetected = digitalRead(MQ2_DO_PIN);
// Calculate PPM estimation (simplified)
// Asumsi: 0-5V = 0-1000 PPM untuk simulasi
gasPPM = (gasVoltage / 5.0) * 1000.0;
// Debug output
Serial.print("Gas ADC: ");
Serial.print(gasLevel);
Serial.print(" | Voltage: ");
Serial.print(gasVoltage, 2);
Serial.print("V | Percentage: ");
Serial.print(gasPercentage);
Serial.print("% | PPM: ");
Serial.print(gasPPM, 1);
Serial.print(" | Digital: ");
Serial.println(digitalGasDetected ? "HIGH" : "LOW");
}
// Fire alarm system - menggunakan nilai persentase dan digital output
void checkFireAlarm() {
// Menggunakan kombinasi analog dan digital reading
// Ambang batas: 60% untuk analog, atau digital output HIGH
bool fireDetected = (gasPercentage > 60) || digitalGasDetected;
if (fireDetected) {
if (!fireAlarmActive) {
fireAlarmActive = true;
digitalWrite(FIRE_LED_PIN, HIGH);
tone(BUZZER_PIN, 1000); // Bunyi buzzer 1 kHz
Blynk.virtualWrite(V_FIRE_STATUS, 1);
String alertMessage = "🔥 FIRE DETECTED! Gas: " + String(gasPercentage) + "% | " +
String(gasPPM, 1) + " PPM | Voltage: " + String(gasVoltage, 2) + "V";
Blynk.logEvent("fire_alarm", alertMessage);
Serial.println("🔥 FIRE ALARM ACTIVATED!");
Serial.println("Gas Percentage: " + String(gasPercentage) + "%");
Serial.println("Gas PPM: " + String(gasPPM, 1));
Serial.println("Digital Output: " + String(digitalGasDetected ? "HIGH" : "LOW"));
}
} else {
if (fireAlarmActive) {
fireAlarmActive = false;
digitalWrite(FIRE_LED_PIN, LOW);
noTone(BUZZER_PIN); // Matikan buzzer
Blynk.virtualWrite(V_FIRE_STATUS, 0);
Serial.println("Fire alarm deactivated");
}
}
}
// Motion detection system
void checkMotionSensors() {
// Door motion sensor (Camera simulation)
if (digitalRead(PIR_DOOR_PIN) == HIGH) {
if (!motionDetected) {
motionDetected = true;
digitalWrite(CAMERA_LED_PIN, HIGH);
Blynk.virtualWrite(V_MOTION_STATUS, 1);
Blynk.logEvent("motion_detected", "📷 Motion detected at door - Photo taken! Time: " + currentTimeString);
Serial.println("📷 Motion detected - Camera recording at " + currentTimeString);
// Turn off camera LED after 3 seconds
timer.setTimeout(3000L, []() {
digitalWrite(CAMERA_LED_PIN, LOW);
motionDetected = false;
Blynk.virtualWrite(V_MOTION_STATUS, 0);
});
}
}
// Room motion sensor for energy saving
if (digitalRead(PIR_ROOM_PIN) == HIGH) {
lastMotionTime = millis();
}
}
// Auto light control based on RTC time
void autoLightControl() {
if (lightAutoMode) {
// Night: 18:00 - 06:00 (6 PM to 6 AM)
if (currentHour >= 18 || currentHour < 6) {
digitalWrite(LIGHT_LED_PIN, HIGH);
Blynk.virtualWrite(V_LIGHT_CONTROL, 1);
} else {
digitalWrite(LIGHT_LED_PIN, LOW);
Blynk.virtualWrite(V_LIGHT_CONTROL, 0);
}
}
}
// Energy saving mode
void checkEnergyMode() {
if (millis() - lastMotionTime > 120000) { // No motion for 2 minutes
// Turn off lights and fan to save energy
if (digitalRead(LIGHT_LED_PIN) == HIGH || digitalRead(FAN_LED_PIN) == HIGH) {
digitalWrite(LIGHT_LED_PIN, LOW);
digitalWrite(FAN_LED_PIN, LOW);
Blynk.virtualWrite(V_LIGHT_CONTROL, 0);
Blynk.virtualWrite(V_FAN_CONTROL, 0);
Blynk.logEvent("energy_save", "⚡ Energy saving mode activated at " + currentTimeString);
Serial.println("⚡ Energy saving mode activated at " + currentTimeString);
}
}
}
// Update data to Blynk
void updateBlynkData() {
Blynk.virtualWrite(V_TEMPERATURE, temperature);
Blynk.virtualWrite(V_HUMIDITY, humidity);
Blynk.virtualWrite(V_GAS_LEVEL, gasPercentage); // Mengirim persentase gas
Blynk.virtualWrite(V_CURRENT_TIME, currentTimeString);
// Update lock status
Blynk.virtualWrite(V_LOCK_STATUS, lockStatus ? "🔒 Locked" : "🔓 Unlocked");
}
// Update time from RTC
void updateTime() {
readDS1307time(¤tHour, ¤tMinute);
// Format time string
String hourStr = currentHour < 10 ? "0" + String(currentHour) : String(currentHour);
String minuteStr = currentMinute < 10 ? "0" + String(currentMinute) : String(currentMinute);
currentTimeString = hourStr + ":" + minuteStr;
Serial.println("Current time: " + currentTimeString);
}
// Function to set DS1307 time
void setDS1307time(byte second, byte minute, byte hour, byte dayOfWeek, byte dayOfMonth, byte month, byte year) {
Wire.beginTransmission(DS1307_I2C_ADDRESS);
Wire.write(0); // set next input to start at the seconds register
Wire.write(decToBcd(second)); // set seconds
Wire.write(decToBcd(minute)); // set minutes
Wire.write(decToBcd(hour)); // set hours
Wire.write(decToBcd(dayOfWeek)); // set day of week (1=Sunday, 7=Saturday)
Wire.write(decToBcd(dayOfMonth)); // set date (1 to 31)
Wire.write(decToBcd(month)); // set month
Wire.write(decToBcd(year)); // set year (0 to 99)
Wire.endTransmission();
}
// Function to read DS1307 time
void readDS1307time(int* hour, int* minute) {
Wire.beginTransmission(DS1307_I2C_ADDRESS);
Wire.write(0); // set DS1307 register pointer to 00h
Wire.endTransmission();
Wire.requestFrom(DS1307_I2C_ADDRESS, 7);
byte second = bcdToDec(Wire.read() & 0x7f);
*minute = bcdToDec(Wire.read());
*hour = bcdToDec(Wire.read() & 0x3f);
byte dayOfWeek = bcdToDec(Wire.read());
byte dayOfMonth = bcdToDec(Wire.read());
byte month = bcdToDec(Wire.read());
byte year = bcdToDec(Wire.read());
}
// Blynk Virtual Pin Handlers
// Light manual control
BLYNK_WRITE(V_LIGHT_CONTROL) {
if (!lightAutoMode) {
int value = param.asInt();
digitalWrite(LIGHT_LED_PIN, value);
Serial.println("Light " + String(value ? "ON" : "OFF") + " at " + currentTimeString);
}
}
// Light auto mode toggle
BLYNK_WRITE(V_LIGHT_AUTO) {
lightAutoMode = param.asInt();
Serial.println("Light auto mode: " + String(lightAutoMode ? "ON" : "OFF"));
}
// Fan manual control
BLYNK_WRITE(V_FAN_CONTROL) {
if (!fanAutoMode) {
int value = param.asInt();
digitalWrite(FAN_LED_PIN, value);
Serial.println("Fan " + String(value ? "ON" : "OFF") + " at " + currentTimeString);
}
}
// Fan auto mode toggle
BLYNK_WRITE(V_FAN_AUTO) {
fanAutoMode = param.asInt();
Serial.println("Fan auto mode: " + String(fanAutoMode ? "ON" : "OFF"));
}
// Smart lock control
BLYNK_WRITE(V_LOCK_CONTROL) {
int value = param.asInt();
lockStatus = value;
if (lockStatus) {
doorLock.write(90); // Locked position
Blynk.logEvent("door_locked", "🔒 Door locked at " + currentTimeString);
Serial.println("🔒 Door LOCKED at " + currentTimeString);
} else {
doorLock.write(0); // Unlocked position
Blynk.logEvent("door_unlocked", "🔓 Door unlocked at " + currentTimeString);
Serial.println("🔓 Door UNLOCKED at " + currentTimeString);
}
}
// Connected to Blynk
BLYNK_CONNECTED() {
Serial.println("Connected to Blynk!");
Blynk.syncAll(); // Sync all virtual pins
}Fire Alarm
Motion Depan Pintu
Lampu
Kipas/AC
Custom MQ2 Sensor
Modul Pengatur Waktu (RTC)
Sensor Suhu dan Kelembaban (DHT 22)
Sensor Gerak Depan Pintu (PIR)
Sensor Gerak Ruangan (PIR)
Kunci Pintu (Servo)