Accueil / Domotique / MySensors v2 – découverte, nouveautés, conversion d’anciens croquis

MySensors v2 – découverte, nouveautés, conversion d’anciens croquis

La librairie MySensors vient de recevoir une mise à jour importante et passe par la même occasion à la version 2. C’est l’occasion de découvrir (ou redécouvrir) cette librairie pour créer des objets connectés DIY développée par l’équipe Suédoise Sensnology AB. Cette article sera suivi d’une série de tutoriels pour intégrer des objets connectés dans Jeedom et Domoticz.

You can read this post in English here

Il y a déjà beaucoup d’explications sur le principe de la librairie MySensors sur internet. Dans cet article nous allons nous concentrer sur les modifications apportées dans la version 2 de la librairie. Avant de rentrer dans le vif du sujet, la librairie MySensors est maintenant disponible dans l’IDE Arduino, vous pouvez l’installer depuis de gestionnaire de bibliothèque très facilement.

mysensors version 2 installation ide arduino

Le plus gros changement se trouve sous le capot. L’équipe Sensnology a fait un gros travail d’optimisation qui a permis de réduire la taille de la librairie de 20%, ce qui est toujours très appréciable dans un projet Arduino. Cette optimisation s’accompagne d’un changement dans l’écriture du code. Par exemple, il n’est plus nécessaire de créer un objet gw (MySensor gw) puis d’appeler la méthode désirée (par exemple gw.begin), on appel maintenant directement la méthode désirée, par exemple sendSketchInfo() pour envoyer le nom et la version de l’objet.

Ecrire un programme Arduino avec la version 2 de MySensors

L’écriture d’un programme Arduino avec la version 2 n’est pas fondamentalement différente. L’écriture est simplifiée et plus claire, beaucoup de mécanisme se déroulent de manière transparente. Pour comprendre comment écrire avec la version 2, je vous propose de suivre pas à pas l’exemple UVSensor basé sur le capteur UVM-30A proposé dans les exemples de la librairie.

Pour faciliter la mise au point du programme ou identifier une erreur de câblage, on active le traçage du programme sur le port série avec

#define MY_DEBUG

Choisissez le type de module radio employé dans votre projet. Attention à ne pas mélanger les standards sinon vos modules ne pourront pas communiquer entre eux (nous verrons les différences et quel matériel choisir dans un prochain article). Dans le cas présent on utilise un module NRF24L01 fonctionnant à 2,4 Ghz. Au passage, sachez que MySensors supporte 3 technologies pour transporter les données : nRF24, RFM69 et RS485. Si vous avez une plus grande distance à couvrir ou que vous avez de nombreux mur qui peuvent gêner la transmission de données, vous pouvez opter pour un modèle avec une antenne externe (nRF24L01+PA+LNA).

#define MY_RADIO_NRF24
//#define MY_RADIO_RFM69
//#define MY_RS485

Avec la version 2, le fichier MyConfig n’est plus nécessaire (mais il existe encore). Tout peut être configuré directement dans le programme Arduino avec des #define. Par contre tous les paramètres doivent être déclarés avant d’appeler la librairie MySensors.

Vient ensuite la déclaration des librairies externes. On a toujours besoin d’appeler les 2 librairies SPI et MySensors. Vous l’avez remarqué, un ‘s‘ à la fin du nom de la librairie permet de distinguer la version 2 des précédentes. Si vous migré vos anciens sketchs, commencez par là !

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

Ensuite on définit les identifiants des noeuds attachés à l’objet (les enfants de l’objet). On attribue un numéro à chaque capteur ou actionneur branché à l’Arduino. Dans le cas présent,

#define CHILD_ID_UV 0

et enfin on créé un objet MyMessage. Cette objet prend en paramètre l’identifiant du noeud et son type de données. Dans ce cas un index d’UV (V_UV).

MyMessage uvMsg(CHILD_ID_UV, V_UV);

Nous verrons dans le prochain paragraphe les modifications apportées au types de données gérés par la librairie. Ce constructeur est très important car non seulement il va contenir la donnée que l’on va transmettre à la gateway mais c’est également lui que va se charger de mettre en forme avant d’envoi à partir du type de donnée indiqué.

