Electrovanne bi-stable et contrôle du bon fonctionnement

Forum dédie aux capteurs et gateway mysensors.org
Gilles BILLARD
Messages : 75
Inscription : 09 oct. 2017, 09:34
Localisation : 45km sud Paris

Re: Electrovanne bi-stable et contrôle du bon fonctionnement

Message par Gilles BILLARD »

AU SECOURS les amis;
Ce qui fonctionnait ne fonctionne plus !
La centrale semble ne plus recevoir d'acquittement pour un ordre envoyé et pourtant, l'ordre est convenablement reçu et exécuté par le destinataire;
En conséquence, l'ordre est renvoyé une seconde fois puis un message d'erreur apparait sur la console Domotiquez
"Error sending switch command, check device/hardware (idx=74) !"
Tout cela arrive après que je me sois aperçu que mes tempos ne fonctionnait pas car j'utilisais delay() au lieu de wait()
Mais en mettant wait() en lieu et place, me voila avec des tempo qui sont prises en compte mais qui font bugger le prggm...et si je reviens en arrière, la panne disparait.
De quel coté faut il que je cherche ?
(j'ai dans l'idée que MySensors et les timers ne sont pas très copains; J'ai eu des déboires avec la fonctions sleep() (résolus par l'adoption de la librairie "MiniCore"); Maintenant voila qcq chose de nouveau avec wait(); Curieux tout ca...Je n'ai pas encore tenté le coup, mais je vasi essayer de bruler le bootloader MiniCore pour voir si ca change qcq chose...)
++
boum
Messages : 233
Inscription : 18 janv. 2019, 11:34
Localisation : France

Re: Electrovanne bi-stable et contrôle du bon fonctionnement

Message par boum »

Je dirais — vraiment à tout hasard, vu que pas de log mysensors — que c'est un problème de réentrance. Pour faire simple, il ne faut jamais appeler wait() (ou sleep) dans receive().
Durant le wait(), mysensors va vérifier la réception et potentiellement ré-appeler receive. Avec potentiellement des écrasements en mémoire de certaines variables.

Le problème, c'est que ça marche « souvent. » D'ailleurs, les exemples officiels le font…
Il y a plus de chance de tomber dans ce cas quand il y a beaucoup de messages.

Pour éviter cela, il faut différer les actions dans loop().

Plutot que :

Code : Tout sélectionner

int etat = 0;
//...
void loop() {
//...
}
//...
void receive(const MyMessage &message)
{
	// ...
	if (message.getType()==V_STATUS) {
		etat = message.getBool() ? 1 : 0;
		actionneEtAppellePotentiellementWait(etat)
	}
}
par :

Code : Tout sélectionner

int etat = 0;
int etatDemande = etat;
//...
void loop() {
//...
	if (etat != etatDemande)
	{
		etat = etatDemande;
		actionneEtAppellePotentiellementWait(etat);
	}
}
//...
void receive(const MyMessage &message)
{
	// ...
	if (message.getType()==V_STATUS) {
		etatDemande = message.getBool() ? 1 : 0;
		// l'action sera effectuée à la prochaine itération de loop()
	}
}
S'il y a plusieurs états, on peut ajouter un booléen/sémaphore qui vérifie qu'il n'y a plus d'état en attente de changement à la fin du loop, et on peut alors exécuter un wait/sleep plus long.

:!: Attention, c'est une cause probable d'anomalie. Pas sûr que ce soit la cause de ton soucis.
Bon courage
Domoticz v2022.2 sur linux-mint / Z-Wave-JS / RFXCom / Zigbee2MQTT
Gilles BILLARD
Messages : 75
Inscription : 09 oct. 2017, 09:34
Localisation : 45km sud Paris

Re: Electrovanne bi-stable et contrôle du bon fonctionnement

Message par Gilles BILLARD »

j'ai bien pensé a cette hypothèse et j'ai changé mon programme en conséquence vu que c'était bien le cas et que j'avais des attentes dans le receive();
Comme ca:

Code : Tout sélectionner

/*
Sketch MySensor pour activer et monitorer une électrovanne (d'arrosage)suivie d'un débimètre numérique.
Pour etre bien certain qu'une électtrovanne bistable se trouve dans la position voulue, il faut une information en retour
Un ordre donné par la centrale peut très bien etre arrivé a destination sans que l'électrovanne n'ait suivi;
Une solution consiste a monitorer le passage de l'eau au moyen d'un débimètre low-cost pour boucler le système.
BOM:
Electrovanne bistable (récup Gardena ou low-cost chinois) 
Débimetre chinois a 450 impulsions par litre (https://fr.aliexpress.com/item/32873453373.html?spm=a2g0s.9042311.0.0.4f676c377Zowm9)
30 l.mn Max soit 225 Hz max (4.44ms de prériode mini entre 2 impulsions)
Pour les tests sur table, cabler led verte en pin 4 et led rouge en pin 5
En réel, cabler un pont en H (H-bridge) a la place des leds

Pont en H L9110s; cabler entrées Ia (patte 6) et Ib (patte 7) en 4 et 5 de l'arduino
cabler les sorties du pont en H OA (patte 1) et OB (patte 4) sur l'électrovanne
Câbler ses alim avec le +9v en 2 et 3 et le -9V (0; gnd) en pattes 5e t 8

Version 1.0 Initiale
Version 1.1 
Version 1.2 
 */

#define MY_RADIO_RF24               // Enable and select radio type attached
//#define MY_RADIO_NRF5_ESB
//#define MY_RADIO_RFM69
//#define MY_RADIO_RFM95
#define MY_REPEATER_FEATURE         // Repeater functionality valid (for far watering points)

#define CHILD_ID_EV_Cmd 0           // Commande de l'élecrovanne
#define CHILD_ID_EV_Status 1        // Statut de l'Electro-Vanne
#define CHILD_ID_FLOW 2             // débit (non utilisé pour l'instant)
#define CHILD_ID_VOLUME 3           // volume

#include <MySensors.h>
#define DIGITAL_INPUT_SENSOR 3      // Entrée interruption du débimètre
#define Open_PIN 4                  // Sortie H bridge vers électrovanne
#define Close_PIN 5                 // Sortie H bridge vers électrovanne

//*******Options utilisateur**********
double ppl = 450;                   // ppl (Pulses per liter) comme défini pas la notice du capteur
double miniFlow = 0;                // seuil de détection de débit (en tics par seconde)
byte nbTentatives = 3;              // nombre de tentative pour ouvrir la vanne avant renvoi d'une erreur
unsigned long dureePulseEV = 50;             // (50ms) durée de l'impulsion pour activer l'EV (CF notice fabriquant)
unsigned long delayFlowMetre = 1000;        // (1000ms) tempo de mise en route du flot et donc du débimètre
unsigned long cadenceBoucle = 50;
//************************************
volatile unsigned int ticsCount = 0;
short pulseCount = 0;
uint32_t oldPulseCount = 0;
double flow = 0;
double vol=0;
double oldflow = 0;
double oldvolume =0;
MyMessage cmdMsg(CHILD_ID_EV_Cmd, V_STATUS);
MyMessage flowMsg(CHILD_ID_FLOW, V_FLOW);
MyMessage volMsg(CHILD_ID_VOLUME, V_VOLUME);
MyMessage errorEVMsg(CHILD_ID_EV_Status, V_TRIPPED);

