diff --git a/Kode Program Arduino/tugas_akhir.ino b/Kode Program Arduino/tugas_akhir.ino new file mode 100644 index 0000000..5b84c67 --- /dev/null +++ b/Kode Program Arduino/tugas_akhir.ino @@ -0,0 +1,423 @@ +#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."); + } +} +