Rentrons maintenant un peu plus dans le programme Arduino. Un sketch Arduino est maintenant constitué de trois blocs obligatoires :

  • La fonction d’initialisation setup(){} présent dans tous les programmes Arduino. Il n’y a rien à faire coté MySensors ici.
  • La nouvelle fonction presentation(){} qui permet d’initialiser l’objet auprès de la Gateway Mysensors. Au minimum, on doit envoyer les informations sur l’objets avec la fonction sendSketchInfo(désignation, numéro de version) et enregistrer l’objet (et les capteurs/actionneurs) avec la méthode present(). Cela donne ici
void presentation()  {
  // Send the sketch version information to the gateway and Controller
  sendSketchInfo("UV Sensor", "1.2");

  // Register all sensors to gateway (they will be created as child devices)
  present(CHILD_ID_UV, S_UV);
}
  • la fonction loop(){} habituelle des projets Arduino.

La boucle loop ne fait que trois choses :

  • Récupérer la mesure du capteur UV sur la broche analogique
uint16_t uv = analogRead(UV_SENSOR_ANALOG_PIN);
  • Détermine l’index d’UV et détermine s’il doit être publié (s’il la valeur a changé ou si la dernière mesure date de plus de 5 minutes). On envoi l’index avec la fonction send() comme ceci
send(uvMsg.set(uvIndex,2));
  • Met en sommeille l’Arduino et le module radio durant un temps donné (on verra dans un prochain article comment réveiller l’objet à l’aide d’une interruption). On indique le temps en millisecondes. Par exemple, pour faire dormir l’objet 30 secondes, on ferra 30 x 1000.
sleep(SLEEP_TIME);

Comment convertir les sketchs en version 2

Dans la version 2, toute la configuration se fait directement dans le croquis Arduino avec des #define. Le fichier MyConfig est toujours présent pour ceux qui préfèrent séparer la configuration du programme mais ce n’est plus la logique préconisée par l’équipe de développement.

Tous les #define doivent être fait avant d’inclure la librairie MySensors. En effet, au moment de son appel, la librairie analyse la configuration et s’occupe d’inclure tout ce qui est nécessaire au fonctionnement du projet.

Ajoutez un ‘s‘ à

#include <MySensors.h>

Supprimez MySensor gw et gw.begin()

Supprimer gw. devant tous les appels à la librairie. Par exemple gw.send(msg) devient send(msg).

Déplacez la présentation de l’objet dans la nouvelle fonction presentation() comme ceci :

void presentation()  {
  sendSketchInfo("UV Sensor", "1.2");
  present(CHILD_ID_UV, S_UV);
}

Autres nouveautés de la version 2

Outre la réécriture du code qui a permis d’alléger la librairie de 20%, la version apporte un très grand nombre de nouveautés (la liste complète ici en Anglais) dont voici les principales :

  • Une Gateway devient un noeud comme un autre. Par exemple on peut relier une Gateway ESP8266 et une Gateway Ethernet sans passer par un module radio. Pratique pour tester la librairie si vous n’avez pas encore de module radio.
  • De nouveaux types de capteurs ont été ajoutés (la liste complète au prochain paragraphe).
  • On peut maintenant définir une adresse ip fixe, ce qui est très pratique pour relier une Gateway à un serveur domotique Jeedom ou Domoticz.
  • On peut maintenant créer une Gateway MQTT (client) en Ethernet ou à base d’ESP8266

Nouvelles fonctions pratiques

De nouvelles fonction très pratiques ont été ajoutées :

  • before() : cette fonction permet d’exécuter du code avant que la librairie MySensors soit initialisée
  • setup() : la fonction setup habituelle des croquis Arduino est exécutée après l’initialisation de la librairie MySensors
  • receive(const MyMessage &message) : permet de récupérer les messages reçus par l’objet
  • receiveTime(unsigned long ts) : permet de récupérer l’heure sur la gateway. On demande l’heure à l’aide de la fonction requestTime().

Nouveaux capteurs et formats de données

L’une des forces de la librairie MySensors est d’avoir standardisé les formats de données publiées par les capteurs. C’est aussi une faiblesse car si votre capteur n’existe pas dans le liste (par exemple un capteur de radioactivité que j’ai vu passer sur les forums), il faut en faire la demande à l’équipe de développement et attendre une prochaine mise à jour de la librairie…puis de tous les plugins des serveurs domotique. Il existe toutefois un objet appelé S_CUSTOM avec le type V_CUSTOM associé. Rassurez vous il y a déjà beaucoup de capteurs supportés (la liste complète ici en Anglais).

