#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Keypad.h>
#include <ESP32Servo.h>
#include <DHT.h>
#include <WiFi.h>
#include <PubSubClient.h>
// =========================================
// WIFI & MQTT SETUP
// =========================================
const char* ssid = "Wokwi-GUEST";
const char* password = "";
// --- THINGSBOARD CONFIGURATION ---
const char* mqtt_server = "thingsboard.cloud";
const int mqtt_port = 1883;
const char* accessToken = "hA9sUlKLf8GeSlDH1idS"; // YOUR TOKEN
WiFiClient espClient;
PubSubClient client(espClient);
// ThingsBoard Default Topics
#define TB_TELEMETRY "v1/devices/me/telemetry"
#define TB_RPC "v1/devices/me/rpc/request/+"
// =========================================
// PIN DEFINITIONS
// =========================================
#define DHTPIN 16
#define DHTTYPE DHT22
#define PIR_PIN 35
#define LDR_PIN 34
#define TRIG_PIN 18
#define ECHO_PIN 19
#define RELAY_FAN_PIN 17
#define RELAY_LIGHT_PIN 5
#define SERVO_PIN 15
#define BUZZER_PIN 23
#define RED_PIN 25
#define GREEN_PIN 26
#define BLUE_PIN 27
// =========================================
// OBJECT SETUP
// =========================================
LiquidCrystal_I2C lcd(0x27, 20, 4);
DHT dht(DHTPIN, DHTTYPE);
Servo doorServo;
const byte ROWS = 4;
const byte COLS = 4;
char keys[ROWS][COLS] = {
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};
byte rowPins[ROWS] = {13, 12, 14, 32};
byte colPins[COLS] = {33, 2, 0, 4};
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
// =========================================
// GLOBAL VARIABLES
// =========================================
String inputPassword = "";
String correctPassword = "1234";
bool isArmed = true;
unsigned long lastClimateCheck = 0;
unsigned long lastGarageCheck = 0;
unsigned long lastMqttRetry = 0;
unsigned long buzzerTimer = 0;
bool buzzerState = false;
// Garage
long duration;
int distance;
int beepFrequency = 0;
// =========================================
// SETUP
// =========================================
void setup() {
Serial.begin(115200);
delay(100);
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
pinMode(RELAY_FAN_PIN, OUTPUT);
pinMode(RELAY_LIGHT_PIN, OUTPUT);
pinMode(PIR_PIN, INPUT);
pinMode(BUZZER_PIN, OUTPUT);
pinMode(RED_PIN, OUTPUT);
pinMode(GREEN_PIN, OUTPUT);
pinMode(BLUE_PIN, OUTPUT);
pinMode(LDR_PIN, INPUT);
lcd.init();
lcd.backlight();
dht.begin();
doorServo.attach(SERVO_PIN);
doorServo.write(0);
delay(500);
doorServo.detach();
Serial.println("[BOOT] Testing Buzzer...");
tone(BUZZER_PIN, 1000, 200);
setup_wifi();
client.setServer(mqtt_server, mqtt_port);
client.setCallback(Callback);
lcd.clear();
updateStatusRGB(1, 0, 0);
lcd.print("System: ARMED");
Serial.println("[SYSTEM] Ready! Connecting to ThingsBoard...");
}
// =========================================
// WIFI FUNCTIONS
// =========================================
void setup_wifi() {
delay(10);
lcd.setCursor(0,0);
lcd.print("WiFi Connecting...");
WiFi.begin(ssid, password);
int retry = 0;
while (WiFi.status() != WL_CONNECTED && retry < 10) {
delay(500);
Serial.print(".");
retry++;
}
if(WiFi.status() == WL_CONNECTED) {
Serial.println("\n[WIFI] Connected!");
lcd.setCursor(0,1); lcd.print("WiFi OK! ");
} else {
Serial.println("\n[WIFI] Failed (Running Offline Mode)");
lcd.setCursor(0,1); lcd.print("Offline Mode ");
}
delay(1000);
lcd.clear();
}
void attemptMqttReconnect() {
if (!client.connected()) {
// CONNECT WITH ACCESS TOKEN AS USERNAME
if (client.connect("ESP32_Home_Hub", accessToken, NULL)) {
Serial.println("[MQTT] Connected to ThingsBoard!");
// Send initial status
client.publish(TB_TELEMETRY, "{\"alarmStatus\":\"ONLINE\"}");
}
}
}
void Callback(char* topic, byte* payload, unsigned int length) {
// RPC Handling would go here, but omitted for simplicity
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
}
Serial.println();
}
// =========================================
// MAIN LOOP
// =========================================
void loop() {
unsigned long currentMillis = millis();
// Non-blocking MQTT Reconnect
if (!client.connected()) {
if (currentMillis - lastMqttRetry > 5000) {
lastMqttRetry = currentMillis;
attemptMqttReconnect();
}
} else {
client.loop();
}
handleKeypad();
if (currentMillis - lastGarageCheck > 100) {
handleGarage();
lastGarageCheck = currentMillis;
}
if (currentMillis - lastClimateCheck > 2000) {
handleClimate();
lastClimateCheck = currentMillis;
}
handleLighting();
handleBuzzer(currentMillis);
delay(10);
}
// =========================================
// ZONE FUNCTIONS
// =========================================
void handleKeypad() {
char key = keypad.getKey();
if (key) {
Serial.print("[KEYPAD] Key: "); Serial.println(key);
lcd.setCursor(0, 3);
lcd.print("Pin: " + maskPassword(inputPassword) + key);
if (key == '#') {
lcd.clear();
if (inputPassword == correctPassword) unlockDoor();
else triggerAlarm();
inputPassword = "";
}
else if (key == '*') {
lockDoor();
inputPassword = "";
}
else {
inputPassword += key;
}
}
}
void handleGarage() {
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
duration = pulseIn(ECHO_PIN, HIGH, 25000);
distance = duration * 0.034 / 2;
if (distance > 0 && distance < 10) beepFrequency = 2;
else if (distance >= 10 && distance < 50) beepFrequency = 1;
else beepFrequency = 0;
}
void handleClimate() {
float t = dht.readTemperature();
float h = dht.readHumidity();
if (isnan(t)) return;
lcd.setCursor(0, 1);
lcd.print("T:" + String(t,1) + "C H:" + String(h,0) + "%");
// --- SEND DATA TO THINGSBOARD ---
if (client.connected()) {
// Construct JSON Payload
String payload = "{";
payload += "\"temperature\":" + String(t, 1) + ",";
payload += "\"humidity\":" + String(h, 0);
payload += "}";
client.publish(TB_TELEMETRY, payload.c_str());
}
if (t > 30.0) {
digitalWrite(RELAY_FAN_PIN, HIGH);
lcd.setCursor(15, 1); lcd.print("FAN+");
} else {
digitalWrite(RELAY_FAN_PIN, LOW);
lcd.setCursor(15, 1); lcd.print(" ");
}
}
void handleLighting() {
int lightLevel = analogRead(LDR_PIN);
int motion = digitalRead(PIR_PIN);
// --- 1. Existing Local Logic (Control Relay) ---
if (lightLevel < 2000 && motion == HIGH) digitalWrite(RELAY_LIGHT_PIN, HIGH);
else digitalWrite(RELAY_LIGHT_PIN, LOW);
// --- 2. NEW: Send Data to ThingsBoard ---
// We use 'static' so the ESP32 remembers the value from the previous loop
static int lastMotion = -1;
// Only publish if the state has CHANGED (to avoid spamming)
if (motion != lastMotion) {
lastMotion = motion;
if (client.connected()) {
String statusMsg = (motion == HIGH) ? "DETECTED" : "NO MOTION";
// Construct JSON: {"motionStatus":"DETECTED"}
String payload = "{\"motionStatus\":\"" + statusMsg + "\"}";
client.publish(TB_TELEMETRY, payload.c_str());
Serial.print("[MQTT] Motion Update: "); Serial.println(statusMsg);
}
}
}
// =========================================
// HELPER FUNCTIONS
// =========================================
void unlockDoor() {
Serial.println("[ACTION] UNLOCKING DOOR");
lcd.setCursor(0,0); lcd.print("WELCOME HOME");
// Send Status to ThingsBoard
if(client.connected()) client.publish(TB_TELEMETRY, "{\"doorStatus\":\"OPEN\"}");
doorServo.attach(SERVO_PIN);
for (int pos = 0; pos <= 90; pos += 2) { doorServo.write(pos); delay(15); }
updateStatusRGB(0, 1, 0);
isArmed = false;
noTone(BUZZER_PIN);
}
void lockDoor() {
Serial.println("[ACTION] LOCKING DOOR");
lcd.setCursor(0,0); lcd.print("System ARMED");
// Send Status to ThingsBoard
if(client.connected()) client.publish(TB_TELEMETRY, "{\"doorStatus\":\"LOCKED\"}");
doorServo.attach(SERVO_PIN);
for (int pos = 90; pos >= 0; pos -= 2) { doorServo.write(pos); delay(15); }
updateStatusRGB(1, 0, 0);
isArmed = true;
delay(500); doorServo.detach();
}
void triggerAlarm() {
Serial.println("[ACTION] ALARM TRIGGERED");
lcd.setCursor(0,0); lcd.print("ACCESS DENIED!");
// Send Alarm to ThingsBoard
if(client.connected()) client.publish(TB_TELEMETRY, "{\"alarmStatus\":\"INTRUDER\"}");
updateStatusRGB(1, 0, 0);
for(int i=0; i<3; i++) { tone(BUZZER_PIN, 1000); delay(200); noTone(BUZZER_PIN); delay(200); }
}
void handleBuzzer(unsigned long currentMillis) {
if (beepFrequency == 2) tone(BUZZER_PIN, 2000);
else if (beepFrequency == 1) {
if (currentMillis - buzzerTimer > (distance * 10)) {
buzzerTimer = currentMillis;
if (buzzerState) { noTone(BUZZER_PIN); buzzerState = false; }
else { tone(BUZZER_PIN, 1000); buzzerState = true; }
}
} else { noTone(BUZZER_PIN); buzzerState = false; }
}
String maskPassword(String pass) {
String masked = "";
for(int i=0; i<pass.length(); i++) masked += "*";
return masked;
}
void updateStatusRGB(bool r, bool g, bool b) {
digitalWrite(RED_PIN, r); digitalWrite(GREEN_PIN, g); digitalWrite(BLUE_PIN, b);
}Loading
esp32-devkit-c-v4
esp32-devkit-c-v4
The Security Zone (Door Access)
The Climate Zone (Automatic Fan/AC)
The Garage Zone (Parking Assistant)
The Smart Lighting Zone (Energy Saver)