Ma ferme verticale automatisée

Bonjour à tous,

Il m'est souvent venu de faire appel au soutien de ce forum pour pouvoir réaliser mes projets arduino.
Pour une fois j'aimerais faire l'inverse et vous montrer ce que vous m'avez permis de faire.

Cela m'a pris énormément de temps même si le résultat peut paraître simple au final.

Voici le résultat ;
Ma ferme verticale hydroponique

Tous vos commentaires sont plus que bien venus, positif comme négatif.

Voilà l'architecture actuelle
Un module RTC DS3231 pour garder le tout à l'heure
Un module DHT11 pour mesure de la T° & de l'humidité de l'air
Un module DS18B20 pour la mesure de température de l'eau
Une sonde pH à calibrer de manière régulière ( d'où la fonctionnalité de calibrage dans le menu sur l'écran tactile)
Un écran tactile ILI9341 (quel boulot pour l'implémenter !!`#!*? )
avec sa carte SD principalement utilisée pour l'affichage d'image "user-friendly"
Un ESP8266 pour envoyer toutes ces info sur une database INFLUXDB et afficher le résultat en ligne sur Grafana : tout ça est proposé en un par le site Colrysis, faut encore que j'apprenne à envoyer les commandes POST… :slight_smile:

Des flotteurs pour la mesure du niveau d'eau dans le réservoir qui alimente tout le circuit (ceux-ci bientôt remplacés par un capteur radar, plus facile à installer dans le "toit" du réservoir)

(manque encore le sensor pour la mesure d'electro-négativité qui permet de détecter la richesse de l'eau en nutriments - cependant cela a un sacré coût!)


Schéma cablage

La navigation se fait comme suit:
il y a un écran principal affichant tous les paramètres nécessaires à la ferme verticale :
température - humidité - cycle de lumière - pH et electro-conductivité - niveau d'eau ainsi que l'heure et la date.
Il suffit d'appuyer sur l'un de ces paramètres pour que leur écran de reglage s'affiche, vous pouvez alors facilement paramétrer votre automatisation comme vous le souhaitez. N'oubliez pas de sauvegarder vos modifications en cliquant sur la case "save" en haut à droite de l'écran. Vous pouvez à tout moment revenir en arrière, à l'écran principal en cliquant sur la case home en bas à droite.

L'écran propre à l'EC n'a pas encore été réalisé n'ayant pas eu le sensor. Si cela vous est nécessaire- il vous suffira de copier coller les fonctions drawpHscreen et RefreshpHScreen et de les adapter à votre convenance.

Par exemple pour définir les cycles de lumières:

Ou pour calibrer son sensor de pH (il faut le mettre dans 2 solutions de pH différentes et lui indiquer à chaque fois à quelle valeur de pH cela correspond pour qu'il enregistre et se calibre):

Comme vous pouvez le voir dans le code, il y a un gros travail sur la partie navigation sur l'écran qui prend beaucoup de place dans le code. Elle est cependant assez facile à comprendre si vous y regardez de plus prêt.

Le code se trouve en 2eme page.

Je me suis bien évidemment inspiré de beaucoup d'aide trouvé par-ci par-là, mais tout est fait maison. Ca représente un nombre incalculable d'heures de travail, d'apprentissage et d'itération :wink:

Next step? Idéalement une acquisition de données sur un serveur web qui peut afficher l'historique des paramètres de la ferme verticale et l'évolution des données en temps réel.
Un tout autre domaine de compétence.

Je rajouterai les éléments du projet au fur et a mesure de curiosité/besoins/critiques.

Bien, mais en général les membres postent ici des dossiers complets :

  • schéma
  • code
  • mode d'emploi

Bonjour

L'esprit de ce sous forum consiste donner, au delà de l'annonce d'une réalisation, tous les détails de la réalisation (schémas , codes et liens vers les composants) pour permettre à d'autres de s'en inspirer ou reproduire à l'identique.
Non pas seulement dire 'j'ai fait', mais montrer en détail 'comment faire'
Avec cette intéressante réalisation on sent qu'il y a matière à 'montrer comment faire '!

Hello,

C'est le but, c'est en cours de construction pour pouvoir fournir des schémas "clairs" (fritzing sucks chez moi :frowning: )

Merci pour vos réac !

Rien de tel que des VRAIS schémas (composants représentés par leurs symboles, pas par leur apparence) quand il s'agit de décrire un fonctionnement !!
Merci !!

Voilà voilà, ca m'a pris une belle aprem pour faire un schéma un peu hybride mais qui plus clair selon moi.

Schéma cablage

Merci de vos réac', c'est du direct mais ca pousse à peaufiner le projet !

L'image est totalement illisible. J'ai mes lunettes sur le nez pourtant.

Aussi rapide que Lucky Luke, à peine eu le temps de le poster que tu avais déjà vu l'image compressée :slight_smile:

Voilà c'est lisible désormais

Schéma cablage

C'est mieux.

beau travail

je ne connais pas la mega adk, la sortie serie tx/rx0, où est relié le tx esp01, est la même qui sert à la console série et au televersement usb ? il y a 3 autres sérial port disponibles sur la mega ?
les flotteurs sont des interrupteurs ? éliminer les 2 10k en les branchant sur des entrées digitales en input_pullup ?
le tft est enfiché directement ou relié par des fils dupont ? le branchement est trop confus pour moi.

un "vrai" schéma ? un arduino avec des modules, le dessin physique est plus parlant pour les débutants, parce que sinon il faut aller au bout des choses et representer les modules par leur schéma interne aussi.
c'est vrai que sous fritzing l'arduino et les modules sont représentés par des dessins

Félicitations

je ne connais pas la mega adk, la sortie serie tx/rx0, où est relié le tx esp01, est la même qui sert à la console série et au televersement usb ?

Tout à fait, je ne fais que commencer à travailler avec les ports Serial, je ne suis pas du tout expert encore mais il me semble que c'est bien le même port Serial que celui utilisé pour faire la console série. Je le mettrai sur le Serial port 2.

Pour le moment j'essaie d'uploader les datas sur Colrysis.com qui propose une database INFLUXdb et un dashboard Grafana ; terrible pour montrer ses résultats en ligne !

Seulement je n'arrive pas du tout à envoyer les requêtes POST, je découvre un tout nouveau monde de communication. Ca parait pourtant si simple mais je bloque complet.

les flotteurs sont des interrupteurs ?

Oui ce sont bien de simples interrupteurs.

éliminer les 2 10k en les branchant sur des entrées digitales en input_pullup ?

Très bonne idée, je me demandais juste si dans ce cas, je ne risquais pas d'avoir trop de pertes de jus. Si je fais un pullup, la mesure est vue derrière la résistance ? (coté sortie Arduino)

Je compte à termes mettre un sensor de type radar qui est plus facile à installer et plus précis qu'une série de flotteurs qui nécessitent de percer le réservoir à plusieurs endroits pour les installer

Le vrai schéma sortira soon !
Je trouve le schéma actuel plutot clair, toutes les pins misent en jeu sont déclarées.

le "vrai schéma" est plutot une réponse à la remarque post #4
ton dessin est parfait

Beau boulot Merci

elektrax:
le "vrai schéma" est plutot une réponse à la remarque post #4
ton dessin est parfait

Beau boulot Merci

OUF ! Merci :))

