// import des librairies
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>           // Pour faire un serveur web
#include <ESP8266mDNS.h>                // Pour le DNS du serveur web  
#include <ESP8266HTTPUpdateServer.h>    // Pour la mettre à jour le programme par le réseau
#include <TimeLib.h> 
#include <Wire.h>                       // Pour communiquer avec l'écran par l I2C
#include <NtpClientLib.h>               // https://github.com/gmag11/NtpClient    Pour avoir la date et l'heure
#include <Ephemeris.h>                  // https://github.com/MarScaper/ephemeris Pour calculer l'heure du lever et coucher du soleil en fonction de sa position géographique
#include <LiquidCrystal_I2C.h>          // https://github.com/johnrickman/LiquidCrystal_I2C Pour utiliser l'écran LCD I2C 
#include "DHT.h"                        // https://github.com/adafruit/DHT-sensor-library Pour lire les sondes DHT

//*****************************************************************************************************\\
//******************  Partie à modifier avec vos paramètres  ******************************************\\
//*****************************************************************************************************\\

const charssid "XXXXX";                       // Le noms de votre réseau wifi
const charpassword "YYYYY";                   // La clé de votre réseau wifi
const charserveur "OOOOO";                    // L'adresse IP de votre serveur web (NAS, Raspberry pi ou hébergeur)
const charhost "terranodemcu";                // le noms qui remplace l'IP pour la fonction update 
const charupdate_path "/update";              // le chemin pour le fichier d' update
const charupdate_username "xxxxx";            // On défini ici le login pour la fonction update
const charupdate_password "yyyyy";            // On défini ici le mot de passe pour la fonction update
charville "Varage";                           // On donne le noms de sa position géographique
float lat 43.605201;                            // On donne sa latitude (https://www.coordonnees-gps.fr/)
float lon 5.955421;                             // On donne sa longitude
charserveurNTP "fr.pool.ntp.org";             // Le serveur NTP que l'on va interrogé
const byte timeZone 1;                          // GMT +1 (paris) 
const long interval 10000;                      // interval des relevés (pour la fonction millis)
unsigned int targetJour 28;                     // la température désiré le jour                  
unsigned int targetNuit 23;                     // la température désiré la nuit

// pour la fontion événement  les prenoms, dates anniversaires et heure d'avertissement
const charnoms[] = {"manu""sosso""yohan""clara"};  
int dateanniv[] = {2612100828062206};
int heureanniv[] = {7308001600163019302000};
// jour et heure d'avertissement du repas des serpents
int daterepas[] = {181624};
int heurerepas[] = {8302030};

      // les GPIO utilisé :
// pour la com I2C
const byte Sda 2;           // D4     
const byte Scl 4;           // D2 
// défini le capteur DHT22
const char DHTTYPE DHT22;   // DHT11, DHT21 ou DHT22
// Pins des sondes
const byte DHTPINPC 14;     // D5
const byte DHTPINPF 0;      // D3
// Pins des relais
const byte lum 16;          // D0    
const byte chauff 5;        // D1
// On défini le bouton
const byte  buttonPin 12;   // D6
// Détecteur de sécheresse
const byte PinHumi 13;      // D7
byte secheresse;             
// Le buzzer
const byte buzzerPin 15;    // D8
// Les LEDs
const byte ledPin1 1;       // D9
const byte ledPin2 3;       // D10

//*****************************************************************************************************\\
//*****************************************************************************************************\\

