Home Assistant & Présence

En 2020 je vous parlais déjà de la gestion de la présence à l'aide d'objets BLE. Je vais essayer d'être plus exhaustif. Le BLE reste toujours d'actualité, mais il convient de définir la présence dont on a besoin et les sources à y associer. Pour faire bref il s'agit de savoir si on souhaite savoir si une personne est présente ou absente de la maison (ou dans une autre zone géographique définie), ou encore si une personne est présente dans une pièce particulière de la maison. Et là c'est un peu plus compliqué. On va voir avec quelles sources on va gérer tous ça.

A quoi ça sert ?

Savoir si on est à la maison permettre se d'intégrer à des automation, pour par exemple gérer le chauffage. On peut également associer la géolocalisation avec l'intégration proximity: afin de déclencher des actions en s'approchant de la maison, par exemple pour allumer des lampes ou ouvrir un portail. Surveiller les entrées sorties des enfants ?

Quant à la présence dans une pièce particulière, cela sera utile pour maintenir une action. Si le chauffage supporte la latence d'un indicateur de présence, Imaginons par exemple un détecteur de présence qui va allumer une lampe combiné à une indicateur de présence qui va la maintenir allumée tant que l'on se trouve dans la pièce. Ici l'indicateur de présence n'est pas suffisant car sa latence ne permettrait pas l'allumage suffisamment rapide. A noter qu'il existe des capteurs plus sophistiqués, donc plus couteux, qui permettent une détection de présence.

Simple ?

Oui et non. Savoir si une personne est présente à la maison est simple. Pour savoir dans quelle pièce elle se trouve ça devient plus compliqué et fastidieux à étalonner afin d'éviter les fausses informations. De plus ça impose de "porter" un tracker ou un mobile lorsque l'on se déplace dans la maison. Autant ça m'a amusé de tester toutes ces intégrations, autant je ne suis pas sur de les mettre en production.

Présence ou absence

  • Application mobile Home Assistant : C'est un peu la base. L'application va nous remonter la zone (home, not_home ainsi que les zones que l'on aura définies et l'adresse). L'application communique directement avec HA.
  • Google Maps : On obtient le même retour avec parfois une meilleure position. La configuration est devenue extrêmement simple avec cette intégration qui ne nécessite ni cookie, ni yaml ! Avec l'accord de son propriétaire on peut facilement suivre un mobile. Et pour rappel on partage la localisation avec un compte Google dédié qui sera utilisé dans HA.
  • Life 360 : Obsolète, l'API n'est plus disponible.
  • Tile : Il y a plusieurs façons d'utiliser un tracker et on en parlera plus loin, mais il est également possible de créer un compte Tile sans tracker, de l'installer sur un mobile afin de remonter la position (home, not_homeainsi que les coordonnées GPS). C'est peut tordu, mais ça peut éviter de faire un partage Google.
  • Owntrack : Il faut une application dédiée et le résultat est inégal, toutefois meilleur sur IOS.

Pour une meilleure précision on combine bien sur plusieurs sources sur l'entité person. Ces solutions présentent toutefois l'inconvénient d'être dépendantes du cloud ou de l'exposition à Internet de Home Assistant.

On peut également utiliser le WI-FI, pas mal d'intégrations de routeurs (Unifi par exemple) permettent de remonter à HA si un device est connecté. (home, not_home). Attention toutefois à la latence.

Et bien sur le Bluetooth, et plus particulièrement BLE (Bluetooth low energy). On va parler ici de présence locale (home, not_home), mais également de présence dans une pièce précise.

De base et intégré à Home Assistant

