Différences entre les versions de « Boitier Fil Pilote a base d ESP8266 »

De GCE Electronics
Aller à la navigation Aller à la recherche
Ligne 268 : Ligne 268 :
==Pour aller plus loin==
==Pour aller plus loin==
A ce stade nous avons :
A ce stade nous avons :
<ul>
* assemblé le montage dans son boitier ;
<li>assemblé le montage dans son boitier ;</li>
* fait sa configuration initiale pour l’attacher au réseau WiFi du logement ;
<li>fait sa configuration initiale pour l’attacher au réseau WiFi du logement ;</li>
* utilisé le boitier de manière autonome par appui sur le bouton de changement d’état ;
<li>utilisé le boitier de manière autonome par appui sur le bouton de changement d’état ;</li>
* intégré dans un dashboard de l’IPX800 un widget permettant de visualiser l’état du pilote et de le faire changer via l’interface graphique ;
<li>intégré dans un dashboard de l’IPX800 un widget permettant de visualiser l’état du pilote et de le faire changer via l’interface graphique ;</li>
* paramétré un ou plusieurs « Push » pour pouvoir piloter le boitier via des scenarii.
<li>paramétré un ou plusieurs « Push » pour pouvoir piloter le boitier via des scenarii.</li>
 
</ul>


Nous n’avons cependant pas encore exploité :
Nous n’avons cependant pas encore exploité :
<ul>
* les remontées de température et d’humidité possibles si un capteur DHT22 a été branché ;
<li>les remontées de température et d’humidité possibles si un capteur DHT22 a été branché ;</li>
* la modification de certains paramètres (luminosité des LEDs, nom du boitier sur le réseau…) ;
<li>la modification de certains paramètres (luminosité des LEDs, nom du boitier sur le réseau…) ;</li>
* les possibilités de remontées d’informations du boitier vers l’IPX en cas de dépassement de certains seuils pour que celui-ci puisse déclencher de lui-même certaines actions.
<li>les possibilités de remontées d’informations du boitier vers l’IPX en cas de dépassement de certains seuils pour que celui-ci puisse déclencher de lui-même certaines actions.</li>
 
</ul>
===Objet des API en fonctionnement « normal » du boitier===
===Objet des API en fonctionnement « normal » du boitier===
En fonctionnement « normal », c’est à dire hors du cycle « initialisation », le programme tourne en permanence dans une boucle qui attend des événements (appui sur un bouton, requête http, mesure périodique de température et d’humidité), ce qui va permettre de :
En fonctionnement « normal », c’est à dire hors du cycle « initialisation », le programme tourne en permanence dans une boucle qui attend des événements (appui sur un bouton, requête http, mesure périodique de température et d’humidité), ce qui va permettre de :
<ul>
* consulter les paramètres du dispositif et l’état du fil pilote ;
<li>consulter les paramètres du dispositif et l’état du fil pilote ;</li>
* faire changer l’état du fil pilote ;
<li>faire changer l’état du fil pilote ;</li>
* provoquer un « Hard Reset » du boitier pour qu’il repasse en mode « initialisation » (par exemple en vue d’un changement de SSID ou de clé WPA sur le réseau WiFi) ;
<li>provoquer un « Hard Reset » du boitier pour qu’il repasse en mode « initialisation » (par exemple en vue d’un changement de SSID ou de clé WPA sur le réseau WiFi) ;</li>
* renseigner ou modifier certains paramètres parmi lesquels :
<li>renseigner ou modifier certains paramètres parmi lesquels :
** la luminosité des LEDs ;
<ul>
** le nom du boitier (même paramètre que « DEVICE_NAME » à l’initialisation) ;
<li>la luminosité des LEDs ;</li>
** l’activation ou la désactivation du capteur DHT (il n’y a pas de détection automatique de la présence de celui-ci et il peut être installé sans que l’on veuille pour autant l’exploiter) ;
<li>le nom du boitier (même paramètre que « DEVICE_NAME » à l’initialisation) ;</li>
 
<li>l’activation ou la désactivation du capteur DHT (il n’y a pas de détection automatique de la présence de celui-ci et il peut être installé sans que l’on veuille pour autant l’exploiter) ;</li>
''NB : activer le capteur DHT alors qu’il n’est pas installé ne générera pas d’erreur mais du retard dans l’affichage de l’état du dispositif puisqu’une vingtaine de tentatives de lecture de la température et de l’humidité vont être faites sans aboutir.''
''NB : activer le capteur DHT alors qu’il n’est pas installé ne générera pas d’erreur mais du retard dans l’affichage de l’état du dispositif puisqu’une vingtaine de tentatives de lecture de la température et de l’humidité vont être faites sans aboutir.''</li>
 
<li>faire afficher (via l’USB et le moniteur série d’Arduino IDE) le contenu de l’EEPROM et la remettre complètement à 0 si besoin ;</li>
* faire afficher (via l’USB et le moniteur série d’Arduino IDE) le contenu de l’EEPROM et la remettre complètement à 0 si besoin ;
<li>les paramètres de l’IPX à joindre pour remonter des alertes sur la température et l’humidité (adresse IP de l’IPX et son APIkey si celle-ci est activée) ;</li>
** les paramètres de l’IPX à joindre pour remonter des alertes sur la température et l’humidité (adresse IP de l’IPX et son APIkey si celle-ci est activée) ;
<li>les seuils de température et d’humidité ainsi que les sorties virtuelles que la détection de ces seuils doit faire changer d’état ;</li>
** les seuils de température et d’humidité ainsi que les sorties virtuelles que la détection de ces seuils doit faire changer d’état ;</li>
''NB1 : les seuils de température sont obligatoires, mais ceux d’humidité ne le sont pas, si on ne souhaite pas surveiller ce paramètre.''
 
''NB
- les seuils de température sont obligatoires, mais ceux d’humidité ne le sont pas, si on ne souhaite pas surveiller ce paramètre.''
- les sorties virtuelles passent à 1 quand la température descend en dessous du seuil mini et quand l’humidité passe au dessus du seuil maxi, elles passent à 0 quand la température monte au dessus du seuil maxi et quand l’humidité passe en dessous du seuil mini. Cela permet, si la même sortie virtuelle est configurée pour les 2 paramètres d’avoir la même action, par exemple allumer le chauffage pour monter la température et donc baisser l’humidité, au niveau de l’IPX qui ignorera lequel des 2 la déclenche (simplification des scéranii).''


''NB2 : les sorties virtuelles passent à 1 quand la température descend en dessous du seuil mini et quand l’humidité passe au dessus du seuil maxi, elles passent à 0 quand la température monte au dessus du seuil maxi et quand l’humidité passe en dessous du seuil mini. Cela permet, si la même sortie virtuelle est configurée pour les 2 paramètres d’avoir la même action, par exemple allumer le chauffage pour monter la température et donc baisser l’humidité, au niveau de l’IPX qui ignorera lequel des 2 la déclenche (simplification des scéranii).''
</ul>
</ul>
===Les commandes http associées à ces API===
===Les commandes http associées à ces API===
En fonctionnement normal, différentes commandes, éventuellement associées à des paramètres, vont donc permettre de déclencher certaines actions, obtenir des informations ou régler des valeurs, comme décrit ci-dessus. La commande se passe, depuis un navigateur Web, avec la syntaxe suivante :
En fonctionnement normal, différentes commandes, éventuellement associées à des paramètres, vont donc permettre de déclencher certaines actions, obtenir des informations ou régler des valeurs, comme décrit ci-dessus. La commande se passe, depuis un navigateur Web, avec la syntaxe suivante :


http://adresse_IP_du_boitier/commande_et_paramètres_éventuels
<code></nowiki>http://adresse_IP_du_boitier/commande_et_paramètres_éventuels</nowiki></code>


Les commandes possibles et leur syntaxe sont détaillées ci-dessous. Elles peuvent aussi, bien évidemment, être envoyées via des « Push » depuis l’IPX (par exemple pour augmenter la luminosité des LEDs dans la journée et les réduire la nuit, en fonction d’horaires ou d’un capteur de luminosité ambiante).
Les commandes possibles et leur syntaxe sont détaillées ci-dessous. Elles peuvent aussi, bien évidemment, être envoyées via des « Push » depuis l’IPX (par exemple pour augmenter la luminosité des LEDs dans la journée et les réduire la nuit, en fonction d’horaires ou d’un capteur de luminosité ambiante).


''NB1 : les commandes et les paramètres ne sont pas sensibles à la casse et peuvent donc indifféremment être entrés en Majuscules ou minuscules ou un mélange des deux.''
''NB
 
- les commandes et les paramètres ne sont pas sensibles à la casse et peuvent donc indifféremment être entrés en Majuscules ou minuscules ou un mélange des deux.''
''NB2 : afin de retrouver facilement quel boitier porte quelle adresse IP, il est fortement conseillé de fixer l’adresse IP du boitier via le service DHCP d’une Box ou d’un routeur présent sur le réseau en associant une adresse IP à l’adresse MAC de la carte. Se référer au manuel de sa Box ou du routeur pour cela.''
- afin de retrouver facilement quel boitier porte quelle adresse IP, il est fortement conseillé de fixer l’adresse IP du boitier via le service DHCP d’une Box ou d’un routeur présent sur le réseau en associant une adresse IP à l’adresse MAC de la carte. Se référer au manuel de sa Box ou du routeur pour cela.''


