Détecteur de fuite d'eau

Bonjour à tous,

Je suis nouveau dans le monde de l'Arduino, et je n'arrive pas à faire fonctionner mon programme. Je pense que la solution est simple.
Pour le moment, je n'ai que l'affichage du débit qui fonctionne, mes pas la coupure du relais.

But du programme :
Je voudrais que lorsque mon débitmètre détecte un débit pendant 3 secondes, il coupe le relais pour fermer une électrovanne et la maintient fermée.

liste du matériel
un débitmètre (USN-HS43TA)
un relais (JQC-3FF-S-Z)
un écran 16x2
un Arduino UNO

Programme

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);  // Initialise l'écran LCD avec l'adresse I2C et les dimensions
volatile int flow_frequency = 0;     // Compteur des impulsions du capteur de débit
float vol = 0.0;                      // Volume total en litres
unsigned long currentTime, cloopTime;  // Variables pour le suivi du temps
unsigned long zeroFlowTime = 0;        // Temps lorsque le débit est devenu nul
unsigned long relayOffTime = 0;        // Temps d'arrêt du relais
int relayPin = 8; // Broche de contrôle du relais
bool isLeakDetected = false; // Indicateur de détection de fuite

void flow() {
  flow_frequency++;  // Incrémente le compteur d'impulsions à chaque interruption du capteur
}

void setup() {
  Serial.begin(9600);  // Initialise la communication série à 9600 bauds
  lcd.init();  // Initialise l'écran LCD
  lcd.backlight(); // Allume le rétroéclairage de l'écran (si pris en charge)
  lcd.clear();  // Efface l'écran LCD
  lcd.setCursor(0, 0);  // Positionne le curseur en haut à gauche de l'écran
  lcd.print("Fuite d'eau"); // Affiche le texte "Fuite d'eau"
  lcd.setCursor(0, 1);  // Positionne le curseur en bas à gauche de l'écran
  lcd.print("V1"); // Affiche la version "V1"
  currentTime = millis(); // Initialise le temps actuel
  cloopTime = currentTime; // Initialise le temps de la boucle
  pinMode(2, INPUT_PULLUP); // Configure la broche du capteur de débit en entrée avec résistance de tirage interne
  attachInterrupt(digitalPinToInterrupt(2), flow, RISING); // Associe la fonction d'interruption "flow" à la montée du signal
  pinMode(relayPin, OUTPUT); // Configure la broche du relais en sortie
  digitalWrite(relayPin, HIGH); // Désactive initialement le relais
}

void loop() {
  currentTime = millis(); // Obtient le temps actuel
  if (currentTime >= (cloopTime + 1000)) // Toutes les secondes, effectue les opérations suivantes
  {
    cloopTime = currentTime; // Met à jour le temps de la boucle
    if (flow_frequency != 0) // Si des impulsions ont été détectées par le capteur de débit
    {
      zeroFlowTime = 0; // Réinitialise le temps lorsque le débit est nul
      float l_seconde = (flow_frequency / 7.5); // Calcule le débit en litres par seconde (L/s)
      lcd.clear(); // Efface l'écran LCD
      lcd.setCursor(0, 0); // Positionne le curseur en haut à gauche
      lcd.print("Debit: ");
      lcd.print(l_seconde, 2); // Affiche le débit en litres par seconde avec 2 décimales
      lcd.print(" L/S"); // Affiche l'unité
      lcd.setCursor(0, 1); // Positionne le curseur en bas à gauche
      vol += (l_seconde / 3600); // Met à jour le volume total en litres (L)
      lcd.print("Vol:");
      lcd.print(vol, 2); // Affiche le volume total avec 2 décimales
      lcd.print(" L"); // Affiche l'unité
      flow_frequency = 0; // Réinitialise le compteur d'impulsions du capteur de débit
      Serial.print(l_seconde, 2); // Affiche le débit en litres par seconde avec 2 décimales sur la console série
      Serial.println(" L/Sec"); // Affiche l'unité

      if (l_seconde > 1.0) {
        relayOffTime = currentTime; // Enregistre le temps lorsque le débit est supérieur à 1 L/s
      } else if (l_seconde == 0 && currentTime - relayOffTime >= 3000) {
        // Désactive le relais si le débit est supérieur à 1 L/s pendant plus de 3 secondes
        digitalWrite(relayPin, HIGH); // Désactive le relais
        isLeakDetected = false; // Réinitialise l'indicateur de détection de fuite
        Serial.println("Désactivation du relais"); // Affiche un message sur la console série
      }
      else if (l_seconde > 1.0) {
        // Active l'indicateur de détection de fuite si le débit est supérieur à 1 L/s
        isLeakDetected = true;
      }
    } else {
      if (zeroFlowTime == 0) {
        zeroFlowTime = currentTime; // Enregistre le temps lorsque le débit est devenu nul
      }
      if (currentTime - zeroFlowTime >= 1000) {
        // Attend 1 seconde avant de réinitialiser l'affichage lorsque le débit est nul
        Serial.println("Debit = 0 "); // Affiche un message sur la console série
        lcd.clear(); // Efface l'écran LCD
        lcd.setCursor(0, 0); // Positionne le curseur en haut à gauche
        lcd.print("Debit: 0 L/S");
        lcd.setCursor(0, 1); // Positionne le curseur en bas à gauche
        lcd.print("Vol:");
        lcd.print(vol, 2); // Affiche le volume total avec 2 décimales
        lcd.print(" L"); // Affiche l'unité
        if (isLeakDetected) {
          // Si une fuite est détectée, affiche "Fuite" sur l'écran
          lcd.setCursor(0, 0);
          lcd.print("Fuite");
        }
      }
    }
  }
}

