Zigate, une passerelle Zigbee autonome et boostée par NodeRED

Je vous avez présenté il y a quelques semaines la PiZigate. Aujourd’hui, je vous en reparle avec la réalisation d’une passerelle Zigbee entièrement autonome toujours à base de Raspberry Zero.

Mais avant d’aller plus loin dans la pratique, voici un petit point sur le protocole Zigate qui va vous permettre de mieux comprendre la suite du projet…

Les télégrammes Zigate

La Zigate possède une structure de télégramme qui lui est propre:

Un télégramme Zigate débute toujours par « 0x01 » et se termine toujours par « 0x03« . Ces 2 bytes nous permettent de distinguer les différents télégrammes lorsqu’il y en a plusieurs les uns à la suite des autres.
Entre ces 2 bytes, nous avons le message. La encore, la structure est définie. Cette structure nous permettra de créer correctement une commande à envoyer (ex : Envoyer un signal ON) ou de décoder une réponse (ex : Valeur de l’attribut OnOff).

Le message est constitué de X bytes. La longueur dépend de ce que vous envoyez/recevez.
Le message est divisé en 2 parties. Le header qui contient des informations sur le contenu du message et le payload qui contient les données proprement dites.

Le header est toujours composé de 5 bytes :

  • 2 bytes pour la commande (que ce soit une commande d’envoi ou une réponse)
  • 2 bytes pour la longueur des données (= longueur du payload)
  • 1 byte pour le checksum (qui est un byte de contrôle)

Le payload peut être vide ou contenir un nombre « illimité » de bytes:

  • X bytes pour le payload (= les données) où X vaut la longueur que l’on retrouve dans le header.

Comment créer une commande

Connaissant à présent la forme que peut avoir un télégramme, intéressons nous aux commandes mises à disposition.
J’ai dans un premier temps utilisé les commandes disponibles sur la partie « documentation »  mais je dois avouer que la mise en page n’est pas pratique. J’ai ensuite trouvé, grâce à Google, cette page bien plus lisible sur le « Wiki » mais moins complète (ex : la commande 0x004C est manquante).

Partons d’un exemple simple, la commande pour récupérer la version de notre Zigate:

Cette commande ne dispose pas de payload(= données), il suffit d’envoyer uniquement la commande « 0x0010 ».

Le télégramme à envoyer se limitera donc au header :

0x00 0x10 0x00 0x00 0xZZ

J’ai volontairement mis la valeur du « checksum » à 0xZZ car ce champ est calculé (voir plus bas).

XOR

Le XOR ou « OU Exclusif » est une notion que l’on retrouve souvent dans la Zigate. Voici un petit tableau qui vous permettra de calculer le XOR :

source : Wikipedia

Dans le cas du transcodage, il faut appliquer un XOR entre la valeur du byte et « 0x10 ». Le « 0x10 » n’est pas précisé sur le site même de Zigate, mais dans la documentation du projet Github. Et oui, la Zigate est sympa, mais il faut chercher un peu ?

En utilisant notre table de vérité ET la valeur binaire des différents bytes, nous pouvons facilement calculer le XOR :
0x00 => 0000 0000
0x10 => 0001 0000
XOR => 0001 0000 => 0x10

Des sites permettent de convertir rapidement une valeur hexadécimal en binaire et inversement.

Heureusement lorsqu’on passe par un langage de programmation il existe des raccourcis qui ne nécessitent pas la connaissance théorique. En javascript, par exemple, le signe « ^ » permet de faire un XOR. Notre exemple ci-dessus sera codé comme suit : « 0x00 ^ 0x10 ».

Checksum

Le checksum correspond à un byte de validation. Il est calculé en faisant un XOR des bytes :

  • de la longueur
  • de la commande
  • du payload

Dans le cas de la commande « version », cela consistera à faire :

0x00 ^ 0x10 ^ 0x00 ^ 0x00 = 0x10

Transcodage

Notre télégramme est presque prêt pour être envoyé. Avant cela, il est nécessaire de transcoder le message.
La documentation dit :

  • Appliquer un XOR sur la donnée réelle et envoyer

Le transcodage consiste donc à parcourir l’ensemble des données du message et à appliquer la règle citée ci-dessus.

