home castoo
chapitre electronique
Electronique reserve eau

Suivi du niveau
de ma reserve d'eau de pluie
Le plan B

avril 2025

Un plan B pour suivre le niveau
de ma réserve d'eau de pluie dans mes cuves

Connaitre le niveau de son réservoir d'eau de pluie n'est certes pas indispensable, sachant que l'on ne peut pas agir sur son remplissage ! Par contre on peut réguler la vitesse à laquelle on va le vider. On peut également envisager de prévoir une augmentation de la quantité d'eau stockée en fonction de la vitesse de remplissage (Achat de nouvelles citernes.) de la réserve actuelle. Ces quelques remarques et le fait que j'aime bien concevoir des petits projets m'ont conduit à me lancer dans ce développement. Je vous partage ici tous les éléments de ce petit projet.
Je vous présente ici un plan B qui fait suite au dév à base d'un capteur ultrasonique présenté "ici". Ce projet est plus complexe, il comporte plus de composant, son prix de revient est donc plus important mais les mesures sont plus fiables dans diverses types de cuve et pour une profondeur pouvant atteindre jusqu'à 5 mètres.

Si vous avez réalisé "le projet de base" avec le capteur ultrasonique, il n'y a que la partie électronique et logiciel à revoir, l'impression 3D étant exactement identique.

Vous pouvez également trouver dans d'autres page du site "Bricolages" comment réparer une cuve en PE qui est percée mais aussi "l'impression en 3D" d'un système de capteur d'eau à installer sur une gouttière avec un gros débit.

Ce plan B est basé sur l'utilisation d'un nouveau type de capteur.

Capteur de niveau de liquide ALS-MPM-2F DC24V 4-20mA, profondeur de gamme 0-5m

Entre 20 et 25 euros chez Ali et + ou - 50 euros chez AmaZ mais c'est plus rapide !

Reserve eau de pluie ALS-MPM-2F.

L'aspect extérieur du projet terminé et
l'impression 3D reste identique au premier dev.

Reserve eau de pluie.

Principes de base du dev :

Mesure de la distance entre le fond de la cuve et la surface. Le système sera autonome, alimenté par deux batteries de 3v7 rechargées par un capteur solaire. Afin de limiter au maximum la consommation, le processeur sera passé en mode Deep Sleep et ne se réveillera qu'une fois toutes les heures. La sonde ainsi que tous les éléments liés aux mesures ne seront alimentés que lorsque le processeur sera éveillé et sera coupé dés que les mesures seront effectuées à l'aide d'un MOSFET commandé par le processeur. Le montage ne sera disponible par wifi que toutes les heures pendant cinq minutes toujours dans l'idée d'économiser la batterie.

Toutes les données des mesures effectuées toutes les heures seront sauvegardées dans des tableaux qui seront stockés dans la mémoire EEPROM du processeur de façon à assurer leur sauvegarde pendant les périodes de deep sleep.

L'horloge est mise à jour par un serveur internet régulièrement.

Le logiciel peut s'adapter à plusieurs type de configuration de cuve pourvu que le diamètre sur la hauteur soit stable le système calcul un nombre de litre au cm de hauteur donc si le diamètre n'est pas égal en haut qu'en bas le calcul sera faussé !
Il faut aussi prendre en compte que toutes les valeurs de remplissage sont des taux donc exprimés en pourcentage.

L'adresse pour se connecter au système est fixe : 192.168.1.88 (vous pouvez la modifier dans le code) par contre il ne faut pas oublier que la connexion n'est possible qu'a heure pleine et fixe pendant seulement 5 minutes (ou il faut aussi modifier le code).

Plusieurs solutions matériels ont été testées au fil des années. Ce plan B semble enfin être totalement fiable et malgrés sont prix de revient plus important je vous le conseil !


Le schéma du montage est celui-ci, plusieurs particularités :


- L'ESP est alimenté en 3v3 par les batteries qui sont rechargées par le TP4056 qui est connecté au panneau solaire.

- L'ESP doit être modifié pour utiliser l'antenne extérieur (il faut modifier l'orientation du strap CMS pour utiliser l'antenne extérieur de l'ESP Wemos PRO (voir en bas de page).).

- le petit interrupteur entre D0 et Rst qui doit être fermé pour le deep Sleep et ouvert pour la programmation de l'ESP.

- La sonde doit être utilisé avec du 24v (c'est aussi possible avec un peu moins !) cette tension est donc obtenue avec un LM2596 qui transforme le 5v en 24v (il est nécessaire de régler le petit potentiomètre pour affiner la tension de sortie.)

- La sonde exprime la profondeur d'eau en cm sous forme d'intensité de 4 à 20 Ma, pour mesurer cette valeur nous allons procéder en deux étapes.

- Transformation de l'intensité en tension avec un module convertisseur (deux réglages avec des potars sur le module le point 0 et le point max. Un cavalier doit également être positionné pour choisir la plage de tension de sortie (voir plus bas)), puis mesure de cette tension avec un ADS1115 (convertisseur analogique vers numérique) qui va transmettre à l'ESP la mesure sur 15 bits via l'interface I2C. (Le choix d'utiliser un ADS est justifié par l'instabilité des mesures avec l'ESP en direct sur seulement 10 bits (voir vidéo plus bas)).

Remarques : (il serait possible de n'utiliser qu'une résistance et de mesurer la tension à ses bornes mais la précision serait vraiment médiocre. Il serait aussi possible d'utiliser un INA219 qui mesure directement l'intensité d'un montage et qui la transmet en I2C mais sur seulement 10 bits (solution déjà utilisée dans un autre projet sur ce site).)

- Le MOSFET est là pour couper l'alimentation une fois que les mesures sont effectuées il est commandé par la broche D5 de l'ESP au travers d'une résistance de 200 ohms (une résistance de 10K est là pour maintenir un état bas lorsque l'ESP est en deepsleep.), cela permet au montage de ne rien consommer pendant la période de deep sleep (seulement quelques micro-ampères) alors que la charge de la batterie en solaire reste opérationnelle.



Reserve eau de pluie chema electronique

Le matériel nécessaire :

Un module ESP8266 Wemos D1 mini PRO et son antenne extérieur.
Un module de charge TP4056.
deux batteries type 18650 de 3v7 / 4200
Un capteur solaire 5v 3W de 17 x 13 cm
Capteur de niveau de liquide ALS-MPM-2F DC24V 4-20mA
Un convertisseur Analogique vers numérique 15bits (I2C) type ADS1115
Un convertisseur DC/DC type LM2596
Un convertisseur Courant Tension (pas trouvé de numéro d'identification).
Un MOSFET N de type AO3400 et son adaptateur pour boitier SOT23 3 broches (plus facile car le FET n'est dispo qu'en CMS).
Une résistance de 10k et une de 200 ohms.
Un presse étoupe étanche pour le cable (PG9)

Un petit jeu de LEGO en modules electronique



L'interface accessible en html est simple (IP fixe).
Adresse : http://192.168.1.88


Reserve eau de pluie Menu HTML

Après avoir saisie l'adresse dans un navigateur le menu principal suivant apparait. Il est possible ici de configurer le type de cuve et un aperçu des dernières mesures est visible (seul graphique en litre). Ici un petit indicateur permet de voir l'etat de la batterie.



Reserve eau de pluie suivi 72 heures.

Graphique de suivi des 72 dernieres heures en %.



Reserve eau de pluie suivi du mois en cours.

Graphique de suivi des 31 derniers jours en %.



Reserve eau de pluie suivi des 12 derniers mois.

Graphique des 12 derniers mois en %.



Reserve eau de pluie detail memoire.

Affichage des mesures sauvegardées dans L'EEPROM du processeur.
d'abord les valeurs des 72 dernières heures puis celles des 31 derniers jour puis celles des 12 derniers mois.



Reserve eau de pluie detail mémoire.

Fin de l'affichage des mesures (ici on voit la fin des données de l'année).
En toute fin de la liste on retrouve les dix dernières mesures stockées, celle-ci non exprimées en pourcentage.
Ce sont ces 10 dernières mesures qui apparaissent sur la page principale du site.



Impression 3D

Vue du boitier à imprimer.



Vue du couvercle à imprimer.


Les fichiers STL pour l'impression sont disponibles dans la partie "Impression3D" du site.


Modif sur le module ESP32 Wemos PRO

1) Prise pour antenne externe.
2) Strap à modifier pour choisir le type d'antenne horizontale (defaut) interne vertical (notre cas) externe.
3) Prévoir un petit strap ou inter entre Rst et D0.

