1 – Déclaration variables

#include <lib.h>

// todo--------------------------------------Variables générales ----------------------------
const char *PARAM_INPUT_1 = "output";
const char *PARAM_INPUT_2 = "state";
int led = LED_BUILTIN; // led interne au ESP8266 fonction sur recherche connexion WIFI
int cpt = 0;
uint8_t wifi_ok = 1;
int Mode_AM = false;
String inputMessage1;
String inputMessage2;
int val_out = 0;
int val_state = 0;
int AutoManu = 0;
String T1M, T2M; // Ajout 0 si les Mn plage horaire

String mode_am = "";
AsyncWebServer server(80); // Create AsyncWebServer object on port 80

//----------------------------------------- Afficheur LCD ---------------------------------------

#define SCREEN_WIDTH 128    // OLED largeur écran en pixels
#define SCREEN_HEIGHT 32    // OLED hauteur écran en pixels
#define OLED_RESET -1       // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C // L'adresse i2c -> 0x3C de l'écran oled 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
uint16_t EcritureTexteBlanc = SSD1306_WHITE; // Affichage du texte en "blanc"
uint16_t EcritureTexteNoir = SSD1306_BLACK;  // Affichage du texte en "noir"
uint16_t FondTexteBlanc = SSD1306_WHITE;     // Affichage du fond texte en "blanc"
uint16_t FondTexteNoir = SSD1306_BLACK;      // Affichage du fond texte en "noir"
unsigned long timer_ecran = millis();        // Compteur gestion marche arrêt écran
unsigned long tempo_ecran = 100000;          // valeur de la durée avec extinction écran
int ecran = 0;                               // Drapeau bascule ecran
#define input_ecran 15                       // (D8) BP cde allumage ecran

// important -------------------------------------- Gestion PCF8574 -------------------------------
PCF8574 PCF_21(0x21); // Ajout entrées sorties avec module PCF8574 à l'adresse 0X21

// *** les interrupteurs de commande
uint8_t I_EV1; // Goutte a goutte avant
uint8_t I_EV2; // Goutte a goutte arrière
uint8_t I_EV3; // Circuit tuyeres
uint8_t I_EV4; // Circuit turbines

// *** les sorties relais
int S_EV1 = 3; // Sortie relais
int S_EV2 = 2; // Sortie relais
int S_EV3 = 1; // Sortie relais
int S_EV4 = 0; // Sortie relais

//--------------------------------------Variables gestion horaire ----------------------
//***** Gestion Heures minutes EV1 tranche 1 *****
String T1_Debut_EV1, T1_Debut_M_EV1, T1_Nb_Cycle_EV1, T1_Periode_Cycle_EV1, T1_Duree_Cycle_EV1; // Déclaration des variables pour la page web
int T1_Total_Debut_EV1, T1_Total_Fin_Cycle_EV1, T1_Cpt_Nb_Cycle_EV1;
int T1_Debut_EV1_Int, T1_Debut_M_EV1_Int, Nb_Cycle_EV1_Int, T1_Periode_Cycle_EV1_Int, T1_Duree_Cycle_EV1_Int;

//------------------------ Variables température & humidité  ATH10----------------------------

Adafruit_AHTX0 aht; // SCL -> D1 - SDA -> D2
int humidite;       //
sensors_event_t humidity, temp;

//--------------------------------- Variables GPS --------------------------------------
#define SerialGPS Serial                    // Définir les entrées TX & RX du gps
TinyGPSPlus gps;                            // Lib TinyGPS et SoftwareSerial sont l'œuvre de Mikal Hart
time_t prevDisplay = 0;                     // lorsque l'horloge numérique était affichée
float Latitude, Longitude;                  // variables GPS
int Year, Month, Day, Hour, Minute, Second; // Mois, jour, heure, minute, seconde GPS
int changement_heure = 2;                   // Décalage des heures par rapport à l'heure GPS (UTC)

//--------------------------Variables Heure & date ------------------------------------------

