Besoin d'aide sur du code ( ESP32 ) pour mesure de niveau d'eau dans un récupérateur d'eau de pluie

Bonjour à tous et à toutes.

Par avance, désolé si le sujet a été abordé, ou si mes questions paraissent " bêtes" mais ça fait que 1 mois que je me suis lancé sur l'arduino/ le code et l'électronique également d'ailleurs.

Je viens plus de l'univers "domotique" comme JEEDOM/EEDOMUS, et c'est pour concevoir et fabriquer mes propres dispositifs et les faire communiquer avec l'univers domotique que je me suis lancer.

Mon projet est de fabriquer plusieurs dispositifs pour la mesure de cuve de récupération d'eau de pluie.
J'en ai installé plusieurs ( de même que d'autres proches familles/amis).

J'ai donc trouvé plusieurs ressources sur le web ( tutoriels ) décrivant ce type de projet. Donc je suis parti d'un tutoriel de base mais que je souhaite amélioré et adapter à un ESP32.

Le tutoriel est celui-ci :

J'utilise plusieurs fils dans la cuve et quand l'eau fait contact, la led correspondante au niveau s'allume.
ça c'est bon j'ai réussi à le mettre ne place.

Mais dès que je veux rajouter quelque chose ou modifier en profondeur la chose je bloque.
Voici mon code fonctionnel adapté selon le tutoriel ( désolé si mon copié-collé est pas bon, c'est mon 2eme message sur le forum:

// Entrées analogiques
const int Level0Pin = 34;
const int Level1Pin = 35;
const int Level2Pin = 32;
const int Level3Pin = 33;

// Sorties LEDs 
const int Level0LED = 19;
const int Level1LED = 18;
const int Level2LED = 5;
const int Level3LED = 4;


int ADC_Val=0; 
const int Seuil_0=400; // 1.9V (2.5V pour 512)

void setup() 
{   
      // Indicateurs LEDs
    pinMode(Level0LED,OUTPUT);
    pinMode(Level1LED,OUTPUT);
    pinMode(Level2LED,OUTPUT);
    pinMode(Level3LED,OUTPUT);
    
     
    //Liaison série 
    Serial.begin(115200);
   
}


void loop() 
{       
    digitalWrite (Buzzer, LOW);  //turn buzzer off  
    // Lecture et Affichage 34
    ADC_Val=analogRead(Level0Pin);
    Serial.print(ADC_Val);  Serial.print("\t");
    SetStateLevel(ADC_Val, Seuil_0, Level0LED);
    delay(100);
    
    // Lecture et Affichage 35
    ADC_Val=analogRead(Level1Pin);
    Serial.print(ADC_Val); Serial.print("\t");
    SetStateLevel(ADC_Val, Seuil_0, Level1LED);
    delay(100);
 
    // Lecture et Affichage 32
    ADC_Val=analogRead(Level2Pin);
    Serial.print(ADC_Val); Serial.print("\t");
    SetStateLevel(ADC_Val, Seuil_0, Level2LED);
    delay(100);
    
    // Lecture et Affichage 33
    ADC_Val=analogRead(Level3Pin);
    Serial.print(ADC_Val); Serial.print("\n"); 
    SetStateLevel(ADC_Val, Seuil_0, Level3LED);
    delay(100);

    
}

void SetStateLevel(int ADCVal, int Seuil, int LED_Pin)
{
  if(ADCVal > Seuil)
    {
      digitalWrite(LED_Pin, HIGH);
    }
    else
    {
      digitalWrite(LED_Pin, LOW);
    }

}

Mon idée étant:

De rendre la chose communicante :

  • Ajout d'une fonction Serveur Wifi ( avec possibilité AP , pour pas avoir a programmer dans le code le SSID /MDP du wifi , ça me permettra d'avoir un seul code pour tous les dispositifs que je pourrais faire pour donner à des amis / familles ). .... j'ai pas encore commencé à travailler la dessus.
  • Pouvoir récupérer les infos sur les systèmes domotiques ( JEEDOM/EEDOMUS via des requêtes HTTP ) Idem j'ai pas encore commencé la chose.