// les notes de musique
#define NOTE_B0  31
#define NOTE_C1  33
#define NOTE_CS1 35
#define NOTE_D1  37
#define NOTE_DS1 39
#define NOTE_E1  41
#define NOTE_F1  44
#define NOTE_FS1 46
#define NOTE_G1  49
#define NOTE_GS1 52
#define NOTE_A1  55
#define NOTE_AS1 58
#define NOTE_B1  62
#define NOTE_C2  65
#define NOTE_CS2 69
#define NOTE_D2  73
#define NOTE_DS2 78
#define NOTE_E2  82
#define NOTE_F2  87
#define NOTE_FS2 93
#define NOTE_G2  98
#define NOTE_GS2 104
#define NOTE_A2  110
#define NOTE_AS2 117
#define NOTE_B2  123
#define NOTE_C3  131
#define NOTE_CS3 139
#define NOTE_D3  147
#define NOTE_DS3 156
#define NOTE_E3  165
#define NOTE_F3  175
#define NOTE_FS3 185
#define NOTE_G3  196
#define NOTE_GS3 208
#define NOTE_A3  220
#define NOTE_AS3 233
#define NOTE_B3  247
#define NOTE_C4  262
#define NOTE_CS4 277
#define NOTE_D4  294
#define NOTE_DS4 311
#define NOTE_E4  330
#define NOTE_F4  349
#define NOTE_FS4 370
#define NOTE_G4  392
#define NOTE_GS4 415
#define NOTE_A4  440
#define NOTE_AS  455
#define NOTE_AS4 466
#define NOTE_B4  494
#define NOTE_C5  523
#define NOTE_CS5 554
#define NOTE_D5  587
#define NOTE_DS5 622
#define NOTE_E5  659
#define NOTE_F5  698
#define NOTE_FS5 740
#define NOTE_G5  784
#define NOTE_GSH  830
#define NOTE_GS5 831
#define NOTE_A5  880
#define NOTE_AS5 932
#define NOTE_B5  988
#define NOTE_C6  1047
#define NOTE_CS6 1109
#define NOTE_D6  1175
#define NOTE_DS6 1245
#define NOTE_E6  1319
#define NOTE_F6  1397
#define NOTE_FS6 1480
#define NOTE_G6  1568
#define NOTE_GS6 1661
#define NOTE_A6  1760
#define NOTE_AS6 1865
#define NOTE_B6  1976
#define NOTE_C7  2093
#define NOTE_CS7 2217
#define NOTE_D7  2349
#define NOTE_DS7 2489
#define NOTE_E7  2637
#define NOTE_F7  2794
#define NOTE_FS7 2960
#define NOTE_G7  3136
#define NOTE_GS7 3322
#define NOTE_A7  3520
#define NOTE_AS7 3729
#define NOTE_B7  3951
#define NOTE_C8  4186
#define NOTE_CS8 4435
#define NOTE_D8  4699
#define NOTE_DS8 4978

// TIMEOUT de la connexion NTP
#define NTP_TIMEOUT 1500  

// On défini le serveur web pour l' update
ESP8266WebServer httpServer(80);
ESP8266HTTPUpdateServer httpUpdater;

// On définie l'écran avec son adresse 0x27 pour le mien
LiquidCrystal_I2C lcd(0x27162);   

byte UTCOffset;                                                               // Offset pour prendre en ompte l'heure d'été pour le calcule du levé et couché du soleil                      
bool wifiFirstConnectedsyncEventTriggeredledStateflag_killer false;   // les flags dont on a besoin a l'état false
NTPSyncEvent_t ntpEvent;                                                      // pour stocker le retour des événements déclenché
unsigned long previousMillis 0;                                             // variable de temps pour la fonction millis  
unsigned int HnowHmatinHsoirHjourMjourHnuitMnuit;                 // les variables de temps pour nos calculs

// On défini les sondes
DHT dhtPC(DHTPINPCDHTTYPE);
DHT dhtPF(DHTPINPFDHTTYPE);

// On défini les variables pours les datas des sondes
float tC,hC,tF,hF;

// On définie les variables où seront stockées les caractères perso             
const byte HEAD 1
const byte TAIL 2;             
const byte CLEAR 3;
const byte SKULL 4;
const byte BONES 5;     
const byte ACCENT 6;  
const byte COEUR 7;
const byte REPAS 8;

// Le dessin des caractères HEAD TAIL CLEAR (https://maxpromer.github.io/LCD-Character-Creator/)
uint8_t snakeHead[8] = {0x110xa0x1f0x150xa0x110xe};
uint8_t snakeTail[8] = {0x40xe0x1b0x1b0xe0xe0x4};
uint8_t noSnake[8] = {0x00x00x00x00x00x00x0};
uint8_t tete[8] = {0x00x00x00x1F0x150x1F0x110x1F};
uint8_t os[8] = {0x110x0E0x0E0x110x00x00x00x0};
uint8_t eAigu[8] = {0x010x020x00x0E0x110x1F0x100x0F};
uint8_t heart[8] = {0x00xa0x1f0x1f0xe0x40x0};
uint8_t bell[8]  = {0x40xe0xe0xe0x1f0x00x4};

// Compteur de la fonction "sec" et "beep"
unsigned int alarmcompteur 0

// On déclare les variables temps pour gérer la boucle des événements
unsigned long tempsannivtempsrepas;

// fonction de connexion
void onSTAGotIP (WiFiEventStationModeGotIP ipInfo) {                 // lorsque l'on a une IP      
    wifiFirstConnected true;                                       // on active le flag de première connexion
}