String zs;                  // pour ajout 0 formatage ex seconde 02
String zmn;                 // pour ajout 0 formatage ex minute 02
String zh;                  // pour ajout 0 formatage ex heure 02
String zmois;               // pour ajout 0 formatage ex  mois 05
String val_heure, val_date; // calcul de l'heure au format String"02:05:05" ou "10:15:25"
int total_mn_gps;           // Calcul le total en minute de l'heure réelle.
// String Val_T1EV1;           //= "test pour verification bon fonctionnement "; // Création d'une variable pour affichage WEB de la plage horaire de EV1 (début fin matin )
//  String Plage_horaire_EV2;        // Création d'une variable pour affichage WEB de la plage horaire de EV2 (début fin matin )
String EtatWeb_EV1, EtatWeb_EV2; // envois sur web état inter marche forcée

// ---------------------------------- Variables sonde pluie -----------------------------------
String EtatPluie;
int presence_pluie;    // si detection pluie alors "presence_pluie" = 1 (microswitch "NO" sur la sonde )

Les fonctions

//-------------------------------------- Sous programmes -------------------------------

void ecriture_json()
{ // Créer un document JSON avec la capacité définie
  JsonDocument doc;
  // Assigner des valeurs aux variables
  doc["T1_Debut_EV1"] = T1_Debut_EV1;
  doc["T1_Debut_M_EV1"] = T1_Debut_M_EV1;
  doc["T1_Nb_Cycle_EV1"] = T1_Nb_Cycle_EV1;
  doc["T1_Periode_Cycle_EV1"] = T1_Periode_Cycle_EV1;
  doc["T1_Duree_Cycle_EV1"] = T1_Duree_Cycle_EV1;

  // Convertir le document JSON en chaîne JSON
  String output;
  serializeJson(doc, output);

  // Enregistrer la chaîne JSON dans l'EEPROM
  for (size_t i = 0; i < output.length(); ++i)
  {
    EEPROM.write(i, output[i]);
  }
  EEPROM.commit(); // N'oubliez pas de faire un commit après avoir écrit dans l'EEPROM

  Serial.println("Données enregistrées dans l'EEPROM !");
}

void lecture_json()
{
  // Lire la chaîne JSON enregistrée dans l'EEPROM
  String input;
  for (int i = 0; i < 200; ++i)
  {
    input += char(EEPROM.read(i));
  }

  // Convertir la chaîne JSON en document JSON
  JsonDocument doc;
  DeserializationError error = deserializeJson(doc, input);
  if (error)
  {
    Serial.print("Erreur lors de la lecture du JSON : ");
    Serial.println(error.c_str());
    return;
  }

  // Extraire les valeurs du document JSON
  T1_Debut_EV1 = doc["T1_Debut_EV1"].as<String>();
  T1_Debut_M_EV1 = doc["T1_Debut_M_EV1"].as<String>();
  T1_Nb_Cycle_EV1 = doc["T1_Nb_Cycle_EV1"].as<String>();
  T1_Periode_Cycle_EV1 = doc["T1_Periode_Cycle_EV1"].as<String>();
  T1_Duree_Cycle_EV1 = doc["T1_Duree_Cycle_EV1"].as<String>();
  Serial.print(" lecture du JSON ok ");
}

String readHeure()
{
  if (val_heure == "")
  {
    val_heure = "En attente signal GPS";
    return val_heure;
  }
  else
  {
    // Serial.println(val_heure);
    return val_heure;
  }
}

String readDate()
{
  // Serial.println(val_date);
  return val_date;
}

String readAHTTemperature()
{
  aht.getEvent(&humidity, &temp);
  float temperatureInt = temp.temperature;
  if (isnan(temperatureInt))
  {
    Serial.println("Echec de la lecture du capteur AHT!");
    return "--";
  }
  else
  {
    // Serial.print("température :");
    // Serial.println(temperatureInt);
    return String(temperatureInt);
  }
}

String readAHTHumidity()
{
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  aht.getEvent(&humidity, &temp);
  humidite = humidity.relative_humidity;
  if (isnan(humidite))
  {
    Serial.println("Echec de la lecture du capteur AHT");
    return "--";
  }
  else
  {
    // Serial.print("Humidité :");
    // Serial.println(humidite);
    return String(humidite);
  }
}