Merci d'avance pour votre aide

Je déplace dans le forum principal, ici c'est pour les tutos...

1 Like

Tu fais ce test dans un bloc qui commence par

Or pour avoir l_seconde nul, il faut que flow_frequency soit nul, ce qui n'est pas possible dans ce bloc.

De plus, ceci est bizarre (relis bien) :

Penses-tu que le code suivant fonctionnera ?

// Nouveau bloc
      if (l_seconde > 0) {
        if (flow_frequency != 0) {
          if (zeroFlowTime == 0) {
            zeroFlowTime = currentTime; // Enregistre le temps lorsque le débit devient nul
          }
          if (currentTime - zeroFlowTime >= 3000) {
            // Si le débit est maintenu pendant 3 secondes, coupez le relais
            digitalWrite(relayPin, LOW); // Active le relais (cela dépend de la configuration du relais)
            Serial.println("Activation du relais"); // Affiche un message sur la console série
          }
        } else {
          zeroFlowTime = 0; // Réinitialise le temps lorsque le débit redevient nul
        }
      }
      // Fin du nouveau bloc

Yaka tester... :yum:

Ça ne fonctionne pas, malheureusement. J'ai modifié mon approche, mais le relais se coupe des le lancement du débitmètre. Avez-vous des idées pour résoudre ce problème ?"

const int flowMeterPin = 2;  // Broche du débitmètre (interruption 0)
const int relayPin = 8;      // Broche du relais

volatile int flowPulses = 0; // Compteur des impulsions
bool relayState = false;     // État du relais
unsigned long lastFlowTime = 0;  // Temps de la dernière impulsion

void setup() {
  Serial.begin(9600);
  pinMode(flowMeterPin, INPUT_PULLUP);
  pinMode(relayPin, OUTPUT);
  digitalWrite(relayPin, HIGH); // Désactiver le relais au démarrage
  attachInterrupt(digitalPinToInterrupt(flowMeterPin), flowISR, RISING);
}

void loop() {
  unsigned long currentTime = millis();
  
   // Si le débit est supérieur à 0 impulsions et le temps est supérieur à 3 secondes, activer le relais
  if (!relayState && flowPulses > 0 && (currentTime - lastFlowTime) >= 3000) {
    digitalWrite(relayPin, LOW); // Activer le relais
    relayState = true;
    Serial.println("Relais activé");
  }
}

void flowISR() {
  flowPulses++;
}

c'est typiquement une définition de programme qui se prête bien à la programmation par machine à états (cf mon tuto éventuellement)

3s ça semble court, pourquoi ne pas fermer la vanne en permanence tout simplement ?

Non pour le projet final je veux qu'il coupe sur 20 minutes et le réarmement éventuellement avec un bouton poussoir avec un appuis long

oui une bonne petite machine à état fera le job

Pour simplifier votre gestion des boutons, éventuellement utilisez la bibliothèque Button dans easyRun de @bricoleau ou OneButton de Matthias Hertel ou encore Toggle de @dlloyd.

top le tuto
Je ne vois pas comment on remplace la commande du bouton par une information produite avec le débitmètre. :confused:

les états pourraient ressembler à cela:

au début on est dans l'état REPOS

REPOS: si on détecte un débit, on note l'heure (millis) et on passe en état ACTIF

ACTIF: si le débit s'arrête on revient au REPOS mais si les 3 secondes sont dépassées alors on ferme la vanne et on passe à l'état STOP.

STOP: si on détecte l'appui sur un bouton alors on rouvre la vanne et on revient à l'état REPOS

ensuite se pose la question de savoir comment on sait s'il y a un débit ou pas

pour cela il faut une petite fonction qui regarde si sur la dernière seconde (par exemple) le compteur a changé. c'est un sous système qui peut être aussi une machine à états.

et si vous utilisez une bibliothèque pour le bouton, c'est implémenté aussi sous forme de machine à états pour gérer les rebonds, le simple appui ou double click etc...

bref, on peut mettre des machines à états partout :slight_smile:

je crois enfin avoir fini mon projet
ci joint mon code qui pour moi fonctionne


#include <Wire.h>  // Bibliothèque pour la communication I2C
#include <LiquidCrystal_I2C.h>  // Bibliothèque pour le contrôle de l'écran LCD en mode I2C

LiquidCrystal_I2C lcd(0x27, 16, 2); // Adresse I2C de l'écran LCD 16x2

const int brocheDebit = 2;           // Broche de la sonde de débit d'eau
const int brocheElectrovanne = 3;    // Broche pour contrôler l'électrovanne
const int brocheBouton = 4;          // Broche du bouton-poussoir
const int brocheLedRGB = 5;          // Broche de la LED RVB
unsigned int compteImpulsions = 0;
float debitInstantane = 0.0;
float totalMetresCubes = 0.0; // Changement d'unité de litres à mètres cubes
unsigned long tempsPrecedent = 0;
unsigned long tempsDebutDebit = 0;
unsigned long tempsDebutEtat = 0;
const long intervalle = 500;  // Intervalle d'échantillonnage en millisecondes
const float seuilDebitCoupe = 0.1;
const unsigned long delaiFermetureElectrovanne = 3000;  // Délai de fermeture de l'électrovanne en millisecondes

