Home assistant est en mesure de créer une entité pour à peu près tout ce qu'on veut.
Une entité, c'est un peu comme un objet, unique, qu'on différencie des autres entités par un identifiant.
Il y a des entités possibles pour tout.
Par exemple, une lumière, un ventilateur, un moteur de volet roulant, une prise éléctrique... tout ça est enregistré dans Home Assistant sous forme d'une entité pour chacun.
En modifiant la valeur de cette entité, on agit sur l'objet qui lui est lié: allumer une lumière, changer sa couleur, son intensité, baisser ou relever un volet roulant, allumer ou éteindre une prise.
Certaines entités ne sont pas faites pour être contrôlées. Elles contiennent une information, que l'on peut lire.
Par exemple, une sonde de température est liée à une entité. On peut lire cette entité, mais pas la modifier. C'est Home Assistant qui la modifie lorsqu'il récupère la température relevée par la sonde.
On pourrait vulgairement dire que Home Assistant est orienté objet. On peut définir des scripts ou des automatismes en fonction de l'était de ces objets.
Et ces objets, ce sont les entités.
Alors pourquoi je vous parle de ça ? Et bien parce qu'il existe de nombreuses autres façons de récupérer l'état d'un capteur ou d'un appareil, et d'influer dessus. Et parmi les méthodes possibles, il y a le MQTT.
Et bien que Home Assistant pourrait tout à fait se passer du MQTT, puisqu'il sait gérer lui même ses entités, il l'intègre néanmoins.
La raison est simple: bien que le MQTT ne soit pas à l'origine du tout prévu pour la domotique, ce protocole s'impose désormais comme un incontournable dans le domaine.
Et avant de se demander quelles sont les différences entre les entités de Home Assistant et le MQTT, la première question serait: c'est quoi le MQTT ?
Alors, c'est quoi le MQTT ?
Message Queuing Telemetry Transport
A l'origine crée par des ingénieurs pour l'industrie pétrolière, ce protocole de communication est conçu pour échanger des informations très rapidement, efficacement, et avec une consommation de bande passante très réduite.
Tout est hiérarchisé en MQTT.
Un serveur (qu'on appelle Broker) possède des fils (appelés topic).
Voyez ça comme des "sujets de conversation".
Un topic peut comporter plusieurs sections, et des des sous-sections.
Un appareil peut s'abonner à l'un de ces topics, ou bien à plusieurs.
Il peut lire ou, s'il en a les droits, mettre à jour les informations des topics auxquels il est abonné.
Vous êtes libre de hiérarchiser vos topics et leurs contenus à votre guise.
Le MQTT au sein de River Island
Lorsqu'un sujet est mis à jour, tous ceux qui y sont abonnés peuvent être informés.
Voici l'organisation que j'ai mis en place sur le serveur principal de River Island:
- Paramètres système
- Gestion du mode d'exploitation
- Gestion de la maintenance
- Attraction 1
- Moteur
- Vitesse de rotation
- Lumières
- Moteur
- Attraction 2
- Moteur
- Vitesse de rotation
- Lumières
- Moteur
Et voici concrètement l'arborescence:
Toutes les attractions sont hiérarchiquement similaires.
- Le topic principal porte le nom de l'attraction. Il indique si l'attraction est ouverte, fermée ou en maintenance.
- Une sous-section 'lights' renseigne sur l'état des lumières: allumées, éteintes ou en animation
- Une autre sous-section 'engine' renseigne sur le sens de rotation du moteur de l'attraction: horaire (CW) ou anti horaire (CCW).
- Enfin, une sous-sous-section de la partie 'engine', 'speed' renseigne sur la vitesse de rotation du moteur (de 0 à 100%).
Bien que ces topics soient portés par Home Assistant, puisqu'il est le broker, ils sont majoritairement mis à jour par la console de commande.
Etant donné que l'écran principal donne la possibilité de contrôler toute la maquette, les topics sont mis à jour au fur et à mesure par lui.
Selon l'appareil, l'action se produit directement sur lui, ou bien lance un script sur Home Assistant, ou bien encore dans l'ESP directement.
Un exemple parlant est celui du mode manuel.
Le code du mode manuel se trouve dans l'ESP qui gère l'écran principal.
Dans le mode manuel, un menu déroulant permet de sélectionner l'attraction.
Une fois l'attraction sélectionnée, on en obtient le contrôle total. Moteur, vitesse, sens de rotation, lumières, état de l'attraction...
Par conséquent, le programme doit pouvoir accéder à tous les topics, mais également tous les modifier.
Le mode manuel est à lui seul une sorte de programme dans le programme.
Ses 300 lignes contrôlent tout, et obtient en même temps les informations de toutes les attractions, en MQTT.
En voici les grandes lignes.
Je définit d'abord quelques variables, avec des valeurs par défaut:
globals: - id: manual_mqtt_topic_selection type: std::string restore_value: no initial_value: '"home/attractions/ferris_wheel"' - id: manual_mqtt_topic_selection_light type: std::string restore_value: no initial_value: '"home/attractions/ferris_wheel/lights"' - id: manual_mqtt_topic_selection_engine type: std::string restore_value: no initial_value: '"home/attractions/ferris_wheel/engine"' - id: manual_mqtt_topic_selection_engine_speed type: std::string restore_value: no initial_value: '"home/attractions/ferris_wheel/engine/speed"'
Elles portent les valeurs par défaut des topics de la première attraction du menu déroulant, la Grande Roue.
Dans les valeurs de ces variables, on retrouve bien la structure des topics que j'ai présenté plus haut.
Ensuite vient le code en lui même.
Voici par exemple la section qui affiche le menu déroulant. J'utilise LVGL pour les affichages:
lvgl: touchscreens: - touch displays: - my_display theme: button: border_width: 2 border_color: 0xFFFFFF bg_color: 0x278EDA radius: 5 checkable: false label: text_color: 0x000000 text_font: helvetica_20 buffer_size: 25% pages: # Page de controle manuel - id: manuel bg_color: 0x000000 opa: COVER bg_opa: COVER border_width: 2 border_color: 0xFFFFFF radius: 7 widgets: - obj: bg_color: 0x000000 height: 100% width: 100% y: 0 bg_opa: COVER opa: COVER border_width: 0 widgets: - dropdown: x: 100 y: 5 width: 310 id: dropdown_attraction_selection dir: TOP options: - Grande Roue - Pieuvre - Chaises volantes - Auto Tamponneuses - Flipper - Top Spin - Chenille selected_index: 0 on_value: - logger.log: format: "Selected index is: %d" args: [ x ] - script.execute: attraction_selection
Le menu déroulant renvoie une valeur numérique: la position de l'élément sélectionné.
Dans notre cas, nous avons donc:
Ne reste qu'à définir la valeur des variables qu'on a crée au préalable, selon le choix fait dans le menu déroulant.
Ensuite, tous les autres éléments du mode manuel appelleront ces variables.
script: - id: attraction_selection then: - lambda: |- int selected_value = lv_dropdown_get_selected(id(dropdown_attraction_selection)); ESP_LOGD("dropdown", "Selected value: %d", selected_value); if (selected_value == 0) { id(manual_mqtt_topic_selection) = "home/attractions/ferris_wheel"; id(manual_mqtt_topic_selection_light) = "home/attractions/ferris_wheel/lights"; id(manual_mqtt_topic_selection_engine) = "home/attractions/ferris_wheel/engine"; id(manual_mqtt_topic_selection_engine_speed) = "home/attractions/ferris_wheel/engine/speed"; } if (selected_value == 1) { id(manual_mqtt_topic_selection) = "home/attractions/octopussy"; id(manual_mqtt_topic_selection_light) = "home/attractions/octopussy/lights"; id(manual_mqtt_topic_selection_engine) = "home/attractions/octopussy/engine"; id(manual_mqtt_topic_selection_engine_speed) = "home/attractions/octopussy/engine/speed"; } if (selected_value == 2) { id(manual_mqtt_topic_selection) = "home/attractions/flying_chairs"; id(manual_mqtt_topic_selection_light) = "home/attractions/flying_chairs/lights"; id(manual_mqtt_topic_selection_engine) = "home/attractions/flying_chairs/engine"; id(manual_mqtt_topic_selection_engine_speed) = "home/attractions/flying_chairs/engine/speed"; } if (selected_value == 3) { id(manual_mqtt_topic_selection) = "home/attractions/bumper_cars"; id(manual_mqtt_topic_selection_light) = "home/attractions/bumper_cars/lights"; id(manual_mqtt_topic_selection_engine) = "home/attractions/bumper_cars/engine"; id(manual_mqtt_topic_selection_engine_speed) = "home/attractions/bumper_cars/engine/speed"; } if (selected_value == 4) { id(manual_mqtt_topic_selection) = "home/attractions/flipper"; id(manual_mqtt_topic_selection_light) = "home/attractions/flipper/lights"; id(manual_mqtt_topic_selection_engine) = "home/attractions/flipper/engine"; id(manual_mqtt_topic_selection_engine_speed) = "home/attractions/flipper/engine/speed"; } if (selected_value == 5) { id(manual_mqtt_topic_selection) = "home/attractions/top_spin"; id(manual_mqtt_topic_selection_light) = "home/attractions/top_spin/lights"; id(manual_mqtt_topic_selection_engine) = "home/attractions/top_spin/engine"; id(manual_mqtt_topic_selection_engine_speed) = "home/attractions/top_spin/engine/speed"; } if (selected_value == 6) { id(manual_mqtt_topic_selection) = "home/attractions/jungle_train"; id(manual_mqtt_topic_selection_light) = "home/attractions/jungle_train/lights"; id(manual_mqtt_topic_selection_engine) = "home/attractions/jungle_train/engine"; id(manual_mqtt_topic_selection_engine_speed) = "home/attractions/jungle_train/engine/speed"; }
Ce code est largement perfectible.
Par exemple, on pourrait définir que
Mais mes connaissances sont encore trop faibles pour savoir la syntaxe pour cela. Mais ça fonctionne !
Avec cette portion de code fonctionnelle, le développement de l'interface graphique avance d'un grand pas.
Reste à configurer le mode autonome. Et c'est dans Home Assistant que ça se passera !