Aide pour activation relais en mode automatique temporisé via machine a etats

Non pas vraiment, mettez vous dans la peau d'un utilisateur néophyte qui voudrait dupliquer votre projet.
Que doit il savoir, comment connecter et choisir les composants, quels sont les problèmes matériels que vous avez eu à résoudre etc

Justement non, le nom d'un état doit décrire un état de ta machine, dans ton cas tu as déjà ta variable qui indique tu applique l'état à ton relais, donc tu n'es pas obligé de faire référence au relais dans le nom de ton état et cela peut te permettre d'appliquer cet état potentiellement à autre chose qu'un relais.
Mais effectivement les machines à état peuvent être un peu déroutant au début, par rapport un du code "normal"
D'ailleurs de la manière dont tu gère les choses, on a du mal à lire la machine à état, car le cœur de la machine est à l'intérieur de plusieurs fonctions/fichiers.

oui tout a fait d ' accord avec ca .
j ' essaie de mettre ca en place proprement pour l' arrosage , car a ce niveau là c ' est encore pire que pour la gestion des relais .


est ce que cela semble correct pour l' arrosage ?

L'image est coupé, c'est normal ?

oui je debute avec inscape ... toute 1ere fois que je m' en sers desolé .
c ' est rectifié .

Je pense que tu devrais ajouté un état mise en service de l'arrosage, renommer arrosée par mise hors service de l'arrosage.
du coup dans
l'état "attente du prochain arrosage" : tu attends que le jour et l'heure arrive.
l'état "mise en service de l'arrosage": tu active tes relais et passe directement à l'état "en arrosage"
l'état "en arrosage": tu attends que le temps expire pour passer à l'état "mise hors service de l'arrosage"
l'état "mise hors service de l'arrosage" tu désactive les relais et passe directement à l'état "en attente du prochain arrosage"

En gros dans chaque état tu fais qu'une seul chose.

effectivement ca parait logique .

il faudrait un "cahier des charges" un peu plus complet
Que voulez vous pouvoir faire ?

  • déclenchement manuel / arrêt manuel
  • déclenchement manuel / arrêt au bout d'un certain temps
  • déclenchement manuel / arrêt sur condition d'un capteur
  • déclenchement automatique / arrêt automatique au bout d'un certain temps
  • déclenchement automatique / arrêt manuel
  • déclenchement automatique / arrêt sur condition d'un capteur
  • gestion des erreurs / mode protection
    ...

et bien sûr la partie "automatique" doit elle même faire l'objet de spécifications. avez vous un semainier par exemple ?

idem pour la partie manuelle (commande web, commande interface série, boutons physiques, BLE, ....)

➜ avant de coder on passe un peu de temps sur les besoins. ça évite les mauvaises surprises ensuite.

dans un 1er temps , c ' est pas forcement une bonne idée c ' est sur ... mais je pensais me cantonner a la machine a etats uniquement pour le mode automatique ( et ne pas y inclure le mode manuel )

j ' ai corrigé le schema :

oui c ' est ca .
pour les capteurs :
l ' hiver , si il fait trop froid en cas de gel par exemple , ne pas arroser .
si il pleut inutile d ' arroser aussi .

Je partage l'avis de @J-M-L ca vaut le coup de réfléchir un peu avant de ce lancer dans le code.
Les actions manuels peuvent être un cas particulier de la machine à état ou partie intégrante des états suivant ce que tu veux faire.

Par exemple tu peux déclencher un arrosage manuel via ton application Web, qui lance l'arrosage mais pour le même temps déterminer dans ton programme que l'arrosage automatique.
Ou alors, qui ne s'arrêtera uniquement par une action d'arrêt manuel, mais qui peut aussi être ou pas dans un de tes états.

En gros avec ton serveur HTTP, tu peux faire passer ta machine d'un état à l'autre, sans forcément que la partie manuel ne génère des états spécifiques.

Mais pour ça il faut réfléchir un peu à ce que tu veux faire.
Personnellement je ferais que ta machine à état gère tout tes cas, cela simplifiera ton code et donc sa maniabilité future, comme l'intégration de différent capteur.

Bonjour et bon diamanche a vous .

j ' ai repris le code du portail qui ne fonctionnait pas comme je le desirais .
j ' ai changer tout un tas de truc dans l' espoir de rendre le code plus lisible et comprehensible et pour qu ' il fasse ce que je voulais bien sur :grin:
petit soucis au niveau du "nettoyage " dans le nouveau switch case de gererUnRelais() , je ne rentre jamais dans un des cas ( le dernier = 3 ) . sauf que je ne vois pas comment supprimer cet etat dans le code ... car meme si il n' est pas utile dans le gererUnRelais , il l' est dans d ' autre partie , comme dans la fonction desactiverUnRelaisEtUnTimer() par exemple .

voici le nouveau code utilisé :

enum t_commandeRelais : uint8_t {ACTIVE, DESACTIVE, ACTIVE_TIMER, DESACTIVE_TIMER, NULL_R};
…{45,  R_INACTIF, "Heures creuses", 0}
};
const uint8_t NOMBREDERELAIS = sizeof(lesRelais) / sizeof(t_relais);

//// Fonctions de gestion des relais : ////
bool verifPinOK (int8_t pin) { // on s' assure grace a cette fonction que le pin qu ' on recoit est bien un numero valide compris dans la plage de pin que doit gerer notre serveur.
  return (pin >= -4 && pin < 53);
}

void initialiserUnRelais (t_relais* unRelais) {
  pinMode(unRelais->pinRelais, OUTPUT);
  digitalWrite(unRelais->pinRelais, RELAIS_INACTIF); // à l'arret
  if (DEBUG) {
    Serial.print (F("* initialiserUnRelais => PIN : "));
    Serial.println (unRelais->pinRelais);
  }
}

void activerUnRelais(t_relais* unRelais) {
  if (unRelais->etat != R_ACTIF) {
    if (!TEST) digitalWrite(unRelais->pinRelais, RELAIS_ACTIF);
    unRelais->etat = R_ACTIF;
  }
}
void desactiverUnRelais(t_relais* unRelais) {
  if (unRelais->etat != R_INACTIF) {
    if (!TEST) digitalWrite(unRelais->pinRelais, RELAIS_INACTIF);
    unRelais->etat = R_INACTIF;
    // juste au cas ou un timer est activé :
    //desactiverUnTimerRelais(unRelais->pinRelais);
  }
}
void inverserUnRelais(t_relais* unRelais) {
  activerUnRelais(unRelais);
  desactiverUnRelais(unRelais);
}

