From 25055c5df90b073fadae68b2769782b062bc9fc1 Mon Sep 17 00:00:00 2001 From: Aditya Date: Wed, 30 Jul 2025 14:39:52 +0700 Subject: [PATCH] Add SISTEM KEAMANAN PINTU RUMAH DENGAN RFID (RADIO FREQUENCY INDENTIFICATION) BERBASIS INTERNET OF THINGS --- ...DENTIFICATION) BERBASIS INTERNET OF THINGS | 417 ++++++++++++++++++ 1 file changed, 417 insertions(+) create mode 100644 SISTEM KEAMANAN PINTU RUMAH DENGAN RFID (RADIO FREQUENCY INDENTIFICATION) BERBASIS INTERNET OF THINGS diff --git a/SISTEM KEAMANAN PINTU RUMAH DENGAN RFID (RADIO FREQUENCY INDENTIFICATION) BERBASIS INTERNET OF THINGS b/SISTEM KEAMANAN PINTU RUMAH DENGAN RFID (RADIO FREQUENCY INDENTIFICATION) BERBASIS INTERNET OF THINGS new file mode 100644 index 0000000..96afeb5 --- /dev/null +++ b/SISTEM KEAMANAN PINTU RUMAH DENGAN RFID (RADIO FREQUENCY INDENTIFICATION) BERBASIS INTERNET OF THINGS @@ -0,0 +1,417 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +// ========== 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"); + } + } +} \ No newline at end of file