Arduino - MySensors : Perte de communication, programme arrêté

Salut à tous,

J’imagine fort bien que je ne suis même pas sur le bon forum, mais je sais que parmi vous, certains ont déjà été confronté au problème.

Je vous explique le projet …

Cette année, je me fait un potager de A à Z et donc je fais mes semis.
Pour optimiser certaines graines, je chauffe avec 2 plateaux chauffants, mes bacs de semis.
Ces plateaux sont gérés par 2 relais via un Arduino.
Et les remontées de températures se font via 2 sondes DS18B20.
L’affichage des températures et de l’état des relais se fait sur un LCD.

Le programme est simple et rudimentaire mais pour l’urgence et le besoin, il fonctionne très bien.

J’ai voulu ajouter à ce projet la couche MySensors.
Jusque là tout va bien aussi, lorsque je check avec MysController, je vois bien tout remonter.

Par contre, ça se complique lorsque j’éloigne ma passerelle.
Je n’ai plus de connexion entre mon projet et l GateWay MySensors.

Alors, oui, d’une part, je vais voir à changer l’antenne RF24 que j’utilise pour une plus longue protée.
Mais ce n’est pas ce qui m’inquiète.

Mon problème c’est que lorsque mon projet ne capte pas la passerelle et bien il bloque sur ce point et tourne en rond.

Résultat : plus de fonctionnement de mon automatisation.

Ce que je voudrais c’et que la couche MySensors soit optionnelle.
Si tu joins la passerelle tant mieux, remontes les infos, etc.
Sinon, bah fais quand même ton boulot en local parceque çe ne va pas chauffer tout seul ce bazard!

Donc l’idée c’est comment gérer ces interuptions de communication avec la passerelle?
Forcément, ça a été géré chez MySensors ?
On ne va pas perdre la gestion d’un capteur ou actionneur simplement parce que la passerelle n’est plus joignable.

Le truc, c’est que je ne sais pas du tout comment gérer ça.
Si vous avez déjà rencontré le problème ?

Voici le code de mon sketch ci-dessous au besoin :

/*
 * 
 *        Semis4Tonyo
 *        
 * Création du programme : 10 Février 2021
 * 
 * Gestion de 2 plateaux de chauffage commandés par 2 relais
 * et régulés par 2 sondes DS18B20
 * Utilisation d'un affichage LCD 16x2 pour l'affichage des
 * températures et des status des relais.
 * 
 * Utilisation du protocole MySensors pour transmission sans
 * fil des informations.
 * 
 * 
 * 
 * 
 * 
 * 
 */

// MySensors - Activation du Debug
#define MY_DEBUG

// MySensors - Activation et choix du module Radio
#define MY_RADIO_RF24


//////////////////////////////
// Inclusion des librairies //
//                          //

#include <TinkerKit.h>            // Relais
#include <OneWire.h>              // Gestion des Sonde de température DS18B20
#include <DS18B20.h>              // Gestion des Sonde de température DS18B20
#include <LiquidCrystal_I2C.h>    // LCD (Adresse 0x3F
#include <MySensors.h>            // Librairie MySensors

//                          //
// Inclusion des librairies //
//////////////////////////////

//////////////////////////////////////////
// Variables globales pour le programme //
//                                      //

// Températures des sondes
float tempSonde1;       // Température de la sonde 1
float tempSonde2;       // Température de la sonde 2
float LASTtempSonde1 = 99.99;   // Dernière température relevée de la sonde 1
float LASTtempSonde2 = 99.99;   // Dernière température relevée de la sonde 2

// Température de consigne
float tempConsigne1 = 24;
float tempConsigne2 = 24;

// Etat du chauffage (en chauffe ou non)
bool chauffe1 = false;      // Etat du relais 1
bool chauffe2 = false;      // Etat du relais 2
bool LASTchauffe1 = false;  // Dernier état du relais 1
bool LASTchauffe2 = false;  // Dernier état du relais 2

// Seuil d'Hysteresis
float hysteresis = 0.5;

//                                      //
// Variables globales pour le programme //
//////////////////////////////////////////