J4l13n:
Bonjour,

Sympa cette ferme :slight_smile:

Avez vous le sketch poster quelque part ?

@+

J'y compte bien dès que je l'aurais rendu plus clair , c'est encore un peu le foutoir et il y a un sacré paquets de lignes ! Entre autre dû à l'écran tactile.

Artouste:
Bonjour
C'est toujours agréable de voir un projet bien aboutir :grin:

Je reste un peu sur "ma faim" avec ta video
qq details sur les equipements peripheriques et la construction mecanique de "ta ferme" ?

encombrement par exemple ?

Message reçu, j'en posterai un peu plus.
Ici mon but était de me limiter à présenter la partie electronique mais en effet pourquoi ne pas aller plus loin :slight_smile:

La ferme verticale possède ;
un container où l'eau est puisée pour ensuite être pompée dans ce circuit fermé.
Le circuit en lui même est composé de ce container, et de goutières où j'y ai percé des trous afin d'accueillir les paniers qui contiennent les plantes.



Ces paniers permettent de laisser passer les racines de la plante afin qu'elles puissent se baigner et tirer le nécessaire de cette eau qui circule. (principe de culture de type NFT, où les racines baignent dans un fluide qui circule constamment).
L'eau est oxygénée par une pompe à air située dans le réservoir. C'est un des principaux atouts de cette culture : la suroxygénation de la plante permet de booster sa croissance.

Cette eau est pompée en continue, elle est régulée en pH et en nutriments à l'aide de 4 pompes péristaltiques ; 1 pour le pH + , 1 pour le pH - , 1 pour les nutriments de type A , une pour les nutriments de type B
.

Toutes les prises de mesures sont faites au sein du réservoir d'eau afin de vérifier la bonne gestion de la ferme ( pH, EC, température, niveau d'eau ( à partir de flotteurs - je prévois d'intégrer plutôt un capteur radar pour avoir un niveau d'eau plus précis)

Au niveau de l'encombrement de la ferme verticale, en réalité je n'ai pas construit une structure idéale pour l'indoor :
la structure est oblique afin que chaque étage ne fasse pas de l'ombre à celui d'en dessous, cela est utile pour mettre l'installation dehors au soleil. En indoor, on rajoute de toute façon une lumière artificielle à chaque étage, il n'est donc pas nécessaire d'avoir une structure oblique qui prend beaucoup plus de place qu'une structure droite.

L'écran tactile intègre un menu qui permet de paramétrer tous ces éléments, mon but était de faire quelque chose de user-friendly que n'importe qui pourrait utiliser.
J'ai essayé sur ma copine pour faire le test, ca s'est avéré plutot facile d'utilisation :smiley:

Le but de ce projet était vraiment de partir sur du lowcost (bonjour Aliexpress) de faire un gros boulot d'automatisation dessus et de pouvoir facilement le répliquer à moindre prix.
C'est pour cette raison que je suis resté sur Arduino et non Raspberry pi qui aurait faciliter beaucoup de choses mais dont le prix des composants est bien plus important.

Prochaine étape: mettre les infos du monitoring en ligne par un ESP8266, la connexion est faite, plus qu'à comprendre comment bien envoyer les informations sur une database INFLUXDB à partir d'un Arduino connecté en Serial avec un ESP8266 (je précise car les libraires pour l'envoi de données sont souvent faites pour un ESP8266 directement).

bogtus:
OUF ! Merci :))

J'y compte bien dès que je l'aurais rendu plus clair , c'est encore un peu le foutoir et il y a un sacré paquets de lignes ! Entre autre dû à l'écran tactile.

Message reçu, j'en posterai un peu plus.
Ici mon but était de me limiter à présenter la partie electronique mais en effet pourquoi ne pas aller plus loin :slight_smile:

La ferme verticale possède ;
un container où l'eau est puisée pour ensuite être pompée dans ce circuit fermé.
Le circuit en lui même est composé de ce container, et de goutières où j'y ai percé des trous afin d'accueillir les paniers qui contiennent les plantes.