class electrovanne {
  private:
    byte Open_Pin;
    byte Close_Pin;
  public:
    bool position;
    electrovanne (byte O_pin, byte C_pin){ // constructeur
      Open_Pin = O_pin;
      Close_Pin = C_pin;
      init();    
    }
    void init() {
      pinMode(Open_Pin, OUTPUT);
      pinMode(Close_Pin, OUTPUT); 
      off ();    
    }
    void open(){
      digitalWrite(Close_Pin, LOW);
      digitalWrite(Open_Pin, HIGH);
    }
    void close() {
      digitalWrite(Open_Pin, LOW);
      digitalWrite(Close_Pin, HIGH);  
    }
    void off() {
      digitalWrite(Close_Pin, LOW);
      digitalWrite(Open_Pin, LOW);      
    }    
};

class debimetre {
  private: 
    byte inputPin;
  public:
    bool actif = false;
    double volume = 0;
    double flow = 0;
    debimetre(byte I_pin) {                 // constructeur
      inputPin =  I_pin;
      init();
    }
  void init () {
    pinMode (inputPin, INPUT_PULLUP);
  }
}; 

debimetre myDebimetre(DIGITAL_INPUT_SENSOR);          // Instanciation du débimètre
electrovanne myElectrovanne(Open_PIN,Close_PIN);      // Instanciation de l'electrovanne

void setup(){
  pinMode(DIGITAL_INPUT_SENSOR, INPUT_PULLUP); // pour etre certain de détecter un  front descendant
  myElectrovanne.off();
  pulseCount = oldPulseCount = 0;
  attachInterrupt(digitalPinToInterrupt(DIGITAL_INPUT_SENSOR), isr, FALLING);
  Serial.begin(115200);  
}

void presentation(){
    sendSketchInfo("Arrosage", "1.0");// Send the sketch version information to the gateway and Controller
    present(CHILD_ID_EV_Cmd, S_BINARY);
    present(CHILD_ID_EV_Status, S_DOOR);  
    present (CHILD_ID_FLOW, S_WATER);
    present(CHILD_ID_VOLUME,S_WATER);
}

//*************************************
void loop()
{
  pulseCount = ticsCount;                         // sauvegarde et raz du compteur d'impulsions
  ticsCount = 0;
  vol = pulseCount/ppl;                           // débit par seconde
  flow = vol*60;                                  // débit en litres.minute   
  if (flow != oldflow) oldflow = flow;            // calcul du débit instantané (en cas de besoin ultérieur)
  if (pulseCount != 0) {                          // En cas de mesure...
    oldPulseCount = oldPulseCount + pulseCount;
    myDebimetre.volume = ((double)oldPulseCount/((double)ppl));    
    pulseCount=0; 
    myDebimetre.actif = true;   
//    Serial.println ("OUVERT");     
    } 
    else { 
      myDebimetre.actif = false;
//      Serial.println ("FERME");  
    } 
    wait(cadenceBoucle);                                    // une mesure par seconde                                                                          
}
//*************************************
//*************************************
void isr()
{
  ticsCount++;
}
//*************************************
//*************************************
void receive(const MyMessage &message)
{
    if (message.getType()==V_STATUS) {                // vérification du type de msg
      if (message.getBool()== true) {                 // Ordre d'ouverture
          for (int i=1; i <= nbTentatives; i++) {     // tentatives...
          myElectrovanne.open();                      // envoi de l'impulsion d'ouverture
          Serial.println ("ouverture EV "); 
          wait (dureePulseEV);                        
          myElectrovanne.off();
          wait (delayFlowMetre);                    // attente pleine ouverture
          if (myDebimetre.actif == true){           // si bien ouverte...
            send(errorEVMsg.set(0));                // Electrovanne OK
            Serial.println ("La vanne s'est bien ouverte ");
            break;
          }  
          else{ 
            if(i== nbTentatives){
            send(errorEVMsg.set(1));                // Envoi d'une alerte Panne electrovanne
            Serial.println ("La vanne ne s'est pas ouverte ");           
            }
          }
        }
      }
      else {                                        // Orde de fermeture
        for (int i=1; i <= nbTentatives; i++) {     // tentatives
          myElectrovanne.close();                   // envoi de l'impulsion de fermeture
          Serial.println ("fermeture EV "); 
          wait (dureePulseEV);                      
          myElectrovanne.off(); 
          wait (delayFlowMetre);                     // attente arret du flot d'eau
          if (myDebimetre.actif == false) {
            Serial.println (myDebimetre.volume); 
            send(volMsg.set(myDebimetre.volume,1));
            send(errorEVMsg.set(0));                 // Electrovanne OK
            Serial.println ("La vanne s'est bien fermée ");
            myDebimetre.volume=0;                    // RAZ du volumed'eau qui est passé durant la période ouverte
            myDebimetre.flow=0;                      // RAZ du débit
            break;                      
          }
          else{                                       // si pas bien fermée
            if(i== nbTentatives){
            send(errorEVMsg.set(1));                 // Envoi d'une alerte Panne electrovanne
            Serial.println ("La vanne ne s'est pas fermée ");
            }
          }
        } 
        // TODO sleep(.....)        // faire dormir le node et envoyer un hartbeat au réveil...                         
      }
    }
}
j'ai donc changé comme ca (avec les delay() ca tourne comme avant; mais avec sleep, ca plante comme ci-dessus):