/////////////////////////////
// Environnement MySensors //
//                         //

// On définit les identifiants des noeuds attachés à l'objet.
// Un numéro pour chaque capteur ou actionneur connecté à l'arduino
#define CHILD_ID_TEMP1 0    // Température de la sonde 1
#define CHILD_ID_TEMP2 1    // Température de la sonde 2
#define CHILD_ID_RELAIS1 2  // Etat du relais 1
#define CHILD_ID_RELAIS2 3  // Etat du relais 2

// On créé un objet MyMessage avec en paramètre son dientifiant et son type de données
MyMessage tempMsg1(CHILD_ID_TEMP1, V_TEMP);
MyMessage tempMsg2(CHILD_ID_TEMP2, V_TEMP);
MyMessage relaisMsg1(CHILD_ID_RELAIS1, V_STATUS);
MyMessage relaisMsg2(CHILD_ID_RELAIS2, V_STATUS);

//                         //
// Environnement MySensors //
/////////////////////////////



// Initialisation du LCD 16x2 en adresse 0x3F
LiquidCrystal_I2C lcd(0x3F,16,2); // 0x3F est l'adresse du LCD obtenu via i2C_Scanner

// Initialisation des relais chauffage sur leur PIN de connexion
TKRelay relais1(5);  // relais 1 (chauffage 1) sur PIN 5
TKRelay relais2(6);  // relais 2 (chauffage 2) sur PIN 6

// Initialisation des sondes de température de type OnWire sur leur PIN de connexion
#define ONE_WIRE_BUS_1 3   // Sonde 1 sur PIN 3
#define ONE_WIRE_BUS_2 4    // Sonde 2 sur PIN 4
OneWire oneWire_1(ONE_WIRE_BUS_1);
OneWire oneWire_2(ONE_WIRE_BUS_2);

// Initialisation des sondes via la libraire DS18B20
DS18B20 temperature_1(&oneWire_1);
DS18B20 temperature_2(&oneWire_2);

void setup()
{
  //////////////////////////////
  // Initialisation MySensors //
  //                          //

  // envoie la version info du sketch à la Gateway
  sendSketchInfo("Semis4Tonyo", "1.0");

  // enregitre les capteurs à la passerelle
  present(CHILD_ID_TEMP1, S_TEMP);      // Température de la sonde 1
  present(CHILD_ID_TEMP2, S_TEMP);      // Température de la sonde 2
  present(CHILD_ID_RELAIS1, S_BINARY);  // Etat du relais 1
  present(CHILD_ID_RELAIS2, S_BINARY);  // Etat du relais 2

  //                                   //
  // FIN de l'initialisation MySensors //
  ///////////////////////////////////////


  
  ////////////////////////////////////
  // Initialisation des équipements //
  //                                //

  // Initialisation du LCD
  lcd.init();
  lcd.backlight();
  lcd.clear();
  lcd.noBlink();
  
  // Initialisation de la communciation Série en vitesse 115200
  Serial.begin(115200);

  // Initialisation des relais 1 et 2 à OFF
  relais1.off();
  relais2.off();

  // Initialisation des sonde de température 1 et 2
  temperature_1.begin();
  temperature_2.begin();

  //                                         //
  // FIN de l'initialisation des équipements //
  /////////////////////////////////////////////

  /////////////////////////////////////////////
  // Affichage des informations de démarrage //
  //                                         //
  Serial.println("Semis4Tonyo");
  Serial.println("Start ...");
  lcd.setCursor(0, 0);
  lcd.print("Semis4Tonyo");
  lcd.setCursor(0,1);
  lcd.print("Start ...");

  delay(3000);  // Attendre 1 secondes
  lcd.clear();
  //                                                //
  // FIN d'affichage des informations des démarrage //
  ////////////////////////////////////////////////////
}
void loop(){
  // On récupère les températures
  TraitementChangementTempRelais();

  // DEBUG Serial affichage de Températures et de l'état des relais
  Serial.print("Sonde 1: ");
  Serial.println(tempSonde1);
  Serial.print("Sonde 2: ");
  Serial.println(tempSonde2);
  Serial.println("");
  Serial.print("Etat relais chauffage 1 : ");
  Serial.println(chauffe1);
  Serial.print("Etat relais chauffage 2 : ");
  Serial.println(chauffe2);

  // Activation / Désactivation du chauffage 1
  if(tempSonde1 <= (tempConsigne1 - hysteresis)) // Si la température de la sonde 1 est inférieur ou égal à la consigne + l'hystérisis
  {
    relais1.on(); // On active le relais du chauffage 1
    chauffe1 = true; // On passe à 1 l'état de chauffe 1
  }
  else if (tempSonde1 >= (tempConsigne1 + hysteresis)) // Si la température de la sonde 2 est supérieur ou égal à la consigne - l'hystérisis
  {
    relais1.off(); // On désactive le relais du chauffage 1
    chauffe1 = false; // on passe à 0 l'état de chauffe 1
  }

  // Activation / Désactivation du chauffage 2
  if(tempSonde2 <= (tempConsigne2 - hysteresis)) // Si la température de la sonde 1 est inférieur ou égal à la consigne + l'hystérisis
  {
    relais2.on(); // On active le relais du chauffage 1
    chauffe2 = true; // On passe à 1 l'état de chauffe 1
  }
  else if (tempSonde2 >= (tempConsigne2 + hysteresis)) // Si la température de la sonde 2 est supérieur ou égal à la consigne - l'hystérisis
  {
    relais2.off(); // On désactive le relais du chauffage 1
    chauffe2 = false; // on passe à 0 l'état de chauffe 1
  }
}


