#include <Wire.h>
#include <hd44780.h>                        // main hd44780 header
#include <hd44780ioClass/hd44780_I2Cexp.h>  // i2c expander i/o class header
#include <Toggle.h>                         // https://github.com/Dlloydev/Toggle

// les leds
const char ledCa = 50;  // pin Led fonction CANICULE
const char ledFr = 51;  // pin led fonction FROID
const char ledCh = 52;  // pin Led fonction CHAUFFAGE

// les relais
const char relaisComp = 30;          // pin relais Compresseur
const char relaisV4V = 31;           // pin relais vanne 4 voies
const char relaisVentExt = 32;  // pin relais
const char relaisVitesseExt = 33;       // pin relais Ventilateur Exterieur (petite et grande Vitesses)
const char relaisVitesse1 = 34;  // pin relais Ventilateur Interieur vitesse 1
const char relaisVitesse2 = 35;       // pin relais Ventilateur Interieur vitesse 2
const char relaisVitesse3 = 36;     // pin relais Ventilatuer Interieur vitesse 3
const char relaisVitesse4 = 37;     // pin relais Ventilateur Interieur vitesse 4
const char relaisVolets = 38;        // pin relais Saison été / hiver

// les capteurs
const char thermostatsPin = 8;        // pin thermostat Chambre 1 , bouton poussoir pour test
const char capteurFiltrePin = 9;  // pin capteur de presence porte filtre
Toggle thermostats;
Toggle capteurFiltre;
const unsigned int ms = 1000;

// les boutons
const char menuPin = 22;         // pin bouton Menu
const char validPin = 23;        // pin bouton Valid
const char boutonPlusPin = 24;   // pin bouton Plus
const char boutonMoinsPin = 25;  // pin bouton Moins
Toggle boutonMenu;
Toggle boutonValid;
Toggle boutonPlus;
Toggle boutonMoins;

// les led boutons
const char ledBoutonMenu = 42;  // pin Led bouton Menu
const char ledBoutonValid = 43; // pin led bouton Valid
const char ledBoutonPlus = 44;  // pin led bouton Plus
const char ledBoutonMoins = 45; // pin led bouton Moins

// les  Sondes CTN
const float BETA = 3950; // should match the Beta Coefficient of the thermistor
//float temperature;

struct Sonde {
  const char* nom;
  byte pinSonde;
  float temperature;

  void lireTemperature() {
    analogRead(pinSonde); // double lecture pour plus de précision
    int valeur = analogRead(pinSonde);
    temperature =   valeur == 0 ? -1000 : 1 / (log(1 / (1023. / valeur - 1)) / BETA + 1.0 / 298.15) - 273.15;
  }
};

Sonde sondes[] = {
  { "T\xDF""Ext", A0, 0 },
  { "T\xDF""UExt", A1, 0 },
  { "T\xDF""EExt", A2, 0 },
  { "T\xDF""UInt", A3, 0 },
  { "T\xDF""EInt", A4, 0 }
};
constexpr size_t nombreDeSondes = sizeof sondes / sizeof * sondes;
size_t indexSondeEnCours = 0;

// calibrage sondes
float tempExtLueCalibre;
float tempUnitExtLueCalibre;
float tempEchangeurExtLueCalibre;
float tempUnitIntLueCalibre;
float tempEchangeurIntLueCalibre;

struct Calibrage {
  const char* nom;
  float calibrage;
};

Calibrage calibrages[] = {
  { "calSExt", 0 },
  { "calSUExt", 0 },
  { "calSEExt", 0 },
  { "calSUInt", 0 },
  { "calSEInt", 0 }
};
constexpr size_t nombreDeCalibrages = sizeof calibrages / sizeof * calibrages;
size_t indexCalibrageEnCours = 0;

// les tempos
unsigned long long tempoLcdConsigne;
unsigned long long tempoBacklightLcd;

unsigned long long tempoFr;
unsigned long long tempoV4VFr;
unsigned long long tempoCompFr;
unsigned long long tempoDegFr;
unsigned long long tempoTempDegFr;
unsigned long long tempoCh;
unsigned long long tempoCompCh;
unsigned long long tempoV4VCh;
unsigned long long tempoTempDegEle;
unsigned long long tempoDegCh;
unsigned long long tempoDegNat;
unsigned long long tempoEgouttageFr;
unsigned long long tempoEgouttageNat;
unsigned long long tempoEgouttageEle;
unsigned long long tempoFinEgouttageEle;
unsigned long long tempoCa;

unsigned long long tempoVentilation;

unsigned long long departChronoFiltre;
unsigned long long finChronoFiltre;
unsigned long nettoyageFiltre;

unsigned long tempoLedFrClignoteDeg = 0;
bool ledFrCl = 0;
unsigned long tempoLedChClignoteDeg = 0;
bool ledChCl = 0;
unsigned long tempoLedCaClignoteDeg = 0;
bool ledCaCl = 0;
unsigned long tempoLedArretCompletProgramClignote = 0;
bool ledChFrCaCl = 0;
unsigned long tempoLedBoutonClignote = 0;

unsigned long tempoAutoMode = 0;

unsigned long tempoAfficheTemps = 0;

// les consignes
struct Consigne {
  const char* nom;
  float consigne;
};

Consigne consignes[] = {
  { "T\xDF""Ch/Fr", 13.5 }, //0 consigne via sonde Ext
  { "T\xDF""Ca", 30.0 },  //1 sonde Ext
  { "T\xDF""GVExtFr", 20.0 },   //2 sonde UnitExt
  { "T\xDF""GVExtCh", 5.0 },    //3 sonde UnitExt
  { "T\xDF""DegNaCh", 5.0 },    //4 sonde UnitExt
  { "T\xDF""blocCh", 11.0 },  //5 sonde UnitExt
  { "T\xDF""DegEleCh", -3.0 },  //6 sonde EchangeurExt
  { "T\xDF""FinDegCh", 12.5 },  //7 sonde EchangeurExt
  { "T\xDF""PVIntFr", 23.0 },   //8 sonde UnitInt
  { "T\xDF""PVIntCh", 22.0 },   //9 sonde UnitInt
  { "T\xDF""VentFr", 24.0 },  //10 sonde UnitInt
  { "T\xDF""VentCh", 22.0 },  //11 sonde UnitInt
  { "T\xDF""DVIntCh", 30.0 },  //12 sonde EchangeurInt
  { "T\xDF""DegFr", -3.0 },      //13 sonde EchangeurInt
  { "T\xDF""FinDegFr", 15.0 },  //14 sonde EchangeurInt
  { "T\xDF""Delta", 6 }      //15
};
constexpr size_t nombreDeConsignes = sizeof consignes / sizeof * consignes;
size_t indexConsigneEnCours = 0;

float consigneIntCa;

struct TestRelais {
  const char* nom;
  byte pinRelais;
};

TestRelais testRelais[] = {
  { "Relai Comp", 30 },
  { "Relai V4V", 31 },
  { "RelaiV1Ext", 32 },
  { "RelaiV2Ext", 33 },
  { "RelaiV1Int", 34 },
  { "RelaiV2Int", 35 },
  { "RelaiV3Int", 36 },
  { "RelaiV4Int", 37 },
  { "RelaiVolet", 38 }
};
constexpr size_t nombreDeTest = sizeof testRelais / sizeof * testRelais;
size_t indexTestRelaisEnCours = 0;
byte testRelaisTravail = testRelais[indexTestRelaisEnCours].pinRelais;

// les vitesses interieur
struct Vitesse {
  const char* nom;
  byte vitesse;
};

Vitesse vitesses[] = {
  { "Auto", 0 },
  { "Vitesse", 1 },
  { "Vitesse", 2 },
  { "Vitesse", 3 },
  { "Vitesse", 4 }
};
constexpr size_t nombreDeVitesses = sizeof vitesses / sizeof * vitesses;
size_t indexVitesseEnCours = 0;
bool modifVitesseInt = false;
byte vitesseTravail = vitesses[indexVitesseEnCours].vitesse;

bool departGainable = false; // active ou desactive la machine a etasGainable (arret)

// le lcd
const uint8_t nbColonnes = 16;
const uint8_t nbLignes = 2;
hd44780_I2Cexp lcd;

// les caracteres speciaux
byte flecheFr[8] = {
  B00100,
  B00100,
  B00100,
  B00100,
  B00100,
  B10101,
  B01110,
  B00100
};
byte flecheCh[8] = {
  B00100,
  B01110,
  B10101,
  B00100,
  B00100,
  B00100,
  B00100,
  B00100
};
byte goutte[8] = {
  B00100,
  B00100,
  B00100,
  B01010,
  B10001,
  B10001,
  B10001,
  B01110
};
byte degivrage[8] = {
  B11111,
  B10001,
  B00100,
  B00100,
  B01010,
  B10001,
  B10001,
  B01110
};
byte eclaire[8] = {
  B00010,
  B00100,
  B01000,
  B11111,
  B00010,
  B00100,
  B01000,
  B10000
};
byte soleil[8] = {
  B00100,
  B10101,
  B01110,
  B11010,
  B01011,
  B01110,
  B10101,
  B00100
};
byte ventilateur[8] = {
  B01100,
  B01100,
  B00101,
  B11011,
  B11011,
  B10100,
  B00110,
  B00110
};

// les fonctions de l'affichages

void affiche(const char* etiquette, float valeur, byte ligne, byte precision = 2, byte tailleValeur = 6) {
  // on a nbColonnes-tailleValeur cases pour le nom - cadré à gauche
  // tailleValeur cases pour la consigne - cadrée à droite
  char bufferEtiquette[nbColonnes - tailleValeur + 1];
  strlcpy(bufferEtiquette, etiquette, sizeof bufferEtiquette);  // ça va tronquer l'étiquette si nécesaire
  lcd.setCursor(0, ligne);
  lcd.print(bufferEtiquette);

  char bufferValeur[nbColonnes];                           // suffisamment grand  pour nos besoins
  dtostrf(valeur, tailleValeur, precision, bufferValeur);  // conversion en chaîne de caractères

  byte nbEspaces = nbColonnes - (strlen(bufferEtiquette) + strlen(bufferValeur));
  for (byte i = 0; i < nbEspaces; i++) lcd.write(' ');  // pour cadrer la valeur à droite

  lcd.print(bufferValeur);
  static uint32_t x = 0;
}

