/***  Les 2 DHT22   *************************************/
#include <DHT.h>
int dhtExtSignalPin = 5;   // DHT extérieur
int dhtSalonSignalPin = 6; // DHT intérieur
DHT capteurDHT_Ext(dhtExtSignalPin, DHT22);    // dhtExtSignalPin(pin, Type)
DHT capteurDHTSalon(dhtSalonSignalPin, DHT22); // dhtSalonSignalPin(pin, Type)
// Variable de type float "flottante" pour les DHT22.
float Hum, Cel, Far; // Variables à virgule flottante.
char tC[6], tF[6], H[6], buffer[20],  buffer2[20]; // mémoires tampons (Buffers)

/***  Module de capteur à photorésistance (LDR)   ******/
int LDR_Pin = 7;
// LDR Charactéristiques Variables constantes de type float
const float GAMMA = 0.7, RL10 = 50;

/***  Module RTC DS1307 (RealTime Clock)   *************/
#include <RTClib.h>
RTC_DS1307 rtc; // rtc = nom du module d'horloge en temps réel (rtc)
char Jour[7][10] = {"Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi"}; // Les jours de la semaine.
char Mois[13][10] = {"", "Janvier", "Fevrier", "Mars", "Avril", "Mai", "Juin",
                     "Juillet", "Aout", "Septembre", "Octobre", "Novembre", "Decembre"
                    };
char Horloge[9], LaDate[20];
DateTime now; // Variable de type DateTime nommée "now"

/***   Afficheur lcd I2C2004  **************************/
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);

/***   Variables pour l'encodeur rotatif KY-040   ******/
int encodeur_CLK = 2, encodeur_DaTa = 3, encodeur_SWitch = 4;
int compteur = 0, dataValue, resultat, E_Clk, i ;
int currentValue, previousValue;
byte swPreviousEtat = false;
byte buttonState;

/***  construction des pages du menu   *****************/
String txtMsg = "";
int pageNo = 0; // Numéro de de la page = index du menu.
char menu[10][20] = {"Page 1 Instructions",
                     "Date & heure",
                     "Temperature ext",
                     "Temperature int",
                     "Capteur LRD analog",
                     "Capteur LRD digital",
                     "Fonction 7",
                     "Fonction 8",
                     "Fonction 9",
                     "Fonction 10"
                    };
/**** contrôle du rétro éclairage ************************************/
byte lcd_backlight = false ; // Économiseur d'énergie

#define buzzer 13 // Relie le buzzer à la broche 13.

