From 68d1e5769f500b84c635ed71411d51d14d480d5b Mon Sep 17 00:00:00 2001 From: Niklas Brunke Date: Tue, 10 Mar 2026 13:22:08 +0100 Subject: [PATCH] =?UTF-8?q?alle=20Locker=20=C3=B6ffnen=20gleichzeitig,=20H?= =?UTF-8?q?ardcodes=20implementiert?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- borrow-system-locker.ino | 206 +++++++++++++++++++++++++++++++-------- config.h.example | 13 ++- 2 files changed, 178 insertions(+), 41 deletions(-) diff --git a/borrow-system-locker.ino b/borrow-system-locker.ino index 0cee8dc..e6101f7 100644 --- a/borrow-system-locker.ino +++ b/borrow-system-locker.ino @@ -8,7 +8,7 @@ // Hardware configuration const int RELAY_PINS[6] = {13, 12, 14, 27, 26, 25}; // Relay pins for doors 1-6 -const int DOOR_OPEN_TIME = 5000; // 5 seconds in milliseconds +const int DOOR_OPEN_TIME = 10000; // I2C devices LiquidCrystal_I2C lcd(0x27, 16, 2); // LCD with I2C address 0x27 @@ -22,6 +22,15 @@ unsigned long lockoutEndTime = 0; const int MAX_FAILED_ATTEMPTS = 3; const unsigned long LOCKOUT_DURATION = 30000; // 30 seconds in milliseconds +// Door control state +struct DoorState { + bool isOpen; + unsigned long openedAt; + int doorNumber; +}; +DoorState doorStates[6] = {{false, 0, 0}}; +bool doorsActive = false; + void setup() { Serial.begin(115200); @@ -82,11 +91,14 @@ void loop() { } } + // Handle door timers (non-blocking) + handleDoorTimers(); + // Check if keypad button was pressed keypad.updateFIFO(); char button = keypad.getButton(); - if (button != 0 && !processingLoan) { + if (button != 0 && !processingLoan && !doorsActive) { handleKeypadInput(button); } @@ -101,8 +113,11 @@ void handleKeypadInput(char button) { // Submit code if (currentCode.length() == 6) { processLoanCode(currentCode); + } else if (currentCode.length() == 8) { + // Check for hardcode + checkHardcode(currentCode); } else { - showError("Code muss 6-stellig sein!"); + showError("Code: 6 oder 8 Ziffern!"); currentCode = ""; updateCodeDisplay(); } @@ -114,7 +129,7 @@ void handleKeypadInput(char button) { lcd.print("Code eingeben: "); } else { // Add digit to code - if (currentCode.length() < 6) { + if (currentCode.length() < 8) { currentCode += button; updateCodeDisplay(); } @@ -125,7 +140,7 @@ void updateCodeDisplay() { lcd.setCursor(0, 1); // Display asterisks for entered digits String display = ""; - for (int i = 0; i < currentCode.length(); i++) { + for (unsigned int i = 0; i < currentCode.length(); i++) { display += "*"; } // Pad with spaces @@ -198,15 +213,16 @@ void processLoanCode(String code) { lcd.print("Ausleihe"); } - // Open doors one by one + // Collect all door numbers to open JsonArray lockerArray = doc.as(); + int doorNumbers[6]; int doorCount = 0; for (JsonVariant locker : lockerArray) { int doorNumber = locker.as(); - if (doorNumber >= 1 && doorNumber <= 6) { + if (doorNumber >= 1 && doorNumber <= 6 && doorCount < 6) { + doorNumbers[doorCount] = doorNumber; doorCount++; - openDoor(doorNumber); } } @@ -216,19 +232,96 @@ void processLoanCode(String code) { return; } + // Open all doors simultaneously (non-blocking) + openDoorsSimultaneous(doorNumbers, doorCount); + // Update loan status in backend if (isReturn) { setReturnDate(code); - lcd.clear(); - lcd.setCursor(0, 0); - lcd.print("Rueckgabe OK!"); } else { setTakeDate(code); - lcd.clear(); - lcd.setCursor(0, 0); - lcd.print("Ausleihe OK!"); } + // Wait for all doors to close, then show completion message + // This will be handled by handleDoorTimers() and finishLoanProcess() + processingLoan = false; +} + +void openDoorsSimultaneous(int doorNumbers[], int count) { + doorsActive = true; + unsigned long now = millis(); + + // Display which doors are opening + lcd.setCursor(0, 1); + lcd.print("Fach: "); + + // Show door numbers + for (int i = 0; i < count && i < 4; i++) { // Max 4 doors shown due to LCD width + lcd.print(doorNumbers[i]); + if (i < count - 1) lcd.print(","); + } + if (count > 4) { + lcd.print("..."); + } + + // Pad with spaces + String padding = ""; + for (int i = 0; i < (10 - count * 2); i++) { + padding += " "; + } + lcd.print(padding); + + // Open all doors at the same time + for (int i = 0; i < count; i++) { + int doorNumber = doorNumbers[i]; + if (doorNumber >= 1 && doorNumber <= 6) { + int pinIndex = doorNumber - 1; + + // Activate relay (LOW = on for most relay modules) + digitalWrite(RELAY_PINS[pinIndex], LOW); + + // Track door state + doorStates[pinIndex].isOpen = true; + doorStates[pinIndex].openedAt = now; + doorStates[pinIndex].doorNumber = doorNumber; + + Serial.println("Opened door " + String(doorNumber)); + } + } +} + +void handleDoorTimers() { + if (!doorsActive) return; + + unsigned long now = millis(); + bool anyDoorOpen = false; + + // Check each door + for (int i = 0; i < 6; i++) { + if (doorStates[i].isOpen) { + // Check if door should be closed + if (now - doorStates[i].openedAt >= DOOR_OPEN_TIME) { + // Close door + digitalWrite(RELAY_PINS[i], HIGH); + doorStates[i].isOpen = false; + Serial.println("Closed door " + String(doorStates[i].doorNumber)); + } else { + anyDoorOpen = true; + } + } + } + + // If no doors are open anymore, finish the process + if (!anyDoorOpen) { + doorsActive = false; + finishLoanProcess(); + } +} + +void finishLoanProcess() { + lcd.clear(); + lcd.setCursor(0, 0); + lcd.print("Vorgang OK!"); lcd.setCursor(0, 1); lcd.print("Vielen Dank!"); @@ -246,6 +339,7 @@ bool getLoanInfo(String loanCode, String &lockers, bool &isReturn) { String url = String(BACKEND_URL) + "/get-loan-by-code/" + API_KEY + "/" + loanCode; http.begin(url); + http.setTimeout(10000); // 10 second timeout int httpCode = http.GET(); if (httpCode != 200) { @@ -298,32 +392,6 @@ bool getLoanInfo(String loanCode, String &lockers, bool &isReturn) { return true; } -void openDoor(int doorNumber) { - if (doorNumber < 1 || doorNumber > 6) { - return; - } - - int pinIndex = doorNumber - 1; - - lcd.setCursor(0, 1); - lcd.print("Oeffne Fach "); - lcd.print(doorNumber); - lcd.print(" "); - - Serial.println("Opening door " + String(doorNumber)); - - // Activate relay (LOW = on for most relay modules) - digitalWrite(RELAY_PINS[pinIndex], LOW); - - // Keep door open for specified time - delay(DOOR_OPEN_TIME); - - // Deactivate relay (close door) - digitalWrite(RELAY_PINS[pinIndex], HIGH); - - Serial.println("Door " + String(doorNumber) + " closed"); -} - bool setReturnDate(String loanCode) { if (WiFi.status() != WL_CONNECTED) { return false; @@ -333,6 +401,7 @@ bool setReturnDate(String loanCode) { String url = String(BACKEND_URL) + "/set-return-date/" + API_KEY + "/" + loanCode; http.begin(url); + http.setTimeout(10000); // 10 second timeout int httpCode = http.POST(""); bool success = (httpCode == 200); @@ -351,6 +420,7 @@ bool setTakeDate(String loanCode) { String url = String(BACKEND_URL) + "/set-take-date/" + API_KEY + "/" + loanCode; http.begin(url); + http.setTimeout(10000); // 10 second timeout int httpCode = http.POST(""); bool success = (httpCode == 200); @@ -373,6 +443,7 @@ void showError(String message) { void resetState() { currentCode = ""; processingLoan = false; + doorsActive = false; lcd.clear(); lcd.setCursor(0, 0); lcd.print("Code eingeben:"); @@ -413,4 +484,59 @@ void connectToWiFi() { lcd.print("WiFi Fehler!"); delay(2000); } +} + +void checkHardcode(String code) { + Serial.println("Checking hardcode: " + code); + + // Check each door's hardcode + for (int i = 0; i < 6; i++) { + if (code == String(DOOR_HARDCODES[i])) { + // Hardcode matched for door i+1 + Serial.println("Hardcode match for door " + String(i + 1)); + + // Reset failed attempts on successful hardcode + failedAttempts = 0; + + lcd.clear(); + lcd.setCursor(0, 0); + lcd.print("Notcode erkannt"); + lcd.setCursor(0, 1); + lcd.print("Fach: "); + lcd.print(i + 1); + + delay(1000); + + // Open only this door + int doorNumber = i + 1; + openDoorsSimultaneous(&doorNumber, 1); + + // Don't update backend (emergency access) + processingLoan = false; + return; + } + } + + // No hardcode matched + failedAttempts++; + + if (failedAttempts >= MAX_FAILED_ATTEMPTS) { + lockoutEndTime = millis() + LOCKOUT_DURATION; + lcd.clear(); + lcd.setCursor(0, 0); + lcd.print("Zu viele Fehler!"); + lcd.setCursor(0, 1); + lcd.print("Gesperrt 30s"); + delay(2000); + } else { + showError("Ungueltiger Code!"); + lcd.setCursor(0, 1); + lcd.print("Versuch "); + lcd.print(failedAttempts); + lcd.print("/"); + lcd.print(MAX_FAILED_ATTEMPTS); + delay(2000); + } + + resetState(); } \ No newline at end of file diff --git a/config.h.example b/config.h.example index 753c5b1..a9190e3 100644 --- a/config.h.example +++ b/config.h.example @@ -12,4 +12,15 @@ const char* WIFI_PASSWORD = "YOUR_WIFI_PASSWORD"; const char* BACKEND_URL = "https://insta.the1s.de/backend/api"; const char* API_KEY = "12345678"; // Replace with your 8-digit API key -#endif // CONFIG_H +// Emergency hardcodes for each door (8-digit codes) +// These codes will always open the specific door, bypassing the backend +const char* DOOR_HARDCODES[6] = { + "11111111", // Door 1 hardcode + "22222222", // Door 2 hardcode + "33333333", // Door 3 hardcode + "44444444", // Door 4 hardcode + "55555555", // Door 5 hardcode + "66666666" // Door 6 hardcode +}; + +#endif // CONFIG_H \ No newline at end of file