diff --git a/codefix.ino b/codefix.ino new file mode 100644 index 0000000..3910a1c --- /dev/null +++ b/codefix.ino @@ -0,0 +1,456 @@ +#include +#include +#include +#include +#include +#include +#include + +#define DEBUG_MODE true + +const char* ssid = "KOPI"; +const char* password = "digoreng123"; +const String API_BASE_URL = "https://smartlocker.punyapadias.my.id/api/"; + +#define SS_PIN 21 +#define RST_PIN 5 +MFRC522 mfrc522(SS_PIN, RST_PIN); + +LiquidCrystal_I2C lcd(0x27, 16, 2); + +const int trigPins[3] = {17, 16, 33}; +const int echoPins[3] = {35, 34, 32}; + +#define RELAY1_PIN 14 +#define RELAY2_PIN 27 +#define RELAY3_PIN 26 + +#define BUZZER_PIN 13 + +enum SystemState { + STATE_IDLE, + STATE_RFID_DETECTED, + STATE_OPENING_LOCKER, + STATE_REGISTERING_RFID, + STATE_ERROR +}; +SystemState currentState = STATE_IDLE; + +unsigned long lastApiCallTime = 0; +const long apiCallInterval = 5000; +unsigned long rfidActionStartTime = 0; +const long rfidActionDuration = 10000; +bool lcdIdleShown = false; + + +struct RFIDMapping { + String uid; + int lokerId; + int relayPin; +}; + +RFIDMapping rfidMappings[] = { + {"36CB3503", 1, RELAY1_PIN}, + {"5C312903", 2, RELAY2_PIN}, + {"611B2803", 3, RELAY3_PIN}, +}; +const int jumlahRFID = sizeof(rfidMappings) / sizeof(rfidMappings[0]); + +void setRFIDtoLoker(int lokerId, String rfid); +void updateStatusLoker(int lokerId, String status); +int getFirstEmptyRFIDLokerId(); +String getStatusLoker(int lokerId); +void clearRFID(); +void playBuzzer(int count, int durationMs, int pauseMs); +void displayLcdMessage(String line1, String line2, int duration = 0); +void handleRFIDAction(String uidStr, int mappedLokerId, int mappedRelayPin); +void handleNewRFIDRegistration(String uidStr); + +void displayDefaultScreen() { + lcd.clear(); + lcd.setCursor(0, 0); + lcd.print("Loker Pintar"); + lcd.setCursor(0, 1); + lcd.print("Scan Kartu"); +} + +void setup() { + Serial.begin(115200); + Wire.begin(4, 22); + lcd.init(); + lcd.backlight(); + lcd.setCursor(0, 0); + lcd.print("Inisialisasi..."); + + // Menyambung ke WiFi + WiFi.begin(ssid, password); + lcd.setCursor(0, 1); + lcd.print("WiFi connecting..."); + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + + lcd.setCursor(0, 1); + lcd.print("WiFi connected "); + Serial.println("\nWiFi Connected. IP: " + WiFi.localIP().toString()); + + // Inisialisasi RFID + SPI.begin(); + mfrc522.PCD_Init(); + + // Inisialisasi sensor ultrasonik + for (int i = 0; i < 3; i++) { + pinMode(trigPins[i], OUTPUT); + pinMode(echoPins[i], INPUT); + } + + // Inisialisasi relay dan buzzer + pinMode(RELAY1_PIN, OUTPUT); digitalWrite(RELAY1_PIN, HIGH); + pinMode(RELAY2_PIN, OUTPUT); digitalWrite(RELAY2_PIN, HIGH); + pinMode(RELAY3_PIN, OUTPUT); digitalWrite(RELAY3_PIN, HIGH); + + pinMode(BUZZER_PIN, OUTPUT); + digitalWrite(BUZZER_PIN, LOW); + + // Tampilkan layar utama + lcd.clear(); + displayDefaultScreen(); + + lastApiCallTime = millis(); +} + +void loop() { + // Debug: tampilkan state saat ini setiap 1 detik + static unsigned long lastDebugTime = 0; + if (millis() - lastDebugTime > 1000) { + Serial.println("[DEBUG] Current state: " + String(currentState)); + lastDebugTime = millis(); + } + + // Recovery: jika RFID tidak terbaca dalam waktu lama, inisialisasi ulang + static unsigned long lastRFIDScanTime = 0; + if (millis() - lastRFIDScanTime > 10000) { + Serial.println("[RFID] Timeout, re-initialize RFID."); + mfrc522.PCD_Init(); + lastRFIDScanTime = millis(); + } + + switch (currentState) { + case STATE_IDLE: + // Tampilkan LCD hanya sekali saat idle + if (!lcdIdleShown) { + displayDefaultScreen(); + lcdIdleShown = true; + } + + // Cek kartu RFID + if (mfrc522.PICC_IsNewCardPresent() && mfrc522.PICC_ReadCardSerial()) { + lcdIdleShown = false; // agar layar bisa refresh nanti + playBuzzer(1, 50, 0); + lastRFIDScanTime = millis(); // reset timeout counter + + // Ambil UID + String uidStr = ""; + for (byte i = 0; i < mfrc522.uid.size; i++) { + if (mfrc522.uid.uidByte[i] < 0x10) uidStr += "0"; + uidStr += String(mfrc522.uid.uidByte[i], HEX); + } + uidStr.toUpperCase(); + + Serial.println("[RFID] UID: " + uidStr); + displayLcdMessage("RFID Terbaca:", uidStr); + + // Cek UID pada daftar + bool found = false; + int lokerId = -1; + int relayPin = -1; + for (int i = 0; i < jumlahRFID; i++) { + if (uidStr == rfidMappings[i].uid) { + found = true; + lokerId = rfidMappings[i].lokerId; + relayPin = rfidMappings[i].relayPin; + break; + } + } + + if (found) { + currentState = STATE_OPENING_LOCKER; + handleRFIDAction(uidStr, lokerId, relayPin); + } else { + // Jika tidak ditemukan, aktifkan buzzer "tit-tit-tit" dan tampilkan pesan + playBuzzer(3, 100, 100); // Bunyi 3 kali dengan interval 100ms + displayLcdMessage("Kartu Tidak", "Terdaftar!", 2000); + currentState = STATE_REGISTERING_RFID; + handleNewRFIDRegistration(uidStr); + } + + clearRFID(); + delay(200); // beri waktu recovery RFID + } + break; + + case STATE_REGISTERING_RFID: + case STATE_OPENING_LOCKER: + lcdIdleShown = false; + currentState = STATE_IDLE; + break; + + case STATE_ERROR: + if (WiFi.status() != WL_CONNECTED) { + displayLcdMessage("WiFi Disconnect!", "Reconnecting..."); + WiFi.reconnect(); + delay(1000); + } else { + lcdIdleShown = false; + currentState = STATE_IDLE; + } + break; + } +} + + + + + +void handleRFIDAction(String uidStr, int mappedLokerId, int mappedRelayPin) { + if (DEBUG_MODE) Serial.println("[RFID Action] Membuka Loker ID: " + String(mappedLokerId) + " dengan UID: " + uidStr); + + // Aktifkan relay untuk membuka loker + digitalWrite(mappedRelayPin, LOW); + playBuzzer(2, 70, 50); + if (DEBUG_MODE) Serial.println("[RFID Action] Relay " + String(mappedRelayPin) + " AKTIF (Membuka)."); + + // Menunggu beberapa detik sambil menampilkan jarak & status loker + unsigned long showStart = millis(); + float jarak = 0.0; + String status = ""; + + // Baca sensor ultrasonik hanya sekali + int trigPin = trigPins[mappedLokerId - 1]; + int echoPin = echoPins[mappedLokerId - 1]; + + // Tunggu 10 detik dan update status loker + while (millis() - showStart < 10000) { + // Menghitung jarak dengan sensor ultrasonik + digitalWrite(trigPin, LOW); + delayMicroseconds(2); + digitalWrite(trigPin, HIGH); + delayMicroseconds(10); + digitalWrite(trigPin, LOW); + + long durasi = pulseIn(echoPin, HIGH); + jarak = durasi * 0.034 / 2; // Menghitung jarak dalam cm + status = (jarak < 10) ? "digunakan" : "kosong"; // Status jika jarak < 10 cm dianggap 'digunakan' + + // Tampilkan informasi di LCD + displayLcdMessage("Loker " + String(mappedLokerId), + status + " | " + String(jarak, 0) + "cm"); + delay(500); // Mengurangi delay untuk responsifitas yang lebih cepat + } + + // Matikan relay setelah 10 detik + digitalWrite(mappedRelayPin, HIGH); + if (DEBUG_MODE) Serial.println("[RFID Action] Relay " + String(mappedRelayPin) + " NONAKTIF (Terkunci)."); + + // Perbarui status loker ke API + updateStatusLoker(mappedLokerId, status); + + // Kembali ke state idle setelah selesai + currentState = STATE_IDLE; +} + + + +void handleNewRFIDRegistration(String uidStr) { + displayLcdMessage("Mencari Loker", "Kosong..."); + int kosongLokerIdAPI = getFirstEmptyRFIDLokerId(); + + if (kosongLokerIdAPI != -1) { + setRFIDtoLoker(kosongLokerIdAPI, uidStr); + displayLcdMessage("RFID Diset", "Loker ID: " + String(kosongLokerIdAPI), 2000); + playBuzzer(1, 150, 0); + } else { + displayLcdMessage("Gagal Set RFID", "Loker Penuh", 2000); + playBuzzer(3, 100, 50); + } +} + +void updateStatusLoker(int lokerId, String status) { + if (WiFi.status() == WL_CONNECTED) { + HTTPClient http; + String url = API_BASE_URL + "lokers/" + String(lokerId) + "/status"; + + http.begin(url); + http.setTimeout(3000); + http.addHeader("Content-Type", "application/json"); + + String jsonPayload = "{\"status\": \"" + status + "\"}"; + int httpResponseCode = http.POST(jsonPayload); + + if (httpResponseCode > 0) { + String response = http.getString(); + if (DEBUG_MODE) Serial.println("[API] Status update response: " + response); + } else { + currentState = STATE_ERROR; + displayLcdMessage("API Gagal", "Update Status", 2000); + playBuzzer(2, 100, 50); + } + http.end(); + } else { + if (DEBUG_MODE) Serial.println("[API] WiFi belum terhubung, tidak bisa update status."); + currentState = STATE_ERROR; + displayLcdMessage("WiFi Disconnect!", "API Update Gagal", 2000); + playBuzzer(2, 100, 50); + } +} + +int getFirstEmptyRFIDLokerId() { + if (WiFi.status() == WL_CONNECTED) { + HTTPClient http; + String url = API_BASE_URL + "lokers/pertama-rfid-null"; + + http.begin(url); + http.setTimeout(3000); + int httpCode = http.GET(); + + if (httpCode == 200) { + String response = http.getString(); + StaticJsonDocument<256> doc; + DeserializationError error = deserializeJson(doc, response); + + if (error) return -1; + + if (doc.containsKey("data") && doc["data"].containsKey("id")) { + int parsedId = doc["data"]["id"].as(); + if (DEBUG_MODE) Serial.println("[API] ID loker kosong ditemukan: " + String(parsedId)); + http.end(); + return parsedId; + } else { + if (DEBUG_MODE) Serial.println("[API] Respons JSON tidak mengandung 'data.id'."); + http.end(); + return -1; + } + } else if (httpCode == 404) { + http.end(); + return -1; + } else { + currentState = STATE_ERROR; + http.end(); + } + } else { + currentState = STATE_ERROR; + displayLcdMessage("WiFi Disconnect!", "API Get Gagal", 2000); + playBuzzer(2, 100, 50); + } + return -1; +} + +void setRFIDtoLoker(int lokerId, String rfid) { + if (WiFi.status() == WL_CONNECTED) { + HTTPClient http; + String url = API_BASE_URL + "lokers/" + String(lokerId) + "/setrfid"; + + http.begin(url); + http.setTimeout(3000); + http.addHeader("Content-Type", "application/json"); + + String jsonPayload = "{\"rfid\": \"" + rfid + "\"}"; + int httpResponseCode = http.POST(jsonPayload); + + if (httpResponseCode > 0) { + String response = http.getString(); + if (DEBUG_MODE) Serial.println("[API] SET RFID Response: " + response); + StaticJsonDocument<256> doc; + DeserializationError error = deserializeJson(doc, response); + + if (!error && doc.containsKey("message")) { + String message = doc["message"].as(); + if (message.indexOf("RFID sudah digunakan") != -1) { + if (DEBUG_MODE) Serial.println("[API] Server Report: RFID sudah digunakan."); + displayLcdMessage("RFID Sudah", "Terdaftar", 2000); + playBuzzer(2, 100, 50); + } + } + } else { + if (DEBUG_MODE) Serial.println("[API] Gagal kirim set RFID: " + http.errorToString(httpResponseCode)); + currentState = STATE_ERROR; + displayLcdMessage("API Gagal", "Set RFID", 2000); + playBuzzer(2, 100, 50); + } + http.end(); + } else { + if (DEBUG_MODE) Serial.println("[API] WiFi belum terhubung, tidak bisa set RFID."); + currentState = STATE_ERROR; + displayLcdMessage("WiFi Disconnect!", "API Set RFID Gagal", 2000); + playBuzzer(2, 100, 50); + } +} + +String getStatusLoker(int lokerId) { + if (DEBUG_MODE) Serial.println("[API] getStatusLoker dipanggil untuk Loker " + String(lokerId)); + if (WiFi.status() == WL_CONNECTED) { + HTTPClient http; + String url = API_BASE_URL + "single-loker/" + String(lokerId); + + http.begin(url); + http.setTimeout(3000); + int httpCode = http.GET(); + if (DEBUG_MODE) Serial.println("[API] HTTP Code (getStatusLoker): " + String(httpCode)); + + if (httpCode == 200) { + String payload = http.getString(); + if (DEBUG_MODE) Serial.println("[API] GET LOKER Status Response: " + payload); + + StaticJsonDocument<256> doc; + DeserializationError error = deserializeJson(doc, payload); + + if (!error && doc.containsKey("data") && doc["data"].containsKey("status")) { + String status = doc["data"]["status"].as(); + if (DEBUG_MODE) Serial.println("[API] Status dari API: " + status); + http.end(); + return status; + } else { + if (DEBUG_MODE) Serial.println("[API] Parsing JSON error atau format tidak sesuai."); + if (DEBUG_MODE) Serial.println(error.c_str()); + http.end(); + } + } else if (httpCode == 404) { + if (DEBUG_MODE) Serial.println("[API] Loker " + String(lokerId) + " tidak ditemukan."); + http.end(); + return "NotFound"; + } else { + if (DEBUG_MODE) Serial.println("[API] Gagal ambil status loker: " + http.errorToString(httpCode)); + currentState = STATE_ERROR; + http.end(); + } + } else { + if (DEBUG_MODE) Serial.println("[API] WiFi belum terhubung, tidak bisa get status loker."); + currentState = STATE_ERROR; + } + return "Unknown"; +} + +void clearRFID() { + mfrc522.PICC_HaltA(); + mfrc522.PCD_StopCrypto1(); + if (DEBUG_MODE) Serial.println("[RFID] RFID Reader Direset."); +} + +void playBuzzer(int count, int durationMs, int pauseMs) { + for (int i = 0; i < count; i++) { + digitalWrite(BUZZER_PIN, HIGH); + delay(durationMs); + digitalWrite(BUZZER_PIN, LOW); + if (i < count - 1) delay(pauseMs); + } +} + +void displayLcdMessage(String line1, String line2, int duration) { + lcd.clear(); + lcd.setCursor(0, 0); + lcd.print(line1); + lcd.setCursor(0, 1); + lcd.print(line2); + if (duration > 0) delay(duration); +} \ No newline at end of file