void activerUnRelaisEtUnTimer (t_relais* unRelais) {
  if (unRelais->etat != TIMER_ACTIF) {
    if (!TEST) digitalWrite(unRelais->pinRelais, RELAIS_ACTIF);
    unRelais->etat = TIMER_ACTIF;
  }
  activerUnTimerRelais(unRelais);
}
void desactiverUnRelaisEtUnTimer (t_relais* unRelais) {
  if (unRelais->etat != TIMER_INACTIF) {
    if (!TEST) digitalWrite(unRelais->pinRelais, RELAIS_INACTIF);
    unRelais->etat = R_INACTIF;
  }
  desactiverUnTimerRelais(unRelais->pinRelais);
}
void inverserUnRelaisEtUnTimer(t_relais* unRelais) {
  activerUnRelaisEtUnTimer (unRelais);
  desactiverUnRelaisEtUnTimer (unRelais);
}

void gererLesRelais () {

  if (commandeWeb.active) {
    if (commandeWeb.volet == NULL && commandeWeb.actionCMD_V == NULL_V  && commandeWeb.arrosage == NULL && commandeWeb.actionCMD_A == NULL_A && commandeWeb.relais == NULL && commandeWeb.actionCMD_R != NULL_R) {
      // on peut faire ici un " activer tout les relais par exemple "
      commandeWeb.active=false;
      if (DEBUG) {
        Serial.print (F("* gererLesRelais , 1er if "));
      }
    }
  }
  else for (uint8_t r = 0; r < NOMBREDERELAIS; r++) gererUnRelais(&(lesRelais[r]));
}

void gererUnRelais (t_relais* unRelais) {
  switch (unRelais->etat) { // R_ACTIF, R_INACTIF, TIMER_ACTIF, TIMER_INACTIF
    // 0
    case R_ACTIF :
      if ((commandeWeb.active) && (commandeWeb.relais == unRelais)) {
        Serial.print (F("* gererUnRelais => case ACTIF => Etat precedant : "));
        Serial.println (unRelais->etat);
        
        if (commandeWeb.actionCMD_R == DESACTIVE) {
          desactiverUnRelais(unRelais); // avec cette fonction gere aussi le cas ou le portail a été ouvert en auto et arreté a la main . ca enlevera les asyncTask si besoin .
          if (DEBUG) {
            Serial.print (F("* gererUnRelais => case ACTIF => actionCMD_R == DESACTIVE. Etat resultant : "));
            Serial.println (unRelais->etat);
            Serial.println (F(""));
          }
          commandeWeb.active = false;
        }
      }
      break;  
    // 1
    case R_INACTIF : // actionCMD_R = ACTIVE, DESACTIVE, ACTIVE_TIMER, DESACTIVE_TIMER, NULL_R
      if ((commandeWeb.active) && (commandeWeb.relais == unRelais)) {
        
        Serial.print (F("* gererUnRelais => case INACTIF => Etat precedant : "));
        Serial.println (unRelais->etat);
            
        if (commandeWeb.actionCMD_R == ACTIVE) {
          activerUnRelais(unRelais);
          if (DEBUG) {
            Serial.print (F("* gererUnRelais => case INACTIF => actionCMD_R == ACTIVE. Etat resultant : "));
            Serial.println (unRelais->etat);
            Serial.println (F(""));
          }
        }
        else if (commandeWeb.actionCMD_R == ACTIVE_TIMER) {
          activerUnRelaisEtUnTimer(unRelais);
          //inverserUnRelaisEtUnTimer(unRelais);
          if (DEBUG) {
            Serial.print (F("* gererUnRelais => case INACTIF => actionCMD_R == ACTIVE_TIMER. Etat resultant : "));
            Serial.println (unRelais->etat);
            Serial.println (F(""));
          }
        }
        commandeWeb.active = false;
      }
      break;
    // 2
    case TIMER_ACTIF :
      if ((commandeWeb.active) && (commandeWeb.relais == unRelais)) {
        if (DEBUG) {
          Serial.print (F("* gererUnRelais => case TIMER_ACTIF => Etat precedant : "));
          Serial.print (unRelais->etat);
          Serial.print (F(" => commandeWeb.actionCMD_R : "));
          Serial.println (commandeWeb.actionCMD_R);
        }
        if (commandeWeb.actionCMD_R == DESACTIVE_TIMER) {
          desactiverUnRelaisEtUnTimer(unRelais);
          //inverserUnRelaisEtUnTimer(unRelais);
          if (DEBUG) {
              Serial.print (F("* gererUnRelais => case TIMER_ACTIF => actionCMD_R == DESACTIVE_TIMER. Etat resultant : "));
              Serial.println (unRelais->etat);
              Serial.println (F(""));
            }
          }
          else if (commandeWeb.actionCMD_R == DESACTIVE) {
            desactiverUnRelais(unRelais);
            if (DEBUG) {
              Serial.print (F("* gererUnRelais => case TIMER_ACTIF => actionCMD_R == DESACTIVE. Etat resultant : "));
              Serial.println (unRelais->etat);
              Serial.println (F(""));
            }
         }
        commandeWeb.active = false;
      }
      break;
    // 3
    /*case TIMER_INACTIF :
      if ((commandeWeb.active) && (commandeWeb.relais == unRelais)) {
        Serial.print (F("* gererUnRelais => case TIMER_INACTIF => Etat precedant : "));
        Serial.println (unRelais->etat);
        
        if (commandeWeb.actionCMD_R == ACTIVE_TIMER) {
          activerUnRelaisEtUnTimer(unRelais);
          //inverserUnRelaisEtUnTimer(unRelais);
          if (DEBUG) {
            Serial.print (F("* gererUnRelais => case TIMER_INACTIF => actionCMD_R == ACTIVE_TIMER. Etat resultant : "));
            Serial.println (unRelais->etat);
            Serial.println (F(""));
          }
          commandeWeb.active = false;
        }
      }
      break;*/
    default:
      if (DEBUG) Serial.println (F("* gererUnRelais => probleme = case non reconnu !"));
      break;
  } // fin switch
  // comme cette fonction est appellé en permanence , il vaut mieux eviter de mettre quoi que ce soit ici
}

/************************************************************************************/