enum Etat { REPOS, ACTIF, STOP };
Etat etat = REPOS;

void setup() {
  lcd.begin(16, 2);  // Initialisation de l'écran LCD 16x2
  lcd.setCursor(2, 0);
  lcd.print("Detecteur de");
  lcd.setCursor(3, 1);
  lcd.print("fuite V.1");
  delay(2000);  // Attendre 2 secondes après l'allumage

  lcd.clear();  // Effacer l'écran après le message de démarrage
  lcd.print("Debit: 0.0 m3/h");
  lcd.setCursor(0, 1);
  lcd.print("Total: 0.0 m3");

  pinMode(brocheDebit, INPUT);
  pinMode(brocheElectrovanne, OUTPUT);
  pinMode(brocheBouton, INPUT_PULLUP);
  pinMode(brocheLedRGB, OUTPUT);

  digitalWrite(brocheElectrovanne, HIGH);  // Initialement, l'électrovanne est ouverte
}

void loop() {
  unsigned long tempsActuel = millis();  // Obtient le temps actuel en millisecondes

  switch (etat) {
    case REPOS:
      couleurRGB(0, 0, 255);  // Affiche une couleur bleue en mode repos
      if (debitInstantane > seuilDebitCoupe) {
        tempsDebutDebit = tempsActuel;
        etat = ACTIF;
      }
      break;

    case ACTIF:
      clignoterRGB(0, 0, 255);  // Clignote en bleu en mode actif
      if (debitInstantane > seuilDebitCoupe) {
        if (tempsActuel - tempsDebutDebit >= delaiFermetureElectrovanne) {
          digitalWrite(brocheElectrovanne, LOW);
          etat = STOP;
          tempsDebutEtat = tempsActuel;
        }
      } else {
        etat = REPOS;
      }
      break;

    case STOP:
      clignoterRGB(255, 0, 0);  // Clignote en rouge en mode stop
      lcd.setCursor(0, 0);
      lcd.print(" ! ATTENTION !  ");  // Affiche un avertissement de fuite
      lcd.setCursor(0, 1);
      lcd.print(" FUITE EN COUR ");  // Indique qu'il y a une fuite
      // Nouvelle condition pour la réinitialisation avec maintien de 2 secondes
      if (digitalRead(brocheBouton) == LOW) {
        if (tempsActuel - tempsDebutEtat >= 2000) {
          digitalWrite(brocheElectrovanne, HIGH);
          etat = REPOS;
          lcd.setCursor(0, 0);
          lcd.print("                 ");  // Efface le texte "Fuite" lors du retour à l'état REPOS
          lcd.setCursor(0, 1);
          lcd.print("                 ");  // Efface le texte "Fuite" lors du retour à l'état REPOS
        }
      } else {
        tempsDebutEtat = tempsActuel;
      }
      break;
  }

  if (tempsActuel - tempsPrecedent >= intervalle) {
    detachInterrupt(digitalPinToInterrupt(brocheDebit));

    debitInstantane = compteImpulsions / 7.5;  // Conversion du nombre d'impulsions en débit instantané en mètres cubes par heure
    totalMetresCubes += (debitInstantane / 3600.0);  // Ajout du débit instantané au total en mètres cubes

    lcd.clear();
    lcd.print("Debit: ");
    lcd.print(debitInstantane, 1);
    lcd.print(" m3/h");

    lcd.setCursor(0, 1);
    lcd.print("Total: ");
    lcd.print(totalMetresCubes, 1);
    lcd.print(" m3");

    compteImpulsions = 0;
    tempsPrecedent = tempsActuel;

    attachInterrupt(digitalPinToInterrupt(brocheDebit), compteurImpulsions, FALLING);
  }
}

void compteurImpulsions() {
  compteImpulsions++;
}

void couleurRGB(int rouge, int vert, int bleu) {
  analogWrite(brocheLedRGB, rouge);
  analogWrite(brocheLedRGB + 1, vert);
  analogWrite(brocheLedRGB + 2, bleu);
}

void clignoterRGB(int rouge, int vert, int bleu) {
  unsigned long tempsActuel = millis();
  static unsigned long tempsDernierChangement = 0;
  static bool etatRGB = LOW;

  if (tempsActuel - tempsDernierChangement >= 500) {
    etatRGB = !etatRGB;
    couleurRGB(rouge * etatRGB, vert * etatRGB, bleu * etatRGB);
    tempsDernierChangement = tempsActuel;
  }
}

Bonjour jeje95150
Je me suis permis d'emprunter ton code pour l'adapter à mon besoin, à savoir : la détection de fuite sur plusieurs zones d'arrosage avec des débits différents sur chaque zone tout en ayant qu'une vanne principale motorisée et des simples électrovannes pour chaque zone ( pour l'instant dans le code , j'ai défini 6 zones )
J'ai provisoirement activé que deux zones, et déjà j'ai l'impression d'avoir un code trop long
Avons-nous la possibilité d'écrire quelque chose de plus condensé ?
Merci par avance de vos lumières

 //detection de fuite avec bouton de réactivation pour plusieurs Zones avec plusieurs seuils de débit maxi