// fonction de deconnexion
void onSTADisconnected (WiFiEventStationModeDisconnected event_info) {        // si on est déconnecté 
    NTP.stop();                                                               // on stop la synchro au serveur NTP
    WiFi.reconnect ();                                                        // on lance la reconnexion au wifi
}

// fonction de traitement des event avec le serveur NTP
void processSyncEvent (NTPSyncEvent_t ntpEvent) {                            
    if (ntpEvent == timeSyncd) {                             // si le serveur NTP nous repond correctement                  
        NTP.getTimeDateString (NTP.getLastNTPSync ());       // on synchronise l'heure
        if (NTP.isSummerTime ()) {                           // si c'est l'heure d'été
          UTCOffset 2;                                     // l'ofset vaut 2 
        else 
          UTCOffset 1;                                     // l'ofset vaut 1
        }  
        // on calcule le vevé et couché       
        printRiseAndSet(villelatlonUTCOffsetday(),month(),year());
        // on met le flag des chansons et événements à false au cas ou il a été activé
        flag_killer false;
    }
}

// fonction pour mettre 0 devant les nombres de 0 a 9, pour être sur 2 chiffres.
void printDigits(int digits){ 
  if(digits 10) {
    lcd.print('0');
  }
  lcd.print(digits);
}

// fonction qui affiche l'heure
void digitalClockDisplay(){  
  printDigits(hour());
  lcd.print(":");
  printDigits(minute());
  lcd.print(":");
  printDigits(second());  
}

// fonction qui affiche la date 
void digitalDateDisplay(){  
  printDigits(day());
  lcd.print("/");
  printDigits(month());
  lcd.print("/");
  printDigits(year());
}


// la fonction qui calcul le lever et coucher du soleil en fonction de sa position et de la date
void printRiseAndSet(char *cityFLOAT latitudeFLOAT longitudeint UTCOffsetint dayint monthint year) {
  Ephemeris::setLocationOnEarth(latitude,longitude);                                                          // definie notre location       
  SolarSystemObject sun Ephemeris::solarSystemObjectAtDateAndTime(Sun,day,month,year,0,0,0);                // pour avoir le levé et couché du soleil
  ifsun.riseAndSetState == RiseAndSetOk ) {                                                                 // si notre location est correcte
    int hours,minutes;    
    FLOAT seconds;    
    Ephemeris::floatingHoursToHoursMinutesSeconds(Ephemeris::floatingHoursWithUTCOffset(sun.rise,UTCOffset), &hours, &minutes, &seconds); // on réupère l'heure du levé
    Hjour hours;                                                                                                                        
    Mjour minutes;
    Hmatin hours 100 minutes;                                                                                                      // mise en forme pour les calculs (8:00 devient 800)  
    Ephemeris::floatingHoursToHoursMinutesSeconds(Ephemeris::floatingHoursWithUTCOffset(sun.set,UTCOffset), &hours, &minutes, &seconds); // on réupère l'heure du couché
    Hnuit hours;
    Mnuit minutes;
    Hsoir hours 100 minutes;                                                                                                       // mise en forme pour les calculs
  }  
}

// La fonction qui s'occupe du chauffage et de la lumière
void terrarium() {  
  byte target;             
  // Pour faciliter les calcul (21h03 devient 2103) 
  Hnow hour() * 100 minute();                 // Heure actuelle   
  if Hnow Hmatin && Hnow Hsoir ) {          // Si c'est le jour      
    target targetJour;                          // La consigne du chauffage est targetJour           
    digitalWrite(lumLOW);                       // on coupe le relais, ce qui alume la lumière
  }  
  else {                                          // Sinon , donc c'est la nuit                                   
    target targetNuit;                          // La consigne du chauffage est targetNuit    
    digitalWrite(lumHIGH);                      // on active le relais, ce qui coupe la lumière
  }
  // On lis la sondes point chaud
  hC dhtPC.readHumidity();  
  tC dhtPC.readTemperature();    
  // Lire la sonde point froid
  hF dhtPF.readHumidity();  
  tF dhtPF.readTemperature();     
  // si la temperature au point chaud est supérieur à la target OU si il y a un échèc de leture de la sonde     
  if (tC target 0.25 || isnan(tC)) {
    digitalWrite(chauffHIGH);            // on active le relais, ce qui coupe le haffage
  
  // si la temperature au point chaud est inférieur à la target 
  if (tC target 0.25) {                
    digitalWrite(chauffLOW);             // on coupe le relais, ce qui allume le chauffage
  }    
  if isnan(tC) || isnan(tF) ) {         // si il y a un échèc de leture de la sonde
    return;                               // on quitte la fonction terrarium
  }
  // si la lecture de la sonde est ok on continue 
  WiFiClient client;                              // Création de la connexion TCP 
  const int httpPort 80;                        // constante pour le port 80
  if (!client.connect(serveurhttpPort)) {       // si on n'arrive pas a se onnecter au serveur distant    
    return;                                       // on quitte la fonction terrarium  
  }         
  // si on la connexion au serveur distant est ok                                  
  // on envoi toutes ces datas par l'URL et par GET au fichier sonde.php sur le serveur (dans le dossier terranodemcu)
  client.print(String("GET /terranodemcu/sondes.php?tempC=") + String(float (tC)) + "&humiC=" String(float(hC)) + 
               "&tempF=" String(float(tF)) + "&humiF=" String(float(hF)) + "&Hjour=" String(int(Hjour)) + 
               "&Mjour=" String(int(Mjour)) + "&Hnuit=" String(int(Hnuit)) + "&Mnuit=" String(int(Mnuit)) +
               " HTTP/1.1\r\n" +  "Host: " serveur "\r\n" "Connection: close\r\n\r\n");   
  client.flush();   // on vide le buffer
}