Reserve eau de pluie modif. esp wemos.


Exemple de résultat de lecture de la sonde avec la tension lue sur 10b directement par l'ESP, on peut voir les écarts de lecture alors que la profondeur est stable. Cela peut être due au fait que le processeur exécute d'autres taches en même temps que la lecture, échange wifi, interface, calculs... Je vais donc éliminer rapidement cette solution !

Reserve eau de pluie exemple sur 10 bits.

Exemple de résultat de lecture de la sonde avec la tension lue sur l'ADS 15bits, circuit spécialisé qui n'a que la tache de traduire la conversion et de la transférer sur le réseau I2C. On voit ici que non seulement le résultat est beaucoup plus précis mais également beaucoup plus stable. Je vais donc utilisé cette solution même si elle impose un circuit supplémentaire.

Reserve eau de pluie exemple sur 15 bits.

Exemple de résultat de lecture de la sonde avec la tension lue sur l'ADS 15bits, cuve presque pleine (on voit que l'on a de la marge en mesure (je suis loin des 5m)).

Reserve eau de pluie exemple sur 15 bits cuve pleine.

Video de démo du mode deepsleep et de la consommation du montage. pour ces tests les durées de deepsleep on été adaptées à la démo. Le mode deepsleep n'est déclenché qu'une fois que les 5 minutes d'autorisation WiFi sont écoulées, par contre tout le montage nécessaire aux mesures (convertisseur I>T, alim 24v, ADS 15b et sonde) est lui coupé par le MOSFET des que les mesures sont terminées.




