Problème d'affichage de l'heure avec machine à état

Bonjour à tous,
J'ai besoin de votre aide pour un problème d'affichage de date et d'heure.
Je fais un programmateur journalier pour déclencher la pompe de ma piscine.

J'ai voulu le modifier pour ajouter un poussoir qui me permet de mettre en marche forcé ou en arrêt forcé ma pompe (pour sortir du mode programme pour l'entretien de la piscine).

J'ai donc suivi les excellents conseils que m'avait donné J-M-L dans un autre projet, j'ai crée une machine à état avec 3 états possibles:
Programme, pompe_ON forcé et pompe OFF forcé.

Mon problème est que le mode "programme" de ma machine à état enclenche ma pompe en fonction de l'heure, mais je n'arrive pas à récupérer l'heure de ma RTC dans ma machine à état.

Quand mon programme était dans le loop(), pas de problème.

Voici mon code qui fonctionne bien sans machine à état:

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

LiquidCrystal_I2C lcd(0x27, 20, 4);  // Déclaration type ecran
RTC_DS1307 RTC;

  const byte pompe=4;       // relais sur la pin 4 de l'arduino
  const int ledPompeM=5;    // Led Clignotement Pompe marche sur pin 5
  const byte ledMarche=6;   // Led Marche Système sur pin 6
  int ledState = LOW;

// initialistaion millis pour clignotement LED
  unsigned long previousMillis = 0;        
  const long interval = 1000;     

// Fonction Pompe ON Forcé -----------------------------------------------------------------------
void PompeON_Force()
{
    digitalWrite (pompe, LOW); // Pompe ON
    //lcd.setCursor(10, 0);
    //lcd.print(" FORCE");
    //lcd.setCursor(11, 1);
    //lcd.print("  ON ");
}


// Fonction Pompe OFF Forcé ----------------------------------------------------------------------
void PompeOFF_Force()
{
    digitalWrite (pompe, HIGH); // Pompe ON
    //lcd.setCursor(10, 0);
    //lcd.print(" FORCE");
    //lcd.setCursor(11, 1);
    //lcd.print(" OFF ");
  }
  

// Fonction Pompe OFF ---------------------------------------------------------------------- 
void PompeOFF()
{
    digitalWrite (pompe, LOW); // Pompe OFF
    lcd.setCursor(0,1);
    lcd.print("---- MODE AUTO: ----");
    lcd.setCursor(10,2);
    lcd.print(" POMPE OFF");
}

// Fonction Pompe OFF ---------------------------------------------------------------------- 
void PompeON()
{
    digitalWrite (pompe, HIGH); // Pompe ON
    lcd.setCursor(0,1);
    lcd.print("---- MODE AUTO: ----");
  }

// Fonction Cligotement LED ---------------------------------------------------------------------- 
void Cligno_LED()
 {
   unsigned long currentMillis = millis();
   if (currentMillis - previousMillis >= interval) {
     previousMillis = currentMillis;
     if (ledState == LOW) {
       ledState = HIGH;
    lcd.setCursor(11,2);
    lcd.print("POMPE ON "); 
     } else {
       ledState = LOW;
    lcd.setCursor(11,2);
    lcd.print("         ");
     }
    digitalWrite(ledPompeM, ledState);
  }
 }
// Fonction LED OFF---------------------------------------------------------------------- 
void LED_OFF()
{
  digitalWrite (ledPompeM, LOW);
}
  
 void setup(){
    pinMode(pompe, OUTPUT); 
    pinMode(ledPompeM, OUTPUT);
    pinMode(ledMarche, OUTPUT);
    digitalWrite (pompe, LOW);
    digitalWrite (ledMarche, HIGH);
    //Serial.begin(57600);
    Wire.begin();
    RTC.begin();

  //Si RTC ne fonctionne pas
  //if (! RTC.isrunning()) {
    //Serial.println("RTC ne fonctionne pas !");

  // following line sets the RTC to the date & time this sketch was compiled
  //RTC.adjust(DateTime(__DATE__, __TIME__));
  //}
//Initialisation du LCD---------------------------------------------
  lcd.init();
  lcd.cursor_on();
  lcd.blink_on();
  lcd.backlight();
  lcd.setCursor(0, 0);
 }
