#include #include #include #include #include LiquidCrystal lcd(32, 15, 33, 27, 14, 13); //intialize pins for LCD display #define FIREBASE_HOST "https://esp32-led-4ebe6.firebaseio.com/" // the project name address from firebase id #define FIREBASE_AUTH "PqraRQDqfQmHnCZnHkPA3vmyNYVKuphzYFbgtEwC" // the secret key generated from firebase //Define FirebaseESP32 data object FirebaseData firebaseData; const char *ssid = ""; const char *password = ""; //related to NTP time client WiFiUDP ntpUDP; NTPClient timeClient(ntpUDP); String formattedDate; String FormattedTime; String actualTime; //time string received from NTP server String alarmString = ""; // alarm time string received from firebase //related to alarm/simon says mechanism int alarm_condition = 0; //controls alarm beeping int buzzerState = LOW; //allows for PWM beeping without delay int simon_start = 0; //initializes Simon Says game int simonStartState = LOW; //controls LEDs flashing before player presses button to start Simon Says game int alarm_ring = 0; // keeps alarm beeping off during Simon Says game int memory = 0; //keeps time display off during Simon Says game //related to no delay unsigned long currentMillis = 0; unsigned long timeMillis = 0; //enables no delay when updating time display unsigned long alarmMillis = 0; //enables no delay when alarm is beeping unsigned long simonStartMillis = 0; //enables no delay when waiting for player to start Simon Says game const long interval = 1000; //1 sec delay in updating time display const long simonStartInterval = 1000; //1 sec delay when waiting for player to start Simon Says game const long beep = 500; //.5 sec delay between beeps //related to PWM buzzer const int freq = 5000; const int buzzerChannel = 0; const int resolution = 8; #define led_off 0 //Used to control LEDs #define choice_none 0 //Used to check buttons #define choice_red (1 << 0) #define choice_green (1 << 1) #define choice_blue (1 << 2) #define choice_yellow (1 << 3) //LED pin definitions #define led_red 17 #define led_green 26 #define led_blue 25 #define led_yellow 16 // Button pin definitions #define button_red 23 #define button_green 19 #define button_blue 22 #define button_yellow 18 // Buzzer pin definition #define buzzer 5 #define entry_time_limit 3000 // Define game parameters String roundsString = ""; int rounds = 5; //Number of rounds to succesfully remember before player turns off alarm, preset as 5 byte gameBoard[32]; //Array that ontains the combination of buttons as player advances byte gameRound = 0; //Counts the number of succesful rounds the player has made it through void setup() { Serial.begin(115200); WiFi.begin(ssid, password); // try to connect with wifi Serial.print("Connecting to "); Serial.print(ssid); while (WiFi.status() != WL_CONNECTED) { Serial.print("."); delay(500); } Serial.println(); Serial.print("Connected to "); Serial.println(ssid); ledcSetup(buzzerChannel, freq, resolution); //PWM buzzer setup ledcAttachPin(buzzer, buzzerChannel); Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH); // connect to firebase Firebase.reconnectWiFi(true); Firebase.set(firebaseData, "/ALARM_TIME", "OFF"); // set initial string of "OFF" for ALARM_TIME Firebase.set(firebaseData, "/rounds", "5"); //set initial string of "5" for rounds timeClient.begin(); //initialize NTP time client timeClient.setTimeOffset(-25200); //offset by -7 hours for PST time zone lcd.begin(16, 2); //set up LCD display's # of columns and rows //Enable pull up resistors on buttons pinMode(button_red, INPUT_PULLUP); pinMode(button_green, INPUT_PULLUP); pinMode(button_blue, INPUT_PULLUP); pinMode(button_yellow, INPUT_PULLUP); pinMode(led_red, OUTPUT); pinMode(led_green, OUTPUT); pinMode(led_blue, OUTPUT); pinMode(led_yellow, OUTPUT); pinMode(buzzer, OUTPUT); } void loop() { currentMillis = millis(); if (currentMillis - timeMillis >= interval && memory == 0 && simon_start != 1) { //updates time displayed on LCD every second timeMillis = currentMillis; timeDisplay(); Firebase.get(firebaseData, "/ALARM_TIME"); // get alarm status input from firebase alarmString = firebaseData.stringData(); Firebase.get(firebaseData, "/rounds"); //get # of Simon Says rounds from firebase roundsString = firebaseData.stringData(); rounds = roundsString.toInt(); //convert string into integer } if (alarmString == actualTime && alarm_ring == 0) { // compare the input of alarm time received from firebase to real time alarm_condition = 1; //initialize function to buzz simon_start = 1; alarm_ring = 1; } if (alarm_condition == 1) { //function for alarm buzzing via PWM if (currentMillis - alarmMillis >= beep) { alarmMillis = currentMillis; if (buzzerState == LOW) { ledcWriteTone(buzzerChannel, 1500); ledcWrite (buzzerChannel, 125); buzzerState = HIGH; } else { ledcWriteTone(buzzerChannel, 1500); ledcWrite(buzzerChannel, 0); buzzerState = LOW; } } } byte button = checkButton(); if (currentMillis - simonStartMillis >= simonStartInterval && button == choice_none && simon_start == 1) //wait for player to press a button to start Simon game { simonStartMillis = currentMillis; lcd.setCursor(2, 0); lcd.print("Memory Game!"); if (simonStartState == LOW) { setLEDs(choice_red | choice_green); simonStartState = HIGH; } else { setLEDs(choice_yellow | choice_blue); simonStartState = LOW; } } button = checkButton(); if (button != choice_none && simon_start == 1) { //simon game start alarm_condition = 0; simon_start = 0; setLEDs (led_off); //turn off LEDs ledcWrite(buzzerChannel, 0); //turn off buzzer memory = 1; setLEDs(choice_red | choice_green | choice_blue | choice_yellow); // Turn all LEDs on delay(1000); setLEDs(led_off); // Turn off LEDs delay(250); if (simon() == true) { play_winner(); // Player won, play winner tones memory = 0; alarm_ring = 0; //turns time display back on lcd.clear(); //wipe memory game text to replace with time setLEDs (led_off); //turn off LEDs ledcWrite(buzzerChannel, 0); //turn off buzzer } else { //player loses and restarts beeping alarm_condition = 1; simon_start = 1; } } } void timeDisplay() { timeClient.update(); FormattedTime = timeClient.getFormattedTime(); //gives current PST time in HH:MM:SS int splitT = FormattedTime.indexOf("T"); actualTime = FormattedTime.substring(splitT + 1, FormattedTime.length() - 3); //splits current PST time string to HH:MM lcd.setCursor(5, 0); //begin display on line 1, space 5 lcd.print(actualTime); //print time to display } boolean simon() // Returns 0 if player loses, or 1 if player wins { randomSeed(millis()); // Seed the random generator with random amount of millis() gameRound = 0; // Reset the game to the beginning while (gameRound < rounds) { add_to_moves(); // Add a button to the current moves, then play them back playMoves(); // Play back the current game board //Require the player to repeat the sequence for (byte currentMove = 0 ; currentMove < gameRound ; currentMove++) { byte choice = wait_for_button(); // See what button the user presses if (choice != gameBoard[currentMove]) return false; // If the choice is incorect, player loses } delay(1000); // Player was correct, delay before playing moves } return true; // Player made it through all the rounds to win! } void playMoves() { for (byte currentMove = 0 ; currentMove < gameRound ; currentMove++) //playback current gameBoard { playLED(gameBoard[currentMove], 150); delay(150); // Wait some amount of time between button playback } } void add_to_moves() //adds new random button to gameBoard array by sampling timer { byte newButton = random(0, 4); //gives number between 0-3 inclusive if (newButton == 0) newButton = choice_red; //random number converted into specific color choices else if (newButton == 1) newButton = choice_green; else if (newButton == 2) newButton = choice_blue; else if (newButton == 3) newButton = choice_yellow; gameBoard[gameRound++] = newButton; // Add new button byte to the gameBoard array } //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= //The following functions control the hardware void setLEDs(byte leds) //lights specific LED according to choice byte { if ((leds & choice_red) != 0) digitalWrite(led_red, HIGH); else digitalWrite(led_red, LOW); if ((leds & choice_green) != 0) digitalWrite(led_green, HIGH); else digitalWrite(led_green, LOW); if ((leds & choice_blue) != 0) digitalWrite(led_blue, HIGH); else digitalWrite(led_blue, LOW); if ((leds & choice_yellow) != 0) digitalWrite(led_yellow, HIGH); else digitalWrite(led_yellow, LOW); } byte wait_for_button() //waits for button to be pressed and returns LED color as byte { long startTime = millis(); while ((millis() - startTime) < entry_time_limit) // Loop until button is pressed { byte button = checkButton(); if (button != choice_none) { playLED(button, 150); // Play the button the player just pressed while (checkButton() != choice_none) ; // wait for player to release button delay(10); // helps with debouncing and accidental double taps return button; } } } byte checkButton() // Returns a '1' bit in the position corresponding to choice_red, choice_green, etc. { if (digitalRead(button_red) == 0) return (choice_red); else if (digitalRead(button_green) == 0) return (choice_green); else if (digitalRead(button_blue) == 0) return (choice_blue); else if (digitalRead(button_yellow) == 0) return (choice_yellow); return (choice_none); // If no button is pressed, return none } void playLED(byte which, int LED_delay) //Light up an LED { setLEDs(which); //Turn on a given LED //Play the sound associated with the given LED switch (which) { case choice_red: ledcWriteTone(buzzerChannel, 440); ledcWrite (buzzerChannel, 125); delay (150); break; case choice_green: ledcWriteTone(buzzerChannel, 784); ledcWrite (buzzerChannel, 125); delay (150); break; case choice_blue: ledcWriteTone(buzzerChannel, 587); ledcWrite (buzzerChannel, 125); delay (150); break; case choice_yellow: ledcWriteTone(buzzerChannel, 880); ledcWrite (buzzerChannel, 125); delay (150); break; } ledcWrite (buzzerChannel, 0); //turn off buzzer setLEDs(led_off); // Turn off all LEDs } void play_winner() //play winner sound and lights { setLEDs(choice_green | choice_blue | choice_red | choice_yellow); winner_sound(); delay (100); setLEDs(choice_green | choice_blue | choice_red | choice_yellow); delay (100); setLEDs(choice_green | choice_blue | choice_red | choice_yellow); delay (100); setLEDs(choice_green | choice_blue | choice_red | choice_yellow); delay (100); } void winner_sound() //function for winner sound (final fantasy vii fanfare victory) { ledcWriteTone(buzzerChannel, 262); ledcWrite (buzzerChannel, 125); delay (100); ledcWrite (buzzerChannel, 0); delay (10); ledcWriteTone(buzzerChannel, 262); ledcWrite (buzzerChannel, 125); delay (100); ledcWrite (buzzerChannel, 0); delay (30); ledcWriteTone(buzzerChannel, 262); ledcWrite (buzzerChannel, 125); delay (100); ledcWrite (buzzerChannel, 0); delay (30); ledcWriteTone(buzzerChannel, 262); ledcWrite (buzzerChannel, 125); delay (300); ledcWrite (buzzerChannel, 0); delay (30); ledcWriteTone(buzzerChannel, 208); ledcWrite (buzzerChannel, 125); delay (300); ledcWrite (buzzerChannel, 0); delay (30); ledcWriteTone(buzzerChannel, 233); ledcWrite (buzzerChannel, 125); delay (300); ledcWrite (buzzerChannel, 0); delay (30); ledcWriteTone(buzzerChannel, 262); ledcWrite (buzzerChannel, 125); delay (180); ledcWrite (buzzerChannel, 0); delay (50); ledcWriteTone(buzzerChannel, 233); ledcWrite (buzzerChannel, 125); delay (100); ledcWrite (buzzerChannel, 0); delay (30); ledcWriteTone(buzzerChannel, 262); ledcWrite (buzzerChannel, 125); delay (300); ledcWrite (buzzerChannel, 0); }