void affiche(const char* etiquette, int valeur, byte ligne, byte tailleValeur = 6) {
  // on a nbColonnes-tailleValeur cases pour le nom - cadré à gauche
  // tailleValeur cases pour la consigne - cadrée à droite
  char bufferEtiquette[nbColonnes - tailleValeur + 1];
  strlcpy(bufferEtiquette, etiquette, sizeof bufferEtiquette);  // ça va tronquer l'étiquette si nécesaire
  lcd.setCursor(0, ligne);
  lcd.print(bufferEtiquette);

  char bufferValeur[nbColonnes];   // suffisamment grand  pour nos besoins
  itoa(valeur, bufferValeur, 10);  // conversion en chaîne de caractères

  byte nbEspaces = nbColonnes - (strlen(bufferEtiquette) + strlen(bufferValeur));
  for (byte i = 0; i < nbEspaces; i++) lcd.write(' ');  // pour cadrer la valeur à droite

  lcd.print(bufferValeur);
}

void affiche(const char* etiquette, byte ligne) {

  char bufferEtiquette[nbColonnes];
  strlcpy(bufferEtiquette, etiquette, sizeof bufferEtiquette);
  lcd.setCursor(0, ligne);
  lcd.print(bufferEtiquette);
}

void calibrageSonde() {
  if (indexCalibrageEnCours == 0) {
    affiche(calibrages[indexCalibrageEnCours].nom, sondes[0].temperature, 0);//sondes[0].temperature(), 0);
  } else if (indexCalibrageEnCours == 1) {
    affiche(calibrages[indexCalibrageEnCours].nom, sondes[1].temperature, 0);//sondes[1].temperature(), 0);
  } else if (indexCalibrageEnCours == 2) {
    affiche(calibrages[indexCalibrageEnCours].nom, sondes[2].temperature, 0);//sondes[2].temperature(), 0);
  } else if (indexCalibrageEnCours == 3) {
    affiche(calibrages[indexCalibrageEnCours].nom, sondes[3].temperature, 0);//sondes[3].temperature(), 0);
  } else if (indexCalibrageEnCours == 4) {
    affiche(calibrages[indexCalibrageEnCours].nom, sondes[4].temperature, 0);//sondes[4].temperature(), 0);
  }
}

void afficheTempsCalibre() {

  if (millis() - tempoAfficheTemps >= 25000) {
    tempoAfficheTemps = millis();
  } else {
    if (millis() - tempoAfficheTemps >= 20000) {
      affiche("T\xDF""EIntLue", tempEchangeurIntLueCalibre, 1);
      //affiche(sondes[4].nom, tempEchangeurIntLueCalibre, 1);
    } else if (millis() - tempoAfficheTemps >= 15000) {
      affiche("T\xDF""UIntLue", tempUnitIntLueCalibre, 1);
      //affiche(sondes[3].nom, tempUnitIntLueCalibre, 1);
    } else if (millis() - tempoAfficheTemps >= 10000) {
      affiche("T\xDF""EExtLue", tempEchangeurExtLueCalibre, 1);
      //affiche(sondes[2].nom, tempEchangeurExtLueCalibre, 1);
    } else if (millis() - tempoAfficheTemps >= 5000) {
      affiche("T\xDF""UExtLue", tempUnitExtLueCalibre, 1);
      //affiche(sondes[1].nom, tempUnitExtLueCalibre, 1);
    } else {
      affiche("T\xDF""ExtLue", tempExtLueCalibre, 1);
      //affiche(sondes[0].nom, tempExtLueCalibre, 1);
    }
  }
}


// les consignes en fonction des sondes
void consigneSonde() { // affichage consignes par rapport au sondes sur la ligne 0
  if (indexConsigneEnCours == 0 || indexConsigneEnCours == 1) { // si : consigne 0 (13.5°C) ou consigne 1 (30.0°C)
    affiche(consignes[indexConsigneEnCours].nom, tempExtLueCalibre, 0); // affiche la consigne en cours et affiche la temperature lue par la sonde 0 (Temp-Ext) a la ligne 0
  } else if (indexConsigneEnCours == 2 || indexConsigneEnCours == 3 || indexConsigneEnCours == 4 || indexConsigneEnCours == 5) {
    affiche(consignes[indexConsigneEnCours].nom, tempUnitExtLueCalibre, 0);
  } else if (indexConsigneEnCours == 6 || indexConsigneEnCours == 7) {
    affiche(consignes[indexConsigneEnCours].nom, tempEchangeurExtLueCalibre, 0);
  } else if (indexConsigneEnCours == 8 || indexConsigneEnCours == 9 || indexConsigneEnCours == 10 || indexConsigneEnCours == 11) {
    affiche(consignes[indexConsigneEnCours].nom, tempUnitIntLueCalibre, 0);
  } else if (indexConsigneEnCours == 12 || indexConsigneEnCours == 13 || indexConsigneEnCours == 14) {
    affiche(consignes[indexConsigneEnCours].nom, tempEchangeurIntLueCalibre, 0);
  } else { // si non :
    affiche(consignes[indexConsigneEnCours].nom, consigneIntCa, 0); // affiche la consigne en cours et affiche la consigne canicule
  }
}

void relaisTest() {
  if (indexTestRelaisEnCours == 0) {
    digitalWrite(relaisComp, HIGH);
    digitalWrite(relaisV4V, LOW);
    digitalWrite(relaisVentExt, LOW);
    digitalWrite(relaisVitesseExt, LOW);
    digitalWrite(relaisVitesse1, LOW);
    digitalWrite(relaisVitesse2, LOW);
    digitalWrite(relaisVitesse3, LOW);
    digitalWrite(relaisVitesse4, LOW);
    digitalWrite(relaisVolets, LOW);
    testRelaisTravail = testRelais[indexTestRelaisEnCours].pinRelais;
  } else if (indexTestRelaisEnCours == 1) {
    digitalWrite(relaisComp, LOW);
    digitalWrite(relaisV4V, HIGH);
    digitalWrite(relaisVentExt, LOW);
    digitalWrite(relaisVitesseExt, LOW);
    digitalWrite(relaisVitesse1, LOW);
    digitalWrite(relaisVitesse2, LOW);
    digitalWrite(relaisVitesse3, LOW);
    digitalWrite(relaisVitesse4, LOW);
    digitalWrite(relaisVolets, LOW);
    testRelaisTravail = testRelais[indexTestRelaisEnCours].pinRelais;
  } else if (indexTestRelaisEnCours == 2) {
    digitalWrite(relaisComp, LOW);
    digitalWrite(relaisV4V, LOW);
    digitalWrite(relaisVentExt, HIGH);
    digitalWrite(relaisVitesseExt, LOW);
    digitalWrite(relaisVitesse1, LOW);
    digitalWrite(relaisVitesse2, LOW);
    digitalWrite(relaisVitesse3, LOW);
    digitalWrite(relaisVitesse4, LOW);
    digitalWrite(relaisVolets, LOW);
    testRelaisTravail = testRelais[indexTestRelaisEnCours].pinRelais;
  } else if (indexTestRelaisEnCours == 3) {
    digitalWrite(relaisComp, LOW);
    digitalWrite(relaisV4V, LOW);
    digitalWrite(relaisVentExt, LOW);
    digitalWrite(relaisVitesseExt, HIGH);
    digitalWrite(relaisVitesse1, LOW);
    digitalWrite(relaisVitesse2, LOW);
    digitalWrite(relaisVitesse3, LOW);
    digitalWrite(relaisVitesse4, LOW);
    digitalWrite(relaisVolets, LOW);
    testRelaisTravail = testRelais[indexTestRelaisEnCours].pinRelais;
  } else if (indexTestRelaisEnCours == 4) {
    digitalWrite(relaisComp, LOW);
    digitalWrite(relaisV4V, LOW);
    digitalWrite(relaisVentExt, LOW);
    digitalWrite(relaisVitesseExt, LOW);
    digitalWrite(relaisVitesse1, HIGH);
    digitalWrite(relaisVitesse2, LOW);
    digitalWrite(relaisVitesse3, LOW);
    digitalWrite(relaisVitesse4, LOW);
    digitalWrite(relaisVolets, LOW);
    testRelaisTravail = testRelais[indexTestRelaisEnCours].pinRelais;
  } else if (indexTestRelaisEnCours == 5) {
    digitalWrite(relaisComp, LOW);
    digitalWrite(relaisV4V, LOW);
    digitalWrite(relaisVentExt, LOW);
    digitalWrite(relaisVitesseExt, LOW);
    digitalWrite(relaisVitesse1, LOW);
    digitalWrite(relaisVitesse2, HIGH);
    digitalWrite(relaisVitesse3, LOW);
    digitalWrite(relaisVitesse4, LOW);
    digitalWrite(relaisVolets, LOW);
    testRelaisTravail = testRelais[indexTestRelaisEnCours].pinRelais;
  } else if (indexTestRelaisEnCours == 6) {
    digitalWrite(relaisComp, LOW);
    digitalWrite(relaisV4V, LOW);
    digitalWrite(relaisVentExt, LOW);
    digitalWrite(relaisVitesseExt, LOW);
    digitalWrite(relaisVitesse1, LOW);
    digitalWrite(relaisVitesse2, LOW);
    digitalWrite(relaisVitesse3, HIGH);
    digitalWrite(relaisVitesse4, LOW);
    digitalWrite(relaisVolets, LOW);
    testRelaisTravail = testRelais[indexTestRelaisEnCours].pinRelais;
  } else if (indexTestRelaisEnCours == 7) {
    digitalWrite(relaisComp, LOW);
    digitalWrite(relaisV4V, LOW);
    digitalWrite(relaisVentExt, LOW);
    digitalWrite(relaisVitesseExt, LOW);
    digitalWrite(relaisVitesse1, LOW);
    digitalWrite(relaisVitesse2, LOW);
    digitalWrite(relaisVitesse3, LOW);
    digitalWrite(relaisVitesse4, HIGH);
    digitalWrite(relaisVolets, LOW);
    testRelaisTravail = testRelais[indexTestRelaisEnCours].pinRelais;
  } else if (indexTestRelaisEnCours == 8) {
    digitalWrite(relaisComp, LOW);
    digitalWrite(relaisV4V, LOW);
    digitalWrite(relaisVentExt, LOW);
    digitalWrite(relaisVitesseExt, LOW);
    digitalWrite(relaisVitesse1, LOW);
    digitalWrite(relaisVitesse2, LOW);
    digitalWrite(relaisVitesse3, LOW);
    digitalWrite(relaisVitesse4, LOW);
    digitalWrite(relaisVolets, HIGH);
    testRelaisTravail = testRelais[indexTestRelaisEnCours].pinRelais;
  }
}

