diff --git a/src/src/main.cpp b/src/src/main.cpp index 212a766..c85a191 100644 --- a/src/src/main.cpp +++ b/src/src/main.cpp @@ -33,6 +33,13 @@ bool isOpen = false; // enkodér int lastCLK = HIGH; +// blokace po špatných pokusech +constexpr byte MAX_WRONG_ATTEMPTS = 3; +constexpr unsigned long LOCKOUT_DURATION_MS = 30000UL; +byte wrongAttempts = 0; +bool lockedOut = false; +unsigned long lockoutStart = 0; + // maska – po kolika ms nečinnosti se heslo maskuje constexpr unsigned long MASK_DELAY_MS = 2000; unsigned long lastEncoderMove = 0; @@ -95,6 +102,15 @@ void NeutralLED() { analogWrite(RGB_RED_PIN, 0); } +// blikání červené během blokace +void BlockedLED() { + // bliká každých 500 ms + const bool blink = millis() / 500 % 2 == 0; + analogWrite(RGB_RED_PIN, blink ? 120 : 0); + analogWrite(RGB_GREEN_PIN, 0); + analogWrite(RGB_BLUE_PIN, 0); +} + void ButtonPressed() { if (savedPassword != "") { @@ -242,6 +258,58 @@ void setup() { } void loop() { + // Serial Monitor – příkaz "unblock" zruší blokaci + if (Serial.available()) { + String cmd = Serial.readStringUntil('\n'); + cmd.trim(); + if (cmd == "unblock") { + if (lockedOut) { + lockedOut = false; + wrongAttempts = 0; + Serial.println("[SERIAL] Blokace zrusena. Zamek je stale zamcen."); + CloseLED(); + password = 0; + masked = false; + lastEncoderMove = millis(); + showEntryScreen(true); + } else { + Serial.println("[SERIAL] Zamek neni zablokovan."); + } + } else { + Serial.println("[SERIAL] Nezname prikazani. Pouzij: unblock"); + } + } + + // blokace – čeká odpočítávání, neblokuje loop + if (lockedOut) { + if (const unsigned long elapsed = millis() - lockoutStart; elapsed >= LOCKOUT_DURATION_MS) { + // konec blokace + lockedOut = false; + wrongAttempts = 0; + Serial.println("Blokace skoncila."); + CloseLED(); + password = 0; + masked = false; + lastEncoderMove = millis(); + showEntryScreen(true); + } else { + // odpočítávání na LCD – aktualizuje jen každou sekundu + static unsigned long lastCountdownUpdate = 0; + if (millis() - lastCountdownUpdate >= 1000) { + lastCountdownUpdate = millis(); + const int remaining = static_cast((LOCKOUT_DURATION_MS - elapsed + 999) / 1000); + lcd.setCursor(0, 0); + lcd.printstr("Zablokovano! "); + lcd.setCursor(0, 1); + String line = "Zbyva: " + String(remaining) + "s "; + line = line.substring(0, 16); + lcd.printstr(line.c_str()); + } + BlockedLED(); + } + return; // zbytek loop se přeskočí + } + // čtení enkodéru – jen pokud je zamčeno // (při odemčeném stavu enkodér nemá smysl) if (!isOpen) { @@ -275,6 +343,7 @@ void loop() { // pokus o odemčení if (formatCode(password) == savedPassword) { isOpen = true; + wrongAttempts = 0; // reset po úspěšném odemčení OpenLock(); OpenLED(); OpenSound(); @@ -284,18 +353,40 @@ void loop() { lcd.setCursor(0, 1); lcd.printstr("Stiskni pro zamk"); } else { + // špatné heslo + wrongAttempts++; + Serial.print("Spatny pokus: "); + Serial.print(wrongAttempts); + Serial.print("/"); + Serial.println(MAX_WRONG_ATTEMPTS); + CloseSound(); - lcd.setCursor(0, 0); - lcd.printstr("Spatne heslo! "); - lcd.setCursor(0, 1); - lcd.printstr(" "); - delay(1500); + if (wrongAttempts >= MAX_WRONG_ATTEMPTS) { + // spustit blokaci + lockedOut = true; + lockoutStart = millis(); + Serial.println("Zamek zablokovan na 30 sekund. Pouzij 'unblock' pro zruseni."); - // návrat na zadávací obrazovku, hodnota zachována - masked = false; - lastEncoderMove = millis(); - showEntryScreen(true); + lcd.setCursor(0, 0); + lcd.printstr("Zablokovano! "); + lcd.setCursor(0, 1); + lcd.printstr("Zbyva: 30s "); + BlockedLED(); + } else { + lcd.setCursor(0, 0); + String warn = "Spatne! (" + String(wrongAttempts) + "/" + String(MAX_WRONG_ATTEMPTS) + ") "; + warn = warn.substring(0, 16); + lcd.printstr(warn.c_str()); + lcd.setCursor(0, 1); + lcd.printstr(" "); + delay(1500); + + // návrat na zadávací obrazovku, hodnota zachována + masked = false; + lastEncoderMove = millis(); + showEntryScreen(true); + } } } else { // zamčení