Le code de base qui fonctionne bien pour moi mais que je vous laisse adapter pour votre besoin...
Attention le SSID "ZZZZZZZ"et le passe "XXXXXX" doivent être adaptés à votre configuration internet.


      #include <Arduino.h>
      #include <ESP8266WiFi.h>
      #include <ESP8266WebServer.h>
      #include <EEPROM.h>
      #include <Adafruit_ADS1X15.h>
      
      Adafruit_ADS1115 ads;
      
      //#define debug_sur_usb
      //#define debug_temp
      
      int MosFet = 14; // D5 est uitilisé pour alimenter le montage suite deepSleep avec un MOSFET 
      #define ssid "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ" // SSID de la box
      #define password "XXXXXXXXXXXXXXXXXXXXXXXXX" // Pass de la box
      ESP8266WebServer server(80); // Port IP par defaut du serveur HTML
      const uint64_t duree_sommeil = (60e6)*54; // 54 minutes (duree du sommeil entre deux mesures, ensuite le systeme reste 5 minutes acif).
      const unsigned long memo_temps = (1000*60)*5; // 5 minutes d'activité (mesure + acces wifi)
      unsigned long temps_qui_passe; // Mesure le delai de fonctionnement pendant lequel une cnx est possible.
      unsigned long temps_inter_h; // Mesure du temps entre deux mesure du serveur heure
      boolean top_mesure; // Si true on lance la mesure
      struct tm * timeinfo;
      // declaration structure memo memoire RTC (l'ensemble fait 4 octets) pour ne pas les perdre avec le mode deepsleep
      #define debut_RTC 65 // Début de la zone de mémoire RTC (paquet de 4 octets)
      #define fin_RTC 193 // debut_RTC + 512/4 Fin de la zone de mémoire RTC (paquet de 4 octets)
      struct { // Mémorisation d'une mesure (enregistrement de 65 à 192)
        uint8_t v_m; // mois (1 - 12)
        uint8_t v_j; // jour (1 - 31)
        uint8_t v_h; // heure (0 - 23)
        uint8_t v_pc; // % de remplissage de la reserve (0 - 100)
      } memoval;
      #define debut_TJ 65 // Début tableau Jour
      #define fin_TJ 137 // Début tableau Jour
      struct gr_jour { // Info du graph des 72 dernieres heures (enregistrement de 65 à 137)
        uint8_t v_m; // mois (1 - 12)
        uint8_t v_j; // jour (1 - 31)
        uint8_t v_h; // heure (0 - 23)
        uint8_t v_pc; // % de remplissage de la reserve (0 - 100)
      };
      gr_jour tgr_jour[74];
      #define debut_TM 138 // Début tableau Mois
      #define fin_TM 169 // Début tableau Mois
      struct gr_mois { // Info du graph des 31 derniers jours (enregistrement de 138 à 169)
        uint8_t v_a; // an (20 - 99)
        uint8_t v_m; // mois (1 - 12)
        uint8_t v_j; // jour (1 - 31)
        uint8_t v_pc; // % de remplissage de la reserve (0 - 100) (moyenne)
      };
      gr_mois tgr_mois[32];
      struct String nom_mois[13] = {"nul", "Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Aout", "Septembre", "Octobre", "Novembre", "Decembre"};
      #define debut_TA 170 // Début tableau An
      #define fin_TA 182 // Fin tableau An
      struct gr_an { // Info du graph des 12 derniers mois (enregistrement de 170 à 182)
        uint8_t v_a; // an (20 - 99)
        uint8_t v_m; // mois (1 - 12)
        uint8_t v_0; // = à 0
        uint8_t v_pc; // % de remplissage de la reserve (0 - 100) (moyenne)
      } ;
      gr_an tgr_an[13];
      #define debut_TD 183 // Début tableau Data
      #define fin_TD 192 // Fin tableau Data
      // Variables divers (enregistrement de 183 à 192) 10x4 octets ou 10 int
      struct { // Mémorisation des dernieres mesures en int (enregistrement de 183 à 192)
        int v_x;
      } memodiv;
      int tdiv[11];
      String const v_css_body = "body { background-color: grey; font-family: Sans-Serif; Color: orange; text-align: center;}";
      String const v_css_lien = "a.btn { text-decoration: none; padding: 10px; font-family: arial; font-size: 1em; color: #FFFFFF; background-color: #b2a2c7; border-radius: 24px;-webkit-border-radius: 24px; -moz-border-radius: 24px; border: 4px solid #ffffff; box-shadow: 3px 3px 8px #444444; -webkit-box-shadow: 3px 3px 8px #444444; -moz-box-shadow: 3px 3px 8px #444444; }";
      String const v_css_lien_vol = "a.btn:hover { padding: 10px; color: #ffff00; background-color: #5f497a; border: 4px solid #fbd5b5; box-shadow: 1px 1px 4px #777777; -webkit-box-shadow: 1px 1px 4px #777777; -moz-box-shadow: 1px 1px 4px #777777; }";
      // Structure des infos sauvegardées dans l'eeprom de l'esp
      struct  {
          int h_cuve;
          int c_cuve;
          char v_ok;
      } eeprom_esp;
      char str_mesure[15];
      int mesure;
      int vh_cuve; // Hauteur de la cuve
      int vc_cuve; // Capacité de la cuve
      void init_RTC_complet();
      void charge_tableaux();
      String niveau_bat; // Représentation graphique de la charge de la batterie
      
      // -----------------------------------------------------------------------------------------------------------------------------------
      // Ecriture d'une valeur en mémoire 4 octets dif
      void set_val_mem(uint8_t v_adr){
        system_rtc_mem_write(v_adr, &memoval, sizeof(memoval));
      }
      
      // -----------------------------------------------------------------------------------------------------------------------------------
      // Ecriture d'une valeur en mémoire 1 int de 4 octets
      void set_val_div(uint8_t v_adr){
        system_rtc_mem_write(v_adr, &memodiv, sizeof(memodiv));
      }
      
      // -----------------------------------------------------------------------------------------------------------------------------------
      // Lecture d'une valeur en mémoire 4 octets dif
      void get_val_mem(uint8_t v_adr){
        system_rtc_mem_read(v_adr, &memoval, sizeof(memoval));
      }
      
      // -----------------------------------------------------------------------------------------------------------------------------------
      // Lecture d'une valeur en mémoire 1 int de 4 octets
      void get_val_div(uint8_t v_adr){
        system_rtc_mem_read(v_adr, &memodiv, sizeof(memodiv));
      }
      
      // -----------------------------------------------------------------------------------------------------------------------------------
      // dernieres mesures
      String der_mes(){
        String page = "<!DOCTYPE html><html dir='ltr' lang='fr'><head><meta http-equiv='content-type' content='text/html; charset=UTF-8'>";
        page += "<title>Gestion Reserve d'eau Graph dernieres valeurs</title>";
        page += "<style> " + v_css_body + v_css_lien + v_css_lien_vol + " </style>";
        page += "<script type='text/javascript' src='https://www.gstatic.com/charts/loader.js'></script>";
        page += "<script type='text/javascript'>";
        page += "google.charts.load('current', {'packages':['corechart']});";
        page += "google.charts.setOnLoadCallback(drawChart);";
        page += "function drawChart() { var data = google.visualization.arrayToDataTable([['',''],";
        int vadr=0; while (vadr < 9){ page += "['H" + String(vadr+-9) + "', "; page += String((tdiv[vadr] == 1024) ? 0 : tdiv[vadr]) + "],"; vadr++; }
        page += "['H', " + String((tdiv[9] == 1024) ? 0 : tdiv[9]) + "]]); var options = {title: 'Reserve eau (dernieres valeurs en litres)',";
        page += "curveType: 'function',legend: { position: 'bottom' }}; ";
        page += "var chart = new google.visualization.LineChart(document.getElementById('curve_chart'));";
        page += "chart.draw(data, options);}</script></head><body>";
        page += "<div align='center'>";
        page += "<h1>Gestion réserve d'eau (version sonde inox)</h1>";
        page += "Cuve(s) d'une hauteur de " + String(vh_cuve) + " cm et d'une capacité de " + String(vc_cuve) + " litres.";
        page += " Nous sommes le " + String(timeinfo->tm_mday) + "/" + String(timeinfo->tm_mon + 1) + "/" +  String(timeinfo->tm_year + 1900);
        page += " il est " + String(timeinfo->tm_hour) + " H " + String(timeinfo->tm_min) + " Niveau batterie : " + niveau_bat + " <br/>";
        page += "<h2>Profondeur enregistrée à la derniere mesure " + String(str_mesure) +  " soit " + String(int(vc_cuve/vh_cuve) * mesure) + " litres" + "</h2>";
        page += "</div>";
        page += "<table align='center'>";
        page += "<tr><td width='60%'><form action='/mod_param' method='POST'>";
        page += "<H3>PARAMETRES</H3><br/>";
        page += "Hauteur maximum de la ou des cuve(s) :  <input type='number' id='h_cuve' name='h_cuve' min='10' max='200' value='" + String(vh_cuve) + "'/> cm<br/><br/>";
        page += "Capacité maximum de la ou des cuve(s) : <input type='number' id='c_cuve' name='c_cuve' min='10' max='10000' value='" + String(vc_cuve) + "'/> litres<br/><br/><br/>";
        page += "Soit " + String(int(vc_cuve/vh_cuve)) + " litres / cm <br/><br/> Soit " + String(int(vc_cuve/100)) + " litres / %";
        page += "<br/><br/><br/><button>Valider les modifications</button> <input type='reset' value='Annuler les modifications' /></form>";
        page += "<br/><br/>Attention en cas de modification de ces valeurs les % mémorisés seront faux, une réinitialisation de toutes les mesures est à prévoir...</td>";
        page += "<td><div id='curve_chart' style='width: 400px; height: 400px'></div></td></tr>";
        page += "<tr><td>";
        page += "<br><p> <a class='btn' target='_self' href='/mem_RTC'>Affichage de toutes les données en mémoire</a> </p>";
        page += "<br><p> <a class='btn' target='_self' href='/raz_data'>Réinitialiser toutes les mesures</a> </p>";
        page += "</td>";
        page += "<td align='center'>";
        page += "<br><p><a class='btn' target='_self' href='/graph_jour'>Graphique des 72 dernieres heures en %</a></p>";
        page += "<br><p><a class='btn' target='_self' href='/graph_mois'>Graphique des 31 derniers jours en %</a></p>";
        page += "<br><p><a class='btn' target='_self' href='/graph_an'>Graphique des 12 derniers mois en %</a></p>";
        page += "</td></tr></table>";
        page += "<br><p><a class='btn' href='https://www.castoo.fr' target='_blank'>Visiter le site https://www.castoo.fr</a></p>";
        page += "</body></html>";
        return page;
      }
      
      // -----------------------------------------------------------------------------------------------------------------------------------
      // Construction de la page HTML Graphique Jour 72 heures
      String page_grjour(){
        String page = "<!DOCTYPE html><html dir='ltr' lang='fr'><head><meta http-equiv='content-type' content='text/html; charset=UTF-8'>";
        page += "<title>Gestion Reserve d'eau Graph 72 heures</title>";
        page += "<style> " + v_css_body + v_css_lien + v_css_lien_vol + " </style>";
        page += "<script type='text/javascript' src='https://www.gstatic.com/charts/loader.js'></script>";
        page += "<script type='text/javascript'>";
        page += "google.charts.load('current', {'packages':['corechart']});";
        page += "google.charts.setOnLoadCallback(drawChart);";
        page += "function drawChart() { var data = google.visualization.arrayToDataTable([['Heure',";
        page += "'Derniere date " + String(tgr_jour[72].v_j) + " " + nom_mois[tgr_jour[72].v_m] + " à " + String(tgr_jour[72].v_h) + "H '],";
        int vadr=0;
        while (vadr <= 72){
          page += "['" + String(tgr_jour[vadr].v_j) + "/" + String(tgr_jour[vadr].v_h) + "h', ";
          page += String((tgr_jour[vadr].v_pc == 255) ? 0 : tgr_jour[vadr].v_pc) + "],";
          vadr++;
        }
        page += "['" + String(tgr_jour[vadr].v_h) + "h', " + String((tgr_jour[vadr].v_pc == 255) ? 0 : tgr_jour[vadr].v_pc) + "]";
        page += "]); var options = {";
        page += "title: 'Evolution de la réserve d eau sur les 72 dernieres heures  en % de remplissage',";
        page += "curveType: 'function',";
        page += "legend: { position: 'bottom' }";
        page += "}; var chart = new google.visualization.LineChart(document.getElementById('curve_chart'));";
        page += "chart.draw(data, options);}</script></head><body><div align='center'><div id='curve_chart' style='width: 1000px; height: 500px'></div>";
        page += "<br><p align='center'><a class='btn' target='_self' href='/'>Retour Accueil</a> ";
        page += " <a class='btn' href='https://www.castoo.fr' target='_blank'>Visiter le site https://www.castoo.fr</a></p>";
        page += "</div></body></html>";
        return page;
      }
      
      // -----------------------------------------------------------------------------------------------------------------------------------
      // Construction de la page HTML Graphique Mois 31 jours
      String page_grmois(){
        String page = "<!DOCTYPE html><html dir='ltr' lang='fr'><head><meta http-equiv='content-type' content='text/html; charset=UTF-8'>";
        page += "<title>Gestion Reserve d'eau Graph 31 jours</title>";
        page += "<style> " + v_css_body + v_css_lien + v_css_lien_vol + " </style>";
        page += "<script type='text/javascript' src='https://www.gstatic.com/charts/loader.js'></script>";
        page += "<script type='text/javascript'>";
        page += "google.charts.load('current', {'packages':['corechart']});";
        page += "google.charts.setOnLoadCallback(drawChart);";
        page += "function drawChart() { var data = google.visualization.arrayToDataTable([['Jour',";
        page += "'(début analyse) Mois de " + nom_mois[tgr_mois[0].v_m] + " " + String(tgr_mois[0].v_a + 1900) + "'],";
        int vadr=0;
        while (vadr <= 30){
          page += "['" + String(tgr_mois[vadr].v_j) + "/" + String(tgr_mois[vadr].v_m) + "', ";
          page += String((tgr_mois[vadr].v_pc == 255) ? 0 : tgr_mois[vadr].v_pc) + "],";
          vadr++;
        }
        page += "['" + String(tgr_mois[vadr].v_j) + "/" + String(tgr_mois[vadr].v_m) + "', " + String((tgr_mois[vadr].v_pc == 255) ? 0 : tgr_mois[vadr].v_pc) + "]";
        page += "]); var options = {title: 'Evolution de la réserve eau sur les 31 derniers jours en % de remplissage',";
        page += "curveType: 'function',legend: { position: 'bottom' }}; ";
        page += "var chart = new google.visualization.LineChart(document.getElementById('curve_chart'));";
        page += "chart.draw(data, options);}</script></head><body><div align='center'><div id='curve_chart' style='width: 900px; height: 500px'></div>";
        page += "<br><p align='center'><a class='btn' href='/' target='_self'>Retour Accueil</a> ";
        page += " <a class='btn' href='https://www.castoo.fr' target='_blank'>Visiter le site https://www.castoo.fr</a></p>";
        page += "valeur 31 => " + String(tgr_mois[31].v_pc);
        page += "</div></body></html>";
        return page;
      }
      
      // -----------------------------------------------------------------------------------------------------------------------------------
      // Construction de la page HTML Graphique An 12 mois
      String page_gran(){
        String page = "<!DOCTYPE html><html dir='ltr' lang='fr'><head><meta http-equiv='content-type' content='text/html; charset=UTF-8'>";
        page += "<title>Gestion Reserve d'eau Graph 12 mois</title>";
        page += "<style> " + v_css_body + v_css_lien + v_css_lien_vol + " </style>";
        page += "<script type='text/javascript' src='https://www.gstatic.com/charts/loader.js'></script>";
        page += "<script type='text/javascript'>";
        page += "google.charts.load('current', {'packages':['corechart']});";
        page += "google.charts.setOnLoadCallback(drawChart);";
        page += "function drawChart() { var data = google.visualization.arrayToDataTable([['Jour',";
        page += "'(début analyse) Année " + String(tgr_an[0].v_a + 1900) + "'],";
        int vadr=0;
        while (vadr <= 11){
          page += "['" + nom_mois[tgr_an[vadr].v_m] + "', ";
          page += String((tgr_an[vadr].v_pc == 255) ? 0 : tgr_an[vadr].v_pc) + "],";
          vadr++;
        }
        page += "['" + nom_mois[tgr_an[vadr].v_m] + "', " + String((tgr_an[vadr].v_pc == 255) ? 0 : tgr_an[vadr].v_pc) + "]";
        page += "]); var options = {title: 'Evolution de la réserve eau sur les 12 derniers mois en % de remplissage',";
        page += "curveType: 'function',legend: { position: 'bottom' }}; ";
        page += "var chart = new google.visualization.LineChart(document.getElementById('curve_chart'));";
        page += "chart.draw(data, options);}</script></head><body><div align='center'><div id='curve_chart' style='width: 900px; height: 500px'></div>";
        page += "<br><p align='center'><a class='btn' href='/' target='_self'>Retour Accueil</a> ";
        page += " <a class='btn' href='https://www.castoo.fr' target='_blank'>Visiter le site https://www.castoo.fr</a></p>";
        page += "valeur 12 => " + String(tgr_an[12].v_pc);
        page += "</div></body></html>";
        return page;
      }
      
      // -----------------------------------------------------------------------------------------------------------------------------------
      // -------------------------- Afficher toutes les valeurs de la mémoire RTC ----------------------
      String aff_toutes_valeurs_RTC(){
        String page = "<!DOCTYPE html><html dir='ltr' lang='fr'><head><meta http-equiv='content-type' content='text/html; charset=UTF-8'>";
        page += "<style> " + v_css_body + v_css_lien + v_css_lien_vol + " </style>";
        page += "<title>mémoire RTC</title>";
        page += "<style> body { background-color: grey; font-family: Sans-Serif; Color: orange; }</style>";
        page += "</head><body><div align='center'><h1>Gestion reserve eau</h1>";
        page += "<p>Liste des variables mémorisées dans la mémoire RTC :</p>";
          for(int vadr=debut_RTC; vadr <= fin_TA; vadr++){
            get_val_mem(vadr);
            page += "<p align='center'> val : " + String(vadr) + " => mois :" + String(memoval.v_m) + " => jour :" + String(memoval.v_j) + " => heure :" + String(memoval.v_h) + " => % :" + String(memoval.v_pc) + "</p>";
          }
          for(int vadr=debut_TD; vadr <= fin_TD; vadr++){
            get_val_div(vadr);
            page += "<p align='center'> val : " + String(vadr) + " RTC x1 :" + String(memodiv.v_x) + "</p>";
          }
        page += "<br><p align='center'><a class='btn' href='/' target='_self'>Retour Accueil</a> ";
        page += " <a class='btn' href='https://www.castoo.fr' target='_blank'>Visiter le site https://www.castoo.fr</a></p>";
        page += "</body></html>";
        return page;
      }
      
      // ---------------------------------------------------------------
      // --------- Demande de page inexistante ------
      void page_inexistante() {
        String page_inexist = "Page inexistante";
        page_inexist += "<br/>URL: ";
        page_inexist += server.uri();
        page_inexist += "<br/>Method: ";
        page_inexist += (server.method() == HTTP_GET) ? "GET" : "POST";
        page_inexist += "<br/>Arguments: ";
        page_inexist += server.args();
        page_inexist += "<br/>";
        for (uint8_t i = 0; i < server.args(); i++) { page_inexist += " " + server.argName(i) + ": " + server.arg(i) + "<br/>"; }
        server.send(404, "text/plain", page_inexist);
        #ifdef debug_sur_usb
          Serial.println("Envoi : page_inexistante");
        #endif
      }
      
      // -----------------------------------------------------------------------------------------------------------------------------------
      // -------------------------- Mesure de la profondeur d'eau ----------------------
      // ADS1115 la résolution est de 15 bits (allant de 0 à 32767)
      float lireHauteurCm() {  // Fonction de conversion analogique -> hauteur en cm
        float tension;
        int16_t brut;
        brut = ads.readADC_SingleEnded(0); // Lecture de la valeur de l'ADS (convertisseur analogique numerique)
        #ifdef debug_sur_usb
          Serial.print("Mesure brut de l'ADS sonde (allant de 0 à 32767) : ");
          Serial.println(brut);
        #endif
        tension = ads.computeVolts(brut); // Valeur brut entre 0 et 32767 (32767 = 5m) convertie en tension
        float tensionMin = 0.66; // correspond à 4 mA
        float tensionMax = 3.3;  // correspond à 20 mA
        if (tension < tensionMin) tension = tensionMin;
        if (tension > tensionMax) tension = tensionMax;
        float pourcentage = (tension - tensionMin) / (tensionMax - tensionMin);
        float hauteurCm = pourcentage * 500.0; // Plage 0–5 m
        return hauteurCm;
      }
      
      // -----------------------------------------------------------------------------------------------------------------------------------
      // -------------------------- Mesure du niveau de la batterie ----------------------
      int lireVBatterie() {  // Fonction de conversion analogique -> Niveau de la batterie
        float tension;
        int tension_p; // tension en pourcentage
        int16_t brut;
        brut = ads.readADC_SingleEnded(1); // Lecture de la valeur de l'ADS (convertisseur analogique numerique)
        tension = brut * 0.125 / 100.0; // volts
        if (tension >= 4.20) tension_p = 100;
        else if (tension >= 4.10) tension_p =  90;
        else if (tension >= 3.95) tension_p =  75;
        else if (tension >= 3.85) tension_p =  50;
        else if (tension >= 3.73) tension_p =  25;
        else if (tension >= 3.50) tension_p =  10;
        else if (tension >= 3.20) tension_p =  0;
        else tension_p = 0;
        #ifdef debug_sur_usb
          Serial.print("Mesure brut de l'ADS batterie (allant de 0 à 32767) : "); Serial.println(brut);
          Serial.print("Tension en volt : ");Serial.println(tension);
          Serial.print("Tension en % : ");Serial.println(tension_p);
        #endif
        return tension_p;
      }
      
      // -----------------------------------------------------------------------------------------------------------------------------------
      // -------------------------- Création d'une barre pour représenter la charge de la batterie ----------------------
      String batterie_Icon(int tension_pourcentage) {
        int blocks = map(tension_pourcentage, 0, 100, 0, 10);
        String icon = "[";
        for (int i = 0; i < 10; i++) {
          if (i < blocks) icon += "█";
          else icon += "&nbsp;";
        }
        icon += "]";
        return icon;
       }
      
      // -----------------------------------------------------------------------------------------------------------------------------------
      // ---------------- Calcul de la moyenne des mesures --------------------
      float moyenneTableau(float tableau[], float tailleTableau){
          float somme=0;
          for(int i=0; i < tailleTableau; i++){
              somme=somme+tableau[i];
          }
          somme = somme / (tailleTableau);
          return somme;
      }
      
      // -----------------------------------------------------------------------------------------------------------------------------------
      // Remise à 0 de toutes les variables
      void raz_toutes_les_donnees(){
        init_RTC_complet();
        charge_tableaux();
        server.send(200, "text/html", der_mes());
      }
      
      // -----------------------------------------------------------------------------------------------------------------------------------
      // Enregistrement d'une nouvelle valeur dans la mémoire RTC
      void enr_nouvelle_valeur(int v_val){
        int vadr, van, vmois, vjour, vheure;
        vjour = timeinfo->tm_mday;
        vmois = timeinfo->tm_mon + 1;
        vheure = timeinfo->tm_hour;
        van = timeinfo->tm_year;
        int vnbh = 1;
        int v_val_pc = (v_val * 100)/ vh_cuve;
        if(v_val_pc > 100){v_val_pc = 100;} // En cas d'erreur (lors du dev.)
        #ifdef debug_sur_usb
          Serial.println("v_val cm : " + String(v_val));
          Serial.println("vh_cuve cm : " + String(vh_cuve));
          Serial.println("Enregistrement mesure v_val_pc : " + String(v_val_pc));
        #endif
        int vcumulh = v_val_pc;
        // ------------------------- Enr. dans RTC jour on place la val en position RTC-72(+65) et on recopie TJour de 2 à 72 vers RTC-1(+65) à RTC-71(+65)
        // memo 
        for(vadr=debut_TJ; vadr <= fin_TJ-1; vadr++){
          memoval.v_m =  tgr_jour[vadr-debut_TJ+1].v_m; tgr_jour[vadr-debut_TJ].v_m = tgr_jour[vadr-debut_TJ+1].v_m;
          memoval.v_j =  tgr_jour[vadr-debut_TJ+1].v_j; tgr_jour[vadr-debut_TJ].v_j = tgr_jour[vadr-debut_TJ+1].v_j;
          memoval.v_h =  tgr_jour[vadr-debut_TJ+1].v_h; tgr_jour[vadr-debut_TJ].v_h = tgr_jour[vadr-debut_TJ+1].v_h;
          memoval.v_pc = tgr_jour[vadr-debut_TJ+1].v_pc; tgr_jour[vadr-debut_TJ].v_pc = tgr_jour[vadr-debut_TJ+1].v_pc;
          // selection des données pour calcul de la moyenne du jour
          if(memoval.v_j==vjour && memoval.v_pc!=255){
            vnbh++;
            vcumulh+=memoval.v_pc;
          }
          set_val_mem(vadr);
        }
        // memo 72eme heure
        memoval.v_m = vmois; tgr_jour[72].v_m = vmois;
        memoval.v_j = vjour; tgr_jour[72].v_j = vjour;
        memoval.v_h = vheure; tgr_jour[72].v_h = vheure;
        memoval.v_pc = v_val_pc; tgr_jour[72].v_pc = v_val_pc;
        set_val_mem(fin_TJ);
       // -------------------------------------------- Enr. dans RTC mois
        // calcul de la moyenne du jour
        int moyjour=0;
        moyjour = int(vcumulh/vnbh);
        int vnbj = 1;
        int vcumulj = moyjour;
        // Si nouvelle journée alors on decale les 30 premiers jours
        if(tgr_mois[fin_TM-debut_TM].v_j != vjour){
          for(vadr=debut_TM; vadr <= fin_TM-1; vadr++){
            memoval.v_m = tgr_mois[vadr-debut_TM+1].v_a; tgr_mois[vadr-debut_TM].v_a = tgr_mois[vadr-debut_TM+1].v_a;
            memoval.v_j = tgr_mois[vadr-debut_TM+1].v_m; tgr_mois[vadr-debut_TM].v_m = tgr_mois[vadr-debut_TM+1].v_m;
            memoval.v_h = tgr_mois[vadr-debut_TM+1].v_j; tgr_mois[vadr-debut_TM].v_j = tgr_mois[vadr-debut_TM+1].v_j;
            memoval.v_pc = tgr_mois[vadr-debut_TM+1].v_pc; tgr_mois[vadr-debut_TM].v_pc = tgr_mois[vadr-debut_TM+1].v_pc;
            // selection des données pour calcul de la moyenne du mois
            if(memoval.v_j==vmois && memoval.v_pc!=255){
              vnbj++;
              vcumulj+=memoval.v_pc;
            }
            set_val_mem(vadr);
          }
        }
        // memo 31em jour
        memoval.v_m = van; tgr_mois[31].v_a = van;
        memoval.v_j = vmois; tgr_mois[31].v_m = vmois;
        memoval.v_h = vjour; tgr_mois[31].v_j = vjour;
        memoval.v_pc = moyjour; tgr_mois[31].v_pc = moyjour;
        set_val_mem(fin_TM);
        // ---------------------------- Enr. dans RTC an
        // Calcul moyenne mois
        int moymois=0;
        moymois = int(vcumulj/vnbj);
        // Si nouveau mois alors on decale les 11 premiers mois
        if(tgr_an[fin_TA-debut_TA].v_m != vmois){
          for(vadr=debut_TA; vadr <= fin_TA-1; vadr++){
            memoval.v_m = tgr_an[vadr-debut_TA+1].v_a; tgr_an[vadr-debut_TA].v_a = tgr_an[vadr-debut_TA+1].v_a;
            memoval.v_j = tgr_an[vadr-debut_TA+1].v_m; tgr_an[vadr-debut_TA].v_m = tgr_an[vadr-debut_TA+1].v_m;
            memoval.v_h = tgr_an[vadr-debut_TA+1].v_0; tgr_an[vadr-debut_TA].v_0 = tgr_an[vadr-debut_TA+1].v_0;
            memoval.v_pc = tgr_an[vadr-debut_TA+1].v_pc; tgr_an[vadr-debut_TA].v_pc = tgr_an[vadr-debut_TA+1].v_pc;
            set_val_mem(vadr);
          }
        }
        // memo 12em mois
        memoval.v_m = van; tgr_an[12].v_a = van;
        memoval.v_j = vmois;  tgr_an[12].v_m = vmois;
        memoval.v_h = 0;  tgr_an[12].v_0 = 0;
        memoval.v_pc = moymois;  tgr_an[12].v_pc = moymois;
        set_val_mem(fin_TA);
        // ------------------------- Enr. dans RTC divers
        // On decale dans tous les cas les 9 dernieres valeurs
        for(vadr=1; vadr <= 9; vadr++){
          memodiv.v_x = tdiv[vadr];
          set_val_div((vadr-1)+debut_TD);
        }
        // Mémo derniere valeur
        tdiv[9] = int(vc_cuve / vh_cuve) * v_val;
        memodiv.v_x = tdiv[9];
        set_val_div(fin_TD-1); // fin_TD);
        #ifdef debug_sur_usb
          Serial.println("Enregistrement mesure : " + String(tdiv[9]));
        #endif
      
        //-----------------------------
        // a enlever quand le deepsleep sera en route
          //charge_tableaux();
      }
      
      // -----------------------------------------------------------------------------------------------------------------------------------
      // Chargement des tableaux (jour, mois, an, divers)
      void charge_tableaux(){
        int vadr;
        // Chargement tableau Jour
        #ifdef debug_sur_usb
          Serial.println("Chargement tableau Jour");
        #endif
        for(vadr=debut_TJ-1; vadr <= fin_TJ; vadr++){
          get_val_mem(vadr);
          tgr_jour[vadr-debut_TJ].v_m = memoval.v_m;
          tgr_jour[vadr-debut_TJ].v_j = memoval.v_j;
          tgr_jour[vadr-debut_TJ].v_h = memoval.v_h;
          tgr_jour[vadr-debut_TJ].v_pc = memoval.v_pc;
          #ifdef debug_sur_usb
            //Serial.println( "val : " + String(vadr-debut_TJ) + " => mois :" + String(tgr_jour[vadr-debut_TJ].v_m) + " => jour :" + String(memoval.v_j) + " => heure :" + String(memoval.v_h) + " => % :" + String(tgr_jour[vadr-debut_TJ].v_pc) );
          #endif
        }
        
        // Chargement tableau Mois
        #ifdef debug_sur_usb
          Serial.println("Chargement tableau Mois");
        #endif
        for(vadr=debut_TM; vadr <= fin_TM; vadr++){
          get_val_mem(vadr);
          tgr_mois[vadr-debut_TM].v_a = memoval.v_m;
          tgr_mois[vadr-debut_TM].v_m = memoval.v_j;
          tgr_mois[vadr-debut_TM].v_j = memoval.v_h;
          tgr_mois[vadr-debut_TM].v_pc = memoval.v_pc;
          #ifdef debug_sur_usb
            //Serial.println( "val : " + String(vadr) + " => mois :" + String(memoval.v_m) + " => jour :" + String(memoval.v_j) + " => heure :" + String(memoval.v_h) + " => % :" + String(memoval.v_pc) );
          #endif
       }
        // Chargement tableau An
        #ifdef debug_sur_usb
          Serial.println("Chargement tableau An");
        #endif
        for(vadr=debut_TA; vadr <= fin_TA; vadr++){
          get_val_mem(vadr);
          tgr_an[vadr-debut_TA].v_a = memoval.v_m;
          tgr_an[vadr-debut_TA].v_m = memoval.v_j;
          tgr_an[vadr-debut_TA].v_0 = memoval.v_h;
          tgr_an[vadr-debut_TA].v_pc = memoval.v_pc;
          #ifdef debug_sur_usb
            //Serial.println( "val : " + String(vadr) + " => mois :" + String(memoval.v_m) + " => jour :" + String(memoval.v_j) + " => heure :" + String(memoval.v_h) + " => % :" + String(memoval.v_pc) );
          #endif
        }
        // Chargement tableau Divers
        #ifdef debug_sur_usb
          Serial.println("Chargement tableau Divers");
        #endif
        for(vadr=debut_TD; vadr <= fin_TD; vadr++){
          get_val_div(vadr);
          tdiv[vadr-debut_TD] = memodiv.v_x;
          #ifdef debug_sur_usb
            //Serial.println( "val : " + String(vadr) + " => x : " + String(memodiv.v_x)  );
          #endif
        }
      }
      
      // -----------------------------------------------------------------------------------------------------------------------------------
      // Sauve param dans eeprom esp
      void sauve_data_eeprom_esp(){
          eeprom_esp.h_cuve = vh_cuve;
          eeprom_esp.c_cuve = vc_cuve;
          eeprom_esp.v_ok = 'O';
          EEPROM.put(0,eeprom_esp);
          EEPROM.commit();
      }
      
      // -----------------------------------------------------------------------------------------------------------------------------------
      // Les parametres ont été modifiés
      void modif_param(){
        if ( server.hasArg("h_cuve")) { vh_cuve = server.arg("h_cuve").toInt(); sauve_data_eeprom_esp();}
        if ( server.hasArg("c_cuve")) { vc_cuve = server.arg("c_cuve").toInt(); sauve_data_eeprom_esp();}
        server.send ( 200, "text/html", der_mes() );
      }
      
      // -----------------------------------------------------------------------------------------------------------------------------------
      void setup() {
        #ifdef debug_sur_usb
          Serial.begin(9600);
        #endif
        #ifdef debug_temp
          Serial.begin(9600);
        #endif
        pinMode(MosFet, OUTPUT); // Alimentation du montage pour mesures
        digitalWrite(MosFet, LOW);
        IPAddress ip(192, 168, 1, 88); // Declaration adr IP fixe
        IPAddress dns(192,168,1,1);
        IPAddress gateway(192,168,1,1);
        IPAddress subnet(255, 255, 255, 0);
        WiFi.mode(WIFI_STA);
        WiFi.config(ip, gateway, subnet, dns);
        WiFi.begin(ssid, password);
        //wifiMulti.addAP(ssid, password);
        #ifdef debug_sur_usb
          Serial.println("Init WiFi : ");
        #endif
        //while (wifiMulti.run() != WL_CONNECTED) {
        while (WiFi.status() != WL_CONNECTED) {
          #ifdef debug_sur_usb
            Serial.print(".");
          #endif
          delay ( 100 );
        }
        #ifdef debug_sur_usb
        Serial.print("IP : ");
        Serial.println(WiFi.localIP());
        Serial.println("Init TIME_ZONE pool.ntp.org : ");
        #endif
        //configTime(TIME_ZONE, "pool.ntp.org", "time.nis.gov");
        configTime(0, 0 , "pool.ntp.org", "time.nis.gov"); // 7200 heure hiver / 3600 heure ete
        setenv("TZ", "CET-1CEST-2,M3.5.0/02:00:00,M10.5.0/03:00:00", 1);
        while (time(nullptr) < 1000000000ul) {
          delay(100);
          #ifdef debug_sur_usb
            Serial.print(".");
          #endif
        }
        time_t now = time(nullptr);
        timeinfo = localtime (&now);
        char buffer [80];
        strftime (buffer,80,"Local time: %H:%M.",timeinfo);
        #ifdef debug_sur_usb
          Serial.println(buffer);
        #endif
        time(&now);
        temps_qui_passe = millis();
        temps_inter_h = temps_qui_passe;
        ads.setGain(GAIN_ONE); // +/- 4.096V Résolution de 0.125mV par bit
        if (!ads.begin()) { Serial.println("Probleme init ADS 1115"); }
        top_mesure = true;
        EEPROM.begin(sizeof(eeprom_esp)+1); //eeprom esp
        EEPROM.get(0, eeprom_esp);
        if(eeprom_esp.v_ok == 'O'){ // l'enregistrement est valide alors on charge les variables de l'eeprom
          vh_cuve = eeprom_esp.h_cuve;
          vc_cuve = eeprom_esp.c_cuve;
        } else {
          vh_cuve = 170;  // valeur par defaut pour hauteur
          vc_cuve = 2000; // valeur par defaut pour capacité
          sauve_data_eeprom_esp();
        }
        charge_tableaux(); // Chargement des tableaux (jour, mois, an, divers) qui ont été sauvegardés pendant le deepsleep
        server.on ( "/"          ,  [](){ server.send(200, "text/html", der_mes()); });
        server.on ( "/graph_jour",  [](){ server.send(200, "text/html", page_grjour()); });
        server.on ( "/graph_mois",  [](){ server.send(200, "text/html", page_grmois()); });
        server.on ( "/graph_an"  ,  [](){ server.send(200, "text/html", page_gran()); });
        server.on ( "/mem_RTC"   ,  [](){ server.send(200, "text/html", aff_toutes_valeurs_RTC()); });
        server.on ( "/raz_data"  , raz_toutes_les_donnees);
        server.on ( "/mod_param" , modif_param); // Retour des parametres (hauteur cuve et capacité cuve)
        server.onNotFound(page_inexistante);
        server.begin();
        delay(1000);
        digitalWrite(MosFet, HIGH); // On alimente le capteur
        delay(50);
        #ifdef debug_sur_usb
          Serial.println("Montage sous tension ");
        #endif
      }
      
      // -----------------------------------------------------------------------------------------------------------------------------------
      // Initialise la totalité des tableaux de variables
      void init_RTC_complet(){
        int vadr, van, vmois, vjour, vheure;
        // RAZ memo jour (72 heures)
        vjour = timeinfo->tm_mday;
        vmois = timeinfo->tm_mon + 1;
        vheure = timeinfo->tm_hour;
        for(vadr=debut_TJ; vadr <= fin_TJ; vadr++){
          memoval.v_m = vmois;
          memoval.v_j = vjour;
          memoval.v_h = vheure;
          vheure++;
          if(vheure==24){
            vheure=0;
            vjour++; 
            if(vjour==31){ 
              vjour=1; 
              vmois++;
              if(vmois==13) vmois=1;
            } 
          }
          memoval.v_pc = 255;
          set_val_mem(vadr);
        }
        // RAZ memo mois (31 jours)
        van = timeinfo->tm_year;
        vmois = timeinfo->tm_mon + 1;
        vjour = timeinfo->tm_mday;
        for(vadr=debut_TM; vadr <= fin_TM; vadr++){
          memoval.v_m = van;
          memoval.v_j = vmois;
          memoval.v_h = vjour;
          vjour++;
          if(vjour==31){
            vjour=1;
            vmois++; 
            if(vmois==13){ 
              vmois=1; 
              van++;
            } 
          }
          memoval.v_pc = 255;
          set_val_mem(vadr);
        }
        // RAZ memo an (12 mois)
        van = timeinfo->tm_year;
        vmois = timeinfo->tm_mon + 1;
        for(vadr=debut_TA; vadr <= fin_TA; vadr++){
          memoval.v_m = van;
          memoval.v_j = vmois;
          vmois++;
          if(vmois==13){
            vmois=1;
            van++; 
          }
          memoval.v_h = 0;
          memoval.v_pc = 255;
          set_val_mem(vadr);
        }
        // RAZ memo variables divers
        for(vadr=debut_TD; vadr <= fin_TD; vadr++){
          memodiv.v_x = 1024;
          set_val_div(vadr);
        }
      }
      
      // -----------------------------------------------------------------------------------------------------------------------------------
      void loop() {
        server.handleClient(); // mise en reception du serveur wifi
        if(top_mesure){ // On vient de demarrer alors on lance une mesure
          #ifdef debug_sur_usb
            Serial.println("Lancement de la mesure suite demarrage...");
          #endif
          float vmesure[3]; // on va faire une moyenne sur 3 mesures
          float resultat = 0;
          for(int cpt = 0; cpt < 3; cpt++){
            vmesure[cpt] = lireHauteurCm();
            #ifdef debug_sur_usb
              Serial.print("Lancement mesure : ");
              Serial.print(cpt);
              Serial.print(" valeur : ");
              Serial.println(vmesure[cpt]);
            #endif
            delay(1000);
          }
          resultat = moyenneTableau(vmesure, 3);
          mesure = int(resultat);
          snprintf (str_mesure, 50, " : %d cm", mesure);
          enr_nouvelle_valeur(mesure);
          int tension_bat = lireVBatterie(); // Lecture de la tension de la batterie
          niveau_bat = batterie_Icon(tension_bat); // Création d'un icone pour présenter la charge de la batterie
          top_mesure = false; // On ne relancera pas la mesure avant une heure
          digitalWrite(MosFet, LOW); // On coupe l'alim du capteur (plus besoin pour la lecture des infos web wifi)
        }
        if((millis() - temps_inter_h) >= 60000){ // on ne lance une interrogation serveur horaire qu'une fois toutes les minutes
          time_t now = time(nullptr);
          timeinfo = localtime (&now);
          temps_inter_h += 60000;
          #ifdef debug_sur_usb
            Serial.println(String(timeinfo->tm_hour) + "H" + String(timeinfo->tm_min));
            Serial.println("Lancement interrogation serveur heure...");
          #endif
        }
        if((millis() - temps_qui_passe) >= memo_temps){ // On ne laisse que 5 minutes en route pour faire la mesure et se connecter au wifi.
          #ifdef debug_sur_usb
            Serial.println(String(timeinfo->tm_hour) + "H" + String(timeinfo->tm_min));
            Serial.println("Les 5 minutes sont en cours...");
          #endif
          if(timeinfo->tm_min > 5){ // Si on est bien sur un nombre de minute > 5 on coupe l'esp
            #ifdef debug_sur_usb
              Serial.println(String(timeinfo->tm_hour) + "H" + String(timeinfo->tm_min));
              Serial.println("Les 5 minutes sont en passées, arret de l'esp !!!!!-------!!!!!!");
            #endif
            // on essai de partir sur un arret de l'esp jusqu'à la prochaine heure pleine.
            if(timeinfo->tm_min == 6){
              ESP.deepSleep(duree_sommeil); // On coupe l'esp pendant 54 minutes (impossible de le joindre pendant cette période)
            }else{
              int nb_min = 60 - timeinfo->tm_min;
              ESP.deepSleep((60e6)*nb_min); // On coupe l'esp jusqu'à la prochaine heure pleine (impossible de le joindre pendant cette période)
            }
          }
        }
        delay(100);
      }

  



