#include #include #include #include #include #include #include #include // Deklarasi objek BluetoothSerial SerialBT; WebServer server(80); WiFiUDP ntpUDP; NTPClient timeClient(ntpUDP, "pool.ntp.org", 25200, 60000); // Waktu WIB (UTC +7) // Konfigurasi WiFi const char* ssid = "realme XT"; const char* password = "dimasdwi01"; // Konfigurasi keypad const byte ROWS = 4; // Empat baris pada keypad const byte COLS = 3; // Tiga kolom pada keypad char keys[ROWS][COLS] = { {'1','2','3'}, {'4','5','6'}, {'7','8','9'}, {'*','0','#'} }; byte rowPins[ROWS] = {15, 2, 0, 4}; // Pin yang terhubung ke baris keypad byte colPins[COLS] = {16, 17, 5}; // Pin yang terhubung ke kolom keypad Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS); // Variabel global char btAddress[18]; String btAddressStr = ""; const int EEPROM_SIZE = 512; const int EEPROM_SLOT_SIZE = 50; // Ukuran slot di EEPROM const char* adminAddress = "9C:6B:72:57:0C:10"; const int doorControlPin = 12; const int buzzerPin = 25; const int buttonPin = 18; const int magneticSwitchPin = 32; bool buzzerSounding = false; unsigned long buzzerStartTime = 0; unsigned long buzzerDuration = 0; bool previousDoorStatus = HIGH; bool currentDoorStatus = HIGH; String doorOpenerName; String doorOpenerAddress; String enteredCode = ""; String activityLog = ""; // String untuk menyimpan log aktivitas unsigned long lastKeyPressTime = 0; // Waktu terakhir tombol ditekan const unsigned long keyPressTimeout = 5000; // Timeout 5 detik // Memindai apakah perangkat Bluetooth ada void callback(esp_spp_cb_event_t event, esp_spp_cb_param_t *param) { if (event == ESP_SPP_SRV_OPEN_EVT) { Serial.println("Client mencoba terhubung dengan alamat:"); memset(btAddress, 0, sizeof(btAddress)); byte c = 0; byte v, v1, v2; const char hx[16] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' }; for (int i = 0; i < 6; i++) { Serial.printf("%02X", param->srv_open.rem_bda[i]); v = param->srv_open.rem_bda[i]; v1 = v & 0xF; v2 = (v >> 4) & 0xF; btAddress[c] = hx[v2]; c++; btAddress[c] = hx[v1]; c++; if (i < 5) { Serial.print(":"); btAddress[c] = ':'; c++; } } btAddressStr = btAddress; Serial.println(); Serial.print("Alamat: "); Serial.println(btAddressStr); if (btAddressStr == adminAddress) { Serial.println("Admin terhubung."); logActivity("Admin terhubung", btAddressStr, true); soundBuzzer(2, 100); sendIPAddress(); } else { int addr = findDeviceSlot(btAddressStr.c_str()); if (addr >= 0) { String record = EEPROM.readString(addr); if (record != "") { doorOpenerName = record.substring(0, record.indexOf(',')); // Nama perangkat pembuka pintu doorOpenerAddress = btAddressStr; // Gunakan alamat perangkat yang terhubung Serial.println("Client terhubung."); Serial.print("Stored record: "); Serial.println(record); Serial.print("Nama perangkat: "); Serial.println(doorOpenerName); Serial.print("Alamat perangkat: "); Serial.println(doorOpenerAddress); logActivity(doorOpenerName + " terhubung", doorOpenerAddress, true); soundBuzzer(2, 100); sendIPAddress(); } else { Serial.println("Client tidak diizinkan untuk terhubung."); SerialBT.disconnect(); logActivity("Client tidak diizinkan untuk terhubung", btAddressStr, true); soundBuzzer(1, 1000); } } else { Serial.println("Client tidak diizinkan untuk terhubung."); SerialBT.disconnect(); logActivity("Client tidak diizinkan untuk terhubung", btAddressStr, true); soundBuzzer(1, 1000); } } } } // Kode komunikasi diinisialisasi, pin diatur sebagai input atau output, EEPROM mulai berjalan void setup() { Serial.begin(115200); EEPROM.begin(EEPROM_SIZE); pinMode(doorControlPin, OUTPUT); digitalWrite(doorControlPin, LOW); pinMode(buzzerPin, OUTPUT); pinMode(buttonPin, INPUT_PULLUP); pinMode(magneticSwitchPin, INPUT_PULLUP); SerialBT.register_callback(callback); if (!SerialBT.begin("Door Lock")) { Serial.println("Terjadi kesalahan saat menginisialisasi Bluetooth"); } else { Serial.println("Bluetooth terinisialisasi"); } WiFi.begin(ssid, password); unsigned long startAttemptTime = millis(); while (WiFi.status() != WL_CONNECTED && millis() - startAttemptTime < 10000) { delay(100); Serial.print("."); } if (WiFi.status() == WL_CONNECTED) { Serial.println("WiFi terhubung"); Serial.print("IP address: "); Serial.println(WiFi.localIP()); server.on("/", handleRoot); server.begin(); timeClient.begin(); } else { Serial.println("Koneksi WiFi gagal, melanjutkan operasi offline."); } } // Menambahkan dan Menghapus Perangkat void loop() { if (WiFi.status() == WL_CONNECTED) { server.handleClient(); timeClient.update(); } if (SerialBT.available()) { String incomingData = ""; while (SerialBT.available()) { incomingData += char(SerialBT.read()); } Serial.print("Data diterima: "); Serial.println(incomingData); StaticJsonDocument<200> doc; DeserializationError error = deserializeJson(doc, incomingData); if (error) { Serial.print(F("deserializeJson() gagal: ")); Serial.println(error.f_str()); return; } const char* action = doc["action"]; const char* name = doc["name"]; const char* address = doc["address"]; const char* password = doc["password"]; if (btAddressStr == adminAddress) { if (strcmp(action, "add") == 0) { addDevice(name, address, password); logActivity(String(name) + ", " + address + " ditambahkan", "", false); } else if (strcmp(action, "delete") == 0) { deleteDevice(address, name); } } else { int addr = findDeviceSlot(btAddressStr.c_str()); if (addr >= 0) { if (strcmp(action, "open_door") == 0) { openDoor(doorOpenerName.c_str(), doorOpenerAddress.c_str()); // Gunakan nama dan alamat perangkat yang terhubung } else if (strcmp(action, "close_door") == 0) { closeDoor(); } } else { Serial.println("Client tidak diizinkan untuk mengontrol pintu."); } } } if (digitalRead(buttonPin) == LOW) { openDoorWithButton(); } if (buzzerSounding && millis() - buzzerStartTime >= buzzerDuration) { digitalWrite(buzzerPin, LOW); buzzerSounding = false; } currentDoorStatus = digitalRead(magneticSwitchPin); if (currentDoorStatus != previousDoorStatus) { previousDoorStatus = currentDoorStatus; } handleKeypadEntry(); } void addDevice(const char* name, const char* address, const char* password) { Serial.print("Menambahkan perangkat dengan nama: "); Serial.print(name); Serial.print(", alamat: "); Serial.print(address); Serial.print(", dan password: "); Serial.println(password); if (findDeviceSlot(address) == -1) { int addr = findEmptySlot(); if (addr != -1) { String record = String(name) + "," + String(address) + "," + String(password); EEPROM.writeString(addr, record); EEPROM.commit(); Serial.println("Perangkat ditambahkan ke EEPROM."); } else { Serial.println("EEPROM penuh, tidak dapat menambahkan perangkat."); } } else { Serial.println("Perangkat dengan alamat ini sudah ada."); } } void deleteDevice(const char* address, const char* name) { Serial.print("Menghapus perangkat dengan alamat: "); Serial.println(address); int addr = findDeviceSlot(address); if (addr != -1) { EEPROM.writeString(addr, ""); EEPROM.commit(); Serial.println("Perangkat dihapus dari EEPROM."); logActivity(String(name) + " dihapus", address, true); } else { Serial.println("Perangkat tidak ditemukan di EEPROM."); } } void openDoor(const char* name, const char* address) { Serial.println(String(name) + " membuka pintu."); Serial.print("Nama perangkat: "); Serial.println(name); Serial.print("Alamat perangkat: "); Serial.println(address); digitalWrite(doorControlPin, HIGH); delay(5000); digitalWrite(doorControlPin, LOW); logActivity(String(name) + " membuka pintu", address, true); } void openDoorWithButton() { Serial.println("Pintu dibuka dengan tombol."); digitalWrite(doorControlPin, HIGH); delay(5000); digitalWrite(doorControlPin, LOW); logActivity("Pintu dibuka dengan tombol", "", false); } void closeDoor() { Serial.println("Pintu ditutup"); digitalWrite(doorControlPin, LOW); } //pengecekan data bool isCodeValid(const String& code) { for (int addr = 0; addr < EEPROM_SIZE; addr += EEPROM_SLOT_SIZE) { String record = EEPROM.readString(addr); if (record != "") { int lastCommaIndex = record.lastIndexOf(','); if (lastCommaIndex != -1) { String storedCode = record.substring(lastCommaIndex + 1); if (storedCode == code) { return true; } } } } return false; } void logActivity(String name, String address, bool includeConnected) { time_t rawTime = timeClient.getEpochTime(); struct tm * timeInfo = localtime(&rawTime); char timeBuffer[20]; strftime(timeBuffer, sizeof(timeBuffer), "%H:%M - %d/%m/%Y", timeInfo); // Ubah format waktu untuk menyertakan tanggal lengkap String formattedTime = String(timeBuffer); String logEntry = formattedTime + " - " + name + (includeConnected ? " (" + address + ")" : ""); activityLog += "" + formattedTime + "" + name + (includeConnected ? " (" + address + ")" : "") + ""; Serial.println(logEntry); } // web server void handleRoot() { // Cek status pintu String doorStatus = digitalRead(magneticSwitchPin) == HIGH ? "Terbuka" : "Tertutup"; // Memperbaiki logika status pintu String html = "Log Aktivitas Smart Lock"; html += ""; html += ""; html += "
Status Pintu: " + doorStatus + "
"; html += "