Télégramme final

Lorsque notre télégramme est « transcodé », il ne nous reste plus qu’à ajouter les bytes de début (0x01) et de fin (0x03) pour obtenir le télégramme à envoyer.

Et pour les réponses

Lorsque la Zigate reçoit un télégramme provenant d’un périphérique, il faut appliquer le transcodage mais à l’envers. Si nous rencontrons un byte 0x02, on l’ignore et on applique un XOR au byte suivant pour connaître la valeur réelle.
Après transcodage, nous aurons un télégramme propre que nous pourrons décoder grâce à la documentation.

Voilà pour la théorie, passons à la pratique !

Matériel Requis

Pour réaliser ce petit montage, vous aurez besoin obligatoirement de :

Et éventuellement un ou plusieurs périphériques Zigbee :

Passerelle Zigate

Maintenant que les bases théoriques sont là, nous pouvons envisager une implémentation du protocole pour notre future passerelle.

Dans mon premier article, j’avais utilisé une libraire appelée « Node-Zigate ». L’avantage était qu’une grande partie du protocole était déjà implémentée. L’inconvénient, il fallait développer le reste (Interface utilisateur, logique, etc). Le projet que je vous propose de découvrir, sera public, je souhaite donc qu’il soit compréhensible et modifiable par la majorité d’entre vous.  Une librairie et des centaines de lignes de codes n’étaient donc pas, à mon sens, une bonne idée. Je me suis donc tourné vers un outil appelé « Node RED« .

Pourquoi NodeRED ?

Certains d’entre vous le connaisse peut être, il s’agit d’un outil développé par IBM. On travaille sous forme de flux (flow). Un flux est composé d’un enchaînement de blocs que nous relions entre eux. Chaque bloc effectue un traitement particulier (ex : Lecture des bytes du port série, exécution de code Javascript, envoie d’un mail, etc).

NodeRED a été particulièrement pensé pour l’IoT et il est donc un candidat idéal pour notre Zigate. Il permet aussi de mettre en place rapidement une API, un envoie de mail, la lecture du port série, etc. On gagne énormément de temps, car il permet de se concentrer sur l’essentiel, la Zigate, sans en perdre sur l’aspect technique (ex : lecture du port série).
La représentation visuelle des flux permet aussi de mieux comprendre l’enchaînement des étapes.

Autre avantage de NodeRED, il est disponible sur toutes les plateformes que ce soit Windows, Mac ou Linux. Vous pouvez donc tester ce tutoriel sur votre PC si vous possédez un dongle USB.

Installation

Dans un premier temps, il est nécessaire de créer une image pour notre Raspberry et activer la Zigate. Je vous invite à suivre ces étapes dans cet article.

Une fois effectué, on passe à l’installation de NodeRED. Tout est expliqué sur le site même de NodeRED mais voici les étapes :