La version 2 ajoute les capteurs suivants (d’après) :

  • S_INFO (36) – pour afficher du texte sur un écran LCD externe relié à l’objet. On utilise le format V_TEXT
  • S_GAS (37) – Débitmètre de gaz. Formats associés V_FLOW (débit), V_VOLUME (volume)
  • S_GPS (38) – Capteur GPS. Format V_POSITION
  • S_WATER_QUALITY (39) – Capteur qualité d’eau. Formats disponibles V_TEMP, V_PH, V_ORP, V_EC, V_STATUS (voir ci-dessous)
  • S_LIGHT est déprécié. Il faut utiliser S_BINARY à la place

et les nouveaux formats associés (et quelques autres) :

  • V_TEXT (47) – pour S_INFO.
  • V_CUSTOM (48) – pour  S_CUSTOM. Attention, on écrit pas un roman ici
  • V_POSITION (49) – Position et altitude (en m) GPS. Formatage : latitude;longitude;altitude(m), par exemple « 55.722526;13.017972;18 »
  • V_IR_RECORD (50) – Record IR codes S_IR for playback
  • V_PH (51), – Pour S_WATER_QUALITY, PH de l’eau
  • V_ORP (52) – Pour S_WATER_QUALITY, Potentiel redox de l’eau en mV. (water ORP)
  • V_EC (53) – pour S_WATER_QUALITY, conductivité en μS/cm (microSiemens/cm)
  • V_VAR (54) – pour S_POWER, puissance réactive en volt-ampere (var)
  • V_VA (55) – pour S_POWER, puissance apparent en volt-ampere (VA)
  • V_POWER_FACTOR (56) – pour S_POWER, Ratio entre la puissance réelle et la puissance apparente. Valeur décimale comprise entre [-1,..,1]
  • V_DIMMER est déprécié – utilisez V_PERCENTAGE
  • V_HEATER est déprécié – utilisez V_HVAC_FLOW_STATE
  • V_LIGHT est déprécié – utilisez V_STATUS