String outputState(int output)
{
  if (digitalRead(output))
  {
    return "checked";
  }
  else
  {
    return "";
  }
}

void GestionZero()
{
  zh = "";
  if (Hour < 10)
  {
    zh = "0";
  }
  zmn = "";
  if (Minute < 10)
  {
    zmn = "0";
  }
  zs = "";
  if (Second < 10)
  {
    zs = "0";
  }

  zmois = "";
  if (Month < 10)
  {
    zmois = "0";
  }
}
void Affiche_gpio()
{
  Serial.print("GPIO: ");
  Serial.print(inputMessage1);
  Serial.print(" - Etat: ");
  Serial.println(inputMessage2);
  Serial.print(" - Mode Am ");
  Serial.println(Mode_AM);
}
void Clignotement(int temps)
{
  digitalWrite(led, LOW); // led clignote en attende de synchronisation avec le WIFI
  delay(temps);
  digitalWrite(led, HIGH);
  delay(temps);
}

void affiche_ecran()
{
  display.setCursor(0, 0);
  display.clearDisplay();
  display.print(val_date);
  display.print(" ");
  display.println(val_heure);
  display.setCursor(0, 24);
  display.print("Mem libre:");
  display.print(ESP.getFreeHeap()); // Imprimez la quantité de mémoire libre
  // display.println(" octets");
  display.display();
}

String readOut()
{
  String output = String(val_out);
  String state = String(val_state);
  return output + "&" + state;
}
// Replaces placeholder with button section in your web page
String processor(const String &var)
{

  if (var == "T1_Debut_EV1")
  {
    return T1_Debut_EV1;
  }

  if (var == "T1_Debut_M_EV1")
  {
    return T1_Debut_M_EV1;
  }

  if (var == "T1_Nb_Cycle_EV1")
  {
    return T1_Nb_Cycle_EV1;
  }

  if (var == "T1_Periode_Cycle_EV1")
  {
    return T1_Periode_Cycle_EV1;
  }

  if (var == "T1_Duree_Cycle_EV1")
  {
    return T1_Duree_Cycle_EV1;
  }

  if (var == "HEURE")
  {
    return readHeure();
  }

  if (var == "DATE")
  {
    return readDate();
  }

  if (var == "TEMPERATURE")
  {
    return readAHTTemperature();
  }
  else if (var == "HUMIDITY")
  {
    return readAHTHumidity();
  }
   if (var == "BUTTONPLACEHOLDER")
  {
    String buttons = "";
    // buttons += "<h4>Manu/Auto</h4><label class=\"switch\"><input type=\"checkbox\" onchange=\"toggleMode(this)\" id=\"modeSwitch\" " + outputState(1) + "><span class=\"slider\"></span></label>";
    buttons += "<h4>Manu/Auto</h4><label class=\"switch\"><input type=\"checkbox\" onchange=\"toggleCheckbox(this)\" id=\"4\" id=\"modeSwitch\"" + outputState(1) + "><span class=\"slider\"></span></label>";
    buttons += "<div id=\"manualControls\">";
    buttons += "<h4>Arret/Marche EV1</h4><label class=\"switch\"><input type=\"checkbox\" onchange=\"toggleCheckbox(this)\" id=\"3\" " + outputState(1) + "><span class=\"slider\"></span></label>";
    buttons += "<h4>Arret/Marche EV2</h4><label class=\"switch\"><input type=\"checkbox\" onchange=\"toggleCheckbox(this)\" id=\"2\" " + outputState(1) + "><span class=\"slider\"></span></label>";
    buttons += "<h4>Arret/Marche EV3</h4><label class=\"switch\"><input type=\"checkbox\" onchange=\"toggleCheckbox(this)\" id=\"1\" " + outputState(1) + "><span class=\"slider\"></span></label>";
    buttons += "<h4>Arret/Marche EV4</h4><label class=\"switch\"><input type=\"checkbox\" onchange=\"toggleCheckbox(this)\" id=\"0\" " + outputState(1) + "><span class=\"slider\"></span></label>";
    buttons += "</div>";

    return buttons;
  }
  return String();
}