Toutes les commandes renvoient une réponse en JSON ce qui permet de les exploiter dans des widgets HTML via du JavaScript (c’est ce qui est fait dans le widget proposé ci-dessus).
Toutes les commandes renvoient une réponse en JSON ce qui permet de les exploiter dans des widgets HTML via du JavaScript (c’est ce qui est fait dans le widget proposé ci-dessus).
Ligne 555 : Ligne 553 :
}
}
</source>
</source>
==Interfaçage avec l’IPX800 de plusieurs boîtiers dotés de capteur DHT22==
==Interfaçage avec l’IPX800 de plusieurs boîtiers dotés de capteur DHT22==
Une fois les dispositifs mis en service et leurs différents paramètres réglés, ceux-ci peuvent-être intégrés dans l’IPX800 v.4 afin de :
Une fois les dispositifs mis en service et leurs différents paramètres réglés, ceux-ci peuvent-être intégrés dans l’IPX800 v.4 afin de :

Version du 12 février 2019 à 19:17

[[Fichier:|300px]]
Nom
Famille

Doc v.1.4 par Patrice Le Graverend

Le 12 février 2019

Introduction

Les solutions de pilotage sans fil de radiateurs électrique depuis un IPX800 sont peu nombreuses. Il est possible de le faire :

Ces deux solutions présentent certaines limites :

  • portée et stabilité du pilotage et des retours d’information pour la solution Enocean ;
  • complexité d’intégration, dépendance par rapport à une société tierce pour la solution Heatzy et ouverture d’un canal de communication entre les serveurs de cette dernière et le boitier et donc le réseau local de la maison (failles de sécurité possibles).

J’ai donc décidé de créer mes propres boitiers, complètement autonomes et intégrés avec mon IPX800 v.4.

Je remercie vivement @fgtoul qui m’a mis sur le chemin de cette fabrication avec ses tutos sur l’ESP8266 et pour ses précieux conseils lors de nos échanges au cours de la mise au point de ces boitiers. Je remercie également, sans pouvoir les citer tant ils sont nombreux et parfois anonymes, ceux qui partagent leur expérience sur des sites et forums divers et variés, et qui m’ont permis d’acquérir les connaissances nécessaires à la conception et la fabrication de ces petits modules.

Le principe, les objectifs

L’idée de base était d’avoir un dispositif complètement autonome permettant :

  • de commander un radiateur avec les 4 ordres de base : Confort, Eco, Hors Gel et Arrêt ;
  • de pouvoir lui intégrer un capteur de mesure de température et d’humidité ;
  • de pouvoir l’interroger pour avoir des retours de différentes informations : état du fil pilote, nom du dispositif, température et humidité si le capteur est présent ;
  • de pouvoir lui faire envoyer des requêtes vers l’IPX800 pour changer d’état des sorties virtuelles en fonction de seuils de température et d’humidité, et donc de pouvoir faire déclencher des actions via l’IPX ;
  • de pouvoir complètement le paramétrer sans avoir besoin d’intervenir dans le code et devoir faire une version spécifique à chaque boitier, plus complexe à maintenir et à faire évoluer ;
  • de conserver les informations en cas de coupure de courant et de redémarrer dans l’état précédent la coupure.

L’article

Ce wiki aborde :

  1. dans une première partie, accessible à des débutants, la fabrication du dispositif sous forme d’un ensemble prêt à monter et à utiliser directement depuis un IPX800. Il faut juste être en mesure de réaliser soi-même un circuit imprimé ou bien le faire fabriquer via une entreprise spécialisée. Les composants peuvent être achetés dans des boutiques d’électronique ou via des sites sur Internet. Il est donc également nécessaire de savoir monter et souder des composants sur une carte pour assembler le dispositif. Les schémas, typons et codes sources sont téléchargeables à partir du wiki. Je donnerai également, à titre d’exemple, la façon dont j’ai réalisé la mise en boitier.
  2. Une deuxième partie détaille les commandes http qui peuvent être envoyées au boitier pour le configurer plus finement et pouvoir exploiter toutes ses fonctionnalités (mesure de température et d’humidité), remontée d’infos sur des dépassements de seuils de température et/ou d’humidité…
  3. Une troisième partie, plus technique, pour les plus curieux et les plus initiés, détaille un peu plus le fonctionnement du programme écrit directement en C++, et non via un générateur de code comme Tuniot présenté par @fgtoul dans ses tutos.

Licence d’utilisation et de modification

Les schémas, typons et codes sources sont fournis sous licence Creative Commons BY NC SA de la part de Patrice Le Graverend ce qui signifie qu’ils peuvent être utilisés, communiqués, modifiés :

  • BY : en faisant clairement apparaître mon nom « Patrice Le Graverend » ou mon pseudo utilisé sur le forum de l’entreprise GCE Electronics « PatLeHibou » (sur le typon et dans le code source) ;
  • NC : sans en faire d’utilisation commerciale ;
  • SA : et en les repartageant dans les mêmes conditions en cas d’adaptation ou de modification.


Fichier:CC-BY-NC-SA-88x31.png

Mise en garde préalable, décharge de responsabilité

Piloter un radiateur via son fil pilote, nécessite de brancher le montage sur le secteur 220 V. Il convient donc d’adopter la plus grande prudence dans sa manipulation, son test, sa mise au point, ainsi que sa protection par rapport à l’humidité ou d’éventuels éléments conducteurs qui pourraient tomber sur le circuit.

L’auteur décline toute responsabilité en cas de dysfonctionnement du montage proposé dans ces pages ainsi que de tout dommage, matériel ou humain, pouvant survenir à l’occasion de la fabrication ou de l’utilisation de celui-ci.

Le montage électronique

L’architecture globale

Le cœur du montage repose sur un ESP8266. J’ai choisi, pour ma part, son intégration sous forme d’une carte WeMos D1 mini, plus petite que la NodeMCU LUA Lolin v.3 proposée par @fgtoul dans ses tutos et donc plus facile à intégrer dans un boitier de petite taille. Cette carte présente le même avantage d’une programmation facile via le port USB. Les pré-requis d’installation sont donc les mêmes que ceux décrits dans le tuto de @fgtoul : ESP8266 : ENVIRONNEMENT. La carte à choisir dans Arduino IDE est toutefois WeMos D1 R2 & mini au lieu de NodeMCU 1.0.

Une petite carte d’alimentation autonome 220V~-5V= assure l’alimentation électrique du circuit.100px

Deux poussoirs permettent :

  • l’un, accessible depuis l’extérieur du boitier, de faire changer le radiateur d’état dans un cycle (Confort -> Eco -> Hors Gel -> Arrêt -> Confort) ;
  • l’autre, accessible uniquement en ouvrant le boitier, pour forcer un « Hard Reset » du dispositif (en cas de changement de réseau WiFi par exemple, ou de modification de la clé WPA).

Deux LEDs permettent :

  • l’une, bleue, de voir que le dispositif est en fonctionnement et d’avoir des retours d’informations sur la connexion WiFi ;
  • l’autre, bicolore rouge/vert, pour indiquer l’état du pilote : rouge = Confort, orange (rouge+vert) = Eco, Vert = Hors Gel, Eteint = Arrêt.

Un capteur DHT22 (optionnel) permet la mesure de température et d’humidité. S’il est absent, la résistance de pull-up peut être omise.

Deux optocoupleurs MOC3041 en série avec des diodes 1N4007 assurent quant à eux la délivrance des alternances positives et/ou négatives (ou leur non-délivrance) sur le fil pilote pour générer les 4 états. Merci à Pierre-Henri pour son article sur le sujet qui m’a mis sur la voie de cette intégration, plutôt qu’avec un système à relais.

Rappel sur le fonctionnement d’un fil pilote de radiateur électrique

Les 4 états de base de fonctionnement d’un radiateur muni d’un fil pilote sont liés aux états suivants sur ce fil :

  • Confort : absence de tension (c’est ce qui se passe quand le fil est « en l’air » en l’absence de pilotage, les états « Confort » et « Commandé par fil pilote » au niveau du radiateur reviennent donc au même en ce cas) ;
  • Eco : phase complète et fixe de la tension secteur sur le fil pilote (selon les radiateurs, la température de consigne peut être celle de « Confort » diminuée de quelques degrés, 3,5° bien souvent, ou une autre température, réglable sur le radiateur) ;
  • Hors Gel : demi alternance négative de la tension secteur (la température de consigne est en général descendue à 7°) ;
  • Arrêt ou Délestage : demi alternance positive de la tension secteur (le radiateur est complètement arrêté).
NB : pour recevoir les ordres du fil pilote, il faut bien entendu que le radiateur soit configuré pour les accepter. Sur certains modèles de radiateurs, même s’il n’est pas configuré pour être géré par le fil pilote, l’ordre HG et/ou AR peut primer sur le comportement demandé via le panneau de contrôle du radiateur (voir pour cela la notice technique du radiateur).

Le schéma électronique

Le schéma ci-dessous détaille le circuit électronique :

Les composants nécessaires

Les composants nécessaires pour le montage sont donc :

  • une carte WeMos D1 mini,
  • une carte d’alimentation 220Vac / 5Vdc,
  • 3 résistances de 220 Ω (pour les LEDs),
  • 2 résistances de 560 Ω (pour les optocoupleurs),
  • 2 résistances de 5,1 KΩ (pull-up pour les poussoirs),
  • 1 résistance de 4,7 KΩ (pull-up pour le capteur DHT22),
  • 1 LED bleue (de 3 mm),
  • 1 LED bicolore rouge/vert à cathode commune (de 3 mm),
  • 2 optocoupleurs MOC3041,
  • 2 diodes 1N4007,
  • un capteur DHT22 (optionnel),
  • un micro-poussoir à plat (pour le « Hard Reset »),
  • un micro-poussoir à angle droit (pour le changement d’état),
  • un bornier à 3 plots pour le raccordement au secteur et du fil pilote.