La communication se fait avec une clé Bluetooth ou des proxys qui peuvent être des ESP ou des Shelly gen2 et +. On commence à placer ceci dans configuration.yaml (l'option track_new_devices: true va servir à ce que son nom indique, mais je vous conseille de le laisser à false et d'utiliser une application mobile (WIFIMan IOS ou Android par exemple, mail il y en a d'autres) pour rechercher l'adresse MAC de vos devices :

device_tracker:
  - platform: bluetooth_le_tracker  
    interval_seconds: 12
    consider_home: 180
    track_new_devices: false  

Et ensuite le device à suivre dans le fichier known_devices.yaml :

ha_ble_amazfit:
  name: Amazfit
  mac: BLE_A9:13:AB:43:22:64
  icon:
  picture:
  track: true
Après un redémarrage de Home Assistant on obtient cette entité : device_tracker.ha_ble_amazfit

Via un ESP sous ESPHome

Pour la faire courte il suffit d'ajouter ceci à la configuration ESPHome. La porté dépend de l'antenne et on aura bien sur de meilleurs résultats avec un ESP32 pourvu d'une antenne extérieure, genre Olimex...

esp32_ble_tracker:
  scan_parameters:
    # interval: 5s
    # window: 5s
    active: true # ou false

binary_sensor:
  - platform: ble_presence
    mac_address: A8:DF:32:B0:00:30
    name: "ESP Tile"

Via TheengsGateway

TheengsGateway, qui reprends l'ancien projet BLE to MQTT, s'installe sur différents types de devices, mais peut également l'installer sous forme d'addon sur Home Assistant. Il utilisera alors une clé Bluetooth et communiquera via le brooker MQTT. Si l'on peut remonter le home, not_home des devices (trackers ou autres), je verrais plus son usage en remplacement de BLE Passive Monitor pour qui veut des devices MQTT. Pour avoir un sensor dédié à la distance il faudra le créer et redémarrer :

sensor:
- platform: mqtt_room
  device_id: "E9:13:CD:43:20:66"
  unique_id: fc9dc91f-522d-43d1-bfaf-e3cdbec1026-9
  name: "Theengs : Amazfit"
  state_topic: "home/presence"

Via ESPresence

Dans l'idée ESPresence est plutôt fait pour monitorer la présence dans une pièce particulière. Il faut installer le firmware dédié sur un ESP. La communication avec Home Assistant se fait en MQTT. On disposera alors d'un sensor avec le home, not_home et la distance en attribut. Bien sur ça demande un peu d'étalonnage, mais en plaçant un ESP par pièce on peut parvenir à un résultat intéressant. L'autre avantage est que ce projet permet de découvrir l'IRK d'un mobile (Android et IOS) et de le tracker malgré son adresse MAC qui est nativement aléatoire.

sensor:
- platform: mqtt_room
  device_id: "irk:dff2a090agdfgdfgd66a4d97f4dc1ac4c9e"
  unique_id: fc9dc91f-522d-43d1-bfaf-e3cdbec1026-2
  name: 'ESPresence : IRK'
  state_topic: 'espresense/devices/irk:dff2a090agdfgdfgd66a4d97f4dc1ac4c9e'
  timeout: 10
  away_timeout: 120

Je vous conseille cette vidéo :

Via Bermuda BLE Trilateration

Cette intégration est à mon gout la plus moderne et fonctionnelle pour monitorer des pièces. Elle zappe l'étape MQTT et elle s'appuie sur une clé Bluetooth, mais on préfèrera des les proxy BLE dans chaque zone, qu'ils soient sous espHome ou Shelly gen2+ (avec lesquels j'ai obtenu les meilleurs résultats). S'agissant d'une intégration moderne tout se fait sans une ligne de yaml ce qui ravira les réfractaires. L'intégration gère nativement les mobiles via l'IRK et on choisit les devices un à un. Le plus compliqué restera l'étalonnage...

Amusez vous bien !

 

Home Assistant & Piles

La gestion des piles des capteurs peut rapidement devenir un casse tête. De plus cela dépend également de qui va gérer les changements de piles, par exemple un utilisateur qui n'a pas accès au code et aux entités. Je voulais une carte synthétique qui en plus de l'état des piles indique leur type et la date du dernier changement. Estimer la durée de vie d'une pile peut être très subjectif quand on le fait au fil de l'eau. Je voulais également une notification, mais ça c'était déjà en place.

Et un peu par hasard je suis tombé sur l'intégration Battery Notes qui va m'aider à faite tout ça !

Installer et configurer l'intégration est facile en suivant la documentation très bien faite. Pour que cela fonctionne il ne faut pas oublier d'installer les automations: développés par la communauté, ou les blueprint: proposés par l'auteur.

L'intégration ajoute des entités aux capteurs configurés pour et des attributs à l'entité principale Battery+. Ensuite on peu jouer avec, tant pour afficher que pour notifier.

Mon plus gros défit a été de créer une qui corresponde à mon désir, à savoir, lister les capteurs et afficher ces informations :

  • La date du dernier changement de pile. Cette date est mise à jour par l'intégration, mais il me fallait ajouter un bouton afin de pouvoir forcer la mise à jour de lors d'un changement qui n'aurais pas été pris en compte automatiquement. Et pour cela il me fallait récupérer l'entité du bouton de mises à jour ce qui m'a pris beaucoup (trop) de temps, moi qui ne suis pas développeur (les premières lignes du template).
  • Le type de pile et leur nombre,
  • L'état de de charge de la pile (on pourrait imaginer une couleur et un icone différent, il y a une carte pour ça),

Pour y parvenir j'ai combiné deux cartes : Auto-Entities et Multiple-Entity-Row.

Et voici le code de la carte que l'on pourrait surement optimiser :

type: custom:auto-entities
card:
  type: entities
filter:
  template: |-
    {% for DEVICE in states.sensor -%}
      {%- if DEVICE.entity_id is match('sensor.*_battery_plus') -%}
      {%- set device_name = DEVICE.entity_id.rsplit('_', 2)[0].split('.', 1)[1] -%}
      {%- set associated_plus   = 'sensor.' ~ device_name ~ '_battery_plus' -%}
      {%- set associated_button = 'button.' ~ device_name ~ '_battery_replaced' -%}
      {%- set associated_type   = 'sensor.' ~ device_name ~ '_battery_type' -%}
      {%- set associated_last   = 'sensor.' ~ device_name ~ '_battery_last_replaced' -%}
      {%- set associated_low    = 'binary_sensor.' ~ device_name ~ '_battery_plus_low' -%}
      {{
        {
          'entity': DEVICE.entity_id,
          'type': 'custom:multiple-entity-row',
          'name': '-'.join((DEVICE.attributes.friendly_name).split('-')[1:]).split(' ')[0],
          'secondary_info': { 'attribute': 'battery_last_replaced', 'name': 'Last changed :', 'format': 'date'},
          'state_color': true,
          'show_state': false,
          'entities': [
            {
              'attribute': 'battery_type_and_quantity',
              'name': 'Battery type',
              'styles': {'width': '80px', 'font-weight': 'bold', 'text-align': 'right'},
            },
            {
              'entity': associated_low,
              'name': 'State',
              'styles': {'width': '50px', 'font-weight': 'bold', 'text-align': 'right'},
            },
            {
              'entity': associated_plus,
              'name': 'Charge',
              'format': 'precision0',
              'styles': {'width': '50px', 'font-weight': 'bold', 'text-align': 'right'},
            },
            {
              'entity': associated_button,
              'name': false,
              'type': 'button',
              'icon': 'mdi:update',
              'styles': {'width': '20px', 'font-weight': 'bold', 'text-align': 'right'},
              'tap_action': {
                'action': 'call-service',
                'service': 'button.press',
                'service_data': {
                  'entity_id': associated_button
                   },  
                'confirmation': {
                  'text': 'Are you sure ?'   
                }
              }
            }
          ]
        }
      }},
    {%- endif -%}
    {%- endfor %}
sort:
  method: friendly_name
view_layout:
  position: main

EDIT 17/02/2025

Mon problème étant que j'ai trop de piles pour les afficher sur une seule page. Je vais donc ajouter un label à l'entité afin de faire un filtrage et pouvoir afficher ça sur plusieurs pages :

{%- if DEVICE.entity_id is match('sensor.*_battery_plus') and DEVICE.entity_id in label_entities('battery_notes_remotes') -%}  

ou pour ne pas afficher les entités avec ce label afin de les exclure d'une page :

{%- if DEVICE.entity_id is match('sensor.*_battery_plus') and DEVICE.entity_id not in label_entities('battery_notes_remotes') -%}

Home Assistant & Nuki

Ca me travaillait depuis un moment, automatiser la porte d'entrée ! L'objectif étant que la porte se verrouille quand je part (process d'alarme, fermeture des volets, etc.) et se déverrouille quand j'arrive avec le process inverse. Accessoirement permettre à des tiers d'ouvrir (clavier et tags), ou moi même d'ouvrir et fermer à distance.

J'ai regardé un peu le marché et j'ai trouvé :

  • Linus Yale : un peu trop américaine, et de fait encombrante ! (lien Amazon)
  • Tedee : tentant mais un peu jeune (test ici et lien Amazon)
  • Danalock : on dirait qu'ils ne bougent plus trop...
  • Nuki : mon choix par défaut ! (lien Amazon)
  • Switchbot : La nouvelle Pro à l'air plus intéressante de l'ancienne... (lien Amazon)
  • Et enfin beaucoup de chinoiseries que je préfère éviter pour ce genre d'objets...

Après avoir bien creusé le sujet et écouté les conseils d'autrui j'ai porté mon choix sur une Nuki Pro 4.0, en y voyant comme avantage :

  • Du WIFI intégré afin d'éviter un bridge supplémentaire
  • Un bloc de batterie rechargeable
  • Une meilleure finition
  • Matter, enfin, un jour peut être...

Je fait l'impasse de l'installation qui est effectivement facile, mais qui m'a tout de même couté un cylindre débrayable (lien Amazon). Et on passe à la configuration.

Je n'ai pas grand chose à redire sur la mise en œuvre via l'application, c'est plutôt bien fait, tout comme Nuki Web ou l'accès à distance depuis un smartphone. Là ou ça va se compliquer c'est pour intégrer ça à Home Assistant, et c'était le but ! Il existe plusieurs solutions et je veux bien comprendre que les débutants soient perdus.

Intégration du Core HA

On me l'a déconseillé et j'en ai lu du mal, j'ai donc zappé.

Intégration Nuki NG

Ca semble bien fait, mais c'est un fail. Je pense qu'il vaut mieux disposer du bridge Nuki.

Intégration Nuki BT

Il s'agit d'un fork de Nuki NG qui a la particularité de se connecter directement au Nuki en Bluetooth. A priori parfait pour mon usage. Sauf que je n'ai jamais réussit à appairer le Nuki à cette intégration.

MQTT

Proposé comme la solution officielle pour connecter Nuki à Home Assistant, je me suis dit que ça serait facile. En effet la configuration est simple et les information de base (Look/Unlook et batterie) remontent bien dans Home Assistant. Il faut laisser le WIFI actif, ça consommera un peu plus mais ça devrait aller.

Oui, mais ! Il y a un tout petit problème : entre l'envoi d'une commande, l'action et le retour d'état il peut se passer de 1 à 3 minutes (quand ça fonctionne). Et je ne me voit pas passer 3 minutes à attendre devant la porte... Que se passe t'il ? Direction le forum Nuki, et la c'est le bug ! Problème plus ou moins connu, récurent, bref les utilisateurs ne sont pas contents et j'aurais du lire ça avant. Bien sur Nuki explique que ça vient du Wi-Fi des utilisateurs, sauf que j'ai testé avec mon Unifi de base et 3 AP d'autres marques, avant de me dire que si l'application Nuki connectée sur un smartphone en 4G fonctionnait bien, le problème n'était pas lié au Wi-Fi mais à l'implémentation MQTT. Un peu dégouté, je me suis dit qu'ils voulaient vendre leur bridge et que n'y couperait pas !

MQTT via ESP Nuki HUB

Dans mes pérégrinations j'a commencé par tester sans succès un projet basé sur espHome avant de tomber sur Nuki Hub, un projet très complet qui crée un bridge avec un ESP. Nuki Hub communique avec un Nuki Lock, un Opener et un clavier via Bluetooth (BLE) et utilise MQTT pour s'intégrer à d'autres systèmes. Il expose l'état de verrouillage (et bien plus encore) via MQTT et permet d'exécuter des commandes telles que le verrouillage et le déverrouillage via MQTT (n'hésitez pas à bien lire la doc qui est une mine d'informations).

Un petit flash plus loin j'ai réussit à associer mon Nuki à ce bridge DIY, il remonte toutes les informations utiles, voire plus, et surtout il permet de verrouiller / déverrouiller rapidement la serrure, ce qui est tout de même la base.

Par contre il faut savoir une chose, chez Nuki c'est fromage ou dessert, pas le deux ! En gros pour activer un bridge, qu'il soit Nuki ou DIY, il faut désactiver le Wi-Fi du Nuki. Ce qui concrètement veut dire qu'on ne pourra plus le commander à distance depuis l'application Nuki et que si on veut utiliser localement cette application il faudra se rapprocher du Nuki, la portée du Bluetooth de cet objet étant très faible (j'ai du mal dans mon bureau qui est à 3 mètres de la porte d'entrée...).

Conclusion

Ou moralité ! Je crois que j'ai acheté une version 4 et Pro pour rien. En effet le Wi-Fi intégré ne me servira à rien et une v3 standard aurait parfaitement fait le job pour pas cher (il y a plein sur le Bon Coin !

EDIT 02/09/2024

J'ai retenté quelques configurations différentes :

  • BT avec l'appli mobile : Ce mode est le seul à peu près fiable. Donc pour Nuki tout est ok et ils peuvent même faire un peu de collecte de données. Mais le but est que cette serrure sont intégrée à Home Assistant.
  • MQTT natif en WI-FI : Pas fiable, la serrure passe son temps à faire le yoyo sur le WI-FI. Nuki joue au con sur son forum en renvoyant la balle aux fournisseurs de WI-FI en disant que chez eux c'est OK. J'ai une centaine de modules WI-FI qui ne posent pas de problèmes sur mon réseau Unifi. La serrure passe son temps à se déconnecter / reconnecter, et ne réactive la connexion MQTT que longtemps plus tard. Les seuls modules qui ont le même défaut sont certains vieux objets Xiaomi, je les ait virés. Une serrure c'est stratégique et ça sous entent une fiabilité à 100%.
  • Matter : Fail, que ce soit en natif sous HA ou via la passerelle Aqara M3.
  • Nuki Hub : J'ai réinstallé la v9. Cette mise à jour nécessite de repartir à zéro. Ca reste ce que j'ai de plus fiable.

On ne peut pas imaginer devoir rester quelques minutes devant la porte pour qu'elle s'ouvre après la désactivation de l'alarme. Je suis à deux pas de revenir à la clé !

EDIT 24/09/2024

Démontage de ce produit. Trop de déconvenues, et s'il faut se balader avec la clé au risque de dormir dehors, autant l'utiliser, d'autant plus que cette serrure est lente. Donc à vendre si l'aventure vous tente. Je suis preneur de vrais retours sur les autres modèles.

INFO

Contrairement à la majorité des blogs et autres influenceurs, je ne "reçoit" pas les produits d'un quelconque service de presse, mais je les achète, ce qui me permet d'assumer ce que je pense vraiment d'un produit. Pour autant ce n'est pas une critique des blogs ou YT qui en vivent, il faut bien manger ! De plus j'ai moi même été "journaliste" dans la presse tech et ça m'a jadis fait manger !

 

Home Assistant, Zigbee & Legrand

On m'a demandé récemment d'intégrer des appareils Legrand dans Home Assistant, je l'avais déjà fait pour certains et j'en avais parlé dans cet article. Aujourd'hui il s'agit d'intégrer des commandes sans fil vue come des télécommandes dans HA. Vous allez me demander quel est l'intérêt quand un simple bouton Ikea (E1743) à moins de 10 fait le job pour mes volets roulants. C'est purement esthétique, quand on a un logement équipé en Legrand Céliane ou Mosaic, on veut parfois que les commandes des volets soient dans la même collection.

Soit, Legrand propose des commandes en Zigbee, il n'y a plus qu'à !

Dans la pratique on va voir que ce n'est pas si simple, en tous cas bien moins simple qu'avec mon bouton Ikea à 10 € ! Je précise le prix car les commandes Legrand sont plutôt à 80 €. Mais quand on aime on ne compte pas.

Il existe plusieurs type d'équipements Zigbee chez Legrand

  • Ceux qui sont filaires, j'en ai parlé ici (micro modules, contacteur DIN, prise connectée, etc...)
  • La gamme des commandes sans fil à pile
  • La gamme des commandes sans fil sans piles (gamme Self-e). J'y reviendrait certainement, mais d'après mes infos cette gamme supporte tous les canaux et serait mieux intégrée ZHA/Z2M.

Je me suis donc penché sur la gamme avec pile.

Première observation, ces devices sont généralement livrés avec un firmware de niveau 42 qui ne permet que l'utilisation du canal Zigbee 11. Don impossible à faire fonctionner sur mon ZHA qui est en 15. Je l'ai donc appairé sur mon Z2M en 11 et ça fonctionne. Et là je me suis dit que j'allais pouvoir mettre à jour ce firmware en OTA. Mais non, ça ne fonctionne pas et on se retrouve dans la problématique des équipements franco Français qui n'intéressent pas grand monde au niveau international (on pense par exemple à tout ce qui est lié à l'intégration Overkiz...).

Après moultes lectures des forums de diverses plateformes domotique, la conclusion est que la mise à jour du firmware ne peut se faire qu'au travers d'une passerelle officielle Legrand ! J’ai donc acheté le kit qui comprend :

  • La prise Control qui sert de passerelle
  • Un inter sans fil
  • Une ampoule

Il faut bien sur installer l’appli Legrand et ensuite tenter d’associer la prise au WIFI. Facile ? Non, ça m’a pris de plombes car vu que leur process est trop long, le mobile qui se connecte à la prise pour la configurer repasse sur le WIFI normal ou il retrouve Internet, et perd la config en cours. Solution faire ça avec un vieux mobile… Bref, un premier amateurisme car on fait facilement ce genre d'association avec la majorité des objets mobile en WIFI !

Bon, la logique de l’appli est orientée électricien très grand public, avec une logique d'électricien qui n’est pas nécessairement la notre. C'est un choix, il faut s'y faire, mais n'oublions pas que nous sommes ici uniquement pour faire un mise à jour...

Ensuite il faut ajouter les inter. Sauf que la il faut comprendre qu’on ne peut pas ajouter un inter seul. Dans la logique Legrand si tu ajoute un inter, en fin de dialogue ça te demande ce que tu veux commander, sans quoi ça bloque et il n’y a plus qu’à forcer le redémarrage de l’appli et recommencer... Je n’avais pas de prise Legrand sous la main, mais au bout d’un moment j’ai fini par penser à appairer l’ampoule. Et la je vois enfin l’inter livré et mon inter de volet roulant qui ne peut rien commander, c’est le même mais avec un firmware différent.

Mais souvenons nous que nous somme là à jouer avec ce bazar dans le seul but de mettre à jour le firmware de ces putains d’inter qui au delà de couter un rein ne fonctionnent (mal) que sur le canal 11. Hélas il n’y arien pour faire cette mise à jour, mon inter de VR apparait en 42 dans l’appli et en 002a dans z2m, donc identique l’un étant en hexa. D’après ce que j’ai pu lire, la mise à jour se fera, un jour, mais on ne peut pas la forcer. Il faut juste laisser branché, en espérant que mon inter qui n’est pas connecté à un appareil se mette à jour tout seul…

Donc je laisse branché, la suite pour bientôt…

EDIT un peu plus tard :

  • L’inter (0 677 73N) est passé de 50 à 70
  • L’inter VR (0 777 48LA) n’a pas bougé…
  • Je testerais si on peut l’appairer hors du canal 11 mais je commence à douter…

EDIT le lendemain :

  • L’inter s’appaire bien sur un autre canal après sa mise à jour. Testé en ZHA sur 15, mais ZHA ne le supporte pas et rien ne bouge, aucun event.
  • L’inter VR ne s’est toujours pas mis à jour. Un peu comme s’il lui fallait une charge...

EDIT le lendemain soir :

  • L’inter VR est bien passé de 42 à 70, mon ZHA qui est sur le canal 15 le voit mais n’en fait rien. Quand à Z2M il n’en veut plus ! Pire ça me fait planter Z2M…

EDIT le sur lendemain midi :

  • L’inter VR qui ne veut toujours pas de ZHA ou Z2M s’est appairé correctement sur deconz en canal 15, il retourne dans les event les valeurs suivantes :

Montée : 1002 / Montée puis relâché : 1002/3002
Descente : 2002 / Descente puis relâché : 2002/3003
Stop (Les deux en même temps) : 3003

Ce comportement est identique à ce qu’il était sous Z2M et contrairement à d'autres télécommandes (le on/off Ikea (E1743 par exemple) il manque le fait qu’un second appui bref provoque un stop. Il faut donc bien appuyer au milieu pour faire un « stop » et ce n’est pas toujours pris en compte (problème physique).

Qu’il ne soit pas supporté sur ZHA est un fait, il faudrait développer un quirk et ça me dépasse. Je ne sais pas pourquoi il ne veut plus s’appairer sur Z2M, mais c’est peut être lié à mon installation, ma clé, que sais-je...

Il y a des chances que l’aventure Legrand va prendre fin et je que je retourne fissa ce Kit à Amazon !

Homekit

A signaler toutefois que cette passerelle est Homekit. Ce qui veut dire que ses équipements remontent dans Home Assistant. Mais ne rêvez pas trop, si l’ampoule remonte bien, et certainement tous les actionneurs connectés (prises, modules DIN), pas les inter En fait si, il faut juste attendre un peu. Néanmoins tout ne semble pas remonter, uniquement une action par bouton ! Mais j’avais déjà remarqué ça avec les télécommandes Tuya qui ne remontent pas via une passerelle Tuya Homekit. Il y a une forme de logique, Homekit sert à commander un équipement, comme une télécommande, hors on ne commande pas une télécommande…

Par contre ça veut dire que les équipements reconnus par Legrand vont remonter dans Homekit, ce qui peut être une solution de contrôle facile pour des produit pas reconnus par HA (Profalux, Bubendorf, Aldes, etc…).

La suite

Je vous propose de poursuivre ici et que chacun y apporte ses retours.

Sources

  • https://developer.legrand.com/production-firmware-download/

Home Assistant & Mi Boxer

J'avais acheté cette télécommande Mi Boxer il y a quelques mois afin de gérer les éclairages de mon séjour, en me disant que les curseurs seraient plus pratiques que mon Opple avec ses 6 boutons actuelle. Hélas elle n'était reconnue nulle part et avait terminé sa course dans le tiroir aux oubliettes du Zigbee...

C'était sans compter sur la ténacité de quelques amateurs de reverse engineering sur lesquels je suis tombé il y a quelques semaines et qui on fait un travail formidable qui a aboutit à une extension pour Zigbee2MQTT, ce qui rend cette télécommande enfin utilisable, tout au moins partiellement pour l'instant. Mais l'essentiel est là !

Ce qui fonctionne :

  • 7 boutons avec ON et OFF (deux actions et non un toggle). Celui du bas à droite n'est pas actif et je vous déconseille de l'utiliser...
  • 1 bouton avec ON et OFF (en haut)
  • 1 bouton W (si on veut bricoler...)
  • La barre de réglage de la luminosité
  • La remontée de l'état de la batterie

Ce qui ne fonctionne pas (pour l'instant) :

  • La barre de réglage des couleurs
  • La barre de réglage de la température du blanc
  • Les touches RGB
  • Les touches de temporisation (en bas à droite)

Une fois la télécommande reconnue sous Z2M on peut commencer à créer des actions. On remarque tout de suite que l'affaire va manquer de sensor: et que certains ne fonctionnent pas. Pas de panique, il y a une solution comme je vais vous le démonter avec l'automation: qui suit. 

J'ai fait un mélange de choose: / conditions: / trigger.id . C'est un peu long, mais je la colle en entier ce qui vous évitera une fastidieuse saisie. Il faudra tout de même y coller vous id: et entity: ! Ah j'allais oublier, il faut aussi ajouter un petit input_select: ... Voir plus bas EDIT du 11/01/2024 !

J'ai tenté de faire ça avec ControllerX que j'adore et qui me sert pour toutes mes télécommandes, mais pour l'instant c'est un échec !

alias: GUI - Mi Boxer
description: ""
trigger:
  - platform: state
    entity_id:
      - sensor.mi_boxeur_brightness
    id: bright
  - platform: device
    domain: mqtt
    device_id: 86c1403c24491ce021ac3ee081a86308
    type: button_short_press
    subtype: button_group_1_on
    discovery_id: 0x003c84fffec29c71_zone_1_button_on
    id: 1on
  - platform: device
    domain: mqtt
    device_id: 86c1403c24491ce021ac3ee081a86308
    type: button_short_press
    subtype: button_group_1_off
    discovery_id: 0x003c84fffec29c71_zone_1_button_off
    id: 1off
  - platform: device
    domain: mqtt
    device_id: 86c1403c24491ce021ac3ee081a86308
    type: button_short_press
    subtype: button_group_2_on
    discovery_id: 0x003c84fffec29c71_zone_2_button_on
    id: 2on
  - platform: device
    domain: mqtt
    device_id: 86c1403c24491ce021ac3ee081a86308
    type: button_short_press
    subtype: button_group_2_off
    discovery_id: 0x003c84fffec29c71_zone_2_button_off
    id: 2off
  - platform: device
    domain: mqtt
    device_id: 86c1403c24491ce021ac3ee081a86308
    type: button_short_press
    subtype: button_group_3_on
    discovery_id: 0x003c84fffec29c71_zone_3_button_on
    id: 3on
  - platform: device
    domain: mqtt
    device_id: 86c1403c24491ce021ac3ee081a86308
    type: button_short_press
    subtype: button_group_3_off
    discovery_id: 0x003c84fffec29c71_zone_3_button_off
    id: 3off
  - platform: device
    domain: mqtt
    device_id: 86c1403c24491ce021ac3ee081a86308
    type: button_short_press
    subtype: button_group_4_on
    discovery_id: 0x003c84fffec29c71_zone_4_button_on
    id: 4on
  - platform: device
    domain: mqtt
    device_id: 86c1403c24491ce021ac3ee081a86308
    type: button_short_press
    subtype: button_group_4_off
    discovery_id: 0x003c84fffec29c71_zone_4_button_off
    id: 4off
  - platform: device
    domain: mqtt
    device_id: 86c1403c24491ce021ac3ee081a86308
    type: button_short_press
    subtype: button_group_5_on
    discovery_id: 0x003c84fffec29c71_zone_5_button_on
    id: 5on
  - platform: device
    domain: mqtt
    device_id: 86c1403c24491ce021ac3ee081a86308
    type: button_short_press
    subtype: button_group_5_off
    discovery_id: 0x003c84fffec29c71_zone_5_button_off
    id: 5off
  - platform: device
    domain: mqtt
    device_id: 86c1403c24491ce021ac3ee081a86308
    type: button_short_press
    subtype: button_group_6_on
    discovery_id: 0x003c84fffec29c71_zone_6_button_on
    id: 6on
  - platform: device
    domain: mqtt
    device_id: 86c1403c24491ce021ac3ee081a86308
    type: button_short_press
    subtype: button_group_6_off
    discovery_id: 0x003c84fffec29c71_zone_6_button_off
    id: 6off
  - platform: device
    domain: mqtt
    device_id: 86c1403c24491ce021ac3ee081a86308
    type: button_short_press
    subtype: button_group_7_on
    discovery_id: 0x003c84fffec29c71_zone_7_button_on
    id: 7on
  - platform: device
    domain: mqtt
    device_id: 86c1403c24491ce021ac3ee081a86308
    type: button_short_press
    subtype: button_group_7_off
    discovery_id: 0x003c84fffec29c71_zone_7_button_off
    id: 7off
  - platform: device
    domain: mqtt
    device_id: 86c1403c24491ce021ac3ee081a86308
    type: button_short_press
    subtype: button_group_8_on
    discovery_id: 0x003c84fffec29c71_zone_8_button_on
    id: 8on
  - platform: device
    domain: mqtt
    device_id: 86c1403c24491ce021ac3ee081a86308
    type: button_short_press
    subtype: button_group_8_off
    discovery_id: 0x003c84fffec29c71_zone_8_button_off
    id: 8off
    
condition: []
action:
  - choose:
      - conditions: "{{ trigger.id in ['1on'] }}"
        sequence:
          - service: light.turn_on
            data: {}
            target:
              entity_id: light.shellydimmer_f3d426
          - service: input_select.select_option
            data:
              option: "1"
            target:
              entity_id: input_select.mi_boxer_select
      - conditions: "{{ trigger.id in ['1off'] }}"
        sequence:
          - service: light.turn_off
            data: {}
            target:
              entity_id: light.shellydimmer_f3d426

      - conditions: "{{ trigger.id in ['2on'] }}"
        sequence:
          - service: light.turn_on
            data: {}
            target:
              entity_id: light.shellydimmer_d3e57c
          - service: input_select.select_option
            data:
              option: "2"
            target:
              entity_id: input_select.mi_boxer_select
      - conditions: "{{ trigger.id in ['2off'] }}"
        sequence:
          - service: light.turn_off
            data: {}
            target:
              entity_id: light.shellydimmer_d3e57c

      - conditions: "{{ trigger.id in ['3on'] }}"
        sequence:
          - service: light.turn_on
            data: {}
            target:
              entity_id: light.ikea_e27_tv
          - service: input_select.select_option
            data:
              option: "3"
            target:
              entity_id: input_select.mi_boxer_select
      - conditions: "{{ trigger.id in ['3off'] }}"
        sequence:
          - service: light.turn_off
            data: {}
            target:
              entity_id: light.ikea_e27_tv

      - conditions: "{{ trigger.id in ['4on'] }}"
        sequence:
          - service: light.turn_on
            data: {}
            target:
              entity_id: light.lidl_led_stand
          - service: input_select.select_option
            data:
              option: "4"
            target:
              entity_id: input_select.mi_boxer_select
      - conditions: "{{ trigger.id in ['4off'] }}"
        sequence:
          - service: light.turn_off
            data: {}
            target:
              entity_id: light.lidl_led_stand

      - conditions: "{{ trigger.id in ['5on'] }}"
        sequence:
          - service: light.turn_on
            data: {}
            target:
              entity_id: light.dimmable_sm309
          - service: input_select.select_option
            data:
              option: "5"
            target:
              entity_id: input_select.mi_boxer_select
      - conditions: "{{ trigger.id in ['5off'] }}"
        sequence:
          - service: light.turn_off
            data: {}
            target:
              entity_id: light.dimmable_sm309

      - conditions: "{{ trigger.id in ['6on'] }}"
        sequence:
          - service: light.turn_on
            data: {}
            target:
              entity_id: light.shelly_bulb_1
          - service: input_select.select_option
            data:
              option: "6"
            target:
              entity_id: input_select.mi_boxer_select
      - conditions: "{{ trigger.id in ['6off'] }}"
        sequence:
          - service: light.turn_off
            data: {}
            target:
              entity_id: light.shelly_bulb_1

      - conditions: "{{ trigger.id in ['7on'] }}"
        sequence:
          - service: light.turn_on
            data: {}
            target:
              entity_id: light.led_strip_1
          - service: input_select.select_option
            data:
              option: "7"
            target:
              entity_id: input_select.mi_boxer_select
      - conditions: "{{ trigger.id in ['7off'] }}"
        sequence:
          - service: light.turn_off
            data: {}
            target:
              entity_id: light.led_strip_1

      - conditions: "{{ trigger.id in ['8on'] }}"
        sequence:
          - service: light.turn_on
            data: {}
            target:
              entity_id: 
                - light.shellydimmer_f3d426
                - light.shellydimmer_d3e57c
                - light.ikea_e27_tv
                - light.dimmable_sm309
                - light.shelly_bulb_1
                - light.lidl_led_stand
                - light.plug_tz_10_switch
                - light.led_strip_1
          - service: input_select.select_option
            data:
              option: "8"
            target:
              entity_id: input_select.mi_boxer_select
      - conditions: "{{ trigger.id in ['8off'] }}"
        sequence:
          - service: light.turn_off
            data: {}
            target:
              entity_id: 
                - light.shellydimmer_f3d426
                - light.shellydimmer_d3e57c
                - light.ikea_e27_tv
                - light.dimmable_sm309
                - light.shelly_bulb_1
                - light.lidl_led_stand
                - light.plug_tz_10_switch
                - light.led_strip_1
              
      - conditions: >-
          {{ is_state('input_select.mi_boxer_select', '1') and trigger.id in ['bright'] }}
        sequence:
          - service: light.turn_on
            data:
              brightness_pct: "{{ trigger.to_state.state }}"
              transition: 0.2
            target:
              entity_id: light.shellydimmer_f3d426
            enabled: true

      - conditions: >-
          {{ is_state('input_select.mi_boxer_select', '2') and trigger.id in ['bright'] }}
        sequence:
          - service: light.turn_on
            data:
              brightness_pct: "{{ trigger.to_state.state }}"
              transition: 0.2
            target:
              device_id: 1ff4112785e14b8b8cba18d45fec3b11
            enabled: true

      - conditions: >-
          {{ is_state('input_select.mi_boxer_select', '3') and trigger.id in ['bright'] }}
        sequence:
          - service: light.turn_on
            data:
              brightness_pct: "{{ trigger.to_state.state }}"
              transition: 0.2
            target:
              entity_id: light.ikea_e27_tv
            enabled: true

      - conditions: >-
          {{ is_state('input_select.mi_boxer_select', '4') and trigger.id in ['bright'] }}
        sequence:
          - service: light.turn_on
            data:
              brightness_pct: "{{ trigger.to_state.state }}"
              transition: 0.2
            target:
              entity_id: light.lidl_led_stand
            enabled: true

      - conditions: >-
          {{ is_state('input_select.mi_boxer_select', '5') and trigger.id in ['bright'] }}
        sequence:
          - service: light.turn_on
            data:
              brightness_pct: "{{ trigger.to_state.state }}"
              transition: 0.2
            target:
              entity_id: light.dimmable_sm309
            enabled: true

      - conditions: >-
          {{ is_state('input_select.mi_boxer_select', '6') and trigger.id in ['bright'] }}
        sequence:
          - service: light.turn_on
            data:
              brightness_pct: "{{ trigger.to_state.state }}"
              transition: 0.2
            target:
              entity_id: light.shelly_bulb_1
            enabled: true

      - conditions: >-
          {{ is_state('input_select.mi_boxer_select', '7') and trigger.id in ['bright'] }}
        sequence:
          - service: light.turn_on
            data:
              brightness_pct: "{{ trigger.to_state.state }}"
              transition: 0.2
            target:
              entity_id: light.led_strip_1
            enabled: true
mode: restart

EDIT 11/01/2024

Avec la dernière mise à jour Zigbee2MQTT (1.35.1-1) il n’y a plus besoin de l’extension. Par contre ce que j’avais fait sur la base de ce qui est proposé ici ne fonctionne plus (bien que toujours dans la doc).

J’ai donc biaisé en faisant du mqtt direct :

Pour la détection (trigger:) des boutons (à dupliquer) :

- platform: mqtt
    topic: zigbee2mqtt/Mi Boxer
    payload: ('on', 101)
    value_template: "{{ value_json.action , value_json.action_group }}"
    id: 1on
  - platform: mqtt
    topic: zigbee2mqtt/Mi Boxer
    payload: ('off', 101)
    value_template: "{{ value_json.action , value_json.action_group }}"
    id: 1off

Et pour la luminosité (il me reste à trouver comment ne prendre en compte que la charge action_level) :

- platform: mqtt
    topic: zigbee2mqtt/Mi Boxer
    id: bright

Ensuite on modifie dans le chose: coté action (à dupliquer bien entendu :

      - conditions:
          - condition: template
            value_template: >-
              {{ is_state('input_select.mi_boxer_select', '2') and trigger.id in ['bright'] }}
        sequence:
          - service: light.turn_on
            data_template:
              entity_id: light.shellydimmer_d3e57c
              brightness_pct: "{{ trigger.payload_json.action_level }}"

EDIT 11/01/2024

Le problème avec la solution de mon EDIT précédent est que le trigger sur la charge MQTT globale génère trop de bruit. On va donc faire deux sensor: basés sur MQTT afin d'isoler la valeur de la luminosité (merci Mathieu) ainsi que le groupe (bouton) correspondant à la light: active, ce qui va nous permettre d'éliminer l'input_select: dans le filtrage à venir :

mqtt:
  sensor:
    - name: "Mi Boxer Bright"
      unique_id: "mi_boxer_bright"
      state_topic: "zigbee2mqtt/Mi Boxer"
      value_template: "{{ value_json.action_level |int }}"

    - name: "Mi Boxxer Group"
      unique_id: "mi_boxer_group"
      state_topic: "zigbee2mqtt/Mi Boxer"
      value_template: "{{ value_json.action_group |int }}"

En trigger: on utilisera l'action : action_brightness_move_to_level qui remonte dans HA :

trigger:
  - platform: device
    domain: mqtt
    device_id: 86c1403c24491ce021ac3ee081a86308
    type: action
    subtype: brightness_move_to_level
    discovery_id: 0x003c84fffec29c71 action_brightness_move_to_level
    id: bright

Et on complète notre action déclenchée par l'id: bright et filtrée sur le sensor: correspondant au bon bouton, et j'ai ajouté le light: actif afin de ne pas risquer une fausse manœuvre :

      - conditions:
          - condition: template
            value_template: >-
              {{ is_state('sensor.mi_boxer_group', '101') and trigger.id in ['bright'] and is_state('light.shellydimmer_f3d426', 'on') }}
        sequence:
          - service: light.turn_on
            data_template:
              entity_id: light.shellydimmer_f3d426
              brightness_pct: "{{ states('sensor.mi_boxer_bright') | int}}"

Il ne reste plus qu'à attendre que Z2M remonte les informations liées à la température du blanc et la roue chromatique et on pourra les traiter avec la même méthode.

 
 

 

 

Home Assistant & Arrosage

Je n'ai pas vraiment la main verte et et mon jardin ressemble souvent à un no man's land, mais au printemps dernier une amie m'a convaincu de créer un carré d'herbes aromatiques, l'idée à fait son chemin et au centre on a même planté des plants de tomates qui produisent bien cet été ! Bon, vous imaginez bien que je ne vais pas ici vous conter ma vie privée mais plutôt la part domotique de cette réalisation !

En Provence, si on veut un peu de verdure et espérer manger ses propres tomates, il n'y a pas de secret, il faut arroser ! J'ai donc commencé par disposer un tuyau poreux sur mon carré. Ensuite j'ai acheté un robinet Zigbee et préparé un petit scheduler qui me permet facilement d'activer ou pas la plage journalière d'arrosage. J'ai fait quelque chose de simple en m'inspirant de ce que j'avais fait pour mon chauffe eau. Je publie ici le code suite à quelques demandes, même si ça n'a pas une grande valeur ajoutée.

Pour l'instant ça ne prends pas en compte les valeurs remontés sur les capteurs de plantes car je n'en suis pas satisfait.

L'offre en matière de capteurs de plantes n'est pas énorme :

  • Le capteur Xiaomi (ou ses copies) qui fonctionnent en Bluetooth et que l'on trouve sur Amazon ou Ali Express : C'est ce qui fonctionne le "mieux", mais cela nécessite un proxy BLE à l'extérieur que l'on peut facilement se bricoler avec un ESP sous ESPHome.
  • Le capteur Rehent en Zigbee que j'ai acheté chez Domadoo : Et là c'est la déconvenue. Il est un peu encombrant mais ne pose pas de soucis particulier pour l'appairer en ZHA ou Z2M (ou sur une passerelle Tuya), sauf que si ce capteur remonte parfaitement la température du sol, l'humidité du sol reste invariablement entre 75% et 85% (voir les sources au bas de cet article). Et bien sur chez Domadoo on est pas chez Amazon, le client a tort et l'éventuel retour est à votre charge. Bref capteur et fournisseur à éviter ! Il semblerait qu'autres séries de ce capteur que l'on trouve chez AliExpress fonctionnent, mais là il faudra aussi oublier le retour...

J'utilise une vanne Zigbee Woox qui alimente le tuyaux poreux (que je devrais remplacer par un un goute à goute). Pour avoir un réseau Zigbee fiable à l'extérieur, j'ai installé sous la toiture de la terrasse des prises Zigbee dont le relais est HS mais qui continuent à remplir parfaitement leur rôle de routeur Zigbee.

Tout cela reste très expérimental... Coté intégration j'utilise Home Assistant Plant et la carte qui va avec.

Automation

Une automation de schedule simple et visuelle :

input_datetime:
  watering_start:
    has_date: false
    has_time: true
  watering_stop:
    has_date: false
    has_time: true

input_boolean:
  watering_day_monday:
    name: "WATERING : Lundi"
    icon: mdi:toggle-switch
  watering_day_tuesday:
    name: "WATERING : Mardi"
    icon: mdi:toggle-switch
  watering_day_wednesday:
    name: "WATERING : Mercredi"
    icon: mdi:toggle-switch
  watering_day_thursday:
    name: "WATERING : Jeudi"
    icon: mdi:toggle-switch
  watering_day_friday:
    name: "WATERING : Vendredi"
    icon: mdi:toggle-switch
  watering_day_saturday:
    name: "WATERING : Samedi"
    icon: mdi:toggle-switch
  watering_day_sunday:
    name: "WATERING : Dimanche"
    icon: mdi:toggle-switch

automation:

- id: 'xx8d0e1-fcb6-4412-abvxx-99c4d37be5xx'
  alias: 'WATERING ON'
  trigger:
  - platform: template
    value_template: '{{ states.sensor.time.state == states.input_datetime.watering_start.state[0:5] }}'
  condition:
    condition: or
    conditions:
      - '{{ (now().strftime("%a") == "Mon") and is_state("input_boolean.watering_day_monday", "on") }}'
      - '{{ (now().strftime("%a") == "Tue") and is_state("input_boolean.watering_day_tuesday", "on") }}'
      - '{{ (now().strftime("%a") == "Wed") and is_state("input_boolean.watering_day_wednesday", "on") }}'
      - '{{ (now().strftime("%a") == "Thu") and is_state("input_boolean.watering_day_thursday", "on") }}'
      - '{{ (now().strftime("%a") == "Fri") and is_state("input_boolean.watering_day_friday", "on") }}'
      - '{{ (now().strftime("%a") == "Sat") and is_state("input_boolean.watering_day_saturday", "on") }}'
      - '{{ (now().strftime("%a") == "Sun") and is_state("input_boolean.watering_day_sunday", "on")}}'
  action:
  - service: switch.turn_on
    entity_id: switch.vanne_woox_switch
  - service: notify.slack_hass_canaletto
    data:
      message: "{{now().strftime('%d/%m/%Y, %H:%M')}} > WATERING | START | Soil : {{ states.sensor.soil_01_soil_moisture.state }}%" 


- id: 'zz9csdfsef-76dd-4fdd-9dzz-40bfsdq158zz'
  alias: 'WATERING OFF'
  trigger:
  - platform: template
    value_template: '{{ states.sensor.time.state == states.input_datetime.watering_stop.state[0:5] }}'
  action:
  - service: switch.turn_off
    entity_id: switch.vanne_woox_switch
  - service: notify.slack_hass_canaletto
    data:
      message: "{{now().strftime('%d/%m/%Y, %H:%M')}} > WATERING | STOP | Soil : {{ states.sensor.soil_01_soil_moisture.state }}%"   

La carte Lovelace :

type: vertical-stack
cards:
  - type: entities
    entities:
      - entities:
          - entity: automation.watering_on
            name: false
          - entity: sensor.energy_total_yearly_1pm_watering
            name: false
            unit: kWh
            format: precision2
          - entity: sensor.soil_01_soil_moisture
            name: false
        entity: switch.vanne_woox_switch
        name: Arrosage
        icon: mdi:watering-can-outline
        show_state: false
        state_color: true
        type: custom:multiple-entity-row
  - type: horizontal-stack
    cards:
      - type: custom:button-card
        color_type: card
        entity: input_boolean.watering_day_monday
        name: Lundi
        show_last_changed: false
        show_state: false
        tap_action:
          action: toggle
        state:
          - value: 'on'
            color: green
            icon: mdi:water-boiler
          - value: 'off'
            color: grey
            icon: mdi:water-boiler-off
        styles:
          card:
            - height: 60px
            - border-radius: 5px
            - font-size: 12px
      - type: custom:button-card
        color_type: card
        entity: input_boolean.watering_day_tuesday
        name: Mardi
        show_last_changed: false
        show_state: false
        tap_action:
          action: toggle
        state:
          - value: 'on'
            color: green
            icon: mdi:water-boiler
          - value: 'off'
            color: grey
            icon: mdi:water-boiler-off
        styles:
          card:
            - height: 60px
            - border-radius: 5px
            - font-size: 12px
      - type: custom:button-card
        color_type: card
        entity: input_boolean.watering_day_wednesday
        name: Mercredi
        show_last_changed: false
        show_state: false
        tap_action:
          action: toggle
        state:
          - value: 'on'
            color: green
            icon: mdi:water-boiler
          - value: 'off'
            color: grey
            icon: mdi:water-boiler-off
        styles:
          card:
            - height: 60px
            - border-radius: 5px
            - font-size: 12px
      - type: custom:button-card
        color_type: card
        entity: input_boolean.watering_day_thursday
        name: Jeudi
        show_last_changed: false
        show_state: false
        tap_action:
          action: toggle
        state:
          - value: 'on'
            color: green
            icon: mdi:water-boiler
          - value: 'off'
            color: grey
            icon: mdi:water-boiler-off
        styles:
          card:
            - height: 60px
            - border-radius: 5px
            - font-size: 12px
      - type: custom:button-card
        color_type: card
        entity: input_boolean.watering_day_friday
        name: Vendredi
        show_last_changed: false
        show_state: false
        tap_action:
          action: toggle
        state:
          - value: 'on'
            color: green
            icon: mdi:water-boiler
          - value: 'off'
            color: grey
            icon: mdi:water-boiler-off
        styles:
          card:
            - height: 60px
            - border-radius: 5px
            - font-size: 12px
      - type: custom:button-card
        color_type: card
        entity: input_boolean.watering_day_saturday
        name: Samedi
        show_last_changed: false
        show_state: false
        tap_action:
          action: toggle
        state:
          - value: 'on'
            color: green
            icon: mdi:water-boiler
          - value: 'off'
            color: grey
            icon: mdi:water-boiler-off
        styles:
          card:
            - height: 60px
            - border-radius: 5px
            - font-size: 12px
      - type: custom:button-card
        color_type: card
        entity: input_boolean.watering_day_sunday
        name: Dimanche
        show_last_changed: false
        show_state: false
        tap_action:
          action: toggle
        state:
          - value: 'on'
            color: green
            icon: mdi:water-boiler
          - value: 'off'
            color: grey
            icon: mdi:water-boiler-off
        styles:
          card:
            - height: 60px
            - border-radius: 5px
            - font-size: 12px
  - type: conditional
    conditions:
      - entity: automation.watering_on
        state: 'on'
    card:
      type: custom:vertical-stack-in-card
      cards:
        - type: horizontal-stack
          cards:
            - type: markdown
              content: '#### <center> Heure de début'
            - type: markdown
              content: '#### <center> Arrosage'
            - type: markdown
              content: '#### <center> Heure de Fin'
        - type: horizontal-stack
          cards:
            - entity: input_datetime.watering_start
              type: custom:time-picker-card
              name: Début
              layout:
                align_controls: center
                embedded: true
              hide:
                name: true
                icon: true
            - type: glance
              show_state: true
              show_name: false
              entities:
                - switch.vanne_woox_switch
            - entity: input_datetime.watering_stop
              type: custom:time-picker-card
              layout:
                align_controls: center
                embedded: true
              hide:
                name: true
                icon: true
  - color_thresholds:
      - color: '#039BE5'
        value: 0
      - color: '#0da035'
        value: 19
      - color: '#e0b400'
        value: 25
      - color: '#e45e65'
        value: 2400
    color_thresholds_transition: hard
    entities:
      - entity: sensor.plant_01_moisture
        name: Humidité du sol
      - entity: sensor.plant_01_temperature
        name: Températire du sol
      - color: rgba(0,0,255,1)
        entity: binary_sensor.night_reworked
        name: Nuit
        show_line: false
        y_axis: secondary
    group: false
    hour24: true
    hours_to_show: 24
    line_width: 2
    name: Humidité et température du sol
    points_per_hour: 4
    show:
      extrema: true
      fill: fade
      icon: true
      labels: false
      name: true
      state: true
    state_map:
      - label: Day
        value: 'off'
      - label: Night
        value: 'on'
    type: custom:mini-graph-card
  - type: custom:flower-card
    entity: plant.jardin
    show_bars:
      - illuminance
      - humidity
      - moisture
      - conductivity
      - temperature
      - dli
    battery_sensor: sensor.demo_battery

Souces

Capteur Rehent

 

Home Assistant & Plug Security

On utilise souvent des prises commandées uniquement pour mesurer la consommation de certains appareils. Ces prises sont toujours en position ON. Ces prises, si elles ne sont pas de trop mauvaise qualité un mécanisme de sécurité intégré qui les passent OFF en cas de surtension ou de surcharge. Et dans la pratique ça arrive parfois et on constate plus tard que le lave linge ou le lave vaisselle s'est arrêté, ou pire dans le cas d'un congélateur.

Pour palier à cet inconvénient on va créer une automation qui va réarmer la prise après quelques minutes en OFF. Jusque là c'est simple, mais il se peut également que le problème soit plus grave et qu'il ne faille pas forcer indéfiniment ce réarmement automatique. Etant donné qu'on ne dispose généralement pas d'information sur la cause de ce passage en sécurité on va considérer qu'au bout de "n" tentatives sur un temps donné on ne réarme plus. Pour ça on va utiliser des compteurs (à créer avec un minimum à 0 et un maximum à 10) et on fera un reset de ceux-ci toutes les nuits...

J'ai fixé ici arbitrairement à 5 le nombre de réarmements possibles.

Attention : Je vous explique ici comment j'ai fait, mais un risque existe toujours et la mise en œuvre de cette solution est à vos risques (et périls). Je me dégage ainsi de toute responsabilité.

On va faire ça avec une seule automation que j'ai voulue la plus concise et qui servira également à notifier :

automation:
- id: '2bd0ertyyf-2687-45f98f-aed0-to-off'
  alias: "Notify Plug Off"
  description: "Notification mise en sécurité des prises"
  mode: single
  trigger:
    - platform: state
      entity_id: switch.bw_1
      to: "off"
      id: "Lave Vaisselle"
    - platform: state
      entity_id: switch.bw_2
      to: "off"
      id: "Lave Linge"
    - platform: state
      entity_id: switch.bw_3
      to: "off"
      id: "Seche Linge"
    - platform: state
      entity_id: switch.bw_4
      to: "off"
      id: "Congelateur"
    - platform: time
      at: "00:05:00"
      id: "Reset"
  condition: []
  action:
  - delay:
      hours: 0
      minutes: 5
      seconds: 0
      milliseconds: 0  
  - choose:
      - conditions: "{{ trigger.id in ['Lave Vaisselle'] and states('counter.plug_bw_1') | int < 5 }}"
        sequence:
          - service: switch.turn_on
            target:
              entity_id: switch.bw_1
          - service: counter.increment
            target:
              entity_id: counter.plug_bw_1
          - service: notify.slack_hass_mondon
            data:
              message: "{{now().strftime('%d/%m/%Y, %H:%M:%S')}} > Réarmement n°{{ states('counter.plug_bw_1')}} du {{ trigger.id }}"               

      - conditions: "{{ trigger.id in ['Lave Linge'] and states('counter.plug_bw_2') | int < 5 }}"
        sequence:
          - service: switch.turn_on
            target:
              entity_id: switch.bw_2
          - service: counter.increment
            target:
              entity_id: counter.plug_bw_2
          - service: notify.slack_hass_mondon
            data:
              message: "{{now().strftime('%d/%m/%Y, %H:%M:%S')}} > Réarmement n°{{ states('counter.plug_bw_2')}} du {{ trigger.id }}" 

      - conditions: "{{ trigger.id in ['Seche Linge'] and states('counter.plug_bw_3') | int < 5 }}"
        sequence:
          - service: switch.turn_on
            target:
              entity_id: switch.bw_3
          - service: counter.increment
            target:
              entity_id: counter.plug_bw_3
          - service: notify.slack_hass_mondon
            data:
              message: "{{now().strftime('%d/%m/%Y, %H:%M:%S')}} > Réarmement n°{{ states('counter.plug_bw_3')}} du {{ trigger.id }}" 

      - conditions: "{{ trigger.id in ['Congelateur'] and states('counter.plug_bw_4') | int < 5 }}"
        sequence:
          - service: switch.turn_on
            target:
              entity_id: switch.bw_4
          - service: counter.increment
            target:
              entity_id: counter.plug_bw_3
          - service: notify.slack_hass_mondon
            data:
              message: "{{now().strftime('%d/%m/%Y, %H:%M:%S')}} > Réarmement n°{{ states('counter.plug_bw_4')}} du {{ trigger.id }}" 

      - conditions: 
          - condition: or
            conditions:
              - "{{ trigger.id in ['Lave Vaisselle'] and states('counter.plug_bw_1') | int >= 5 }}"
              - "{{ trigger.id in ['Lave Linge'] and states('counter.plug_bw_2') | int >= 5 }}"
              - "{{ trigger.id in ['Seche Linge'] and states('counter.plug_bw_3') | int >= 5 }}"
              - "{{ trigger.id in ['Congelateur'] and states('counter.plug_bw_4') | int >= 5 }}"
        sequence:
          - service: notify.slack_hass_mondon
            data:
              message: "{{now().strftime('%d/%m/%Y, %H:%M:%S')}} > Problème avec le {{ trigger.id }}. On ne réarme plus, une vérification s'impose." 

      - conditions: "{{ trigger.id in ['Reset'] }}"
        sequence:
          - service: counter.reset
            target:
              entity_id:
                - counter.plug_bw_1
                - counter.plug_bw_2
                - counter.plug_bw_3
                - counter.plug_bw_4

Home Assistant & Sirènes

J'ai déjà parlé ici du système d'alarme Alarmo pour Home Assistant et notamment des commandes possibles pour armer et désarmer le système. Aujourd'hui il s'agira des sirènes.

J'ai trois modèles

  • La plus basique est juste branchée sur une prise commandée Zigbee ondulée. Donc un switch: vu en tant que siren:.
  • Une sirène Heiman qui sous ZHA décroche régulièrement et que j'ai du appairer à ma seconde passerelle sous Z2M.
    • Sous ZHA elle était vue en tant que siren:.
    • Sous Z2M elle est vue en tant que rien du tout...
  • Une sirène SMaBit sous Z2M également vue en rien du tout...

Pour commander une sirène via ZHA HA propose :

    - service: siren.turn_on
      target:
        entity_id:
          - siren.heiman_sirene

Pour commander une sirène sous Z2M il faut lui envoyer le payload correspondant :

    - service: mqtt.publish
      data:
        topic: zigbee2mqtt/Sirène SMaBiT/set
        payload: >-
          {"warning": {"mode": "fire", "level": "very_high", "strobe_level": "low", "strobe": "false", "strobe_duty_cycle": "10", "duration": "360"}}

Un peu plus compliqué et moins facile à mémoriser, mais ça fonctionne.

Mon objectif a donc été de faire en sorte qu'une sirène Z2M soit vue par Home Assistant comme une sirène ZHA et ainsi pouvoir la commander par un siren.turn_on comme les autres... Et voici ce que ça donne :

mqtt:
  siren:
    - unique_id: heiman_sirene_1s
      name: Heiman Sirène 1s
      state_topic: "zigbee2mqtt/Heiman Sirène 1/set"
      command_topic: "zigbee2mqtt/Heiman Sirène 1/set"
      optimistic: false
      qos: 0
      retain: true
      state_value_template: "{{ value_json.warning['mode'] }}"
      command_template: '{"warning": {"duration": 2, "mode": "burglar", "level": "very_high", "strobe": true}}'
      command_off_template: '{"warning": {"duration": 2, "mode": "stop", "level": "very_high", "strobe": true}}'
      state_on: "burglar"
      state_off: "stop"

Problème, car il y en a un, la sirène Heiman ne retourne aucun état sous Z2M. Il y a beaucoup d'articles à ce sujet, et l'intégration ne semble pas vraiment terminée. Hors dans l'activation il y a une durée, le principe étant d'activer la sirène pour x secondes. Et donc comme elle ne retourne pas son état, son commutateur restera sur ON alors que le délais d'activation est terminé et la prochaine action n'aura aucun effet... De plus certaines sirènes proposent plusieurs fonctions et tonalités (les bips de délais d'armement et désarmement par exemple).

Donc contrairement à ZHA ou l'intégration siren: peut gérer tous les modes, chercher à gérer une sirène Z2M en tant que siren: n'a pas de sens... (hormis peut être de bricoler un template: qui en fonction de la durée d'activation repasserait le commutateur à off, on peut aussi le faire via une automation: mais là ça va alourdir la chose...).

Alternative

S'agissant d'envoyer un payload à une sirène Z2M, ce que j'ai trouvé de plus logique est un mqtt:/button: et il faut donc en faire deux :

mqtt:
  button:
    - unique_id: siren_heiman_1_warning
      name: "Sirène Heiman 1 : Waraning"
      command_topic: "zigbee2mqtt/Heiman Sirène 1/set"
      payload_press: '{"warning": {"duration": 2000, "mode": "burglar", "level": "very_high", "strobe": true}}'
      qos: 0
      retain: false
      entity_category: "config"
      device_class: "restart"

    - unique_id: siren_heiman_1_stopped
      name: "Sirène Heiman 1 : Stopped"
      command_topic: "zigbee2mqtt/Heiman Sirène 1/set"
      payload_press: '{"warning": {"duration": 2, "mode": "stop", "level": "very_high", "strobe": true}}'
      qos: 0
      retain: false
      entity_category: "config"
      device_class: "restart"   

Ou plusieurs pour gérer les différents mode de la SMaBit :

mqtt:
  button:
    - unique_id: siren_smabit_armed
      name: "Sirène SMaBit : Armed"
      command_topic: "zigbee2mqtt/Sirène SMaBiT/set"
      payload_press: '{"squawk": {"state": "system_is_armed", "level": "veryhigh", "strobe": "true"}}'
      qos: 0
      retain: false
      entity_category: "config"
      device_class: "restart"

    - unique_id: siren_smabit_disarmed
      name: "Sirène SMaBit : Disarmed"
      command_topic: "zigbee2mqtt/Sirène SMaBiT/set"
      payload_press: '{"squawk": {"state": "system_is_disarmed", "level": "veryhigh", "strobe": "true"}}'
      qos: 0
      retain: false
      entity_category: "config"
      device_class: "restart"

    - unique_id: siren_smabit_warning
      name: "Sirène SMaBit : Warning"
      command_topic: "zigbee2mqtt/Sirène SMaBiT/set"
      payload_press: '{"warning": {"mode": "fire", "level": "very_high", "strobe_level": "low", "strobe": "false", "strobe_duty_cycle": "10", "duration": "360"}}'
      qos: 0
      retain: false
      entity_category: "config"
      device_class: "restart"

    - unique_id: siren_smabit_stopped
      name: "Sirène SMaBit : Stopped"
      command_topic: "zigbee2mqtt/Sirène SMaBiT/set"
      payload_press: '{"warning": {"mode": "stop"}}'
      qos: 0
      retain: false
      entity_category: "config"
      device_class: "restart"

Vous l'aurez compris, il s'agit plus d'un exercice de style qu'autre chose. Mais ça m'aura permis de comprendre comment créer des devices MQTT non reconnus par le discovery:. Merci @Mathieu pour ta participation !

Sources

 

Sony mon amour !

Amour déçu comme on le verra plus loin ! Depuis très jeune j'ai toujours été un afficionado de la marque Sony. Et si d'aucune pourraient trouver cela déplacé, il est des domaines ou je suis fidèle ! Coté TV après avoir eu quelques Trinitrons cathodiques célèbres tel le Profeel, je me suis offert jadis le premier moniteur plasma pro de la marque, qui avait du me couter un an de salaire et que je me suis résolu récemment à le porter à la déchetterie, le pauvre il trainait dans le garage depuis bientôt 20 ans !

Je ne vais pas vous faire la liste des écrans Sony que j'ai eu successivement, ni leur cout car ça me déprimerait, mais juste vous parler des déboires de mon dernier TV. Il y a un an j'ai craqué pour le A80J, un Oled ! Un TV intelligent sous Google TV, même si d'intelligence il n'a que la pub et les traqueurs que cela induit !

Je considère Google TV / Android TV comme étant le meilleur choix car il me permet d'installer les application qui me sont utiles, en opposition aux écosystèmes fragmentés de la concurrence qui ne proposent que l'essentiel bien commercial ! C'est du business, on le sait et on l'accepte car ça nous apporte du confort.

Autres points que les pseudo journalistes testeurs oublient souvent, c'est la télécommande et l'implémentation du CEC. Celles de Sony m'ont toujours satisfait alors que je déteste certaines d'autres marques. Mais Sony est radin, et sur le A80J la télécommande n'est pas même rétroéclairée ! Qu'à cela ne tienne il suffit de commander sur Amazon celle du A90J qui elle est premium et rétro éclairée... Quant au CEC il a toujours été très bien chez Sony.

Je ne vais pas vous raconter ce que vaut cette TV, plusieurs sites l'ont déjà fait plus ou moins bien. Enfin, je parle de TV, mais je ne regarde même pas la télé et aucune antenne n'y est raccordée. Je rêve d'une version moniteur !

Domotique

Oh le gros mot ! Encore un client qui veut faire des choses louches ! Louches car je ne me plie pas à la domotique commerciale et forcément limitative (Amazon, Google, Apple, Tuya, etc...) mais que ma domotique est libre, Home Assistant.

Et pourquoi faire ? Pas grand chose, juste inclure ce TV dans me scénarios (scènes). Et on va faire simple !

  • Play / Pause : on éteint et on rallume progressivement les éclairages comme au cinéma.
  • On / Off : on mets sur pause la musique qui était diffusée.

Ce n'est pas sorcier et très simple à faire. Mais pour ca il faut pouvoir extraire les informations du TV. Ca tombe bien ce TV est reconnu sous Home Assistant par l'intégration Bravia ou HomeKit. Dès lors on dispose des information idoines et ça fonctionne très bien, il suffit d'agir en fonction de l'état remonté.

Mais alors il se plaint de quoi le râleur ? Et oui il y a un "mais" !

Consommation

Pour accéder à ces fonctions il faut que le contrôle à distance ou / et HomeKit soit activé. C'est d'ailleurs le cas par défaut. Et les ingés de chez Sony, dont je ne doute pas des prouesses en audio / vidéo s'avèrent des brèles en réseau ! Pour que ces fonctions soient accessibles ils laissent simplement la partie réseau allumée quand le téléviseur est en veille. Et comme leur carte réseau doit dater du siècle dernier (elle a du mal à accrocher le réseau et est limitée à du 10/100 en 2022 ou on est censés passer de la full 4K !), elle consomme en veille pas moins de 26/28 W alors que si ces fonctions sont désactivées la veille est à seulement 0.9 W.

Cela pose deux constats :

  • Il est inacceptable qu'un TV en veille consomme 27 W en 2022 (c-a-d + ou - 50 € / an).
  • Il est inacceptable que ces fonctionnalités soient activées par défaut et induisent cette surconsommation ! Et certainement contraire aux directives européennes en la matière. Il est en effet peu probable qu'un consommateur lambda ne pense à mesurer et désactiver ces fonctions.

En l'état il est donc inenvisageable d'utiliser ces fonctionnalités qui ajoutent un plus au téléviseur. Et il faut noter que tout pilotage par les applis standard, Chromecast, Alexa, etc pose le même problème...

Le pire étant que si on désactive ces fonctions, quand on allume le téléviseur il mets bien trop longtemps pour accrocher le réseau, que ce soit en Ethernet ou en WI-FI. Je sais c'est fait pour regarder la télé avec un râteau sur la toiture !

Alternative

Avant j'utilisait un LCD Sony bien plus bête et une NVidia Shield que je pilotait très bien sans que cela ne grève mon budget. Le Shield allumait le TV en CEC et tout était parfait. Je vais peut être en racheter un, encore que mon Shield de 2015 fonctionne encore très bien dans ma chambre. Un bel exemple de non obsolescence qui mérite d'être signalé !

Et les autres ?

Je ne sais pas comment ça se passe chez les autres constructeurs de TV car je ne suis pas client. On me remonte 1 à 2 W avec les options de pilotage activées chez Samsung ou Panasonic, mais je n'ai pas vérifié. Par contre j'ai un bel élevage de Sonos, et là non plus ce n'est pas très joli à voir : aucun progrès depuis le début, conso identique en veille sur les anciens Play 1 et 3 et les nouveaux One (gen 1 et 2), entre 3 et 4 W voire plus de 8 à 11 W sur un AMP ou 6 W pour une Beam !

Moralité

La domotique n'est pas vraiment écologique, elle crée un énorme talon de consommation de part son infrastructure (caméras, nvr, switches, micro modules et autres prise connectées). Elle apporte plus de confort qu’elle ne fait réaliser des économies (les économies c’est le bobard que racontent certains à leur compagne quand c’est elle qui tiens les cordons de la bourse, car, hélas, la domotique reste un truc de mec, comme le BBQ, n’en déplaise à Sandrine).

Un panneau solaire va devoir s'imposer à moi !

Sources

 

 

Home Assistant & Volets roulants, automatismes !

Dans un précédent article je vous avait parlé de la partie matérielle de mes volets roulants et de leur commande via des interrupteurs et des télécommandes. Mais avec une installation domotique ouverte, on peut faire bien mieux !

L'objectif ici sera pour chaque volet (ou groupe de volets) d'automatiser leur ouverture, position intermédiaire et fermeture en fonction de :

  • Le jour et la nuit
  • La température extérieure et intérieure et les contraintes météo (canicule, etc.)
  • La position du soleil
  • Les contraintes de vie (lever tardif, soirée, etc...)
  • Les contraintes de présence / absence plus ou moins longue (alarme et simulation de présence)
  • Le débrayage de l'automatisme afin de laisser en paix un invité ou les enfants en vacances avec leur propres horaires et mode de vie.

Vous allez me dire tout de suite que la tache est complexe et vous aurez raison, mais pas tant que ça car je vais m'appuyer sur le travail de Fabien qui a créé un superbe moteur pour gérer tout ça, moteur que chacun pourra adapter à ses propres besoin en lui fournissant des prérequis (inputs, binary, etc..) qui permettront de gérer les différents conditions de positionnement. Vous trouverez les détails sur son blog, mais l'installation est relativement aisée, on commence par créer les entités nécessaires, ensuite on ajoute les BluePrint's de configuration et on termine avec un peu de yaml pour la configuration des conditions.

Facile, mais ça prends un peu de temps. Et surtout commencez par mettre sur le papier le résultat que vous voulez obtenir. Dans cet article je vais vous parler de ce que j'ai mis autour de son travail, plus que de son travail. 

Avant de chercher à intégrer mes exemples, prenez le temps d'avoir une installation vraiment fonctionnelle avec les Blueprint's de Fabien.

De base et sans rien ajouter le moteur de Fabien va permettre d'ouvrir le volet au lever de soleil et de le fermer au coucher du soleil grâce à l'intégration sun.sun. Bon, pour faire ça on a pas besoin d'une usine, c'est pour ça que je vais vous montrer que son moteur permet bien d'autres choses.

Température extérieure et position du soleil

Voici un exemple des plus basic de ce que j'avais fait au départ, mais je vous conseille d'adapter la version de Fabien que j'ai moi même adoptée et qui permet d'aller plus loin, avec différentes sources et notamment un capteur de luminosité.

Exemple

J'utilise les Packages et je vais commencer par créer deux sensor: en fonction de ma localisation en m'appuyant sur sun.sun

sensor: 
  - platform: template
    sensors:
      sunelevation:
        friendly_name: "Elevation du soleil"
        value_template: "{{ state_attr('sun.sun', 'elevation') }}"
      sunazimuth:
        friendly_name: "Azimut du soleil"
        value_template: "{{ state_attr('sun.sun', 'azimuth') }}"

Ensuite je vais me servir de ce site pour trouver les bonnes valeurs et je vais créer 3 binary_sensor: avec les les valeurs basses et hautes d'azimut, ces binary passeront à ON quand le soleil tapera sur la façade concernée. Bien sur il faudra un peu tâtonner pour trouver les bonnes valeurs et les ajuster.

binary_sensor:
  - platform: threshold
    name: "Soleil : Ouest"
    upper: 170
    lower: 80
    entity_id: sensor.sunazimuth
  - platform: threshold
    name: "Soleil : Sud"
    upper: 270
    lower: 100
    entity_id: sensor.sunazimuth
  - platform: threshold
    name: "Soleil : Est"
    upper: 299
    lower: 260
    entity_id: sensor.sunazimuth

Et pour terminer je vais créer un dernier binary_sensor: pour déterminer les conditions météo. Il s'appuie sur les infos de l'intégration Météo France (ou avec un capteur de luminosité en s'appuyant sur l'exemple de Fabien) et dépend de seuils définis dans des input_number: qui pourront s'afficher dans Lovelace. (je n'ai pas pris en compte la température intérieure pour l'instant).

binary_sensor:
  - platform: template
    sensors:
      vr_sun_hot:
        device_class: heat
        delay_on: 
          seconds: 300
        delay_off:
          seconds: 300
        value_template: "{{states('sensor.avignon_temperature')|float(0) >= states('input_number.vr_sun_hot') |float(0)
                        and states('sensor.avignon_cloud_cover')|float(0) <= states('input_number.vr_cloud_cover')|float(0) }}" 
        friendly_name: "Alerte haute température"

input_number:
  vr_sun_hot:
    name: Seuil haute température
    min: "10"
    max: "40"
    step: "1"
    unit_of_measurement: "°"
    icon: mdi:sun-thermometer-outline
  vr_cloud_cover:
    name: Seuil couverture nuageuse
    min: "0"
    max: "100"
    step: "5"
    unit_of_measurement: "%"
    icon: mdi:cloud-lock-outline 

Et voici le travail :

Exploitation

Vous aurez remarqué que j'ai deux seuils. Il y aura donc deux conditions possibles dans le choose: de l'automation de positionnement qui exploite les Blueprint's de Fabien. On retrouve dans l'ordre :

  1. La ou les conditions (and), ici la température est hot et le soleil au sud.
  2. La séquence de services à lancer :
    1. Je positionne le volet dans un input_number: à partir d'un input_number: de préréglage.
    2. A des fin de debug je note la dernière condition utilisée et la position du volet dans un input_text: que je peux afficher dans Lovelace
        - conditions:
            - condition: state
              entity_id: binary_sensor.vr_sun_hot
              state: "on"
            - condition: state
              entity_id: binary_sensor.soleil_sud
              state: "on"
          sequence:
            - service: input_number.set_value
              target:
                entity_id: input_number.vr_cuisine_planned_position
              data:
                value: "{{ states('input_number.vr_global_position_sun_alert') }}"
            - service: input_text.set_value
              target:
                entity_id: input_text.vr_cuisine_condition
              data:
                value: "Condition : Ensoleillement excessif - {{ states('input_number.vr_global_position_sun_alert') }} %"

Attention : Dans un choose: l'ordre de priorité des différentes conditions est important. Il y a aussi une option par défaut si aucune des conditions n'est valide mais que l'automation est tout de même déclenchée. On placera donc en premier celles qui doivent prendre le dessus, par exemple la condition issue de l'activation de l'alarme sera en premier car il est évident que l'on se moque de position du soleil si on est en voyage et que la maison est fermée.

Cela n'empêchera éventuellement pas une solution de simulation de présence qui agirait sur les volets de fonctionner. Je suis en train de tester cette intégration, attention à bien valider avant de partir en vacances...

Contraintes de vie

Réveil

Ici c'est au petit bonheur de chacun. En ce qui me concerne je n'ai pas d'horaires réguliers et je suis un lève tard. J'ai donc créé un script qui se déroule quand je dis bonjour (ou bonne nuit) à Alexa ou que j'appuis simplement sur un bouton de télécommande. Ce script va entre autres choses faire un push, si je suis présent dans la maison, sur un input_button: que je vais utiliser ici pour entrouvrir le volet de ma chambre et de la baie du séjour (une baie vitrée coulissante s'ouvre très facilement si elle n'est pas protégée, je vais donc éviter d'ouvrir son volet quand je dors). On a donc deux input_button: :

input_button:
  lionel_up:
    name: Je me lève
    icon: mdi:human-greeting-variant
  lionel_down:
    name: Je me couche
    icon: mdi:bed

La condition correspondant au réveil (la position du volet est stockée dans un input_number: afin d'être facilement ajustée depuis l'interface)

        - conditions:
            - "{{ as_timestamp(states('input_button.lionel_up'))|timestamp_custom('%H:%M', true) == states('sensor.time')  }}"
          sequence:
            - service: input_number.set_value
              target:
                entity_id: input_number.vr_lionel_planned_position
              data:
                value: "{{ states('input_number.vr_global_position_reveil') }}"

Il faut bien sur ne pas oublier de déclarer input_button: dans le BluePrint correspondant au volet (en condition immédiate) et l'actionner dans le script ou l'interface :

  - service: input_button.press
    target:
      entity_id: input_button.lionel_up

Et pour ce volet je vais modifier l'action par défaut d'ouverture dans l'automation afin qu'il ne se passe rien avant 13 heures... mais également rien si le volet est déjà un peu ouvert par une condition fugitive (button.press).

            - conditions:
                - condition: numeric_state # On ouvre le volet si le soleil est au dessus de l'horizon
                  entity_id: sun.sun
                  attribute: elevation
                  above: 0
                - condition: time
                  after: "13:00:00"
                - condition: state
                  entity_id: cover.vr_baie
                  state: "closed"

Soirée

En soirée, surtout en été, je n'ai pas envie que les volets soient complètement fermés car c'est l'heure ou on ouvre les fenêtres pour faire entrer un air plus frais. Je vais donc définir un binary-sensor: correspondant à ma soirée (merci Fabien) :

binary_sensor:
  - platform: template
    sensors:
      vr_evening:
        value_template:  "{{ (state_attr('sun.sun', 'azimuth') | float(0.0)) > 180 and (state_attr('sun.sun', 'elevation') | float(0.0)) < 0 and ('12:00:00' < states('sensor.time')) }}"
        friendly_name: "Soirée"

J'aurais pu y ajouter un and supplémentaire afin de valider la saison en me basant sur l'intégration Season. Sauf que les saisons tout le monde sait que ça ne veut plus dire grand chose et qu'ici depuis le début du mois de mail il fait plus ou moins 30° en journée, je testerais donc un input_boolean: de plus pour valider cette condition (que j'aurais également pu valider dans le binary-sensor:) :

        - conditions:
            - condition: state
              entity_id: binary_sensor.vr_evening
              state: "on"
            - condition: state
              entity_id: input_boolean.vr_evening
              state: "on"
          sequence:
            - service: input_number.set_value
              target:
                entity_id: input_number.vr_cuisine_planned_position
              data:
                value: "{{ states('input_number.vr_global_position_soir') }}"
            - service: input_text.set_value
              target:
                entity_id: input_text.vr_cuisine_condition
              data:
                value: "Condition : Soirée - {{ states('input_number.vr_global_position_soir') }} %"

On peut aussi faire la même chose avec d'autres conditions et sans binary_sensor: et tout mettre dans les conditions...

        - conditions:
            - condition: numeric_state
              entity_id: sun.sun
              attribute: azimuth
              above: 180
            - condition: numeric_state
              entity_id: sun.sun
              attribute: elevation
              below: 0
            - condition: time
              after: "18:00:00"            
            - condition: state
              entity_id: input_boolean.vr_evening
              state: "on"     

Présence / Absence et Alarme 

Pour ce chapitre c'est un peu plus compliqué. J'utilise en parallèle deux système. Ma centrale Visonic indépendante mais que je pilote dans Home Assistant et l'intégration Alarmo. Lors de mes test je me suis aperçu que tester uniquement l'état "armed" pouvait conduire à des surprises. Lors de l'armement et surtout le déclenchement d'une alarme (possiblement fausse) l'état de alarm_control_panel: passe par des phases successives peu simple à gérer, et ça peu conduire à une ouverture des volets non souhaitée.

Chez moi j'ai différentes possibilités pour armer ces deux systèmes (télécommande, code, tag), je vais donc me servir d'Alarmo qui permet de lancer un script selon un état pour basculer un input_boolean: qui me servira dans la condition immédiates du volet :

  • On passe tous les volets en mode automatique (certains auraient pu êtres débrayés comme on le verra plus loin)
  • On active l'input_boolean: qui va nous servir dans la condition de l'automatisation
  • Sur le mode Vacances (absence de longue durée) je rebascule tous les volets en mode manuel. Une sécurité de plus afin d'empêcher qu'ils soient ouverts par erreur.
script:
  alarmo_after_arm:
    alias: Alarmo - after Arm
    sequence:
      - if:
        then:
        - service: input_select.select_option
          target:
            entity_id:
              - input_select.vr_cuisine_immediate
              - input_select.vr_marie_immediate
              - input_select.vr_baie_immediate
              - input_select.vr_sejour_immediate
              - input_select.vr_antoine_immediate
              - input_select.vr_lionel_immediate
          data:
            option: Automatique
      - if: "{{ is_state('alarm_control_panel.alarmo', 'armed_away') }}"
        then:
          - service: input_boolean.turn_on
            target:
              entity_id: input_boolean.alarmo_armed_away
      - if: "{{ is_state('alarm_control_panel.alarmo', 'armed_vacation') }}"
        then:
          - service: input_boolean.turn_on
            target:
              entity_id: input_boolean.alarmo_armed_vacation
          - delay: "00:02:30"
          - service: input_select.select_option
            target:
              entity_id:
                - input_select.vr_cuisine_immediate
                - input_select.vr_marie_immediate
                - input_select.vr_baie_immediate
                - input_select.vr_sejour_immediate
                - input_select.vr_antoine_immediate
                - input_select.vr_lionel_immediate
            data:
              option: Manuel              
      - if: "{{ is_state('alarm_control_panel.alarmo', 'armed_home') }}"
        then:
          - service: input_boolean.turn_on
            target:
              entity_id: input_boolean.alarmo_armed_home
                entity_id: input_boolean.alarmo_armed_away

Et au retour sur le disarm :

  • Je repasse les input_boolean: à off
  • Je repasse tous les volets en automatique afin que les conditions courantes prennent effet.
  • Et si ma fille ou mon fils sont présents présente je vais basculer leurs volets en manuel afin qu'ils soient gérés comme bon leur semble. Mais j'attend un peu afin que l'automatisation du volet  le place dans la position de la contrainte en cours.
script:
  alarmo_after_to_disarm:
    alias: Alarmo - after Disarm
    sequence:
      - if:
        then:
        - service: input_boolean.turn_off
          target:
            entity_id: 
              - input_boolean.alarmo_armed_away
              - input_boolean.alarmo_armed_vacation
              - input_boolean.alarmo_armed_home
        - service: input_select.select_option
          target:
            entity_id:
              - input_select.vr_cuisine_immediate
              - input_select.vr_marie_immediate
              - input_select.vr_baie_immediate
              - input_select.vr_sejour_immediate
              - input_select.vr_antoine_immediate
              - input_select.vr_lionel_immediate
          data:
            option: Automatique
      - if: "{{ is_state('input_boolean.presence_marie', 'on') }}"
        then:
          - delay: "00:01:30"
          - service: input_select.select_option
            target:
              entity_id:
                - input_select.vr_marie_immediate
            data:
              option: Manuel
      - if: "{{ is_state('input_boolean.presence_antoine', 'on') }}"
        then:
          - delay: "00:01:30"
          - service: input_select.select_option
            target:
              entity_id:
                - input_select.vr_antoine_immediate
            data:
              option: Manuel

Ensuite il me reste qu'à configurer la contrainte dans l'automatisation, et surtout de la placer en priorité (la première).

        - conditions:
            - condition: state
              entity_id: input_boolean.alarmo_armed_away
              state: "on"
          sequence:
            - service: input_number.set_value
              target:
                entity_id: input_number.vr_cuisine_planned_position
              data:
                value: "{{ states('input_number.vr_global_position_alarm') }}"
            - service: input_text.set_value
              target:
                entity_id: input_text.vr_cuisine_condition
              data:
                value: "Condition : Alarmo Away - {{ states('input_number.vr_global_position_alarm') }} %"

J'ai deux positions d'alarme, ARMED_AWAY et ARMED_VACATION. J'utilise la première quand que pars quelques heures, ça laisse certains volets entrouverts afin de simuler une présence avec d'autres artifices, et la seconde pour une fermeture totale.

Le débrayage

Les automatismes c'est bien, mais si mes enfants sont ici en vacances ou des amis occupent leurs chambres, je ne voudrais pas qu'un automatisme les sortent du lit à l'aube. Pour mes enfants qui disposent de l'application Home Assistant je pourrait imaginer un automatisme, mais on va oublier et leur laisser de la liberté, d'autant plus que s'agissant d'amis je ne vais pas leur imposer ma domotique.

Par contre je dispose facilement de leur date de départ et d'arrivée et une automation bascule déjà un input_boolean: qui sert au chauffage. Je vais donc m'en servir pour passer le volet de leur chambre en mode manuel :

automation:
- id: a800970c-9bf4-48ce-aedg-a67c29093eb3
  description: Change vr_marie_immediate
  alias: VR Global - Change mode VR Marie
  mode: restart
  trigger:
    - platform: state
      entity_id: input_boolean.presence_marie
  action:
    - choose:
        - conditions:
            - condition: state
              entity_id: input_boolean.presence_marie
              state: "on"
          sequence:
            - service: input_select.select_option
              target:
                entity_id:
                  - input_select.vr_marie_immediate
              data:
                option: Manuel
        - conditions:
            - condition: state
              entity_id: input_boolean.presence_marie
              state: "off"
          sequence:
            - service: input_select.select_option
              target:
                entity_id:
                  - input_select.vr_marie_immediate
              data:
                option: Automatique

Enfants et amis commanderont donc leur volets avec la petite télécommande de leur chambre.

Suspension

Si vous êtes arrivés là et que vous avez lors de la configuration des BluePrint's la durée de suspension vous vous demandez peut être de quoi il s'agit. En fait configure là le durée pendant laquelle l'automatisme sera suspendu. Imaginons que celle ci est réglée du 60 minutes, il est 13 heures, le soleil frappe fort et vous décidez de déjeuner dans le cuisine. Vous remontez le volet avec la télécommande (ou l'application), il restera levé le temps de manger (suspension de 60 minutes) et l'automatisme reprendra le dessus ensuite avec la contrainte idoine... Magique !

Conclusion

Tout cela m'a pris un peu de temps et j'ai servi de cobaye dans la phase de test d'appréhension de la solution que Fabien viens de mettre à disposition. Quand vous aurez parfaitement validé le fonctionnement souhaité sur un volet pour pourrez le dupliquer sur l'ensemble des volets.

Pour cela il faut :

  1. Dupliquer le fichier qui contient les informations propres à chaque volet (mes fichiers sont ici) et changer l'ID: de l'automation.
  2. Repérer les informations des 3 BluePrint's du premier volet dans le fichier /config/automations.yaml, les dupliquer à la suite en changeant les informations propres à chaque volet et les ID: . Si vous ne le sentez pas configurez les BluePrint's individuellement à la main.
  3. Vérifier une fois de plus que tous les ID: ont bien été changés. J'insiste sur ce point car ça peut être la cause de bien des dysfonctionnements. Vous trouverez ici un générateur d'UUID.
  4. Redémarrer Home Assistant
  5. S'armer de patience car ce que l'on imagine parfait pour le premier volet ne le sera pas nécessairement pour les autres.
  6. Et surtout tester toutes les conditions car il sera désagréable de voir s'ouvrir le volet de la chambre quand on dort (vécu) voir certains volets ne pas se fermer sur l'alarme enclenchée quand on part que l'on est déjà en retard (vécu avec obligation de tous les passer en mode manuel et de les baisser à la main).

Avec plaisir pour en parler, ici ou mieux sur ce fil HACF.

Sources