// La fonction bouton qui lance l'affichage LCD et coupe les chansons ou événement si il est appuyé pendant une chanson.
void bouton() {                 
  int reading digitalRead(buttonPin);  // on lit l'état du bouton
  if (reading == 0) {                    // si on appuye
      flag_killer true;                // on passe ce flag à true, il sert à tuer une chanson ou un événement
      affichage();                       // on lance l'affichage      
  }    
}

// la fontion qui vérifie qu'il y a de l'eau
void sec() {   
  secheresse digitalRead(PinHumi);    // on lit la valeur du détecteur
  if (secheresse) {                     // si la valeur du détecteur vaut 1 c'est qu'il n'y a plus d'eau    
    // pour éviter de lancer l'alarme sur une fausse détection   
    alarm++;                            // on incrémente le compteur  
    if (alarm 2) {                    // au 3 eme tour de boucle
      eau();                            // on lance la fonction eau
      alarm 0;                        // on remet le compteur alarm à 0
    }          
  else {                           
    alarm 0;                          // si la valeur du détecteur vaut 0 alarm vaut 0;
  }  
}

// la fontion qui affiche qu'il n'y a pas d'eau et lance la chanson Starwars
void eau() {
  lcd.backlight();
  lcd.setCursor(1,0);
  lcd.write(SKULL);
  lcd.setCursor(4,0);
  lcd.print("Il n'y a");
  lcd.setCursor(14,0); 
  lcd.write(SKULL);   
  lcd.setCursor(11);
  lcd.write(BONES);  
  lcd.setCursor(3,1);
  lcd.print("plus d'eau");
  lcd.setCursor(14,1); 
  lcd.write(BONES);
  Hnow hour() * 100 minute();        // Heure actuelle      
  if Hnow 700 && Hnow 2200 ) {     // Si c'est le jour      
    Starwars();                          // On lance l'alarme
  else {                               // Sinon on me laisse dormir 
    delay(1500);        
  }
  lcd.clear();
  lcd.noBacklight();
}

// le setup 
void setup () {
  // On déclare les GPIO pour l' I2C (D1 et D2 par défaut)
   Wire.begin(Sda,Scl);
  // On initialise le LCD
  lcd.begin();  
  lcd.clear();
  lcd.setCursor(3,0);
  lcd.print("Debut de l '");
  lcd.setCursor(1,1);
  lcd.print("initialisation");
  delay(2000);
  static WiFiEventHandler e1e2;                        // on déclare 3  event sur le wifi: e1 e2 et e3
  e1 WiFi.onStationModeGotIP (onSTAGotIP);                 // la fonction de connexion bis  est associé a l'evenement Wifi e1
  e2 WiFi.onStationModeDisconnected (onSTADisconnected);   // la fonction de déconnexion est associé a l'evenement Wifi e2  
  WiFi.mode (WIFI_STA);                               // on definie le mode de Wifi 
  WiFi.begin (ssidpassword);                        // on demarre la connexion au réseau Wifi   
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);  
  }
  // on definie notre synchro
  NTP.onNTPSyncEvent ([](NTPSyncEvent_t event) {      // quand un evenement se produit
        ntpEvent event;                             // on definie nos event                              
        syncEventTriggered true;                    // on passe le flag syncEventTriggered a vrai 
    });  
  MDNS.begin(host);
  MDNS.addService("http""tcp"80);  
  // On déclare le buzzer en sortie   
  pinMode(buzzerPinOUTPUT);   
  // On déclare les pins des relais en sortie
  pinMode(lumOUTPUT);
  pinMode(chauffOUTPUT);
  // On initialise les DHT 
  dhtPC.begin();
  dhtPF.begin();
  // On déclare le GPIO du bouton et du détecteur de sécheresse en entrée avec la résistance de PULLUP: 
  pinMode(buttonPinINPUT_PULLUP);
  pinMode(PinHumiINPUT_PULLUP);  
  // les LED , après la déclaration des LED en sortie, on aura plus rien sur le port série
  // car elles sont branché sur le TX RX du NodeMCU il faut donc commenté ces 2 lignes pour le débug
  pinMode(ledPin1OUTPUT);
  pinMode(ledPin2OUTPUT);
  digitalWrite(ledPin1LOW);
  digitalWrite(ledPin2LOW);  
  // Création des caractères perso
  lcd.createChar(HEADsnakeHead);
  lcd.createChar(TAILsnakeTail);
  lcd.createChar(CLEARnoSnake);
  lcd.createChar(SKULLtete);
  lcd.createChar(BONESos);  
  lcd.createChar(ACCENTeAigu);
  lcd.createChar(COEURheart);
  lcd.createChar(REPASbell);
  // on defini la fonction de mise à jour avec nos paramètre (le serveur, le chemin, le login et mdp)          
  httpUpdater.setup(&httpServerupdate_pathupdate_usernameupdate_password);
  // on associe la page handle_Root a la racine du serveur web
  httpServer.on("/"handle_root);
  // on associe les page chansons a des alias 
  httpServer.on("/Star"handle_Star);
  httpServer.on("/Happy"handle_Happy);
  httpServer.on("/Game"handle_Game);  
  // on démarre le serveur web
  httpServer.begin();  
  lcd.clear();
  lcd.setCursor(3,0);
  lcd.print("Fin de l' ");
  lcd.setCursor(1,1);
  lcd.print("initialisation");
  delay(2000); 
  lcd.clear(); 
  lcd.noBacklight();    
}


