commit dd9329713f2492c5bb7246fc2cf1e2d255f5f921 Author: thatscringebro Date: Thu Oct 5 22:37:03 2023 -0400 init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..89cc49c --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.pio +.vscode/.browse.c_cpp.db* +.vscode/c_cpp_properties.json +.vscode/launch.json +.vscode/ipch diff --git a/platformio.ini b/platformio.ini new file mode 100644 index 0000000..f015c4a --- /dev/null +++ b/platformio.ini @@ -0,0 +1,15 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[env:uno] +platform = atmelavr +board = uno +framework = arduino +monitor_speed = 115200 diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..57ee398 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,482 @@ +#include +#include +#include + +// Pin Definitions +#define MENU_BUTTON A2 +#define SET_BUTTON A3 +#define GAUCHE_BUTTON A4 +#define DROITE_BUTTON A5 +#define BUZZER_PIN 8 +#define ALARM_LED_PIN 13 +#define TEMPERATURE_SENSOR_PIN A0 +#define ALARM_SETTINGS_ADDRESS 0 +#define ALARM_SET_FLAG_ADDRESS 2 +#define LCD_D2 2 +#define LCD_D3 3 +#define LCD_D4 4 +#define LCD_D5 5 +#define LCD_D11 11 +#define LCD_D12 12 + +// LCD Configuration +LiquidCrystal lcd(LCD_D12, LCD_D11, LCD_D5, LCD_D4, LCD_D3, LCD_D2); + +// Global Variables +bool alarmEnabled = true; +bool editMode = false; +bool editingHour = false; +bool editingMinute = false; +bool editingSecond = false; +bool isAlarmSet = false; +bool menuButtonPressed = false; +bool setButtonPressed = false; +bool gaucheButtonPressed = false; +bool droiteButtonPressed = false; +unsigned int hour = 0; +unsigned int minute = 0; +unsigned int second = 0; +byte setHour = 12; +byte setMinute = 0; +byte setSecond = 0; +byte alarmHour = 0; +byte alarmMinute = 0; +float temperature = 0.0; +int ledTimer = 0; + +enum MenuState { + MENU_OFF, + MENU_TIME, + MENU_ALARM_TIME, + MENU_ALARM_STATUS +}; + +MenuState menuState = MENU_OFF; + +// Alarm State +enum AlarmState { + ALARM_OFF, + ALARM_ON, + ALARM_SNOOZE, +}; + +AlarmState alarmState = ALARM_OFF; +unsigned long alarmStartTime = 0; +const unsigned long snoozeDuration = 120000; // 2 minutes snooze duration (in milliseconds) + + +void updateTemperature() { + // Read temperature from the sensor and return the value + int valeur = analogRead(TEMPERATURE_SENSOR_PIN); + + //Formule pour transformer en degré -> 10000 pour resistance 10k, 3977 pour beta + double voltage = valeur * 5.0 / 1023.0; + double resistance = 10000.0 * voltage / (5.0 - voltage); + double tempKelvin = 1.0 / (1.0 / 298.15 + log(resistance / 10000.0) / 3977); + + double tempCelcius = tempKelvin - 273.15; + + temperature = tempCelcius; +} + +void updateTime() { + // Update the time variables based on the elapsed time + second = millis() / 1000; + minute = second / 60; + hour = second / 3600; + minute %= 60; + second %= 60; + hour %= 24; +} + + +void displayTime() { + // Display current time on the LCD + lcd.setCursor(0, 0); // Set cursor to top-left corner + char str[16]; + snprintf(str, sizeof(str), "%02d:%02d:%02d", hour + setHour, minute + setMinute, second + setSecond); + lcd.print(str); +} + +void displayTemperature() { + // Display temperature on the LCD + lcd.setCursor(9, 0); // Set cursor to top-right corner + lcd.print(String(temperature, 2)); +} + +void displayAlarmStatus() { + // Display alarm status (ON/OFF) and time on the bottom row of the LCD + lcd.setCursor(0, 1); // Set cursor to the start of the second row + + char str[16]; + snprintf(str, sizeof(str), "%02d:%02d", alarmHour, alarmMinute); + + // Display alarm status and time + if (alarmEnabled) + { lcd.print(str); lcd.print(" (ON)"); } + else + { lcd.print(str); lcd.print(" (OFF)"); } +} + +void displayMenuTop(){ + lcd.setCursor(0, 0); + lcd.print("Menu: "); + lcd.setCursor(6, 0); + switch (menuState) { + case MENU_TIME: + lcd.print("Heure"); + break; + case MENU_ALARM_TIME: + lcd.print("Alarme"); + break; + case MENU_ALARM_STATUS: + lcd.print("Alarme"); + break; + } +} + +void displayMenuInfo(){ + lcd.setCursor(0, 1); + char str[16]; + switch (menuState) { + case MENU_TIME: + snprintf(str, sizeof(str), "%02d:%02d:%02d", hour + setHour, minute + setMinute, second); + lcd.print(str); + break; + case MENU_ALARM_TIME: + snprintf(str, sizeof(str), "%02d:%02d", alarmHour, alarmMinute); + lcd.print(str); + break; + case MENU_ALARM_STATUS: + if(alarmEnabled) + lcd.print("ON"); + else + lcd.print("OFF"); + break; + } +} + +void handleMenuButton() { + if(digitalRead(MENU_BUTTON)) + menuButtonPressed = false; + + if(!menuButtonPressed){ + if(!digitalRead(MENU_BUTTON)){ + if(alarmState == ALARM_ON){ + snoozeAlarm(); + return; + } + + switch (menuState) { + case MENU_OFF: + lcd.clear(); + menuState = MENU_TIME; + break; + case MENU_TIME: + lcd.clear(); + menuState = MENU_ALARM_TIME; + break; + case MENU_ALARM_TIME: + lcd.clear(); + menuState = MENU_ALARM_STATUS; + break; + case MENU_ALARM_STATUS: + lcd.clear(); + menuState = MENU_OFF; + break; + } + + menuButtonPressed = true; + } + } +} +void handleSetButton() { + if(digitalRead(SET_BUTTON)) + setButtonPressed = false; + + if(!setButtonPressed){ + if(!digitalRead(SET_BUTTON)){ + switch (menuState) { + case MENU_OFF: + break; + case MENU_TIME: + if(!editMode){ + editMode = true; + } + else{ + if(!editingHour){ + editingHour = true; + } + else{ + editingHour = false; + if(!editingMinute){ + editingMinute = true; + } + else{ + editingMinute = false; + if(!editingSecond){ + editingSecond = true; + } + else{ + editingSecond = false; + editMode = false; + } + } + } + } + break; + case MENU_ALARM_TIME: + if(!editMode){ + editMode = true; + } + else{ + if(!editingHour){ + editingHour = true; + } + else{ + editingHour = false; + if(!editingMinute){ + editingMinute = true; + } + else{ + editingMinute = false; + editMode = false; + setAlarm(); + } + } + } + break; + case MENU_ALARM_STATUS: + if(!editMode){ + editMode = true; + } + else{ + editMode = false; + } + break; + } + + setButtonPressed = true; + } + } +} +void handleGaucheButton() { + if(digitalRead(GAUCHE_BUTTON)) + gaucheButtonPressed = false; + + if(!gaucheButtonPressed){ + if(!digitalRead(GAUCHE_BUTTON)){ + if(alarmState == ALARM_ON){ + if(!digitalRead(DROITE_BUTTON)){ + stopAlarm(); + } + } + + switch (menuState) { + case MENU_OFF: + break; + case MENU_TIME: + if(editMode){ + if(editingHour){ + setHour++; + } + if(editingMinute){ + setMinute++; + } + if(editingSecond){ + setSecond++; + } + } + break; + case MENU_ALARM_TIME: + if(editMode){ + if(editingHour){ + alarmHour++; + } + if(editingMinute){ + alarmMinute++; + } + } + break; + case MENU_ALARM_STATUS: + if(editMode){ + lcd.clear(); + if(alarmEnabled) + alarmEnabled = false; + else + alarmEnabled = true; + } + break; + } + + gaucheButtonPressed = true; + } + } +} +void handleDroiteButton() { + if(digitalRead(DROITE_BUTTON)) + droiteButtonPressed = false; + + if(!droiteButtonPressed){ + if(!digitalRead(DROITE_BUTTON)){ + + switch (menuState) { + case MENU_OFF: + break; + case MENU_TIME: + if(editMode){ + if(editingHour){ + setHour--; + } + if(editingMinute){ + setMinute--; + } + if(editingSecond){ + setSecond--; + } + } + break; + case MENU_ALARM_TIME: + if(editMode){ + if(editingHour){ + alarmHour--; + } + if(editingMinute){ + alarmMinute--; + } + } + break; + case MENU_ALARM_STATUS: + break; + } + + droiteButtonPressed = true; + } + } +} + +void checkAlarm() { + if (alarmEnabled && (hour + setHour == alarmHour) && (minute + setMinute == alarmMinute) && alarmState == ALARM_OFF) { + // Set alarm state to sound + alarmState = ALARM_ON; + alarmStartTime = millis(); + } +} + +void stopAlarm() { + alarmState = ALARM_OFF; + noTone(BUZZER_PIN); + digitalWrite(ALARM_LED_PIN, LOW); +} + +void snoozeAlarm() { + alarmState = ALARM_SNOOZE; + alarmStartTime = millis(); +} + +void restoreAlarmSettings() { + // Read alarm settings from EEPROM and set variables accordingly + // If no settings are found, use default values + byte storedHour = EEPROM.read(ALARM_SETTINGS_ADDRESS); + byte storedMinute = EEPROM.read(ALARM_SETTINGS_ADDRESS + 1); + isAlarmSet = EEPROM.read(ALARM_SET_FLAG_ADDRESS); + + // Check if EEPROM contains valid alarm settings + if (isAlarmSet && storedHour != 255 && storedMinute != 255) { + alarmHour = storedHour; + alarmMinute = storedMinute; + } else { + // Default alarm time (12:01) if EEPROM is empty or contains invalid data + alarmHour = 12; + alarmMinute = 1; + isAlarmSet = false; + } +} + +void saveAlarmSettings() { + // Save alarm settings and the alarm set flag to EEPROM + EEPROM.write(ALARM_SETTINGS_ADDRESS, alarmHour); + EEPROM.write(ALARM_SETTINGS_ADDRESS + 1, alarmMinute); + EEPROM.write(ALARM_SET_FLAG_ADDRESS, isAlarmSet); +} + +void setAlarm() { + isAlarmSet = true; + + // Save alarm settings and the alarm set flag to EEPROM when the alarm is set + saveAlarmSettings(); +} + +void clearAlarm() { + // Clear the alarm and update the alarm set flag in EEPROM + alarmHour = 6; + alarmMinute = 0; + isAlarmSet = false; + saveAlarmSettings(); +} + +void setup() { + //For debugging + Serial.begin(115200); + + // Initialize LCD + lcd.begin(16, 2); + + // Restore alarm settings from EEPROM + restoreAlarmSettings(); + + // Initialize buttons as inputs + pinMode(MENU_BUTTON, INPUT_PULLUP); + pinMode(SET_BUTTON, INPUT_PULLUP); + pinMode(GAUCHE_BUTTON, INPUT_PULLUP); + pinMode(DROITE_BUTTON, INPUT_PULLUP); +} + +void loop() { + + + if(menuState == MENU_OFF){ + // Update temperature + updateTemperature(); + + // Update time + updateTime(); + + // Display information on LCD + displayTime(); + displayTemperature(); + displayAlarmStatus(); + + // Check and activate the alarm + checkAlarm(); + + // Handle the alarm state + switch (alarmState) { + case ALARM_OFF: + stopAlarm(); + break; + case ALARM_ON: + + tone(BUZZER_PIN, 300); + break; + case ALARM_SNOOZE: + // Check if snooze duration has passed + if (millis() - alarmStartTime >= snoozeDuration) { + alarmState = ALARM_ON; + alarmStartTime = millis(); + } + break; + } + } + else{ + displayMenuTop(); + displayMenuInfo(); + } + + // Handle button presses + handleMenuButton(); + handleSetButton(); + handleGaucheButton(); + handleDroiteButton(); +} + diff --git a/todo.txt b/todo.txt new file mode 100644 index 0000000..871917d --- /dev/null +++ b/todo.txt @@ -0,0 +1,28 @@ +DONE 1. Votre réveil matin doit afficher de façon fluide et sans lag différentes informations sur l’écran LCD (voir photo ci-haut pour un exemple) +DONE 1. L’heure courante, au format 24h (hh:mm:ss) +DONE 2. La température actuelle en degrés celcius, avec une décimale après la virgule. +DONE 3. L’heure de l’alarme, au format 24h (hh:mm) +DONE 4. Si l’alarme est activée ou non (ON/OFF) +DONE 5. Tout en respectant les formats d’affichage des heures ci-haut, les minutes et les secondes sont remplis avec des zéros à gauche, et + les heures avec un espace blanc à gauche si nécessaire, exemple: _6:08:54) de sorte que peu importe l’heure la longueur est toujours la même. + +DONE 2. Les informations de l’heure d’alarme doit être sauvegardée lorsqu’elle est modifiée et restaurée à chaque démarrage de votre arduino (eeprom) + +DONE 3. Lors du démarrage de votre arduino +DONE 1. Votre écran doit afficher l’heure par défaut qui est midi (12:00:00). +DONE 2. L’heure de l’alarme est la même que la dernière qui a été sauvegardée, ou 12:01 sinon. +DONE 3. L’alarme est activée par défaut + +4. Votre réveil-matin possède 4 boutons: +DONE 1. Menu: lorsqu’appuyé, entre en mode menu et affiche le premier élément du menu (voir plus bas pour la description du format des menus). + 2. Set: permet d’activer la modification d’une valeur dans le menu courant, et de l’accepter une fois modifiée + 3. Gauche et Droite: naviguer dans les différents menus et modifier les valeurs du menu actuel lorsqu’on est en mode modification + +5. Lorsque l’alarme se déclanche (l’heure courante est la même que l’heure de l’alarme ET l’alarme est activée): +DONE 1. Votre buzzer doit émettre un son/musique (au choix) à répétition tant que l’utilisateur n’a pas réagit + 2. La LED de l’alarme doit flasher en boucle en respectant une séquence de 250ms allumée suivi de 500ms éteinte. +DONE 3. Il est possible de “snoozer” en appuyant sur le bouton Menu (lorsque l’alarme est déclanchée, le bouton menu ne fait plus afficher le menu). Une fois le “snooze” +DONE appuyé, l’alarme se redéclanchera automatiquement au bout de 2 minutes. +DONE 4. Pour arrêter l’alarme une fois qu’elle s’est déclanchée, il faut appuyer simultanément sur les boutons Gauche et Droite. L’alarme reste active et se +DONE redéclanchera le lendemain à l’heure voulue +