#include <Wire.h>  // Bibliothèque pour la communication I2C
#include <LiquidCrystal_I2C.h>  // Bibliothèque pour le contrôle de l'écran LCD en mode I2C

LiquidCrystal_I2C lcd(0x27, 16, 2); // Adresse I2C de l'écran LCD 16x2 

const int brocheDebit = 2;           // Broche de la sonde de débit d'eau
const int brocheElectrovanne = 3;    // Broche pour contrôler l'électrovanne
const int brocheBouton = 4;          // Broche du bouton-poussoir pour remise à zéro
const int brocheZone1 = 5;          // Broche d'information de l'arrosage de la Zone 1
const int brocheZone2 = 6;          // Broche d'information de l'arrosage de la Zone 2
const int brocheZone3 = 7;          // Broche d'information de l'arrosage de la Zone 3
const int brocheZone4 = 8;          // Broche d'information de l'arrosage de la Zone 4
const int brocheZone5 = 9;          // Broche d'information de l'arrosage de la Zone 5
const int brocheZone6 = 10;         // Broche d'information de l'arrosage de la Zone 6
unsigned int compteImpulsions = 0;
float debitInstantane = 0.0;
float totalMetresCubes = 0.0; // Changement d'unité de litres à mètres cubes
unsigned long tempsPrecedent = 0;
unsigned long tempsDebutDebit = 0;
unsigned long tempsDebutEtat = 0;
const long intervalle = 500;  // Intervalle d'échantillonnage en millisecondes
const float seuilDebitCoupeZone1 = 1.1; //Débit maxi pour la zone 1
const float seuilDebitCoupeZone2 = 2.1; //Débit maxi pour la zone 2
const float seuilDebitCoupeZone3 = 5.1; //Débit maxi pour la zone 3
const float seuilDebitCoupeZone4 = 4.1; //Débit maxi pour la zone 4
const float seuilDebitCoupeZone5 = 3.1; //Débit maxi pour la zone 5
const float seuilDebitCoupeZone6 = 6.1; //Débit maxi pour la zone 6
const unsigned long delaiFermetureElectrovanne = 1000;  // Délai de fermeture de l'électrovanne en millisecondes

enum Etat { REPOS, ACTIF, STOP };
Etat etat = REPOS;



void setup() {
  lcd.begin(16, 2);  // Initialisation de l'écran LCD 16x2
  lcd.print("Debit: 0.0 m3/h");
  lcd.setCursor(0, 1);
  lcd.print("Total: 0.0 m3");

  pinMode(brocheDebit, INPUT);
  pinMode(brocheElectrovanne, OUTPUT);
  pinMode(brocheBouton, INPUT_PULLUP);
  pinMode(brocheZone1, INPUT);
  pinMode(brocheZone2, INPUT);
  pinMode(brocheZone3, INPUT);
  pinMode(brocheZone4, INPUT);
  pinMode(brocheZone5, INPUT);
  pinMode(brocheZone6, INPUT);


 
}

void loop() {
  unsigned long tempsActuel = millis();  // Obtient le temps actuel en millisecondes


     if(digitalRead(brocheZone1) == HIGH){   //Lecture de l'information de l'arrosage de la Zone 1
      
      
  switch (etat) {
    case REPOS:
    digitalWrite(brocheElectrovanne, HIGH);
      if (debitInstantane > seuilDebitCoupeZone1) {
        tempsDebutDebit = tempsActuel;
        etat = ACTIF;
      }
      break;

    case ACTIF:
      if (debitInstantane > seuilDebitCoupeZone1) {
        if (tempsActuel - tempsDebutDebit >= delaiFermetureElectrovanne) {
          digitalWrite(brocheElectrovanne, LOW);
          etat = STOP;
          tempsDebutEtat = tempsActuel;
        }
      } else {
        etat = REPOS;
      }
      break;

    case STOP:
      //lcd.clear();  // Effacer l'écran après le message de démarrage
      lcd.setCursor(0, 0);
      lcd.print("Fuite Zone1 ");  // Affiche un avertissement de fuite
      // Nouvelle condition pour la réinitialisation avec maintien de 2 secondes
      if (digitalRead(brocheBouton) == LOW) {
        if (tempsActuel - tempsDebutEtat >= 2000) {
          digitalWrite(brocheElectrovanne, HIGH);
          etat = REPOS;
          lcd.setCursor(0, 0);
          lcd.print("                 ");  // Efface le texte "Fuite" lors du retour à l'état REPOS
          lcd.setCursor(0, 1);
          lcd.print("                 ");  // Efface le texte "Fuite" lors du retour à l'état REPOS
        }
      } else {
        tempsDebutEtat = tempsActuel;
      }
      break;
  }
  }
     if(digitalRead(brocheZone2) == HIGH){   //Lecture de l'information de l'arrosage de la Zone 2
      
      
  switch (etat) {
    case REPOS:
    digitalWrite(brocheElectrovanne, HIGH);
      if (debitInstantane > seuilDebitCoupeZone2) {
        tempsDebutDebit = tempsActuel;
        etat = ACTIF;
      }
      break;

    case ACTIF:
      if (debitInstantane > seuilDebitCoupeZone2) {
        if (tempsActuel - tempsDebutDebit >= delaiFermetureElectrovanne) {
          digitalWrite(brocheElectrovanne, LOW);
          etat = STOP;
          tempsDebutEtat = tempsActuel;
        }
      } else {
        etat = REPOS;
      }
      break;

    case STOP:
      //lcd.clear();  // Effacer l'écran après le message de démarrage
      lcd.setCursor(0, 0);
      lcd.print("Fuite Zone2 ");  // Affiche un avertissement de fuite
      // Nouvelle condition pour la réinitialisation avec maintien de 2 secondes
      if (digitalRead(brocheBouton) == LOW) {
        if (tempsActuel - tempsDebutEtat >= 2000) {
          digitalWrite(brocheElectrovanne, HIGH);
          etat = REPOS;
          lcd.setCursor(0, 0);
          lcd.print("                 ");  // Efface le texte "Fuite" lors du retour à l'état REPOS
          lcd.setCursor(0, 1);
          lcd.print("                 ");  // Efface le texte "Fuite" lors du retour à l'état REPOS
        }
      } else {
        tempsDebutEtat = tempsActuel;
      }
      break;

  }
     
  }

  if (tempsActuel - tempsPrecedent >= intervalle) {
    detachInterrupt(digitalPinToInterrupt(brocheDebit));

    debitInstantane = compteImpulsions / 7.5;  // Conversion du nombre d'impulsions en débit instantané en mètres cubes par heure
    totalMetresCubes += (debitInstantane / 3600.0);  // Ajout du débit instantané au total en mètres cubes

    lcd.clear();
    lcd.print("Debit: ");
    lcd.print(debitInstantane, 1);
    lcd.print(" m3/h");

    lcd.setCursor(0, 1);
    lcd.print("Total: ");
    lcd.print(totalMetresCubes, 1);
    lcd.print(" m3");

    compteImpulsions = 0;
    tempsPrecedent = tempsActuel;

    attachInterrupt(digitalPinToInterrupt(brocheDebit), compteurImpulsions, FALLING);
  }
}