// la boucle
void loop () {   
  MDNS.update();                                        // On maintient notre nom d'hote                                                      
  httpServer.handleClient();                            // On l'ance l'écoute sur le serveur
  bouton();                                             // On check le bouton
  if (wifiFirstConnected) {                             // Si le flag de la première connexion est activé
      wifiFirstConnected false;                       // On le bascule a false
      NTP.setInterval (63);                             // On régle l'interval de synchonisation en seconde  
      NTP.setNTPTimeout (NTP_TIMEOUT);                  // On régle le timout de synchonisation
      NTP.begin (serveurNTPtimeZonetrue);           // On démarre la syncho avec le serveur NTP toute les 63s
  }
  
  if (syncEventTriggered) {                             // Si une synchro est efféctuée
      processSyncEvent (ntpEvent);                      // On lance la fonction qui traite le retour de la synchro (erreur ou réussite)
      syncEventTriggered false;                       // On repasse le flag syncEventTriggered a false 
  }

  unsigned long currentMillis millis();               // Variable currentMillis vaut millis() ( le temps depuis le debut du programme)                     
  if (currentMillis previousMillis >= interval) {     // Sion dépasse ou atteint l'interval (donc ici toute les 10 secondes) 
    previousMillis currentMillis;                     // On reset notre compteur temps
    // on lance nos fonctions
    terrarium();                                        
    sec();
    evenement(); 
  }
}

// intro animation LCD 
void intro() {         
  lcd.setCursor(0,1);
  lcd.write(HEAD);   
  delay(200);  
  for (int i=0i<6i++) {
   int i+1;
   lcd.setCursor(i,1);
   lcd.write(TAIL);
   lcd.setCursor(j,1);
   lcd.write(HEAD);
   delay(200);
  }          
  lcd.setCursor(0,1);
  lcd.write(CLEAR);
  lcd.setCursor(6,1);
  lcd.write(TAIL);
  lcd.setCursor(7,0);
  lcd.write(HEAD);
  delay(200);      
  lcd.setCursor(0,0);
  lcd.print("Terra");
  for (int i=1i<7i++) {
   int i+6;
   int j+1;
   lcd.setCursor(i,1);
   lcd.write(CLEAR);
   lcd.setCursor(j,0);
   lcd.write(TAIL);
   lcd.setCursor(k,0);
   lcd.write(HEAD);
   delay(200);
  }   
  lcd.setCursor(7,1);
  lcd.print("NodeMCU");
  for (int i=7i<9i++) {
   int i+6;
   int j+1;
   lcd.setCursor(i,0);
   lcd.write(CLEAR);
   lcd.setCursor(j,0);
   lcd.write(TAIL);
   lcd.setCursor(k,0);
   lcd.write(HEAD);
   delay(200);
  }      
  lcd.setCursor(8,0);
  lcd.write(CLEAR);
  lcd.setCursor(15,0);
  lcd.write(TAIL);
  delay(200);
  for (int i=9i<16i++) {
   lcd.setCursor(i,0);
   lcd.write(CLEAR);
   delay(200);
  }   
  lcd.clear();
}