void loop(){
 //Affichage de l'heure
  DateTime now = RTC.now();
 //Affichage HEURE ------------------------------------------------------ 
   lcd.setCursor(12, 0); 
   lcd.print(now.hour()); 
   lcd.print(":"); 
   if (now.minute() < 10) { 
     lcd.print("0"); 
   } 
   lcd.print(now.minute()); 
   lcd.print(":"); 
   if (now.second() < 10) { 
     lcd.print("0"); 
   } 
   lcd.print(now.second());
   
 //Affichage DATE ------------------------------------------------------ 
   lcd.setCursor(0, 0);
   if (now.day() < 10) { 
     lcd.print("0");
   }   
   lcd.print(now.day());  
   lcd.print(" ");  
  
   switch (now.month()) { 
   case 1: 
     lcd.print("JAN"); 
     break; 
   case 2: 
     lcd.print("FEV"); 
     break; 
   case 3: 
     lcd.print("MAR"); 
     break; 
   case 4: 
     lcd.print("AVR"); 
     break; 
   case 5: 
     lcd.print("MAI"); 
     break; 
   case 6: 
     lcd.print("JUI"); 
     break; 
   case 7: 
     lcd.print("JULL"); 
     break; 
   case 8: 
     lcd.print("AOU"); 
     break; 
   case 9: 
     lcd.print("SEP"); 
     break; 
   case 10: 
     lcd.print("OCT"); 
     break; 
   case 11: 
     lcd.print("NOV"); 
     break; 
   case 12: 
     lcd.print("DEC"); 
     break; 
   } 
   lcd.print(" ");  
   lcd.print(now.year());  
  
   lcd.cursor_off();
   lcd.blink_off();

  if(now.hour() == 9 && now.minute() <= 30) {   
      PompeON();
      Cligno_LED();
      lcd.setCursor(0,2);
      lcd.print(" 9h->9h30 ");
    }
  if(now.hour() == 9 && now.minute() > 30) {   
      PompeOFF();
      LED_OFF();
      lcd.setCursor(0,2);
      lcd.print("9h30->10h ");
    }
  if(now.hour() == 10 && now.minute() <= 30) {   
      PompeON();
      Cligno_LED();
      lcd.setCursor(0,2);
      lcd.print("10h->10h30");
    }
  if(now.hour() == 10 && now.minute() > 30) {   
      PompeOFF();
      LED_OFF();
      lcd.setCursor(0,2);
      lcd.print("10h30->11h");
    }
  if(now.hour() == 11 && now.minute() <= 30) {   
      PompeON();
      Cligno_LED();
      lcd.setCursor(0,2);
      lcd.print("11h->11h30");
    }
  if(now.hour() == 11 && now.minute() > 30) {   
      PompeOFF();
      LED_OFF();
      lcd.setCursor(0,2);
      lcd.print("11h30->12h");
    }
  if(now.hour() == 12 && now.minute() <= 30) {   
      PompeON();
      Cligno_LED();
      lcd.setCursor(0,2);
      lcd.print("12h->12h30");
    }
  if(now.hour() == 12 && now.minute() > 30) {   
      PompeOFF();
      LED_OFF();
      lcd.setCursor(0,2);
      lcd.print("12h30->13h");
    }
  if(now.hour() == 13 && now.minute() <= 30) {   
      PompeON();
      Cligno_LED();
      lcd.setCursor(0,2);
      lcd.print("13h->13h30");
    }
  if(now.hour() == 13 && now.minute() > 30) {   
      PompeOFF();
      LED_OFF();
      lcd.setCursor(0,2);
      lcd.print("13h30->14h");
    }
  if(now.hour() == 14 && now.minute() <= 30) {   
      PompeON();
      Cligno_LED();
      lcd.setCursor(0,2);
      lcd.print("14h->14h30");
    }
  if(now.hour() == 14 && now.minute() > 30) {   
      PompeOFF();
      LED_OFF();
      lcd.setCursor(0,2);
      lcd.print("14h30->15h");
    }
  if(now.hour() == 15 && now.minute() <= 30) {   
      PompeON();
      Cligno_LED();
      lcd.setCursor(0,2);
      lcd.print("15h->15h30");
    }
  if(now.hour() == 15 && now.minute() > 30) {   
      PompeOFF();
      LED_OFF();
      lcd.setCursor(0,2);
      lcd.print("15h30->16h");
    }
  if(now.hour() == 16 && now.minute() <= 30) {   
      PompeON();
      Cligno_LED();
      lcd.setCursor(0,2);
      lcd.print("16h->16h30");
    }
  if(now.hour() == 16 && now.minute() > 30) {   
      PompeOFF();
      LED_OFF();
      lcd.setCursor(0,2);
      lcd.print("16h30->17h");
    }
 if(now.hour() == 17 || now.hour() == 18 || now.hour() == 19 || now.hour() == 20) {   
      PompeON();
      Cligno_LED();
      lcd.setCursor(0,2);
      lcd.print(" 17h->21h ");
    }
 if(now.hour() == 21 || now.hour() == 22 || now.hour() == 23 || now.hour() == 00 || now.hour() == 1 || now.hour() == 2 || now.hour() == 3 || now.hour() == 4 || now.hour() == 5 || now.hour() == 6 || now.hour() == 7 || now.hour() == 8) {   
      PompeOFF();
      LED_OFF();
      lcd.setCursor(0,2);
      lcd.print(" 21h->9h  ");
    }
    
 }