void compteurImpulsions() {
  compteImpulsions++;
}


Ce n'est pas une impression. Quand on relit son code et que l'on voit des zones similaires on a loupé quelque chose. En informatique DRY "don't repeat yourself". Par facilité on fait un copier-coller en changeant les variables au lieu de créer un nouveau module. En C une fonction qui prendra en paramètre le numéro de sonde doit effectuer le traitement. C'est un peu long pour entrer dans le détail cela fait parti des bases de la programmation en C.

quand on commence à numéroter des variables et qu'elles sont liées c'est qu'il est temps de passer à des tableaux et des structures / classes

Bonjour,
Merci pour vos réponses,
2 points à préciser :
1° J'avais ouvert un autre post " contrôler débit eau " la semaine dernière pour avoir votre aide sur un premier code, puis en fouillant le site, j'ai découvert celui de @Jeje95150 qui me paraissait mieux correspondre à mon besoin.
Pour éviter de faire doublon, je continue à répondre sur mon premier post
2° Je n'ai suivi aucune formation sur la programmation (cela se voit ), j'essaie de comprendre les codes, et grâce à vos réponses, je progresse doucement (je me forme sur le tas...)
Merci encore pour toute votre aide précieuse

Bonjour bobardui1 je ne comprends pas l'usage final de ton projets peut tu me l'expliquer ?

Bonjour Jeje95150,
actuellement, j'ai plusieurs programmateurs d'arrosage qui sont répartis à différents lieux dans mon terrain. Tous fonctionnent très bien, sauf que quand un tuyau se démanche ou éclate, je n'ai aucun moyen d'arrêter immédiatement l'arrivée de l'eau avant l'électrovanne pilotée par le programmateur. Et ce de façon définitive avant de réarmer manuellement l'ouverture de la vanne principale .
A noter que la fermeture de la vanne principale ne doit concerné que la zone d'arrosage qui a un tuyau défectueux. C'est pour cela que le pilotage de ce détecteur de fuite est assujetti à la commande d'un des programmateurs d'arrosage
Est-ce cela te paraît plus clair
A noter que tu peux suivre mon autre post qui a bien avancé par l'aide de Kamill pour mon problème de "structure"
Je te joins aussi le code d'un programmateur 6 zones qui a l'avantage d'inverser la polarité des sondes d'humidité toutes les 14 minutes

#include <LiquidCrystal.h>
#include <Wire.h>
#include <RTClib.h>
#include <EEPROM.h>
#define MAGIC 10
RTC_DS3231 RTC ;
//Carte UNO =>SDA (A4) & SCL(A5)...Carte Mega 2560 =>SDA (20) & SCL(21)
//DateTime now = RTC.now();
// Init Shield LCD
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
//Variables mise à jour Horloge
byte TabMaH[6] = {27, 2, 23, 21, 00, 0};
byte MaH;
int BpH;
byte DrapH, SelH, ColH, MaxH, MinH, CurH, CurligH, Val;

// Variables mise à jour de la plage horaire
int Bp, MaJ, Flag, Vo, Lig, Sel, Col, Max, Cur, CurLig;
// Table Evénerments chaque ligne correspond à une voie. Sur la ligne, on trouve H départ, M Départ, H Arrêt, M Arrêt..
byte TabEvt [6][4] =
{
  {20, 8, 21, 11},
  {21, 6, 22, 42},
  {22, 12, 22, 43},
  {21, 23, 21, 44},
  {21, 12, 22, 40},
  {22, 50, 23, 05},
};
byte PinSorties[6] = {57, 56, 11, 12, 2, 3}; // dans l'ordre de fonctionnement
// Carte UNO => byte PinSorties[6] = {17, 16, 11, 12, 2, 3}; // dans l'ordre de fonctionnement

