Serveur relais interactif ( volets roulants + arrosage )

ben faut pas mettre le tableau à deux dimensions: j'ai proposé 1 seule dimensionconst  char* daysOfTheWeek[] = {"Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi"};et il ne devrait pas y avoir de souci avec cette approche (et vous gagnez de la mémoire)

Pour le code d'une manière générale j'évite de tester un moment "exact" pour déclencher quelque chose comme vous le faites avec   if ( 0 == now.hour() && 0 == now.minute()) { // si on est a 0 h et 0 min => en heures creuse .dans l'absolu ici vous avez une minute pour que le test soit valide, donc il y a de fortes chances pour que vous ne ratiez pas le moment, mais de manière générale je préfère mémoriser le fait que je n'ai pas encore déclenché et tester avec une inégalité "si nous sommes après tel moment et que je n'ai pas encore fait le job, alors....". Comme cela vous pouvez régler un déclenchement à la milliseconde si vous voulez, quand le code fait le test c'est pris en compte même si vous aviez eu des délais par ailleurs.

sinon d'un point de vue syntaxique, un booléen est une valeur de vérité en soi, donc pas besoin de == dans un if, on n'écrit pasif (Pluie() == false) {mais if (! Pluie()) {

De même on essaye d'éviter les constantes magiques, donc je déclarerais un enum : uint8_t {DIMANCHE, LUNDI, MARDI, MERCREDI, JEUDI, VENDREDI, SAMEDI};de façon à pouvoir faire dans le switch

 switch (now.dayOfTheWeek()) {
          case DIMANCHE:
            MarcheArretArrosage ( tempsOFF , 0 ); // arrose la zone Arbres
            break;
          case LUNDI:
            MarcheArretArrosage ( tempsOFF , 1 ); // arrose la zone Bordures
            MarcheArretArrosage ( tempsOFF , 5 ); // arrose la zone Potager
            break;
          case MARDI:
            MarcheArretArrosage ( tempsOFF , 2 ); // arrose la zone Fruitiers
            break;
...

J-M-L:
ben faut pas mettre le tableau à deux dimensions: j'ai proposé 1 seule dimension

const  char* daysOfTheWeek[] = {"Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi"};

et il ne devrait pas y avoir de souci avec cette approche (et vous gagnez de la mémoire)

Pour le code d'une manière générale j'évite de tester un moment "exact" pour déclencher quelque chose comme vous le faites avec

 if ( 0 == now.hour() && 0 == now.minute()) { // si on est a 0 h et 0 min => en heures creuse .

dans l'absolu ici vous avez une minute pour que le test soit valide, donc il y a de fortes chances pour que vous ne ratiez pas le moment, mais de manière générale je préfère mémoriser le fait que je n'ai pas encore déclenché et tester avec une inégalité "si nous sommes après tel moment et que je n'ai pas encore fait le job, alors....". Comme cela vous pouvez régler un déclenchement à la milliseconde si vous voulez, quand le code fait le test c'est pris en compte même si vous aviez eu des délais par ailleurs.

sinon d'un point de vue syntaxique, un booléen est une valeur de vérité en soi, donc pas besoin de == dans un if, on n'écrit pas

if (Pluie() == false) {

mais

if (! Pluie()) {

De même on essaye d'éviter les constantes magiques, donc je déclarerais un

enum : uint8_t {DIMA?CHE, LUNDI, MARDI, MERCREDI, JEUDI, VENDREDI, SAMEDI};

de façon à pouvoir faire dans le switch

 switch (now.dayOfTheWeek()) {

case DIMACHE:
           MarcheArretArrosage ( tempsOFF , 0 ); // arrose la zone Arbres
           break;
         case LUNDI:
           MarcheArretArrosage ( tempsOFF , 1 ); // arrose la zone Bordures
           MarcheArretArrosage ( tempsOFF , 5 ); // arrose la zone Potager
           break;
         case MARDI:
           MarcheArretArrosage ( tempsOFF , 2 ); // arrose la zone Fruitiers
           break;
...

j ' ai suivi vos conseils pour les modifications , ca rend le code plus leger , plus agreable et aussi plus facile a lire ,

pour le tableau a 2 dimensions , ca ne veut pas marcher , mais le code c ' est pas moi qui l' ai ecrit , il est tiré de l' example de la bibliotheque RTClib.h

J ' ai du ajouter un tableau de booleens pour marquer les zones arrosées , et eviter les repetitions , j ' ai aussi supprimer le flag arrosageON , j ' utilise a la place l' etat du relais haut bas comme un booleen dans les comparaisons .

voilà ce que ca donne maintenant :

//// Fonctions d ' arrosage : ////
void MarcheArretArrosage ( const unsigned long tempsOFF , byte zone ) { // met en route et arrete en fonction de tempsON et tempsOFF .

 byte numRelais = RELAY_NUMBER_V + zone; // pour faire correspondre la zone d' arrosage aux numeros de relais correspondants

 if ( tableau_Etat_Relais [numRelais]  && ! zoneArrosee[zone] ) { // si l ' arrosage est arrete pour la zone
 chrono = millis(); // demarrage du chrono pour l' arret
 activeRelais (numRelais); // met en route l ' arrosage de la zone concernée
 //tableau_Etat_Relais[numRelais] = LOW; // TEST l ' affichage sur le serveur  sans activer le relais
 
 //MsTimer2::start();
 }

 if ( ! zoneArrosee[zone] && ! tableau_Etat_Relais [numRelais]  && millis() - chrono > tempsOFF) { // on arrete l ' arrosage
 zoneArrosee[zone] = 1; // la zone correspondante est marquee comme arosee
 reInitRelais (numRelais); // on descative le relais et l ' affichage correspondant
 //tableau_Etat_Relais[numRelais] = HIGH; // TEST l ' affichage sur le serveur  sans activer le relais
 //MsTimer2::stop();
 }

}

void arrosage_autonome () { // gere l ' arrosage automatiquement
// l ' objectif est de verifier a minuit , si il est neccessaire d' arroser ou pas , donc verification de la pluie , si il ne pleut pas , on verifie l ' humidité du sol .
// si il est necessaire  , en fonction du jour de la semaine on active une ou plusieurs zones pendant un temps donné .

// Arbres= 0, Bordures = 1, Fruitiers = 2, Haies = 3, Jardin = 4, Potager = 5 .
//  tempsOFF et tempsON sont a 1 minute ! utiliser des multiples  => tempsOFF*60 = 1 heure .

 DateTime now = rtc.now(); // recupere toutes les infos du RTC .
 const byte FIN_HEURE_CREUSE = 6;
 enum : uint8_t {DIMANCHE, LUNDI, MARDI, MERCREDI, JEUDI, VENDREDI, SAMEDI};
 enum : uint8_t {Arbres, Bordures, Fruitiers, Haies, Jardin, Potager};
 
 // reset le tableau chaque jour , afin de pouvoir arroser 2 jours desuite la meme zone si besoin
 if ( now.hour() >  FIN_HEURE_CREUSE + 14 ) {
 for ( byte i = 0; i < RELAY_NUMBER_A; i++ ) {
 zoneArrosee [i] = 0;
 }
 }

 //if ( ! Pluie() && read_Humidity_sensor() >= 50 &&  now.hour() < FIN_HEURE_CREUSE) { // si l ' humidité du sol , qu ' il ne pleut pas et qu on est en heure creuse
 if ( 1  ) { // pour tester seulement si le reste fonctionne sans toucher aux autres conditions

 switch (now.dayOfTheWeek()) {
 case DIMANCHE :
 if ( ! zoneArrosee [ Arbres ] ) MarcheArretArrosage ( tempsOFF , Arbres );
 break;
 case LUNDI :
 if ( ! zoneArrosee [ Bordures ] ) MarcheArretArrosage ( tempsOFF , Bordures );
 break;
 case MARDI :
 if ( ! zoneArrosee [ Fruitiers ] ) MarcheArretArrosage ( tempsOFF , Fruitiers );
 break;
 case MERCREDI :
 if ( ! zoneArrosee [ Haies ] ) MarcheArretArrosage ( tempsOFF , Haies );
 break;
 case JEUDI :
 if ( ! zoneArrosee [ Jardin ] ) MarcheArretArrosage ( tempsOFF , Jardin );
 break;
 case VENDREDI :
 if ( ! zoneArrosee [ Potager ] ) MarcheArretArrosage ( tempsOFF , Potager );
 break;
 case SAMEDI :
 if ( ! zoneArrosee [ Haies ] ) MarcheArretArrosage ( tempsOFF , Haies );
 break;

 default:
 break;
 } // fin du switch

 }

}
//// FIN des Fonctions d ' arrosage : ////

j ' ai poussé le vice avec un enum de + pour les zones , ca fait desuite plus humain pour lire ce switch ;D

Merci beaucoup pour vos conseils toujours avises ! 8)

je met le code en PJ , a peu pres nettoyé et revu aux conseils de J-M-L .

PS : une interruption sert generalement a quoi ? et dans quel cas on l ' utilise ?

serveur_volet_arrosage_RTC.v6.1.ino (29.5 KB)

Ce n'est pas que vous ne pouvez pas utiliser une interruption pour votre idée, mais que c'est généralement fait pour un truc hyper rapide, qui interrompt le cours normal du programme et ensuite on revient comme si de rien n'était. là vous comptez modifier sensiblement l'état du système pendant l'interruption donc ça pourrait prendre du temps et pendant ce temps les interruptions sont suspendues, millis() n'avance plus etc..

Si vous vous perdez dans les millis() etc, je vais essayer de retrouver une petite classe qui gère des callBacks "plus tard". ça simplifie la vie :slight_smile:

pour le tableau a 2 dimensions , ca ne veut pas marcher , mais le code c ' est pas moi qui l' ai ecrit , il est tiré de l' example de la bibliotheque RTClib.h

c'est quoi l'erreur ? ce tableau n'est que dans votre code, donc la bibliothèque ne joue pas.

c ' etait la premiere fois que je mettais en place un chrono avec la fonction millis () , vu qu ' avant j' etais tombé sur MsTimer 2 :stuck_out_tongue: pour les volets roulants notemment ...

les callback , j ' ai vu ca rapidement en python pour mon pi , c ' est parfois un peu tendu :disappointed_relieved: , si y a une classe biblio library qui simplifie tout ca et qu ' elle est facile a maitrise et mettre en oeuvre , je suis preneur :wink:

iznobe:
les callback , j ' ai vu ca rapidement en python pour mon pi , c ' est parfois un peu tendu :disappointed_relieved: , si y a une classe biblio library qui simplifie tout ca et qu ' elle est facile a maitrise et mettre en oeuvre , je suis preneur :wink:

j'ai posté un truc ici qui devrait vous simplifier la vie

ouahhh , pas mal du tout !!!

c ' est pratiquement pareil , mais en mieux :smiley: et on peut meme passer un parametre identifier !!! coolll ca

juste une question a propos de la callback 2 pourquoi celle-ci est remanente ? alors que les 2 autres non ?

a cause de l ' imbrication ou j ' ai loupé un truc ?

Cf dans l’autre post

Salut , c ' est exactement ce dont j ' avais besoin pour faire mon arrosage autonome !

voilà apres implementation " basique " du gestionnaire de tache ce que ca donne :

//// Fonctions d ' arrosage : ////
void MarcheArretArrosage ( byte zone , const unsigned long tempsOFF ) { // met en route et arrete en fonction de tempsON et tempsOFF .
	byte numRelais = zone + RELAY_NUMBER_V; // pour faire correspondre la zone d' arrosage aux numeros de relais correspondants
	
	if ( tableau_Etat_Relais [ numRelais ]  && ! zoneArrosee[ zone ] ) { // si l ' arrosage est arrete pour la zone
		//gestionnaireDeTache.registerAsyncCommand( zone, TIMER_A, resetArrosage );
		chrono = millis(); // demarrage du chrono pour l' arret
		activeRelais (numRelais); 	// met en route l ' arrosage de la zone concernée
		//tableau_Etat_Relais[numRelais] = LOW; // TEST l ' affichage sur le serveur  sans activer le relais
		//gestionnaireDeTache.registerAsyncCommand( zone, TIMER_A, MarcheArretArrosage );
	}
	if ( ! zoneArrosee[zone] && ! tableau_Etat_Relais [numRelais]  && millis() - chrono > tempsOFF) {	// on arrete l ' arrosage
		zoneArrosee[zone] = 1; // la zone correspondante est marquee comme arosee
		reInitRelais (numRelais); // on descative le relais et l ' affichage correspondant
		//tableau_Etat_Relais[numRelais] = HIGH; // TEST l ' affichage sur le serveur  sans activer le relais
	}
}

void MarcheArrosage ( byte zone , const unsigned long tempsOFF ) { // met en route et arrete en fonction de tempsON et tempsOFF .
	byte numRelais = zone + RELAY_NUMBER_V; // pour faire correspondre la zone d' arrosage aux numeros de relais correspondants

	if ( tableau_Etat_Relais [ numRelais ]  && ! zoneArrosee[ zone ] ) { // si l ' arrosage est arrete pour la zone
		gestionnaireDeTache.registerAsyncCommand( numRelais , tempsOFF , resetArrosage );
		activeRelais ( numRelais ); 	// met en route l ' arrosage de la zone concernée
		//gestionnaireDeTache.registerAsyncCommand( zone, TIMER_A, MarcheArretArrosage );
	}
}

void resetArrosage ( t_commandID identifier ) {
	zoneArrosee[ identifier - RELAY_NUMBER_V ] = 1; // la zone correspondante est marquee comme arosee
	reInitRelais (identifier); // on descative le relais et l ' affichage correspondant
}

void arrosage_autonome () {	// gere l ' arrosage automatiquement
// l ' objectif est de verifier a minuit , si il est neccessaire d' arroser ou pas , donc verification de la pluie , si il ne pleut pas , on verifie l ' humidité du sol .
// si il est necessaire  , en fonction du jour de la semaine on active une ou plusieurs zones pendant un temps donné .

// Arbres= 0, Bordures = 1, Fruitiers = 2, Haies = 3, Jardin = 4, Potager = 5 .
//  tempsOFF et tempsON sont a 1 minute ! utiliser des multiples  => tempsOFF*60 = 1 heure .

	DateTime now = rtc.now();	// recupere toutes les infos du RTC .
	const byte FIN_HEURE_CREUSE = 6;
	enum : uint8_t {DIMANCHE, LUNDI, MARDI, MERCREDI, JEUDI, VENDREDI, SAMEDI};
	enum : uint8_t {Arbres, Bordures, Fruitiers, Haies, Jardin, Potager};

	// reset le tableau chaque jour , afin de pouvoir arroser 2 jours desuite la meme zone si besoin
	if ( now.hour() >  FIN_HEURE_CREUSE + 14 ) {
		for ( byte i = 0; i < RELAY_NUMBER_A; i++ ) {
			zoneArrosee [i] = 0;
		}
	}

	if ( ! Pluie() && read_Humidity_sensor() >= 50 &&  now.hour() < FIN_HEURE_CREUSE) {	// si l ' humidité du sol , qu ' il ne pleut pas et qu on est en heure creuse
	//if ( 1  ) { // pour tester seulement si le reste fonctionne sans toucher aux autres conditions

		switch (now.dayOfTheWeek()) {
			case DIMANCHE :
				if ( ! zoneArrosee [ Arbres ] ) 	MarcheArretArrosage ( Arbres , tempsOFF );
				
				break;
			case LUNDI :
				if ( ! zoneArrosee [ Bordures ] ) 	MarcheArretArrosage ( Bordures , tempsOFF );
				break;
			case MARDI :
				if ( ! zoneArrosee [ Fruitiers ] ) 	MarcheArretArrosage ( Fruitiers , tempsOFF );
				break;
			case MERCREDI :
				if ( ! zoneArrosee [ Haies ] )	 MarcheArrosage ( Haies , tempsOFF );
				break;
			case JEUDI :
				if ( ! zoneArrosee [ Jardin ] ) 	MarcheArretArrosage ( Jardin , tempsOFF );
				break;
			case VENDREDI :
				if ( ! zoneArrosee [ Potager ] ) 	MarcheArretArrosage ( Potager , tempsOFF );
				break;
			case SAMEDI :
				if ( ! zoneArrosee [ Haies ] ) 	MarcheArretArrosage ( Haies , tempsOFF );
				break;

			default:
				break;
		}	// fin du switch

	}
}
//// FIN des Fonctions d ' arrosage : ////

la fonction de base MarcheArretArrosage ( incorporant millis() ) est supplanté par la fonction MarcheArrosage qui lance par l' intermediaire du gestionnaire de tache la fonction ResetArrosage les zones et relais sont couverts par le parametre identifier qui se transmet dans la fonction reset .
ca marche impecable .

cependant , une petite remarque , la classe MsTimer2 , reste cependant plus adapté pour les volets a mon avis , dans le sens ou de temps en temps on a besoin ( ? ) surtout ma femme :stuck_out_tongue: , de les arreter n ' importe ou ailleurs qu ' au debut ou a la fin et donc on place un MsTimer2::stop(); et nickel pour ca que dans mon code general j ' ai conserver les 2 ( 3 ) façon de faire .

maintenant si je voulais aller plus loin , je pourrais lancer une tache avec comme callback MarcheArretArrosage pour une zone et faire la remanence toutes les 24 , 48 ou 72 heures selon le besoin de la zone ?
MarcheArretArrosage() dans mon code gere l ' arret avec millis .

cependant , une petite remarque , la classe MsTimer2 , reste cependant plus adapté pour les volets a mon avis , dans le sens ou de temps en temps on a besoin ( ? ) surtout ma femme :stuck_out_tongue: , de les arreter n ' importe ou ailleurs qu ' au debut ou a la fin et donc on place un MsTimer2::stop(); et nickel pour ca que dans mon code general j ' ai conserver les 2 ( 3 ) façon de faire .

on pourrait étendre la classe pour lui demander de retirer une commande identifiée par son ID de la liste, ce n'est pas très compliqué:

    bool unregisterAsyncCommand(t_commandID id) {
      bool commandRemoved = false;
      for (int32_t i = 0; i < _maxCommands; i++) {
        if ((_queueCommandList[i].active) && (_queueCommandList[nextSlot].commandID == id)) {
          // on l'a trouvée
          _queueCommandList[i].active = false;
          _count--;
          commandRemoved = true;
          break;
        }
      }
      return commandRemoved;
    }

Donc si l'utilisateur interrompt manuellement une action qui avait une tâche de fin enregistrée, on peut demander d'enlever cette tâche de la liste des choses à faire plus tard. ça aurait l'avantage de fonctionner pour tout.

maintenant si je voulais aller plus loin , je pourrais lancer une tache avec comme callback MarcheArretArrosage pour une zone et faire la remanence toutes les 24 , 48 ou 72 heures selon le besoin de la zone ?
MarcheArretArrosage() dans mon code gere l ' arret avec millis .

comme je l'avais fait vous pouvez avoir un callback qui remet dans la liste des choses à faire plus tard une nouvelle demande. c'est avec cela que je jouerais

J-M-L:
on pourrait étendre la classe pour lui demander de retirer une commande identifiée par son ID de la liste, ce n'est pas très compliqué:

    bool unregisterAsyncCommand(t_commandID id) {

bool commandRemoved = false;
     for (int32_t i = 0; i < _maxCommands; i++) {
       if ((_queueCommandList[i].active) && (_queueCommandList[nextSlot].commandID == id)) {
         // on l'a trouvée
         _queueCommandList[i].active = false;
         _count--;
         commandRemoved = true;
         break;
       }
     }
     return commandRemoved;
   }



Donc si l'utilisateur interrompt manuellement une action qui avait une tâche de fin enregistrée, on peut demander d'enlever cette tâche de la liste des choses à faire plus tard. ça aurait l'avantage de fonctionner pour tout. 


comme je l'avais fait vous pouvez avoir un callback qui remet dans la liste des choses à faire plus tard une nouvelle demande. c'est avec cela que je jouerais

c ' est une super idée , ca n' est pas tres difficile , ca c' est moins sur , pour ma part n ' ayant jamais touché une classe , et ayant juste regardé le code de loin , je ne m ' aventurerais pas trop la dedans , par simple precaution .

mais bon si vous donnez deja le code , un copier coller au bon endroit ( bien que l ' info soit manquante ) ne devrait pas etre trop difficile pour moi :stuck_out_tongue:

Si je met la fonction bool unregisterAsyncCommand(t_commandID id) en ligne 59 du fichier AsyncTask.h ca devrait etre bon ? ca tombe entre la fonction bool registerAsyncCommand(t_commandID id, uint32_t deltaT, t_callback cb) et updatequeue.

ca donnerait :

#ifndef ASYNCTASK_H
#define ASYNCTASK_H

#include <Arduino.h>

typedef uint16_t t_commandID; // command idendifier is on 2 bytes (0x00 to 0xFFFF).
typedef void (*t_callback)(t_commandID); // same as "using t_callback = void (*)(t_commandID);"

template <uint16_t queueLength>
class AsyncTask
{
  private:
    struct t_queueCommand
    {
      t_callback    callback;    // a pointer to the function you want to execute after the delay is expired
      t_commandID   commandID;   // An ID for this command, used in callBack
      uint32_t      maxWait;     // how long to wait before the callback
      uint32_t      startTime;
      bool          active;
    };

    uint16_t _count;
    t_queueCommand _queueCommandList[queueLength];
    static const uint16_t _maxCommands = queueLength;

  public:
    // constructor
    AsyncTask()
    {
      _count = 0;
      for (uint16_t i = 0; i < _maxCommands; i++)
        _queueCommandList[i].active = false;
    }

    bool registerAsyncCommand(t_commandID id, uint32_t deltaT, t_callback cb) {

      // find the next empty slot
      int32_t nextSlot = -1;

      for (int32_t i = 0; i < _maxCommands; i++) {
        if (! _queueCommandList[i].active) {
          nextSlot = i; // found a position
          break;
        }
      }

      // register the command in that slot
      if (nextSlot != -1) {
        _queueCommandList[nextSlot].startTime = millis();
        _queueCommandList[nextSlot].commandID = id;
        _queueCommandList[nextSlot].callback = cb;
        _queueCommandList[nextSlot].maxWait = deltaT;
        _queueCommandList[nextSlot].active = true;
        _count++;
      } // else  // error no room left

      return (nextSlot != -1);
    }

	bool unregisterAsyncCommand(t_commandID id) {
      bool commandRemoved = false;
      for (int32_t i = 0; i < _maxCommands; i++) {
        if ((_queueCommandList[i].active) && (_queueCommandList[nextSlot].commandID == id)) {
          // on l'a trouvée
          _queueCommandList[i].active = false;
          _count--;
          commandRemoved = true;
          break;
        }
      }
      return commandRemoved;
    }
	
    uint16_t updateQueue()
    {
      uint16_t taskExpired = 0;
      if (_count == 0) return false; // no command to execute
      for (uint16_t i = 0; i < _maxCommands; i++) {
        if (_queueCommandList[i].active) {
          if (millis() - _queueCommandList[i].startTime >= _queueCommandList[i].maxWait) {
            // trigger the callback
            _queueCommandList[i].callback(_queueCommandList[i].commandID);
            // mark it as done
            _queueCommandList[i].active = false;
            _count--;
            taskExpired++; // count number of completed tasks
          }
        }
      } // end for each possible task
      return taskExpired;
    }


    // utilities
    uint16_t maxCommands() const {
      return _maxCommands;
    }

    uint16_t queueCount() const  {
      return _count;
    }
};

#endif

iznobe:
mais bon si vous donnez deja le code , un copier coller au bon endroit ( bien que l ' info soit manquante ) ne devrait pas etre trop difficile pour moi :stuck_out_tongue:

oui à mettre n'importe ou dans la classe, c'est juste une méthode en plus. par exemple après le code de la méthode registerAsyncCommand() semblerait un bon endroit :slight_smile:

notez que j'ai laissé un bug :wink:

Il ne faut pas mettre nextSlot mais i bien sûr dans le test :slight_smile: - mauvais copier collé (j'ai tapé ça ici)

    bool unregisterAsyncCommand(t_commandID id) {
      bool commandRemoved = false;
      for (int32_t i = 0; i < _maxCommands; i++) {
        if ((_queueCommandList[i].active) && (_queueCommandList[i].commandID == id)) {
          // on l'a trouvée
          _queueCommandList[i].active = false;
          _count--;
          commandRemoved = true;
          break;
        }
      }
      return commandRemoved;
    }

J-M-L:
oui à mettre n'importe ou dans la classe, c'est juste une méthode en plus. par exemple après le code de la méthode registerAsyncCommand() semblerait un bon endroit :slight_smile:

notez que j'ai laissé un bug :wink: faut pas mettre nextSlot mais i bien sûr :slight_smile: - mauvais copier collé (j'ai tapé ça ici)

    bool unregisterAsyncCommand(t_commandID id) {

bool commandRemoved = false;
     for (int32_t i = 0; i < _maxCommands; i++) {
       if ((_queueCommandList[i].active) && (_queueCommandList[i].commandID == id)) {
         // on l'a trouvée
         _queueCommandList[i].active = false;
         _count--;
         commandRemoved = true;
         break;
       }
     }
     return commandRemoved;
   }

ba j' etais en train d' editez mon message precedent , en disant la meme chose :smiley:

mon fichier perso est corrigé , merci .

bravo vous êtes un pro du debug :wink:

J-M-L:
bravo vous êtes un pro du debug :wink:

c ' est pas bien de se moquer :smiley: et merci pour cette nouvelle methode ! :wink:

j ' avoue , avoir un peu de mal avec certaines choses dans les classes :grin:

et ne pas avoir aprofondi la lecture de votre code , bien que la logique se tienne !

reste plus qu ' a tester !

donc si j ' ai suivi , j ' appelle la methode en faisant :

gestionnaireDeTache.unregisterAsyncCommand(identifier);

?

cependant , je ne suis pas certain que votre methode fera ce qu ' il faudrait .

Dans le sens ou en fait qu on apelle la methode "stop" dans l' autre bibliotheque , en fait c ' est comme si il changeait juste le timer enregistré en now() .

C ' est a dire que la fonction callback est executé quand meme , mais le timer est en quelquesorte reset .

je ne suis pas tres sur de ce que je dis ni si c' est clair :art: :grin:

ah OK - je pensais que vous faisiez le stop à la main et que vous vouliez simplement enlever le callBack sans l'exécuter.

Maintenant on peut prévoir une autre méthode qui déclenche le callBack instantanément:

    bool forceAsyncCommand(t_commandID id) {
      bool commandExecuted = false;
      for (int32_t i = 0; i < _maxCommands; i++) {
        if ((_queueCommandList[i].active) && (_queueCommandList[i].commandID == id)) {
          // trigger the callback
          _queueCommandList[i].callback(_queueCommandList[i].commandID);
          // mark it as done
          _queueCommandList[i].active = false;
          _count--;
          commandExecuted = true;
          break;
        }
      }
      return commandExecuted;
    }

donc suffit d'appeler gestionnaireDeTache.forceAsyncCommand(identifier);pour forcer son exécution immédiate indépendamment de millis()

ok , mais apres je ne suis pas certain de ce que fait exactement le MsTimer2::stop dans l' autre bibliotheque , je suppose , vu que c ' est la premier fois que je met le nez a l ' interieur d' une et que c ' est tout juste maintenant , je suis loin d' avoir le niveau de tout comprendre :o

EDIT : a priori ma carte arduino est en vrac apres avoir envoyé :

#include "AsyncTask.h"
AsyncTask<10> gestionnaireDeTache;

const unsigned long tempsOFF = 30000ul;

void callback1(t_commandID identifier)
{
  Serial.print(millis() / 1000);
  Serial.print(F("\tCall back #1 pour ID = "));
  Serial.println(identifier);
}

void callback2(t_commandID identifier)
{
  Serial.print(millis() / 1000);
  Serial.print(F("\tCall back #2 pour ID = "));
  Serial.println(identifier);
  gestionnaireDeTache.registerAsyncCommand(40, 5000UL, callback2); // on relance la tâche ID 40 pour dans 5 secondes
}

void setup()
{
  Serial.begin(115200);
  // on amorce avec 3 tâches futures dans 3, 6 et 9 secondes
  gestionnaireDeTache.registerAsyncCommand(10, 3000UL, callback1);
  gestionnaireDeTache.registerAsyncCommand(20, 6000UL, callback1);
  gestionnaireDeTache.registerAsyncCommand(30, 9000UL, callback2);

  unsigned long chrono = millis();
  if ( chrono > tempsOFF ) {
    gestionnaireDeTache.unregisterAsyncCommand(40);
  }
}

void loop()
{
  gestionnaireDeTache.updateQueue();
}

ben il suffit de regarder le code source :slight_smile: ça arrête le timer sans appeler le callback.

(le callback est appelé dans la fonction overflow)

ok , il vaut mieux que vous regardiez au moins on est sur !! :grinning:

j ' avais poster le code source de la bibli dans l' autre post celui a propos de ca justement .

j ' ai voulu tester la methode unregisterAsyncCommand , mais sans succes .

bien sur j ' ai ajouté la methode en ligne 59 au fichier asyncTask.h puis enregistrer .

pour tester j ' ai mis ce code dans le mega :

#include "AsyncTask.h"
AsyncTask<10> gestionnaireDeTache;

const unsigned long tempsOFF = 30000ul;

void callback1(t_commandID identifier)
{
  Serial.print(millis() / 1000);
  Serial.print(F("\tCall back #1 pour ID = "));
  Serial.println(identifier);
}

void callback2(t_commandID identifier)
{
  Serial.print(millis() / 1000);
  Serial.print(F("\tCall back #2 pour ID = "));
  Serial.println(identifier);
  gestionnaireDeTache.registerAsyncCommand(40, 5000UL, callback2); // on relance la tâche ID 40 pour dans 5 secondes
}

void setup()
{
  Serial.begin(115200);
  // on amorce avec 3 tâches futures dans 3, 6 et 9 secondes
  gestionnaireDeTache.registerAsyncCommand(10, 3000UL, callback1);
  gestionnaireDeTache.registerAsyncCommand(20, 6000UL, callback1);
  gestionnaireDeTache.registerAsyncCommand(30, 9000UL, callback2);

  unsigned long chrono = millis();
  if ( chrono > tempsOFF ) {
    gestionnaireDeTache.unregisterAsyncCommand(40);
  }
}

void loop()
{
  gestionnaireDeTache.updateQueue();
}

maintenant l ' IDE me met avrdude , time out .

Bon j ' ai relancé tout est a nouveau ok :wink:

j ' ai refait le test , mais ca n' a pas l' air de marcher , dans le moniteur j ' ai toujours :

14:33:29.620 -> 119	Call back #2 pour ID = 40

si vous mettez ça dans le setup

  unsigned long chrono = millis();
  if ( chrono > tempsOFF ) {
    gestionnaireDeTache.unregisterAsyncCommand(40);
  }

ça ne va être exécuté qu'une fois et comme millis() dans le setup vaudra 0, la commande ne sera jamais enlevée (en plus à ce moment là on n'a pas de ID 40 dans la liste).

-> faudrait mettre ça dans la loop et normalement après 30 secondes ça va virer la commande sans exécution et donc il n'y aura plus rien dans le liste des tâches et le code s'arrêtera d'afficher des trucs

AH ouai , j ' ai plus les yeux en face des trous :smiley:

-> faudrait mettre ça dans la loop et normalement après 30 secondes ça va virer la commande sans exécution et donc il n'y aura plus rien dans le liste des tâches et le code s'arrêtera d'afficher des trucs

effectivement ca marche impec ! merci .