Ces paniers permettent de laisser passer les racines de la plante afin qu'elles puissent se baigner et tirer le nécessaire de cette eau qui circule. (principe de culture de type NFT, où les racines baignent dans un fluide qui circule constamment).
L'eau est oxygénée par une pompe à air située dans le réservoir. C'est un des principaux atouts de cette culture : la suroxygénation de la plante permet de booster sa croissance.

Cette eau est pompée en continue, elle est régulée en pH et en nutriments à l'aide de 4 pompes péristaltiques ; 1 pour le pH + , 1 pour le pH - , 1 pour les nutriments de type A , une pour les nutriments de type B
.

Toutes les prises de mesures sont faites au sein du réservoir d'eau afin de vérifier la bonne gestion de la ferme ( pH, EC, température, niveau d'eau ( à partir de flotteurs - je prévois d'intégrer plutôt un capteur radar pour avoir un niveau d'eau plus précis)

Au niveau de l'encombrement de la ferme verticale, en réalité je n'ai pas construit une structure idéale pour l'indoor :
la structure est oblique afin que chaque étage ne fasse pas de l'ombre à celui d'en dessous, cela est utile pour mettre l'installation dehors au soleil. En indoor, on rajoute de toute façon une lumière artificielle à chaque étage, il n'est donc pas nécessaire d'avoir une structure oblique qui prend beaucoup plus de place qu'une structure droite.

L'écran tactile intègre un menu qui permet de paramétrer tous ces éléments, mon but était de faire quelque chose de user-friendly que n'importe qui pourrait utiliser.
J'ai essayé sur ma copine pour faire le test, ca s'est avéré plutot facile d'utilisation :smiley:

Le but de ce projet était vraiment de partir sur du lowcost (bonjour Aliexpress) de faire un gros boulot d'automatisation dessus et de pouvoir facilement le répliquer à moindre prix.
C'est pour cette raison que je suis resté sur Arduino et non Raspberry pi qui aurait faciliter beaucoup de choses mais dont le prix des composants est bien plus important.

Prochaine étape: mettre les infos du monitoring en ligne par un ESP8266, la connexion est faite, plus qu'à comprendre comment bien envoyer les informations sur une database INFLUXDB à partir d'un Arduino connecté en Serial avec un ESP8266 (je précise car les libraires pour l'envoi de données sont souvent faites pour un ESP8266 directement).

Bonjour.... et bien à présent pour être complet, il ne manque plus que le code....sinon ça sert pas à d'autres....ici, cela s'appelle :"communauté Arduino"....merci

Merci pour ta leçon de morale sur la communaute patgyver ! Tu as du donner beaucoup de toi-même avec 2 messages tous les 2 sur ce post :wink:

Bref, je vous envoie le code. Je ne l'ai pas posté pour la simple raison qu'il n'est pas peaufiné. Je n'ai plus le temps de travailler dessus, mais il y a assez de commentaires et de précisions pour que vous puissiez l'adapter si nécessaire.

Le fonctionnement est expliqué autant que possible dans les commentaires de chaque fonction, je l'ai rendu le plus clair possible afin de pouvoir aussi le ré-utiliser quand j'aurai tout oublié du code… :slight_smile:

Je mettrais un lien pour télécharger le tout - mais ces liens étant éphémères je préfère également poster le code ici

Et voici le code

Les commentaires que j'y ai mis (en Français ou en anglais en fonction de l'humeur du jour) devraient vous suffire à comprendre.

Je l'ai divisé en plusieurs parties car il est trop long que pour être posté en 1 message.
1ère partie

Bon courage :wink:

//Hydroponics controller made by Arthur
// CODE FOR INVERSED RELAY (Low voltage = actived)
//TIME, CLOCK RTC DS3231
// pH sensors = pin A0
//Water temperature sensor = digital pin 12
// Air T° & Humidity sensor = digital pin 13
//relay Light = pin 16
//relay Heating = pin 17
//relay 3 = pin 15 , relay 4 = pin 14
//relay pump pH UP = pin 8, pump pH down = pin 9
//relay nutrients1 = pin 10, relay nutrients2 = pin 11
//Water level sensor 1 (lowest)= pin A1
//Water level sensor 2 (highest)=  pin A2

#include <Time.h>
#include <TimeLib.h>
#include <TimeAlarms.h>
// Date and time functions using a DS3231 RTC connected via I2C and Wire lib
#include <Wire.h>
#include "RTClib.h"
RTC_DS3231 rtc;

char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
int dateday; int datemonth; int dateyear; int timeminute; int timehour;


// For humidity & T°
#include <SimpleDHT.h>
// for DHT11, VCC: 5V,GND: GND, DATA: 3 (1ere pin = DATA, 2eme VCC, 3 GND)
int pinDHT11 = 13;
SimpleDHT11 dht11;
int AirTemperature;
int AirHumidity;
int HumidityMin=40;
int HumidityMax=80;
int AirTempmin = 10; //Air Temperature must be between 11-25°C for lettuce, ideal is around 12.
const int relayHeating =17;