80pxPour rendre le DHT22 optionnel et amovible, j’ai choisi d’implanter sur la carte une prise femelle mini-jack 3,5 mm et de monter le capteur sur un connecteur jack A/V 4 bornes comme celui ci-contre.

NB : pour le câble d’alimentation, ne trouvant pas de câble 3 fils marron/bleu/noir dans le commerce, j’utilise un câble 3 x 0,75 mm² marron/bleu/jaune-vert et je noircis le fil de terre avec un marqueur pour indiquer qu’il s’agit d’un pilote et non d’une terre.

Le typon de la carte électronique est accessible, en PDF, via ce lien.

« Mise en boite »

Fichier:Boitier ouvert.jpg
Boitier pour pilote

Trouver un boitier adapté à l’intégration d’un circuit électronique est souvent une gageure.

Pour ma part, j’ai trouvé et choisi celui-ci, auprès d’un vendeur de Hong-Kong via le site Amazon et vendu par lot de 5 boitiers. Il mesure 100 mm x 60 mm x 23 mm sans son couvercle.

La carte électronique a été dimensionnée pour s’ajuster au mieux dans ce boitier.

Les percements à réaliser sont :

  • sur le dessus : 3 trous pour faire passer les 2 LEDs et le poussoir de changement d’état ;
  • sur le côté droit : 1 trou pour faire passer l’orifice de la prise jack (facultatif si le capteur DHT22 n’est pas utilisé et la prise femelle donc non montée) ;
  • sur le dessous : à gauche, un trou pour faire passer le câble d’alimentation, à droite un trou oblong pour permettre de brancher une prise micro-USB pour connecter le dispositif sur un ordinateur (pour une modification de logiciel par exemple, bien penser en ce cas à couper l’alimentation du radiateur pour ne pas avoir de conflit d’alimentations et d’endommagement possible, de la carte, ou, pire, de l’ordinateur).
NB : pour le passage de la prise micro-USB, je n’ai pas trouvé de solution plus « propre » que de percer une première succession de trous alignés de 1 mm puis de les rejoindre entre eux avec un forêt de 3 mm utilisé comme une fraise. Le trou n’a donc pas la forme trapézoïdale de ce type de prise et n’est pas très régulier. Pour obstruer au mieux la prise, j’ai placé un cache pour prise micro-USB trouvé dans le commerce.

Le positionnement des trous, dans ce boitier, est indiqué dans les schémas ci-dessous.

Dessus du boitier
passage des LEDs et du poussoir de changement d’état


Dessous du boitier
passage du fil d’alimentation et accès à la prise micro-USB


Côté droit du boitier
passage de la prise jack 3,5 mm


L’entrée de la carte se fait un peu « en force », surtout quand la prise jack est présente, ce qui permet toutefois à la carte de bien tenir dans le boitier et de ne pas avoir besoin de la visser sur les entretoises présentes au fond de la boîte. Mais cela peut être fait en perçant les trous ad-hoc dans la carte. Attention toutefois à vérifier leur positionnement par rapport aux pastilles prévues sur le circuit imprimé.

Selon les cartes WeMos, la position de la prise micro-USB peut varier légèrement, ce qui amène à revoir précisément le positionnement du passage prévu pour ce branchement lors de chaque assemblage.

Je « bloque » le fil d’alimentation à l’intérieur du boitier avec un collier autobloquant très fortement serré, afin d’éviter que le fil ne puisse ressortir du boitier et tirer sur le bornier. Mais un percement juste à la bonne dimension par rapport au câble permet de le faire passer en force, ce qui limite déjà les risques.

Pour la fixation au mur, j’utilise du double-face.

Pour ceux que cela intéresserait, je peux envoyer par message privé (MP) les références précises et les liens vers les composants et éléments utilisés. Contactez-moi pour cela en MP via le forum de GCE Electronics sur mon pseudo @PatLeHibou.

Le chargement du programme

Le code est relativement long, vu le nombre de fonctions implémentées, mais largement commenté pour en permettre une lecture et une modification facile en cas de besoin. Nous ne le détaillerons pas, mais expliquerons en fin d’article son principe dans les grandes lignes pour ceux que ces aspects intéressent. Nous nous contenterons dans cette partie de voir comment le charger sur la carte WeMos du montage pour rendre celui-ci opérationnel.

Des messages sont envoyés via le port USB et peuvent donc être visualisés via le moniteur série (à 9600 bauds) d’Arduino IDE pour suivre le déroulement précis des opérations et observer le fonctionnement du dispositif, voire le dépanner.

Le code source dans sa version actuelle (2.2c) est disponible via ce lien.

Compilation et téléchargement via Arduino IDE

Comme dans les tutos proposés par @fgtoul, la compilation et le téléchargement du logiciel sur la carte peut se faire via l’application Arduino IDE. Celle-ci nécessite cependant, en plus des librairies ESP8266 indiquées dans le tuto précédemment mentionné, d’installer la librairie supplémentaire « DHT sensor library for ESPx ».

Fichier:Librairie DHT.png

NB : la librairie d’Adafruit « DHT sensor library » semble mal adaptée à l’ESP8266 et peut conduire à des dysfonctionnements concernant en particulier la bonne lecture de la température et de l’humidité. C’est, en tout cas, ce que j’ai personnellement constaté. Je l’ai donc abandonnée au profit de celle indiquée ci-dessus.

Avec cette librairie supplémentaire installée, la compilation et le téléchargement du programme sur la carte WeMos ne doit, normalement, pas poser de problème. Et la carte devrait démarrer d’elle-même en mode « initialisation ». Si ce n’est pas le cas (LED bleue faisant un double clignotement permanent, signe qu’elle cherche à se connecter à un réseau WiFi sans y parvenir), l’appui sur le bouton de « Hard Reset » permettra de la forcer à redémarrer en mode « initialisation ». Cela peut venir d’une information présente dans l’EEPROM de la carte (premier bit du premier octet à « 1 » et non à « 0 », cela sera expliqué plus loin).

Initialisation du boitier

Une fois le dispositif assemblé et le programme chargé, il va être nécessaire de l’initialiser pour lui permettre de se raccorder au réseau WiFi du domicile. Cela nécessite de disposer d’un ordinateur, une tablette voire un smartphone équipé du WiFi et d’un navigateur pour pouvoir entrer les commandes. Le boitier sera ensuite pleinement opérationnel pour commencer à fonctionner de manière autonome et être piloté depuis le dashboard d’un IPX800.

NB : je conseille fortement de faire cette initialisation en étant branché via le port USB pour pouvoir contrôler ce qui se passe sur le moniteur série d’Arduino IDE.

Attention : pour ne pas risquer de conflit d’alimentations, ne pas brancher le boitier sur le port USB d’un ordinateur et sur le secteur simultanément, ce qui pourrait peut-être avoir des répercussions graves (griller des composants du montage, voire le port USB de l’ordinateur).

Commandes à passer

Lors du premier démarrage, après un appui sur le bouton « Hard Reset » ou après une remise à zéro de l’EEPROM de la carte WeMos, celle-ci doit démarrer en mode « initialisation ». Si ce n’est pas le cas (LED bleue faisant un double clignotement permanent toutes les 0,3 s, signe que la carte croit avoir une configuration valide enregistrée alors que ce n’est pas le cas), un appui sur le bouton de « Hard Reset » corrigera la chose (voir plus loin les explications sur le paramètre « Device Config » enregistré dans le 1er octet de l’EEPROM). Dans le cadre du mode « initialisation » :

  • Le programme place le dispositif en « Access Point WiFi » avec pour SSID (nom sous lequel le réseau est vu par les appareils) « Pilote_ » suivi des 3 derniers octets en hexadécimal de l’adresse MAC de la carte, sans clé de protection ;
  • Il donne à la carte l’adresse IP 10.10.10.1, active la fonction DHCP et la LED bicolore clignote en rouge toutes les 2,5 secondes, tant qu’aucune station n’est connectée ;
  • Il faut alors se connecter à ce « réseau » WiFi à partir d’un ordinateur, d’une tablette, ou d’un smartphone pour pouvoir passer les informations de configuration à la carte. Quand la station se connecte, la LED clignote en vert toutes les 2,5 secondes pour indiquer la connexion et l’attente d’une commande ;
  • Les commandes, envoyées via un navigateur, depuis la station connectée au dispositif peuvent être :
    • http://10.10.10.1/MACaddress
      qui permet d’obtenir l’adresse MAC du boitier (celle qui sera vue quand il sera connecté au réseau WiFi local) en vue de lui affecter une adresse IP fixe via le service DHCP fourni par une Box présente sur le réseau (fortement recommandé pour être sûr que la carte conserve toujours bien la même adresse IP) et, éventuellement, l’autoriser à se connecter au réseau WiFi si une protection du réseau par adresses MAC a été mise en place ;
    • http://10.10.10.1/NetConfig?SSID=SSID_WIFI&WPA=WPA_KEY&Name=DEVICE_NAME
      pour entrer les paramètres d’accès au réseau WiFi et dans laquelle :
      • SSID_WIFI est le SSID du réseau local WiFi à rejoindre, il doit avoir 31 caractères au plus ;
      • WPA_KEY est la clé WPA à utiliser, elle doit avoir 62 caractères au plus ;
      • DEVICE_NAME est le nom du périphérique qui sera vu via le réseau, il doit avoir 15 caractères au plus.