void setup() {
  lcd.init(); lcd.noBacklight();  rtc.begin();
  capteurDHT_Ext.begin(); capteurDHTSalon.begin();
  pinMode(buzzer, OUTPUT);
  // définir le mode des broches utilisées
  pinMode(dhtExtSignalPin, INPUT_PULLUP);
  pinMode(dhtSalonSignalPin, INPUT_PULLUP);
  pinMode(LDR_Pin, INPUT);
  pinMode(encodeur_CLK, INPUT);
  pinMode(encodeur_DaTa, INPUT);
  pinMode(encodeur_SWitch, INPUT_PULLUP);

  attachInterrupt(digitalPinToInterrupt(encodeur_CLK), LireEncodeur, FALLING);

}
void loop() {
  EnergySaver();
  MenuFonctions();
}
void EnergySaver() {
  buttonState = digitalRead(encodeur_SWitch);
  if (buttonState != swPreviousEtat) {
    swPreviousEtat = buttonState;
    if (buttonState == LOW) {
      lcd_backlight = (lcd_backlight == HIGH) ? LOW : HIGH;
      switch (lcd_backlight) {
        case 0: lcd.noBacklight(); break;
        case 1: lcd.backlight(); break;
      }
      beep();
    }
  }
}
void MenuFonctions() {
  previousValue = currentValue;  // stocker ce qui a été lu la dernière fois
  currentValue = compteur;  // obtenir une nouvelle lecture

  if (previousValue != currentValue) {
    // comparez-les et s'ils sont différents,
    // changement de page et efface l'ancienne
    animation();
    lcd.clear();
  } else {// s'ils sont les mêmes appelle la fonction...
    displayMenu(compteur); // afficheur lcd
  }
}
void displayMenu(int pageNo) {
  txtMsg = menu[compteur]; // page du menu selon la position de l'encodeur
  int len = txtMsg.length();    // donne la longueur du titre pour être centré.
  lcd.setCursor((20 - len) / 2, 0); lcd.print(txtMsg); // affiche le titre au centre

  switch (pageNo) {
    case 0: // Première page affichée "Instructions"
      lcdPrintCenter("Bouton = Led ON/OFF", 1);
      lcdPrintCenter("Navigation", 2);
      lcdPrintCenter("<<<  >>>", 3);
      break;

    case 1: // Page 2: Affiche la date et l'heure
      now = rtc.now(); //DateTime, ajoute la capacité de chronométrage et donne accès aux heures, minutes, secondes, jours, mois et années.
      // Affiche le jour de la semaine = Jour[now.dayOfTheWeek()];
      lcdPrintCenter(String(Jour[now.dayOfTheWeek()]), 1);
      // Formate l'affichage de la date.
      sprintf(LaDate, "Le %d %s %d", now.day(), Mois[now.month()], now.year());
      lcdPrintCenter(LaDate, 2); // Affiche la date au complet...
      //Formate l'affichage de l'heure. Heure = now.hour(), Minutes = now.minute(), Secondes = now.second()
      sprintf(Horloge, " %02d:%02d:%02d ", now.hour(), now.minute(), now.second());
      lcdPrintCenter(Horloge, 3); // Affiche l'heure ...
      break;

    case 2: // Page 3: Affiche la température et l'humidité du DHT22 extérieur
      Hum = capteurDHT_Ext.readHumidity();       // Pourcentage de l'humidité.
      Cel = capteurDHT_Ext.readTemperature();    // Température en degré Celcius
      Far = capteurDHT_Ext.readTemperature(true);// Température en degré Fahrenheit
      displayDHT(Hum, Cel, Far);

      break;

    case 3: // Page 4: Affiche la température et l'humidité du DHT22 intérieur
      Hum = capteurDHTSalon.readHumidity();       // Pourcentage de l'humidité.
      Cel = capteurDHTSalon.readTemperature();    // Température en degré Celcius
      Far = capteurDHTSalon.readTemperature(true);// Température en degré Fahrenheit
      displayDHT(Hum, Cel, Far);
      break;

    case 4: // Page 5: Affiche la luminosité selon les valeur analogique
      displayLDR_Analogique();
      break;

    case 5: // Page 6: Affiche la luminosité selon la valeur numérique de LDR_PIN (broche D7 de l'arduino)
      displayLDR_Digital();
      break;
  }
}
void LireEncodeur() { // ISR (Routine de Service d'Interruption)
  dataValue = digitalRead(encodeur_DaTa);
  if (dataValue == HIGH) {
    compteur++; // Dans le sens horaire incrémente de 1
    if (compteur > 9)compteur = 9;
  }
  if (dataValue == LOW) {
    compteur--; // Sens antihoraire décrémente de 1
    if (compteur < 0)compteur = 0;
  }
  tick();
}
int getCompteur() {
  /* Obtenir la valeur du compteur, en désactivant les interruptions.
    Cela garantit que LireEncodeur() ne modifie pas la valeur
    pendant qu'elle est lue.
  */
  resultat;
  noInterrupts(); // pas d'interruptions
  resultat = compteur;
  interrupts(); // Interruptions
  return resultat;
}
void animation() {
  if (previousValue < currentValue) {
    for (int positionCounter = 0; positionCounter < 20; positionCounter++) {
      // faire défiler une position vers la gauche :
      lcd.scrollDisplayLeft();
      delay(15);// attends un peu :
    }
  }
  if (previousValue > currentValue) {
    for (int positionCounter = 0; positionCounter < 20; positionCounter++) {
      // faire défiler une position vers la droite:
      lcd.scrollDisplayRight();
      delay(15);// attends un peu :
    }
  }
}
void displayLDR_Analogique() {
  int analogValue = analogRead(A0);
  float voltage = analogValue / 1024. * 5;
  float resistance = 2000 * voltage / (1 - voltage / 5);
  float lux = pow(RL10 * 1e3 * pow(10, GAMMA) / resistance, (1 / GAMMA));

  lcdPrintCenter("Luminosity", 1);
  if (lux > 50) {
    lcdPrintCenter("Claire", 2);
  } else {
    lcdPrintCenter("Sombre", 2);
  }
  lcd.setCursor(0, 3); lcd.print("Lux: ");
  lcd.print(lux); lcd.print("          ");
  delay(100);
}
void displayLDR_Digital() {
  lcdPrintCenter("Luminosity", 1);
  if (digitalRead(LDR_Pin) == LOW) {
    lcdPrintCenter("Claire", 2);
  } else {
    lcdPrintCenter("Sombre", 2);
  }
  delay(100);
}
void displayDHT(float Hum, float Cel, float Far) {
  // // Affiche la température et l'humidité des DHT sur lcd1
  lcdPrintCenter("Celsius   Fahrenheit", 1);
  dtostrf(Cel, 5, 2, tC); // Converti float"Cel" en Chaine de caractères.
  // pour afficher la température en degré Celcius
  lcd.setCursor(0, 2); lcd.print(String(tC) + (char)223 + "C ");
  // pour afficher la température en degré Fahrenheit
  dtostrf(Far, 5, 2, tF); // Converti float"Far" en Chaine de caractères.
  lcd.setCursor(11, 2); lcd.print(String(tF) + (char)223 + "F ");
  // pour afficher le Pourcentage de l'humidité.
  dtostrf(Hum, 5, 1, H); // Converti float"Far" en Chaine de caractères.
  lcd.setCursor(0, 3);  lcd.print("Humidity:   " + String(H) + "%  ");
}
void lcdPrintCenter(String texte, int ligne) {
  // Centre l'affichage du texte sur la ligne indiquée de lcd
  int len = texte.length(); // Défini la longeur de la variable "texte"
  lcd.setCursor((20 - len) / 2, ligne);  // positionne le curseur au centre de la ligne choisie et soustrait la longeur du text à afficher
  lcd.print(texte); // Affiche le texte demandé sur lcd2.
}
// Fonctions du buzzer ==========================================
// fonction beep pour Émettre une tonalité de x kHz pendant x ms
void beep() {// Émet une tonalité de 2,5kHz pendant 100 ms
  tone(buzzer, 2500, 100);
}
// Émet une très brève tonalité de 5kHz pendant 4 ms
void tick() {
  tone(buzzer, 5000, 4);   // Émet un son de 5 kHz pendant 1 ms
}
GND5VSDASCLSQWRTCDS1307+
Module de capteur à photorésistance (LDR)
DHT22 extérieur
DHT22 intérieur
Encodeur rotatif KY-040
Encodeur rotatif KY-040 1- Pour activer/désactiver le rétro éclarage de LCD Pressez le bouton. 2- Pour naviguer entre les pages du menu appliquez une rotation horaire ou antihoraire pour se faire... cliquez la flèche droite pour défiler vers la droite (+) cliquez la flèche gauche pour défiles vers la gauche (-)
Real Time Clock RTC DS1307