// initialisation des PinSorties pour les relais d'inversion des sondes
byte PinRelais[6] = {26, 28, 24, 30, 22, 32}; // dans l'ordre de fonctionnement


// Les fonctions
void lecturePlages () {
  Serial.println("lecture plages EEPROM");
  // D'abord lecture du nombre magique
  int address = 0;
  byte magic;
  EEPROM.get(address, magic);
  Serial.print("Nombre magique : "); Serial.println(magic);
  if (magic != MAGIC) {  // J'ai choisi 10
    Serial.println("Pas bon, on sauve...");
    // Le nombre n'y est pas : on sauvegarde les données du TabEvt
    sauvePlages();
  } else {
    Serial.println("Bon, on lit EEPROM");
    // Le nombre y est : on lit les données EEPROM et on les met dans TabEvt
    ++address;
    for (int i = 0; i < 6; i++) {
      for (int j = 0; j < 4; j++) {
        byte nombre;
        EEPROM.get(address, nombre);
        Serial.print ("Lu nombre "); Serial.print(nombre);
        Serial.print(" @ adresse "); Serial.println(address);
        TabEvt[i][j] = nombre;
        Serial.print (" et sauvé dans TabEvt indices "); Serial.print(i);
        Serial.print (" "); Serial.println(j);
        ++address;
      }
    }
  }
}

void sauvePlages() {
  Serial.println("sauvegarde plages EEPROM");
  // D'abord écriture du nombre magique
  int address = 0;
  Serial.println("Sauvegarde nombre magique");
  EEPROM.update(address, MAGIC);
  // Ensuite écriture du tableau
  ++address;
  for (int i = 0; i < 6; i++) {
    for (int j = 0; j < 4; j++) {
      byte nombre = TabEvt[i][j];
      EEPROM.update(address, nombre);
      // if(EEPROM.read(address) != nombre) EEPROM.write(address, nombre);
      Serial.print(i); Serial.print(" "); Serial.print(j); Serial.print(" : sauve nombre ");
      Serial.print(nombre); Serial.print(" @ adresse "); Serial.println(address);
      ++address;
    }
  }
}

