Bien que le système de domotique de la chambre soit parfaitement autonome, sa connexion au reste de la domotique de la maison est essentielle. C’est l’élément qui fera du tout une domotique parfaitement intégrée.
Le choix des technologies
Cette étape n’est pas facile à réaliser. Pour commencer, j’ai dû fournir les capacités matérielles au système pour entrer dans le réseau local. L’Arduino Mega n’offre pas cette possibilité : j’ai donc dû ajouter un second microcontrôleur : un ESP8266-01. Cette carte est très compacte, parfaite pour l’utilisation que je lui ai destinée. Deux microcontrôleurs signifie deux programmes ! Et ainsi deux fois plus de problèmes (à moins que ce ne soit exponentiel ?!).
J’ai pour serveur de domotique Home Assistant, dont j’ai dédié un article. Il faut de ce fait que j’intègre mon propre système à celui d’une organisation externe. Je m’étais dans un premier temps tourné ver une API REST, mais cette méthode présente d’innombrables inconvénients. Le mieux serait d’utiliser un logiciel directement développé par Home Assistant et qui puisse se loger dans l’ESP8266-01 pour communiquer avec le serveur… ESPHome !
Pour comprendre cette partie, il faut avoir quelques bases à propos du fonctionnement d’ESPHome.
ESPHome a ce que l’on appelle des external components
. Ce sont des composants que n’importe qui peut développer, et que l’on peut ensuite utiliser dans les fichiers de configuration YAML
comme un composant normal (exemple : un composant light
).
Il suffit donc de créer des composants externes qui communiquent avec l’Arduino Mega en UART, et le tour est joué. Cependant, ce n’est pas si simple ! Je vais tenter de vous expliquer au mieux comment le tout fonctionne.
Le protocole de communication
ESPHome va gérer la liaison entre Home Assistant et l’ESP8266-01, mais rien ne gère directement la communication entre l’Arduino et cette dernière ! Il y a une simple liaison UART en place.
J’ai donc créé un protocole pour permettre aux deux parties de se comprendre (pour qu’ils parlent la même langue en gros). Tout d’abord, je dois lister les informations qui passeront par la liaison :
- Les ordres de contrôle (allumage, arrêt…) visant les appareils du système.
- Les ordres du contrôle visant les appareils de Home Assistant.
- Les mises à jour d’états des appareils du système.
- Les mises à jour d’états des appareils de Home Assistant.
- Quelques autres messages particuliers : affichage d’un message sur l’écran du boîtier de contrôle, lecture d’une vidéo animée…
Il est aussi nécessaire de pouvoir identifier chaque appareil : c’est l’utilité du communication_id
dans les deux programmes (par exemple dans le programme principal). Il est unique pour chaque appareil. Je suis parti de 1
pour les appareils du système, et de 99
pour les appareils de Home Assistant.
Enfin, il faut connaître toutes les commandes possibles : par exemple, on doit pouvoir changer la couleur d’un ruban lumineux ou déclencher l’alarme manuellement.
J’en suis venu à ce protocole :
- Le premier caractère indique de quel type est le message :
- Pour un ordre, les deux caractères suivants correspondent au type de commande :
- Gestion de l’alimentation (allumer ou éteindre).
- Commandes spécifiques aux rubans lumineux (couleur, animation…).
- …
- Pour une mise à jour, les deux caractères suivants correspondent au type d’information transmise :
- La disponibilité.
- L’état de l’alimentation.
- Un attribut d’un ruban lumineux (couleur, animation actuelle…).
- …
- Pour une vidéo, l’URL de la vidéo à lancer sur la télévision.
- …
- Pour un ordre, les deux caractères suivants correspondent au type de commande :
- Le dernier caractère est un retour chariot pour signaler de la fin du message.
- Il y a aussi deux caractères dédiés à l’identifiant du périphérique concerné, à une position différente dans le message selon son type.
Le protocole est détaillé dans le fichier le définissant.
La partie Arduino Mega
La communication avec l’ESP8266-01 est définie comme héritant de Device
(oui, c’est étrange, mais cela fonctionne !). C’est cette classe qui envoie et reçoit les messages UART. Elle gère donc le traitement des messages pour que le tout soit plus agréable dans le reste du programme.
Cette classe HomeAssistant
a deux principaux rôles :
- Proposer des méthodes à tous les autres périphériques du système pour que ces derniers puissent facilement partager les mises à jour de leur état. Il suffit d’appeler une petite méthode avec quelques paramètres et notre classe
HomeAssistant
formera toute seule le message qu’elle enverra par la suite. - Réceptionner et traiter les messages en provenance de l’ESP8266-01. Elle redistribue ensuite les informations aux périphériques intéressés : contrôle d’un appareil ou mise à jour.
La classe !
La partie ESP8266-01
ESPHome est donc le programme de notre microcontrôleur. J’ai trouvé cette partie intéressante, bien que difficile, car c’était une des premières fois où j’ai dû partir d’un programme préexistant pour y ajouter mes fonctionnalités. Il y a donc eu un travail d’adaptation pour que mon idée de programme rentre dans l’actuel code d’ESPHome. Ce qui aura été le plus difficile était le manque d’information sur le fonctionnement même du programme d’ESPHome. J’ai dû lire moi-même certains fichiers pour en comprendre le fonctionnement.
Le composant externe que j’ai développé se concentre dans un répertoire. Tout d’abord, nous avons besoin d’une classe centrale qui gérera la ligne UART, comme HomeAssistant
dans l’autre programme. Ici, je l’ai appelée ConnectedBedroom
. Cette classe fonctionne de la manière suivante :
- Chaque classe représentant un périphérique de la domotique s’enregistre auprès de
ConnectedBedroom
qui stocke le tout dans des listes par type de périphérique (lumière, télévision…). - Elle réceptionne les messages de l’Arduino Mega et répercute les actions sur les classes des périphériques.
- Toutes les classes représentant des appareils se réfèrent à
ConnectedBedroom
pour envoyer des messages à l’Arduino Mega.
Les classes des périphériques, elles, représentent chacune un unique appareil du système de domotique. Ce sont ces classes que Home Assistant peut prendre en compte pour les afficher dans l’interface en tant qu’entité light
, alarm_control_panel
, etc. Lorsque son état est modifié par Home Assistant (donc par l’utilisateur ou une automatisation), une méthode est appelée. On peut alors faire en sorte d’envoyer un message UART. Inversement, lorsqu’une mise à jour de l’état est reçue de l’Arduino, la classe ConnectedBedroom
appelle une méthode qui engendre la mise à jour de l’état du périphérique et qui est reporté à Home Assistant.
Exemple :
/// @brief Classe représentant un périphérique "basique" du système de domotique : apparaît comme une entité "switch".
class ConnectedBedroomSwitch : public Component, public switch_::Switch, public ConnectedBedroomDevice {
public:
void register_device() override;
protected:
void write_state(bool state) override;
};
Voir sur GitHub.
Home Assistant appelle write_state
pour modifier l’état, ce qui envoie le message suivant en UART :
/// @brief Envoie une requête à l'Arduino Mega pour modifier l'état d'un périphérique.
/// @param state L'état à définir.
void ConnectedBedroomSwitch::write_state(bool state) {
this->parent_->write('0');
this->parent_->write_str(addZeros(this->communication_id_, 2).c_str());
this->parent_->write('0');
this->parent_->write('0');
this->parent_->write(state ? '1' : '0');
this->parent_->write('\n');
}
Voir sur GitHub.
Lorsque ConnectedBedroom
reçoit une mise à jour, il va retrouver la classe de l’appareil concerné grâce à son identifiant unique, et mettre à jour son état ainsi :
switch_->publish_state(getIntFromVector(this->receivedMessage_, 5, 1));
Voir sur GitHub.
Cette ligne est un peu barbare, mais l’important est le publish_state
qui va mettre à jour l’état du switch_
.
Concernant les périphériques provenant de Home Assistant, il n’y a pas de classe dédiée. ConnectedBedroom
s’abonne aux mises à jour de l’état de ces entités de HA au démarrage. Concrètement, lorsqu’une lumière est contrôlée, une méthode de ConnectedBedroom
est appelée. Il suffit d’envoyer les modifications à l’Arduino. Dans le sens inverse, lorsque l’Arduino envoie un ordre de commande d’un appareil de Home Assistant, ConnectedBedroom
effectue une action (anciennement appelé service) Home Assistant.
Il nous manque encore un dernier élément pour que le programme fonctionne : le fichier python. Oui, moi aussi, je m’en serais bien passé, d’autant plus que cette partie était la plus difficile à comprendre ! Le fichier python sert à générer le programme en C++ à partir de la configuration de l’utilisateur en YAML. Je n’ai trouvé que très peu de documentation sur ce sujet, et cette méthode de programmation m’est étrangère. Je suis tout-de-même parvenu à un résultat fonctionnel et plutôt propre après de nombreux essais et un peu d’aide de la communauté ESPHome. Je ne vais pas entrer dans les détails parce que je ne m’y connais pas assez, mais globalement, on définit un schéma de configuration avec des paramètres à indiquer pour ensuite générer le fichier C++. Je vous invite à aller directement voir le programme pour obtenir plus de détails !
On obtient le résultat suivant dans le fichier de configuration ESPHome de l’ESP8266-01 :
...
external_components:
- source:
type: git
url: https://github.com/zetiti10/Domotique-chambre-ESPHome
components: [ connected_bedroom ]
refresh: 0s
uart:
tx_pin: TX
rx_pin: RX
baud_rate: 9600
id: uart_bus
connected_bedroom:
uart_id: uart_bus
analog_sensors:
- communication_id: 18
name: "Température"
accuracy_decimals: 1
device_class: temperature
unit_of_measurement: "°C"
binary_sensors:
- communication_id: 12
name: "Portes de l'armoire"
device_class: door
- communication_id: 13
name: "Porte de la chambre"
device_class: door
switches:
- communication_id: 1
name: "Plateau"
icon: "mdi:tray"
- communication_id: 2
name: "Cube de DEL"
icon: "mdi:cube"
alarms:
- communication_id: 10
name: "Alarme"
codes:
- !secret louis_alarm_code
missile_launcher:
base_number:
name: "Orientation de la base du lance-missile"
icon: "mdi:cached"
angle_number:
name: "Inclinaison de la tête du lance-missile"
icon: "mdi:swap-vertical"
launch_button:
name: "Tirer un missile"
icon: "mdi:firework"
missiles_sensor:
name: "Missiles disponibles"
icon: "mdi:dots-horizontal"
televisions:
- communication_id: 11
state_switch:
name: "Télévision"
icon: "mdi:remote-tv"
mute_switch:
name: "Télévision en sourdinne"
icon: "mdi:volume-mute"
volume_up_button:
name: "Augmenter le volume de la télévision"
icon: "mdi:volume-plus"
volume_down_button:
name: "Diminuer le volume de la télévision"
icon: "mdi:volume-minus"
volume_state:
name: "Volume de la télévision"
icon: "mdi:volume-high"
RGB_LED_strips:
- communication_id: 9
name: "Ruban de DEL RVB"
icon: "mdi:led-strip-variant"
effects:
- rainbow:
- soundreact:
- alarm:
connected_lights:
- communication_id: 96
entity_id: "light.lumiere_plafond_de_la_chambre_de_louis"
type: BINARY_CONNECTED_DEVICE
J’ai supprimé certains appareils pour ne pas trop allonger l’article.
Le résultat est parfaitement intégré à ESPHome, avec une grande modularité. Le contrôle depuis Home Assistant est tout aussi bien intégré !
Le résultat
Grâce à la conception de l’ensemble, la mise à jour des états est instantanée tout en étant optimisée. C’est assez satisfaisant d’entendre instantanément le relai qui s’allume lorsqu’on clique sur Home Assistant ; et inversement, on voit directement la fermeture de la porte sur le téléphone dès qu’elle est fermée.
Laisser un commentaire