void relaisHeureCreuse () { // ok
  static unsigned long chrono = 0;
  unsigned int timestamp = RTC.heure()*60 + RTC.minute();
  static int RHC = -1; // jamais lu
  static bool oldRHC = false;

  if ((RHC == -1) || (millis() - chrono >= TIMER_V)) { // si jamais lue ou lue depuis plus de 30 secondes
    if (DEBUG && RHC == -1 ) {
      Serial.print (F("relaisHeureCreuse => initialisation sur PIN : "));
      Serial.print (lesRelais[1].pinRelais);
      Serial.print (F(" , etat : "));
      Serial.println (lesRelais[1].etat);
    }
    // si on est dans le bon crenau horraire
    //if ( (timestamp > HC_START_TIME_N && timestamp < HC_END_TIME_N) || (timestamp > HC_START_TIME_D && timestamp < HC_END_TIME_D) ) { // entre 12 et 14 heures + la nuit
    if (timestamp > HC_START_TIME_D && timestamp < HC_END_TIME_D ) { // enclenchement uniquement entre 12 et 14 Heures
      RHC = 1;
      //if (DEBUG) Serial.println (F("relaisHeureCreuse => etat actif"));
    }
    else {
      RHC = 0;
      //if (DEBUG) Serial.println (F("relaisHeureCreuse => etat passif"));
    }
    if ((oldRHC != RHC) && (RHC != -1)) {
      if (DEBUG) {
        Serial.print (F("relaisHeureCreuse => oldRHC avant = "));
        Serial.print (oldRHC);
        Serial.print (F(" , relaisHeureCreuse => RHC = "));
        Serial.println (RHC);
      }
      inverserUnRelais(&(lesRelais[1]));
      oldRHC = RHC;
    }
    chrono = millis();

  // histoire de verifier le nombre de tache au cours de l' evolution du programme.
    /*if (DEBUG) {
      uint8_t count = 0;
      for (uint8_t i=0; i<255; i++) {
        if (gestionnaireDeTache.findAsyncCommand(i)) {
          count++;
          Serial.print (F("setup => trouver taches : "));
          Serial.println (i);
        }
      }
      if (! count) Serial.print (F("setup => pas de tache trouvée ."));
      else {
        Serial.print (F("setup => "));
        Serial.print (count);
        Serial.println (F(" tache(s) trouvée(s) ."));
      }
    }*/
  }
}

// on recoit le pin du timer asynctask ...
// cette fonction sert uniquement a desactiver le bon relais et mettre a jour l' etat .
// elle est appelée uniquement par le callback du gestionnaire de tache , voir fichier timers_rtc.ino
void desactiverRelais(t_commandID pin) {
  for (uint8_t i = 0; i < NOMBREDERELAIS; i++) {
    if (lesRelais[i].pinRelais == pin) {
      lesRelais[i].etat = R_INACTIF;
      if (!TEST) digitalWrite(lesRelais[i].pinRelais, RELAIS_INACTIF);
      if (DEBUG) {
        Serial.print (F("* desactiverRelais => indice = "));
        Serial.print (i);
        Serial.print (F(", relais = "));
        Serial.println (lesRelais[i].pinRelais);
      }
    }
  }
}

void activerUnTimerRelais (t_relais* unRelais) {
  // si une tache existe deja , on la remplace par la nouvelle , donc , 1ere chose , on supprime la tache si elle existe deja .
  desactiverUnTimerRelais(unRelais->pinRelais);

  if (!gestionnaireDeTache.findAsyncCommand(unRelais->pinRelais)) {
    gestionnaireDeTache.registerAsyncCommand(unRelais->pinRelais, unRelais->timerRelais, desactiverRelais);
    if (DEBUG) {
      Serial.print (F("* activerTimerRelais => tache "));
      Serial.print (unRelais->pinRelais);
      Serial.print (F(" enregistrée pour dans "));
      Serial.println (unRelais->timerRelais);
    }
  }
}

void desactiverUnTimerRelais (uint8_t pin) { // en cas de suppression manuelle du timer
  if (gestionnaireDeTache.findAsyncCommand(pin)) {
    gestionnaireDeTache.unregisterAsyncCommand(pin);
    if (DEBUG) {
      Serial.print (F("* desactiverUnTimerRelais => tache : "));
      Serial.print (pin);
      Serial.println (F(" supprimee"));
    }
  }
}

//// FIN Des Fonctions de gestion des relais ////

       
 case PORTAIL : // commandeWeb.relais = ACTIVE, DESACTIVE, ACTIVE_TIMER, DESACTIVE_TIMER, NULL_R
          if(DEBUG) { // etatRelais = R_ACTIF, R_INACTIF, TIMER_ACTIF, TIMER_INACTIF
            Serial.print(F("* parseCommand => PORTAIL => labelValue = "));
            Serial.println(labelValue);
          }
          //if (! TEST) inverserUnRelaisEtUnTimer (&(lesRelais[0])); // fonctionne aussi
          for (uint8_t r = 0; r < NOMBREDERELAIS; r++) {
            if (strcmp(lesRelais[r].nomRelais, "Portail") == 0) {
              if(DEBUG) {
                Serial.print(F("* parseCommand => PORTAIL => envoi = "));
                Serial.println(lesRelais[r].pinRelais);
              }
              if (lesRelais[r].etat == R_INACTIF || lesRelais[r].etat == TIMER_INACTIF) affecteCommandeWeb(true, NULL, NULL_V, NULL, NULL_A, &(lesRelais[r]), ACTIVE);
              else if (lesRelais[r].etat == R_ACTIF || lesRelais[r].etat == TIMER_ACTIF) affecteCommandeWeb(true, NULL, NULL_V, NULL, NULL_A, &(lesRelais[r]), DESACTIVE);
              break;
            }
          }
          break;
        case PORTAIL_AUTO : // commandeWeb.portail = ACTIVE, DESACTIVE, ACTIVE_TIMER, DESACTIVE_TIMER, NULL_R
          if(DEBUG) { // etatRelais = R_ACTIF, R_INACTIF, TIMER_ACTIF, TIMER_INACTIF
            Serial.print(F("* parseCommand => PORTAIL_AUTO => labelValue = "));
            Serial.println(labelValue);
          }
          for (uint8_t r = 0; r < NOMBREDERELAIS; r++) {
            if (strcmp(lesRelais[r].nomRelais, "Portail") == 0) {
              if (lesRelais[r].etat != TIMER_ACTIF) {
                affecteCommandeWeb(true, NULL, NULL_V, NULL, NULL_A, &(lesRelais[r]), ACTIVE_TIMER);
              }
              else if (lesRelais[r].etat == TIMER_ACTIF) {
                affecteCommandeWeb(true, NULL, NULL_V, NULL, NULL_A, &(lesRelais[r]), DESACTIVE_TIMER);
              }
              break;
            }
          }
          break;

serveur_machine_etats_7.334.zip (26.1 KB)


Pour l' arrosage , je n' ai pas encore trop reflechi a la question , mais le code actuel , fait deja pas mal des fonctions proposées par @J-M-L .

je ne pense pas cependant , avoir besoin de :

  • déclenchement manuel / arrêt manuel , bien que ce soit deja fait , et c ' est pas vraiment le plus difficile a gerer au cas ou .
  • déclenchement manuel / arrêt sur condition d'un capteur . a part pour le cas ou il se met a pleuvoir , pas tres interressant .