// les modification de vitesses interieur
void vitesseInterieur() { // modification des relais ventilateur interieur en fonction de l'affichage pour changer les vitesses
  if (indexVitesseEnCours == 0) { // si : 0 (automatique)
    modifVitesseInt = false; // pas de modification de vitesse
    vitesseTravail = vitesses[indexVitesseEnCours].vitesse;
  } else if (indexVitesseEnCours == 1) { // si non si : 1 (vitesse 1)
    modifVitesseInt = true; // modification de vitesse possible
    digitalWrite(relaisVitesse1, HIGH); // desactive relais ventilateur interieur petite vitesse 1 et grande vitesse 4
    digitalWrite(relaisVitesse2, LOW); // desactive relais ventilateur interieur petite vitesse 2
    digitalWrite(relaisVitesse3, LOW); // desactive relais ventilateur interieur grande vitesse 3
    digitalWrite(relaisVitesse4, LOW);
    vitesseTravail = vitesses[indexVitesseEnCours].vitesse;
  } else if (indexVitesseEnCours == 2) { // si non si ; 2 (vitesse 2)
    modifVitesseInt = true; // modification de vitesse possible
    digitalWrite(relaisVitesse1, LOW); // desactive relais ventilateur interieur petite vitesse 1 et grande vitesse 4
    digitalWrite(relaisVitesse2, HIGH); // active relais ventilateur interieur petite vitesse 2
    digitalWrite(relaisVitesse3, LOW); // desactive relais ventilateur interieur grande vitesse 3
    digitalWrite(relaisVitesse4, LOW);
    vitesseTravail = vitesses[indexVitesseEnCours].vitesse;
  } else if (indexVitesseEnCours == 3) {
    modifVitesseInt = true;
    digitalWrite(relaisVitesse1, LOW);
    digitalWrite(relaisVitesse2, LOW);
    digitalWrite(relaisVitesse3, HIGH);
    digitalWrite(relaisVitesse4, LOW);
    vitesseTravail = vitesses[indexVitesseEnCours].vitesse;
  } else if (indexVitesseEnCours == 4) {
    modifVitesseInt = true;
    digitalWrite(relaisVitesse1, LOW);
    digitalWrite(relaisVitesse2, LOW);
    digitalWrite(relaisVitesse3, LOW);
    digitalWrite(relaisVitesse4, HIGH);
    vitesseTravail = vitesses[indexVitesseEnCours].vitesse;
  }
}

// La machine à état de commande
enum { ETEINT,
       TEST_RELAIS,
       CONSIGNE,
       DETAIL_CONSIGNE,
       CALIBRAGE,
       DETAIL_CALIBRAGE,
       VITESSE,
       ACTIF,
       AUTOMATIQUE,
       NETTOYAGE_FILTRE
     } mode = ETEINT;

// les Variables de commande
bool entretienFiltre = false;
byte ledMaitre = 0;
bool test = false;

// les fonctions de commande
void etablirModeEteint() {
  test = false;
  lcd.backlight();
  if (departGainable == true) {
    lcd.clear();
    lcd.print("** ETEINDRE ? **");
    mode = ETEINT;
  } else {
    lcd.clear();
    lcd.print("***  ETEINT  ***");
    mode = ETEINT;
  }
}

void etablirModeActif() {
  lcd.backlight();
  lcd.clear();
  lcd.print("** DEMARAGE ? **");
  mode = ACTIF;
}

void etablirModeAutomatique() {
  lcd.backlight();
  lcd.clear();
  departGainable = true;
  tempoBacklightLcd = millis();
  mode = AUTOMATIQUE;
}

void etablirModeConsigne() {
  lcd.backlight();
  lcd.clear();
  lcd.print("*** CONSIGNE ***");
  affiche(consignes[indexConsigneEnCours].nom, consignes[indexConsigneEnCours].consigne, 1);
  tempoLcdConsigne = millis();
  mode = CONSIGNE;
}

void etablirModeDetailConsigne() {
  lcd.backlight();
  lcd.clear();
  consigneSonde();
  affiche("consigne:", consignes[indexConsigneEnCours].consigne, 1);
  tempoLcdConsigne = millis();
  mode = DETAIL_CONSIGNE;
}

void etablirModeCalibrage() {
  lcd.backlight();
  lcd.clear();
  lcd.print("** CALIBRAGE  **");
  affiche(calibrages[indexCalibrageEnCours].nom, calibrages[indexCalibrageEnCours].calibrage, 1);
  tempoLcdConsigne = millis();
  mode = CALIBRAGE;
}

void etablirModeDetailCalibrage() {
  lcd.backlight();
  lcd.clear();
  calibrageSonde();
  affiche("calibrage:", calibrages[indexCalibrageEnCours].calibrage, 1);
  tempoLcdConsigne = millis();
  mode = DETAIL_CALIBRAGE;
}

void etablirModeVitesse() {
  lcd.backlight();
  lcd.clear();
  lcd.print("*** VITESSES ***");
  affiche(vitesses[indexVitesseEnCours].nom, vitesses[indexVitesseEnCours].vitesse, 1);
  mode = VITESSE;
}

void etablirModeNettoyageFiltre() {
  lcd.backlight();
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Nettoyage       ");
  lcd.setCursor(0, 1);
  lcd.print("          Filtre");
  mode = NETTOYAGE_FILTRE;
}

void etablirModeTest() {
  test = true;
  lcd.backlight();
  lcd.clear();
  lcd.print("* TEST RELAIS  *");
  affiche(testRelais[indexTestRelaisEnCours].nom, testRelais[indexTestRelaisEnCours].pinRelais, 1);
  mode = TEST_RELAIS;
}

void majBoutons() {
  boutonMenu.poll();
  boutonValid.poll();
  boutonPlus.poll();
  boutonMoins.poll();
}

void majCapteurs() {
  thermostats.poll();
  capteurFiltre.poll();
}

// les leds clignotantes des boutons
void activeLedBoutonClignote() { // clignotement des leds des boutons a la meme cadence
  if (millis() - tempoLedBoutonClignote > 300) {
    ledMaitre = !ledMaitre;
    if (mode == ETEINT && departGainable == true)
    {
      digitalWrite(ledBoutonMenu, ledMaitre);
      digitalWrite(ledBoutonValid, ledMaitre);
      digitalWrite(ledBoutonPlus, LOW);
      digitalWrite(ledBoutonMoins, LOW);
    } else if (mode == ETEINT) {
      digitalWrite(ledBoutonMenu, ledMaitre);
      digitalWrite(ledBoutonValid, LOW);
      digitalWrite(ledBoutonPlus, LOW);
      digitalWrite(ledBoutonMoins, LOW);
    } else if (mode == CONSIGNE || mode == VITESSE || mode == CALIBRAGE) {
      digitalWrite(ledBoutonMenu, ledMaitre);
      digitalWrite(ledBoutonValid, ledMaitre);
      digitalWrite(ledBoutonMoins, ledMaitre);
      digitalWrite(ledBoutonPlus, ledMaitre);
    } else if (mode == DETAIL_CONSIGNE || mode == DETAIL_CALIBRAGE) {
      digitalWrite(ledBoutonValid, ledMaitre);
      digitalWrite(ledBoutonMoins, ledMaitre);
      digitalWrite(ledBoutonPlus, ledMaitre);
      digitalWrite(ledBoutonMenu, LOW);
    } else if (mode == ACTIF) {
      digitalWrite(ledBoutonMenu, ledMaitre);
      digitalWrite(ledBoutonValid, ledMaitre);
      digitalWrite(ledBoutonPlus, LOW);
      digitalWrite(ledBoutonMoins, LOW);
    } else if (mode == AUTOMATIQUE) {
      digitalWrite(ledBoutonMenu, ledMaitre);
      digitalWrite(ledBoutonValid, LOW);
      digitalWrite(ledBoutonPlus, LOW);
      digitalWrite(ledBoutonMoins, LOW);
    } else if (mode == TEST_RELAIS) {
      digitalWrite(ledBoutonMenu, ledMaitre);
      digitalWrite(ledBoutonValid, LOW);
      digitalWrite(ledBoutonMoins, ledMaitre);
      digitalWrite(ledBoutonPlus, ledMaitre);
    }
    tempoLedBoutonClignote = millis();
  }
}

