// =================================================================
// == SMART DOOR LOCK PROJECT (VERSI PERBAIKAN) ==
// == RFID RC522 + KEYPAD 4x4 + LCD I2C + SERVO + 2 LED ==
// == Dibuat untuk ESP32 ==
// =================================================================
// 1. Sertakan semua library yang dibutuhkan
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <SPI.h>
#include <MFRC522.h>
#include <Keypad.h>
#include <ESP32Servo.h> // PERBAIKAN: Menggunakan ESP32Servo.h karena Servo.h standar error
// =================================================================
// == KONFIGURASI PENGGUNA (SESUAIKAN DI SINI) ==
// =================================================================
// Atur UID kartu RFID yang diizinkan
// GANTI "XX XX XX XX" DENGAN UID KARTU ANDA (dari I2C_Scanner.ino)
String authorizedUID = "XX XX XX XX";
// Atur Password/PIN yang benar
String correctPassword = "4758";
// =================================================================
// == DEFINISI PIN (SESUAI GAMBAR) ==
// =================================================================
// PIN LCD I2C
const int col = 16;
const int raw = 2;
#define I2C_SDA 21
#define I2C_SCL 22
// Pin untuk RFID-RC522 (SPI)
#define RST_PIN 16 // Reset
#define SS_PIN 5 // SDA / Slave Select
// Pin untuk LED
#define LED_GREEN_PIN 4
#define LED_RED_PIN 2
// Pin untuk Servo Motor
#define SERVO_PIN 17
// (TAMBAHAN) Pin untuk Buzzer
#define BUZZER_PIN 15
// Pin untuk Keypad 4x4
const byte ROWS = 4; // 4 baris
const byte COLS = 4; // 4 kolom
char keys[ROWS][COLS] = {
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};
// Pin koneksi keypad ke ESP32
byte rowPins[ROWS] = {13, 12, 14, 27};
byte colPins[COLS] = {26, 25, 33, 32};
// =================================================================
// == INISIALISASI OBJEK ==
// =================================================================
// Buat objek untuk setiap komponen
MFRC522 rfid(SS_PIN, RST_PIN);
// ===============================================================
// == PERHATIAN: GANTI 0x27 DENGAN ALAMAT LCD ANDA YANG BENAR! ==
// == (Kemungkinan besar 0x3F dari hasil I2C_Scanner.ino) ==
// ===============================================================
LiquidCrystal_I2C lcd(0x27, col, raw);
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
Servo myServo;
// Variabel untuk menyimpan password yang dimasukkan
String enteredPassword = "";
// =================================================================
// == FUNGSI SETUP ==
// =================================================================
void setup() {
Serial.begin(115200); // Mulai komunikasi serial untuk debug
// (PERBAIKAN KRUSIAL) Mulai I2C SEBELUM memanggil lcd.init()
Wire.begin(I2C_SDA, I2C_SCL);
// Sekarang baru kita inisialisasi LCD
lcd.init();
lcd.backlight();
lcd.print("LCD OK"); // Tes cepat
delay(500);
// Lanjutkan inisialisasi komponen lain
SPI.begin(); // Mulai komunikasi SPI
rfid.PCD_Init(); // Inisialisasi MFRC522
// Atur pin LED sebagai OUTPUT
pinMode(LED_GREEN_PIN, OUTPUT);
pinMode(LED_RED_PIN, OUTPUT);
// (TAMBAHAN) Atur pin Buzzer sebagai OUTPUT
pinMode(BUZZER_PIN, OUTPUT);
digitalWrite(BUZZER_PIN, LOW); // Pastikan buzzer mati di awal
// Pasang servo ke pin yang ditentukan
myServo.attach(SERVO_PIN);
myServo.write(0); // Pastikan pintu terkunci (posisi 0 derajat)
// Tampilkan pesan selamat datang
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Welcome to");
lcd.setCursor(0, 1);
lcd.print("Smart Door Lock");
delay(2000); // Tunggu 2 detik
// Tampilkan pesan standby
displayStandbyMessage();
}
// =================================================================
// == FUNGSI LOOP UTAMA ==
// =================================================================
void loop() {
// 1. Cek input dari Keypad
char key = keypad.getKey();
if (key) {
handleKeypadInput(key);
}
// 2. Cek kartu RFID baru
if (rfid.PICC_IsNewCardPresent() && rfid.PICC_ReadCardSerial()) {
handleRfidScan();
}
}
// =================================================================
// == FUNGSI-FUNGSI BANTUAN ==
// =================================================================
// (Logika di bawah ini sudah bagus)
// Fungsi untuk menangani input dari keypad
void handleKeypadInput(char key) {
lcd.setCursor(0, 0); // Tampilkan di baris atas
lcd.print("Enter PIN: ");
if (key >= '0' && key <= '9') {
if(enteredPassword.length() < 16) { // Batasi panjang
enteredPassword += key;
}
}
else if (key == '#') { // Tombol '#' untuk konfirmasi
if (enteredPassword == correctPassword) {
grantAccess();
} else {
denyAccess();
}
enteredPassword = ""; // Reset password setelah dicek
}
else if (key == '*') { // Tombol '*' untuk hapus
enteredPassword = "";
displayStandbyMessage(); // Kembali ke pesan awal
}
// Update tampilan password
lcd.setCursor(0, 1);
lcd.print(" "); // Clear baris
lcd.setCursor(0, 1);
for (int i = 0; i < enteredPassword.length(); i++) {
lcd.print("*"); // Tampilkan '*' untuk setiap digit
}
}
// Fungsi untuk menangani scan kartu RFID
void handleRfidScan() {
String scannedUID = "";
for (byte i = 0; i < rfid.uid.size; i++) {
scannedUID += (rfid.uid.uidByte[i] < 0x10 ? " 0" : " ");
scannedUID += String(rfid.uid.uidByte[i], HEX);
}
scannedUID.toUpperCase();
scannedUID.trim(); // Hapus spasi di awal
Serial.println("Kartu terdeteksi: " + scannedUID);
if (scannedUID == authorizedUID) {
grantAccess();
} else {
denyAccess();
}
rfid.PICC_HaltA(); // Hentikan pembacaan kartu saat ini
rfid.PCD_StopCrypto1();
}
// Fungsi jika akses diberikan (Accepted)
void grantAccess() {
beep_success(); // (TAMBAHAN) Bunyikan beep sukses
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Access Accepted");
digitalWrite(LED_GREEN_PIN, HIGH);
digitalWrite(LED_RED_PIN, LOW);
myServo.write(90); // Buka kunci (posisi 90 derajat)
delay(5000); // Pintu terbuka selama 5 detik
lockDoor(); // Kunci kembali pintu
}
// Fungsi jika akses ditolak (Denied)
void denyAccess() {
beep_fail(); // (TAMBAHAN) Bunyikan beep gagal
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Access Denied");
// Kedipkan LED merah 3 kali
for(int i=0; i<3; i++) {
digitalWrite(LED_RED_PIN, HIGH);
delay(200);
digitalWrite(LED_RED_PIN, LOW);
delay(200);
}
delay(1000);
displayStandbyMessage(); // Kembali ke pesan standby
}
// Fungsi untuk mengunci pintu dan reset state
void lockDoor() {
myServo.write(0); // Kunci pintu (posisi 0 derajat)
digitalWrite(LED_GREEN_PIN, LOW);
enteredPassword = "";
displayStandbyMessage();
}
// Fungsi untuk menampilkan pesan standby
void displayStandbyMessage() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Input Password");
lcd.setCursor(0, 1);
lcd.print("or Scan Card");
}
// (FUNGSI BARU) Beep untuk sukses
void beep_success() {
digitalWrite(BUZZER_PIN, HIGH);
delay(150); // Beep 1x
digitalWrite(BUZZER_PIN, LOW);
}
// (FUNGSI BARU) Beep untuk gagal
void beep_fail() {
digitalWrite(BUZZER_PIN, HIGH);
delay(75);
digitalWrite(BUZZER_PIN, LOW);
delay(75);
digitalWrite(BUZZER_PIN, HIGH);
delay(75);
digitalWrite(BUZZER_PIN, LOW);
}