#include <WiFi.h>
#include <PubSubClient.h>
#include <ESP32Servo.h>
#include <Keypad.h>
// WiFi & MQTT Secure Config
const char* ssid = "Wokwi-GUEST";
const char* password = "";
const char* mqtt_server = "broker.mydomain.com"; // Secure Broker
const char* mqtt_user = "mohdy";
const char* mqtt_password = "M_baby01";
WiFiClient espClient;
PubSubClient client(espClient);
Servo lockerServo;
// Pin Assignments
#define SERVO_PIN 17
#define PIR_PIN 5
#define ULTRASONIC_TRIG 18
#define ULTRASONIC_ECHO 19
#define BUZZER_PIN 23
#define LED_PIN 2
// Keypad Setup
const byte ROWS = 4, COLS = 3;
char keys[ROWS][COLS] = { {'1','2','3'}, {'4','5','6'}, {'7','8','9'}, {'*','0','#'} };
byte rowPins[ROWS] = {32, 33, 25, 26};
byte colPins[COLS] = {27, 12, 13};
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
String enteredCode = "";
const String accessCode = "1234"; // TODO: Implement hashed access code storage
bool isUnlocked = false;
unsigned long unlockTime = 0;
const unsigned long autoLockDuration = 5 * 60 * 1000; // 5 minutes
void connectMQTT() {
while (!client.connected()) {
Serial.print("Connecting to MQTT...");
if (client.connect("ESP32Locker", mqtt_user, mqtt_password)) {
Serial.println("Connected!");
client.subscribe("locker/command");
client.publish("locker/status", "Locker Online");
} else {
Serial.println("Retrying in 2 sec...");
delay(2000);
}
}
}
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting...");
}
Serial.println("Connected to WiFi");
client.setServer(mqtt_server, 1883); // Non-TLS for debugging. Change to 8883 with TLS in production.
client.setCallback(mqtt_callback);
connectMQTT();
pinMode(PIR_PIN, INPUT);
pinMode(ULTRASONIC_TRIG, OUTPUT);
pinMode(ULTRASONIC_ECHO, INPUT);
pinMode(BUZZER_PIN, OUTPUT);
pinMode(LED_PIN, OUTPUT);
lockerServo.attach(SERVO_PIN);
lockerServo.write(0); // Locked by default
}
void loop() {
client.loop();
if (!client.connected()) connectMQTT();
// Motion Detection
if (digitalRead(PIR_PIN)) {
Serial.println("🚨 Unauthorized Access Detected!");
digitalWrite(BUZZER_PIN, HIGH);
delay(500);
digitalWrite(BUZZER_PIN, LOW);
client.publish("locker/status", "ALERT: Motion Detected");
}
// Ultrasonic Object Detection
long duration;
int distance;
digitalWrite(ULTRASONIC_TRIG, LOW);
delayMicroseconds(2);
digitalWrite(ULTRASONIC_TRIG, HIGH);
delayMicroseconds(10);
digitalWrite(ULTRASONIC_TRIG, LOW);
duration = pulseIn(ULTRASONIC_ECHO, HIGH, 30000); // 30ms timeout
distance = (duration > 0) ? duration * 0.034 / 2 : 999;
Serial.printf("Distance: %d cm\n", distance);
if (distance > 0 && distance < 30) {
Serial.println("✅ Object Detected in Locker.");
digitalWrite(LED_PIN, HIGH);
} else {
Serial.println("❌ No Object Detected.");
digitalWrite(LED_PIN, LOW);
}
// Keypad Access Logic
char key = keypad.getKey();
if (key) {
Serial.printf("Key Pressed: %c\n", key);
if (key == '#') {
if (enteredCode == accessCode) {
Serial.println("🔓 Access Granted!");
lockerServo.write(90);
isUnlocked = true;
unlockTime = millis();
client.publish("locker/status", "Locker Unlocked Successfully!");
} else {
Serial.println("❌ Access Denied!");
digitalWrite(BUZZER_PIN, HIGH);
delay(1000);
digitalWrite(BUZZER_PIN, LOW);
client.publish("locker/status", "Access Denied!");
}
enteredCode = ""; // Reset entry
} else {
enteredCode += key;
}
}
// Auto-lock after timeout
if (isUnlocked && millis() - unlockTime >= autoLockDuration) {
lockerServo.write(0);
isUnlocked = false;
client.publish("locker/status", "Locker Auto-Locked");
Serial.println("🔒 Locker auto-locked.");
}
}
// MQTT Callback Handling
void mqtt_callback(char* topic, byte* message, unsigned int length) {
String msg;
for (int i = 0; i < length; i++) msg += (char)message[i];
Serial.printf("MQTT Command Received: %s\n", msg.c_str());
if (msg == "open") {
lockerServo.write(90);
isUnlocked = true;
unlockTime = millis();
client.publish("locker/status", "Locker Opened via Cloud Command!");
Serial.println("🔓 Locker opened remotely.");
} else if (msg == "close") {
lockerServo.write(0);
isUnlocked = false;
client.publish("locker/status", "Locker Closed via Cloud Command!");
Serial.println("🔒 Locker closed remotely.");
}
}