Log Aktivitas Smart Lock

"; html += ""; html += activityLog; html += "
WaktuAktivitas
"; server.send(200, "text/html", html); } // penyimpanan data int findDeviceSlot(const char* address) { for (int addr = 0; addr < EEPROM_SIZE; addr += EEPROM_SLOT_SIZE) { String record = EEPROM.readString(addr); if (record.indexOf(address) != -1) { return addr; } } return -1; } int findEmptySlot() { for (int addr = 0; addr < EEPROM_SIZE; addr += EEPROM_SLOT_SIZE) { String record = EEPROM.readString(addr); if (record == "") { return addr; } } return -1; } void soundBuzzer(int beeps, int duration) { for (int i = 0; i < beeps; i++) { digitalWrite(buzzerPin, HIGH); delay(duration); digitalWrite(buzzerPin, LOW); delay(100); } } void handleKeypadEntry() { char key = keypad.getKey(); if (key) { lastKeyPressTime = millis(); // Set waktu terakhir tombol ditekan soundBuzzer(1, 100); // Suara buzzer setiap tombol ditekan Serial.print("Keypad input: "); Serial.println(key); if (key == '*') { enteredCode = ""; Serial.println("Kode yang dimasukkan direset."); } else if (key == '#') { Serial.println("Memverifikasi kode yang dimasukkan..."); Serial.print("Kode yang dimasukkan: "); Serial.println(enteredCode); if (enteredCode.length() == 0 || !isCodeValid(enteredCode)) { Serial.println("Kode salah atau tidak ada perangkat terdaftar."); logActivity("Kode salah atau tidak ada perangkat terdaftar", "", false); // Tambahkan log aktivitas soundBuzzer(1, 1000); // Buzzer berbunyi 1 kali lebih panjang } else { Serial.println("Kode benar."); String deviceName = getDeviceNameByCode(enteredCode); soundBuzzer(2, 100); // Buzzer berbunyi 2 kali openDoorWithKeypad(deviceName.c_str()); } enteredCode = ""; } else { enteredCode += key; } } // Cek apakah waktu timeout tercapai if (millis() - lastKeyPressTime >= keyPressTimeout && enteredCode != "") { Serial.println("Timeout: Kode yang dimasukkan salah."); logActivity("Timeout: Kode yang dimasukkan salah", "", false); // Tambahkan log aktivitas enteredCode = ""; soundBuzzer(1, 1000); // Buzzer berbunyi 1 kali lebih panjang } } void openDoorWithKeypad(const char* name) { Serial.println(String(name) + " membuka pintu dengan keypad."); digitalWrite(doorControlPin, HIGH); delay(5000); digitalWrite(doorControlPin, LOW); logActivity(String(name) + " membuka pintu dengan keypad", "", false); } //Pengiriman data ke aplikasi String getDeviceNameByCode(const String& code) { for (int addr = 0; addr < EEPROM_SIZE; addr += EEPROM_SLOT_SIZE) { String record = EEPROM.readString(addr); if (record != "") { int lastCommaIndex = record.lastIndexOf(','); if (lastCommaIndex != -1) { String storedCode = record.substring(lastCommaIndex + 1); if (storedCode == code) { int firstCommaIndex = record.indexOf(','); if (firstCommaIndex != -1) { return record.substring(0, firstCommaIndex); } } } } } return "Pengguna tidak dikenal"; } // Function to send the IP address to the connected Bluetooth client void sendIPAddress() { if (WiFi.status() == WL_CONNECTED) { String ipAddress = WiFi.localIP().toString(); String message = "{\"ip\":\"" + ipAddress + "\"}"; SerialBT.print(message); Serial.println("IP address sent: " + ipAddress); } else { Serial.println("WiFi not connected, cannot send IP address."); } }