//////////////////////////////////////////////////////////////////////////////
// Fonction qui traite les changements de températures et d'état des relais //
//                                                                          //
void TraitementChangementTempRelais()
{
  // Lecture des températures des sondes 1 et 2
  temperature_1.requestTemperatures();
  temperature_2.requestTemperatures();

  // On affecte les températures aux variables tempSonde1 et tempSonde2
  tempSonde1 = temperature_1.getTempC();
  tempSonde2 = temperature_2.getTempC();

  if (LASTtempSonde1 != tempSonde1) // Si changement de température depuis le dernier relevé de la sonde 1
  {
    // On affiche les infos à l'écran
    lcd.setCursor(0,0);
    lcd.print("SEM1:       Ch:");
    lcd.setCursor(5,0);
    lcd.print(tempSonde1);

    // MySensors - Envoi du message de température de la sonde 1
    send(tempMsg1.set(tempSonde1,2));
    
    LASTtempSonde1 = tempSonde1;  // On actualise LASTtempSonde1
  }

  if (LASTtempSonde2 != tempSonde2) // Si changement de température depuis le dernier relevé de la sonde 2
  {
    // On affiche les infos à l'écran
    lcd.setCursor(0,1);
    lcd.print("SEM2:       Ch:");
    lcd.setCursor(5,1);
    lcd.print(tempSonde2);

    // MySensors - Envoi du message de température de la sonde 2
    send(tempMsg2.set(tempSonde2,2));

    LASTtempSonde2 = tempSonde2;  // On actualise LASTtempSonde2
  }

  if (LASTchauffe1 != chauffe1) // Si changement d'état sur un relais
  {
    // On affiche les infos à l'écran
    lcd.setCursor(15,0);
    lcd.print(chauffe1);

    // MySensors - Envoi du message de l'état du relais 1
    send(relaisMsg1.set(chauffe1,2));

    LASTchauffe1 = chauffe1;    // On actualise LASTchauffe1
  }

  if (LASTchauffe2 != chauffe2)
  {
    // On affiche les infos à l'écran
    lcd.setCursor(15,1);
    lcd.print(chauffe2);

    // MySensors - Envoi du message de l'état du relais 2
    send(relaisMsg2.set(chauffe2,2));

    LASTchauffe2 = chauffe2;    // On actualise LASTchauffe2
  }
}
//                                                                                    //
// FIN de la Fonction qui traite les changements de températures et d'état des relais //
////////////////////////////////////////////////////////////////////////////////////////

Bonjour @tonyo08

Il faut que tu ajoute dans ton sketch arduino