void setup() {
  Wire.begin();
  RTC.begin();
  // if (RTC.lostPower()) {
  Serial.println("RTC lost power, let's set the time!");
  // Lorsque le temps doit être réglé sur un nouvel appareil, ou après une perte de puissance,
  //la ligne suivante définit le CCF à la date et à l’heure à laquelle ce croquis a été compilé.
  // RTC.adjust(DateTime(F(__DATE__), F(__TIME__)));
  // }
  lcd.begin(16, 2);
  // RTC.adjust(DateTime(2021,01,18,21,01,01));
  // Initialisation A2,A3,2,3,11,12 en sorties
  byte i; for ( i = 0; i < 6; i++ ) {
    pinMode(PinSorties[i], OUTPUT);
    digitalWrite (PinSorties[i], HIGH);
    pinMode(PinRelais[i], OUTPUT);
    digitalWrite (PinRelais[i], HIGH);
  }
  Serial.begin(9600);



  // Saisie MaJ Date,Heure ?
  lcd.setCursor(0, 0); lcd.print("Maj Date,Heure ?");
  lcd.setCursor(0, 1); lcd.print("Sel: O Right: N");
  MaH = 1;
  // Mise à jour Date Heure
  while (MaH == 1) {
    BpH = analogRead (0); delay(100); lcd.setCursor(0, 0);
    Serial.println(BpH);

    //Sortie  mise à jour
    if (BpH < 50) {
      Serial.println("Mise à jour heure date");
      if (DrapH == 2)
      {
        RTC.adjust(DateTime(TabMaH[0], TabMaH[1], TabMaH[2], TabMaH[3], TabMaH[4], TabMaH[5]));
      }
      lcd.clear(); lcd.setCursor(0, 0); lcd.print("Fin saisie"); delay(2000); lcd.clear();
      MaH = 0;
    }// Fin mise à jour

    // Incrémentation
    else if (BpH < 200) {
      if (DrapH == 2 && TabMaH[ColH] < MaxH) {
        TabMaH[ColH] ++;
        lcd.setCursor (CurH, CurligH);
        if (TabMaH[ColH] < 10) lcd.print (0);
        lcd.print(TabMaH[ColH]);
      }
      delay(200);
    }// Fin incrémentation

    // Décrémentation
    else if (BpH < 380) {
      if (DrapH == 2 && TabMaH[ColH] > MinH) {
        TabMaH[ColH] --;
        lcd.setCursor (CurH, CurligH);
        if (TabMaH[ColH] < 10) lcd.print (0);
        lcd.print(TabMaH[ColH]);
      }
      delay(200);
    }// Fin décrémentation

    //Choix valeur à mettre à jour
    else if (BpH < 600) {
      if (DrapH > 0) DrapH = 2;
      if (SelH < 6) {
        SelH++ ;
        delay(200);
        ColH = SelH - 1;
      }
      if (SelH == 6) SelH =  0;

      if (ColH == 0) {
        lcd.setCursor(7, 0);
        lcd.print ("**");
        MaxH = 50;
        MinH = 10;
        CurH = 7;
        CurligH = 0;
      } else {
        lcd.setCursor(7, 0);
        if (TabMaH[0] < 10) lcd.print (0);
        lcd.print (TabMaH[0]);
      }

      if (ColH == 1) {
        lcd.setCursor(10, 0);
        lcd.print ("**");
        MaxH = 12;
        MinH = 1;
        CurH = 10;
        CurligH = 0;
      } else {
        lcd.setCursor(10, 0);
        if (TabMaH[1] < 10) lcd.print (0);
        lcd.print (TabMaH[1]);
      }

      if (ColH == 2) {
        lcd.setCursor(13, 0);
        lcd.print ("**");
        MaxH = 31;
        MinH = 1;
        CurH = 13;
        CurligH = 0;
      } else {
        lcd.setCursor(13, 0);
        if (TabMaH[2] < 10) lcd.print (0);
        lcd.print (TabMaH[2]);
      }

      if (ColH == 3) {
        lcd.setCursor(7, 1);
        lcd.print ("**");
        MaxH = 23;
        MinH = 0;
        CurH = 7;
        CurligH = 1;
      } else {
        lcd.setCursor(7, 1);
        if (TabMaH[3] < 10)  lcd.print (0);
        lcd.print (TabMaH[3]);
      }

      if (ColH == 4) {
        lcd.setCursor(10, 1);
        lcd.print ("**");
        MaxH = 59;
        MinH = 0;
        CurH = 10;
        CurligH = 1;
      } else {
        lcd.setCursor(10, 1);
        if (TabMaH[4] < 10) lcd.print (0);
        lcd.print (TabMaH[4]);
      }

      if (ColH == 5) {
        lcd.setCursor(13, 1);
        lcd.print ("**");
        MaxH = 59;
        MinH = 0;
        CurH = 13;
        CurligH = 1;
      } else {
        lcd.setCursor(13, 1);
        if (TabMaH[5] < 10) lcd.print (0);
        lcd.print (TabMaH[5]);
      }
    }//Fin choix valeur

    //Affichage ecran saisie
    else if (BpH < 800) {
      lcd.clear();
      lcd.setCursor(0, 0); lcd.print (" Date:   /  /  ");
      lcd.setCursor(0, 1); lcd.print ("Heure:   :  :  ");

      lcd.setCursor (7, 0); if (TabMaH[0] < 10) lcd.print (0);
      lcd.print(TabMaH[0]);
      lcd.setCursor (10, 0); if (TabMaH[1] < 10) lcd.print (0);
      lcd.print(TabMaH[1]);
      lcd.setCursor (13, 0); if (TabMaH[2] < 10) lcd.print (0);
      lcd.print(TabMaH[2]);
      lcd.setCursor (7, 1); if (TabMaH[3] < 10) lcd.print (0);
      lcd.print(TabMaH[3]);
      lcd.setCursor (10, 1); if (TabMaH[4] < 10) lcd.print (0);
      lcd.print(TabMaH[4]);
      lcd.setCursor (13, 1); if (TabMaH[6] < 10) lcd.print (0);
      lcd.print(TabMaH[5]);
      DrapH = 1;
    }// Fin Affichage
  }//Fin While Maj Heure

  // Saisie Plages Horaires ?
  lcd.setCursor(0, 0); lcd.print("Maj Horaires ?");
  lcd.setCursor(0, 1); lcd.print("Sel: O Right: N");
  MaJ = 1;
  lecturePlages(); // lecture dans Eeprom
  // Mise à jour plages horaires
  while (MaJ == 1) {
    Bp = analogRead (0);
    delay(100);
    lcd.setCursor(0, 0);
    //Sortie  mise à jour
    if (Bp < 50) {
      lcd.clear(); lcd.setCursor(0, 0); lcd.print("Fin saisie"); delay(2000); lcd.clear(); MaJ = 0;
      Serial.println(Bp);
    } // Fin Sortie

    // Incrémentation
    else if (Bp < 200) {
      Serial.println(Bp);
      if (Flag == 2) {
        if (Val < Max) {
          Val++; TabEvt[Lig][Col] = Val; delay(200); lcd.setCursor(Cur, CurLig);
          if (Val < 10) {
            lcd.setCursor(Cur, CurLig);
            lcd.print ("0");
          }
          lcd.print (Val);
        }
      }
    }// Fin Incrémentaion
    // Décrémentation
    else if (Bp < 380) {
      Serial.println(Bp);
      if (Flag == 2) {
        if (Val > 0) {
          Val--; TabEvt[Lig][Col] = Val; delay(200); lcd.setCursor(Cur, CurLig);
          if (Val < 10) {
            lcd.setCursor(Cur, CurLig);
            lcd.print ("0");
          }
          lcd.print (Val);
        }
      }
    }// Fin Décrémentation

    // Affichage Plage horaire, sélection Colonne
    else if (Bp < 600) {
      Serial.println(Bp);
      if ( Flag > 0 ) {
        Flag = 2;
        if (Sel < 6) {
          Sel++;
          delay(200);
          Col = Sel - 1;
        }

        if (Col == 0) {
          lcd.setCursor(9, 0);
          lcd.print ("**");
          Val = TabEvt[Lig][Col];
          Max = 23;
          Cur = 9;
          CurLig = 0;
        }
        else if (Col != 0) {
          lcd.setCursor(9, 0);
          if (TabEvt[Lig][0] < 10) lcd.print (0);
          lcd.print (TabEvt[Lig][0]);
        }

        if (Col == 1) {
          lcd.setCursor(12, 0);
          lcd.print ("**");
          Val = TabEvt[Lig][Col];
          Max = 59;
          Cur = 12;
          CurLig = 0;
        } else {
          lcd.setCursor(12, 0);
          if ( TabEvt[Lig][1] < 10) lcd.print (0);
          lcd.print (TabEvt[Lig][1]);
        }

        if (Col == 2) {
          lcd.setCursor(9, 1);
          lcd.print ("**");
          Val = TabEvt[Lig][Col];
          Max = 23;
          Cur = 9;
          CurLig = 1;
        } else {
          lcd.setCursor(9, 1);
          if ( TabEvt[Lig][2] < 10) lcd.print (0);
          lcd.print (TabEvt[Lig][2]);
        }

        if (Col == 3) {
          lcd.setCursor(12, 1);
          lcd.print ("**");
          Val = TabEvt[Lig][Col];
          Max = 59;
          Cur = 12;
          CurLig = 1;
        } else {
          lcd.setCursor(12, 1);
          if ( TabEvt[Lig][3] < 10) lcd.print (0);
          lcd.print (TabEvt[Lig][3]);
        }

        if (Sel == 6) Sel =  0;
      }
    }// Fin Plages Horaires

    // Affichage Voies,sélection ligne
    else if (Bp < 800) {
      Serial.println(Bp);
      lcd.clear();
      //Max = 23; Cur = 9; CurLig = 0;
      Flag = 1;
      if (Vo < 6) {
        Vo++;
        delay(300);
        Lig = Vo - 1;
      }

      lcd.setCursor(0, 0); lcd.print ("V:   On:   :  "); lcd.setCursor(0, 1); lcd.print ("    Off:   :  ");

      lcd.setCursor(2, 0); lcd.print (Vo);

      lcd.setCursor(9, 0);
      if (TabEvt[Lig][0] < 10) lcd.print (0);
      lcd.print (TabEvt[Lig][0]);

      lcd.setCursor(12, 0); if (TabEvt[Lig][1] < 10) lcd.print (0);
      lcd.print (TabEvt[Lig][1]);

      lcd.setCursor(9, 1); if (TabEvt[Lig][2] < 10) lcd.print (0);
      lcd.print (TabEvt[Lig][2]);

      lcd.setCursor(12, 1); if (TabEvt[Lig][3] < 10) lcd.print (0);
      lcd.print (TabEvt[Lig][3]);

      if (Vo == 6) Vo = 0;
      Sel = 0;
    }// Fin Affichage
  }// Fin While  Maj Plages Horaires
  sauvePlages(); //sauvegarde des plages dans Eeprom
}// Fin Setup