Void (setup)

void setup()
{

  // Serial port for debugging purposes
  Serial.begin(9600);
  EEPROM.begin(512);
  PCF_21.begin(); // Entrées sortie sup.
  //-------------------------------------- Gestion AHT10 -------------------------------
  aht.begin();

  //---------------------------------------- Gestion GPS -------------------------------
  SerialGPS.begin(9600);

  //--------------------------- Gestion écran OLED -----------------------------

  pinMode(input_ecran, INPUT_PULLUP);

  if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS))
  {
    Serial.println(F("SSD1306 allocation erreur"));
    for (;;)
      ; // Ne continuez pas, bouclez pour toujours
  }
  display.clearDisplay();
  display.drawBitmap(0, 0, logo_arrosage, 128, 64, 1); // affiche le logo arrosage sur l'écran Oled
  display.display();
  delay(1000); // Pause de 1 secondes

  display.setCursor(0, 0); // Déplacement du curseur en position (0,0), angle supérieur gauche
  display.clearDisplay();
  display.setTextColor(EcritureTexteBlanc, FondTexteNoir);
  display.println("Recherche borne Wifi");

  //-------------------------------------- Gestion Wi-Fi -------------------------------
  WiFi.begin(ssid, password);
  Serial.print("Recherche borne Wifi");
  while (WiFi.status() != WL_CONNECTED)
  {
    Clignotement(500);
    Serial.print(".");
    display.print(".");
    display.display();
    cpt++;
    if (cpt == 1000)
    {
      wifi_ok = 0;
      return; // Sortir de la boucle si non connexion au bout de x tentatives}
    }
  }

  Serial.print("Connection à l'adresse  IP: ");
  Serial.println(WiFi.localIP());
  WiFi.printDiag(Serial); // imprimer les principales informations du wifi
  Serial.println();

  // ---------- Etat connection du wifi sur ecran Oled -------------

  display.setCursor(0, 0);
  display.clearDisplay();
  display.display();
  display.println(WiFi.localIP());
  display.display();

  lecture_json(); // lire les valeurs des heure et incorporer dans les variables

  //  ---- Page web bouton & varables (heure/date ...)  Initialisation du serveur Web ------------------

  server.on("/", HTTP_POST, [](AsyncWebServerRequest *request) { // HTTP POST ssid value
  });

  server.on("/get_out", HTTP_GET, [](AsyncWebServerRequest *request)
            { request->send_P(200, "text/plain", readOut().c_str()); });

  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request)
            { request->send_P(200, "text/html", index_html, processor); });
  server.on("/val_heure", HTTP_GET, [](AsyncWebServerRequest *request)
            { request->send_P(200, "text/plain", readHeure().c_str()); });
  server.on("/val_date", HTTP_GET, [](AsyncWebServerRequest *request)
            { request->send_P(200, "text/plain", readDate().c_str()); });
  server.on("/temperatureInt", HTTP_GET, [](AsyncWebServerRequest *request)
            { request->send_P(200, "text/plain", readAHTTemperature().c_str()); });
  server.on("/humidite", HTTP_GET, [](AsyncWebServerRequest *request)
            { request->send_P(200, "text/plain", readAHTHumidity().c_str()); });
  server.on("/update", HTTP_GET, [](AsyncWebServerRequest *request)
            {
    if (request->hasParam(PARAM_INPUT_1) && request->hasParam(PARAM_INPUT_2))
    {
      inputMessage1 = request->getParam(PARAM_INPUT_1)->value();
      inputMessage2 = request->getParam(PARAM_INPUT_2)->value();
    }

    Affiche_gpio();

    request->send(200, "text/plain", "OK"); });

  //  ----------------------------- Formulaire -------------------------------
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request)
            {
              request->send_P(200, "text/html", index_html); // Envoyer la page HTML depuis le fichier index_html.h
            });

  server.on("/submit", HTTP_POST, [](AsyncWebServerRequest *request)
            {
    if (request->hasParam("T1_Debut_EV1", true)) {
      T1_Debut_EV1 = request->getParam("T1_Debut_EV1", true)->value();
    }
 if (request->hasParam("T1_Debut_M_EV1", true)) {
      T1_Debut_M_EV1 = request->getParam("T1_Debut_M_EV1", true)->value();
    }
    if (request->hasParam("T1_Nb_Cycle_EV1", true)) {
      T1_Nb_Cycle_EV1 = request->getParam("T1_Nb_Cycle_EV1", true)->value();
    }
    if (request->hasParam("T1_Periode_Cycle_EV1", true)) {
      T1_Periode_Cycle_EV1 = request->getParam("T1_Periode_Cycle_EV1", true)->value();
    }
    if (request->hasParam("T1_Duree_Cycle_EV1", true)) {
      T1_Duree_Cycle_EV1 = request->getParam("T1_Duree_Cycle_EV1", true)->value();
    }

    String response = "<!DOCTYPE html><html lang=\"fr\"><head><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><title>Résultat de l'Arrosage</title></head><body>";
    response += "<div style=\"background-color: blue; padding: 10px;\">";
    response += "<h3 style=\"color: white;\">Zone 1</h3>";
    response += "<p style=\"color: white;\">Heure de démarrage: " + T1_Debut_EV1 + "</p>";
    response += "<p style=\"color: white;\">Minute de démarrage: " + T1_Debut_M_EV1 + "</p>";
    response += "<p style=\"color: white;\">Nombre d'arrosage: " + T1_Nb_Cycle_EV1 + "</p>";
    response += "<p style=\"color: white;\">Intervalle d'arrosage: " + T1_Periode_Cycle_EV1 + "</p>";
    response += "<p style=\"color: white;\">Durée d'arrosage: " + T1_Duree_Cycle_EV1 + "</p>";
    response += "</div>";
    response += "<br><br><a href=\"/\" style=\"background-color: white; color: blue; padding: 10px 20px; text-decoration: none; border: 1px solid blue;\">Retour</a>";
    response += "</body></html>";
    ecriture_json();
    request->send(200, "text/html", response); });

  // Start server
  server.begin();
}