// le mode
void gestionEtat() {

  majBoutons();
  majCapteurs();
  if (test == false) {
    gainable();
  }

  switch (mode) {

    case ETEINT:

      if (departGainable == true) {
        if (millis() - tempoLcdConsigne >= 15000) {
          etablirModeAutomatique();
          tempoBacklightLcd = millis();
        }
        if (boutonMenu.onPress()) {
          etablirModeAutomatique();
        } else if (boutonValid.onPress()) {
          departGainable = false;
          etablirModeEteint();
        } else {
          activeLedBoutonClignote();
        }
      } else if (boutonMenu.onPress() && capteurFiltre.releasedFor(ms)) {
        etablirModeActif();
      } else if (boutonPlus.onPress()) {//&& boutonMoins.onPress()) {
        etablirModeTest();
      } else {
        activeLedBoutonClignote();
      }
      break;

    case TEST_RELAIS:

      relaisTest();
      if (boutonPlus.onPress()) {
        indexTestRelaisEnCours = (indexTestRelaisEnCours + 1) % nombreDeTest;
        affiche(testRelais[indexTestRelaisEnCours].nom, testRelais[indexTestRelaisEnCours].pinRelais, 1);
      } else if (boutonMoins.onPress()) {
        if (indexTestRelaisEnCours == 0) indexTestRelaisEnCours = nombreDeTest - 1;
        else indexTestRelaisEnCours--;
        affiche(testRelais[indexTestRelaisEnCours].nom, testRelais[indexTestRelaisEnCours].pinRelais, 1);
      } else if (boutonMenu.onPress()) {
        desactiveTousRelais();
        etablirModeConsigne();
      } else {
        activeLedBoutonClignote();
      }
      break;

    case CONSIGNE:

      if (boutonPlus.onPress()) {
        indexConsigneEnCours = (indexConsigneEnCours + 1) % nombreDeConsignes;
        affiche(consignes[indexConsigneEnCours].nom, consignes[indexConsigneEnCours].consigne, 1);
      } else if (boutonMoins.onPress()) {
        if (indexConsigneEnCours == 0) indexConsigneEnCours = nombreDeConsignes - 1;
        else indexConsigneEnCours--;
        affiche(consignes[indexConsigneEnCours].nom, consignes[indexConsigneEnCours].consigne, 1);
      } else if (boutonValid.onPress()) {
        etablirModeDetailConsigne();
      } else if (boutonMenu.onPress()) {
        etablirModeCalibrage();
      } else {
        activeLedBoutonClignote();
      }
      break;

    case DETAIL_CONSIGNE:

      consigneSonde();
      if (boutonPlus.onPress()) {
        consignes[indexConsigneEnCours].consigne += 0.5;
        affiche("consigne:", consignes[indexConsigneEnCours].consigne, 1);
      } else if (boutonMoins.onPress()) {
        consignes[indexConsigneEnCours].consigne -= 0.5;
        affiche("consigne:", consignes[indexConsigneEnCours].consigne, 1);
      } else if (boutonValid.onPress()) {
        etablirModeConsigne();
      } else {
        activeLedBoutonClignote();
      }
      break;

    case CALIBRAGE:

      if (boutonPlus.onPress()) {
        indexCalibrageEnCours = (indexCalibrageEnCours + 1) % nombreDeCalibrages;
        affiche(calibrages[indexCalibrageEnCours].nom, calibrages[indexCalibrageEnCours].calibrage, 1);
      } else if (boutonMoins.onPress()) {
        if (indexCalibrageEnCours == 0) indexCalibrageEnCours = nombreDeCalibrages - 1;
        else indexCalibrageEnCours--;
        affiche(calibrages[indexCalibrageEnCours].nom, calibrages[indexCalibrageEnCours].calibrage, 1);
      } else if (boutonValid.onPress()) {
        etablirModeDetailCalibrage();
      } else if (boutonMenu.onPress()) {
        etablirModeEteint();
      } else {
        activeLedBoutonClignote();
      }
      break;

    case DETAIL_CALIBRAGE:

      calibrageSonde();
      if (boutonPlus.onPress()) {
        calibrages[indexCalibrageEnCours].calibrage += 0.25;
        affiche("calibrage:", calibrages[indexCalibrageEnCours].calibrage, 1);
      } else if (boutonMoins.onPress()) {
        calibrages[indexCalibrageEnCours].calibrage -= 0.25;
        affiche("calibrage:", calibrages[indexCalibrageEnCours].calibrage, 1);
      } else if (boutonValid.onPress()) {
        etablirModeCalibrage();
      } else {
        activeLedBoutonClignote();
      }
      break;

    case VITESSE:

      if (millis() - tempoLcdConsigne >= 15000) {
        etablirModeAutomatique();
        tempoBacklightLcd = millis();
      }
      vitesseInterieur();
      if (boutonPlus.onPress()) {
        tempoLcdConsigne = millis();
        indexVitesseEnCours = (indexVitesseEnCours + 1) % nombreDeVitesses;
        affiche(vitesses[indexVitesseEnCours].nom, vitesses[indexVitesseEnCours].vitesse, 1);
      } else if (boutonMoins.onPress()) {
        tempoLcdConsigne = millis();
        if (indexVitesseEnCours == 0) indexVitesseEnCours = nombreDeVitesses - 1;
        else indexVitesseEnCours--;
        affiche(vitesses[indexVitesseEnCours].nom, vitesses[indexVitesseEnCours].vitesse, 1);
      } else if (boutonMenu.onPress()) {
        etablirModeEteint();
      } else if (boutonValid.onPress()) {
        etablirModeAutomatique();
      } else {
        tempoBacklightLcd = millis();
        activeLedBoutonClignote();
      }
      break;

    case ACTIF:

      if (boutonValid.onPress()) {
        etablirModeAutomatique();
        tempoAfficheTemps = millis();
        tempoBacklightLcd = millis();
      } else if (boutonMenu.onPress()) {
        etablirModeEteint();
      } else {
        activeLedBoutonClignote();
      }
      break;

    case AUTOMATIQUE:
      {
        bool noBacklightLcd = false;

        if (entretienFiltre == true) {
          etablirModeNettoyageFiltre();
        } else {
          affichageGainable();
        }
        if (millis() - tempoBacklightLcd >= 60000) {
          digitalWrite(ledBoutonValid, LOW);
          digitalWrite(ledBoutonPlus, LOW);
          digitalWrite(ledBoutonMoins, LOW);
          digitalWrite(ledBoutonMenu, LOW);
          lcd.noBacklight();
          noBacklightLcd = true;
          if (boutonMenu.onPress()) {
            lcd.backlight();
            tempoBacklightLcd = millis();
            noBacklightLcd = false;
          }
        } else if (boutonMenu.onPress() && noBacklightLcd == false) {
          tempoLcdConsigne = millis();
          vitesseGainable();
        } else {
          activeLedBoutonClignote();
        }
      }
      break;

    case NETTOYAGE_FILTRE:

      if (capteurFiltre.pressedFor(ms)) {
        entretienFiltre = false;
        nettoyageFiltre = 0;
        etablirModeEteint();
      } else {
        lcd.backlight();
      }
      break;
  }
}

// la machine à état gainable
enum { ARRET,
       DEPART,
       VENTILATION_FROID,
       TEMPO_V4V,
       TEMPO_COMPRESSEUR_FROID,
       TEMPO_DEGIVRAGE_FROID,
       DEGIVRAGE_FROID,
       EGOUTTAGE_FROID,
       VENTILATION_CHAUFFAGE,
       TEMPO_COMPRESSEUR_CHAUFFAGE,
       TEMPO_DEGIVRAGE,
       MODE_DEGIVRAGE,
       DEGIVRAGE_NATUREL,
       EGOUTTAGE_NATUREL,
       TEMPO_DEG_V4V,
       TEMPO_DEG_COMPRESSEUR,
       DEGIVRAGE_ELECTRIC,
       EGOUTTAGE_CHAUFFAGE,
       FIN_EGOUTTAGE_CHAUFFAGE,
       VENTILATION_CANICULE,
       TEMPO_V4V_CANICULE,
       TEMPO_COMPRESSEUR_CANICULE,
       TEMPO_DEGIVRAGE_CANICULE
     } etatsGainable;

// les variables de gainable
float hysteresis0 = 0.5;
float hysteresis1 = 1.0;
float hysteresis3 = 3.0;

bool tempEteHiver = false;
bool tempCanicule = false;
bool tempVentIntCh = false;
bool tempVentExtCh = false;
bool tempVentIntFr = false;
bool tempVentExtFr = false;
bool tempEchangeurVentIntCh = false;

bool ventilation = false;
bool ventilationInt = false;
bool circulationAir = false;
bool tempChauffage = false;

bool caniculeLed = false;
bool forceVentDegFr = false;

// hysteresis été hivers canicule
void hysteresisTempEteHiver() {
  if (tempEteHiver) {
    tempEteHiver = (tempExtLueCalibre <= (consignes[0].consigne + hysteresis1));
  } else {
    tempEteHiver = (tempExtLueCalibre <= (consignes[0].consigne - hysteresis1));
  }
}

void hysteresisTempCanicule() {
  if (tempCanicule) {
    tempCanicule = (tempExtLueCalibre <= (consignes[1].consigne + hysteresis0));
  } else {
    tempCanicule = (tempExtLueCalibre <= (consignes[1].consigne - hysteresis0));
  }
}

// les hysteresis de consignes vitesses ventilation
void hysteresisTempVentIntCh() {
  if (tempVentIntCh) {
    tempVentIntCh = (tempUnitIntLueCalibre >= (consignes[9].consigne - hysteresis0));
  } else {
    tempVentIntCh = (tempUnitIntLueCalibre >= (consignes[9].consigne + hysteresis0));
  }
}

void hysteresisTempVentExtCh() {
  if (tempVentExtCh) {
    tempVentExtCh = (tempUnitExtLueCalibre <= (consignes[3].consigne + hysteresis0));
  } else {
    tempVentExtCh = (tempUnitExtLueCalibre <= (consignes[3].consigne - hysteresis0));
  }
}

void hysteresisTempVentIntFr() {
  if (tempVentIntFr) {
    tempVentIntFr = (tempUnitIntLueCalibre <= (consignes[8].consigne + hysteresis0));
  } else {
    tempVentIntFr = (tempUnitIntLueCalibre <= (consignes[8].consigne - hysteresis0));
  }
}

void hysteresisTempVentExtFr() {
  if (tempVentExtFr) {
    tempVentExtFr = (tempUnitExtLueCalibre >= (consignes[2].consigne - hysteresis3));
  } else {
    tempVentExtFr = (tempUnitExtLueCalibre >= consignes[2].consigne);
  }
}