void loop() {


  lcd.clear();
  
  DateTime now = RTC.now();

  // Afficher l'heure sur la premiêre ligne du LCD

  lcd.setCursor(0, 0);
  lcd.print("Heure: ");
  if (now.hour() < 10) lcd.print("0");
  lcd.print(now.hour());
  lcd.print(":");
  if (now.minute() < 10) lcd.print("0");
  lcd.print(now.minute());



  // Afficher Voies actives sur la deuxième ligne du LCD

  lcd.setCursor(0, 1);
  lcd.print("Voies:");
  // début de modif
  int heure = now.hour() * 100 + now.minute();

  for (int i = 0; i < 6; i++) {
    if (TabEvt[i][0] == 25) continue; // On en fait rien dans ce cas
    int heureDebut = TabEvt[i][0] * 100 + TabEvt[i][1];
    int heureFin = TabEvt[i][2] * 100 + TabEvt[i][3];
    if (heureDebut <= heure && heure < heureFin) {
      lcd.print(i + 1);
      digitalWrite (PinSorties[i], HIGH);
      digitalWrite (PinRelais[i], HIGH);
      delay(500000);                
      digitalWrite (PinRelais[i], LOW);
      delay(500000);
    } else {
      lcd.print("-");
      digitalWrite (PinSorties[i], LOW);
      digitalWrite (PinRelais[i], HIGH);
    }
  }
  delay(1000);
  lcd.clear();

}

Si je comprends bien, tu as 6 électrovannes, et chaque zone peut être activée individuellement selon deux conditions :

  • programmation d'heures.
  • Le niveau d'humidité.

Tu envisages d'ajouter une condition supplémentaire en utilisant un débitmètre. Si le débitmètre détecte un flux alors que occune des conditions est exécuter alors fuite ?

La vanne motorisée n'est actionnée en position ouverte que si le programmateur d'arrosage sollicite un besoin d'eau en fonction des heures et du degré d'humidité du sol d'une zone, en activant le débitmètre. Si ce dernier détecte un débit supérieur au paramétrage, il y coupure de la vanne motorisée.
Celle-ci peut alors être à nouveau ouverte pour une autre zone tant que le débit de cette zone n'est pas supérieure au paramétrage.
Et ainsi de suite
Est-ce clair pour toi ?
On pourrait tout inclure dans un seul Arduino, mais je n'en ai pas les capacités informatique