// for pH ( 2 potentiometres sur le shield, du coté de la probe = offset , du coté des pins = pour gérer l'alarme sur un niveau de pH)
    const int pHPin = A0; 
    int pHanalog = 0;
    float pHValue;
    unsigned long int avgValue; 
    int buf[10],temp;
    unsigned long Currentmillis;
    unsigned long Lastmillis; //pour laisser un délai entre deux pompage pH afin d'éviter une constante correction, ou laisser le délai de la correction agir
    unsigned long pHperiod=60000;
    unsigned long PumpTime=5000; // temps de pompage de correction pH
    
    float pHmin = 5.5; //valuer min de pH
    float pHmax= 6.5;  // valeur max de pH

    int pH1AnalogRead; //calibration point 1
    int pH2AnalogRead;// calibration point 2
    float pH1Real;
    float pH2Real;
    int checkpH2Read=0;
    int checkpH1Read =0;
    float pHSlope= (-1/35); //configuration of the calibration
    float pHOffset= (731/35);
    
    const int PumppHup = 8;
    const int PumppHdown =9;

// for WaterTemperature (Onewire connection)
#include <OneWire.h> 
#include <DallasTemperature.h>
// Data wire is plugged into digital pin 12 on the Arduino (!!!With 5K Ohm resistance between Data wire & 5V(pull up resistance))
#define ONE_WIRE_BUS 12 
OneWire oneWire(ONE_WIRE_BUS); 
DallasTemperature sensors(&oneWire);
float WaterTemp;

//for light hours of activity
int LightOn = 8;
int LightOff = 20;
const int relayLight = 16 ;

//for waterlevel

const int waterlevelsensor1 = A1;
const int waterlevelsensor2 = A2;
int tanklevel;

//Temporary Variables for savings : 
int NewLightOn;
int NewLightOff;
float NewpHmin;
float NewpHmax;
int NewHumidityMin;
int NewHumidityMax;

//Screen functions
#include <UTFT.h> 
#include <URTouch.h>
#include <UTFT_Buttons.h>
#include <EEPROM.h>

UTFT    myGLCD(ILI9341_16,38,39,40,41); //Parameters should be adjusted to your Display/Schield model CHECK DOCUMENTATION, TFT 480x320
URTouch  myTouch( 6,5, 4, 3, 2);
UTFT_Buttons  myButtons(&myGLCD, &myTouch);

//SD card functions (connected inside of the screen)
#include <SPI.h>
#include <SdFat.h>
#include <UTFT_SdRaw.h> // SdFat lib from here :https://github.com/greiman/SdFat/archive/master.zip
#define SD_CHIP_SELECT  53  
SdFat sd;
UTFT_SdRaw myFiles(&myGLCD);

//==== Defining Fonts
extern uint8_t SmallFont[];
extern uint8_t BigFont[];
extern uint8_t SevenSegNumFont[];

char currentPage;
int x, y; // Variables for the coordinates where the display has been pressed

 
void setup() {
  Serial.begin(9600);

  //TIME CLOCK RTC
         if (! rtc.begin()) {
          Serial.println("Couldn't find RTC");
          while (1);  }
        if (rtc.lostPower()) {
          Serial.println("RTC lost power, lets set the time!");
          // following line sets the RTC to the date & time this sketch was compiled
          rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
          // This line sets the RTC with an explicit date & time, for example to set
          // January 21, 2014 at 3am you would call:
          // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
          }
  
 //SD card initilisation
      Serial.println(F("Initialising SD card..."));
      bool mysd = 0;
      // see if the card is present and can be initialized:
      while (!mysd)
      {
        if (!sd.begin(SD_CHIP_SELECT, SPI_FULL_SPEED)) {
          Serial.println(F("Card failed, or not present"));
          Serial.println(F("Retrying...."));
        }
        else
        {
          mysd = 1;
          Serial.println(F("Card initialised."));
        }
      }
  //Screen initialization
  myGLCD.InitLCD();
  myGLCD.clrScr();
  myTouch.InitTouch();
  myTouch.setPrecision(PREC_MEDIUM);
  myGLCD.fillScr(0,0,0);
  drawHomeScreen();  // Draws the Home Screen
  //drawPHscreen();
  //drawLightscreen();
  //drawTemperaturescreen();
 currentPage = 0; // Indicates that we are at Home Screen
 //drawpHSensorCalibrationscreen ();


//WaterTemperature
  sensors.begin();

  //pH
    pinMode(PumppHup, OUTPUT);
    pinMode(PumppHdown, OUTPUT);
    pinMode(pHPin, INPUT);

    pinMode(relayLight, OUTPUT);
    pinMode(relayHeating, OUTPUT);
    pinMode(waterlevelsensor1, INPUT);
    pinMode(waterlevelsensor2, INPUT);

    Lastmillis = millis();

    //All relays disactivated (= HIGH output)
    digitalWrite(relayLight, HIGH);
    digitalWrite(relayHeating, HIGH);
    digitalWrite(PumppHup, HIGH);
    digitalWrite(PumppHdown, HIGH);
 
}
  