// fonction de temperature declenchement ventilation interieur chauffage
void activeTempVentIntCh() {
  if (tempEchangeurVentIntCh) {
  } else {
    tempEchangeurVentIntCh = (tempEchangeurIntLueCalibre >= consignes[12].consigne);
  }
}

// les clignotements des leds des fonctions en degivrage
void activeLedClignoteFr() {
  if (millis() - tempoLedFrClignoteDeg > 300) {
    tempoLedFrClignoteDeg = millis();
    ledFrCl = (ledFrCl == HIGH) ? LOW : HIGH;
    digitalWrite(ledFr, ledFrCl);
  }
}

void activeLedClignoteVentFr() {
  if (millis() - tempoLedFrClignoteDeg > 1000) {
    tempoLedFrClignoteDeg = millis();
    ledFrCl = (ledFrCl == HIGH) ? LOW : HIGH;
    digitalWrite(ledFr, ledFrCl);
  }
}

void activeLedClignoteCa() {
  if (millis() - tempoLedCaClignoteDeg > 300) {
    tempoLedCaClignoteDeg = millis();
    ledCaCl = (ledCaCl == HIGH) ? LOW : HIGH;
    digitalWrite(ledCa, ledCaCl);
  }
}

void activeLedClignoteVentCa() {
  if (millis() - tempoLedCaClignoteDeg > 1000) {
    tempoLedCaClignoteDeg = millis();
    ledCaCl = (ledCaCl == HIGH) ? LOW : HIGH;
    digitalWrite(ledCa, ledCaCl);
  }
}

void activeLedClignoteCh() {
  if (millis() - tempoLedChClignoteDeg > 300) {
    tempoLedChClignoteDeg = millis();
    ledChCl = (ledChCl == HIGH) ? LOW : HIGH;
    digitalWrite(ledCh, ledChCl);
  }
}

void activeLedClignoteVentCh() {
  if (millis() - tempoLedChClignoteDeg > 1000) {
    tempoLedChClignoteDeg = millis();
    ledChCl = (ledChCl == HIGH) ? LOW : HIGH;
    digitalWrite(ledCh, ledChCl);
  }
}

void activeLedClignoteFiltre() {
  if (millis() - tempoLedArretCompletProgramClignote >= 500) {
    tempoLedArretCompletProgramClignote = millis();
    ledChFrCaCl = (ledChFrCaCl == HIGH) ? LOW : HIGH;
    digitalWrite(ledFr, ledChFrCaCl);
    digitalWrite(ledCa, ledChFrCaCl);
    digitalWrite(ledCh, ledChFrCaCl);
  }
}

// les relais des ventilateurs interieur et exterieur
void activeRelaisVentIntFroid() {      // controle ventilateurs en FROID
  ventilationInt = true;
  if (tempVentIntFr) {                 // si : la temperature unite interieur est inferieur a consigne Petite vitesse interieur 23°C a l'aspiration
    digitalWrite(relaisVitesse1, HIGH);  // ventilateur interieur petite vitesse
    digitalWrite(relaisVitesse4, LOW);
  } else {                             // si non :
    digitalWrite(relaisVitesse4, HIGH);  // ventilateur interieur grande vitesse
    digitalWrite(relaisVitesse1, LOW);
  }
}

void activeRelaisVentExtFroid() {           // controle ventilateur exterieur en froid
  digitalWrite(relaisVentExt, HIGH);
  if (tempVentExtFr) {                     // si : la temperature unite exterieur est superieur a consigne grande vitesse exterieur 20°C ambiante
    digitalWrite(relaisVitesseExt, HIGH);     // ventilateur exterieur grande vitesse
  } else {                                 // si non :
    digitalWrite(relaisVitesseExt, LOW);      // ventilateur exterieur petite vitesse
  }
}

void activeRelaisVentIntCh() { // controle ventilateur interieur en chauffage
  ventilationInt = true;
  if (tempVentIntCh) {                 // si : la temperature unite interieur est superieur a consigne petite vitesse 20°C a l'aspiration
    digitalWrite(relaisVitesse1, HIGH);  // petite vitesse
    digitalWrite(relaisVitesse4, LOW);
  } else {                             // si non :
    digitalWrite(relaisVitesse4, HIGH);  // grande vitesse
    digitalWrite(relaisVitesse1, LOW);
  }
}

void activeRelaisVentExtCh() {             // controle ventilateur exterieur en chauffage
  digitalWrite(relaisVentExt, HIGH);       // ventilateur exterieur (coupure au neutre);
  if (tempVentExtCh) {                     // si : la temperature unite exterieur est inferieur a 5°C ambiante
    digitalWrite(relaisVitesseExt, HIGH);     // ventilateur exterieur grande vitesse
  } else {                                 // si non :
    digitalWrite(relaisVitesseExt, LOW);      // ventilateur exterieur petite vitesse
  }
}

void activeRelaisVents() {  // controle ventilateurs Interieur Canicule
  ventilationInt = true;
  digitalWrite(relaisVitesse4, HIGH);  // relais ventilateur interieur grande vitesse
  digitalWrite(relaisVentExt, HIGH);
  digitalWrite(relaisVitesseExt, HIGH); // relais ventilateur exterieur Grande vitesse
}

void activeRelaisVentEgouttage() {
  digitalWrite(relaisVentExt, HIGH);
  digitalWrite(relaisVitesseExt, HIGH);
}

// l'arret des relais
void desactiveTousRelais() {
  ventilationInt = false;
  digitalWrite(relaisVentExt, LOW);
  digitalWrite(relaisVitesse1, LOW);
  digitalWrite(relaisVitesse2, LOW);
  digitalWrite(relaisVitesse3, LOW);
  digitalWrite(relaisVitesse4, LOW);
  digitalWrite(relaisVitesseExt, LOW);
  digitalWrite(relaisComp, LOW);
  digitalWrite(relaisV4V, LOW);
}

void desactiveRelaisVentInt() {
  ventilationInt = false;
  digitalWrite(relaisVitesse1, LOW);
  digitalWrite(relaisVitesse2, LOW);
  digitalWrite(relaisVitesse3, LOW);
  digitalWrite(relaisVitesse4, LOW);
}

// les affichages des etats du gainable
void affichageGainable() { // affichage des etats et des sympboles sur la ligne 1
  afficheTempsCalibre(); // affcihage nom des sondes et leurs temperatures sur la ligne 0
  if (etatsGainable == VENTILATION_FROID) {
    if (circulationAir == true) {
      lcd.setCursor(0, 0);
      lcd.print("Ventilation  ");
      if (digitalRead(relaisVitesse4) == HIGH) {
        lcd.setCursor(13, 0);
        lcd.print(char(6));
        lcd.setCursor(14, 0);
        lcd.print("4 ");
      }
    } else if (circulationAir == false) {
      lcd.setCursor(0, 0);
      lcd.print("Froid oFF       ");
    }
  } else if (etatsGainable == TEMPO_V4V || etatsGainable == TEMPO_COMPRESSEUR_FROID || etatsGainable == TEMPO_DEGIVRAGE_FROID) {
    lcd.setCursor(0, 0);
    lcd.print("Froid        ");
    if (digitalRead(relaisComp)) {
      lcd.setCursor(15, 0);
      lcd.print(char(0));
    }
    if (forceVentDegFr == true) {
      lcd.setCursor(14, 0);
      lcd.print("4");
    } else if (ventilationInt == true) {
      lcd.setCursor(13, 0);
      lcd.print(char(6));
      if (modifVitesseInt == true) {
        lcd.setCursor(14, 0);
        lcd.print(vitesseTravail);
      } else {
        if (digitalRead(relaisVitesse4)) {
          lcd.setCursor(14, 0);
          lcd.print("4");
        } else {
          lcd.setCursor(14, 0);
          lcd.print("1");
        }
      }
    } else {
      lcd.setCursor(0, 0);
      lcd.print("Froid           ");
    }
  } else if (etatsGainable == DEGIVRAGE_FROID) {
    lcd.setCursor(0, 0);
    lcd.print("Degivrage      ");
    lcd.setCursor(15, 0);
    lcd.print(char(2));
  } else if (etatsGainable == EGOUTTAGE_FROID) {
    lcd.setCursor(0, 0);
    lcd.print("Egouttage      ");
    lcd.setCursor(15, 0);
    lcd.print(char(3));
  } else if (etatsGainable == VENTILATION_CHAUFFAGE) {
    if (circulationAir == true) {
      lcd.setCursor(0, 0);
      lcd.print("Ventilation  ");
      if (digitalRead(relaisVitesse4) == HIGH) {
        lcd.setCursor(13, 0);
        lcd.print(char(6));
        lcd.setCursor(14, 0);
        lcd.print("4 ");
      }
    } else if (circulationAir == false) {
      lcd.setCursor(0, 0);
      lcd.print("Chauffage oFF   ");
    }
  } else if (etatsGainable == TEMPO_COMPRESSEUR_CHAUFFAGE || etatsGainable == TEMPO_DEGIVRAGE || etatsGainable == MODE_DEGIVRAGE) {
    lcd.setCursor(0, 0);
    lcd.print("Chauffage    ");
    if (digitalRead(relaisComp)) {
      lcd.setCursor(15, 0);
      lcd.print(char(1));
      if (ventilationInt == true) {
        lcd.setCursor(13, 0);
        lcd.print(char(6));
        if (modifVitesseInt == true) {
          lcd.setCursor(14, 0);
          lcd.print(vitesseTravail);
        } else {
          if (digitalRead(relaisVitesse4)) {
            lcd.setCursor(14, 0);
            lcd.print("4");
          } else {
            lcd.setCursor(14, 0);
            lcd.print("1");
          }
        }
      }
    } else {
      lcd.setCursor(0, 0);
      lcd.print("Chauffage       ");
    }
  } else if (etatsGainable == DEGIVRAGE_NATUREL) {
    lcd.setCursor(0, 0);
    lcd.print("Degivrage      ");
    lcd.setCursor(15, 0);
    lcd.print(char(3));
  } else if (etatsGainable == EGOUTTAGE_NATUREL) {
    lcd.setCursor(0, 0);
    lcd.print("Egouttage      ");
    lcd.setCursor(15, 0);
    lcd.print(char(4));
  } else if (etatsGainable == TEMPO_DEG_V4V || etatsGainable == TEMPO_DEG_COMPRESSEUR || etatsGainable == DEGIVRAGE_ELECTRIC) {
    lcd.setCursor(0, 0);
    lcd.print("Degivrage     ");
    lcd.setCursor(14, 0);
    lcd.print(char(4));
    lcd.setCursor(15, 0);
    lcd.print(char(3));
  } else if (etatsGainable == EGOUTTAGE_CHAUFFAGE) {
    lcd.setCursor(0, 0);
    lcd.print("Egouttage     ");
    lcd.setCursor(14, 0);
    lcd.print(char(4));
    lcd.setCursor(15, 0);
    lcd.print(char(3));
  } else if (etatsGainable == FIN_EGOUTTAGE_CHAUFFAGE) {
    lcd.setCursor(0, 0);
    lcd.print("Fin Egouttage ");
    lcd.setCursor(14, 0);
    lcd.print(char(4));
    lcd.setCursor(15, 0);
    lcd.print(char(3));
  } else if (etatsGainable == VENTILATION_CANICULE) {
    if (circulationAir == true) {
      affiche("Ventilation  ", 0);
      lcd.setCursor(13, 0);
      lcd.print(char(6));
      lcd.setCursor(14, 0);
      lcd.print("4 ");
    } else if (circulationAir == false) {
      affiche("Canicule oFF     ", 0);
    }
  } else if (etatsGainable == TEMPO_V4V_CANICULE || etatsGainable == TEMPO_COMPRESSEUR_CANICULE || etatsGainable == TEMPO_DEGIVRAGE_CANICULE) {
    lcd.setCursor(0, 0);
    lcd.print("Canicule     ");
    lcd.setCursor(12, 0);
    lcd.print(char(5));
    lcd.setCursor(13, 0);
    lcd.print(char(6));
    if (ventilationInt == true) {
      lcd.setCursor(14, 0);
      lcd.print("4");
    }
    if (digitalRead(relaisComp)) {
      lcd.setCursor(15, 0);
      lcd.print(char(0));
    }
  }
}

