commit 43b05c67e3a0cc15b5f6d5bcdfe70b71591e64c8 Author: fitriyah123 Date: Wed Jul 30 14:28:04 2025 +0700 Jadiin satu mobile, web, dan arduino: diff --git a/API laravel b/API laravel new file mode 160000 index 0000000..5c8f883 --- /dev/null +++ b/API laravel @@ -0,0 +1 @@ +Subproject commit 5c8f883954503de6c8681b500e1080d90fb63778 diff --git a/Arduino/codefix_numbered.ino b/Arduino/codefix_numbered.ino new file mode 100644 index 0000000..1b6dcb3 --- /dev/null +++ b/Arduino/codefix_numbered.ino @@ -0,0 +1,456 @@ +1) #include +2) #include +3) #include +4) #include +5) #include +6) #include +7) #include +8) +9) #define DEBUG_MODE true +10) +11) const char* ssid = "KOPI"; +12) const char* password = "digoreng123"; +13) const String API_BASE_URL = "https://smartlocker.punyapadias.my.id/api/"; +14) +15) #define SS_PIN 21 +16) #define RST_PIN 5 +17) MFRC522 mfrc522(SS_PIN, RST_PIN); +18) +19) LiquidCrystal_I2C lcd(0x27, 16, 2); +20) +21) const int trigPins[3] = {17, 16, 33}; +22) const int echoPins[3] = {35, 34, 32}; +23) +24) #define RELAY1_PIN 14 +25) #define RELAY2_PIN 27 +26) #define RELAY3_PIN 26 +27) +28) #define BUZZER_PIN 13 +29) +30) enum SystemState { +31) STATE_IDLE, +32) STATE_RFID_DETECTED, +33) STATE_OPENING_LOCKER, +34) STATE_REGISTERING_RFID, +35) STATE_ERROR +36) }; +37) SystemState currentState = STATE_IDLE; +38) +39) unsigned long lastApiCallTime = 0; +40) const long apiCallInterval = 5000; +41) unsigned long rfidActionStartTime = 0; +42) const long rfidActionDuration = 10000; +43) bool lcdIdleShown = false; +44) +45) +46) struct RFIDMapping { +47) String uid; +48) int lokerId; +49) int relayPin; +50) }; +51) +52) RFIDMapping rfidMappings[] = { +53) {"36CB3503", 1, RELAY1_PIN}, +54) {"5C312903", 2, RELAY2_PIN}, +55) {"611B2803", 3, RELAY3_PIN}, +56) }; +57) const int jumlahRFID = sizeof(rfidMappings) / sizeof(rfidMappings[0]); +58) +59) void setRFIDtoLoker(int lokerId, String rfid); +60) void updateStatusLoker(int lokerId, String status); +61) int getFirstEmptyRFIDLokerId(); +62) String getStatusLoker(int lokerId); +63) void clearRFID(); +64) void playBuzzer(int count, int durationMs, int pauseMs); +65) void displayLcdMessage(String line1, String line2, int duration = 0); +66) void handleRFIDAction(String uidStr, int mappedLokerId, int mappedRelayPin); +67) void handleNewRFIDRegistration(String uidStr); +68) +69) void displayDefaultScreen() { +70) lcd.clear(); +71) lcd.setCursor(0, 0); +72) lcd.print("Loker Pintar"); +73) lcd.setCursor(0, 1); +74) lcd.print("Scan Kartu"); +75) } +76) +77) void setup() { +78) Serial.begin(115200); +79) Wire.begin(4, 22); +80) lcd.init(); +81) lcd.backlight(); +82) lcd.setCursor(0, 0); +83) lcd.print("Inisialisasi..."); +84) +85) // Menyambung ke WiFi +86) WiFi.begin(ssid, password); +87) lcd.setCursor(0, 1); +88) lcd.print("WiFi connecting..."); +89) while (WiFi.status() != WL_CONNECTED) { +90) delay(500); +91) Serial.print("."); +92) } +93) +94) lcd.setCursor(0, 1); +95) lcd.print("WiFi connected "); +96) Serial.println("\nWiFi Connected. IP: " + WiFi.localIP().toString()); +97) +98) // Inisialisasi RFID +99) SPI.begin(); +100) mfrc522.PCD_Init(); +101) +102) // Inisialisasi sensor ultrasonik +103) for (int i = 0; i < 3; i++) { +104) pinMode(trigPins[i], OUTPUT); +105) pinMode(echoPins[i], INPUT); +106) } +107) +108) // Inisialisasi relay dan buzzer +109) pinMode(RELAY1_PIN, OUTPUT); digitalWrite(RELAY1_PIN, HIGH); +110) pinMode(RELAY2_PIN, OUTPUT); digitalWrite(RELAY2_PIN, HIGH); +111) pinMode(RELAY3_PIN, OUTPUT); digitalWrite(RELAY3_PIN, HIGH); +112) +113) pinMode(BUZZER_PIN, OUTPUT); +114) digitalWrite(BUZZER_PIN, LOW); +115) +116) // Tampilkan layar utama +117) lcd.clear(); +118) displayDefaultScreen(); +119) +120) lastApiCallTime = millis(); +121) } +122) +123) void loop() { +124) // Debug: tampilkan state saat ini setiap 1 detik +125) static unsigned long lastDebugTime = 0; +126) if (millis() - lastDebugTime > 1000) { +127) Serial.println("[DEBUG] Current state: " + String(currentState)); +128) lastDebugTime = millis(); +129) } +130) +131) // Recovery: jika RFID tidak terbaca dalam waktu lama, inisialisasi ulang +132) static unsigned long lastRFIDScanTime = 0; +133) if (millis() - lastRFIDScanTime > 10000) { +134) Serial.println("[RFID] Timeout, re-initialize RFID."); +135) mfrc522.PCD_Init(); +136) lastRFIDScanTime = millis(); +137) } +138) +139) switch (currentState) { +140) case STATE_IDLE: +141) // Tampilkan LCD hanya sekali saat idle +142) if (!lcdIdleShown) { +143) displayDefaultScreen(); +144) lcdIdleShown = true; +145) } +146) +147) // Cek kartu RFID +148) if (mfrc522.PICC_IsNewCardPresent() && mfrc522.PICC_ReadCardSerial()) { +149) lcdIdleShown = false; // agar layar bisa refresh nanti +150) playBuzzer(1, 50, 0); +151) lastRFIDScanTime = millis(); // reset timeout counter +152) +153) // Ambil UID +154) String uidStr = ""; +155) for (byte i = 0; i < mfrc522.uid.size; i++) { +156) if (mfrc522.uid.uidByte[i] < 0x10) uidStr += "0"; +157) uidStr += String(mfrc522.uid.uidByte[i], HEX); +158) } +159) uidStr.toUpperCase(); +160) +161) Serial.println("[RFID] UID: " + uidStr); +162) displayLcdMessage("RFID Terbaca:", uidStr); +163) +164) // Cek UID pada daftar +165) bool found = false; +166) int lokerId = -1; +167) int relayPin = -1; +168) for (int i = 0; i < jumlahRFID; i++) { +169) if (uidStr == rfidMappings[i].uid) { +170) found = true; +171) lokerId = rfidMappings[i].lokerId; +172) relayPin = rfidMappings[i].relayPin; +173) break; +174) } +175) } +176) +177) if (found) { +178) currentState = STATE_OPENING_LOCKER; +179) handleRFIDAction(uidStr, lokerId, relayPin); +180) } else { +181) // Jika tidak ditemukan, aktifkan buzzer "tit-tit-tit" dan tampilkan pesan +182) playBuzzer(3, 100, 100); // Bunyi 3 kali dengan interval 100ms +183) displayLcdMessage("Kartu Tidak", "Terdaftar!", 2000); +184) currentState = STATE_REGISTERING_RFID; +185) handleNewRFIDRegistration(uidStr); +186) } +187) +188) clearRFID(); +189) delay(200); // beri waktu recovery RFID +190) } +191) break; +192) +193) case STATE_REGISTERING_RFID: +194) case STATE_OPENING_LOCKER: +195) lcdIdleShown = false; +196) currentState = STATE_IDLE; +197) break; +198) +199) case STATE_ERROR: +200) if (WiFi.status() != WL_CONNECTED) { +201) displayLcdMessage("WiFi Disconnect!", "Reconnecting..."); +202) WiFi.reconnect(); +203) delay(1000); +204) } else { +205) lcdIdleShown = false; +206) currentState = STATE_IDLE; +207) } +208) break; +209) } +210) } +211) +212) +213) +214) +215) +216) void handleRFIDAction(String uidStr, int mappedLokerId, int mappedRelayPin) { +217) if (DEBUG_MODE) Serial.println("[RFID Action] Membuka Loker ID: " + String(mappedLokerId) + " dengan UID: " + uidStr); +218) +219) // Aktifkan relay untuk membuka loker +220) digitalWrite(mappedRelayPin, LOW); +221) playBuzzer(2, 70, 50); +222) if (DEBUG_MODE) Serial.println("[RFID Action] Relay " + String(mappedRelayPin) + " AKTIF (Membuka)."); +223) +224) // Menunggu beberapa detik sambil menampilkan jarak & status loker +225) unsigned long showStart = millis(); +226) float jarak = 0.0; +227) String status = ""; +228) +229) // Baca sensor ultrasonik hanya sekali +230) int trigPin = trigPins[mappedLokerId - 1]; +231) int echoPin = echoPins[mappedLokerId - 1]; +232) +233) // Tunggu 10 detik dan update status loker +234) while (millis() - showStart < 10000) { +235) // Menghitung jarak dengan sensor ultrasonik +236) digitalWrite(trigPin, LOW); +237) delayMicroseconds(2); +238) digitalWrite(trigPin, HIGH); +239) delayMicroseconds(10); +240) digitalWrite(trigPin, LOW); +241) +242) long durasi = pulseIn(echoPin, HIGH); +243) jarak = durasi * 0.034 / 2; // Menghitung jarak dalam cm +244) status = (jarak < 10) ? "digunakan" : "kosong"; // Status jika jarak < 10 cm dianggap 'digunakan' +245) +246) // Tampilkan informasi di LCD +247) displayLcdMessage("Loker " + String(mappedLokerId), +248) status + " | " + String(jarak, 0) + "cm"); +249) delay(500); // Mengurangi delay untuk responsifitas yang lebih cepat +250) } +251) +252) // Matikan relay setelah 10 detik +253) digitalWrite(mappedRelayPin, HIGH); +254) if (DEBUG_MODE) Serial.println("[RFID Action] Relay " + String(mappedRelayPin) + " NONAKTIF (Terkunci)."); +255) +256) // Perbarui status loker ke API +257) updateStatusLoker(mappedLokerId, status); +258) +259) // Kembali ke state idle setelah selesai +260) currentState = STATE_IDLE; +261) } +262) +263) +264) +265) void handleNewRFIDRegistration(String uidStr) { +266) displayLcdMessage("Mencari Loker", "Kosong..."); +267) int kosongLokerIdAPI = getFirstEmptyRFIDLokerId(); +268) +269) if (kosongLokerIdAPI != -1) { +270) setRFIDtoLoker(kosongLokerIdAPI, uidStr); +271) displayLcdMessage("RFID Diset", "Loker ID: " + String(kosongLokerIdAPI), 2000); +272) playBuzzer(1, 150, 0); +273) } else { +274) displayLcdMessage("Gagal Set RFID", "Loker Penuh", 2000); +275) playBuzzer(3, 100, 50); +276) } +277) } +278) +279) void updateStatusLoker(int lokerId, String status) { +280) if (WiFi.status() == WL_CONNECTED) { +281) HTTPClient http; +282) String url = API_BASE_URL + "lokers/" + String(lokerId) + "/status"; +283) +284) http.begin(url); +285) http.setTimeout(3000); +286) http.addHeader("Content-Type", "application/json"); +287) +288) String jsonPayload = "{\"status\": \"" + status + "\"}"; +289) int httpResponseCode = http.POST(jsonPayload); +290) +291) if (httpResponseCode > 0) { +292) String response = http.getString(); +293) if (DEBUG_MODE) Serial.println("[API] Status update response: " + response); +294) } else { +295) currentState = STATE_ERROR; +296) displayLcdMessage("API Gagal", "Update Status", 2000); +297) playBuzzer(2, 100, 50); +298) } +299) http.end(); +300) } else { +301) if (DEBUG_MODE) Serial.println("[API] WiFi belum terhubung, tidak bisa update status."); +302) currentState = STATE_ERROR; +303) displayLcdMessage("WiFi Disconnect!", "API Update Gagal", 2000); +304) playBuzzer(2, 100, 50); +305) } +306) } +307) +308) int getFirstEmptyRFIDLokerId() { +309) if (WiFi.status() == WL_CONNECTED) { +310) HTTPClient http; +311) String url = API_BASE_URL + "lokers/pertama-rfid-null"; +312) +313) http.begin(url); +314) http.setTimeout(3000); +315) int httpCode = http.GET(); +316) +317) if (httpCode == 200) { +318) String response = http.getString(); +319) StaticJsonDocument<256> doc; +320) DeserializationError error = deserializeJson(doc, response); +321) +322) if (error) return -1; +323) +324) if (doc.containsKey("data") && doc["data"].containsKey("id")) { +325) int parsedId = doc["data"]["id"].as(); +326) if (DEBUG_MODE) Serial.println("[API] ID loker kosong ditemukan: " + String(parsedId)); +327) http.end(); +328) return parsedId; +329) } else { +330) if (DEBUG_MODE) Serial.println("[API] Respons JSON tidak mengandung 'data.id'."); +331) http.end(); +332) return -1; +333) } +334) } else if (httpCode == 404) { +335) http.end(); +336) return -1; +337) } else { +338) currentState = STATE_ERROR; +339) http.end(); +340) } +341) } else { +342) currentState = STATE_ERROR; +343) displayLcdMessage("WiFi Disconnect!", "API Get Gagal", 2000); +344) playBuzzer(2, 100, 50); +345) } +346) return -1; +347) } +348) +349) void setRFIDtoLoker(int lokerId, String rfid) { +350) if (WiFi.status() == WL_CONNECTED) { +351) HTTPClient http; +352) String url = API_BASE_URL + "lokers/" + String(lokerId) + "/setrfid"; +353) +354) http.begin(url); +355) http.setTimeout(3000); +356) http.addHeader("Content-Type", "application/json"); +357) +358) String jsonPayload = "{\"rfid\": \"" + rfid + "\"}"; +359) int httpResponseCode = http.POST(jsonPayload); +360) +361) if (httpResponseCode > 0) { +362) String response = http.getString(); +363) if (DEBUG_MODE) Serial.println("[API] SET RFID Response: " + response); +364) StaticJsonDocument<256> doc; +365) DeserializationError error = deserializeJson(doc, response); +366) +367) if (!error && doc.containsKey("message")) { +368) String message = doc["message"].as(); +369) if (message.indexOf("RFID sudah digunakan") != -1) { +370) if (DEBUG_MODE) Serial.println("[API] Server Report: RFID sudah digunakan."); +371) displayLcdMessage("RFID Sudah", "Terdaftar", 2000); +372) playBuzzer(2, 100, 50); +373) } +374) } +375) } else { +376) if (DEBUG_MODE) Serial.println("[API] Gagal kirim set RFID: " + http.errorToString(httpResponseCode)); +377) currentState = STATE_ERROR; +378) displayLcdMessage("API Gagal", "Set RFID", 2000); +379) playBuzzer(2, 100, 50); +380) } +381) http.end(); +382) } else { +383) if (DEBUG_MODE) Serial.println("[API] WiFi belum terhubung, tidak bisa set RFID."); +384) currentState = STATE_ERROR; +385) displayLcdMessage("WiFi Disconnect!", "API Set RFID Gagal", 2000); +386) playBuzzer(2, 100, 50); +387) } +388) } +389) +390) String getStatusLoker(int lokerId) { +391) if (DEBUG_MODE) Serial.println("[API] getStatusLoker dipanggil untuk Loker " + String(lokerId)); +392) if (WiFi.status() == WL_CONNECTED) { +393) HTTPClient http; +394) String url = API_BASE_URL + "single-loker/" + String(lokerId); +395) +396) http.begin(url); +397) http.setTimeout(3000); +398) int httpCode = http.GET(); +399) if (DEBUG_MODE) Serial.println("[API] HTTP Code (getStatusLoker): " + String(httpCode)); +400) +401) if (httpCode == 200) { +402) String payload = http.getString(); +403) if (DEBUG_MODE) Serial.println("[API] GET LOKER Status Response: " + payload); +404) +405) StaticJsonDocument<256> doc; +406) DeserializationError error = deserializeJson(doc, payload); +407) +408) if (!error && doc.containsKey("data") && doc["data"].containsKey("status")) { +409) String status = doc["data"]["status"].as(); +410) if (DEBUG_MODE) Serial.println("[API] Status dari API: " + status); +411) http.end(); +412) return status; +413) } else { +414) if (DEBUG_MODE) Serial.println("[API] Parsing JSON error atau format tidak sesuai."); +415) if (DEBUG_MODE) Serial.println(error.c_str()); +416) http.end(); +417) } +418) } else if (httpCode == 404) { +419) if (DEBUG_MODE) Serial.println("[API] Loker " + String(lokerId) + " tidak ditemukan."); +420) http.end(); +421) return "NotFound"; +422) } else { +423) if (DEBUG_MODE) Serial.println("[API] Gagal ambil status loker: " + http.errorToString(httpCode)); +424) currentState = STATE_ERROR; +425) http.end(); +426) } +427) } else { +428) if (DEBUG_MODE) Serial.println("[API] WiFi belum terhubung, tidak bisa get status loker."); +429) currentState = STATE_ERROR; +430) } +431) return "Unknown"; +432) } +433) +434) void clearRFID() { +435) mfrc522.PICC_HaltA(); +436) mfrc522.PCD_StopCrypto1(); +437) if (DEBUG_MODE) Serial.println("[RFID] RFID Reader Direset."); +438) } +439) +440) void playBuzzer(int count, int durationMs, int pauseMs) { +441) for (int i = 0; i < count; i++) { +442) digitalWrite(BUZZER_PIN, HIGH); +443) delay(durationMs); +444) digitalWrite(BUZZER_PIN, LOW); +445) if (i < count - 1) delay(pauseMs); +446) } +447) } +448) +449) void displayLcdMessage(String line1, String line2, int duration) { +450) lcd.clear(); +451) lcd.setCursor(0, 0); +452) lcd.print(line1); +453) lcd.setCursor(0, 1); +454) lcd.print(line2); +455) if (duration > 0) delay(duration); +456) } \ No newline at end of file diff --git a/mobile-smart-locker b/mobile-smart-locker new file mode 160000 index 0000000..dd547f5 --- /dev/null +++ b/mobile-smart-locker @@ -0,0 +1 @@ +Subproject commit dd547f5e2f5d092e99b3f32a15882b4e3645d369