NB
- l’ordre des paramètres est important et tout ordre différent conduira à une erreur.
- il ne doit pas y avoir d’espace dans les paramètres, mais des guillemets peuvent les entourer (ils seront ignorés).
- la casse est importante et il est nécessaire de bien respecter Majuscules et minuscules dans les commandes MACaddress et NetConfig.
  • La LED verte devient fixe pendant l’interprétation de la commande et la tentative de rejoindre le réseau WiFi demandé, la LED bleue montre la progression :
  • Elle clignote deux fois toutes les 0,3 s lors des tentatives pour accéder au réseau WiFi
  • Si le nombre maximum de tentatives, fixé à 100, est atteint, le système considère que le réseau demandé n’est pas accessible (erreur au niveau du SSID, erreur au niveau du mot de passe, borne WiFi trop éloignée ou adresse MAC non autorisée sur le réseau si cette protection a été activée sur la borne), la LED rouge s’allume en fixe un bref instant, puis le programme repart au début du cycle d’initialisation ;
  • Si l’accès au réseau WiFi fonctionne, la LED bleue clignote lentement 5 fois pour acquitter cet accès correct, puis très rapidement 20 fois pour la mémorisation des paramètres.


Une fois cette étape passée, la carte entre dans son fonctionnement « normal », de la même façon qu’après une extinction et un allumage où elle va recharger les paramètres précédemment enregistrés et commencer par rattacher le boitier au réseau WiFi et passer en mode « pilotage de radiateur » (mode « normal »).

Interfaçage avec l’IPX800

Parvenu à ce stade, le boitier est opérationnel et le mode de fonctionnement du radiateur peut être changé en appuyant sur le bouton de changement d’état (ce qui se voit au changement de couleur de la LED bicolore). Il est donc déjà possible de contrôler que le radiateur reçoit bien les ordres et les prend en compte correctement.

NB : de nombreux modèles de radiateurs disposant des ordres « Confort -1° » et « Confort -2° » peuvent mettre plusieurs secondes (jusqu’à une dizaine) avant de basculer en mode « Eco ». Cela est tout à fait normal et lié au mode de pilotage de ces états. Voir cet article pour plus de détails sur le « protocole fil pilote ».

De par sa connexion au réseau WiFi du logement, le boitier est également capable de recevoir des ordres par le réseau (sous forme de requêtes http passées sur l’adresse IP du boitier). Cela permet donc de l’interfacer avec un IPX800 sous forme d’un widget dans un dashboard.

Le widget pour un radiateur

Comme toujours en pareil cas, c’est un widget HTML contenant du code JavaScript qui va permettre l’affichage de l’état et le pilotage du radiateur via l’interface graphique de l’IPX. Ce premier widget n’affiche pas les informations de température et d’humidité, car à ce stade, la présence du capteur, si elle est effective, n’a pas encore été déclarée. Nous verrons dans le chapitre suivant comment activer le capteur et donc la remontée de ces informations, et plus loin sera donné un exemple de widget pour 4 radiateurs dotés chacun d’un capteur DHT22.

Le code JavaScript à correspondant à l’exemple ci-contre est donné ci-dessous :

<script>
const IoT_Device_Name='Radiateur Local';
const IoT_Widget_Version='(v.1.1)';
const IP_IoT='http://IP_du_boitier';
var etatFP = ['Confort', 'Eco', 'Hors Gel', 'Arrêt'];
var cdeFP = ['CF', 'EC', 'HG', 'AR'];

function status_IoT () {
	url_IoT=IP_IoT+'/?';
	headers={
		'Accept': 'application/json',
		};
	fetch(url_IoT, {headers}).then(r => r.json()).then(data_state => {
		let status=data_state.status;
		for(let i=0; i < 4; i++) {
			if (i==status) {document.getElementById('fp_IoT'+i).style.color='#3FB740'} else {document.getElementById('fp_IoT'+i).style.color='#C9C5C5'};
			};
		document.getElementById('fp_IoTText').value=etatFP[status];
		document.getElementById('fp_name0').innerHTML=IoT_Device_Name+' '+IoT_Widget_Version;
		document.getElementById('fp_name0').style.color='#C9C5C5';
		});
	};

function cmd_IoT (status) {
	let url_IoT=IP_IoT+"/"+cdeFP[status];
	let headers={
		'Accept': 'application/json',
		};
	fetch(url_IoT, {headers});
    status_IoT();
	};

status_IoT();
setInterval(status_IoT, 5000);

</script>
<div id="fp_IoT0" style="margin-left:12px; margin-right:12px; margin-top:6px">
	<h2 id="fp_name0" class="section-title" style="color: '#C9C5C5'">Recherche boitier</h2>
	<p></p>
	<input value='----' id="fp_IoTText" class="bouton2" style="margin-bottom: 15px; width: 110px; background-color: rgb(68, 68, 68);" type="button"></input>
	<br>
	<span id="fp_IoT3" onclick='cmd_IoT(3);' class="police-switch" style="font-size: 25px; width: 40px; color: '#C9C5C5';"></span>
	<span id="fp_IoT2" onclick='cmd_IoT(2);' class="police-snowflake-alt2" style="font-size: 30px; position: relative; top: 3px; left: 10px; width: 40px; color: '#C9C5C5';"></span>
	<span id="fp_IoT1" onclick='cmd_IoT(1);' class="police-moon_fill" style="font-size: 25px; width: 40px; position: relative; left: 22px; color: '#C9C5C5';"></span>
	<span id="fp_IoT0" onclick='cmd_IoT(0);' class="pol-sunny18" style="font-size: 35px; width: 40px; position: relative; top: 5px; left: 30px; color: '#C9C5C5';"></span>
    <br>
    <br>
    <hr />
</div>

La seule modification à apporter dans ce code est de remplacer « IP_du_boitier » (4ème ligne) par l’adresse IP du boitier à piloter.

NB : au cas où l’on voudrait placer plusieurs widgets de ce type sur le même dashboard (correspondant à différentes zones de la maison par exemple), il y aurait lieu de modifier les Id des balises

<div>

et des balises

<span>

et tous les paramètres associés afin qu’il n’y ait pas de conflits au niveau de l’affichage. Je déconseille néanmoins cet usage qui peut être délicat à mettre au point pour ne garder qu’un widget de ce type par dashboard, en utilisant si besoin la version permettant de visualiser et piloter plusieurs boitiers qui sera donnée ci-après.

Pilotage du boitier par les scenarii

Ce pilotage est particulièrement simple puisque les changements d’état d’un boitier peuvent être pilotés par un « Push » depuis l’IPX. Il suffit d’indiquer l’adresse IP du boitier et une des commandes /CF, /EC, /HG ou /AR sur les actions « URL ON » ou « URL OFF ». En fonction des besoins, des combinaisons astucieuses de commandes sur le « On » et le « Off » d’un même push va permettre de gérer en un seul scénario 2 actions. Un exemple de « Push » permettant la bascule entre le mode Confort et le mode Eco est donné ci-dessous. Celui-ci peut être envoyé selon des horaires définis dans des plages.

Fichier:Push Bureau.png

Pour aller plus loin

A ce stade nous avons :

  • assemblé le montage dans son boitier ;
  • fait sa configuration initiale pour l’attacher au réseau WiFi du logement ;
  • utilisé le boitier de manière autonome par appui sur le bouton de changement d’état ;
  • intégré dans un dashboard de l’IPX800 un widget permettant de visualiser l’état du pilote et de le faire changer via l’interface graphique ;
  • paramétré un ou plusieurs « Push » pour pouvoir piloter le boitier via des scenarii.


Nous n’avons cependant pas encore exploité :

  • les remontées de température et d’humidité possibles si un capteur DHT22 a été branché ;
  • la modification de certains paramètres (luminosité des LEDs, nom du boitier sur le réseau…) ;
  • les possibilités de remontées d’informations du boitier vers l’IPX en cas de dépassement de certains seuils pour que celui-ci puisse déclencher de lui-même certaines actions.

Objet des API en fonctionnement « normal » du boitier

En fonctionnement « normal », c’est à dire hors du cycle « initialisation », le programme tourne en permanence dans une boucle qui attend des événements (appui sur un bouton, requête http, mesure périodique de température et d’humidité), ce qui va permettre de :

  • consulter les paramètres du dispositif et l’état du fil pilote ;
  • faire changer l’état du fil pilote ;
  • provoquer un « Hard Reset » du boitier pour qu’il repasse en mode « initialisation » (par exemple en vue d’un changement de SSID ou de clé WPA sur le réseau WiFi) ;
  • renseigner ou modifier certains paramètres parmi lesquels :
    • la luminosité des LEDs ;
    • le nom du boitier (même paramètre que « DEVICE_NAME » à l’initialisation) ;
    • l’activation ou la désactivation du capteur DHT (il n’y a pas de détection automatique de la présence de celui-ci et il peut être installé sans que l’on veuille pour autant l’exploiter) ;
NB : activer le capteur DHT alors qu’il n’est pas installé ne générera pas d’erreur mais du retard dans l’affichage de l’état du dispositif puisqu’une vingtaine de tentatives de lecture de la température et de l’humidité vont être faites sans aboutir.
  • faire afficher (via l’USB et le moniteur série d’Arduino IDE) le contenu de l’EEPROM et la remettre complètement à 0 si besoin ;
    • les paramètres de l’IPX à joindre pour remonter des alertes sur la température et l’humidité (adresse IP de l’IPX et son APIkey si celle-ci est activée) ;
    • les seuils de température et d’humidité ainsi que les sorties virtuelles que la détection de ces seuils doit faire changer d’état ;