// les etats du gainable possible pour modifier les vitesses interieur
void vitesseGainable() { // les etats Gainable pour modifier vitesse ventilateur interieur
  if (etatsGainable == TEMPO_DEGIVRAGE_FROID || (tempChauffage == true && etatsGainable == TEMPO_DEGIVRAGE) || etatsGainable == MODE_DEGIVRAGE) {
    etablirModeVitesse();
  } else {
    etablirModeEteint();
  }
}

void autoMode() {
  if (millis() - tempoAutoMode >= 10000) {
    etatsGainable = DEPART;
  }
}

// le gainable
void gainable() {

  majCapteurs();

  if (departGainable == false) {
    etatsGainable = ARRET;
  }

  switch (etatsGainable) {

    case ARRET:

      if (departGainable == true) {
        tempoAutoMode = millis();
        etatsGainable = DEPART;
      } else if (entretienFiltre == true) {
        digitalWrite(relaisVolets, LOW);
        activeLedClignoteFiltre();
      } else {
        desactiveTousRelais();
        digitalWrite(relaisVolets, LOW);
        digitalWrite(ledCa, LOW);
        digitalWrite(ledFr, LOW);
        digitalWrite(ledCh, LOW);
      }
      break;

    case DEPART:  // controle automatique de la temperature pour selectionner le mode

      if (nettoyageFiltre >= 42500) {  // 49 jours de fonctionnement du compresseur 4250000000ms
        entretienFiltre = true;
        departGainable = false;
      } else if (tempEteHiver) {  // si la temperature exterieur est inferieur as la consigne (12.5°C)
        tempoAutoMode = millis();
        tempoCh = millis();
        tempoVentilation = millis();
        digitalWrite(relaisVolets, HIGH); // relai volets en mode chauffage
        etatsGainable = VENTILATION_CHAUFFAGE;
      } else if (tempCanicule) {  // si non si la temperature exterieur est inferieur a la consigne canicule (30°C)
        tempoAutoMode = millis();
        tempoCh = millis();
        tempoVentilation = millis();
        etatsGainable = VENTILATION_FROID;
      } else {
        tempoAutoMode = millis();
        tempoFr = millis();
        tempoVentilation = millis();
        etatsGainable = VENTILATION_CANICULE;
      }
      break;

    case VENTILATION_FROID:

      if (thermostats.pressedFor(ms)) { // si un des thermosats est enclencher
        if (millis() - tempoVentilation >= 10000) { // tempo de 10 secondes
          if (millis() - tempoFr >= 18000) { // tempo de 3 minutes
            if (tempUnitIntLueCalibre > consignes[10].consigne) { // si la temperature unité interieur est superieur as 24°C
              tempoV4VFr = millis(); // enregistre le temps pour V4V
              circulationAir = false; // circulation de l'air off
              etatsGainable = TEMPO_V4V;
            } else if (tempUnitIntLueCalibre < consignes[11].consigne) { // si non si la temperature interieur est inferieur as 22°C
              tempoVentilation = millis(); // enregistre le temp pour ventilation
              digitalWrite(ledFr, LOW); // eteint led froid
              digitalWrite(relaisVolets, HIGH); // relai volets en mode chauffage
              etatsGainable = VENTILATION_CHAUFFAGE; // passe dans l'etats commande chauffage
            }
          } else { // si non
            digitalWrite(relaisVitesse4, HIGH);
            activeLedClignoteVentFr(); // active le clignotement de 1 seconde de la led froid
          }
        } else {
          circulationAir = true; // circulation de l'air on
          tempoFr = millis();
          activeLedClignoteVentFr();
        }
      } else { // si non
        circulationAir = false; // circulation de l'air off
        digitalWrite(ledFr, LOW); // led froid off
        digitalWrite(ledCh, LOW); // led chauffage off
        digitalWrite(ledCa, LOW); // led canicule off
        desactiveTousRelais(); // desactive tous les relais
        tempoVentilation = millis(); // enregistre temps pour tempoventilation
        autoMode(); // controle temperature exterieur (nord)
      }
      break;

    case TEMPO_V4V:

      if (thermostats.releasedFor(ms)) {
        etatsGainable = DEPART;
      } else if (millis() - tempoV4VFr >= 6000) {  // temporisation de 1 minute
        tempoCompFr = millis();
        etatsGainable = TEMPO_COMPRESSEUR_FROID;
      } else {
        activeRelaisVentExtFroid();
        digitalWrite(ledFr, HIGH);
        if (modifVitesseInt == false) {
          activeRelaisVentIntFroid();
        }  else {
          vitesseInterieur();
        }
      }
      break;

    case TEMPO_COMPRESSEUR_FROID:

      if (thermostats.onPress()) {
        etatsGainable = DEPART;
      } else if (millis() - tempoCompFr >= 18000) {  // temporisation de 3 minutes avant demarrage compresseur 180000ul
        departChronoFiltre = millis();
        tempoDegFr = millis();
        etatsGainable = TEMPO_DEGIVRAGE_FROID;
      } else {
        digitalWrite(relaisV4V, HIGH);
        activeRelaisVentExtFroid();
        if (modifVitesseInt == false) {
          activeRelaisVentIntFroid();
        }  else {
          vitesseInterieur();
        }
      }
      break;

    case TEMPO_DEGIVRAGE_FROID:

      if (thermostats.releasedFor(ms)) {
        finChronoFiltre = millis();
        nettoyageFiltre = (finChronoFiltre - departChronoFiltre) + nettoyageFiltre;
        etatsGainable = DEPART;
      } else if (millis() - tempoDegFr >= 60000) { // 20 minutes
        if (tempEchangeurIntLueCalibre < consignes[13].consigne) {
          forceVentDegFr = true;
          digitalWrite(relaisVitesse4, HIGH);
          digitalWrite(relaisVitesse1, LOW);
          digitalWrite(relaisVitesse2, LOW);
          digitalWrite(relaisVitesse3, LOW);
          if (millis() - tempoTempDegFr >= 30000) { // 1 minute
            if (tempEchangeurIntLueCalibre < consignes[13].consigne) {
              finChronoFiltre = millis();
              nettoyageFiltre = (finChronoFiltre - departChronoFiltre) + nettoyageFiltre;
              vitesseTravail = vitesses[0].vitesse;
              forceVentDegFr = false;
              etatsGainable = DEGIVRAGE_FROID;
            } else {
              tempoTempDegFr = millis();
            }
          }
        } else {
          forceVentDegFr = false;
          activeRelaisVentExtFroid();
          if (modifVitesseInt == false) {
            activeRelaisVentIntFroid();
          } else {
            vitesseInterieur();
          }
        }
      } else {
        digitalWrite(relaisComp, HIGH);
        tempoTempDegFr = millis();
        activeRelaisVentExtFroid();
        if (modifVitesseInt == false) {
          activeRelaisVentIntFroid();
        } else {
          vitesseInterieur();
        }
      }
      break;

    case DEGIVRAGE_FROID:

      if (tempEchangeurIntLueCalibre >= consignes[14].consigne) {
        tempoEgouttageFr = millis();
        etatsGainable = EGOUTTAGE_FROID;
      } else {
        desactiveTousRelais();
        if (caniculeLed == true) {
          activeLedClignoteCa();
        } else {
          activeLedClignoteFr();
        }
      }
      break;

    case EGOUTTAGE_FROID:  // etat EGOUTTAGE_FR

      if (millis() - tempoEgouttageFr >= 120000) {  // 120000ms = 2 minutes
        desactiveTousRelais();
        digitalWrite(ledFr, LOW);
        caniculeLed = false;
        etatsGainable = DEPART;
      } else {
        digitalWrite(relaisVitesse4, HIGH);
        if (caniculeLed == true) {
          activeLedClignoteCa();
        } else {
          activeLedClignoteFr();
        }
      }
      break;

    case VENTILATION_CHAUFFAGE:

      if (thermostats.pressedFor(ms)) {
        if (millis() - tempoVentilation >= 10000) { // tempo de 10 secondes
          if (millis() - tempoCh >= 18000) { // tempo de 3 minutes
            if (tempUnitIntLueCalibre < consignes[11].consigne) {
              if (tempUnitExtLueCalibre < consignes[5].consigne) {
                circulationAir = false;
                ventilation = false;
                tempoCompCh = millis();
                desactiveRelaisVentInt();
                etatsGainable = TEMPO_COMPRESSEUR_CHAUFFAGE;
              } else {
                tempoCh = millis();
              }
            } else if (tempUnitIntLueCalibre > consignes[10].consigne) {
              digitalWrite(ledCh, LOW);
              tempoVentilation = millis();
              digitalWrite(relaisVolets, LOW); // relai volets en mode Froid
              etatsGainable = VENTILATION_FROID;
            } else {
              tempoCh = millis();
            }
          } else {
            activeLedClignoteVentCh();
            digitalWrite(relaisVitesse4, HIGH);
          }
        } else {
          activeLedClignoteVentCh();
          circulationAir = true;
          tempoCh = millis();
        }
      } else {
        circulationAir = false;
        digitalWrite(ledCh, LOW);
        digitalWrite(ledFr, LOW);
        desactiveTousRelais();
        tempoVentilation = millis();
        autoMode();
      }
      break;

    case TEMPO_COMPRESSEUR_CHAUFFAGE:

      if (!thermostats.pressedFor(ms)) {
        etatsGainable = DEPART;
      } else if (millis() - tempoCompCh >= 18000) {  // temporisation de 3 minutes avant le demarage du compresseur 180000ul
        departChronoFiltre = millis();
        tempoDegCh = millis();
        etatsGainable = TEMPO_DEGIVRAGE;
      } else {
        activeRelaisVentExtCh();
        digitalWrite(ledCh, HIGH);
      }
      break;

    case TEMPO_DEGIVRAGE:

      if (!thermostats.pressedFor(ms)) {
        finChronoFiltre = millis();
        nettoyageFiltre = (finChronoFiltre - departChronoFiltre) + nettoyageFiltre;
        desactiveTousRelais();
        tempChauffage = false;
        etatsGainable = DEPART;
      } else if (millis() - tempoDegCh >= 240000) {  // si : la temporisation de 40 minutes (si compresseur a fonctionner pendant 40 minutes) 2400000ul
        finChronoFiltre = millis();
        nettoyageFiltre = (finChronoFiltre - departChronoFiltre) + nettoyageFiltre;
        etatsGainable = MODE_DEGIVRAGE;
      } else {
        digitalWrite(relaisComp, HIGH);
        activeRelaisVentExtCh();
        if (tempEchangeurVentIntCh) {
          tempChauffage = true;
          if (modifVitesseInt == false) {
            activeRelaisVentIntCh();
          } else {
            vitesseInterieur();
          }
        }
      }
      break;

    case MODE_DEGIVRAGE:

      if (tempUnitExtLueCalibre >= consignes[4].consigne) {  // si : la temperature de l'unité exterieur est supperieur ou egal a 5°C ( lancement degivrage naturel )
        tempoDegNat = millis();
        etatsGainable = DEGIVRAGE_NATUREL;                        // passe a l'etat DEGIVRAGE_NATUREL
      } else if (tempEchangeurExtLueCalibre <= consignes[6].consigne) {  // si : la temperature de l'Echangeur exterieur est inferieur ou egal a -3°C ( degivrage gaz chaud inversion de cycle )
        tempoV4VCh = millis();
        etatsGainable = TEMPO_DEG_V4V;
      } else {
        activeRelaisVentExtCh();
        if (modifVitesseInt == false) {
          activeRelaisVentIntCh();
        } else {
          vitesseInterieur();
        }
      }
      break;

    case DEGIVRAGE_NATUREL:  // etat DEGIVRAGE_NATUREL

      if (millis() - tempoDegNat >= 600000) {  // 600000ms = 10 minutes
        tempoEgouttageNat = millis();
        etatsGainable = EGOUTTAGE_NATUREL;  // passe a l'etat EGOUTTAGE_NATUREL
      } else {
        tempChauffage = false;
        desactiveTousRelais();
        activeLedClignoteCh();
      }
      break;

    case EGOUTTAGE_NATUREL:  // etat EGOUTTAGE_NATUREL

      if (millis() - tempoEgouttageNat >= 300000) {  // 300000ms
        digitalWrite(ledCh, LOW);
        desactiveTousRelais();
        etatsGainable = DEPART;  // passe a l'etat
      } else {
        vitesseTravail = vitesses[0].vitesse;
        activeRelaisVentEgouttage();
        activeLedClignoteCh();
      }
      break;

    case TEMPO_DEG_V4V:  // etat DEGIVRAGE_ELECTRIC

      if (millis() - tempoV4VCh >= 78000) {  // 78000ms 1 minute 30 secondes
        tempoCompCh = millis();
        etatsGainable = TEMPO_DEG_COMPRESSEUR;
      } else {
        desactiveTousRelais();
        activeLedClignoteCh();
      }
      break;

    case TEMPO_DEG_COMPRESSEUR:

      if (millis() - tempoCompCh >= 120000) {  // 120000ms 2 minutes
        tempoTempDegEle = millis();
        etatsGainable = DEGIVRAGE_ELECTRIC;
      } else {
        digitalWrite(relaisV4V, HIGH);  // relais vanne 4 voies oN
        activeLedClignoteCh();
      }
      break;

    case DEGIVRAGE_ELECTRIC:

      if (tempEchangeurExtLueCalibre >= consignes[7].consigne || (millis() - tempoTempDegEle >= 600000ul)) {  // si la temperature est superieur ou egal a 12.5°C ( fin de degivrage )
        tempoEgouttageEle = millis();
        etatsGainable = EGOUTTAGE_CHAUFFAGE;  // passe a l'etat EGOUTTAGE_ELECTRIC
      } else {
        digitalWrite(relaisComp, HIGH);  // relais compresseur oN
        activeLedClignoteCh();
      }
      break;

    case EGOUTTAGE_CHAUFFAGE:  // etat EGOUTTAGE_ELECTRIC

      if (millis() - tempoEgouttageEle >= 300000) {  // 300000ms = 5 minutes
        tempoFinEgouttageEle = millis();
        etatsGainable = FIN_EGOUTTAGE_CHAUFFAGE;  // passe a l'etat FIN_EGOUTTAGE_ELE
      } else {
        desactiveTousRelais();
        activeLedClignoteCh();
      }
      break;

    case FIN_EGOUTTAGE_CHAUFFAGE:  // etat FIN_EGOUTTAGE_ELE

      if (millis() - tempoFinEgouttageEle >= 150000) {  // 150000ms = 2.5 minutes
        desactiveTousRelais();
        digitalWrite(ledCh, LOW);
        etatsGainable = DEPART;  // passe a l'etat
      } else {
        vitesseTravail = vitesses[0].vitesse;
        activeRelaisVentEgouttage();
        activeLedClignoteCh();
      }
      break;

    case VENTILATION_CANICULE:  // etat FROID_CANICULE

      if (thermostats.pressedFor(ms)) {
        if (millis() - tempoVentilation >= 1000) {
          if (millis() - tempoCa >= 18000) {
            if (tempUnitIntLueCalibre > consigneIntCa) {
              circulationAir = false;
              tempoV4VFr = millis();
              etatsGainable = TEMPO_V4V_CANICULE;
            } else {
              tempoCa = millis();
            }
          } else {
            activeLedClignoteVentCa();
            digitalWrite(relaisVitesse4, HIGH);
          }
        } else {
          activeLedClignoteVentCa();
          circulationAir = true;
        }
      } else {
        circulationAir = false;
        digitalWrite(ledCa, LOW);
        digitalWrite(ledFr, LOW);
        desactiveTousRelais();
        tempoVentilation = millis();
        autoMode();
      }
      break;

    case TEMPO_V4V_CANICULE:

      if (!thermostats.pressedFor(ms)) {
        etatsGainable = DEPART;
      } else if (millis() - tempoV4VFr >= 6000) {  // temporisation de 1 minute
        tempoCompFr = millis();
        etatsGainable = TEMPO_COMPRESSEUR_CANICULE;
      } else {
        activeRelaisVents();
        digitalWrite(ledCa, HIGH);
      }
      break;

    case TEMPO_COMPRESSEUR_CANICULE:

      if (!thermostats.pressedFor(ms)) {
        etatsGainable = DEPART;
      } else if (millis() - tempoCompFr >= 18000) {  // temporisation de 3 minutes avant demarrage compresseur
        departChronoFiltre = millis();
        etatsGainable = TEMPO_DEGIVRAGE_CANICULE;
      } else {
        digitalWrite(relaisV4V, HIGH);
        activeRelaisVents();
      }
      break;

    case TEMPO_DEGIVRAGE_CANICULE:

      if (!thermostats.pressedFor(ms)) {
        finChronoFiltre = millis();
        nettoyageFiltre = (finChronoFiltre - departChronoFiltre) + nettoyageFiltre;
        etatsGainable = DEPART;
      } else if (millis() - tempoDegFr >= 60000) { // 20 minutes
        if (tempEchangeurIntLueCalibre < consignes[13].consigne) {
          if (millis() - tempoTempDegFr >= 30000) { // 1 minute
            if (tempEchangeurIntLueCalibre < consignes[13].consigne) {
              finChronoFiltre = millis();
              nettoyageFiltre = (finChronoFiltre - departChronoFiltre) + nettoyageFiltre;
              caniculeLed = true;
              etatsGainable = DEGIVRAGE_FROID;
            } else {
              tempoTempDegFr = millis();
            }
          }
        } else {
          tempoTempDegFr = millis();
        }
      } else {
        digitalWrite(relaisComp, HIGH);
        tempoTempDegFr = millis();
        activeRelaisVents();
      }
      break;
  }
}