Code : Tout sélectionner

/*
Sketch MySensor pour activer et monitorer une électrovanne (d'arrosage)suivie d'un débimètre numérique.
Pour etre bien certain qu'une électtrovanne bistable se trouve dans la position voulue, il faut une information en retour
Un ordre donné par la centrale peut très bien etre arrivé a destination sans que l'électrovanne n'ait suivi;
Une solution consiste a monitorer le passage de l'eau au moyen d'un débimètre low-cost pour boucler le système.
BOM:
Electrovanne bistable (récup Gardena ou low-cost chinois) 
Débimetre chinois a 450 impulsions par litre (https://fr.aliexpress.com/item/32873453373.html?spm=a2g0s.9042311.0.0.4f676c377Zowm9)
30 l.mn Max soit 225 Hz max (4.44ms de prériode mini entre 2 impulsions)
Pour les tests sur table, cabler led verte en pin 4 et led rouge en pin 5
En réel, cabler un pont en H (H-bridge) a la place des leds

Pont en H L9110s; cabler entrées Ia (patte 6) et Ib (patte 7) en 4 et 5 de l'arduino
cabler les sorties du pont en H OA (patte 1) et OB (patte 4) sur l'électrovanne
Câbler ses alim avec le +9v en 2 et 3 et le -9V (0; gnd) en pattes 5e t 8

Version 1.0 Initiale
Version 1.1 fct receive() raccourcie a son plus strict minimum
Version 1.2 
 */

#define MY_RADIO_RF24               // Enable and select radio type attached
//#define MY_RADIO_NRF5_ESB
//#define MY_RADIO_RFM69
//#define MY_RADIO_RFM95
#define MY_REPEATER_FEATURE         // Repeater functionality valid (for far watering points)

#define CHILD_ID_EV_Cmd 0           // Commande de l'élecrovanne
#define CHILD_ID_EV_Status 1        // Statut de l'Electro-Vanne
#define CHILD_ID_FLOW 2             // débit (non utilisé pour l'instant)
#define CHILD_ID_VOLUME 3           // volume

#include <MySensors.h>
#define DIGITAL_INPUT_SENSOR 3      // Entrée interruption du débimètre
#define Open_PIN 4                  // Sortie H bridge vers électrovanne
#define Close_PIN 5                 // Sortie H bridge vers électrovanne