NB
- les seuils de température sont obligatoires, mais ceux d’humidité ne le sont pas, si on ne souhaite pas surveiller ce paramètre.
- les sorties virtuelles passent à 1 quand la température descend en dessous du seuil mini et quand l’humidité passe au dessus du seuil maxi, elles passent à 0 quand la température monte au dessus du seuil maxi et quand l’humidité passe en dessous du seuil mini. Cela permet, si la même sortie virtuelle est configurée pour les 2 paramètres d’avoir la même action, par exemple allumer le chauffage pour monter la température et donc baisser l’humidité, au niveau de l’IPX qui ignorera lequel des 2 la déclenche (simplification des scéranii).

Les commandes http associées à ces API

En fonctionnement normal, différentes commandes, éventuellement associées à des paramètres, vont donc permettre de déclencher certaines actions, obtenir des informations ou régler des valeurs, comme décrit ci-dessus. La commande se passe, depuis un navigateur Web, avec la syntaxe suivante :

</nowiki>http://adresse_IP_du_boitier/commande_et_paramètres_éventuels</nowiki>

Les commandes possibles et leur syntaxe sont détaillées ci-dessous. Elles peuvent aussi, bien évidemment, être envoyées via des « Push » depuis l’IPX (par exemple pour augmenter la luminosité des LEDs dans la journée et les réduire la nuit, en fonction d’horaires ou d’un capteur de luminosité ambiante).

NB
- les commandes et les paramètres ne sont pas sensibles à la casse et peuvent donc indifféremment être entrés en Majuscules ou minuscules ou un mélange des deux.
- afin de retrouver facilement quel boitier porte quelle adresse IP, il est fortement conseillé de fixer l’adresse IP du boitier via le service DHCP d’une Box ou d’un routeur présent sur le réseau en associant une adresse IP à l’adresse MAC de la carte. Se référer au manuel de sa Box ou du routeur pour cela.

Toutes les commandes renvoient une réponse en JSON ce qui permet de les exploiter dans des widgets HTML via du JavaScript (c’est ce qui est fait dans le widget proposé ci-dessus).

? : status

http://adresse_IP_du_boitier/?

Cette commande retourne, sous forme d’un fichier JSON, l’état du boitier et ses paramètres sous la forme :

{
     "device" : "Nom_boitier",
     "command" : "?",
     "status" : "2",
     "dht" : "1",
     "temp" : 10.10,
     "humi" : 75.60,
     "IP_IPX" : "XXX.YYY.ZZZ.TTT",
     "IPX_API_Prefix" : "/api/xdevices.json?key=Mon_API_Key&",
     "th_control" : {
       "status" : "On",
       "periodicity" : "10",
       "t_min" : "10",
       "t_max" : "12",
       "sv_te" : "39",
       "h_min" : "70",
       "h_max" : "80",
       "sv_hu" : "40"
     },
     "luminosity" : "10"
}

Les paramètres sont relativement évidents à interpréter vu les noms choisis.

Le chiffre en regard de « status » s’interprète de la fonction suivante :

  • 0 = Confort
  • 1 = Eco
  • 2 = Hors Gel
  • 3 = Arrêt

La valeur de DHT est à « 0 » si le capteur est absent ou n’est pas utilisé (les valeurs « temp » et « humi » ne sont alors pas indiquées) et à « 1 » s’il est utilisé et présent (c’est ici que l’absence de capteur se traduira par un délai d’affichage plus long et l’indication « nan » en regard des valeurs, indiquant que la température et l’humidité n’ont pas pu être mesurés).

Le sous-paramètre « status » de « th_control » est à « Off » s’il n’y a pas de surveillance du climat, ce qui se programme en choisissant une périodicité de surveillance à 0. Les autres sous-paramètres ne sont, dans ce cas, pas affichés. Quand il est à « On » les seuils et sorties virtuelles sont indiqués.

Le paramètre « luminosity » est en « pour 1000 tours de boucle ». La valeur 10 permet d’avoir une visibilité suffisante dans des conditions d’éclairage normal. La monter sensiblement risque d’avoir un effet d’éclairage fort dans le noir. Réglé à 0 les LEDs sont complètement éteintes, ce qui est possible, mais ne permet plus aucun retour visuel sur l’état du boitier.

CF : confort

Passe le pilote en mode « Confort »

EC : éco

Passe le pilote en mode « Eco »

HG : hors gel

Passe le pilote en mode « Hors Gel »

AR : arrêt

Passe le pilote en mode « Arrêt » ou « Délestage »

Dans ces 4 cas une réponse en JSON est renvoyée. Par exemple pour un ordre HG :

http://adresse_IP_du_boitier/HG

La réponse retournée est :

{
     "device" : "Nom_boitier",
     "command" : "HG",
     "status" : "2"
}

VE : version

http://adresse_IP_du_boitier/VE

Affiche en JSON, la version du boitier et du code source utilisé. Exemple :

{
     "device" : " Nom_boitier",
     "command" : "VE",
     "version" : "PatLeHibou's WiFi Heater Pilot v.2",
     "source" : "WiFi_Heater_Pilot_v.2.2c"
}

LU=valeur : réglage de la luminosité

http://adresse_IP_du_boitier/LU=valeur

Avec une valeur comprise entre 0 (extinction complète) et 1000 (allumage permanent), ce paramètre permet de fixer la luminosité des LEDs comme indiqué précédemment, afin de ne pas générer un éclairage trop fort au niveau du boitier et pouvant être gênant (la nuit dans une chambre par exemple). La réponse est affichée en JSON sous la forme :

{
     "device" : " Nom_boitier",
     "command" : "LU=10",
     "luminosity" : "10"
}

NM=Nom_boitier : renommage du boitier

http://adresse_IP_du_boitier/NM=Nouveau_nom

Permet de changer le nom du boitier tel qu’il est vu sur le réseau et peut être lu par l’IPX. La réponse est affichée en JSON sous la forme :

{
     "device" : "Nom_boitier",
     "command" : "NM=Nouveau_nom",
     "newname" : "Nouveau_nom"
}

TH=On/Off : activation/désactivation du capteur DHT

http://adresse_IP_du_boitier/TH=[On|Off]

TH=On active le capteur DHT. Le système répond :

{
     "device" : " Nom_boitier ",
     "command" : "TH=On",
     "dht" : "1"
}

TH=Off, ou n’importe quoi d’autre, le désactive. Le système répond :

{
     "device" : " Nom_boitier",
     "command" : "TH=abcd",
     "dht" : "0"
}

EP=Dump/Wipe : affichage du contenu de l’EEPROM ou vidage de celle-ci

Nécessite que le boitier soit branché en USB sur une station, et qu’Arduino IDE soit lancé avec le moniteur série.

http://adresse_IP_du_boitier/EP=Dump

Affiche via le port série le contenu de l’EEPROM en hexadécimal et en ASCII à des fins de vérification. Attention, le SSID et la clé WPA apparaissent en clair.

http://adresse_IP_du_boitier/EP=Wipe

Remet à 0 les 512 octets de l’EEPROM et affiche le résultat pour vérification (si tous les octets ne sont pas à 0, l’EEPROM a un souci d’enregistrement et est probablement endommagée)

NB : le système ne reboote volontairement pas tout seul après un « Wipe » pour permettre d’éventuelles autres opérations. Pour le faire redémarrer, il est possible d’appuyer sur le bouton « Hard Reset » ou de débrancher et rebrancher le boitier.I

IPX_CFG?paramètres : configuration de l’IPX

Cette commande nécessite au moins un paramètre IP_IPX sous forme d’une chaine de caractères représentant l’adresse IP de l’IPX800 à joindre pour remonter les informations de surveillance du climat de la pièce. Les guillemets peuvent être omis autour de l’adresse IP.

Exemple :

http://adresse_IP_du_boitier/IPX_CFG?IP_IPX=192.168.1.100

Si la clef API est activée sur l’IPX (se référer à la documentation de l’IPX800 pour cela), il faut indiquer la valeur de celle-ci et ajoutant après l’adresse IP : « &APIkey=Mon_API_key »

Exemple :

http://adresse_IP_du_boitier/IPX_CFG?IP_IPX=192.168.1.100&APIkey=Ma_clé_API

NB : la validité et la syntaxe de l’adresse IP n’est pas contrôlée par le programme, mais vous pouvez la visualiser par la commande « ? » (status).

CTRL_TH?paramètres : paramétrage de la surveillance du climat

Cette commande permet d’activer/désactiver la surveillance du climat et de fixer les paramètres pour ce faire. Elle nécessite a minima le premier paramètre « PERIOD » qui indique, en minutes, la périodicité de la mesure de la température et de l’humidité. Si celui-ci est passé à 0, les autres paramètres éventuels sont ignorés et la fonction de surveillance est désactivée. Si celui-ci dépasse 1440 (plus de 24h), une erreur est renvoyée.

Si PERIOD est compris entre 1 et 1440, les 3 paramètres suivants sont lus. Ils doivent être, dans l’ordre :

  • T_MINI : seuil minimum de température (doit être comprise entre 0 et 20)
  • T_MAXI : seuil maximum de température (doit être comprise entre 0 et 30 et supérieure à T_MINI)
  • SV_TE : sortie virtuelle recevant les infos (doit être inférieure ou égale à 128)