accueil electronique

Bricolage Robotique Informatique Peinture Voyage
Téléc. portail Le robot "mécano" Astuces informatique Henri Bertrou Auvergne
Bat. Iphone 6S Le robot "solaire" Réseau couche app. Jean-Michel Castille Floride
Robot piscine Servo et IR" Réseau Les couches New York
Xiaomi M365 Le robot "thymio" Réseaux Outils L'Ouest américain
Mac Mini Le robot "Rovio" Unités grandeur inf. L'Ile Maurice
Putty SSH Windows L'Italie / Venise
Bases Raspberry Tunisie
Termius IPhone/IPad Grece
Le vieux ZX 81
...
Navigation La Rochelle CNC / Imp3D Electronique Programmation
Rencontre dauphins Les Minimes Construction CNC Alim. TPL 5110 Doc. programme
Analyse NMEA 0183 Le Vieux port CNC du commerce Carte ESP8266 Indent programme
graph. NMEA 0183 L'Ile de Ré Martyr CNC ESP8266 1 relai Prog. objet
Analyse trames AIS A visiter Réa. imp. 3D ESP8266 Alarme Prog. procédurale
Analyse AIS TCP-IP Cura impression 3D ESP8266 MQTT
Sortie en ketch Plateau CR10 ESP8266 Temp.
Echange GPS C80 Anémomètre.
HP Sun-Odyssey CNC / 3D en vrac MCP9808 Librairie
LCD yanmar Saisie Oled
Testeur nmea esp1 i2c