// la fonction calculs
void autresCalculs() {
  tempExtLueCalibre = sondes[0].temperature + calibrages[0].calibrage;
  tempUnitExtLueCalibre = sondes[1].temperature + calibrages[1].calibrage;
  tempEchangeurExtLueCalibre = sondes[2].temperature + calibrages[2].calibrage;
  tempUnitIntLueCalibre = sondes[3].temperature + calibrages[3].calibrage;
  tempEchangeurIntLueCalibre = sondes[4].temperature + calibrages[4].calibrage;
  consigneIntCa = sondes[0].temperature - consignes[15].consigne;  // consigne interieur canicule est egale a la temperature exterieur (NORD) - temperature delta (-6)
  hysteresisTempEteHiver();
  hysteresisTempCanicule();
  hysteresisTempVentIntCh();
  hysteresisTempVentExtCh();
  hysteresisTempVentIntFr();
  hysteresisTempVentExtFr();
  activeTempVentIntCh();
}

// l'affichage Serial
void imprimeTout() {
  const unsigned long deltaT = 2500;    // en ms, toutes les 2,5 secondes
  static unsigned long chrono = -deltaT;  // valeur initiale pour affichage au premier appel

  if (millis() - chrono >= deltaT) {

    Serial.print(F("chrono : "));
    Serial.println(chrono);

    for (byte i = 0; i <= nombreDeSondes; i++) sondes[i].lireTemperature();

    Serial.print(F("tempExtLue = "));
    Serial.println(sondes[0].temperature);
    Serial.println(tempExtLueCalibre);

    const char* nomDesEtats[] = { "ARRET", "DEPART", "VENTILATION_FROID", "TEMPO_V4V", "TEMPO_COMPRESSEUR_FROID", "TEMPO_DEGIVRAGE_FROID", "DEGIVRAGE_FROID", "EGOUTTAGE_FROID", "VENTILATION_CHAUFFAGE", "TEMPO_COMPRESSEUR_CHAUFFAGE", "TEMPO_DEGIVRAGE", "MODE_DEGIVRAGE", "DEGIVRAGE_NATUREL", "EGOUTTAGE_NATUREL", "TEMPO_DEG_V4V", "TEMPO_DEG_COMPRESSEUR", "DEGIVRAGE_ELECTRIC", "EGOUTTAGE_CHAUFFAGE", "FIN_EGOUTTAGE_CHAUFFAGE", "VENTILATION_CANICULE", "TEMPO_V4V_CANICULE", "TEMPO_COMPRESSEUR_CANICULE", "TEMPO_DEGIVRAGE_CANICULE" };
    Serial.print(F("ETAT: "));
    Serial.println(nomDesEtats[etatsGainable]);

    const char* nomDesEtatsMode[] = { "ETEINT", "TEST_RELAIS", "CONSIGNE", "DETAIL_CONSIGNE", "CALIBRAGE", "DETAIL_CALIBRAGE", "VITESSE", "ACTIF", "AUTOMATIQUE", "NETTOYAGE_FILTRE" };
    Serial.print(F("MODE: "));
    Serial.println(nomDesEtatsMode[mode]);

    Serial.print(F("Nettoyage filtre = "));
    Serial.println(nettoyageFiltre);

    chrono = millis();
  }
}