void loop() {
   Serial.println("Current page is");
   Serial.println(currentPage);

   Serial.println("=================================");

// TIME CLOCK RTC
    DateTime now = rtc.now();
    
      Serial.println("We are the date of");
      Serial.print(now.year(), DEC);
      Serial.print('/');
      Serial.print(now.month(), DEC);
      Serial.print('/');
      Serial.print(now.day(), DEC);
      Serial.print(" (");
      Serial.print(daysOfTheWeek[now.dayOfTheWeek()]);
      Serial.println(") ");
      Serial.print("Time is   ");
      Serial.print(now.hour(), DEC);
      Serial.print(':');
      Serial.print(now.minute(), DEC);
      Serial.print(':');
      Serial.print(now.second(), DEC);
      Serial.println();
      
      dateday= now.day();//used for the display
      datemonth=now.month();
      dateyear=now.year(); 
      timeminute=now.minute();
      timehour=now.hour();


// LIGHT CONTROL
if (timehour >=LightOn && timehour <LightOff)
  {
    Serial.println("Time to turn ON the light ");
  digitalWrite(relayLight, LOW); // LightOn
  }
  else 
  {
    digitalWrite(relayLight, HIGH); //LightOff
  Serial.println("Time to turn OFF the light !");
  }

2ème partie :

// TEMPERATURE ET HUMIDITE AIR

 
      Serial.println("Sample DHT11..."); // T° et humidité air
      
          // read with raw sample data.
          byte temperature = 0;
          byte humidity = 0;
          byte data[40] = {0};
          if (dht11.read(pinDHT11, &temperature, &humidity, data)) { // cas erreur lecture humidité et T°
          Serial.print("Read DHT11 failed");
          
          }
          
          else 
          {
            Serial.print("Sample RAW Bits: ");
            for (int i = 0; i < 40; i++) {  // code source capteur pour calculer
            Serial.print((int)data[i]);
             if (i > 0 && ((i + 1) % 4) == 0) {
              Serial.print(' ');
                    }
                 }
                Serial.println("");
                Serial.print("Sample OK: ");
                Serial.print((int)temperature); Serial.print(" *C, ");
                Serial.print((int)humidity); Serial.println(" %");
                AirTemperature = ((int)temperature);
                AirHumidity = ((int)humidity);


                if (AirTemperature < AirTempmin)
                {
                  digitalWrite(relayHeating,LOW);}// activates the heating system
                  else if (AirTemperature> (AirTempmin + 2)) {digitalWrite(relayHeating,HIGH);}//hysterisis de + de 2°C
          }
           
      // DHT11 sampling rate is 1HZ.
     // delay(1000);


//pH calcul
               /*taking 10 samples of the analogue input A0, ordering them and discarding the highest and the lowest 
            and calculating the mean with the six remaining samples by converting this value to voltage in the variable pHVol,
            then using the equation that we have calculated with the pH reference values we convert pHVol to pHValue and send 
            it to the serial port to see it in the serial monitor.*/
         for(int i=0;i<10;i++) 
         { 
          buf[i]=analogRead(pHPin);
          delay(10);
          pHanalog=analogRead(pHPin);
         }
         for(int i=0;i<9;i++)
         {
          for(int j=i+1;j<10;j++)
          {
           if(buf[i]>buf[j])
           {
            temp=buf[i];
            buf[i]=buf[j];
            buf[j]=temp;
           }
          }
         }
         avgValue=0;
         for(int i=2;i<8;i++)
         avgValue+=buf[i];
         float pHVol=(float)avgValue/6;
        // float pHValue = -5.70 * pHVol + 21.34;  calibration
         pHValue = ((pHVol*pHSlope)+pHOffset); // Find the real pH based on calibration values
         Serial.print("\tPH: ");
         Serial.println(pHValue,1);
         Serial.print("analogRead pH sensor is  ");
         Serial.println(pHanalog);
//pH Pumps 
 if ( pHValue >= pHmin && pHValue <= pHmax)
            {
              Serial.println("pH respecting setpoints");
            }


else 
        {
             Currentmillis = millis();
             
            if(Currentmillis - Lastmillis >= pHperiod)
            {
              Serial.println("Periode pH ok");
              if (pHValue <0)
               {
                Serial.println("reading pH value Error");
                }
          
                else
                {
                      if (pHValue > pHmax)
                      {
                        digitalWrite(PumppHdown, LOW);// loop PUMP on for x time ALSO INVERSED RELAY -> LOW;
                        Serial.println("Pompe pH down activée");
                        delay(PumpTime);
                        digitalWrite(PumppHdown, HIGH);
                        Serial.println("Pompe pH down désactivée après");
                        Serial.print(PumpTime);
                        Serial.print("s");
                        Lastmillis=millis(); // enregistrer le dernier dosage time
                      }
                      else if (pHValue < pHmin)
                      {
                        digitalWrite(PumppHup, LOW);// loop PUMP on for x time ;
                        Serial.println("Pompe pH UP actived");
                        delay(PumpTime);
                        digitalWrite(PumppHup, HIGH);
                        Serial.println("Pompe pH UP desactived");
                        Lastmillis=millis(); // enregistrer le dernier dosage time
                        
                      }
      }
      }
  
  else {
    Serial.println("Period pH NOK");
    }
    }

  // Water Temperature


       Serial.print(" Requesting temperatures..."); 
       sensors.requestTemperatures(); // Send the command to get temperature readings 
       Serial.println("DONE"); 
      /********************************************************************/
       Serial.print("Temperature of the Water is: "); 
       Serial.println(sensors.getTempCByIndex(0)); //   
         // You can have more than one DS18B20 on the same bus.  
         // 0 refers to the first IC on the wire 
         WaterTemp = sensors.getTempCByIndex(0);
         Serial.print("T =");
         Serial.println(WaterTemp,1);


    //Water level

    if (analogRead(waterlevelsensor2) < 500)
    {
    Serial.println("Tank level above 75%");
    Serial.print("water level sensor n°2 has digital read of");
    Serial.println(waterlevelsensor2);
    tanklevel = 75;
    }

    else 
    {
      if (analogRead(waterlevelsensor1) > 500)
      {
        Serial.println("Tank level between 50 and 75%");
        Serial.print("water level sensor n°1 has digital read of");
        Serial.println(waterlevelsensor1);
        tanklevel = 50;
      }
      else
      {
        Serial.println("ATTENTION : Tank level below 50% !!!");
        tanklevel = 25;
      }
     }

////////REFRESH SCREENS FUNCTIONS///

if (currentPage == 0) {    
               refreshHomescreen ();
               }

if (currentPage == 10) {  //Light Screen
              drawRefreshLightscreen(); }

if (currentPage == 30) {  //Humidity Screen
              drawRefreshHumidityscreen();  }

if (currentPage == 41) {  //pH Screen
              drawRefreshPHscreen(); }

if (currentPage == 42) {  //pH Sensor Calibration
              drawRefreshpHSensorCalibrationscreen (); } 
                        
   // delay(1000);
   //refreshHomescreen();
    
     

/////////////////////////////////////////////////////////////LOOP SCREEN TOUCH FUNCTIONS//////////////////////////////////////////////////////////////
  if (myTouch.dataAvailable())
    {
      myTouch.read();
      x=myTouch.getX();
      y=myTouch.getY();  
           if (currentPage == 0) {    
               refreshHomescreen ();
      
              // If we press the Back Button
             /* if ((x>=10) && (x<=60) &&(y>=10) && (y<=36)) 
              {
                currentPage = '0'; // Indicates we are at home screen
                myGLCD.clrScr();
                drawHomeScreen(); // Draws the home screen
              }*/
                  if ((x>=10) && (x<=100) &&(y>=30) && (y<=100)) //Go to Temperature Screen 
                          {
                            
                            myGLCD.clrScr();
                            NewLightOn = LightOn;
                            NewLightOff = LightOff;
                            drawTemperaturescreen ();
                            currentPage = 20; //
                          }

3eme partie :

                  if ((x>=110) && (x<=200) &&(y>=30) && (y<=100)) //Go to Light Screen 
                  {
                    
                    myGLCD.clrScr();
                    NewLightOn = LightOn;
                    NewLightOff = LightOff;
                    drawLightscreen();
                    currentPage = 10; //
                  }

                  if ((x>=220) && (x<=320) &&(y>=30) && (y<=100)) //Go to pH &EC Screen 
                  {
                    
                    myGLCD.clrScr();
                    drawPHandECscreen();
                    currentPage = 40; //
                  }

                 if ((x>=110) && (x<=200) &&(y>=110) && (y<=230)) //Go to Humidity Screen 
                  {
                    
                    myGLCD.clrScr();
                    NewHumidityMin = HumidityMin;
                    NewHumidityMax = HumidityMax;
                    drawHumidityscreen();
                    currentPage = 30; //
                  }
            }

      
            if (currentPage == 10) {  //Light Screen
              drawRefreshLightscreen();  
                    if ((x>=60) && (x<=90) &&(y>=60) && (y<=90)) {
                        NewLightOn+=1; // 
                      }
                    if ((x>=60) && (x<=90) &&(y>=200) && (y<=230)) {
                        NewLightOn-=1; // 
                      }
                    if ((x>=220) && (x<=250) &&(y>=60) && (y<=90)) {
                        NewLightOff+=1; // 
                      }
                    if ((x>=220) && (x<=250) &&(y>=200) && (y<=230)) {
                        NewLightOff-=1; // Draws the home screen
                      }
                    if ((x>=280) && (x<=320) &&(y>=10) && (y<=30)) { // SAVE
                        LightOn=NewLightOn;
                        LightOff=NewLightOff;
                        myGLCD.setColor(255,255,255);
                        myGLCD.setFont(SmallFont);
                        myGLCD.print("SAVED!",270,40);
                      }
                            // If we press the Home Button
                    if ((x>=270) && (x<=320) &&(y>=200) && (y<=240)) {
                      currentPage = 0; // Indicates we are at home screen
                      myGLCD.clrScr();
                      drawHomeScreen(); // Draws the home screen
                      }
                         
              }
            if (currentPage == 20) {  //Temperature Screen
              //drawRefreshLightscreen();  
                    
                    if ((x>=280) && (x<=320) &&(y>=10) && (y<=30)) { // SAVE
                        LightOn=NewLightOn;
                        LightOff=NewLightOff;
                        myGLCD.setColor(255,255,255);
                        myGLCD.setFont(SmallFont);
                        myGLCD.print("SAVED!",270,40);
                      }
                            // If we press the Home Button
                    if ((x>=270) && (x<=320) &&(y>=200) && (y<=240)) {
                      currentPage = 0; // Indicates we are at home screen
                      myGLCD.clrScr();
                      drawHomeScreen(); // Draws the home screen
                      }
                         
              }

            if (currentPage == 30) {  //Humidity Screen
              drawRefreshHumidityscreen();  
                        if ((x>=20) && (x<=50) &&(y>=60) && (y<=100)) {
                        NewHumidityMin+=1; // 
                      }
                    if ((x>=20) && (x<=50) &&(y>=200) && (y<=240)) {
                        NewHumidityMin-=1; // 
                      }
                    if ((x>=110) && (x<=150) &&(y>=60) && (y<=100)) {
                        NewHumidityMax+=1; // 
                      }
                    if ((x>=110) && (x<=150) &&(y>=200) && (y<=240)) {
                        NewHumidityMax-=1; // Draws the home screen
                      }
                    if ((x>=280) && (x<=320) &&(y>=10) && (y<=40)) { // SAVE
                        HumidityMin=NewHumidityMin;
                        HumidityMax=NewHumidityMax;
                        myGLCD.setColor(255,255,255);
                        myGLCD.setFont(SmallFont);
                        myGLCD.print("SAVED!",270,40);
                      }
                            // If we press the Home Button
                    if ((x>=270) && (x<=320) &&(y>=200) && (y<=240)) {
                      currentPage = 0; // Indicates we are at home screen
                      myGLCD.clrScr();
                      drawHomeScreen(); // Draws the home screen
                      }
                     
                         
              }

            if (currentPage == 40) { //drawPHandECscreen

                  if ((x>=80) && (x<=130) &&(y>=110) && (y<=150)) //Go to PH Screen 
                      {
                        
                        myGLCD.clrScr();
                        NewpHmin = pHmin;
                        NewpHmax= pHmax;
                        drawPHscreen();
                        currentPage = 41; //
                      }

                   /*if ((x>=220) && (x<=320) &&(y>=30) && (y<=100)) //Go to EC Screen 
                      {
                        
                        myGLCD.clrScr();
                        NewpHmin = pHmin;
                        NewpHmax= pHmax;
                        drawECscreen();
                        currentPage = 51; //
                      }*/
                      // If we press the Home Button
                    if ((x>=270) && (x<=320) &&(y>=200) && (y<=240)) {
                      currentPage = 0; // Indicates we are at home screen
                      myGLCD.clrScr();
                      drawHomeScreen(); // Draws the home screen
                      }
                
              
            }

          if (currentPage == 41) {  //pH Screen
              drawRefreshPHscreen();  
                        if ((x>=20) && (x<=50) &&(y>=60) && (y<=100)) {
                        NewpHmin+=0.1; // 
                      }
                    if ((x>=20) && (x<=50) &&(y>=200) && (y<=240)) {
                        NewpHmin-=0.1; // 
                      }
                    if ((x>=110) && (x<=150) &&(y>=60) && (y<=100)) {
                        NewpHmax+=0.1; // 
                      }
                    if ((x>=110) && (x<=150) &&(y>=200) && (y<=240)) {
                        NewpHmax-=0.1; // Draws the home screen
                      }
                    if ((x>=280) && (x<=320) &&(y>=10) && (y<=40)) { // SAVE
                        pHmin=NewpHmin;
                        pHmax=NewpHmax;
                        myGLCD.setColor(255,255,255);
                        myGLCD.setFont(SmallFont);
                        myGLCD.print("SAVED!",270,40);
                      }
                            // If we press the Home Button
                    if ((x>=270) && (x<=320) &&(y>=200) && (y<=240)) {
                      currentPage = 0; // Indicates we are at home screen
                      myGLCD.clrScr();
                      drawHomeScreen(); // Draws the home screen
                      }
                             // If we press pH sensor calibration button
                    if ((x>=200) && (x<=300) &&(y>=70) && (y<=130)) {
                      currentPage = 42; // Indicates we are at home screen
                      myGLCD.clrScr();
                      drawpHSensorCalibrationscreen (); 
                      pH2Real= 7;
                      pH1Real=7;
                      }

                             // If we press pH pumps calibration button
                    if ((x>=200) && (x<=300) &&(y>=140) && (y<=200)) {
                      currentPage = 0; // Indicates we are at home screen
                      myGLCD.clrScr();
                      drawHomeScreen(); // Draws the home screen
                      }
                         
              }

Vous verrez qu'ici je n'ai pas encore réalisé l'écran pH Pump calibration (il renvoie en Home Screen) qui vise à définir le temps de pompage pour chaque activation des pompes, et le délai entre 2 activations.
Ces 2 valeurs sont déjà initialement paramétrées et modifiable au tout début du code. Ici c'est juste pour les rendre modifiable par un utilisateur externe par l'écran de navigation

4ème partie: principalement les fonctions pour dessiner les différentes pages de navigation sur l'écran

            if (currentPage == 42) {  //pH Sensor Calibration
              drawRefreshpHSensorCalibrationscreen ();  
                               
                        if ((x>=90) && (x<=110) &&(y>=70) && (y<=85)) {
                        pH1Real+=0.1; // 
                      }
                    if ((x>=90) && (x<=110) &&(y>=130) && (y<=145)) {
                        pH1Real-=0.1; // 
                      }
                    if ((x>=175) && (x<=195) &&(y>=70) && (y<=85)) {
                        pH2Real+=0.1; // 
                      }
                    if ((x>=175) && (x<=195) &&(y>=130) && (y<=145)) {
                        pH2Real-=0.1; 
                      }
                    if ((x>=80) && (x<=120) &&(y>=200) && (y<=230)) { // Read pH Analog 1
                       pH1Read ();
                      }
                            // If we press the Read Button
                    if ((x>=165) && (x<=205) &&(y>=200) && (y<=230)) {
                      pH2Read ();
                      }
                             // If we press pH sensor calibration button
                    if ((x>=235) && (x<=315) &&(y>=90) && (y<=120)) {
                      pHSensorCalibration ();
                      }

                             // If we press Home button
                    if ((x>=270) && (x<=320) &&(y>=200) && (y<=240)) {
                      currentPage = 0; // Indicates we are at home screen
                      myGLCD.clrScr();
                      drawHomeScreen(); // Draws the home screen
                      }
                         
              }


      }

}
  