Et voici le code avec la machine à état:

début du code idem 

// Machine à états-----------------------------------------------------------------------
enum {programme, pompe_ON, pompe_OFF} etatCourant; // la liste des états possible de notre système

void simpleclick()
{
switch (etatCourant) {
  
  case programme: 
  
    if(now.hour() == 9 && now.minute() <= 30) {   
    PompeON();
    Cligno_LED();
    lcd.setCursor(0,2);
    lcd.print(" 9h->9h30 ");
  }
  if(now.hour() == 9 && now.minute() > 30) {   
    PompeOFF();
    LED_OFF();
    lcd.setCursor(0,2);
    lcd.print("9h30->10h ");
  }
  if(now.hour() == 10 && now.minute() <= 30) {   
    PompeON();
    Cligno_LED();
    lcd.setCursor(0,2);
    lcd.print("10h->10h30");
  }
  if(now.hour() == 10 && now.minute() > 30) {   
    PompeOFF();
    LED_OFF();
    lcd.setCursor(0,2);
    lcd.print("10h30->11h");
  }
  if(now.hour() == 11 && now.minute() <= 30) {   
    PompeON();
    Cligno_LED();
    lcd.setCursor(0,2);
    lcd.print("11h->11h30");
  }
  if(now.hour() == 11 && now.minute() > 30) {   
    PompeOFF();
    LED_OFF();
    lcd.setCursor(0,2);
    lcd.print("11h30->12h");
  }
  if(now.hour() == 12 && now.minute() <= 30) {   
    PompeON();
    Cligno_LED();
    lcd.setCursor(0,2);
    lcd.print("12h->12h30");
  }
  if(now.hour() == 12 && now.minute() > 30) {   
    PompeOFF();
    LED_OFF();
    lcd.setCursor(0,2);
    lcd.print("12h30->13h");
  }
  if(now.hour() == 13 && now.minute() <= 30) {   
    PompeON();
    Cligno_LED();
    lcd.setCursor(0,2);
    lcd.print("13h->13h30");
  }
  if(now.hour() == 13 && now.minute() > 30) {   
    PompeOFF();
    LED_OFF();
    lcd.setCursor(0,2);
    lcd.print("13h30->14h");
  }
  if(now.hour() == 14 && now.minute() <= 30) {   
    PompeON();
    Cligno_LED();
    lcd.setCursor(0,2);
    lcd.print("14h->14h30");
  }
  if(now.hour() == 14 && now.minute() > 30) {   
    PompeOFF();
    LED_OFF();
    lcd.setCursor(0,2);
    lcd.print("14h30->15h");
  }
  if(now.hour() == 15 && now.minute() <= 30) {   
    PompeON();
    Cligno_LED();
    lcd.setCursor(0,2);
    lcd.print("15h->15h30");
  }
  if(now.hour() == 15 && now.minute() > 30) {   
    PompeOFF();
    LED_OFF();
    lcd.setCursor(0,2);
    lcd.print("15h30->16h");
  }
  if(now.hour() == 16 && now.minute() <= 30) {   
    PompeON();
    Cligno_LED();
    lcd.setCursor(0,2);
    lcd.print("16h->16h30");
  }
  if(now.hour() == 16 && now.minute() > 30) {   
    PompeOFF();
    LED_OFF();
    lcd.setCursor(0,2);
    lcd.print("16h30->17h");
  }
 if(now.hour() == 17 || now.hour() == 18 || now.hour() == 19 || now.hour() == 20) {   
    PompeON();
    Cligno_LED();
    lcd.setCursor(0,2);
    lcd.print(" 17h->21h ");
  }
 if(now.hour() == 21 || now.hour() == 22 || now.hour() == 23 || now.hour() == 00 || now.hour() == 1 || now.hour() == 2 || now.hour() == 3 || now.hour() == 4 || now.hour() == 5 || now.hour() == 6 || now.hour() == 7 || now.hour() == 8) {   
    PompeOFF();
    LED_OFF();
    lcd.setCursor(0,2);
    lcd.print(" 21h->9h  ");
  }
  break;
  
case pompe_ON:
  PompeON_Force();
  break;
  
 case pompe_OFF: 
  PompeOFF_Force();
  break;
}
}
void setup(){
  pinMode(pompe, OUTPUT); 
  pinMode(ledPompeM, OUTPUT);
  pinMode(ledMarche, OUTPUT);
  digitalWrite (pompe, LOW);
  digitalWrite (ledMarche, HIGH);
  //Serial.begin(57600);
  Wire.begin();
  RTC.begin();
  button.attachClick(simpleclick);  // On attache la fonction simpleClick() comme callBack
  etatCourant = programme;   //démarre la machine à état sur programme
 
 //RTC.adjust(DateTime(__DATE__, __TIME__));
}
//Initialisation du LCD---------------------------------------------
lcd.init();
lcd.cursor_on();
lcd.blink_on();
lcd.backlight();
lcd.setCursor(0, 0);
}