Le reste me parait essentiel .

Si il est inutile dans cette fonction tu le supprime du switch, mais tu le laisse dans l'énumération si il est utilisé ailleurs.

Merci pour ta reponse .

c ' est fait .

je ne vois pas comment je pourrais realiser une seule machine a etats directements qui gere tout cela a la fois .
Pour moi qui n' ai pas l' habitude c ' est trop . je n' arrive deja pas a realiser un shcema correct de cette machine alors ...

bref , pour commencer petit ( a mon niveau quoi :sweat_smile: ) , j' essaie dejà de mettre en place ce que j ' ai evoqué precedemment .

je sens que certain vont crier au loup , mais bon , je fais comme je peux :stuck_out_tongue:

voici ce que j ' ai tenter de faire cette apres-midi :

////*   Arrosage    *////
bool arrosageAutoON = false;
bool resetZoneArrosee;
uint8_t saison = 5;
enum t_saison : uint8_t {PRINTEMPS, ETE, AUTOMNE, HIVER};
enum t_commandeArrosage : uint8_t {MARCHE, ARRET, MARCHE_TOUT, ARRET_TOUT, TIMERR_A, AUTOMA, NULL_A};
enum t_etat : uint8_t {ACTIF, INACTIF, TIMER};//, AUTO
enum t_etat_auto : uint8_t {INITIAL, EN_ATTENTE, A_ACTIVER, EN_ARROSAGE, ARROSE};
struct t_arrosage { // "Arbres", "Bordures", "Fruitiers", "Haies", "Jardin", "Potager
  uint8_t     	  zone;				  	        //1 index
  const char* 	  nom;				  	        //2
  uint8_t     	  pinRelais;  			      //3
  t_etat	        etat;					          //4
  uint32_t		    timerArrosage;        	//5
  // mode auto :
  
  uint8_t     	  joursIntervalle;	    	//6
  bool     	  	  zoneArrosee;	    	    //7
  uint32_t      	heureDebutArrosage;			//8
  uint32_t		    dureeJusquaFinArrosage;	//9
  uint32_t		    timerProchainArrosage;  //10
  t_etat_auto     etat_auto;              //11

};
float coeffSaison = 1UL;
t_arrosage lesArrosages[] = {
// 1     2          3     4     5    6    7  8     9     10  11
  {0, "Arbres",    38, INACTIF, 0, false, 0, 0, TIMER_A, 0, INITIAL},
  {1, "Bordures",  39, INACTIF, 0, false, 0, 0, TIMER_A, 0, INITIAL},
  {2, "Fruitiers", 40, INACTIF, 0, false, 0, 0, TIMER_A, 0, INITIAL},
  {3, "Haies",     41, INACTIF, 0, false, 0, 0, TIMER_A, 0, INITIAL},
  {4, "Jardin",    42, INACTIF, 0, false, 0, 0, TIMER_A, 0, INITIAL},
  {5, "Potager",   43, INACTIF, 0, false, 0, 0, TIMER_A, 0, INITIAL}
};
const uint8_t NOMBREDARROSAGE = sizeof(lesArrosages) / sizeof(t_arrosage) , HEURE_RESET_A = 24;

//// Fonctions d ' arrosage : ////

void initialiserUnArrosage(t_arrosage* unArrosage) {
  pinMode(unArrosage->pinRelais, OUTPUT);
  digitalWrite(unArrosage->pinRelais, RELAIS_INACTIF); // à l'arret
  if (DEBUG) {
    Serial.print (F("* initialiserUnArrosage => PIN : "));
    Serial.println (unArrosage->pinRelais);
  }
}

//// mode manuel ////

void activerTimerArrosage (t_arrosage* unArrosage) {
  // si une tache existe deja , on la remplace par la nouvelle , donc , 1ere chose , on supprime la tache si elle existe deja .
  desactiverTimerArrosage(unArrosage->pinRelais);

  if (!gestionnaireDeTache.findAsyncCommand(unArrosage->pinRelais)) {
    gestionnaireDeTache.registerAsyncCommand(unArrosage->pinRelais, unArrosage->timerArrosage, desactiverArrosage);// normal le reinit ici : oui fonction de callback ( c ' est elle qui reinitialisera le relais a la fin du timer )
    if (DEBUG) {
      Serial.print (F("* activerTimerArrosage => tache "));
      Serial.print (unArrosage->pinRelais);
      Serial.print (F(" enregistrée pour dans "));
      Serial.println (unArrosage->timerArrosage);
    }
  }
}

// pour supprimer le timer lors de l' arret manuel d ' un arrosage si celui-ci a été activé
void desactiverTimerArrosage (uint8_t pin) {
  if (gestionnaireDeTache.findAsyncCommand(pin)) {
    gestionnaireDeTache.unregisterAsyncCommand(pin);
    if (DEBUG) {
      Serial.print (F("* desactiverTimerArrosage => tache : "));
      Serial.print (pin);
      Serial.println (F(" supprimee"));
    }
  }
  else { // gestion des doubles ID manuel / auto
    pin=pin+100;
    if (gestionnaireDeTache.findAsyncCommand(pin)) {
      gestionnaireDeTache.unregisterAsyncCommand(pin);
      if (DEBUG) {
        Serial.print (F("* desactiverTimerArrosage => tache : "));
        Serial.print (pin);
        Serial.println (F(" supprimee"));
      }
    }
  }
}