S’il n’y a pas d’autres paramètres derrière, l’humidité mini est fixée à 0, la maxi à 100 et la sortie virtuelle à 0 (n’existe pas dans l’IPX). S’il y en a, les 3 paramètres suivants sont lus et doivent être, dans l’ordre :

  • H_MINI : seuil minimum d’humidité (doit être comprise entre 0 et 100)
  • H_MAXI : seuil maximum d’humidité (doit être comprise entre 0 et 100 et supérieure à H_MINI)
  • SV_HU : sortie virtuelle recevant les infos (doit être inférieure ou égale à 128)

La cohérence des données est vérifiée et génère une erreur sous forme d’une réponse en JSON en cas de problème, sans altérer la configuration précédente.

Exemples :

http://adresse_IP_du_boitier/CTRL_TH?PERIOD=0

Désactive la surveillance. Réponse :

{
     "device" : " Nom_boitier",
     "command" : "CTRL_TH?PERIOD=0",
     "status" : "CTRL_TH Successfully deactivated"
}

La commande « ? » (status) renverra :

{
     "device" : " Nom_boitier",
     "command" : "?",
     "status" : "2",
     "dht" : "1",
     "temp" : 11.90,
     "humi" : 64.40,
     "IP_IPX" : " XXX.YYY.ZZZ.TTT",
     "IPX_API_Prefix" : "/api/xdevices.json?key= Mon_API_key&",
     "th_control" : {
       "status" : "Off"
     },
     "luminosity" : "10"
}
http://adresse_IP_du_boitier/CTRL_TH?PERIOD=10&T_MINI=10&T_MAXI=12&SV_TE=30

Surveille la température toutes les 10 minutes et fait passer la sortie virtuelle 30 à 1 si la température mesurée devient inférieure à 10° et la fait passer à 0 si la température dépasse les 12°. Réponse :

{
     "device" : " Nom_boitier",
     "command" : "CTRL_TH?PERIOD=10&T_MINI=10&T_MAXI=12&SV_TE=33",
     "status" : "CTRL_TH Successfull"
}

La commande « ? » (status) renverra :

{
     "device" : " Nom_boitier ",
     "command" : "?",
     "status" : "2",
     "dht" : "1",
     "temp" : 11.90,
     "humi" : 64.10,
     "IP_IPX" : "XXX.YYY.ZZZ.TTT",
     "IPX_API_Prefix" : "/api/xdevices.json?key=Mon_API_key&",
     "th_control" : {
       "status" : "On",
       "periodicity" : "10",
       "t_min" : "10",
       "t_max" : "12",
       "sv_te" : "30",
       "h_min" : "0",
       "h_max" : "100",
       "sv_hu" : "0"
     },
     "luminosity" : "10"
}
http://adresse_IP_du_boitier/CTRL_TH?PERIOD=30&T_MINI=18&T_MAXI=20&SV_TE=60&H_MINI=60&H_MAXI=70&SV_HU=61

Surveille la température et l’humidité toutes les 30 minutes et fait passer la sortie virtuelle 60 à 1 si la température mesurée devient inférieure à 18° et à 0 si la température dépasse les 20°, et fait passer la sortie virtuelle 61 à 1 si l’humidité mesurée dépasse les 75% et à 0 si elle devient inférieure 65%. Réponse :

{
     "device" : "Chf_Local",
     "command" : "CTRL_TH?PERIOD=30&T_MINI=18&T_MAXI=20&SV_TE=60&H_MINI=65&H_MAXI=75&SV_HU=61",
     "status" : "CTRL_TH Successfull"
}

La commande « ? » (status) renverra :

{
     "device" : " Nom_boitier ",
     "command" : "?",
     "status" : "2",
     "dht" : "1",
     "temp" : 11.90,
     "humi" : 64.10,
     "IP_IPX" : "XXX.YYY.ZZZ.TTT",
     "IPX_API_Prefix" : "/api/xdevices.json?key=Mon_API_key&",
     "th_control" : {
       "status" : "On",
       "periodicity" : "30",
       "t_min" : "10",
       "t_max" : "12",
       "sv_te" : "60",
       "h_min" : "65",
       "h_max" : "75",
       "sv_hu" : "61"
     },
     "luminosity" : "10"
}

Interfaçage avec l’IPX800 de plusieurs boîtiers dotés de capteur DHT22

Une fois les dispositifs mis en service et leurs différents paramètres réglés, ceux-ci peuvent-être intégrés dans l’IPX800 v.4 afin de :

  • voir l’état des pilotes, et éventuellement les valeurs de température et d’humidité si des capteurs DHT22 sont présents et activés, et faire changer chaque pilote d’état (et donc le radiateur associé), au travers d’un widget ;
  • piloter par scenarii le fonctionnement des radiateurs (présence/absence, jour/nuit…) ;
  • gérer dans des scenarii les remontées d’informations pouvant être faites par le boitier en cas de dépassement des seuils de température ou d’humidité pour déclencher des actions.

Le widget pour 4 pilotes

De la même façon que pour un unique radiateur sans capteur, c’est un widget HTML contenant du code JavaScript qui va permettre l’affichage de l’état et le pilotage des radiateurs via l’interface graphique de l’IPX.

Le code JavaScript est donné ci-dessous pour 4 boitiers, tous capables de mesurer température et humidité. L’affichage ressemble à cela dans l’interface de l’IPX.

Selon qu’il y a plus ou moins de 4 boitiers à afficher dans le même widget, le code est à adapter en conséquence.

Si certains boitiers n’ont pas de capteur DHT22, les lignes correspondantes peuvent être supprimées dans la partie « affichage ».

Le tableau IP_IoT, au début du code, est à renseigner avec les valeurs des adresses IP des dispositifs sur le réseau.

<script>
var IP_IoT=['http://IP_boitier_1', 'http://IP_boitier_2', 'http://IP_boitier_3', 'http://IP_boitier_4'];
var etatFP = ['Confort', 'Eco', 'Hors Gel', 'Arrêt'];
var cdeFP = ['CF', 'EC', 'HG', 'AR'];