//sortie animation LCD  
void outro () {          
  lcd.setCursor(2,0);
  lcd.print("Bye bye !!!");
  lcd.setCursor(1,1);
  lcd.print("Terra-NodeMCU");
  delay(1500); 
  lcd.clear(); 
  lcd.noBacklight();
 }

// La fonction de l'affichage des datas des sondes en temps réel sur l'écran LCD ********
void affichage() {
  // on allume le retro-éclairage
  lcd.backlight();
  delay(100);    
  // on lance l'animation d'introduction
  intro();
  // on lance l'animation 
  lcd.setCursor(0,0);
  lcd.print("Nous sommes le :");
  lcd.setCursor(0,1);
  digitalDateDisplay();
  delay(1500); 
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Il est :");
  lcd.setCursor(0,1);
  digitalClockDisplay();
  delay(1500); 
  lcd.clear();    
  lcd.setCursor(3,0);
  lcd.print("Point chaud :");
  lcd.setCursor(0,1);
  lcd.print("Temp = ");
  lcd.print(float (tC));
  lcd.print(" ");
  lcd.write(223);
  lcd.print("C");
  delay(1500);    
  lcd.setCursor(0,1);
  lcd.print("Humi =  ");
  lcd.print(float (hC));
  lcd.print(" %");
  delay(1500);
  lcd.clear();    
  lcd.setCursor(3,0);
  lcd.print("Point froid :");
  lcd.setCursor(0,1);
  lcd.print("Temp = ");
  lcd.print(float (tF));
  lcd.print(" ");
  lcd.write(223);    // caractère spécial du °
  lcd.print("C");
  delay(1500);        
  lcd.setCursor(0,1);
  lcd.print("Humi =  ");
  lcd.print(float (hF));
  lcd.print(" %");
  delay(1500);
  lcd.clear();   
  // on lance l'animation de sortie
  outro();         
}