/////////////////////////////////////////DRAW SCREEN FUNCTIONS//////////////////////////////////////////////////////////////////////////////////
void drawHomeScreen() {
              // 
              myGLCD.fillScr(0,0,0); //black backgroung color   
              myGLCD.setBackColor(0, 0, 0); // Sets the background color of the area where the text will be printed to black
                            
              //quadrillage
                myGLCD.setColor(0, 172, 51); // Sets color to green & blue
                myGLCD.fillRoundRect(3,3,317,22);
                myGLCD.drawRect(1,1,319,239);
                myGLCD.drawLine(108,22,108,240); // Draws the line (x1,y1 ,x2, y2)
                myGLCD.drawLine(214,22,214,240);
                myGLCD.drawLine(10,129,310,129);
                myGLCD.drawLine(10,131,310,131);

               //Title
                myGLCD.setBackColor(0, 172, 51);
                myGLCD.setColor(255, 255, 255); 
                myGLCD.setFont(SmallFont);
                myGLCD.print("Hydroponics   controller", 65, 3);
                myGLCD.setBackColor(0, 0, 0);
            
                //1er quadrant Temperature
                  // + intégrer image Thermometre
                myGLCD.setColor(255,255,255); // Sets color to white
                myGLCD.setFont(SmallFont); // Sets the font to small
               //myGLCD.print("Temperature", 10, 30);
                myFiles.load(10,50,36,60,"thermom.raw", 1);
                myGLCD.print("Air:", 60, 30);
                //myGLCD.print("15", 70, 50);
                myGLCD.printNumI(AirTemperature, 70, 50);
                myGLCD.print("o", 88, 45);
                myGLCD.print("C", 96, 50);
                myGLCD.setColor(255,255,255);
                myGLCD.print("Water:",60, 70);
                //myGLCD.print("21", 70, 90);
                myGLCD.printNumF(WaterTemp,1,50,90);
                myGLCD.print("o", 88, 85);
                myGLCD.print("C", 96, 90);
                myGLCD.drawCircle(95, 115, 5); //entourer le cercle de blanc
                myGLCD.setColor(0,255,0);// témoin vert & remplir le cercle
                myGLCD.fillCircle(95, 115, 4);
                
            
              //2eme quadrant Light
                 // + intégrer image goutte eau via SDcard max 60x70
              myGLCD.setColor(255,255,255); // Sets color to white
              myGLCD.setFont(SmallFont);
              myGLCD.print("LIGHT", 140, 30);// Sets the font to small
              if (timehour >=LightOn && timehour <LightOff) //draw moon or sun if LIGHT ON or OFF
                    {
                     myFiles.load(140,50,40,40,"sunbis.raw", 1);
                    }
                    else 
                    {
                     myFiles.load(140,50,40,40,"moon40x40.raw", 1);
                    }
              myGLCD.printNumI(LightOn,112,100);
              myGLCD.print(":00 - ", 126, 100);
              myGLCD.printNumI(LightOff,171,100);
              myGLCD.print(":00", 185, 100);

         
               //3eme quadrant pH & Electro-conductivity
                 // + intégrer image soleil via SDcard 
                  myGLCD.setColor(255,255,255); // Sets color to white
                  myGLCD.setFont(SmallFont);
                  myFiles.load(220,25,40,37,"eprouvett.raw", 1);
                  myGLCD.print("PH", 260, 40);
                  //myGLCD.print("6.7", 260, 60);
                  myGLCD.printNumF(pHValue,1,260,60);
                  myGLCD.drawCircle(310, 65, 5); 
                     //diode témoin pH ; SP respectée (VERT) ou non (Orange si correction en cours, Rouge sinon)
                    if(pHValue <= pHmax && pHValue >= pHmin)
                    {                   myGLCD.setColor(0, 255, 0);// setpoint : témoin vert & remplir le cercle
                                        myGLCD.fillCircle(310, 65, 4);}
                                        
                    else {              
                                        if(Currentmillis - Lastmillis < pHperiod) { //indicates that the pump was working trying to correct pH
                                        myGLCD.setColor(150, 255, 0); // correction témoin : orange car correction pH en cours
                                        myGLCD.fillCircle(310, 65, 4);}
                                        else {myGLCD.setColor(250, 150, 0); // correction témoin : rouge car aucune correction pH en cours
                                              myGLCD.fillCircle(310, 65, 4);}
                                          }

                  myGLCD.setColor(255, 255, 255);
                  myGLCD.print("EC", 260, 90);
                  myGLCD.print("1.2 mS", 250, 110);
                  myGLCD.drawCircle(310, 115, 5);
                  myGLCD.setColor(0, 255, 0);// setpoint : témoin vert & remplir le cercle
                  myGLCD.fillCircle(310, 115, 4);
                  myFiles.load(220,65,40,37,"eprouvetteblue.raw", 1);
                  


                  //4eme quadrant CLOCK
                 // + intégrer image horloge via SDcard 
                  myGLCD.setColor(255,255,255); // Sets color to white
                  myGLCD.setFont(SmallFont);
                  //myGLCD.print("TIME", 240, 140).
                  myFiles.load(250,140,30,30,"clock.raw", 1);
                  myGLCD.printNumI(timehour ,240,170); //display time
                  myGLCD.print(":", 261, 170); 
                  myGLCD.printNumI(timeminute,269,170);
                  myGLCD.printNumI(dateday,230,190);//display date
                  myGLCD.print("/", 246, 190);
                  myGLCD.printNumI(datemonth,254,190);
                  myGLCD.print("/", 270, 190);
                  myGLCD.printNumI(dateyear,278,190);


                //5eme quadrant Humidity
                                     
                    myGLCD.setColor(255,255,255); // Sets color to white
                    myGLCD.setFont(SmallFont);
                    myGLCD.print("Humidity", 130, 140);// Sets the font to small
                    myGLCD.printNumI(AirHumidity,160,180);
                    myFiles.load(110,160,35,35,"hydropo.raw", 1);
                    myGLCD.print("%", 185, 180);
                    //diode témoin 1 ; SP respectée ou non
                    myGLCD.drawCircle(200, 185, 5); //entourer le cercle de blanc
                    if (AirHumidity>=HumidityMin && AirHumidity<= HumidityMax) 
                    {
                    myGLCD.setColor(0, 250, 0);// témoin vert & remplir le cercle
                    myGLCD.fillCircle(200, 185, 4);
                    }
                    else {
                    myGLCD.setColor(255, 0, 0);// témoin rouge & remplir le cercle
                    myGLCD.fillCircle(200, 185, 4);
                                          }