Void (loop)

void loop()
{
  while (SerialGPS.available() > 0)
  {
    if (gps.encode(SerialGPS.read()))
    {
      if (gps.date.isValid())
      {
        Day = gps.date.day();
        Month = gps.date.month();
        Year = gps.date.year();
      }
      if (gps.time.isValid())
      {
        Hour = gps.time.hour() + changement_heure; // ajuste UTC (heure hivers +1 - heure été +2)
        Minute = gps.time.minute();
        Second = gps.time.second();
      }
      GestionZero(); // Ajout 0 si var < 10

      val_heure = zh + String(Hour) + ":" + zmn + String(Minute) + ":" + zs + String(Second);
      val_date = String(Day) + "/" + zmois + String(Month) + "/" + String(Year);
      total_mn_gps = (Hour) * 60 + Minute; // calcul nb total en minutes des heures du GPS
    }
  }

  // ------------------------- Conversion des heures en minutes & calcul tranche début fin --------------------------
  if (T1_Debut_EV1 != "")
  {
    T1_Debut_EV1_Int = T1_Debut_EV1.toInt();
  }

  if (T1_Debut_M_EV1 != "")
  {
    T1_Debut_M_EV1_Int = T1_Debut_M_EV1.toInt();
  }

  if (T1_Nb_Cycle_EV1 != "")
  {
    Nb_Cycle_EV1_Int = T1_Nb_Cycle_EV1.toInt();
  }

  if (T1_Periode_Cycle_EV1 != "")
  {
    T1_Periode_Cycle_EV1_Int = T1_Periode_Cycle_EV1.toInt();
  }

  if (T1_Duree_Cycle_EV1 != "")
  {
    T1_Duree_Cycle_EV1_Int = T1_Duree_Cycle_EV1.toInt();
  }

  // ----------------------------------- traitement des tranches à afficher sur la page web -----------------------------

  T1M = ""; // Ajout 0 si mn entre 0et 9
  if (T1_Debut_M_EV1_Int < 10)
  {
    T1M = "0";
  }
  T1_Total_Debut_EV1 = T1_Debut_EV1_Int * 60 + T1_Debut_M_EV1_Int + T1_Periode_Cycle_EV1_Int * T1_Cpt_Nb_Cycle_EV1; // Conversion des heures en minutes
  T1_Total_Fin_Cycle_EV1 = T1_Total_Debut_EV1 + T1_Duree_Cycle_EV1_Int;                                             // Calcul de la fin des cycles
  if (T1_Total_Fin_Cycle_EV1 == total_mn_gps && T1_Cpt_Nb_Cycle_EV1 < Nb_Cycle_EV1_Int)                             // A la fin du cycle calcul le cycle suivant
  {
    T1_Cpt_Nb_Cycle_EV1++;
  }

  if (T1_Cpt_Nb_Cycle_EV1 == Nb_Cycle_EV1_Int)
  {
    T1_Cpt_Nb_Cycle_EV1 = 0;
  }
  //------------------------------Gestion des cde de sortie électrovannes (PCF8475) -----------------------------
  I_EV1 = PCF_21.read(7); // inter marche/arrêt forcée EV1
  I_EV2 = PCF_21.read(6); // inter march/arrête forcée EV2
  I_EV3 = PCF_21.read(5); // inter marche/arrêt forcée EV3
  I_EV4 = PCF_21.read(4); // inter marche/arrêt forcée EV4

  if (inputMessage1 == "4" && inputMessage2 == "0")
  {
    Mode_AM = 0;
    inputMessage1 == "";
  }

  if (inputMessage1 == "4" && inputMessage2 == "1")
  {
    Mode_AM = 1;
    inputMessage1 == "";
  }

  //* ----------------------- Marche/Arrêt mode manuel -----------------------
  if (Mode_AM == 0)
  {
      val_out = 5; //! permet de na pas activer les sortie de 0 à 4 (essai)
      val_state = 0;
    if (inputMessage1 == "3")
    {
      if (I_EV1 == 1 || inputMessage2 == "1")
      {
        PCF_21.write(S_EV1, 0); // Marche EV1
      }
      else if (I_EV1 == 0 || inputMessage2 == "0")
      {
        PCF_21.write(S_EV1, 1); //  Arrêt EV1
      }
    }

    if (inputMessage1 == "2")
    {
      if (I_EV2 == 1 || inputMessage2 == "1")
      {
        PCF_21.write(S_EV2, 0); // Marche EV2
      }
      else if (I_EV2 == 0 || inputMessage2 == "0")
      {
        PCF_21.write(S_EV2, 1); //  Arrêt EV2
      }
    }
    if (inputMessage1 == "1")
    {
      if (I_EV3 == 1 || inputMessage2 == "1")
      {
        PCF_21.write(S_EV3, 0); // Marche EV3
      }
      else if (I_EV3 == 0 || inputMessage2 == "0")
      {
        PCF_21.write(S_EV3, 1); //  Arrêt EV3
      }
    }
    if (inputMessage1 == "0")
    {
      if (I_EV4 == 1 || inputMessage2 == "1")
      {
        PCF_21.write(S_EV4, 0); // Marche EV4
      }
      else if (I_EV4 == 0 || inputMessage2 == "0")
      {
        PCF_21.write(S_EV4, 1); //  Arrêt EV4
      }
    }
  }

  //* ----------------------- Marche/Arrêt mode automatique -----------------------
  if (Mode_AM == 1)
  {
    // if (((total_mn_gps >= T1_Total_Debut_EV1) && (total_mn_gps < T1_Total_Fin_Cycle_EV1)))
    if (total_mn_gps >= T1_Total_Debut_EV1 && total_mn_gps < T1_Total_Fin_Cycle_EV1)
    {
      PCF_21.write(S_EV1, 0); // marche auto
      val_out = 3;
      val_state = 1;
    }
    else
    {
      PCF_21.write(S_EV1, 1); // arrêt auto
      val_out = 3;
      val_state = 0;
    }
  }

  affiche_ecran();
}