// la fonction qui gére les événements
void evenement(){
  int Hnow hour() * 100 minute();
  int DMnow day() * 100 month();  
  int Dnow day();    
  if (flag_killer == false) {                                           // si le flag est false
    for (int 0< (sizeof(dateanniv)/sizeof(int)); i++) {         // pour chaque date du tableau dateanniv
       if (DMnow == dateanniv[i]) {                                     // si elle est égale à la date d'aujourd'hui 
         for (int 0< (sizeof(heureanniv)/sizeof(int)); j++) {   // a chaque heure du tableau heureanniv on lancera la musique        
             if (Hnow == heureanniv[j]) {                 
                if((millis() - tempsanniv) > 10000) {   
                  lcd.backlight();
                  lcd.setCursor(1,0);
                  lcd.print("happy birthday");
                  lcd.setCursor(0,1);
                  lcd.write(COEUR);
                  lcd.write(COEUR);
                  lcd.write(COEUR);
                  lcd.setCursor(5,1);
                  lcd.print(noms[i]); 
                  lcd.setCursor(13,1); 
                  lcd.write(COEUR);
                  lcd.write(COEUR);
                  lcd.write(COEUR);                          
                  HappyBirthday();                
                  lcd.clear();
                  lcd.noBacklight();                                              
                  tempsanniv millis();         
                }              
             }                     
          }              
       
    }  
    for (int 0< (sizeof(daterepas)/sizeof(int)); i++) {          // pour chaque date du tableau daterepas   
       if (daterepas[i] == Dnow) {                                       // si elle est égale à la date d'aujourd'hui
         for (int 0< (sizeof(heurerepas)/sizeof(int)); j++) {    // a chaque heure du tableau heurerepas on lancera la musique                    
             if (Hnow == heurerepas[j]) {                   
                if((millis() - tempsrepas) > 20000) {                 
                  lcd.backlight();
                  lcd.setCursor(1,0);
                  lcd.print("c'est l'heure");
                  lcd.setCursor(0,1);
                  lcd.write(REPAS);
                  lcd.write(REPAS);                
                  lcd.setCursor(4,1);
                  lcd.print("du repas"); 
                  lcd.setCursor(14,1); 
                  lcd.write(REPAS);
                  lcd.write(REPAS);                                          
                  GameOfThrones();                
                  lcd.clear();
                  lcd.noBacklight();               
                  tempsrepas millis();         
                }              
             }                     
          }  
       }    
    }
  }
}

// la pages web d'accueil
void handle_root() {
  char page[] = "<body style='background:#7F7F7F;'>"               
  "<center><h2 style='color:#EC7878;'>La fonction Update</h2></center><br/>"
  "<center><p><a href=\"update\"><button style='background:#EC7878;border:2px solid black;font-size: 20px;padding: 20px 20px;border-radius: 25px;'>update du programme</button></a></p></center>"  
  "<center><h2>Commande des chansons</h2></center><br/>" 
  "<center><div>"
  "<p><a href=\"Star\"><button>Starwars</button></a> &nbsp; &nbsp; <a href=\"Happy\"><button>Happy Birthday</button></a> &nbsp; &nbsp;"  
  "<a href=\"Game\"><button>Game Of Thrones</button></a></p>"    
  "</center></div>"  
  "</body>";                
  httpServer.send(200"text/html"page); // repond avec la page web codee en HTML
}

// la pages web pour Starwars
void handle_Star() {     
  char page[] = "<body style='background:#7F7F7F;'>"
                "<div style='margin-top:10%;'>"
                "<center><h1>Starwars</h1></center><br/>"
                "<center><p><a href=\"/\"><button>Home</button></a></p></center>"
                "</div></body>";
  httpServer.send(200"text/html"page); // repond avec la page web codee en HTML
  Starwars();  
}

// la pages web pour Game Of Thrones
void handle_Game() {    
  char page[] = "<body style='background:#7F7F7F;'>"
                "<div style='margin-top:10%;'>"
                "<center><h1>Game Of Thrones</h1></center><br/>"
                "<center><p><a href=\"/\"><button>Home</button></a></p></center>"
                "</div></body>";
  httpServer.send(200"text/html"page); // repond avec la page web codee en HTML
  GameOfThrones();
}

// la pages web pour Happy Birthday
void handle_Happy() {    
  char page[] = "<body style='background:#7F7F7F;'>"
                "<div style='margin-top:10%;'>"
                "<center><h1>Happy Birthday</h1></center><br/>"
                "<center><p><a href=\"/\"><button>Home</button></a></p></center>"
                "</div></body>";
  httpServer.send(200"text/html"page); // repond avec la page web codee en HTML
  HappyBirthday();
}


// La fonction beep qui joue les notes et allume les leds
void beep(int noteint duree) {   
    int lecture digitalRead(buttonPin);   
    if (lecture == 0) {
      flag_killer true;
    }
    if (flag_killer == true) {
      noTone(buzzerPin);       
    else {         
      tone(buzzerPinnoteduree);     
      // choix des leds à allumer en fonction de la valeur de 'compteur' et de la durée de la note
      if(compteur == 0)
      {    
        digitalWrite(ledPin1, !ledState);    
        delay(duree);
        digitalWrite(ledPin1ledState);    
      
      else
      {    
        digitalWrite(ledPin2, !ledState);      
        delay(duree);
        digitalWrite(ledPin2ledState);   
      }       
      noTone(buzzerPin); 
      delay(50); 
      // On increment le compteur
      compteur++;
    }
}

////////////////////////// Les chansons ////////////////////////

//******* Starwars coté obscure**************** 
void firstSection()
{
  beep(NOTE_A4500);
  beep(NOTE_A4500);    
  beep(NOTE_A4500);
  beep(NOTE_F4350);
  beep(NOTE_C5150);  
  beep(NOTE_A4500);
  beep(NOTE_F4350);
  beep(NOTE_C5150);
  beep(NOTE_A4650); 
  delay(500); 
  beep(NOTE_E5500);
  beep(NOTE_E5500);
  beep(NOTE_E5500);  
  beep(NOTE_F5350);
  beep(NOTE_C5150);
  beep(NOTE_GS4500);
  beep(NOTE_F4350);
  beep(NOTE_C5150);
  beep(NOTE_A4650); 
  delay(500);
}
 
void secondSection()
{
  beep(NOTE_A5500);
  beep(NOTE_A4300);
  beep(NOTE_A4150);
  beep(NOTE_A5500);
  beep(NOTE_GSH325);
  beep(NOTE_G5175);
  beep(NOTE_FS5125);
  beep(NOTE_F5125);    
  beep(NOTE_FS5250); 
  delay(325); 
  beep(NOTE_AS250);
  beep(NOTE_DS5500);
  beep(NOTE_D5325);  
  beep(NOTE_CS5175);  
  beep(NOTE_C5125);  
  beep(NOTE_AS4125);  
  beep(NOTE_C5250);   
  delay(350);
}

void Starwars() 
{    
  firstSection();  
  secondSection(); 
  //Variant 1
  beep(NOTE_F4250);  
  beep(NOTE_GS4500);  
  beep(NOTE_F4350);  
  beep(NOTE_A4125);
  beep(NOTE_C5500);
  beep(NOTE_A4375);  
  beep(NOTE_C5125);
  beep(NOTE_E5650); 
  delay(500);  
  secondSection(); 
  //Variant 2
  beep(NOTE_F4250);  
  beep(NOTE_GS4500);  
  beep(NOTE_F4375);  
  beep(NOTE_C5125);
  beep(NOTE_A4500);  
  beep(NOTE_F4375);  
  beep(NOTE_C5125);
  beep(NOTE_A4650); 
  delay(650);
  compteur 0;
}

//******* GameOfThrones ****************
void GameOfThrones()
  {
    for(int i=0i<3i++)
    {
    beep(NOTE_G4500);     
    beep(NOTE_C4500);    
    beep(NOTE_DS4250);    
    beep(NOTE_F4250);    
    }
    for(int i=0i<3i++)
    {
    beep(NOTE_G4500);    
    beep(NOTE_C4500);    
    beep(NOTE_E4250);    
    beep(NOTE_F4250);    
    }
        beep(NOTE_G4500);
        beep(NOTE_C4500);        
        beep(NOTE_DS4250);
        beep(NOTE_F4250);
        beep(NOTE_D4500);        
    for(int i=0i<2i++)
    {
    beep(NOTE_G3500);
    beep(NOTE_AS3250);
    beep(NOTE_C4250);
    beep(NOTE_D4500);    
    }//
        beep(NOTE_G3500);
        beep(NOTE_AS3250);
        beep(NOTE_C4250);
        beep(NOTE_D41000);
        beep(NOTE_F41000);
        beep(NOTE_AS31000);
        beep(NOTE_DS4250);
        beep(NOTE_D4250);
        beep(NOTE_F41000);
        beep(NOTE_AS31000);
        beep(NOTE_DS4250);
        beep(NOTE_D4250);
        beep(NOTE_C4500);
    for(int i=0i<2i++)
    {
    beep(NOTE_GS3250);
    beep(NOTE_AS3250);
    beep(NOTE_C4500);
    beep(NOTE_F3500);    
    }
          beep(NOTE_G41000);
          beep(NOTE_C41000);
          beep(NOTE_DS4250);
          beep(NOTE_F4250);
          beep(NOTE_G41000);
          beep(NOTE_C41000);
          beep(NOTE_DS4250);
          beep(NOTE_F4250);
          beep(NOTE_D4500);          
    for(int i=0i<3i++)
    {
    beep(NOTE_G3500);
    beep(NOTE_AS3250);
    beep(NOTE_C4250);
    beep(NOTE_D4500);
    }
  compteur 0;
}


//******* Happy Birthday ****************
void HappyBirthday()
{
  beep(NOTE_G3200);
  beep(NOTE_G3200);
  beep(NOTE_A3500);
  beep(NOTE_G3500);
  beep(NOTE_C4500);
  beep(NOTE_B31000);
  beep(NOTE_G3200);
  beep(NOTE_G3200);
  beep(NOTE_A3500);
  beep(NOTE_G3500);
  beep(NOTE_D4500);
  beep(NOTE_C41000);
  beep(NOTE_G3200);
  beep(NOTE_G3200);
  beep(NOTE_G4500);
  beep(NOTE_E4500);
  beep(NOTE_C4500);
  beep(NOTE_B3500);
  beep(NOTE_A3750);
  beep(NOTE_F4200);
  beep(NOTE_F4200);
  beep(NOTE_E4500);
  beep(NOTE_C4500);
  beep(NOTE_D4500);
  beep(NOTE_C41000); 
  compteur 0;
}