bash <(curl -sL https://raw.githubusercontent.com/node-red/linux-installers/master/deb/update-nodejs-and-nodered)

Pour démarrer NodeRED :

node-red-pi

Démarrage automatique

Pour le démarrage automatique de NodeRED, là encore rendez-vous sur le site de NodeRED.
On utilie PM2 qui va monitorer le processus et le redémarrer automatiquement s’il venait à se terminer inopinément.

#Installation de pm2
sudo npm install -g pm2
#Démarrage de NodeRED via pm2
pm2 start /usr/bin/node-red -- -v
#Si pour des raisons de sécurité vous souhaitez démarrer sur un autre port (ex : port 2000)
pm2 start /usr/bin/node-red -- -v -p 2000
#Sauvegarde de la configuration
pm2 save
pm2 startup
#redémarrage
sudo reboot

Sécurité

Tant que nous sommes dans la configuration, nous allons sécuriser NodeRED. Par défaut, l’interface est accessible à tous, mais comme notre but est d’interagir avec nos objets connectés, on souhaite éviter cela.

#Installation du tool "node-red-admin"
sudo npm install -g node-red-admin
#Génération d'un mot de passe
node-red-admin hash-pw
#On répond au question et on copie le mot de passe généré
#On édite le fichier de configuration
sudo nano /home/pi/.node-red/settings.js
#On ajoute en fin de fichier ces 2 propriétés, la première sécurise l'accès à l'interface NodeRED, la seconde sécurise l'accès à l'interface utilisateur.
#Les 2 utilisateurs peuvent être les même ou différent
adminAuth: {
    type: "credentials",
    users: [
        {
            username: "VotreNomUtilisateur",
            password: "LeMotDePasseGénérerParLaCommandeNodeRedAdmin",
            permissions: "*"
        }
    ]
},
httpNodeAuth: {
            user: "UnAutreNomUtilisateur",
            pass: "LeMotDePasseGénérerParLaCommandeNodeRedAdmin"
}
#On redémarre NodeRed, j'utilise l'identifiant PM2 du processus NodeRED qui est 0 si vous n'avec qu'un seul processus
pm2 restart 0

Vous n’êtes pas obligé de spécifier un utilisateur et un mot de passe, mais je vous le conseille fortement tout comme le choix du port sur lequel vous faites tourner NodeRED.

A ce stade, NodeRED devrait fonctionner. Si ce n’est pas le cas, utilisez la commande « pm2 log » afin de vérifier les logs de l’application.
Ensuite, rendez-vous sur : « http://ipdemaraspberry:port » (ex : http://192.168.1.255:1880) qui vous affichera l’interface principale de NodeRED :

On spécifie le nom d’utilisateur et le mot de passe défini plus haut pour arriver sur le dashboard de NodeRED.

Attaquons-nous à la deuxième partie de la configuration qui consiste à importer le projet Zigate.

On clique sur le menu en haut à droite puis sur « Manage Palette » :

Sur l’onglet « Install », on recherche et installe les paquets suivants :

  • json-db-node-red
  • node-red-contrib-uibuilder

Télécharger la dernière version du fichier contenant l’ensemble des flux.
Ensuite, importez les via le menu « Import > Clipboard ».

A présent, vous avez une série de tabs avec des blocs ainsi qu’une série de nouveaux blocs dans le menu de gauche.

Pour que l’ensemble soit effectif, il faut déployer en utilisant le bouton « deploy » :

Si vous importez plusieurs fois les flux, ces derniers ne seront pas mis à jour. NodeRED va créer de nouveaux flux et sous-flux.

Pour terminer, passons à l’importation de l’interface graphique, car oui NodeRED permet aussi d’intégrer une interface graphique avec nos petits blocs.

#Via Putty / Terminal, on se connecte à notre raspberry puis on récupère les sources
git clone https://github.com/domotiqueinfo/nodered-uibuilder-zigate.git /home/pi/.node-red/uibuilder/zigate
#Pour mettre à jour
cd /home/pi/.node-red/uibuilder/zigate
git pull

Pour que l’interface graphique soit accessible, il est nécessaire d’importer la librairie « moment » (manipulation des dates) pour UIBuilder.
Pour cela, aller sur le tab « Zigate UI » et double-cliquez sur le bloc « zigate ».
Cliquez ensuite sur le bouton « Manage front-end librairies » et installez la librairie « moment« , cela prend quelques minutes.
Si vous ne le faites pas, vous ne serez pas en mesure d’accéder à l’interface utilisateur.

Voilà, ce fut long, mais nous y sommes. Tout est en place pour tester notre Zigate :)

Remarque

Pour ceux testant ce tutoriel sur Windows ou Mac, il sera nécessaire d’adapter le port sur lequel se trouve votre dongle USB ainsi que les répertoires.
Pour cela, rendez-vous dans le menu « Configuration Nodes », double cliquez sur l’élément sous « serial-port » et choisissez le port sur lequel est connecté votre dongle USB.

Comment ça marche

En premier lieu, je tiens à préciser que toutes les commandes de la Zigate ne sont pas encore implémentées. Je me suis focalisé sur les fonctions de bases et les périphériques que je possédais afin de réaliser ce projet.

J’ai créé différents sous-flux (que l’on retrouve dans le menu de gauche, tout en bas)
Il y a :

  • « Zigate Send Telegram » , logique pour envoyer un télégramme Zigate
  • « Zigate Decode Response », logique pour décoder un télégramme Zigate
  • « Zigate Send and Receive », combine les 2 flux ci-dessus en une seule commande
  • « Zigate Discover Device » , fait appel à ces différents flux pour effectuer une découverte complète d’un périphérique Zigbee (Endpoints, Clusters, Attributes)