#define MY_TRANSPORT_WAIT_READY_MS 10000 // au cas ou gateway hs saute void presentation

(10000 est le temps d’attente en ms)

Jean-luc

Salut,

Avec le debug du noeud ça aurait été bien !
Déjà tu peux définir l’ID du nœud avec
#define MY_NODE_ID

Salut et merci pour ta réponse.
C’est bien ce que j’ai fais avec « #define CHILD_ID_TEMP1 0 » entre autre.

Et je ne vois pas de quel debug tu parles ?
Ce que je vois sur le moniteur série quand il ne joint pas la passerelle ?

Salut @jlb,
Génial, je vais donc essayer ça.

Donc si 10000ms sont passé il passe au reste du programme.
Et du coup, si la Gateway est de nouveau joignable ?
Comment ça peut fonctionner ?

Merci pour ton retour en tous cas, c’est pil ce qu’il me fallait.

Tonyo

Bonjour @tonyo08

  1. Je te confirme que avec #define MY_TRANSPORT_WAIT_READY_MS 10000
    ca va fonctionner mème si pas de connexion avec ta gateway

  2. oui nrf24 avec ampli et antenne améliore beaucoup la comm

  3. quand tu utilise mysensors, évite les delay(), il faut utiliser wait()

  4. quand tu fait ta comm vers jeedom c’est mieux de gérer les ack pour être sûr

ci-joint un de mes sketch avec gestion ack si ça peut t’aider

Jean-luc

/*
JLB le 11/01/2021
Ventilateurs commandés avec 2 relais statique

*/

// Enable debug prints to serial monitor
//#define MY_DEBUG 

// Enable and select radio type attached
#define MY_RADIO_RF24

//#define MY_REPEATER_FEATURE             // active mode répéteur pour ce node

//#define MY_RF24_PA_LEVEL RF24_PA_MAX
//#define MY_RF24_PA_LEVEL RF24_PA_HIGH
#define MY_RF24_PA_LEVEL RF24_PA_LOW
//#define MY_RF24_PA_LEVEL RF24_PA_MIN

#define MY_TRANSPORT_WAIT_READY_MS 10000    // au cas ou gateway hs saute void presentation
//#define MY_TRANSPORT_SANITY_CHECK
//#define MY_TRANSPORT_MAX_TX_FAILURES 1

#include <MySensors.h>
#include <SPI.h>

#define ventilateur_salle_manger  5   // Arduino Digital I/O pin number for relay
#define ventilateur_salon         3   // Arduino Digital I/O pin number for relay 

#define CHILD_ID_salle_manger     1   // Id of the sensor child
#define CHILD_ID_salon            2   // Id of the sensor child

#define on    1
#define off   0

bool ack = false ;
int debug = 0;                      // mettre à 1 pour affichage sur moniteur ******************************************************************************************************
bool state_ventilateur_salle_manger = false;                // état de la sortie
bool state_ventilateur_salon        = false;                // état de la sortie

bool changement_recu_ventilateur_salle_manger = false;       // true si reception de jeedom
bool changement_recu_ventilateur_salon        = false;       // true si reception de jeedom

bool memo_state_ventilateur_salle_manger  = 0;
bool memo_state_ventilateur_salon         = 0;

unsigned long memo_millis_ventilateur_salle_manger  = 0;
unsigned long memo_millis_ventilateur_salon         = 0;

//MySensor gw;
MyMessage msg(CHILD_ID_salle_manger,V_LIGHT);

//******************************************************************************************
void setup()  
{  
  digitalWrite(ventilateur_salle_manger, off);  // Make sure relays are off when starting up
  pinMode(ventilateur_salle_manger, OUTPUT);    // Then set relay pins in output mode 
  digitalWrite(ventilateur_salon, off);         // Make sure relays are off when starting up
  pinMode(ventilateur_salon, OUTPUT);           // Then set relay pins in output mode 
}

//******************************************************************************************
void presentation()  {
  // Send the sketch version information to the gateway and Controller
  sendSketchInfo("Ventilateur", "2.0");
  wait(200);
  // Register all sensors to gw (they will be created as child devices)
  present(CHILD_ID_salle_manger, S_LIGHT);
  wait(200);
  present(CHILD_ID_salon, S_LIGHT);
  wait(200);
}