De mettre une "vanne motorisée " pour vider la cuve ( éviter que cela déborde par en haut ) si on est absent ( voir même l'utiliser comme arrosage pilotable à distance ou gouttes à gouttes ... ), j'ai pas commencé cette partie la non plus.

De mettre un buzzer qui avertirait par des Bips si la cuve est pleine ( en plus de la LED qui indique le niveau ):

Et la ça se complique ( et ça explique pourquoi j'ai pas avancé sur la partie" connectée ou la vanne pilotable à distance) car impossible d'avoir un buzzer qui ne bip pas dès le démarrage en continu:

Voici le code ( ici le buzzer devrait bipper quand une des LED s'allume, c'est plus un code pour faire un test que quelque chose ayant un usage ... car j'ai un autre soucis avec le code d'origine mais je l'expliquerai après).

// Entrées analogiques
const int Level0Pin = 34;
const int Level1Pin = 35;
const int Level2Pin = 32;
const int Level3Pin = 33;

// Sorties LEDs 
const int Level0LED = 19;
const int Level1LED = 18;
const int Level2LED = 5;
const int Level3LED = 4;

// Sortie Buzzer active
int Buzzer = 2; //for ESP32 Microcontroller

int ADC_Val=0; 
const int Seuil_0=400; // 1.9V (2.5V pour 512)

void setup() 
{   
      // Indicateurs LEDs et sorties buzzer 
    pinMode(Level0LED,OUTPUT);
    pinMode(Level1LED,OUTPUT);
    pinMode(Level2LED,OUTPUT);
    pinMode(Level3LED,OUTPUT);
    pinMode(Buzzer,OUTPUT);
     
    //Liaison série 
    Serial.begin(115200);
   
}


void loop() 
{       
    digitalWrite (Buzzer, LOW);  //turn buzzer off  
    // Lecture et Affichage 34
    ADC_Val=analogRead(Level0Pin);
    Serial.print(ADC_Val);  Serial.print("\t");
    SetStateLevel(ADC_Val, Seuil_0, Level0LED);
    delay(100);
    
    // Lecture et Affichage 35
    ADC_Val=analogRead(Level1Pin);
    Serial.print(ADC_Val); Serial.print("\t");
    SetStateLevel(ADC_Val, Seuil_0, Level1LED);
    delay(100);
 
    // Lecture et Affichage 32
    ADC_Val=analogRead(Level2Pin);
    Serial.print(ADC_Val); Serial.print("\t");
    SetStateLevel(ADC_Val, Seuil_0, Level2LED);
    delay(100);
    
    // Lecture et Affichage 33
    ADC_Val=analogRead(Level3Pin);
    Serial.print(ADC_Val); Serial.print("\n"); 
    SetStateLevel(ADC_Val, Seuil_0, Level3LED);
    delay(100);

    
}

void SetStateLevel(int ADCVal, int Seuil, int LED_Pin)
{
  if(ADCVal > Seuil)
    {
      digitalWrite(LED_Pin, HIGH);
      digitalWrite (Buzzer, HIGH); //turn buzzer on
    }
    else
    {
      digitalWrite(LED_Pin, LOW);
      digitalWrite (Buzzer, LOW);  //turn buzzer off
    }

}

Dans ce cas présent quand je mets l'ESP32 sous tension sans qu'aucun niveau d'eau ne soit détecter, j'ai droit à un BIP en continu.
Quand un niveau est détecté ( peu importe lequel j'ai alors un BIP qui n'est plus en continu mais selon la fréquence "delay" de 100ms définie dans le VOID LOOP.

J'ai essayé avec et sans :
digitalWrite (Buzzer, LOW); //turn buzzer off
dans le VOID LOOP ça change rien.

Comme l'idée est que le BIP ne soit là qu'au moment ou le récupérateur est plein ( donc quand la LED 3 s'allume), j'ai essayé cela aussi :

void SetStateLevel(int ADCVal, int Seuil, int LED_Pin)
{
  if(ADCVal > Seuil)
    {
      digitalWrite(LED_Pin, HIGH);
    }
    else
    {
      digitalWrite(LED_Pin, LOW);
    }
  if (Level3LED, HIGH)
    digitalWrite(Buzzer, HIGH); //turn buzzer on
  else
    digitalWrite(Buzzer, LOW);  //turn buzzer off
}

La encore le BIP est en continu dès le démarrage et quand la LED 3 ou " Level3LED " est allumé rien ne se passe j'ai toujours le BIP en continu.

Excusez mon ignorance quasi absolue dans le code/programmation Arduino mais dans ce code ( originel ) quelque chose m'échappe , dans la partie :

      digitalWrite(LED_Pin, HIGH);
    }
    else
    {
      digitalWrite(LED_Pin, LOW);

A aucun moment n'est défini le terme " LED_Pin " ( j'ai des " Level0LED" par exemple ) donc est un terme " générique" utilisable quelque soit les définitions des branchements / entrées/sorties?
Je sais pas si ma question est claire ? Pour moi ça me parait pas évident.

Si quelqu'un peut m'aider pour cette histoire de " BIP " / Buzzer ( je précise si ça a un intérêt, c'est un Buzzer actif en module ( avec sa propre résistance ), car la je vais me taper dans un mur ( j'ai pas que le problème du BUZZER , j'ai voulu aussi utiliser un écran OLED et la encore d'autres problèmes, mais je pense que mon post est déja bien long...).
Merci par avance.

Une solution (assez mauvaise, mais courante) consiste à ... arrêter le code pour détecter la portion de code défectueuse/ qui ne fait pas ce que vous voulez

la ligne


while(1 == 1) {}

arrête le code et vous pouvez tenter de savoir si, à cette étape, votre code a l'air encore fonctionnel
Exemple

void setup() 
{   
      // Indicateurs LEDs
    pinMode(Level0LED,OUTPUT);
    pinMode(Level1LED,OUTPUT);
    pinMode(Level2LED,OUTPUT);
    pinMode(Level3LED,OUTPUT);
    
     
    //Liaison série 
    Serial.begin(115200);
   while (1 == 1) {} // ajout à votre code
}

permet de verifier si setup ne fait pas sonner votre buzzer... (sinon, vous avez un gros problème, peut être matériel ... ou j'ai mal lu votre code)
En déplaçant (couper / coller) cette ligne, vous pouvez progresser sans être noyé sous des impressions de "débugging"

Dans ce genre de cas, je passe plutôt par une fonction d'attente active de plusieurs secondes avec un print en début de fonction, des lors, le problème est dans l'étape précédente à l'arrêt du bruit.

Je préfère introduire
d'abord un blocage total (ce que je propose, et je m'en tiens là)
puis
un dépannage par serial.print (avec arret)
puis
un depannage par serial.print ralenti (ce que vous proposez)

Même ralenti, le debug par Serial.print (ou équivalent) reste très stressant pour celui qui debuggue, moins que la relecture par celui qui a commis le code.

Oui et non, comme je parle de ce que je débogue, qui souvent est ce que j'ai écris, c'est un stress qui me va bien et le temps de pause étant évaluer en conséquence.
Mais effectivement, dans ces cas, il n'est pas question de regarder par la fenêtre les oiseaux qui volent :rofl:

Par contre pas besoin d'attendre la compilation, ni l'installation du binaire, ni les manipulation
pour la reproduction du cas, donc un grand gain de temps.
Après cela reste une pratique que je m'applique et qui donc par définition me convient.

Ce n'est pas le cas dans ce post;
un stress "qui vous va bien" ne va pas forcèment bien à quelqu'un qui débute.

La lecture soigneuse de SON code évite pas mal de sottises (un peu meilleure que des bricolages empiriques; évite d'énumèrer la chaîne de compilation et autres sources de distraction, assez horribles à infliger à un débutant
Voyez le profil de celui auquel vos donnez des "conseils" )

Edité: je répondais à

configuration où le Serial.print magique (des mauvais programmeurs: c'est aussi l'avis de quelques collègues) a très peu de chances d'être opérant. Si c'est avant le démarrage de la liaison série, le problème est ... un problème materiel... et on doit alors lire le reste du code...

Oui, c'était bien le sens de ma phrase.
Le temps étant ajustable, le stress est très relatif!!!
Je ne pense pas que même pour un débutant 30s entre chaque étape soit impossible à suivre, surtout que dans le cas présent, il s'agit d'attendre la fin du son et de lire ce qu'il se passe sur le moniteur série ou de couper la connexion pour figer l'affichage.
Donc pour moi cet arguments, n'a pas vraiment lieu d'être.

Si il n'est pas opérant, il sera toujours temps d'être plus stricte, en moyenne il sera toujours meilleurs d'opérer dans ce sens.
Il n'y a pas de Serial.print magique, c'est un outil comme un autre, il est évident que l'utilisation de celui-ci, vient si aucun autre outil plus pratique ne peut être utilisé.

C'est une règle qui doit toujours s'appliquer, mais dire ça à un débutant, est un peu comme "pisser" dans un violon.
Par définition un débutant, n'a pas l'expérience permettant de corriger facilement son code, uniquement par la lecture.

Il faut que
a) OP soit sûr que ce n'est pas une horreur materielle.....
b) prenne cette habitude (vu son profil et son historique, c'est possible sans souiller de contrebasses)...
c) ne soit pas trop perturbé par des ergotages sans fin visant à suggérer de mauvaises pratiques...

C'est ton point de vue, personnellement pour moi la mauvaise pratique consiste, à mettre des blocages au hasard en espérant à la longue trouver le problème.
Même toi tu considère ta proposition comme mauvaise et tu me parle d'ergotage :thinking:
Bon je préfère clore ce sujet.

Mettre un blocage au début -n'est pas par hasard- pour verifier le matériel alors que la liaison serie n'est pas initialisée n'est pas le fruit du hasard
J'ai qualifié cette methode par points d'arrêt de mauvaise-à destination du posteur initial - , car en prendre l'habitude débouche manifestement sur de mauvais programmeurs... et il est honnête vis à vis de OP qu'il en soit conscient...

C'est qui OP :thinking:

Original poster.

@hbachetti merci :slight_smile: , j'ai cherché un truc du genre, mais en français :exploding_head:

Vous voyez comment on peut noyer quelqu'un, qui cherche de l'aide, sous des ergotages -et, en passant, pousser une méthode fort peu utilisée car dépassée devant des relectures soigneuses -...
Et on commence toujours par revérifier le matériel...

Dans ce cas arrête d'ergoter en proposant des méthodes dépassé et montre à notre ami @misterden ta preuve de programme!

J'ai l'impression que vous ne savez pas très bien ce que sont les fonctions C, et la portée des variables et j'espère que je ne vais pas trop vous embrouiller (un bon livre de C -++- le ferait mieux)

Il y a 3 variables / paramètres d'appel ADCVal, Seuil, LED_Pin; lors de l'appel de la fonction, ces trois variables sont copiées et les copies ne sont connues/visibles que de la fonction.
Donc, le bout de code

SetStateLevel(444, 300, 22);

aura l'effet suivant
ADCVal recoit la variable 444, Seuil vaudra 300, LED_Pin vaudra 22 et le code de la fonction sera alors prçet à s'éxécuter, ces variables seront connues; ensuite, une fois la fonction parcourue, elles seront oubliées (et la mémoire qu'elles utilisent pourra être réutilisée par d'autres fonctions) ; voyez les comme une espèce de brouillon; (et ce peut être déroutant) .

C'est différent des variables globales (j'ai vu Buzzer) qui sont connues de tout le monde (et tout le monde, un troupeau de fonctions, peut faire des sottises avec ... ou , en contournant la phase de copie, faire bien et très vite les choses; en plus, écrire des fonctions avec beaucoup d'arguments est fastidieux, et peut mener à des erreurs, même si les variables globales sont mal vues -difficiles à dépanner- (elles sont encore pires) )

Mon intervention va être totalement hors sujet:
Récupérateur d'eau de pluie non protégé par une moustiquaire = élevage industriel de moustiques tigres.
Un moustique tigre ne s'éloigne pas à plus de 100m de son lieu de naissance. Si vous avez des tigres c'est vous ou vos voisins qui les font naître.

Fin du hors sujet

Merci pour votre conseil même si c'est HS ), effectivement on est plein de tigre par ici ( sauf dans la piscine ou ils meurent grace au chlore.
Je pensais effectivement mettre déja un filtre sur la gouttière ou sur son arrivée dans le récupérateur pour les impuretés ( j'ai des mousses sur les tuiles et faut voir ce qu'il tombe), mais je prends votre conseil avec grand plaisir on va faire ce qu'il faut ...surtout que je supporte pas bien les piqures de tigre.
Autre conseil toujours avoir une petite bombe de " biséptine" en cas de piqure s'en vaporisé dessus dans les 10 min max, c'est le seul truc qui va calmer la piqure .
Fin du HS.

Des poissons dans la cuve, permettrais de ne pas avoir de larve, après je ne sais pas ce que ça vaut :slight_smile:

Bonne idée. Mets des truites ou des saumons, tu pourras les manger :rofl: