Add SISTEM KEAMANAN PINTU RUMAH DENGAN RFID (RADIO FREQUENCY INDENTIFICATION) BERBASIS INTERNET OF THINGS
This commit is contained in:
commit
25055c5df9
|
@ -0,0 +1,417 @@
|
|||
#include <SPI.h>
|
||||
#include <MFRC522.h>
|
||||
#include <WiFi.h>
|
||||
#include <PubSubClient.h>
|
||||
#include <Wire.h>
|
||||
#include <LiquidCrystal_I2C.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <EEPROM.h>
|
||||
|
||||
// ========== HARDWARE CONFIGURATION ========== //
|
||||
#define SS_PIN 5 // RFID SDA pin
|
||||
#define RST_PIN 27 // RFID Reset pin
|
||||
#define RELAY_PIN 26 // Relay
|
||||
#define LED_ACCESS 15 // Green LED
|
||||
#define LED_DENIED 12 // Red LED
|
||||
#define BUTTON_PIN 14 // Manual button
|
||||
|
||||
// ========== LCD CONFIGURATION ========== //
|
||||
#define LCD_ADDRESS 0x27 // I2C address (usually 0x27 or 0x3F)
|
||||
#define LCD_COLS 16 // 16x2 LCD
|
||||
#define LCD_ROWS 2
|
||||
LiquidCrystal_I2C lcd(LCD_ADDRESS, LCD_COLS, LCD_ROWS);
|
||||
|
||||
// ========== NETWORK CONFIGURATION ========== //
|
||||
const char* ssid = "POCO X7 Pro";
|
||||
const char* password = "12345678";
|
||||
const char* mqtt_server = "192.168.214.186";
|
||||
const int mqtt_port = 1883;
|
||||
|
||||
// ========== EEPROM CONFIGURATION ========== //
|
||||
#define EEPROM_SIZE 512
|
||||
#define MAX_CARDS 20 // Maximum stored cards
|
||||
#define UID_LENGTH 20 // RFID UID length
|
||||
|
||||
// ========== MQTT TOPICS ========== //
|
||||
const char* mqtt_topic_status = "doorlock/status";
|
||||
const char* mqtt_topic_control = "doorlock/control";
|
||||
const char* mqtt_topic_access = "doorlock/access";
|
||||
const char* mqtt_topic_card_manage = "doorlock/card/manage";
|
||||
const char* mqtt_topic_card_response = "doorlock/card/response";
|
||||
|
||||
// ========== GLOBAL VARIABLES ========== //
|
||||
WiFiClient espClient;
|
||||
PubSubClient client(espClient);
|
||||
MFRC522 mfrc522(SS_PIN, RST_PIN);
|
||||
|
||||
String allowedUIDs[MAX_CARDS];
|
||||
int allowedUIDsCount = 0;
|
||||
bool doorUnlocked = false;
|
||||
unsigned long unlockStartTime = 0;
|
||||
const unsigned long unlockDuration = 5000; // Door unlock duration (5 sec)
|
||||
unsigned long lastRFIDRead = 0;
|
||||
const unsigned long rfidDebounce = 1000; // RFID debounce time (1 sec)
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
||||
// Initialize EEPROM
|
||||
EEPROM.begin(EEPROM_SIZE);
|
||||
loadRegisteredCards();
|
||||
|
||||
// Initialize LCD (simplified)
|
||||
Wire.begin();
|
||||
lcd.init();
|
||||
lcd.backlight();
|
||||
lcd.clear();
|
||||
lcd.print("Initializing...");
|
||||
|
||||
// Initialize RFID
|
||||
SPI.begin();
|
||||
mfrc522.PCD_Init();
|
||||
delay(100); // RFID stabilization
|
||||
|
||||
// Initialize GPIO
|
||||
pinMode(RELAY_PIN, OUTPUT);
|
||||
pinMode(LED_ACCESS, OUTPUT);
|
||||
pinMode(LED_DENIED, OUTPUT);
|
||||
pinMode(BUTTON_PIN, INPUT_PULLUP);
|
||||
digitalWrite(RELAY_PIN, HIGH); // Ensure door is locked
|
||||
|
||||
// Connect to WiFi & MQTT
|
||||
connectWiFi();
|
||||
client.setServer(mqtt_server, mqtt_port);
|
||||
client.setCallback(mqttCallback);
|
||||
|
||||
lcd.clear();
|
||||
lcd.print("System Ready");
|
||||
Serial.println("[SYSTEM] System ready");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
if (!client.connected()) {
|
||||
reconnectMQTT();
|
||||
}
|
||||
client.loop();
|
||||
|
||||
handleButton();
|
||||
handleRFID();
|
||||
handleUnlockTimer();
|
||||
}
|
||||
|
||||
// ========== LCD FUNCTIONS ========== //
|
||||
void updateLCD(String line1, String line2) {
|
||||
lcd.clear();
|
||||
lcd.print(line1.substring(0, LCD_COLS));
|
||||
lcd.setCursor(0, 1);
|
||||
lcd.print(line2.substring(0, LCD_COLS));
|
||||
}
|
||||
|
||||
void resetDisplay() {
|
||||
lcd.clear();
|
||||
lcd.print("Smart Door Lock");
|
||||
lcd.setCursor(0, 1);
|
||||
lcd.print("Tap RFID Card");
|
||||
}
|
||||
|
||||
// ========== RFID FUNCTIONS ========== //
|
||||
void handleRFID() {
|
||||
if (millis() - lastRFIDRead < rfidDebounce) return;
|
||||
|
||||
if (mfrc522.PICC_IsNewCardPresent() && mfrc522.PICC_ReadCardSerial()) {
|
||||
String uid = getRFIDUID();
|
||||
lastRFIDRead = millis();
|
||||
Serial.println("[RFID] Card detected: " + uid);
|
||||
|
||||
updateLCD("UID Detected:", uid.substring(0, 16));
|
||||
delay(1000);
|
||||
|
||||
if (checkAccess(uid)) {
|
||||
unlockDoor();
|
||||
publishAccess("rfid", "granted", uid);
|
||||
} else {
|
||||
showAccessDenied();
|
||||
publishAccess("rfid", "denied", uid);
|
||||
}
|
||||
|
||||
mfrc522.PICC_HaltA();
|
||||
mfrc522.PCD_StopCrypto1();
|
||||
}
|
||||
}
|
||||
|
||||
String getRFIDUID() {
|
||||
String content;
|
||||
for (byte i = 0; i < mfrc522.uid.size; i++) {
|
||||
content.concat(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " ");
|
||||
content.concat(String(mfrc522.uid.uidByte[i], HEX));
|
||||
}
|
||||
content.toUpperCase();
|
||||
content.trim();
|
||||
return content;
|
||||
}
|
||||
|
||||
// ========== ACCESS MANAGEMENT ========== //
|
||||
bool checkAccess(String uid) {
|
||||
String normalizedUID = uid;
|
||||
normalizedUID.replace(" ", "");
|
||||
|
||||
for (int i = 0; i < allowedUIDsCount; i++) {
|
||||
String allowedUID = allowedUIDs[i];
|
||||
allowedUID.replace(" ", "");
|
||||
|
||||
if (normalizedUID.equals(allowedUID)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void unlockDoor() {
|
||||
digitalWrite(RELAY_PIN, LOW);
|
||||
digitalWrite(LED_ACCESS, HIGH);
|
||||
updateLCD("Access Granted", "Door Unlocked");
|
||||
doorUnlocked = true;
|
||||
unlockStartTime = millis();
|
||||
client.publish(mqtt_topic_status, "unlocked");
|
||||
Serial.println("[DOOR] Door unlocked");
|
||||
}
|
||||
|
||||
void lockDoor() {
|
||||
digitalWrite(RELAY_PIN, HIGH);
|
||||
digitalWrite(LED_ACCESS, LOW);
|
||||
resetDisplay();
|
||||
doorUnlocked = false;
|
||||
client.publish(mqtt_topic_status, "locked");
|
||||
Serial.println("[DOOR] Door locked");
|
||||
}
|
||||
|
||||
void handleUnlockTimer() {
|
||||
if (doorUnlocked && millis() - unlockStartTime > unlockDuration) {
|
||||
lockDoor();
|
||||
}
|
||||
}
|
||||
|
||||
void showAccessDenied() {
|
||||
updateLCD("Access Denied", "Invalid Card");
|
||||
digitalWrite(LED_DENIED, HIGH);
|
||||
delay(1500);
|
||||
digitalWrite(LED_DENIED, LOW);
|
||||
resetDisplay();
|
||||
}
|
||||
|
||||
// ========== EEPROM FUNCTIONS ========== //
|
||||
void saveRegisteredCards() {
|
||||
EEPROM.write(0, allowedUIDsCount);
|
||||
for(int i = 0; i < allowedUIDsCount; i++) {
|
||||
int addr = 1 + (i * UID_LENGTH);
|
||||
String uid = allowedUIDs[i];
|
||||
for(int j = 0; j < uid.length(); j++) {
|
||||
EEPROM.write(addr + j, uid[j]);
|
||||
}
|
||||
EEPROM.write(addr + uid.length(), '\0');
|
||||
}
|
||||
EEPROM.commit();
|
||||
Serial.println("[EEPROM] Card data saved");
|
||||
}
|
||||
|
||||
void loadRegisteredCards() {
|
||||
allowedUIDsCount = EEPROM.read(0);
|
||||
if(allowedUIDsCount > MAX_CARDS) allowedUIDsCount = 0;
|
||||
|
||||
for(int i = 0; i < allowedUIDsCount; i++) {
|
||||
int addr = 1 + (i * UID_LENGTH);
|
||||
String uid;
|
||||
char c;
|
||||
while((c = EEPROM.read(addr++)) != '\0' && uid.length() < UID_LENGTH) {
|
||||
uid += c;
|
||||
}
|
||||
allowedUIDs[i] = uid;
|
||||
Serial.println("[EEPROM] Loaded card: " + uid);
|
||||
}
|
||||
}
|
||||
|
||||
// ========== NETWORK FUNCTIONS ========== //
|
||||
void connectWiFi() {
|
||||
Serial.println("[WiFi] Connecting...");
|
||||
WiFi.begin(ssid, password);
|
||||
|
||||
updateLCD("Connecting WiFi", "");
|
||||
|
||||
int attempts = 0;
|
||||
while (WiFi.status() != WL_CONNECTED && attempts < 20) {
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
attempts++;
|
||||
}
|
||||
|
||||
if (WiFi.status() == WL_CONNECTED) {
|
||||
Serial.println("\n[WiFi] Connected");
|
||||
Serial.println("IP Address: " + WiFi.localIP().toString());
|
||||
updateLCD("WiFi Connected", WiFi.localIP().toString());
|
||||
delay(1000);
|
||||
} else {
|
||||
Serial.println("\n[WiFi] Connection failed");
|
||||
updateLCD("WiFi Failed", "Check Connection");
|
||||
delay(2000);
|
||||
}
|
||||
}
|
||||
|
||||
void reconnectMQTT() {
|
||||
while (!client.connected()) {
|
||||
Serial.println("[MQTT] Connecting...");
|
||||
updateLCD("Connecting MQTT", "");
|
||||
|
||||
if (client.connect("ESP32DoorLock")) {
|
||||
Serial.println("[MQTT] Connected");
|
||||
client.subscribe(mqtt_topic_control);
|
||||
client.subscribe(mqtt_topic_card_manage);
|
||||
client.publish(mqtt_topic_status, "System Ready");
|
||||
updateLCD("MQTT Connected", "System Ready");
|
||||
delay(1000);
|
||||
} else {
|
||||
Serial.print("[MQTT] Failed, rc=");
|
||||
Serial.print(client.state());
|
||||
updateLCD("MQTT Failed", "Retrying...");
|
||||
delay(5000);
|
||||
}
|
||||
}
|
||||
resetDisplay();
|
||||
}
|
||||
|
||||
// ========== MQTT CALLBACK ========== //
|
||||
void mqttCallback(char* topic, byte* payload, unsigned int length) {
|
||||
String message;
|
||||
for (int i = 0; i < length; i++) {
|
||||
message += (char)payload[i];
|
||||
}
|
||||
|
||||
Serial.print("[MQTT] Message received: [");
|
||||
Serial.print(topic);
|
||||
Serial.print("] ");
|
||||
Serial.println(message);
|
||||
|
||||
if (String(topic) == mqtt_topic_control) {
|
||||
if (message.equalsIgnoreCase("OPEN")) {
|
||||
unlockDoor();
|
||||
publishAccess("remote", "granted", "");
|
||||
} else if (message.equalsIgnoreCase("LOCK")) {
|
||||
lockDoor();
|
||||
}
|
||||
}
|
||||
else if (String(topic) == mqtt_topic_card_manage) {
|
||||
handleCardManagement(message);
|
||||
}
|
||||
}
|
||||
|
||||
void handleCardManagement(String message) {
|
||||
DynamicJsonDocument doc(256);
|
||||
DeserializationError error = deserializeJson(doc, message);
|
||||
|
||||
if (error) {
|
||||
Serial.print("[MQTT] JSON parse error: ");
|
||||
Serial.println(error.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
String action = doc["action"];
|
||||
String uid = doc["uid"];
|
||||
String normalizedUID = uid;
|
||||
normalizedUID.replace(" ", "");
|
||||
|
||||
if (action == "add") {
|
||||
if (allowedUIDsCount >= MAX_CARDS) {
|
||||
String response = "{\"status\":\"error\",\"message\":\"Card capacity full\"}";
|
||||
client.publish(mqtt_topic_card_response, response.c_str());
|
||||
updateLCD("Add Failed", "Capacity Full");
|
||||
delay(2000);
|
||||
resetDisplay();
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < allowedUIDsCount; i++) {
|
||||
String existingUID = allowedUIDs[i];
|
||||
existingUID.replace(" ", "");
|
||||
if (normalizedUID.equals(existingUID)) {
|
||||
String response = "{\"status\":\"error\",\"message\":\"Card already registered\"}";
|
||||
client.publish(mqtt_topic_card_response, response.c_str());
|
||||
updateLCD("Card Already", "Registered");
|
||||
delay(2000);
|
||||
resetDisplay();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
allowedUIDs[allowedUIDsCount] = uid;
|
||||
allowedUIDsCount++;
|
||||
saveRegisteredCards();
|
||||
|
||||
String response = "{\"status\":\"success\",\"message\":\"Card added successfully\"}";
|
||||
client.publish(mqtt_topic_card_response, response.c_str());
|
||||
updateLCD("Card Added", uid.substring(0, 16));
|
||||
delay(2000);
|
||||
resetDisplay();
|
||||
}
|
||||
else if (action == "remove") {
|
||||
bool removed = false;
|
||||
for (int i = 0; i < allowedUIDsCount; i++) {
|
||||
String existingUID = allowedUIDs[i];
|
||||
existingUID.replace(" ", "");
|
||||
if (normalizedUID.equals(existingUID)) {
|
||||
for (int j = i; j < allowedUIDsCount - 1; j++) {
|
||||
allowedUIDs[j] = allowedUIDs[j+1];
|
||||
}
|
||||
allowedUIDsCount--;
|
||||
removed = true;
|
||||
saveRegisteredCards();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (removed) {
|
||||
String response = "{\"status\":\"success\",\"message\":\"Card removed successfully\"}";
|
||||
client.publish(mqtt_topic_card_response, response.c_str());
|
||||
updateLCD("Card Removed", uid.substring(0, 16));
|
||||
} else {
|
||||
String response = "{\"status\":\"error\",\"message\":\"Card not found\"}";
|
||||
client.publish(mqtt_topic_card_response, response.c_str());
|
||||
updateLCD("Card Not", "Found");
|
||||
}
|
||||
delay(2000);
|
||||
resetDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
void publishAccess(String method, String status, String uid) {
|
||||
String payload = "{\"method\":\"" + method + "\",\"status\":\"" + status + "\",\"uid\":\"" + uid + "\",\"time\":" + millis() + "}";
|
||||
client.publish(mqtt_topic_access, payload.c_str());
|
||||
Serial.println("[ACCESS] " + payload);
|
||||
}
|
||||
|
||||
// ========== MANUAL BUTTON ========== //
|
||||
void handleButton() {
|
||||
static unsigned long lastButtonPress = 0;
|
||||
static bool lastButtonState = HIGH; // Menyimpan state sebelumnya
|
||||
static bool buttonPressed = false; // Flag untuk menandai tombol sudah diproses
|
||||
const unsigned long debounceTime = 500; // Diperpanjang menjadi 500ms
|
||||
|
||||
bool currentButtonState = digitalRead(BUTTON_PIN);
|
||||
|
||||
// Deteksi perubahan state (edge detection)
|
||||
if (currentButtonState != lastButtonState) {
|
||||
lastButtonPress = millis();
|
||||
lastButtonState = currentButtonState;
|
||||
buttonPressed = false;
|
||||
}
|
||||
|
||||
// Jika tombol ditekan (LOW) dan belum diproses
|
||||
if (currentButtonState == LOW && !buttonPressed && millis() - lastButtonPress > debounceTime) {
|
||||
buttonPressed = true; // Set flag bahwa tombol sudah diproses
|
||||
|
||||
if (!doorUnlocked) {
|
||||
Serial.println("[BUTTON] Door unlocked manually");
|
||||
unlockDoor();
|
||||
publishAccess("button", "granted", "");
|
||||
updateLCD("Manual Access", "Door Unlocked");
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue