![]() |
Suivi du niveau |
avril 2025 |
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.
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.
Mesure de la distance entre un capteur infrarouge et la surface de l'eau en fond de cuve. Le système sera autonome, alimenté par une batterie de 3v7 rechargée 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. Le capteur est alimenté par une broche du processeur de façon à ce qu'il ne consomme que quand le processeur est actif. 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.87 (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. Plusieurs type de capteur infrarouge et même lidar. Le problème principal étant l'angle de mesure du capteur qui a tendance à buter sur les parois de la cuve plutôt que de mesurer la profondeur de l'eau. Avec le lidar il y avait des problèmes de réflechissement de la lumière au travers de la cuve. Il est certain qu'avec une cuve en forme de cube comme celle de 1000 litres couramment utilisée l'éloignement des parois facilite le travail du capteur (l'angle de mesure sans obstacle est plus important).
![]() |
Il est très important de vérifier l'angle de mesure du capteur ultrasonique. Il faut le faire, cuve vide ou avec une fine pellicule d'eau au fond. Si le capteur bute sur une cloison de la cuve la mesure sera faussée et ne donnera rien, la valeur n'évoluera plus jusqu'à la fin de la cuve. Plus la cuve est large plus ce réglage est facile. L'angle de mesure du capteur est donc important, pour le S100 Y401 il est de 15°. |
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).
Graphique de suivi des 72 dernieres heures en %.
Graphique de suivi des 31 derniers jours en %.
Graphique des 12 derniers mois en %.
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.
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.
Vue du boitier à imprimer.
Vue du couvercle à imprimer.
Les fichiers STL pour l'impression sont disponibles dans la partie "Impression3D" du site.
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>
//#define debug_sur_usb
#define debug_temp
int trigPin = 14; // D5 sur esp8266 wemos
int echoPin = 12; // D6 sur esp8266 wemos
int le_plus = D1; // D1 est uitilisé pour alimenter le Y401 lors du deepSleep
#define ssid "ZZZZZZZZZZZZZZZZZZZZZZZZZ" // SSID de la box
#define password "XXXXXXXXXXXXXXXXXXXXX" // 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();
// -----------------------------------------------------------------------------------------------------------------------------------
// 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</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) + " <br/>";
page += "<h2>Profondeur enregistrée à la derniere mesure " + String(str_mesure) + " soit " + String(int(vc_cuve/vh_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 distance ----------------------
float distanceM(){
digitalWrite(trigPin, LOW);
delayMicroseconds(3);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
float distance = pulseIn(echoPin, HIGH);
distance = (distance * 0.0343) / 2; // Calcul de la distance
return distance;
}
// -----------------------------------------------------------------------------------------------------------------------------------
// ---------------- 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;
float v_temp = (vh_cuve - v_val)*1.0 / vh_cuve * 100.0;
int v_val_pc = int(v_temp);
if(v_val_pc > 100){v_val_pc = 100;} // En cas d'erreur (lors du dev.)
#ifdef debug_sur_usb
Serial.println("vh_cuve : " + String(v_temp));
Serial.println("v_val : " + String(v_val));
Serial.println("Enregistrement mesure : " + 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) * (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(trigPin, OUTPUT); // Broche triger en sortie
pinMode(echoPin, INPUT); // Broche echo en entree
pinMode(le_plus, OUTPUT); // Le plus du S100
digitalWrite(le_plus, LOW);
IPAddress ip(192, 168, 1, 87); // 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.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;
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();
}
// -----------------------------------------------------------------------------------------------------------------------------------
// 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();
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
digitalWrite(le_plus, HIGH); // On alimente le capteur
delay(5);
float vmesure[10];
float resultat = 0;
for(int cpt = 0; cpt < 10; cpt++){
vmesure[cpt] = distanceM();
delay(10);
}
digitalWrite(le_plus, LOW); // On coupe l'alim du capteur
resultat = moyenneTableau(vmesure, 10);
mesure = int(resultat);
snprintf (str_mesure, 50, " : %d cm", mesure);
enr_nouvelle_valeur(mesure);
top_mesure = false; // On ne relancera pas la mesure avant une heure
}
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);
}