//******************************************************************************************
void loop() 
{
  unsigned long eteindre = 14400000;            // tempo pour extinction automatique 4 heures (4x60x60x1000)
  static bool onetime = true;
  
  if (onetime)  {
    send_state (CHILD_ID_salle_manger,state_ventilateur_salle_manger);  // envoie l'état à jeedom
    send_state (CHILD_ID_salon,state_ventilateur_salon);                // envoie l'état à jeedom 
    onetime = false; 
  }
  
  if (changement_recu_ventilateur_salle_manger == true)  {               // commande venant de jeedom
    changement_recu_ventilateur_salle_manger = false;
    send_state (CHILD_ID_salle_manger,state_ventilateur_salle_manger);
  }
  if (changement_recu_ventilateur_salon == true)  {               // commande venant de jeedom
    changement_recu_ventilateur_salon = false;
    send_state (CHILD_ID_salon,state_ventilateur_salon);
  }
  
  if (state_ventilateur_salle_manger == 1) {
    if (millis() - memo_millis_ventilateur_salle_manger >= eteindre) {   // extinction si state=1 depuis plus de 6 heures
      state_ventilateur_salle_manger = 0;
      send_state (CHILD_ID_salle_manger,state_ventilateur_salle_manger);  // envoie l'état à jeedom
    }
  }
  if (state_ventilateur_salon == 1) {
    if (millis() - memo_millis_ventilateur_salon >= eteindre) {   // extinction si state=1 depuis plus de 6 heures
      state_ventilateur_salon = 0;
      send_state (CHILD_ID_salon,state_ventilateur_salon);  // envoie l'état à jeedom
    }
  }
}   // fin loop 

/* ======================================================================
Function: send_state
// envoi l'état à jeedom
// 3 tentatives si pas reception ack
====================================================================== */
void send_state (int child, int valeur) {
  wait(20);
  if (child == CHILD_ID_salle_manger) {
    if (state_ventilateur_salle_manger == 1 && memo_state_ventilateur_salle_manger ==0) {         // detection front montant de state pour faire memo millis
      memo_millis_ventilateur_salle_manger = millis();
      memo_state_ventilateur_salle_manger = 1;
    }
    else { memo_state_ventilateur_salle_manger = state_ventilateur_salle_manger;  }
    digitalWrite(ventilateur_salle_manger, state_ventilateur_salle_manger?on:off);
  }

  if (child == CHILD_ID_salon)  {
    if (state_ventilateur_salon == 1 && memo_state_ventilateur_salon ==0) {         // detection front montant de state pour faire memo millis
      memo_millis_ventilateur_salon = millis();
      memo_state_ventilateur_salon = 1;
    }
    else  {memo_state_ventilateur_salon = state_ventilateur_salon;  }
    digitalWrite(ventilateur_salon, state_ventilateur_salon?on:off);
  }
  wait(100);
  
  for ( int i = 0 ; i < 3 ; i++ ) {
    send(msg.setSensor(child).set(valeur),true);
    if (reception_ack()) {
      break ; // sortie boucle for
    }
  }
}

/* ======================================================================
Function: reception_ack
// attend la réception
// sortie au bout de 2 secondes si pas de reception
====================================================================== */
bool reception_ack () {
  unsigned long previousMillis = 0 ;
  unsigned long interval = 2000 ;  // 2 secondes
  previousMillis = millis() ;
  ack = false ;
  while (! ack) {
    wait(1) ;
    if (millis() - previousMillis >= interval) {  // regarde si timeout
      return false ; // sortie sur timeout
    }
  }
  if (debug == 1) {
    Serial.print("Retournement ack :"); Serial.println((millis() - previousMillis));
  }
  return true ;
}