//*******Options utilisateur**********
double ppl = 450;                   // ppl (Pulses per liter) comme défini pas la notice du capteur
double miniFlow = 0;                // seuil de détection de débit (en tics par seconde)
byte nbTentatives = 3;              // nombre de tentative pour ouvrir la vanne avant renvoi d'une erreur
unsigned long dureePulseEV = 50;             // (50ms) durée de l'impulsion pour activer l'EV (CF notice fabriquant)
unsigned long delayFlowMetre = 10;        // (1000ms) tempo de mise en route du flot et donc du débimètre
unsigned long cadenceBoucle = 500;
//************************************
volatile unsigned int ticsCount = 0;
short pulseCount = 0;
uint32_t oldPulseCount = 0;
double flow = 0;
double vol=0;
double oldflow = 0;
double oldvolume =0;
bool openOrder= false;
bool closeOrder=false;
MyMessage cmdMsg(CHILD_ID_EV_Cmd, V_STATUS);
MyMessage flowMsg(CHILD_ID_FLOW, V_FLOW);
MyMessage volMsg(CHILD_ID_VOLUME, V_VOLUME);
MyMessage errorEVMsg(CHILD_ID_EV_Status, V_TRIPPED);

class electrovanne {
  private:
    byte Open_Pin;
    byte Close_Pin;
  public:
    bool position;
    electrovanne (byte O_pin, byte C_pin){ // constructeur
      Open_Pin = O_pin;
      Close_Pin = C_pin;
      init();    
    }
    void init() {
      pinMode(Open_Pin, OUTPUT);
      pinMode(Close_Pin, OUTPUT); 
      off ();    
    }
    void open(){
      digitalWrite(Close_Pin, LOW);
      digitalWrite(Open_Pin, HIGH);
    }
    void close() {
      digitalWrite(Open_Pin, LOW);
      digitalWrite(Close_Pin, HIGH);  
    }
    void off() {
      digitalWrite(Close_Pin, LOW);
      digitalWrite(Open_Pin, LOW);      
    }    
};

class debimetre {
  private: 
    byte inputPin;
  public:
    bool actif = false;
    double volume = 0;
    double flow = 0;
    debimetre(byte I_pin) {                 // constructeur
      inputPin =  I_pin;
      init();
    }
  void init () {
    pinMode (inputPin, INPUT_PULLUP);
  }
}; 

debimetre myDebimetre(DIGITAL_INPUT_SENSOR);          // Instanciation du débimètre
electrovanne myElectrovanne(Open_PIN,Close_PIN);      // Instanciation de l'electrovanne

void setup(){
  pinMode(DIGITAL_INPUT_SENSOR, INPUT_PULLUP);        //Détection fronts descendants
  myElectrovanne.off();
  pulseCount = oldPulseCount = 0;
  attachInterrupt(digitalPinToInterrupt(DIGITAL_INPUT_SENSOR), isr, FALLING);
  Serial.begin(115200);  
}

void presentation(){
    sendSketchInfo("Arrosage", "1.1");            // Envoi nom et version du sketch a la passerelle et au controleur
    present(CHILD_ID_EV_Cmd, S_BINARY);
    present(CHILD_ID_EV_Status, S_DOOR);  
    present (CHILD_ID_FLOW, S_WATER);
    present(CHILD_ID_VOLUME,S_WATER);
}

