#include #include #include #include #include // LCD Setup LiquidCrystal_I2C lcd(0x27, 20, 4); // I2C 20x4 display // DFPlayer setup HardwareSerial mp3Serial(1); #define MP3_RX 16 #define MP3_TX 17 DFRobotDFPlayerMini mp3; // Keypad setup const byte ROWS = 4; const byte COLS = 4; char keys[ROWS][COLS] = { {'1','2','3','A'}, {'4','5','6','B'}, {'7','8','9','C'}, {'*','0','#','D'} }; byte rowPins[ROWS] = {32, 33, 25, 26}; byte colPins[COLS] = {27, 14, 12, 13}; Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS); // Switches and buttons #define SWITCH1 15 #define SWITCH2 2 #define SWITCH3 4 #define SWITCH4 5 #define GREEN_BTN 18 #define RED_BTN 19 // State Variables bool switchesSet[4]; bool switchesLocked = false; bool codeLocked = false; bool countdownStarted = false; bool waitForReset = false; String disarmCode = ""; String enteredCode = ""; int timerSeconds = 0; unsigned long startTime = 0; unsigned long currentTime = 0; unsigned long lockoutUntil = 0; void setup() { Serial.begin(115200); Serial.println("=== SYSTEM BOOT ==="); lcd.init(); lcd.backlight(); mp3Serial.begin(9600, SERIAL_8N1, MP3_RX, MP3_TX); if (mp3.begin(mp3Serial)) { mp3.volume(25); Serial.println("DFPlayer ready"); } else { Serial.println("ERROR: DFPlayer not detected"); } pinMode(SWITCH1, INPUT_PULLUP); pinMode(SWITCH2, INPUT_PULLUP); pinMode(SWITCH3, INPUT_PULLUP); pinMode(SWITCH4, INPUT_PULLUP); pinMode(GREEN_BTN, INPUT_PULLDOWN); pinMode(RED_BTN, INPUT_PULLDOWN); promptForTimer(); } void loop() { // Always listen for reset if (waitForReset && digitalRead(RED_BTN) == HIGH) { delay(200); Serial.println("RESET TRIGGERED"); waitForReset = false; resetSystem(); return; } // STEP 1: Set switches if (!switchesLocked) { Serial.println("STATE: Waiting for switch config..."); if (digitalRead(GREEN_BTN) == HIGH) { delay(200); Serial.println("INPUT: Green button pressed to confirm switches"); switchesSet[0] = digitalRead(SWITCH1); switchesSet[1] = digitalRead(SWITCH2); switchesSet[2] = digitalRead(SWITCH3); switchesSet[3] = digitalRead(SWITCH4); switchesLocked = true; lcd.clear(); lcd.setCursor(0, 0); lcd.print("Switches Saved"); delay(1000); promptForCode(); } } // STEP 2: Code entry else if (!codeLocked) { char key = keypad.getKey(); if (key) { Serial.print("KEYPAD: "); Serial.println(key); if (key == '#') { codeLocked = true; Serial.println("CODE LOCKED IN"); lcd.clear(); lcd.setCursor(0, 0); lcd.print("Code Saved"); delay(1000); lcd.clear(); lcd.print("Press GREEN to"); lcd.setCursor(0, 1); lcd.print("start countdown"); } else if (disarmCode.length() < 6) { disarmCode += key; lcd.setCursor(0, 1); lcd.print("Code: "); for (int i = 0; i < disarmCode.length(); i++) lcd.print("*"); } } } // STEP 3: Start countdown else if (!countdownStarted) { Serial.println("STATE: Waiting to start timer..."); if (digitalRead(GREEN_BTN) == HIGH) { delay(200); Serial.println("EVENT: Timer started"); lcd.clear(); lcd.setCursor(0, 0); lcd.print("Timer Starts Now"); delay(1000); startTime = millis(); countdownStarted = true; } } // STEP 4: Timer logic else if (countdownStarted) { currentTime = millis(); int elapsed = (currentTime - startTime) / 1000; int remaining = timerSeconds - elapsed; if (remaining <= 0) { lcd.clear(); lcd.setCursor(0, 0); lcd.print("BOOM!"); Serial.println("EVENT: BOOM!"); mp3.play(3); countdownStarted = false; lcd.setCursor(0, 2); lcd.print("Press RED to reset"); waitForReset = true; return; } lcd.setCursor(0, 0); lcd.print("Time left: "); lcd.print(remaining); lcd.print("s "); bool match = switchesMatch(); lcd.setCursor(0, 1); lcd.print("Switches: "); lcd.print(match ? "OK " : "WRONG"); if (match) { lcd.setCursor(0, 2); lcd.print("Enter code: "); for (int i = 0; i < enteredCode.length(); i++) lcd.print("*"); lcd.setCursor(0, 3); lcd.print("Press # to check"); if (millis() >= lockoutUntil) { char key = keypad.getKey(); if (key) { Serial.print("KEYPAD ENTRY: "); Serial.println(key); if (key == '#') { if (enteredCode == disarmCode) { lcd.clear(); lcd.setCursor(0, 0); lcd.print("Bomb Disarmed!"); Serial.println("EVENT: Bomb disarmed"); mp3.play(4); countdownStarted = false; lcd.setCursor(0, 2); lcd.print("Press RED to reset"); waitForReset = true; } else { lcd.clear(); lcd.setCursor(0, 0); lcd.print("Wrong Code!"); Serial.println("ERROR: Wrong Code Entered"); mp3.play(5); lockoutUntil = millis() + 5000; enteredCode = ""; lcd.setCursor(0, 2); lcd.print("LOCKED 5s..."); } } else if (enteredCode.length() < 6) { enteredCode += key; } } } else { enteredCode = ""; // Clear buffer during lockout } } else { enteredCode = ""; // Reset if switches are wrong } } } // Prompt for timer void promptForTimer() { lcd.clear(); lcd.setCursor(0, 0); lcd.print("Enter Timer (sec)"); lcd.setCursor(0, 1); lcd.print("Then press #"); Serial.println("STATE: Waiting for timer..."); String temp = ""; while (true) { char key = keypad.getKey(); if (key) { Serial.print("KEYPAD TIMER: "); Serial.println(key); if (key == '#') break; if (key >= '0' && key <= '9') { temp += key; lcd.setCursor(0, 2); lcd.print("Time: "); lcd.print(temp); } } } timerSeconds = temp.toInt(); lcd.clear(); lcd.setCursor(0, 0); lcd.print("Timer Set: "); lcd.print(timerSeconds); lcd.print("s"); Serial.print("TIMER SET TO: "); Serial.println(timerSeconds); delay(1000); lcd.clear(); lcd.print("Set switches"); lcd.setCursor(0, 1); lcd.print("Then press GREEN"); } // Prompt for code void promptForCode() { lcd.clear(); lcd.setCursor(0, 0); lcd.print("Enter Code:"); Serial.println("STATE: Entering disarm code..."); } // Compare switch positions bool switchesMatch() { return switchesSet[0] == digitalRead(SWITCH1) && switchesSet[1] == digitalRead(SWITCH2) && switchesSet[2] == digitalRead(SWITCH3) && switchesSet[3] == digitalRead(SWITCH4); } // Reset system to initial state void resetSystem() { Serial.println("== SYSTEM RESET =="); disarmCode = ""; enteredCode = ""; switchesLocked = false; codeLocked = false; countdownStarted = false; lockoutUntil = 0; waitForReset = false; lcd.clear(); promptForTimer(); }