//******************************************************************************************
void receive(const MyMessage &message) {
  // We only expect one type of message from controller. But we better check anyway.
  if (message.isEcho()) {
    ack = true;
    //Serial.println("This is an écho from gateway");
  }
  else {
    if (message.type == V_LIGHT && message.sensor == CHILD_ID_salle_manger) {   // reception de jeedom
      state_ventilateur_salle_manger = message.getBool();
      changement_recu_ventilateur_salle_manger = true;
    }
    if (message.type == V_LIGHT && message.sensor == CHILD_ID_salon) {   // reception de jeedom
      state_ventilateur_salon = message.getBool();
      changement_recu_ventilateur_salon = true;
    }
  }
}

En fait mysensors essaye à intervalles régulier

Le #define MY_NODE_ID c’est pour donner d’office un ID au noeud, par défaut c’est la passerelle qui le donne, mais si pas de communication, le noeud attend toujours son ID et ne démarre pas.
Et le debug en question, c’est bien ce que tu vois sur le moniteur série.

Bon courage.

Ça et ce que dit @jlb , devrait le faire à condition que ton nœud soit enregistré dans la gateway.

Ok @Mmx , je comprends.
Ce que j’ai fais ci-dessous, ce n’est pas ça ?

// On définit les identifiants des noeuds attachés à l'objet.
// Un numéro pour chaque capteur ou actionneur connecté à l'arduino
#define CHILD_ID_TEMP1 0    // Température de la sonde 1
#define CHILD_ID_TEMP2 1    // Température de la sonde 2
#define CHILD_ID_RELAIS1 2  // Etat du relais 1
#define CHILD_ID_RELAIS2 3  // Etat du relais 2

Là c’est les ID des différents capteurs, actionneurs qui compose ton noeud.
le MY_NODE_ID c’est pour le noeud, tu le mets au début du sketch. C’est l’identifiant que tu retrouveras dans le plugin Mysensors.
Si tu le dé commentes, c’est la passerelle qui attribue l’ID automatiquement, mais ça ne fonctionne pas à tout les coups.

// Enable debug prints to serial monitor
#define MY_DEBUG

//Node id defaults to AUTO (tries to fetch id from controller). Specify a number (1-254) if you want to manually set your Node ID
#define MY_NODE_ID 15

// Enable and select radio type attached
#define MY_RADIO_RF24

// Enabled repeater feature for this node
#define MY_REPEATER_FEATURE

https://www.mysensors.org/download/sensor_api_20#configuration

… Et je crois qu’un noeud n’a pas besoin de gateway pour fonctionner, mais il en a besoin pour démarrer !

Oui c’est ça
Il faut déja qu’il soit enregistré (en général c’est mieux de laisser my_node_id sur auto)
c’est lors de l’inclusion que jeedom attribut un node_id
l’enregistrement du node_id est faite sur jeedom, la gateway ne mémorise rien !
une fois l’enregistrement fait, le node id est mémorisé dans le noeud et à partir de là
si on veut que le noeud fonctionne même si pas de gateway il faut dans le sketch
#define MY_TRANSPORT_WAIT_READY_MS xxx

Si problème de distance, il faut rapprocher le noeud de la gateway la première
fois pour que l’inclusion soit ok

Merci pour vos précisions.

Je comprends mieux l’histoire de l’ID du noeud.
Si d’une part ça fonctionne forcément en fixant l’ID, j’ai peur de devoir tenir un listing des ID que j’aurai déjà utilisé.
Et si c’est seulement pour l’enregistrement, alors il est préférable que je laisse cela en Auto.

Je vais plancher sur l’amélioration de la portée.

Mais aussi (et ça n’a plsu rien à voir avec mes questions), sur l’économie d’énergie.
J’ai vu que certaines bibliothèques permettaient de mettre en sommeil l’arduino plutôt que de faire des delay() ou des wait().
J’aimerais pas la même occasion couper les antennes pour limiter les ondes.

En fait, je me rends compte que j’avais déjà essayé MySensors et que j’avais abandonné à cause de ce problème sans chercher plus loin. Maintenant je vais pouvoir reprendre pas mal de projets qui nécessitaient une communication sans fil.

Merci à vous 2 !

Ce sujet a été automatiquement fermé après 24 heures suivant le dernier commentaire. Aucune réponse n’est permise dorénavant.