//*************************************
void loop()
{
  pulseCount = ticsCount;                         // sauvegarde et raz du compteur d'impulsions
  ticsCount = 0;
  vol = pulseCount/ppl;                           // débit par seconde
  flow = vol*60;                                  // débit en litres.minute   
  if (flow != oldflow) oldflow = flow;            // calcul du débit instantané (en cas de besoin ultérieur)
  if (pulseCount != 0) {                          // En cas de mesure...
    oldPulseCount = oldPulseCount + pulseCount;
    myDebimetre.volume = ((double)oldPulseCount/((double)ppl));    
    pulseCount=0; 
    myDebimetre.actif = true;   
//    Serial.println ("OUVERT");     
    } 
    else { 
      myDebimetre.actif = false;
//      Serial.println ("FERME");  
    } 
if (openOrder==true){                               // Ordre d'ouverture
       for (int i=1; i <= nbTentatives; i++) {     // tentatives...
          myElectrovanne.open();                      // envoi de l'impulsion d'ouverture
          Serial.println ("ouverture EV "); 
          delay (dureePulseEV);                        
          myElectrovanne.off();
          delay (delayFlowMetre);                    // attente pleine ouverture
          if (myDebimetre.actif == true){           // si bien ouverte...
            send(errorEVMsg.set(0));                // Electrovanne OK
            Serial.println ("La vanne s'est bien ouverte ");
            break;
          }  
          else{ 
            if(i== nbTentatives){
            send(errorEVMsg.set(1));                // Envoi d'une alerte Panne electrovanne
            Serial.println ("La vanne ne s'est pas ouverte ");                       
            }
          }
        }
    openOrder=false;                                                                                                       
    }
if (closeOrder==true){                             // Orde de fermeture
       for (int i=1; i <= nbTentatives; i++) {      // tentatives
          myElectrovanne.close();                   // envoi de l'impulsion de fermeture
          Serial.println ("fermeture EV "); 
          delay (dureePulseEV);                      
          myElectrovanne.off(); 
          delay (delayFlowMetre);                     // attente arret du flot d'eau
          if (myDebimetre.actif == false) {
            Serial.println (myDebimetre.volume); 
            send(volMsg.set(myDebimetre.volume,1));
            send(errorEVMsg.set(0));                 // Electrovanne OK
            Serial.println ("La vanne s'est bien fermée ");
            myDebimetre.volume=0;                    // RAZ du volumed'eau qui est passé durant la période ouverte
            myDebimetre.flow=0;                      // RAZ du débit
            break;                      
          }
          else{                                       // si pas bien fermée
            if(i== nbTentatives){
            send(errorEVMsg.set(1));                 // Envoi d'une alerte Panne electrovanne
            Serial.println ("La vanne ne s'est pas fermée ");
            }
          }
       }
    closeOrder=false;                                                                                                       
    }
  
 delay(cadenceBoucle); // une mesure par seconde  
 // TODO sleep(.....)        // faire dormir le node et envoyer un hartbeat au réveil...               
}
//*************************************
//*************************************
void isr()
{
  ticsCount++;
}
//*************************************
//*************************************
void receive(const MyMessage &message)
{
  if (message.getType()==V_STATUS) {                 // vérification du type de msg
    if (message.getBool()== true) openOrder=true;
    if (message.getBool()== false) closeOrder=true;
  }                                        
}
Maintenant, tu parles du log MySensors, ou se trouve-t-il ?

BTW, Boum; j'ai ouvert un compte sur Github, installé le desktop et je m'instruis en lisant des tutos pour savoir comment avancer pour bien faire....
boum
Messages : 233
Inscription : 18 janv. 2019, 11:34
Localisation : France

Re: Electrovanne bi-stable et contrôle du bon fonctionnement

Message par boum »

Par log, je pensais principalement au moniteur série, pour avoir les Serial.println, mais aussi le log de la passerelle pour avoir les messages qui passent : https://www.mysensors.org/build/debug (il y a lien vers le Log Parser pour décoder le texte).
Domoticz v2022.2 sur linux-mint / Z-Wave-JS / RFXCom / Zigbee2MQTT
Gilles BILLARD
Messages : 75
Inscription : 09 oct. 2017, 09:34
Localisation : 45km sud Paris

Re: Electrovanne bi-stable et contrôle du bon fonctionnement

Message par Gilles BILLARD »

ha ok commae ca;
hé bien, le moniteur série me dit que tout se passe convenablement et que le node recoit deux fois le même ordre et qu'il s'exécute conformément au programme.
Je vais bruler le MiniCore bootloader aujourd'hui, si je me laisse un peu de temps pour le faire, et voir ce qu'il advient...car le pb du débug, c'est qu'il ne tient pas dans un ATmeaga168 qui est celui qui est sur le pro-mini que j'utilise; Alors soit je m'en passe, soit je change et je passe a un 328, ce qui de toutes façon, a terme, sera préférable coté consommation...
Bonne journée.
++
Répondre