void gererUnArrosage(t_arrosage* unArrosage) {
  switch (unArrosage->etat) { // ACTIF, INACTIF, TIMER, AUTO
    case INACTIF : // MARCHE, ARRET, NULL_A, MARCHE_TOUT, ARRET_TOUT
      if ((commandeWeb.active) && (commandeWeb.arrosage == unArrosage)) {
        if (commandeWeb.actionCMD_A == MARCHE) {
          if (DEBUG) {
            Serial.print (F("* gererUnArrosage => case inactif => unArrosage-> zone : "));
            Serial.print (unArrosage->zone);
            Serial.print (F(", unArrosage->pinRelais : "));
            Serial.println (unArrosage->pinRelais);
          }
          activerUnArrosageEtUnTimer (unArrosage);
          commandeWeb.active = false;
        }
      }
      break;

    case ACTIF :
      if ((commandeWeb.active) && (commandeWeb.arrosage == unArrosage)) {
        if (commandeWeb.actionCMD_A == ARRET) {
          if (DEBUG) {
            Serial.print (F("* gererUnArrosage => case actif => unArrosage-> zone : "));
            Serial.print (unArrosage->zone);
            Serial.print (F(", unArrosage->pinRelais : "));
            Serial.println (unArrosage->pinRelais);
          }
          desactiverUnArrosageEtUnTimer(unArrosage);
          commandeWeb.active = false;
        }
      }
      break;
    case TIMER :
      if ((commandeWeb.active) && (commandeWeb.arrosage == unArrosage)) {
        if (commandeWeb.actionCMD_A == TIMERR_A) {
          inverserUnArrosageEtUnTimer(unArrosage);
          commandeWeb.active = false;
          if (DEBUG) {
            Serial.print (F("* gererUnArrosage => case TIMER => unArrosage-> zone : "));
            Serial.print (unArrosage->zone);
            Serial.print (F(", unArrosage->pinRelais : "));
            Serial.println (unArrosage->pinRelais);
          }
        }
      }
      break;
    /*case AUTO :
      if ((commandeWeb.active) && (commandeWeb.arrosage == unArrosage)) {
        if (commandeWeb.actionCMD_A == AUTOMA) {
          if (DEBUG) {
            Serial.print (F("* gererUnArrosage => case AUTOMA => unArrosage-> zone : "));
            Serial.print (unArrosage->zone);
            Serial.print (F(", unArrosage->pinRelais : "));
            Serial.println (unArrosage->pinRelais);
          }
          inverserUnArrosageEtUnTimer(unArrosage);
          //gererUn_A_A(unArrosage);
          commandeWeb.active = false;
        }
      }
      break;*/
    default:
      if (DEBUG) Serial.println (F("* gererUnArrosage => probleme = case non reconnu !"));
      break;
  } // fin switch
  // comme cette fonction est appellé en permanence , il vaut mieux eviter de mettre quoi que ce soit ici
}

void gererLesArrosages() {
  if (commandeWeb.active && commandeWeb.arrosage == NULL && commandeWeb.volet == NULL && commandeWeb.actionCMD_V == NULL_V) {
    if(commandeWeb.actionCMD_A == MARCHE_TOUT) for (uint8_t a = 0; a < NOMBREDARROSAGE; a++) activerUnArrosage(&(lesArrosages[a]));
    else if(commandeWeb.actionCMD_A == ARRET_TOUT) for (uint8_t a = 0; a < NOMBREDARROSAGE; a++) desactiverUnArrosage(&(lesArrosages[a]));
    else if (commandeWeb.actionCMD_A == AUTOMA) {
      for (uint8_t a = 0; a < NOMBREDARROSAGE; a++) gererUn_A_A(&(lesArrosages[a]));
      /*if (arrosageAutoON) for (uint8_t a = 0; a < NOMBREDARROSAGE; a++) initialArrosageAuto(&(lesArrosages[a]));
      else for (uint8_t a = 0; a < NOMBREDARROSAGE; a++) desactiverUnArrosageEtUnTimer(&(lesArrosages[a]));*/
    }
    commandeWeb.active=false;
  }
  else for (uint8_t a = 0; a < NOMBREDARROSAGE; a++) gererUnArrosage(&(lesArrosages[a]));
}
/*		mode manuel		*/

/***************************************************************************************************************/
/*		mode auto		*/
void gererUn_A_A(t_arrosage* unArrosage) {
  if (arrosageAutoON) {
    switch (unArrosage->etat_auto) { // INITIAL, EN_ATTENTE, A_ACTIVER, EN_ARROSAGE, ARROSE
      case INITIAL:
        initialArrosageAuto(unArrosage);
        //unArrosage->etat_auto=EN_ATTENTE;
        break;
      case EN_ATTENTE:
        attenteUnArrosageAuto(unArrosage);
        //unArrosage->etat_auto=A_ACTIVER;
        break;
      case A_ACTIVER:
        marcheArrosageAuto(unArrosage->pinRelais+100);
        //unArrosage->etat_auto=EN_ARROSAGE;
        break;
      case EN_ARROSAGE:
        //unArrosage->etat_auto=ARROSE;
        break;
      case ARROSE:
        //unArrosage->etat_auto=EN_ATTENTE;
        break;
      default:
        break;
    }
  }
}

void initialArrosageAuto (t_arrosage* unArrosage) {
  // objectif lancer les taches auto a intervalles reguliers
  // et remplir la structure et tableau arrosage avec les valeurs pour travailler

  static uint8_t initialAutoA = NOMBREDARROSAGE;
  if (arrosageAutoON && initialAutoA) {
    uint8_t ID100 = unArrosage->pinRelais + 100;
    calculDataArrosageAuto(unArrosage);
    gestionnaireDeTache.registerAsyncCommand(ID100, TIMER_V, marcheArrosageAuto); // initialisation autonome : ID100 = pin + 100
    unArrosage->etat_auto=EN_ATTENTE;
    // on active une nouvelle tache ayant pour id le numero de pin + 100 / un temps de 30 secondes / et la fonction automatique d ' arrosage pour callback .
  // NOTE : on n ' active pas les relais ici , il s' agist juste de lancer la tache apres l' intervalle defini .
    if (DEBUG) {
      Serial.print (F("* initialArrosageAuto => effectue sur zone : "));
      Serial.print (unArrosage->zone);
      Serial.print (F(", unArrosage->etat_auto : "));
      Serial.print (unArrosage->etat_auto);
      Serial.print (F(". tache d ' arrosage principale enclenchée dans "));
      Serial.print (TIMER_V);
      Serial.print (F(". ID100 : "));
      Serial.print (ID100);
      Serial.print (F(" sur pin correspondant : "));
      Serial.print (unArrosage->pinRelais);
      Serial.print (F(", unArrosage->joursIntervalle : "));
      Serial.print (unArrosage->joursIntervalle);
      Serial.print (F(", unArrosage->timerProchainArrosage : "));
      Serial.println (unArrosage->timerProchainArrosage);

    }
  initialAutoA--;
  }
}

void attenteUnArrosageAuto(t_arrosage* unArrosage) {
  while (RTC.heure() < unArrosage->heureDebutArrosage) {
    if (unArrosage->etat_auto != A_ACTIVER) unArrosage->etat_auto = A_ACTIVER;
    // on poireaute
  }
  // quand c ' est ok , on lance la tache asynchrone d ' arrosage
  //marcheArrosageAuto(unArrosage->pinRelais+100);
  gererUn_A_A(unArrosage);
}

