Add SISTEM KEAMANAN PINTU RUMAH DENGAN RFID (RADIO FREQUENCY INDENTIFICATION) BERBASIS INTERNET OF THINGS

This commit is contained in:
Aditya 2025-07-30 14:39:52 +07:00
commit 25055c5df9
1 changed files with 417 additions and 0 deletions

View File

@ -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");
}
}
}