void loop(){
//Affichage de l'heure
DateTime now = RTC.now();
button.tick();    // On vérifie l'état des boutons, ce qui déclenche l'appel de la fonction callBack si nécessaire
//Affichage HEURE ------------------------------------------------------ 
 lcd.setCursor(12, 0); 
 lcd.print(now.hour()); 
 lcd.print(":"); 
 if (now.minute() < 10) { 
   lcd.print("0"); 
 } 
 lcd.print(now.minute()); 
 lcd.print(":"); 
 if (now.second() < 10) { 
   lcd.print("0"); 
 } 
 lcd.print(now.second());
 
//Affichage DATE ------------------------------------------------------ 
 lcd.setCursor(0, 0);
 if (now.day() < 10) { 
   lcd.print("0");
 }   
 lcd.print(now.day());  
 lcd.print(" ");  

 switch (now.month()) { 
 case 1: 
   lcd.print("JAN"); 
   break; 
 case 2: 
  etc.....
 } 
 lcd.print(" ");  
 lcd.print(now.year());  

 lcd.cursor_off();
 lcd.blink_off();

 
}

Le compilateur me dit:

'void simpleclick()':

Programmateur_Piscine3:96: error: 'now' was not declared in this scope

       if(now.hour() == 9 && now.minute() <= 30) {   

          ^

Programmateur_Piscine3:102: error: 'now' was not declared in this scope

     if(now.hour() == 9 && now.minute() > 30) {   

   etc..........

'now' was not declared in this scope

tout semble venir de 'now' qui n'est pas déclaré.

Comment puise-je faire?
merci de votre aide

Ben oui, C’est quoi now? Ce n’est pas un variable globale

DateTime now = RTC.now(); Elle est définie dans la loop, donc visible que dans cette fonction

Cf lecture sur la Portée (visibilité) des variables

Bonjour J-L-M,
contant de vous retrouver.
J'avoue ne pas savoir vous répondre,
pour récupérer la date et l'heure, j'ai suivi un post (que je dois pouvoir retrouver)
je pense que c'est une commande de la Lib RTC que j'utilise.

Soit vous recréez une variable now dans la fonction appelée, comme dans la boucle principale et relisez l’heure, soit vous mettez now comme variable globale en vous assurant de la;mettre à jour avant de vérifier si un bouton est appuyé

Bonjour J-M-L,
je comprends le problème, si je déclare ma variable 'now' dans le void setup(), le message d'erreur de compilation disparaît, ma machine à état fonctionne, mais l'heure affichée reste figée à l'heure de lecture du setup() ce qui est normal.
il faudrait donc de je crée une commande dans le loop pour rafraichir en permanence l'heure et qu'elle soit lue dans mon état "programme" de ma machine à état.
C'est bien ça?
J'avoue ne pas savoir comment faire!

je voulais faire une machine à état pour simplifier mon système avec un seul BP qui me permette de passer d'un état à l'autre (programme, pompe-on, pompe-off) mais j'ai l'impression que ça complique les choses!

Après j'ai un plan B, je laisse tout dans le loop(), je remplace mon BP par un commutateur 3 positions, je test les trois entrées et déclenche les fonctions (programme() ou pompe_on() ou pompe_off()) en fonction.

Mais je voulais mettre en pratique ce que vous m'aviez appris lors de mon projet précèdent.

Question:
Et si je mets les états possible de ma machine à état (switch/case/break) dans le loop() ?
possible ou pas?

je vais testé pour voir.

Mais vos conseils sont les bienvenus.

si vous utilisez la librairie oneButton ça va appeler une fonction, il faut donc que dans cette fonction les variables soit accessibles; Soit elles sont globales (comme l'état) soit locale et dans ce cas il faut les initialiser

void simpleclick()
{
   DateTime now = RTC.now(); // DECLARER ET DEFINIR EN TANT QUE VARIABLE LOCALE

   switch (etatCourant) {
  
     case programme: 
  
       if(now.hour() == 9 && now.minute() <= 30) {   

       ...

Bonsoir J-M-L, et les autres...
J'avais testé cette solution avant de poster mais l'affichage de l'heure restait figée.
J'ai retenté pour être sûr.
Plus de message d'erreur, la machine à état fonctionne mais pas l'état 'progamme'.
si je démarre mon arduino à 20h par exemple, j'ai bien l'affichage et le déclenchement de ma pompe en consequence:

if(now.hour() == 17 || now.hour() == 18 || now.hour() == 19 || now.hour() == 20) {   
      PompeON();
      Cligno_LED();
      lcd.setCursor(0,2);
      lcd.print(" 17h->21h ");

mais rien ne se passe à 21h la ou ma pompe devrait se couper et l'affichage changer

if(now.hour() == 21 || now.hour() == 22 || now.hour() == 23 || now.hour() == 00 || now.hour() == 1 || now.hour() == 2 || now.hour() == 3 || now.hour() == 4 || now.hour() == 5 || now.hour() == 6 || now.hour() == 7 || now.hour() == 8) {   
      PompeOFF();
      LED_OFF();
      lcd.setCursor(0,2);
      lcd.print(" 21h->9h  ");
    }

et la fonction cligno_LED() ne fonctionne plus.
par contre mon poussoir fait bien changer les états.

mais simpleclick() n'est appelé que si vous appuyez sur un bouton...

si vous voulez un évènement "temps" alors il faut traiter cela dans le programme principal comme une détection, un peu comme le timeout dans mon tuto

Bonjour,
effectivement le problème vient visiblement de l'utilisation de la lib Onebutton qui n'est pas adaptée à ce que je veux faire.
Je vais tout rebasculer dans le programme principal et déclencher ma machine à état sur la détection de changement d'état du bouton poussoir.
Merci pour vos précieux conseils.
Je travail la dessus (relecture des tutos et posts...)
A bientôt

sincèrement relire l'heure dans la fonction simpleClick() n'est pas difficile...

Ce n'est pas ce qui est fait avec le commande DateTime now = RTC.now(); ?

 void simpleclick(){
  DateTime now = RTC.now();

  switch (etatCourant) {
    
    case programme: 

    Serial.println("mode programme");
      if(now.hour() == 9 && now.minute() <= 30) {   
      PompeON();
      Cligno_LED();
      lcd.setCursor(0,2);
      lcd.print(" 9h->9h30 ");
    }
...

Si - et ça devrait suffire pour lire l’heure quand la fonction est appelée lors d’un click - ce qu’il y a c’est que vous souhaitez un traitement sans click sur le bouton - donc c’est un autre événement à gérer dans la machine

et ça devrait suffire pour lire l'heure quand la fonction est appelée lors d'un click

C'est bien ce qu'il se produit, l'heure est actualisée à chaque click.

donc c'est un autre événement à gérer dans la machine

si je veux que l'heure soit réactualisée en permanence, il faut donc faire appelle à une commande ou fonction se trouvant dans le Loop().?
C'est possible de faire ça, appeler une commande dans le loop() depuis la fonction Simpleclick() ?

Bon ben désolé, je sèche!

Je ne vois pas comment une fonction que est appelée une fois sur un click peut mettre à jour l'heure continuellement grâce à une commande dans le Loop().
j'ai crée une fonction "acu_heurs()" avec ma commande "DateTime now = RTC.now();" a l'intérieure et je l'appelé dans ma fonction simpleclick().
Mais ce ne change pas le problème.
Help!
Merci

Vous pouvez appeler simpleClick() depuis la loop() vous même...

Merci de votre aide.
Appeler la fonction Simpleclick() depuis la loop() est une solution que j'avais testée et très vite oubliée car ça revient à appuyer sur le bouton poussoir et donc à changer l'état de ma machine à chaque boucle...

Bonjour,

Ben, il suffit d'appeler simplement acu_heurs() dans la loop.

Héhé, pas bête...
Je vais tester et vous dit quoi.
Merci Kamill