void marcheArrosageAuto (t_commandID ID100) { // ID100 est le numero de pin +100 , pas un index du tableau
  uint8_t pin = ID100-100;

  for (uint8_t a = 0; a < NOMBREDARROSAGE; a++) {
    if (lesArrosages[a].pinRelais == pin && lesArrosages[a].etat_auto != EN_ARROSAGE) {
        lesArrosages[a].zoneArrosee = false;
        lesArrosages[a].etat = ACTIF;
        lesArrosages[a].etat_auto = EN_ARROSAGE;
        if (!TEST) digitalWrite (lesArrosages[a].pinRelais , RELAIS_ACTIF);
        gestionnaireDeTache.registerAsyncCommand(ID100, lesArrosages[a].dureeJusquaFinArrosage, resetTimerArrosageAuto);
        // on utilise ID100 pour les taches automatiques / la durée de l' arrosage desirée / la fonction qui arretera le relais ( et l' arrosage donc ) et qui lancera le prochain arrosage a l 'heure desirée .
        if (DEBUG) {
          Serial.print (F("* marcheArrosageAuto => tache arrosageAuto id100 : "));
          Serial.print (ID100);
          Serial.print (F(" lance pendant "));
          Serial.print (lesArrosages[a].dureeJusquaFinArrosage/1000);
          Serial.print (F(" secondes , sur le pin : "));
          Serial.println (lesArrosages[a].pinRelais);
        }
      //else resetTimerArrosageAuto (ID100);
    }
    break;
  }
}

void resetTimerArrosageAuto (t_commandID ID100) { // permet de relancer le prochain arrosage automatique
  // ID100 est le numero de pin +100 , pas un index du tableau
  uint8_t pin = ID100-100;

  for (uint8_t a = 0; a < NOMBREDARROSAGE; a++) {
    if (lesArrosages[a].pinRelais == pin && lesArrosages[a].etat_auto == EN_ARROSAGE) {
        resetZoneArrosee = true; // permet de reinitialiser les zones arrosées de la journée
        lesArrosages[a].zoneArrosee = true;
        if (!TEST) digitalWrite(lesArrosages[a].pinRelais, RELAIS_INACTIF);
        lesArrosages[a].etat = INACTIF;
        lesArrosages[a].etat_auto = ARROSE;

        if (DEBUG) {
          Serial.print (F("* resetTimerArrosageAuto => zoneArrosee "));
          Serial.print (a);
          Serial.print (F(" = "));
          Serial.println (lesArrosages[a].zoneArrosee);
      }
    }
    break;
  }
}

void retourEnAttenteAuto(t_commandID ID100) {
  // ID100 est le numero de pin +100 , pas un index du tableau
  uint8_t pin = ID100-100;
  
  if (arrosageAutoON) {
    for (uint8_t a = 0; a < NOMBREDARROSAGE; a++) {
      if (lesArrosages[a].pinRelais == pin && lesArrosages[a].etat_auto == ARROSE) {
        calculDataArrosageAuto(&(lesArrosages[a]));
        gestionnaireDeTache.registerAsyncCommand(ID100, lesArrosages[a].timerProchainArrosage, marcheArrosageAuto); // tourne en boucle , enregistre le prochain arrosage differe
          // on active une nouvelle tache ayant pour id le numero de pin + 100 / le timer pour relancer le prochain arrosage / et la fonction automatique d ' arrosage pour callback .
        if (DEBUG) {
          Serial.print (F("* resetTimerArrosageAuto => Nouvelle tache enregistrée ayant pour ID : "));
          Serial.print (ID100);
          Serial.print (F(" pour durée :"));
          Serial.println (lesArrosages[a].timerProchainArrosage);
        }
        break;
      }
    }
  }
  else {
    gestionnaireDeTache.unregisterAsyncCommand(ID100);
    if (DEBUG) Serial.print (F("* resetTimerArrosageAuto => tache supprimée ! "));
  }
}

void resetZoneArrosage () { // on reinitialise les zones arrosées pour le lendemain
  if (resetZoneArrosee && (RTC.heure() >= HEURE_RESET_A)) {
    resetZoneArrosee = false;
    for (uint8_t a = 0; a < NOMBREDARROSAGE; a++) lesArrosages[a].zoneArrosee = false;
    if (DEBUG) Serial.println (F("resetZoneArrosee => zones reinitialisees !"));
  }
}

//// Fonctions de calculs : ////
void setSaison(t_commandID identifier) {	// Gere le mode HORSGEL_ON  *///////
  if ((RTC.mois() == 3 && RTC.jour() >= 20) || RTC.mois() ==  4 || RTC.mois() == 5 || (RTC.mois() == 6 && RTC.jour() < 20)) saison = PRINTEMPS;
  else if ((RTC.mois() == 6 && RTC.jour() >= 20) || RTC.mois() == 7  || RTC.mois() == 8  || (RTC.mois() == 9 && RTC.jour() < 22)) saison = ETE;
  else if ((RTC.mois() == 9 && RTC.jour() >= 22) || RTC.mois() == 10 || RTC.mois() == 11 || (RTC.mois() == 12 && RTC.jour() < 21)) saison = AUTOMNE;
  else if ((RTC.mois() == 12 && RTC.jour() >= 21) || RTC.mois() ==  1 || RTC.mois() == 2 || (RTC.mois() == 3 && RTC.jour() < 20)) saison = HIVER;

  if (saison != 5) { // initialisation a 5 expres .
    gestionnaireDeTache.registerAsyncCommand(identifier, 12 * TIMER_A, setSaison); // verifie 24 H apres si la saison n' a pas changé , ID 98
    if (DEBUG) {
        Serial.print (F("* setSaison => saison = "));
        Serial.println (saison);
      }
  }
  else {
    gestionnaireDeTache.registerAsyncCommand(identifier, TIMER_V, setSaison); // on recommence dans 30 secondes .
    if (DEBUG) {
      Serial.print (F("* setSaison => saison = ERREUR !"));
    }
  }
}