// le setup
void setup() {
  pinMode(relaisComp, OUTPUT);            // Relais Compresseur
  pinMode(relaisV4V, OUTPUT);             // Relais Vanne 4 Voies
  pinMode(relaisVentExt, OUTPUT);    // Relais Coupure Neutre
  pinMode(relaisVitesseExt, OUTPUT);         // Relais Ventilateur Exterieur grande et petite vitesse
  pinMode(relaisVitesse1, OUTPUT);    // Relais Ventilateur unité interieur
  pinMode(relaisVitesse2, OUTPUT);         // Relais Ventilateur Interieur grande et petite vitesse
  pinMode(relaisVitesse3, OUTPUT);       // Relais ventilateur Interieur petite vitesse
  pinMode(relaisVitesse4, OUTPUT);       // Relais ventilateur Interieur Grande Vitesse
  pinMode(relaisVolets, OUTPUT);     // Relais Automatique
  pinMode(ledCa, OUTPUT);                 // LED fonction canicule
  pinMode(ledFr, OUTPUT);                 // LED fonction Froid
  pinMode(ledCh, OUTPUT);                 // LED fonction Chauffage
  pinMode(ledBoutonMenu, OUTPUT);         // LED Bouton Menu
  pinMode(ledBoutonValid, OUTPUT);        // LED Bouton Valid
  pinMode(ledBoutonPlus, OUTPUT);         // LED Bouton Plus
  pinMode(ledBoutonMoins, OUTPUT);        // LED Bouton Moins
  thermostats.begin(thermostatsPin);      // Contact NC/NO Thermostat Radio Chambre 1
  capteurFiltre.begin(capteurFiltrePin);  // Capteur Presence Filtre
  boutonMenu.begin(menuPin);              // Bouton Menu
  boutonValid.begin(validPin);            // Bouton Valid
  boutonPlus.begin(boutonPlusPin);        // Bouton Plus
  boutonMoins.begin(boutonMoinsPin);      // Bouton Moins

  for (size_t indice = 0; indice < nombreDeConsignes; indice++);

  for (size_t indice = 0; indice < nombreDeCalibrages; indice++);

  Serial.begin(115200);

  int result = lcd.begin(nbColonnes, nbLignes);
  if (result) {
    Serial.print("LCD initialization failed: ");
    Serial.println(result);
    hd44780::fatalError(result);
  }
  lcd.createChar(0, flecheFr);
  lcd.createChar(1, flecheCh);
  lcd.createChar(2, degivrage);
  lcd.createChar(3, goutte);
  lcd.createChar(4, eclaire);
  lcd.createChar(5, soleil);
  lcd.createChar(6, ventilateur);
  lcd.clear();

  etablirModeEteint();
}

// la loop
void loop() {
  gestionEtat();
  autresCalculs();
  imprimeTout();
}
mega:SCL
mega:SDA
mega:AREF
mega:GND.1
mega:13
mega:12
mega:11
mega:10
mega:9
mega:8
mega:7
mega:6
mega:5
mega:4
mega:3
mega:2
mega:1
mega:0
mega:14
mega:15
mega:16
mega:17
mega:18
mega:19
mega:20
mega:21
mega:5V.1
mega:5V.2
mega:22
mega:23
mega:24
mega:25
mega:26
mega:27
mega:28
mega:29
mega:30
mega:31
mega:32
mega:33
mega:34
mega:35
mega:36
mega:37
mega:38
mega:39
mega:40
mega:41
mega:42
mega:43
mega:44
mega:45
mega:46
mega:47
mega:48
mega:49
mega:50
mega:51
mega:52
mega:53
mega:GND.4
mega:GND.5
mega:IOREF
mega:RESET
mega:3.3V
mega:5V
mega:GND.2
mega:GND.3
mega:VIN
mega:A0
mega:A1
mega:A2
mega:A3
mega:A4
mega:A5
mega:A6
mega:A7
mega:A8
mega:A9
mega:A10
mega:A11
mega:A12
mega:A13
mega:A14
mega:A15
btn1:1.l
btn1:2.l
btn1:1.r
btn1:2.r
btn2:1.l
btn2:2.l
btn2:1.r
btn2:2.r
btn3:1.l
btn3:2.l
btn3:1.r
btn3:2.r
btn4:1.l
btn4:2.l
btn4:1.r
btn4:2.r
lcd1:GND
lcd1:VCC
lcd1:SDA
lcd1:SCL
sw1:1
sw1:2
sw1:3
NOCOMNCVCCGNDINLED1PWRRelay Module
relay1:VCC
relay1:GND
relay1:IN
relay1:NC
relay1:COM
relay1:NO
NOCOMNCVCCGNDINLED1PWRRelay Module
relay2:VCC
relay2:GND
relay2:IN
relay2:NC
relay2:COM
relay2:NO
NOCOMNCVCCGNDINLED1PWRRelay Module
relay3:VCC
relay3:GND
relay3:IN
relay3:NC
relay3:COM
relay3:NO
NOCOMNCVCCGNDINLED1PWRRelay Module
relay4:VCC
relay4:GND
relay4:IN
relay4:NC
relay4:COM
relay4:NO
NOCOMNCVCCGNDINLED1PWRRelay Module
relay5:VCC
relay5:GND
relay5:IN
relay5:NC
relay5:COM
relay5:NO
NOCOMNCVCCGNDINLED1PWRRelay Module
relay6:VCC
relay6:GND
relay6:IN
relay6:NC
relay6:COM
relay6:NO
NOCOMNCVCCGNDINLED1PWRRelay Module
relay7:VCC
relay7:GND
relay7:IN
relay7:NC
relay7:COM
relay7:NO
NOCOMNCVCCGNDINLED1PWRRelay Module
relay8:VCC
relay8:GND
relay8:IN
relay8:NC
relay8:COM
relay8:NO
led1:A
led1:C
led2:A
led2:C
led3:A
led3:C
r1:1
r1:2
r2:1
r2:2
r3:1
r3:2
sw6:1
sw6:2
sw6:3
led4:A
led4:C
led5:A
led5:C
led6:A
led6:C
led7:A
led7:C
r4:1
r4:2
r5:1
r5:2
r6:1
r6:2
r7:1
r7:2
NOCOMNCVCCGNDINLED1PWRRelay Module
relay9:VCC
relay9:GND
relay9:IN
relay9:NC
relay9:COM
relay9:NO
sw2:1
sw2:2
sw2:3
sw3:1
sw3:2
sw3:3
sw4:1
sw4:2
sw4:3
sw5:1
sw5:2
sw5:3
ntc1:GND
ntc1:VCC
ntc1:OUT
ntc2:GND
ntc2:VCC
ntc2:OUT
ntc3:GND
ntc3:VCC
ntc3:OUT
ntc4:GND
ntc4:VCC
ntc4:OUT
ntc5:GND
ntc5:VCC
ntc5:OUT