Avec ces flux et notre connaissance théorique, nous pouvons construire différentes interfaces.

Pour vous démontrer les possibilités de NodeRED, j’ai créé 2 types d’interfaces.
La première, une API qui vous permettra de contrôler vos périphériques via des solutions tierces (Jeedom, Edomus, IPX800, etc).
La seconde, une interface web simple pour ajouter de nouveaux produits et les contrôler.

API Rest

L’API Rest permet d’interagir avec notre Zigate au travers de commandes HTTP.

Par exemple pour connaitre la version de notre Zigate, on appelle : http://ipraspberry:port/zigate/version

Au niveau de NodeRED, il faut passer la commande Zigate à notre flux « send & receive » qui se chargera d’envoyer et décoder les télégrammes.
La commande est un simple objet qui retranscrit la documentation des commandes Zigate en objet javascript.

msg.payload = {
    msgType : 0x0010,
    data : []
}
return msg;

Certains résultats sont stockés dans une base de données JSON. On peut ainsi enregistrer les propriétés du périphérique en vue de faciliter les interactions avec celui-ci.

Interface Utilisateur

NodeRED propose également une solution pour créer votre propre interface web. Pour cette partie, il est nécessaire d’avoir des connaissances en terme de programmation (HTML, Javascript, CSS, etc). Je ne vais donc pas entrer trop dans les détails. L’avantage est que les actions de l’UI peuvent être traitées via NodeRED. Dans le cas d’une ampoule, l’interface envoie la commande à NodeRED qui, ensuite, peut être traitée ou non par l’intermédiaire de nos blocs.

L’interface est disponible via l’url « http://ipraspberry:port/zigate« . Si la page ne répond pas, je vous invite à ouvrir le bloc « zigate » et vérifier que l’URL pointe bien vers « zigate ». Vous pouvez aussi cliquer sur « Edit source files » et vérifier que les fichiers soient accessibles :

A l’heure actuelle, tous les types de périphériques ne sont pas supportés mais n’hésitez pas à me le signaler. Je me ferais un plaisir de faire évoluer cette solution !
Si l’interface utilisateur est mise à jour, seul un « git pull » sera nécessaire pour avoir la dernière version.

Scénarios

La encore, il est tout à fait possible de créer des scénarios avec NodeRED. En installant la dépendance « node-red-contrib-cron-plus« , on peut dès lors envisager des exécutions à intervalles réguliers  :

  • Tous les jours à 08:00
  • Toutes les 2 minutes

Pour connaître l’expression CRON répondant à vos besoins, je vous invite à aller sur « https://crontab.guru« .

Pour des scénarios plus complexes, on peut aussi adapter le flux « Zigate Read Serial ». Par exemple, lorsque nous recevons un télégramme « capteur de porte ouvert » alors allumer « la lumière du hall ». Toute cette logique devra être implémentée par vos soins, mais est simplifiée grâce aux différents blocs disponibles.

Dans le flux « Zigate Read Serial », vous aurez un début de solution comme le montre la capture d’écran.
Nous allons dans un premier temps décoder les télégrammes Zigate. Ensuite, vérifier si parmi ces télégrammes nous avons un message de type « 0x8102 » qui signifie une mise à jour d’un attribut.
Ensuite, suivant le périphérique on effectue une action vis à vis de la valeur reçu dans le télégramme. Dans notre exemple, nous savons que le périphérique 0xFFAA est un détecteur de mouvement et que les valeurs possibles sont 0 ou 1. Suivant le cas que nous souhaitons traiter, nous préparons la commande qui sera envoyée. Dans le cas de la détection, je rajoute un délais de 5sec et ensuite j’envoie la commande de OFF.  Avec mon capteur de mouvement Xiaomi, je ne vois pas le télégramme de non détection passée d’où ces blocs supplémentaires.
J’ai également ajouté un autre scénario pour mon capteur de porte (qui utilise le Cluster On/Off). Cette façon de faire me permet de réutiliser des blocs déjà définis ou en créer de nouveaux.