void calculDataArrosageAuto (t_arrosage* unArrosage) {	// l ' objectif est d ' espacer a intervalle de jours reguliers les arrosages des differentes zones en fonctions des saisons et de la zone a arroser
  uint8_t nbJours = 0;
  uint8_t HDA=0;
  uint32_t convertJoursToMs = 24UL*60UL*60UL*1000UL; // Conversion en millisecondes

  switch (saison) {
    case PRINTEMPS :
      coeffSaison = 1;
      if (strcmp(unArrosage->nom, "Arbres") == 0 || strcmp(unArrosage->nom, "Fruitiers") == 0) {
        nbJours = 7;
      }
      else if (strcmp(unArrosage->nom, "Haies") == 0 || strcmp(unArrosage->nom, "Jardin") == 0)	{
        nbJours = 5 ;
      }
      else if (strcmp(unArrosage->nom, "Bordures") == 0 || strcmp(unArrosage->nom, "Potager") == 0)	{
        nbJours = 2;
      }
      HDA=5;
        break;

    case ETE :
      coeffSaison=1.5;
      if (strcmp(unArrosage->nom, "Arbres") == 0 || strcmp(unArrosage->nom, "Fruitiers") == 0)	{
        nbJours = 4;
      }
      else if (strcmp(unArrosage->nom, "Haies") == 0 || strcmp(unArrosage->nom, "Jardin") == 0)	{
        nbJours = 3;
      }
      else if (strcmp(unArrosage->nom, "Bordures") == 0 || strcmp(unArrosage->nom, "Potager") == 0)	{
        nbJours = 1;
      }
      HDA=0;
      break;

    case AUTOMNE :
      coeffSaison=1;
      if (strcmp(unArrosage->nom, "Arbres") == 0 || strcmp(unArrosage->nom, "Fruitiers") == 0) {
        nbJours = 7; // utile pour lancer le prochain arrosage via asynctask.
      }
      else if (strcmp(unArrosage->nom, "Haies") == 0 || strcmp(unArrosage->nom, "Jardin") == 0)	{
        nbJours = 5 ;
      }
      else if (strcmp(unArrosage->nom, "Bordures") == 0 || strcmp(unArrosage->nom, "Potager") == 0)	{
        nbJours = 2;
      }
      HDA=6;
      break;

    case HIVER : // voir avec temperature exterieure , si risque de gel , a desactiver
      coeffSaison=0.5;
      nbJours = 21;
      HDA=12;
      break;

    default:
      if (DEBUG) Serial.println(F("* => calculIntervalleJoursArrosage : ERREUR !!!"));
      break;
  }
  unArrosage->dureeJusquaFinArrosage = (TIMER_A * coeffSaison);
  unArrosage->joursIntervalle = nbJours;
  unArrosage->timerProchainArrosage = convertJoursToMs * nbJours;
  unArrosage->heureDebutArrosage = HDA;
  unArrosage->zoneArrosee = false;

  if (DEBUG) {
    Serial.print(F("* => calculIntervalleJoursArrosage : nbJours = "));
    Serial.print(nbJours);
    Serial.print(F(" , coeffSaison = "));
    Serial.print(coeffSaison);
    Serial.print(F(" , heureDebutArrosage = "));
    Serial.print(unArrosage->heureDebutArrosage);
    Serial.print(F(" , tempsDArrosage = "));
    Serial.println(unArrosage->dureeJusquaFinArrosage);
  }
}

/*		mode auto		*/
//// FIN des Fonctions d ' arrosage : ////

Bon , je previens desuite , ca compile mais ca ne fonctionne pas .
c ' est surtout pour verifier avec vous que au niveau de la demarche ca semble coherent au projet ennoncé ci-dessus .

Apres activation de l' arrosage automatique sur la page web , j ' obtiens tout de meme dans la moniteur serie :

18:19:56.947 -> labelIndex  = 8
18:19:56.947 -> labelValue = -1
18:19:56.947 -> * => calculIntervalleJoursArrosage : nbJours = 21 , coeffSaison = 0.50 , heureDebutArrosage = 12 , tempsDArrosage = 3600000
18:19:56.947 -> * initialArrosageAuto => effectue sur zone : 0, unArrosage->etat_auto : 1. tache d ' arrosage principale enclenchée dans 30000. ID100 : 138 sur pin correspondant : 38, unArrosage->joursIntervalle : 21, unArrosage->timerProchainArrosage : 1814400000
18:19:56.979 -> * => calculIntervalleJoursArrosage : nbJours = 21 , coeffSaison = 0.50 , heureDebutArrosage = 12 , tempsDArrosage = 3600000
18:19:56.979 -> * initialArrosageAuto => effectue sur zone : 1, unArrosage->etat_auto : 1. tache d ' arrosage principale enclenchée dans 30000. ID100 : 139 sur pin correspondant : 39, unArrosage->joursIntervalle : 21, unArrosage->timerProchainArrosage : 1814400000
18:19:57.011 -> * => calculIntervalleJoursArrosage : nbJours = 21 , coeffSaison = 0.50 , heureDebutArrosage = 12 , tempsDArrosage = 3600000
18:19:57.011 -> * initialArrosageAuto => effectue sur zone : 2, unArrosage->etat_auto : 1. tache d ' arrosage principale enclenchée dans 30000. ID100 : 140 sur pin correspondant : 40, unArrosage->joursIntervalle : 21, unArrosage->timerProchainArrosage : 1814400000
18:19:57.043 -> * => calculIntervalleJoursArrosage : nbJours = 21 , coeffSaison = 0.50 , heureDebutArrosage = 12 , tempsDArrosage = 3600000
18:19:57.043 -> * initialArrosageAuto => effectue sur zone : 3, unArrosage->etat_auto : 1. tache d ' arrosage principale enclenchée dans 30000. ID100 : 141 sur pin correspondant : 41, unArrosage->joursIntervalle : 21, unArrosage->timerProchainArrosage : 1814400000
18:19:57.074 -> * => calculIntervalleJoursArrosage : nbJours = 21 , coeffSaison = 0.50 , heureDebutArrosage = 12 , tempsDArrosage = 3600000
18:19:57.106 -> * initialArrosageAuto => effectue sur zone : 4, unArrosage->etat_auto : 1. tache d ' arrosage principale enclenchée dans 30000. ID100 : 142 sur pin correspondant : 42, unArrosage->joursIntervalle : 21, unArrosage->timerProchainArrosage : 1814400000
18:19:57.106 -> * => calculIntervalleJoursArrosage : nbJours = 21 , coeffSaison = 0.50 , heureDebutArrosage = 12 , tempsDArrosage = 3600000
18:19:57.106 -> * initialArrosageAuto => effectue sur zone : 5, unArrosage->etat_auto : 1. tache d ' arrosage principale enclenchée dans 30000. ID100 : 143 sur pin correspondant : 43, unArrosage->joursIntervalle : 21, unArrosage->timerProchainArrosage : 1814400000
18:19:57.138 -> * parseCommand => ARROSAGE => AUTO : ON
18:20:00.601 -> labelIndex  = 8
18:20:00.601 -> labelValue = -1
18:20:00.601 -> * parseCommand => ARROSAGE => AUTO : OFF
18:20:26.973 -> * marcheArrosageAuto => tache arrosageAuto id100 : 138 lance pendant 3600 secondes , sur le pin : 38

Là j ' ai besoin d ' une bonne pause ...

Il n'y a aucune obligation, c'est si tu as le temps et l'envie d'améliorer ton code.
bon après il faudra me croire sur parole et que ce n'est pas forcément facile à croire :slight_smile:
Mais tu y gagnerais en temps à faire un petit effort au départ. Car ton sac de nœud sera forcément plus difficile à debugger et encore plus à modifier par la suite.