Voilà pour les principales nouveautés apportées par cette nouvelle version. Cet article est le premier d’une petite série dans laquelle nous verrons comment créer une Gateway et l’intégrer dans un serveur domotique (Jeedom, Domoticz..), fabriquer un objet connecté à base de module radio nRF24L01.

    • Sartog

      Bonjour et merci pour cet article très instructif.

      Découvrant MySensor, je m’arrachais les cheveux à savoir ce qu’il fallait mettre à minima pour que ça fonctionne … d’autant que j’utilise MySensors 2.0 alors que les exemples disponible MySensor ne sont pas compatible avec cette bibliothèque !!

      Par contre, pourriez-vous m’indiquer où trouver des informations sur cette ligne de code, s’il vous plait ?
      « send(uvMsg.set(uvIndex,2)); »

      Je n’ai rien trouvé sur le net m’expliquant l’histoire de « uvIndex » et du chiffre « 2 » !

      Je fais un sketch qui récupère la valeur d’une double thermistance NTC, convertis cette valeur en T° et l’envoi, mais je ne voudrais pas faire un copier coller basique 🙂

      Merci par avance pour votre réponse 🙂

      • christophe

        Bonjour Sartog. Merci beaucoup. On va décoder la fonction :
        – send : c’est la fonction qui permet d’envoyer un message
        – uvMsg : c’est l’objet qui contient le message. Il est déclaré au début du code
        – uvIndex : c’est la variable qui contient la valeur mesurée par le capteur
        Avant d’envoyer un message, on doit doit formater correctement le message (conversion du type de données, nombre de chiffres significatifs…). On le fait avec la fonction set. Ce qui donne :
        – uvMsg.set(uvIndex,2) : on copie avec 2 chiffres significatifs l’index uvIndex dans l’objet usMsg que l’on envoi ensuite avec la fonction send.
        Ouff, j’espère ne rien avoir oublié 😉
        A très bientôt

      • Sartog

        Bonjour Christophe.
        Je suis confus, mais je n’arrive pas à voir votre réponse complète.
        Dans la section « commentaires récents », sur la droite de la page, je vois que vous m’avez écrit, mais lorsque je clique dessus ça ne m’emmène pas sur votre réponse.
        Idem quand j’actualise la page.

        Commentaire en attente de validation, bloqué, supprimé ?

        Voici ce que j’ai dans commentaires récents :
        « christophe: Bonjour Sartog. Merci beaucoup. On va décoder la fonction : – send : c’est la fo.. »

        • Bonjour Sartog. Aucun problème, c’est de ma faute. Normalement tout est rentré dans l’ordre. Bonne journée.

          • Sartog

            Pas de problème 🙂

            Merci pour ton complément d’information.
            Ce que je ne comprenais pas s’était le uvIndex et le 2.

            Donc si je comprends bien:
            – le uvIndex provient de la ligne « uint16_t uv = analogRead(UV_SENSOR_ANALOG_PIN); ». Je ne comprenais du fait que la variable de cette ligne est uv et non uvIndex :p
            – le chiffre 2 te retourne ton résultat sur les 2 premiers caractères de uvIndex (si uvIndex = 1200, tu récupère que le 12) ?

            Maintenant, je vais pouvoir m’amuser à faire des tests avec toutes ces nouvelles info 🙂

            • Mais de rien. Continuons :
              – uvIndex est un nombre décimal (float) déclaré ligne 58. Le uvIndex est calculé à partir de la mesure physique renvoyée par le capteur (variable uv). C’est tout le code depuis la ligne 76 à la ligne 97 qui permet de le déterminer.
              – Le 2 correspond au nombre de chiffres significatifs après la virgule https://www.arduino.cc/en/Serial/Print
              Pour t’aider à comprendre ce qui se passe, le mieux est de dé-commenter toutes les impressions sur le port série (serial.print) qu’on trouve partout dans le code et d’activer le moniteur série.
              Voilà, j’espère que ton projet avance bien. A très bientôt.

            • Sartog

              Je comprends vite mais il faut m’expliquer longtemps !!!

              J’ai ouvert le sketch MySensors complet, je comprends mieux l’origine du uvIndex (même si je n’ai pas compris pourquoi tant de calcul, mais ça doit s’expliquer en regardant l’information provenant du capteur d’UV) et du 2.

              Visiblement, avec la bilbiothèque thermistor.h (spécifique pour sonde NTC) il n’y a pas ce fonctionnement d’index.
              Le système se charge de mesurer la tension du pont diviseur, en déduire la résistance et la convertir en température … en théorie 🙂

              Ton article et ton aide m’ont bien aidé à comprendre les éléments de bases à inscrire dans mon nœud MySensors.
              J’espère réussir à mettre tout cela à profit ce week-end !!
              Encore merci à toi (pour la peine, je me suis abonné à FB et Youtube :p)

            • Aucun problème. Ce n’est pas si évident que ça. Une fois qu’on l’a fait, c’est facile mais avant… En fait il doit y avoir une confusion sur la signification de la variable uvIndex. Je n’ai pas regardé dans le détail mais voilà comment ça marche en gros. Le capteur renvoi une mesure sur 1024 niveaux. Ensuite on détermine l’index UV (https://fr.wikipedia.org/wiki/Indice_UV) qui correspond au niveau de la mesure renvoyé par le capteur. Il y a 12 plages (le tableau uvIndexValue). On parcout le tableau uvIndexValue (lignes 82 à 90) et on en sort lorsque la valeur mesurée est <= à la valeur uvIndexValue testée uvIndexValue[i]. Ensuite de 92 à 97, il essai de rendre plus précis l'index UV, par exemple trouver si c'est plutôt 1 ou 1,887. C'est ce résultat décimal qui est tronqué à 2 chiffres significatifs au moment de la publication sur le réseau MySensors.
              Concernant la librairie thermistor.h, il y a la fonction readTemperature qui renvoi la température directement en °C (https://github.com/p-v-o-s/open-lab-monitor/blob/master/arduino/libraries/ThermistorLib/thermistor.cpp). Donc rien à faire de ce coté. Voilà. Bon courage pour ce week end alors ! Si vous voulez partager votre projet, je peux écrire un article. A très bientôt.

      • Bonjour Sartog. Merci beaucoup. On va décoder la fonction :
        – send : c’est la fonction qui permet d’envoyer un message
        – uvMsg : c’est l’objet qui contient le message. Il est déclaré au début du code
        – uvIndex : c’est la variable qui contient la valeur mesurée par le capteur
        Avant d’envoyer un message, on doit formater correctement le message (conversion du type de données, nombre de chiffres significatifs…). On le fait avec la fonction set. Ce qui donne :
        – uvMsg.set(uvIndex,2) : on copie avec 2 chiffres significatifs l’index uvIndex dans l’objet usMsg que l’on envoi ensuite avec la fonction send.
        Ouff, j’espère ne rien avoir oublié 😉
        A très bientôt