Pour les plus motivés, cela ne sera pas plus compliqué que d’écrire un script LUA.

Accès distant

Petit plus à présent !
Je vais vous montrer comment vous pouvez facilement accéder à distance à votre passerelle pour 2€/an ?

Je vais utiliser la fonctionnalité DynHost proposée par OVH. Cette fonctionnalité va me permettre d’accéder à ma Zigate ou tout autre appareil se trouvant sur mon réseau local par l’intermédiaire d’un nom de domaine.

Première chose à faire est d’acheter un nom de domaine. Ensuite dans l’interface utilisateur d’OVH vous avez un menu « DynHost ».
Pour la mise en place, on suit la documentation d’OVH sur le sujet.

Le petit exercice consiste à créer le flux qui nous permettra de mettre à jour l’adresse IP avec celle de notre connexion internet.

Pour cela, nous avons besoin des dépendances suivantes :

  • node-red-contrib-cron-plus
  • node-red-contrib-ip

La logique est la suivante :  toutes les heures, nous allons envoyer à OVH notre adresse IP publique afin qu’elle soit toujours à jour.
On utilise le bloc « CRON+ » afin d’automatiser l’exécution :

On utilise ensuite le bloc « IP » dans lequel nous spécifions que nous souhaitons uniquement récupérer l’adresse publique au format IPV4.

Nous envoyons une requête HTTP à OVH afin de mettre à jour notre adresse IP avec le résultat :

Il est nécessaire de spécifier le type « d’authentification basic » et créer l’utilisateur via la procédure DynHost.
Quant à l’url, elle aura le format suivant :

http://www.ovh.com/nic/update?system=dyndns&hostname=zigate.mon-nom-de-domaine.com&myip={{{msg.payload.publicIPv4}}}

On récupère la valeur du bloc précédent en utilisant « {{{msg.payload.publicIPv4}}}« .
Essayez dans un premier temps l’URL OVH dans votre navigateur afin de confirmer que tous les paramètres soient les bons (url + identifiants).

Le résultat final devrait ressembler à ceci :

Lorsque votre flux NodeRED met bien à jour votre IP distante chez OVH, il ne vous reste plus qu’à ouvrir les ports sur votre routeur.
Cette opération permettra d’accéder à votre Zigate n’importe où dans le monde. Cette manipulation est spécifique à chaque routeur (Orange, Free, SFR, etc), mais le principe est toujours le même.
Il faut rediriger le port local NodeRED de notre raspberry, par défaut 1880, vers un port distant au choix. De cette manière, en utilisant  notre nom de domaine ET le port distant, nous pourrons accéder à notre Zigate à partir de n’importe où.

Dans l’exemple ci-dessous, j’ai redirigé le port local NodeRED « 1880 » vers le port distant « 1880 » :

Conclusion

En allant un peu plus loin que mon premier article, je me rends compte un peu plus des possibilités offertes par la Zigate ainsi que l’énorme travail réalisé. Il ne faut néanmoins pas avoir peur d’aller se perdre dans la documentation de la Zigate et du Zigbee (notamment pour les Clusters) pour parfois mieux comprendre le contenu des télégrammes.

NodeRED m’a permis de construire rapidement une passerelle autonome, accessible à distance et évolutive. Il me permettra aussi, dans le futur, d’intégrer éventuellement d’autres fonctionnalités que ce soit pour la Zigate ou autres. J’ai ainsi vu des plugins IFTTT, Tuya, HomeBridge, etc. Bref, tout ce qu’il faut pour une maison connectée.

Avec une meilleure connaissance du Zigbee, une meilleure maîtrise de la Zigate et les plugins disponibles pour NodeRED, on peut envisager d’avoir une passerelle Zigbee complète avec des scénarios, des notifications, un dashboard, etc. Avoir des bases en programmation est un plus afin de pouvoir concrétiser ses idées.

Cette solution ne remplacera pas une solution professionnelle qui sera bien plus simple pour l’utilisateur final mais si vous avez 50€ à dépenser vous pouvez déjà avoir une solution stable, évolutive, sur mesure et répondant à la majorité des besoins quotidiens.