Ton code est assez complexe, il n'est pas forcément facile de voir les problèmes justes à la lecture.
Peut tu dire ce qui ne fonctionne pas et à quoi tu t'attendrais comme sortie sur le moniteur.

Bonjour , pour essayer d' expliquer ce que j' ai fais .
j ' ai ajouter une enumeration des etats automatique et une fonction qui gerer donc les etats auto .
puis j' ai modifier les fonctions deja existantes pour qu ' elle gere les etats auto .

je n ' ai certainement toujours pas compris comment vraiment structuré parfaitement le code de façon a coller au principe de la machine a etats ...

De plus , de façon a simplifier les choses , il faut soit que je laisse tomber asynctask ( pour utiliser millis() et les pointeurs ) , ou bien que je laisse tomber les pointeurs dans les fonctions pour cette partie de code , car la transmission des parametres de fonction posent un soucis entre les formes pointeurs et les forment ID100 ( pour utiliser asyncTask ) .

sinon , ca resoudrait potentiellement ce soucis , comment transformer un pointeur sur pinrelais en un int ?

EDIT , bon finalement j ' ai reecris les fonctions posant probleme et pense avoir trouver une solution :

void marcheArrosageAuto(t_arrosage* unArrosage) {
  if (unArrosage->etat_auto != EN_ARROSAGE) {
    unArrosage->zoneArrosee = false;
    unArrosage->etat = ACTIF;
    unArrosage->etat_auto = EN_ARROSAGE;
    if (!TEST) digitalWrite(unArrosage->pinRelais, RELAIS_ACTIF);
    gestionnaireDeTache.registerAsyncCommand(unArrosage->pinRelais, unArrosage->dureeJusquaFinArrosage, desactiverArrosage);
    // on utilise pin pour les taches automatiques / la durée de l' arrosage desirée / la fonction qui arretera le relais ( et l' arrosage donc ) et qui lancera le prochain arrosage a l 'heure desirée .
    if (DEBUG) {
      Serial.print(F("* marcheArrosageAuto => tache arrosageAuto lance pendant "));
      Serial.print(unArrosage->dureeJusquaFinArrosage / 1000);
      Serial.print(F(" secondes , sur le pin : "));
      Serial.println(unArrosage->pinRelais);
    }
  }
}

void resetTimerArrosageAuto(t_arrosage* unArrosage) {  // permet de relancer le prochain arrosage automatique
  if (unArrosage->etat_auto != ARROSE) {
    resetZoneArrosee = true;  // permet de reinitialiser les zones arrosées de la journée
    unArrosage->zoneArrosee = true;
    if (!TEST) digitalWrite(unArrosage->pinRelais, RELAIS_INACTIF);
    unArrosage->etat = INACTIF;
    unArrosage->etat_auto = ARROSE;

    if (DEBUG) {
      Serial.print(F("* resetTimerArrosageAuto => zoneArrosee "));
      Serial.print(unArrosage->nom);
      Serial.print(F(" = "));
      Serial.println(unArrosage->zoneArrosee);
    }
  }
}

void retourEnAttenteAuto(t_arrosage* unArrosage) {
  if (arrosageAutoON) {
      if (unArrosage->etat_auto != EN_ATTENTE) {
        calculDataArrosageAuto(unArrosage);
        //gestionnaireDeTache.registerAsyncCommand(unArrosage->pinRelais, unArrosage->timerProchainArrosage, attenteUnArrosageAuto);  // tourne en boucle , enregistre le prochain arrosage differe
          // on active une nouvelle tache ayant pour id le numero de pin + 100 / le timer pour relancer le prochain arrosage / et la fonction automatique d ' arrosage pour callback .
        if (DEBUG) {
          Serial.print(F("* resetTimerArrosageAuto => Nouvelle tache enregistrée ayant pour ID : "));
          Serial.print(unArrosage->pinRelais);
          Serial.print(F(" pour durée :"));
          Serial.println(unArrosage->timerProchainArrosage);
        }
    }
  } else {
    gestionnaireDeTache.unregisterAsyncCommand(unArrosage->pinRelais);
    if (DEBUG) Serial.print(F("* resetTimerArrosageAuto => tache supprimée ! "));
  }
}

j ' ai aussi viré ID100 qui en fait ne sert a rien ( enfin il me semble ) .

Apres quelques nouvelles modifications , je me rends compte que proceder de la façon dont j' essaie de faire fonctionner le truc , au final ca donne :

      for (uint8_t a = 0; a < NOMBREDARROSAGE; a++) gererUnArrosage(&(lesArrosages[a]));
      if (arrosageAutoON) for (uint8_t a = 0; a < NOMBREDARROSAGE; a++) gererUn_A_A(&(lesArrosages[a]));

Forcement c ' est donc pas une bonne idée , @J-M-L a encore raison :stuck_out_tongue:
il ne faut faire qu ' une seule et unique machine pour gerer tout ca ...

Du coup il va falloir que je creuse un peu plus pour au moins trouver un schema partiquemment bon .

On en vient toujours à la même chose, pourquoi t'embêter avec les pointeurs et un ID100, alors que utiliser partout l'indice de ton tableau serait bien plus simple.
Tu aurait accès partout à l'élément de ton tableau et tu peux passer cet indice en paramètre de la callback asynctask

Oui vouloir gérer les états dans un tas de fonction qui font aussi les actions est plus difficile à suivre.
Dans un machine à état, un état décris un état pas forcément une action :slight_smile:

En tous cas cela semble bien avancé même si tu ne vois pas vraiment de progrès sur le fonctionnement, j'ai quand même l'impression que tu structure de mieux en mieux ton programme :slight_smile:

les pointeurs ou un indice tableau ca ne change pas grand chose je pense , a part eviter de faire des boucles a chaque fois dans le code , avec les pointeurs elle se fait en permanence si j' ai bien compris et s' active automatiquement lors d ' un changement d' etat .

l ' ID 100 je l' ai completement viré . ca paraissait utile avant , mais maintenant plus .

il ne reste plus qu ' a faire une " vraie " machine a etats complete " .
Sauf que je ne vois pas trop comment y inclure les " boutons manuels " ( actions manuelles ? ) dedans celle automatique .
le schema est donc indispensable pour pouvoir ensuite coder tout ca .
Alors je suppose que pour certains ca doit etre simple , mais j ' ai du mal a visionner la chose surtout au niveau des etats auto / manuels , j ' essaierai ce soir de faire un vrai schema qui inclue les actions manuelles .
comment faire la distinction entre manuel et auto ? y en a til besoin seulement ?

est ce que pourrais simplement fusionner les enumerations etats et etats_auto de arrosage ?

voici un nouveau schema de la machine , qu ' en pensez vous ?