function rename (name) {
	if (name == Nom_boitier_1') return 'Nom Boitier 1 pour IPX';
	if (name == Nom_boitier_2') return 'Nom Boitier 2 pour IPX';
	if (name == Nom_boitier_3') return 'Nom Boitier 3 pour IPX';
	if (name == Nom_boitier_4') return 'Nom Boitier 4 pour IPX';
	return name;
	};

function status_IoT (num) {
	url_IoT=IP_IoT[num]+'/?';
	headers={
		'Accept': 'application/json',
		};
	fetch(url_IoT, {headers}).then(r => r.json()).then(data_state => {
		let status=data_state.status;
		for(let i=0; i < 4; i++) {
			if (i==status) {document.getElementById('fp_IoT'+i+'_'+num).style.color='#3FB740'} else {document.getElementById('fp_IoT'+i+'_'+num).style.color='#C9C5C5'};
			};
		document.getElementById('fp_IoTText'+num).value=etatFP[status];
		document.getElementById('fp_name'+num).innerHTML=rename(data_state.device);
		document.getElementById('fp_name'+num).style.color='#C9C5C5';
		document.getElementById('temp_IoT'+num).innerHTML="Température : "+data_state.temp+" °C";
		document.getElementById('temp_IoT'+num).style.color='#C9C5C5';
		document.getElementById('humi_IoT'+num).innerHTML="Humidité    : "+data_state.humi+" %";
		document.getElementById('humi_IoT'+num).style.color='#C9C5C5';
		});
	};

function cmd_IoT (boitier, status) {
	let url_IoT=IP_IoT[boitier]+"/"+cdeFP[status];
	let headers={
		'Accept': 'application/json',
		};
	fetch(url_IoT, {headers});
    status_IoT(boitier);
	};

function status_IoTs () {
   for (let i=0; i < 4; i++) {
        status_IoT(i);
		}
	};

status_IoTs();
setInterval(status_IoTs, 5000);

</script>
<div id="fp_IoT0" style="margin-left:12px; margin-right:12px; margin-top:6px">
	<h2 id="fp_name0" class="section-title" style="color: '#C9C5C5'">Recherche boitier</h2>
	<p></p>
	<input value='----' id="fp_IoTText0" class="bouton2" style="margin-bottom: 15px; width: 110px; background-color: rgb(68, 68, 68);" type="button"></input>
	<br>
	<span id="fp_IoT3_0" onclick='cmd_IoT(0,3);' class="police-switch" style="font-size: 25px; width: 40px; color: '#C9C5C5';"></span>
	<span id="fp_IoT2_0" onclick='cmd_IoT(0,2);' class="police-snowflake-alt2" style="font-size: 30px; position: relative; top: 3px; left: 10px; width: 40px; color: '#C9C5C5';"></span>
	<span id="fp_IoT1_0" onclick='cmd_IoT(0,1);' class="police-moon_fill" style="font-size: 25px; width: 40px; position: relative; left: 22px; color: '#C9C5C5';"></span>
	<span id="fp_IoT0_0" onclick='cmd_IoT(0,0);' class="pol-sunny18" style="font-size: 35px; width: 40px; position: relative; top: 5px; left: 30px; color: '#C9C5C5';"></span>
    <br><br>
    <div id="temp_IoT0">Température</div>
    <div id="humi_IoT0" style="color: '#C9C5C5'">Humidité</div>
    <hr />
</div>
<div id="fp_IoT1" style="margin-left:12px; margin-right:12px; margin-top:6px">
	<h2 id="fp_name1" class="section-title" style="color: '#C9C5C5'">Recherche boitier</h2>
	<p></p>
	<input value='----' id="fp_IoTText1" class="bouton2" style="margin-bottom: 15px; width: 110px; background-color: rgb(68, 68, 68);" type="button"></input>
	<br>
	<span id="fp_IoT3_1" onclick='cmd_IoT(1,3);' class="police-switch" style="font-size: 25px; width: 40px; color: '#C9C5C5';"></span>
	<span id="fp_IoT2_1" onclick='cmd_IoT(1,2);' class="police-snowflake-alt2" style="font-size: 30px; position: relative; top: 3px; left: 10px; width: 40px; color: '#C9C5C5';"></span>
	<span id="fp_IoT1_1" onclick='cmd_IoT(1,1);' class="police-moon_fill" style="font-size: 25px; width: 40px; position: relative; left: 22px; color: '#C9C5C5';"></span>
	<span id="fp_IoT0_1" onclick='cmd_IoT(1,0);' class="pol-sunny18" style="font-size: 35px; width: 40px; position: relative; top: 5px; left: 30px; color: '#C9C5C5';"></span>
    <br><br>
    <div id="temp_IoT1">Température</div>
    <div id="humi_IoT1" style="color: '#C9C5C5'">Humidité</div>
    <hr />
</div>
<div id="fp_IoT2" style="margin-left:12px; margin-right:12px; margin-top:6px">
	<h2 id="fp_name2" class="section-title" style="color: '#C9C5C5'">Recherche boitier</h2>
	<p></p>
	<input value='----' id="fp_IoTText2" class="bouton2" style="margin-bottom: 15px; width: 110px; background-color: rgb(68, 68, 68);" type="button"></input>
	<br>
	<span id="fp_IoT3_2" onclick='cmd_IoT(2,3);' class="police-switch" style="font-size: 25px; width: 40px; color: '#C9C5C5';"></span>
	<span id="fp_IoT2_2" onclick='cmd_IoT(2,2);' class="police-snowflake-alt2" style="font-size: 30px; position: relative; top: 3px; left: 10px; width: 40px; color: '#C9C5C5';"></span>
	<span id="fp_IoT1_2" onclick='cmd_IoT(2,1);' class="police-moon_fill" style="font-size: 25px; width: 40px; position: relative; left: 22px; color: '#C9C5C5';"></span>
	<span id="fp_IoT0_2" onclick='cmd_IoT(2,0);' class="pol-sunny18" style="font-size: 35px; width: 40px; position: relative; top: 5px; left: 30px; color: '#C9C5C5';"></span>
    <br><br>
    <div id="temp_IoT2">Température</div>
    <div id="humi_IoT2" style="color: '#C9C5C5'">Humidité</div>
    <hr />
</div>
<div id="fp_IoT3" style="margin-left:12px; margin-right:12px; margin-top:6px">
	<h2 id="fp_name3" class="section-title" style="color: '#C9C5C5'">Recherche boitier</h2>
	<p></p>
	<input value='----' id="fp_IoTText3" class="bouton2" style="margin-bottom: 15px; width: 110px; background-color: rgb(68, 68, 68);" type="button"></input>
	<br>
	<span id="fp_IoT3_3" onclick='cmd_IoT(3,3);' class="police-switch" style="font-size: 25px; width: 40px; color: '#C9C5C5';"></span>
	<span id="fp_IoT2_3" onclick='cmd_IoT(3,2);' class="police-snowflake-alt2" style="font-size: 30px; position: relative; top: 3px; left: 10px; width: 40px; color: '#C9C5C5';"></span>
	<span id="fp_IoT1_3" onclick='cmd_IoT(3,1);' class="police-moon_fill" style="font-size: 25px; width: 40px; position: relative; left: 22px; color: '#C9C5C5';"></span>
	<span id="fp_IoT0_3" onclick='cmd_IoT(3,0);' class="pol-sunny18" style="font-size: 35px; width: 40px; position: relative; top: 5px; left: 30px; color: '#C9C5C5';"></span>
    <br><br>
    <div id="temp_IoT3">Température</div>
    <div id="humi_IoT3" style="color: '#C9C5C5'">Humidité</div>
 </div>

Explication du code JavaScript

La fonction « rename (name) » permet de faire traduire le nom du boitier, tel que vu sur le réseau (paramètre « DEVICE_NAME » de l’initialisation, « Nom_boitier » de la commande /NM= et paramètre « device » dans les réponses JSON), en un nom éventuellement plus explicite dans l’interface graphique de l’IPX. Dans la version pour un seul pilote, le nom était entré « en dur » dans le code JavaScript.

La fonction « status_IoT (num) » interroge un boitier particulier identifié par son n° dans le widget pour remonter son état et les valeurs de température et d’humidité si le capteur DHT est présent et les afficher dans la zone correspondante du widget. Elle est identique à la fonction du même nom du widget pour un pilote, à ceci près que l’on indique le n° du boitier à piloter.

NB : attention en JavaScript, comme dans de nombreux langages de programmation, le premier élément d’un tableau porte l’indice 0. Quatre boitiers portent donc les n° 0, 1, 2 et 3.

La fonction « cmd_IoT (boitier, status) », permet, lors du clic sur un des pictogrammes d’état d’un des boitiers, de faire changer le boitier d’état (et donc le radiateur) en lui en envoyant l’ordre via une requête http. Elle aussi est similaire à celle de la version pour un seul boitier, mais avec la possibilité d’indiquer le n° du boitier commandé.

La fonction « status_IoTs () » permet d’interroger successivement et régulièrement les différents boitiers toutes les 5 secondes depuis une seule fonction via la commande « setInterval (status_IoTs, 5000) » (la périodicité peut être changée).

NB : il est assez déconseillé de placer plusieurs widgets de ce type sur le même dashboard (correspondant à différentes zones de la maison par exemple), car les Id des balises

<div>

et

<span>

risquent d’entrer en conflit, de même que les fonctions. La mise au point et le déboguage en sera complexifié. Il vaudrait donc mieux les placer sur des dashboards différents ou augmenter le nombre de pilotes surveillés dans le même widget en l’adaptant.

Pilotage des boitiers par les scenarii et actions sur remontées d’informations

Ce point a déjà été abordé précédemment. On peut juste ajouter que, si la fonction de surveillance de la température et de l’humidité est activée et correctement paramétrée (cf les explications sur les commandes IP_IPX et CTRL_TH), la ou les sorties virtuelles choisies vont changer d’état lors du franchissement de ces seuils. La détection de ce changement d’état est particulièrement simple dans un scénario et consiste juste à surveiller la sortie virtuelle voulue (éventuellement combinée avec d’autres paramètres) pour pouvoir faire déclencher une action par le scénario. Cette action pourra être un ordre « Push » à destination du même boitier ou d’un autre ou tout autre commande que l’IPX pourra piloter (fermer des volets pour garder la chaleur, passer la VMC en marche forcée pour réduire l’humidité…).

Dès lors, comme pour la bascule entre « Confort » et « Eco » selon l’heure, un unique « Push » peut gérer la bascule de Hors-Gel en Eco et retour, lors de la détection des seuils de températures (pour éviter par exemple que la température du logement descende jusqu’au 7° usuels du mode Hors Gel et limiter des problèmes d’humidité). C’est une façon particulièrement simple de le faire.

Fichier:Push Local.png

Le code plus en détail (pour les « experts »)

Nous allons maintenant entrer dans l’analyse plus détaillée du code source pour en faciliter la compréhension et la modification éventuelle. Cela nécessite toutefois un minimum de connaissances en programmation C++

NB : le code étant très largement commenté, on pourra assez facilement comprendre son fonctionnement via sa lecture, c’est la raison pour laquelle cette analyse ne présente que les grands principes retenus.

Mémorisation des paramètres et de l’état du pilote

Les paramètres du dispositif (SSID, clé WPA, nom, présence ou non du capteur DHT22…) étant des informations changeant très peu, le choix a été fait de les stocker dans l’EEPROM de la carte. Les cartes WeMos D1 mini comportent une EEPROM de 512 octets.

En fonctionnement « normal » (connecté à un réseau WiFi et donc en mesure de piloter un radiateur), une fonction permet de « Dumper » le contenu de l’EEPROM sur le port série (et donc de le faire afficher par l’application Arduino IDE) et de la remettre complètement à 0 (« Wipe ») en cas de besoin (changement de version de logiciel induisant une modification de l’organisation du contenu de l’EEPROM et pouvant nécessiter plus qu’un simple « Hard Reset »).

Par contre, l’état du radiateur étant une information appelée à changer fréquemment, j’ai choisi de mémoriser celle-ci dans la mémoire flash de la carte (via le système de fichiers SPIFFS) dans un petit fichier d’état « status.dat ». Cela permet de moins solliciter l’EEPROM, que des écritures trop fréquentes pourraient rapidement endommager.

Paramètre « Device Config »

Le premier octet de l’EEPROM contient le « Device Config ». Sur cet octet, seuls les 2 bits de poids faible sont utilisés :

  • Le premier bit indique, s’il est à 1, qu’une configuration WiFi valide a précédemment été entrée et vérifiée par une connexion effective au réseau. En ce cas, lors du démarrage de la carte, le programme passe directement à la connexion au réseau puis dans la boucle principale, sinon, il passe dans la boucle d’initialisation qui permet d’entrer les paramètres d’accès au réseau WiFi comme vu précédemment ;
  • Le deuxième bit indique, s’il est à 1, qu’un capteur DHT est censé être branché sur la carte.

Initialisation du boitier : fonction void setup()

Cette fonction, que l’on retrouve dans tous les programmes pilotant des cartes Arduino ou des cartes à base d’ESP8266, permet l’initialisation du dispositif, avant que celui-ci ne tourne sur la boucle principale loop().

Il est impossible de sortir de la fonction setup() tant qu’une configuration WiFi valide n’a pas été transmise au boitier et vérifiée (au premier allumage, après un « Hard Reset » ou après un effacement de l’EEPROM suivi d’un redémarrage).

Le comportement de la fonction setup() est donc le suivant :

  • Après démarrage du dispositif et les initialisations de base (configuration des ports GPIO, ouverture de l’accès à l’EEPROM et lecture du 1er octet contenant le « Device Config », initialisation du système de fichier SPIFFS, lancement du serveur Web), le programme teste si le premier bit du « Device Config » est à 1, indiquant qu’une configuration valide a été entrée et testée ;
  • NB : si le « Device Config » est à 255 (0xFF), ce qui est fréquemment le cas avec une nouvelle carte (et est le cas après un Wipe suivi d’un « Hard Reset »), sa valeur est forcée à 0 et enregistrée dans l’EEPROM pour forcer l’entrée dans le mode « initialisation ».
  • S’il ne l’est pas, il entre dans une boucle qui nécessite pour en sortir qu’une configuration WiFi valide ait été entrée et vérifiée. Comme expliqué précédemment, cette boucle effectue les actions suivantes :
    • Elle place le dispositif en Access Point WiFi avec pour SSID « Pilote_ » suivi des 3 derniers octets en hexadécimal de l’adresse MAC de la carte (le WiFi de l’Access Point a une adresse MAC différente mais qui ne nous intéresse pas ici), sans clé de protection ;
    • Elle donne à la carte l’adresse IP 10.10.10.1 et active la fonction DHCP ;
    • Tant qu’une station n’est pas connectée à la carte, la LED bicolore clignote en rouge toutes les 2,5 secondes ;
    • Quand une station se connecte, la LED clignote en vert toutes les 2,5 secondes pour indiquer la connexion et l’attente d’une commande ;
    • Les commandes, envoyées via un navigateur, depuis la station connectée au dispositif peuvent être :
      • http://10.10.10.1/MACaddress qui permet d’obtenir l’adresse MAC du boitier (celle qui sera vue quand il sera connecté au réseau WiFi local) en vue de lui affecter une adresse IP fixe via le service DHCP fourni par une Box présente sur le réseau et, éventuellement, l’autoriser à se connecter au réseau WiFi si une protection par adresses MAC du réseau a été mise en place ;
      • http://10.10.10.1/NetConfig?SSID=SSID_WIFI&WPA=WPA_KEY&Name=DEVICE_NAME pour entrer les paramètres d’accès au réseau WiFi et dans laquelle :
      • SSID_WIFI est le SSID du réseau WiFi à rejoindre, il doit avoir 31 caractères au plus WPA_KEY est la clé WPA à utiliser, elle doit avoir 62 caractères au plus DEVICE_NAME est le nom du périphérique qui sera vu via le réseau, il doit avoir 15 caractères au plus. NB1 : l’ordre des paramètres est important et tout ordre différent conduira à une erreur. NB2 : il ne doit pas y avoir d’espace dans les paramètres mais des guillemets peuvent les entourer. NB3 : il n’y a pas de possibilité de fixer l’adresse IP par cette commande, cette fonction ayant peu d’intérêt. La fixation de l’adresse IP pourra facilement être faite (et plus facilement changée) en définissant un bail statique (affectation d’une adresse IP à une adresse MAC particulière) au niveau du service DHCP.""
    • La LED verte devient fixe pendant l’interprétation de la commande et la tentative de rejoindre le réseau WiFi demandé, la LED bleue montre la progression :
      • Elle clignote 2 fois toutes les 0,3 s lors des tentatives pour accéder au réseau WiFi ;
      • Le nombre maximum de tentatives est fixé à 100, s’il est atteint, le système considère que le réseau demandé n’est pas accessible (erreur au niveau du SSID, erreur au niveau du mot de passe ou adresse MAC non autorisée sur le réseau si cette protection a été activée sur la borne WiFi), la LED rouge s’allume en fixe un bref instant, puis le programme repart au début du cycle d’initialisation ;
      • Si l’accès au réseau WiFi fonctionne, la LED bleue clignote lentement 5 fois pour acquitter cet accès correct puis très rapidement 20 fois pour la mémorisation des paramètres.
  • Si une configuration d’accès correcte au réseau WiFi est enregistrée (soit après les opérations précédentes, soit après une extinction en fonctionnement normal), la carte termine son initialisation :
    • Elle se connecte au réseau WiFi (boucle indéfiniment si celui-ci n’est pas accessible, si le SSID ou la clé WPA a changé…), la LED bleue clignotante indique la connexion en cours : 2 fois toutes les 0,3 s pendant la recherche du réseau, puis 5 fois lentement lorsque la connexion est établie  ;
    • Elle recharge tous les paramètres précédemment enregistrés : mode du fil pilote, luminosité des LEDs, présence du capteur DHT, paramètres de surveillance de la température et de l’humidité et ceux de l’IPX vers lequel remonter ces infos ;
    • NB : ces paramètres seront ceux par défaut après une initialisation ou un « Hard Reset » : fil pilote en mode Eco, luminosité des LEDs à 10‰, pas de capteur DHT.
    • Elle sort de la fonction setup() pour passer la main à la fonction loop() qui va gérer le fonctionnement du dispositif en mode « normal ».

Le fonctionnement « normal »: fonction void loop()

Les différentes étapes de fonctionnement de la boucle principale sont :

  • la détection de l’appui sur le bouton de « Hard Reset » (qui remet à 0 le 1er bit du 1er octet de l’EEPROM pour indiquer qu’il n’y a pas de configuration WiFi valide enregistrée et fait rebooter le boitier) ;
  • NB : en l’occurrence, c’est une opération « -1 » qui est faite sur la valeur du paramètre « Device Config ». Cela revient bien à mettre à 0 le 1er bit du 1er octet de l’EEPROM si celui-ci était précédemment à 1, et n’affecte pas le 2ème bit qui mémorise la présence du capteur DHT22.
  • la détection de l’appui sur le bouton de changement d’état, ce qui a pour effet de faire passer le pilote d’un état au suivant dans l’ordre indiqué précédemment (Confort -> Eco -> Hors Gel -> Arrêt -> Confort) ;
  • diminuer la luminosité des LEDs en ne les gardant allumées que pendant un certain nombre de cycles consécutifs tous les 1000 tours de boucle ;
  • NB : ce principe très simple a toutefois pour conséquence de conduire a quelques clignotements intempestifs quand la carte est occupée à faire autre chose que sa boucle principale (interrogation via l’IPX depuis un widget…).
  • mesurer la température et l’humidité à intervalle de temps régulier et informer l’IPX en positionnant à 0 ou à 1 la ou les sorties virtuelles déclarées, si cette fonction est activée ;
  • vérifier l’arrivée d’une nouvelle commande http et l’interpréter pour exécuter les opérations nécessaires. Pour cela, les commandes reçues sont converties en un n° si elles sont reconnues (-1 si la commande n’est pas reconnue), ce qui permet leur traitement par un « case ». Les commandes renvoient toutes vers le client (navigateur Web) une réponse sous forme JSON pour indiquer le succès ou non de l’opération, retourner les paramètres demandés…

    Améliorations possibles du code

    Parmi les améliorations possibles du code il y aurait notamment :

    • pouvoir attribuer une adresse IP fixe, ainsi qu’un masque de sous-réseau et éventuellement une adresse de routeur si on souhaite pouvoir accéder au boitier au travers d’une redirection de port ;
    • pouvoir piloter les états « Confort -1° » et « Confort -2° ».

    N’ayant personnellement pas l’usage de ces deux fonctions (même si cela était prévu pour la première dans le code initial, comme cela peut se voir via certaines parties de codes non achevées et mises en commentaire), j’ai choisi de ne pas les développer.

    La fixation de l’adresse IP des boitiers est faite chez moi, comme dit précédemment, via des baux statiques au niveau du service DHCP de ma Box (une FreeBox en ce qui me concerne) qui permet d’attribuer toujours la même IP à une certaine adresse MAC. La plupart des Box, incorporent a priori ce mécanisme. La commande http://10.10.10.1/MACaddress durant la phase d’initialisation sert d’ailleurs à récupérer cette adresse MAC pour pouvoir faire facilement cette affectation. Fixer des adresses IP statiques directement dans les boitiers, complexifierait, à mon sens inutilement, l’administration du réseau et alourdirait beaucoup le code avec les nécessaires contrôles sur les informations IP que cela nécessiterait.

    Quand aux ordres « Confort -1° » et Confort -2° », ils ne présentent, de mon point de vue, aucun intérêt pour le pilotage via un IPX. Par contre, ils peuvent être utilisés par des radiateurs intégrant un capteur de présence et qui vont être capables de passer d’eux-mêmes dans ces modes, malgré un ordre « Confort » sur leur fil pilote, en l’absence de détection durable d’une présence pour faire des économies d’énergie. Se référer à la documentation du radiateur pour voir si cette fonction est proposée dessus, si elle est compatible avec le pilotage par fil pilote et comment la mettre en service.

    Une autre amélioration potentielle serait la détection de la présence du capteur DHT pour interdire sa mise en fonction s’il n’est pas présent (ce qui fait perdre du temps dans les réponses aux requêtes). Présentant peu d’intérêt, je ne l’ai pas développée pour l’instant.

    Bon montage et n’hésitez pas à me remonter vos remarques et améliorations.