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

Microsoft mon amour !

Et non, ce n'est pas une déclaration ! J'ai longtemps été in love avec Microsoft, mais comme on le sait, les histoires d'amour finissent souvent mal ! Blague à part, en imposant d'abord Exchange dans les entreprises, Microsoft telle une pieuvre avait bien préparé le terrain afin que celles-ci migrent vers Exchange Online, une des briques de la méga suite 365. Le résultat est qu'aujourd'hui la domination est quasi totale, domination que les autres acteurs ont bien du mal à concurrencer. Bien ou pas, ce n'est pas l'objet de cet article, par contre cette domination devrait imposer un devoir d'exemplarité, et force est de constater que ce n'est pas toujours le cas, loin s'en faut !

En devenant l'acteur majeur de la messagerie d'entreprise, Microsoft est également devenu un acteur majeur du spam. Face à cette déferlante certains acteurs moins conséquents n'ont d'autre choix que d'imposer régulièrement le blocage des adresses IP de Microsoft, une pratique certes discutable, mais également adoptée par Microsoft lui même pour son service grand public Hotmail (comme on peut le lire 1 | 2 | 3 )

Dans la pratique on se retrouve avec une messagerie professionnelle incapable d'envoyer des messages vers certaines destinations, @free.fr et @orange.fr par exemple, mais pas que. La situation peut se débloquer toute seule et alors les messages prennent du retard, ou sont simplement renvoyés à l'expéditeur via un NDR.

L'un de nos collègue, Marc, a eu l'opportunité d’échanger avec le responsable de la messagerie chez Free et il lui a posé la question :

Pensez vous qu’il puisse être envisageable d’exploiter d’autres mécanismes permettant un filtrage avec une granularité plus fine (genre trio DKIM, SPF, DMARC) ?

    • Non, pas à ce jour et probablement pas dans un futur proche.
    • Le premier problème est que la situation dans laquelle vous êtes ne concerne qu'Office365 et aucun autre hébergeur de messagerie. Il y a bien des problèmes avec Gmail mais les solutions techniques mises en place chez eux n'ont rien à voir avec celles d'Office365 et les dommages collatéraux en sont drastiquement réduits.
    • Le second problème est que si nous devions basculer sur une réputation par domaine en nous basant sur les signatures DKIM, il nous faudrait également prendre en compte les sceaux ARC (signature de l'intermédiaire technique) et qu'ici, il y a un sceau ARC sur microsoft.com sur les mails sortant d'Office365 et qu'il y a un risque conséquent pour que ce soit toute la plateforme Office365 qui se retrouve bloquée.
    • Le troisième problème est que nous avons pu constater ces dernières années des campagnes de spams expédiées au travers de comptes compromis. Sur certaines journées en décembre dernier, c'est plus de 1500 domaines qui participaient ainsi aux envois rien que pour Office365. Il est délicat de mettre en place une whiteliste concernant un domaine ou un compte car cela revient à retirer toutes nos protections alors que nous gérons pas ce domaine ou ce compte.

Dans ces conditions et puisque Microsoft ne réagit pas plus, il faut trouver un contournement qui va nous permettre de rerouter les messages destinés aux domaines qui pratiquent de tels blocages. D’aucuns diront que continuer à utiliser en 2022 un compte de messagerie chez un FAI n’est pas une bonne idée, mais peu importe, dans le cadre d’une relation commerciale on ne commence pas par expliquer la vie au client, mais à entretenir la relation avec lui et ainsi lui apporter des solution viable. On est tous d'accord, on ne devrait pas avoir à apporter une telle solution !

Contournement

Sur Microsoft 365, Exchange Online plus précisément, nous allons utiliser une règle et un connecteur pour dérouter les messages destinés au domaine free.fr  et orange.fr vers un serveur SMTP externe qui va servir de relais. S’il existe bien des services de relai SMTP sur Internet, ces services nécessitent soit une authentification, soit une restriction sur une adresse IP. Problème, il n’est pas possible de s’authentifier sur un connecteur sortant, et Microsoft utilise une multitude d’adresses IP sur ses serveurs SMTP.

*.protection.outlook.com : 40.92.0.0/15, 40.107.0.0/16, 52.100.0.0/14, 52.238.78.88/32, 104.47.0.0/17

Il va donc nous falloir monter un serveur SMTP externe sur lequel on va autoriser le relai depuis ces blocks d’adresses IP. Il existe toutefois un petit risque que d’autres administrateurs trouvent la faille et se servent de notre serveur. Ce risque est faible, et au pire on changera notre adresse IP.

Le relai

Ou relais, une fois de plus les anglais font plus simple avec relay, smtp-relay. Bref, pour monter un tel serveur il existe certainement plusieurs produits possibles, pour peu que ces logiciels soient capable de gérer de multiples plages d’adresses IP sources à relayer. J’ai utilisé HMailServer sous Windows car je le connais bien, mais on doit pouvoir faire ça sous Linux à moindre frais. Quant à la restriction au niveau des IP sources, ça peut aussi se faire au niveau du firewall.

Dans HMailServer (IP Ranges) on va déclarer nos adresses IP autorisés sans authentification, celle des serveur Microsoft 365 :

On répète ça pour chaque plage d’IP et ensuite de la même façon on va déclarer nos relais autorisés, les mêmes IP :

C'est un peu fastidieux et ce serait plus simple de déclarer 107.47.0.0/17, mais ici c’est ainsi.

Ensuite on s’assurera que notre serveur est correctement installé (il n’accepte rien d’autre) et est correctement déclaré et configuré (SPF, reverse IP, etc...) pour les domaines pour lesquels il devra assurer le transit. On fait un Telnet sur mx1.free.fr afin de s’assurer que l’on peut bien les joindre et  que notre IP publique n'est pas elle aussi blacklistée.

A ce stade on se connecte à l’administration Exchange de Microsoft 365 dans laquelle on va faire en sorte que tous les mails à destination de Free et Orange devront transiter via l’IP de notre serveur relai.

Exchange Online

Pour ce faire on va commencer par créer un connecteur qui s'appliquera aux messages sortant d'Exchange Online vers ce qui s'appelle ici Organisation Partenaire :

Le choix suivant est important :

  1. Soit on décide que ce connecteur s'applique à tous les messages à destination de Free et Orange, auquel cas on configure simplement ces domaines. C'est la solution la plus simple pour un tenant qui ne gère qu'un seul domaine.
  2. Soit on décide que ce connecteur ne s'applique qu'au messages qui ont été redirigés par une règle. On utilisera cette option dans le cas ou on souhaite rediriger uniquement certains mails, expéditeurs ou domaines sources, qui seront le fruit d'une règle à créer.

Ensuite se pose la question de la validation du connecteur ou l'on utilisera une adresse @free.fr par exemple. Dans la pratique validé ou pas le connecteur fonctionne tout de même....

Si l'on a fait le choix 2 il va nous falloir créer une règle pour que cela fonctionne. Dans cette règle on va demander à ce que :

  • le destinataire soit sur le domaine free.fr
  • le domaine de l'expéditeur
  • Et enfin que ce trafic transite via le connecteur précédemment créé.

Cela va nous permettre de ne dérouter vers notre MTA premise uniquement les domaines sources qui y seront configurés. Ce cas est spécifique à des tenant "partagés" ou plusieurs domaines coexistent, mais cela peut également permettre d'utiliser plusieurs serveurs relais en fonction des domaines sources.

Il est bien sur possible de faire ceci en PowerShell, vous trouverez les détails dans cet excellent article.

Synology mon amour....

J'utilise des NAS Synology à titre professionnel depuis plus de 10 ans avec une plutôt bonne expérience. J'en ai par exemple de gros qui fonctionnent encore très bien mais par exemple un RS3411xs de 2011 mérite d'être changé préventivement...

Je commande donc un RS3621RPxs et 6 disques Western Digital Ultrastar HC530, un modèle que j'avais utilisé avec succès il y a deux mois dans un RS820RP+. Disque de classe entreprise. Et là c'est le flop, dans ce dernier NAS il apparaissent comme disques non vérifiés et impossible de les monter en SHR, alors que ce disque est compatible avec le RS820RP+ !

Me voici donc partit à la recherche d'informations, le constat est des plus simples et probablement surtout mercantile. Synology vend maintenant ses propres disques en apposant leur étiquette sur des disques Toshiba, et les disques concurrents encore présent dans les listes de compatibilité sont de plus en plus rares. Rien de bien neuf sous le soleil, HPE, Dell et d'autres ont les mêmes pratiques. Saut que Synology nous avait d'une part habitué à pouvoir utiliser n'importe quel disque, le credo des fabricants de NAS, et surtout que les disques estampillés Synology sont peu disponibles et coutent souvent jusqu'à 30/40 % plus cher. Scandaleux, et les groupes d'utilisateurs ne se privent pas pour le dire et orienter les clients vers d'autres solutions.

Bref, j'ai donc 6 disque de 16 TO sur les bras. On va voir qu'il existe des contournements, mais pour des questions légales et de responsabilité vis à vis de mon client, je ne peux pas me permettre d'utiliser ces disque en production sensible. Donc Synology à gagné, et je repasse une commande de 6 disques Synology que je vais monter en stockage de VM. Quant aux 6 premiers je vais les utiliser dans un second groupe dédié à des sauvegardes secondaires en utilisant un contournement.

Synology

Dans la terminologie de Synology, il existe 3 classes de disques :

  • Compatible : Les disques compatibles ont été testés par Synology et sont certifiés pour fonctionner sans limitation.
  • Incompatible : les disques incompatibles sont « mis sur liste noire » par Synology et ne peuvent pas être utilisés (les disques SMR sont inclus dans ce lot). Rien que du normal.
  • Non vérifié : un disque qui n'a pas été testé par Synology est défini comme un lecteur non vérifié. Ca ne veut pas dire qu'il n'est pas 100% compatible, et ici c'est bien plus contestable.

Les disques non vérifiés sont utilisables dans un état non pris en charge avec les contraintes suivantes :

  • L'état d'un disque non vérifié peut apparaître comme non vérifié dans le gestionnaire de stockage de DSM.
  • Des avertissements s'afficheront lors de la sélection de lecteurs non vérifiés pour créer un pool de stockage.
  • Il est parfois impossible de créer des volumes de type SHR avec des disques non vérifiés.
  • Les pools de stockage contenant des lecteurs non vérifiés peuvent afficher un état de danger pouvant faire peur.
  • DSM peut envoyer des notifications d'avertissement lorsque des lecteurs non vérifiés sont en cours d'utilisation.
  • Les informations sur le lecteur telles que l'état de l'allocation, le nombre de secteurs défectueux, la température, le numéro de série, 4K natif peuvent ne pas être affichées.
  • La prise en charge de Synology sera limitée si le problème de prise en charge peut être lié au lecteur non vérifié (la décision de refuser la prise en charge reste à la discrétion de Synology)
  • L'utilisation de disques non vérifiés n'a aucun effet sur la garantie matérielle de Synology

Bien sur cette liste n'est pas exhaustive et malheureusement Synology est resté vague sur le fonctionnement de leur classification de disques et de SSD. Par exemple…

  • Les disques approuvés comme compatibles pour un modèle de NAS peuvent être non vérifiés pour un autre modèle.
  • Les disques approuvés comme compatibles peuvent voir leur classification changée en incompatible ou non vérifié sans préavis par Synology.
  • La compatibilité du lecteur est liée à la version du micrologiciel du lecteur.
  • Le test des disques nouvellement sortis est souvent retardé de plusieurs mois.
  • Le résultat de ces classifications de disques est que l'achat de disques compatibles est souvent limité à des disques rares dans le commerce, avec des micrologiciels obsolètes, qui sont soit indisponibles à la vente, soit en nombre insuffisant, auprès de fournisseurs non éprouvés, à des coûts non compétitifs.

De manière réaliste, un disque SATA de classe NAS/Enterprise utilisant la technologie CMR devrait convenir. Bien sur tout cela vaut pour les SSD...

Contournements

Dans tous les cas, et quelque soient les disques utilisés, on commence toujours par monter un volume et stresser les disques avant une mise en production, en faisant par exemple de gros transferts de données pendant quelques jours... Et si ça se passe mal on n'hésite pas à renvoyer les disques.

Si ça se passe bien on peut envisager deux contournements, l'un va faire croire que le disque a été vérifié, et l'autre que l'on ne s'occupe pas de vérifications... Et rien ne dit que de futures mises à jour ne rendront pas ce contournement obsolète.

Attention : S'agissant de modifications de fichiers système, vous savez et comprenez ce que vous faites, je décline toute forme de responsabilité, tout comme les personnes qui ont trouvé ces hacks et les ont divulgués sur les forums cités en sources (non, ce n'es pas moi qui ait trouvé !).

Cette mise en garde étant posée, j'ai trouvé deux possibilités :

Première option, ajout du disque dans la liste de compatibilité

On active SSH, on se connecte au NAS et on fait :

sudo-i

Qui va vous redemander le mot de passe pour cette élévation. Enduite on va dans le répertoire idoine :

cd /var/lib/disk-compatibility

Et on repère les fichiers *_host.db et *_host.db.new qu'il faudra éditer, par exemple dans mon cas rs3621rpxs_host_v7.db et rs3621rpxs_host_v7.db.new. Attention, tout ça peut évoluer avec le temps et les révisions. Avant d'éditer, je vous conseille de faire une copie de sauvegarde de l'original et de chercher les information de vos disques avec :

sudo smartctl -i /dev/sdc

Qui devrait retourner quelque chose du genre !

Model Family:     Ultrastar
Device Model:     WDC  WUH721816ALE6L4
Serial Number:    3WJAK3BJ
LU WWN Device Id: 5 000cca 284e0faf1
Firmware Version: PCGNW232
User Capacity:    16,000,900,661,248 bytes [16.0 TB]
Sector Sizes:     512 bytes logical, 4096 bytes physical
Rotation Rate:    7200 rpm
Form Factor:      3.5 inches
Device is:        In smartctl database [for details use: -P show]
ATA Version is:   Unknown(0x0ffc) (unknown minor revision code: 0x009c)
SATA Version is:  SATA >3.2 (0x1ff), 6.0 Gb/s (current: 6.0 Gb/s)
Local Time is:    Tue Oct 18 19:04:29 2022 CEST
SMART support is: Available - device has SMART capability.
SMART support is: Enabled

Ensuite on édite avec VI et ça devrait donner quelque chose de ce genre :

{"model":"WUH721816ALE6L4","firmware":"PCGNW232","rec_intvl”:[1]},

Et si on est pas sur, le mieux est d'aller lire, si on en dispose, ces informations dans un fichier pour un autre NAS ou le disque est indiqué compatible (notamment la dernière information en fin de ligne).

Seconde option, ne pas vérifier la compatibilité

Attention : Il y a de grandes chances que cette manipulation saute lors des mises à jour. Il faut donc la refaire à chaque fois, et toujours en partant du fichier original qui contient d'autres informations qui peuvent évoluer. (Je viens d'en faire les frais lors de l'application de 7.1.1-42962 Update 4, mais c'est probablement le cas de chaque mise à jour).

J'aurais tendance à préférer cette option bien plus simple. Mais ça sous entend que nos disque soient testés et non incompatibles. On passe toujours par SSH et on va éditer ce fichier :

/etc.defaults/synoinfo.conf

Et dans ce fichier on va passer cette ligne de yes à no.

support_disk_compatibility="no"

On peut bien sur éditer le fichier directement avec VI, mais pour ceux qui ne seraient pas à l'aise avec ce dinosaure, je conseille de commencer par faire une copie de sauvegarde de ce fichier dans un partage, de sauvegarder cette copie ailleurs et ensuite de l'éditer avec son éditeur préféré, puis d'aller remplacer le fichier original :

sudo cp /etc.defaults/synoinfo.conf /volume2/Backups/

On édite, et :

sudo cp /volume2/Backups/synoinfo.conf /etc.defaults

On sauvegarde et on redémarre le NAS et nos disques ne devrait plus s'afficher en rouge. Cependant ça ne joue pas sur les unités d'extension.

Conclusion

Synology nous enfume mais ils font de bons produits et je n'ai pas envie de vous dire qu'il va falloir changer de crèmerie. D'autant plus que d'autres fabricants seront surement tentés de faire de même. Pour autant je me poserait la question lors de mes prochains investissement ou conseils.

Dans l'absolu que ces avertissements soient présents, pour de louables raisons, est une bonne chose. Il serait par contre raisonnable que l'utilisateur informé puisse les supprimer, notamment quand un disque est largement reconnue par la communauté. Mais il y a également les mauvaises raisons, comme pour les extensions mémoire ou une barrette Crucial à 100 € fonctionnera parfaitement là ou Synology nous en demande près de 400 ! On pourrait également parler de la collecte de données, pas pire que d'autres...

Une alternative consistera à intégrer du logiciel Open Source (FreeNAS, TrueNAS, etc.) dans des serveurs recyclés disposant d'un bon support disque (HPE par exemple) que l'on trouve à des tarifs intéressant sur le marché du reconditionné. Ca fait du NAS dédié stockage pas cher et fiable. Je précise stockage, car contrairement à ce que veulent nous faire croire les fabricants, il faut, à mon sens, oublier l'idée d'installer tout et n'importe quoi sur un NAS, mais c'est là un autre débat....

Sources

 

Home Assistant & Wake on Lan

L'heure est aux économies d'énergies et il parait qu'il faut éteindre "la" Wi-Fi ! Ce n'est peut être pas ce qui consomme le plus et notre domotique fait certainement mieux.... Par contre nombre d'entre nous ont des PC énergivores qui mériteraient de passer en veille. Sauf que dans la pratique on laisse souvent ce PC allumé en se disant que l'on pourra en avoir besoin depuis l'extérieur... Ce que j'ai longtemps fait !

Un PC moderne avec un SSD sait sortir de veille en quelques secondes. Alors pourquoi ne pas ressortit une vieille fonctionnalité très peu utilisée, le Wake on Lan.

Sous Linux, Windows, voire même les mobiles il existe des application GUI ou CLI. Il faut tout de même savoir que Wake on Lan n'a pas été conçu à l'époque pour fonctionner à distance, et même s'il existe des possibilités ça reste compliqué. Alors pourquoi ne pas simplement utiliser Home Assistant qui lui sera toujours disponible, voire même simplement ajouter ça à un ESP existant, sous ESP Home par exemple..

La première chose pour vos tests sera de vérifier en local que le Wake on Lan fonctionne (il y a pas mal d'utilitaires et d'explications sur ce site).

Avec Home Assistant

On commence par ajouter l'intégration au fichier de configuration et on redémarre :

wake_on_lan:

Ensuite on peur créer un switch: , mais aujourd'hui on préfèrera un button: dans Lovelace qui actionnera le service correspondant :

  - action_name: 'Sleep/UnSleep'
    double_tap_action:
      action: call-service
      service: button.press
      target:
        entity_id: button.lia_monitors_off
      action: call-service
      confirmation:
        text: Etes vous sur ?
    tap_action:
      action: call-service
      service: wake_on_lan.send_magic_packet
      data:
        mac: 00-0C-29-FB-77-97
    icon: mdi:microsoft-windows
    name: 'Windows 10 PC'
    type: button

Vous remarquerez que j'ai configuré ça sur le tap_action:, le double_tap_action: étant lui configuré pour la commande de mise en veille via Home Assistant Agent.

Avec ESP Home

J'ai un client full cloud qui dispose d'une douzaine de PC, mais pas de serveur et encore moins de Home Assistant. La première solution était de laisser un PC allumé et y installer de quoi faire du Wake on Lan en remote. Il y a également des possibilités via TeamViewer et hélas pas de base dans l'UDM Pro d'Ubiquiti. On verra ce l'on utilisera mais j'ai également pensé faire ça via un simple ESP qui lui pourrait resté allumé...

Dans ESP Home on va éditer la config et simplement ajouter (attention, ici les séparateurs ne sont pas des "-" mais ":") :

web_server:    

button:
- platform: wake_on_lan
  name: "VM Annia"
  target_mac_address: 00:0C:29:FB:77:97

A partir de là il est possible de presser notre button: qui remonte dans Home Assistant, sur la page web de l'Esp, mais également via la commande curl (la doc est ici) :

curl -X POST http://192.168.210.153/button/vm_annia/press

Et comme on ne va pas demander à l'utilisateur final de faire un "curl" on va lui emballer tout ça dans une page web accessible que l'on sécurisera afin que lui seul puisse y accéder, en partant de cette base :

<HTML>
<center>

	<form name="myform" action="http://192.168.210.153/button/vm_annia/press" method="post">
  	<button>PC Annia ON</button>
	</form>

</center>
</HTML>

Variante avec un WebHook

L'ESP remonte sur Home Assistant via ESPHome. De fait on peu presser un bouton pour réveiller le PC distant, voire même intégrer ce bouton sur un autre Home Assistant en remote. Mais il est également possible de créer un WebHook et de déclencher avec un raccourcis depuis le PC de l'utilisateur distant :

- alias: Réveil PC Carole (WebHook)
  description: ""
  trigger:
    - platform: webhook
      webhook_id: "secret-id"
  condition: []
  action:
    - service: button.press
      data: {}
      target:
        entity_id: button.reveil_pc_carole
  mode: single

Et le raccourcis à créer sur le PC de l'utilisateur qui doit réveiller son PC de bureau...

curl -X POST https://ha-online.suptel.org/api/webhook/<secret-id>

Infos

  • Attention, Microsoft a introduit un concept de veille moderne qui souvent demandera à être désactivé. Des infos ici et .
  • Il n'est pas possible de réveiller un PC connecté en Wi-Fi ou en Ethernet via USB.
  • A noter que la Freebox dispose d'une option permettant de laisser passer du Wake on Lan. Ce n'est pas le cas pour tous les routeurs et il faut parfois ruser avec le port 9.

Sources

 

Home Assistant & BLE Proxy

J'entend souvent parler d'esp32, je ne suis pas un crack du fer à souder, ma vue baisse et je ne me lance généralement pas dans des montages au delà de mes compétences. De plus j'aime que ce que je déploie soit maintenable le plus facilement possible par des tiers. Je reste donc dans les standards, par exemple tous mes Shelly ont leur firmware d'origine, là ou ils seraient plus simples à gérer en ESP Home...

Ceci étant, j'aime aussi bricoler et j'avais un problème à résoudre. Si les petits capteurs de température Aqara en Zigbee sont parfaits, pas mal d'utilisateurs ont une préférence pour des sondes avec afficheur. Et le marché ne nous propose quasiment que des sondes afficheur en Bluetooth (BLE), Xiaomi, Aqara, Swithboot, Goovee ou encore InkBird... En général on peut facilement les gérer avec BLE Monitor et un bon dongle Bluetooth. Mais.

Depuis la version 2022.09 Bluetooth est géré nativement dans Home Assistant, il travaillent avec le développeur de BLE Monitor, une intégration qui devrait disparaitre à terme. Dans la pratique tout n'est pour l'instant pas reconnu mais les premiers résultats avec la version intégrée sont très honorables et j'ai obtenu des meilleurs résultats en BLE Proxy qu'avec des dongles USB ou du Bluthoot de base (NUC).

Pour autant se pose toujours le problème de la porté des sondes, dans notre cas d'usage BLE est uni directionnel et l'intégration se contente d'écouter, de décoder les trames et d'intégrer ce qui est exploitable. Sauf que s'il ne reçoit rien il n'intègre rien, et tout le monde sait que la portée du Bluetooth n'est pas phénoménale.

Lors de mes débuts avec HA j'avais essayé avec des potes des passerelles BLE, l'idée était de dédier des RPI Zero judicieusement placés à cet usage. Ca c'était soldé par un échec, certainement trop débutant que nous étions.

Mais avec la release 2022.09 une nouvelle option intégrée à HA a vu le jour : BLE Proxy

L'idée géniale est de se servir d'un module ESP configuré sous ESP Home et disposant du Bluetooth afin de capter les trames et les présenter à HA qui les décode. Et bien sur ce module sera judicieusement placé là ou on a besoin (cave, dépendance, aile gauche du château, etc...), pour peu que l'endroit dispose de Wi-Fi ou à minima d'Ethernet.

Le plus basic

La méthode la plus simple consiste à acheter un ESP-WROOM-32 (ici ou encore moins cher sur Ali), de le connecter au PC en USB après avoir installé les drivers et de le configurer à partir de cette page qui en fin de configuration vous proposera de l'intégrer à Home Assistant. 

Pour ceux qui jouent déjà avec l'add-on ESP Home il est aussi possible d'intégrer directement ce module et d'ajouter le code que vous trouverez ici et qui ressemble à ça :

esphome:
  name: "esp32-ble-proxy"
esp32:
  board: esp32dev
  framework:
    type: arduino
logger:
api:
  encryption:
    key: "AnUMyESfgsfgsdfhgjfjhhjkhg1WJLcGZHTiD7NoOEog="
ota:
  password: "3fb1ee84wgfsdhgsgh46sgh869d9a4856"
wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  ap:
    ssid: "Ss Fallback Hotspot"
    password: "ws7qfgsfgh6Bl"
captive_portal:
web_server:
dashboard_import:
  package_import_url: github://esphome/bluetooth-proxies/esp32-generic.yaml@main
esp32_ble_tracker:
  scan_parameters:
    interval: 1100ms
    window: 1100ms
    active: true
bluetooth_proxy:
button:
- platform: safe_mode
  name: Safe Mode Boot
  entity_category: diagnostic

Une fois que le module est intégré à Home Assistant celui ci décodera les trames et vous proposera les sondes qu'il reçoit. Il est également possible de les ajouter avec leur adresse MAC.

Le plus compact

L'Atom Lite me plait bien (détails ici). D'une part il n'est pas plus gros qu'une pièce de monnaie, et d'autre part il est livré dans un petit boitier plastique ce qui sera toujours plus élégant que le précédent. De plus on peut avec un coupleur USB-A / USB-C le brancher directement sur un chargeur, à défaut un câble court fera l'affaire. On trouve l'Atom Lite sur Ali ou sur le site de son fabricant.

La mise en œuvre est identique, et en bonus on peut piloter la led multicolore qui pourra éventuellement servir à notifier visuellement des états de ce que vous voulez via HA :

light:
  - platform: fastled_clockless
    chipset: WS2812B
    pin: 27
    num_leds: 1
    rgb_order: GRB
    id: status_led
    name: Stack Light
    effects:
      - random:
      - flicker:
      - addressable_rainbow:  

Et comme il expose des ports GPIO rien n'empêche, comme pour les autres de s'en servir pour faire autre chose. Je vous conseille d'ailleurs d'aller explorer l'univers M5STACK ou vous pourrez piocher des idées, comme ce lecteur RFID par exemple....

Le plus complet

L'Olimex (qui s'achète ici) est le plus complet car il dispose en plus du Wi-Fi d'un port Ethernet ce qui permettra de le placer là ou le Wi-Fi est absent. De plus il est disponible dans une version avec antenne externe pour une meilleure réception, ainsi qu'une version industrielle garantie de -40 + 85C. Le sports GPIO sont présents mais il faudra sortit le fer à souder...

Coté configuration c'est identiques au autres. On peut commence par configurer en USB en Wi-Fi et ensuite on active le port Ethernet en mettant à jour en Wi-Fi. Il semble déconseillé d'utiliser le port USB et le port Ethernet en même temps et on ne va pas jouer... Par contre je vous conseille de figer l'adresse affectée par la résa DHCP dans les deux cas car dans le cas contraire ESP Home a un peu de mal à le retrouver via son adresse en .local qui par définition changera.

# wifi:
#   ssid: !secret wifi_ssid
#   password: !secret wifi_password
#   ap:
#     ssid: "Esp-Test Fallback Hotspot"
#     password: "MHPdiJUnJ8i8"
#   use_address: 192.168.210.69
  
ethernet:
  type: LAN8720
  mdc_pin: GPIO23
  mdio_pin: GPIO18
  clk_mode: GPIO17_OUT
  phy_addr: 0
  power_pin: GPIO12
  use_address: 192.168.210.108

Alternatives

Il existe d'autre options que je n'ai pas testé, comme le GL-Inet GL-S10, que je n'ai pas pu me procurer. Dans un petit boitier on a du Wi-FI, de l'Ethernet et une antenne externe pour $ 25.

Shelly

Les modules Plus de Shelly permettent également d'activer le mode proxy et ainsi jouer ce rôle. Donc si on a des Shelly+ ou des Prises commandées Plusg S+ on pourra se passer d'un ESP dédié. J'ai validé ça avec succès sur un appartement en duplex de 175 m² avec 2 Shelly+ 1PM. C'est la solution la plus simple.

Usages

En fait tout cela nous ouvre pas mal de portes. Imaginons que je veuille faire des relevés de température / humidité sur un site distant ou il n'y a pas de domotique. J'ai alors le choix d'un ESP du genre Atom Lite sur une prise USB qui va remonter les informations des sondes locale sou Bluetooth vers un site Home Assistant distant qui le verra dès lors que j'ai ouvert le port 6053. Mon ESP communiquera alors via l'API avec Home Assistant comme s'il était local et je pourrais le maintenir, changer sa config et le mettre à jour avec ESPHome. L'alternative consiste à monter MQTT et à le faire communiquer avec un brooker. Ca évite d'avoir un port à ouvrir, mais je ne pourrais plus le maintenir.

On peut échanger ici ou sur HACF.

Alternative

Si le mode proxy est intéressant pour couvrir une surface plus grande, il est également possible de déclarer les sondes BLE dans ESPHome et ainsi les voir remonter dans Home Asistant :

sensor:
  - platform: xiaomi_cgg1
    mac_address: "58:2D:34:10:F8:22"
    temperature:
      name: "Cuisine Temperature"
    humidity:
      name: "Cuisine Humidity"
    battery_level:
      name: "Cuisine Battery Level"    

  - platform: xiaomi_lywsd03mmc
    mac_address: "A4:C1:38:AB:59:F7"
    bindkey: "93f19252bcdfhfdqshdhb4f9957424"
    temperature:
      name: "Square Temperature"
    humidity:
      name: "Square Humidity"
    battery_level:
      name: "Square Battery Level"  

  - platform: xiaomi_lywsdcgq
    mac_address: "4C:65:A8:D1:DB:22"
    temperature:
      name: "Terrasse Temperature"
    humidity:
      name: "Terrasse Humidity"
    battery_level:
      name: "Terrasse Battery Level"

  - platform: xiaomi_lywsd02
    mac_address: "3F:59:C8:82:70:2A"
    temperature:
      name: "Hall Temperature"
    humidity:
      name: "Hall Humidity"
    battery_level:
      name: "Hall Battery Level"

EDIT 15/08/2023

Deux choses :

  • Un composant pour les sondes qui ne sont pas reconnues de base.
  • Un constat, beaucoup d'ESP en WIFI donnent des résultats parfois aléatoires. Dans tous mes tests les résultat le plus fiable et constant est celui obtenu avec un ESP Olimex en Ethernet (POE), et avec son antenne externe il couvre toute la maison, terrasse et jardin compris.
  • Eviter plus de 3 proxy (attention avec les Shelly qui jouent ce rôle).
  • Pour les équipements Xiaomi / Aqara cette passerelle Xiaomi peut constituer la bonne alternative avec l'intégration locale idoine. Elle remonte BLE + Zigbee et de plus elles est compatible Homekit.

Home Assistant & Entity Controler

Vous voilà content, vous pouvez allumer, gérer et éteindre votre ampoule via Home Assistant. Je suis sur que vous savez également faire ça via un bouton sans fil, par exemple via ControlerX etc... Mais on peut mieux faire et automatiser en détectant la présence dans une pièce avec quelques lignes et un capteur d'occupation genre Aqara ou Xiaomi... Et pour ça il y a plusieurs méthodes.

EDIT 25/10/2022 : Finalement le problème majeur de Entity Controler est que toute modification impose un redémarrage complet de Home Assistant. J'ai donc basculé sur AD-Automoli qui lui est sous AppDaemon, donc dynamique car les modifications sont prises en compte immédiatement. A considérer également Light Automation pour des éclairages  heures fixes.

L'option classique en YAML

- id: 'fab33b5b-b526-4f6c-a23f-ee98c300012c'
  alias: "PRESENCE : Eclairage Bureau"
  description: ''
  trigger:
    - platform: device
      type: occupied
      id: enter
      device_id: a65b2d5c507be85f0964131f26f8d31e
      entity_id: binary_sensor.motion_bureau_occupancy
      domain: binary_sensor
    - platform: device
      type: not_occupied
      id: leave
      device_id: a65b2d5c507be85f0964131f26f8d31e
      entity_id: binary_sensor.motion_bureau_occupancy
      domain: binary_sensor
  condition:
  action:
    - if:
      - condition: trigger
        id: enter
      then:
        - service: light.turn_on
          data:
            entity_id: light.shellydimmer_db2f18
    - if:
        - condition: trigger
          id: leave
      then:
        - service: light.turn_off
          data:
            entity_id: light.shellydimmer_db2f18

Alternatives

Pour les plus flémards on peu aussi faire ça avec des BluePrint's, ou même en NodeRed si on veut se compliquer la vie (je déteste mais ça vous le savez). Mais j'ai encore plus simple à vous proposer.

Entity Controler

EC pour les intimes. EC est un moteur qui va contrôler des entités (light, switch, scènes, etc...) en fonction d'informations binaires. Donc les sensor: d'entrée seront de détecteurs de présence ou de mouvement, des capteurs d'ouverture ou dans l'absolu n'importe quel binary_sensor: , et pourquoi pas ceux que vous aurez créé dans un usage détourné... A ce contrôle on va bien sur pouvoir appliquer diverses contraintes (horaires, nuit/jour) ou simplement dire que dès lors qu'une lampe s'est allumée automatiquement elle ne s'étendra que manuellement. C'est assez souple et adaptable à quasiment tous les besoins. En tous cas les miens.

Le Git est ici et la doc très complète .

Voici un exemple pour allumer une lampe pendant 180 secondes (durée par défaut) : 3 lignes

motion_light:
  sensor: binary_sensor.motion_sejour
  entity: light.shellydimmer_d3e57c

On peut bien sur régler la durée :

  delay: 320

Faire en sorte que ça ne s'allume que la nuit, avec ici un offset :

  start_time: sunset - 00:30:00
  end_time: sunrise + 00:30:00

Et appliquer des valeurs à la lampe :

  service_data:
    brightness: 255
    color_name: blue
  service_data_on: 
    transition: 5
  service_data_off: 
    transition: 10

Faire en sorte que ça ne s'éteigne pas !

  stay_mode: on

Ou applique une contrainte externe. Ici j'ai mis un input_boolean: mais ça aurait pu être l'état d'une autre lampe, voire un media_player:. A noter que l'on peu également se servir des overrides pour simplement désactiver le contrôle. J'ai par exemple un éclairage extérieur avec des projecteurs que je ne veux pas voir s'allumer quand on dine et que l'éclairage via la guirlande est amplement suffisant et plus agréable.

  overrides:
    - input_boolean.auto_motion_salon

Pareil quand on regarde un film il ne faut pas que l'éclairage se mette en route si on bouge sur le canapé. Pour ça j'ai déjà une automation qui fonctionne sur le play/pause et qui augmente lentement l'éclairage quand je fait pause et inversement (comme au cinéma). Pour l'instant ça ne fonctionne que sur Emby, il faut que je l'intègre à Android TV et EC., je métrais à jour ici quand je le ferait).

Conclusion

Un peu comme ControlerX, voilà de quoi simplifier la chose et gagner des lignes de code. A noter que sous AppDaemon il y Wasp in a Box qui est un peu moins complet ou AD-Automoli qui lui est trop complet...

On peut en discuter ici ou sur HACF.

Windows et le yoyo des écrans....

Sous Windows lorsqu'on utilise plusieurs écrans se pose un problème majeur : si un des écrans passe en veille, déconnecté ou non alimenté, toutes les fenêtres ouvertes passent sur l'écran qui reste disponible. Dans l'absolu c'est logique sur un laptop sur lequel on connecte occasionnellement un écran externe, par contre sur un PC fixe que l'on utilise en permanence avec trois écrans il est extrêmement désagréable de devoir réorganiser ses fenêtres tous les matins... (sujet déjà évoqué ici).

La faute à qui, à quoi ?

Le problème se situe au niveau de la gestion de l'EDID (ici pour les détails).  Il s'agit d'une implémentation dans les écrans qui va transmettre à Windows pas mal d'informations, dont :

  • La résolution d’écran,
  • La profondeur de couleur prise en charge,
  • La résolution et fréquence d’images prises en charge,
  • Le rapport hauteur / largeur
  • Le format audio pris en charge, par exemple, par exemple sur un téléviseur ne prend en charge que les formats 2.0 ou 5.1,

Selon l’année de production du téléviseur ou du moniteur, la version prise en charge d’EDID peut être 1.0, 1.4, 2.0, 3.0 ou plus. Ces informations ne sont bien sur pas modifiables par l'utilisateur mais en dur dans l'écran. A noter également que certains moniteurs permettent de désactiver une partie des informations transmises via le port HDMI ou DP. On peut alors faire un réglage manuel et Windows ne verra pas l'écran disparaitre. Ca résout le problème.

Mais hélas ce n'est pas le cas de mes écrans Samsung.

Il faut savoir que sous Windows il n'y a absolument aucune solutions native ou via un utilitaire pour désactiver l'auto détection des écrans. Ca existait jadis sous Windows 7, sous la forme d'une clé de registre, mais depuis que Windows est devenu avant tout un outil de collecte de données c'est terminé, le marketing a probablement décidé d'éliminer tout ce qui pourrait générer du support... Et pourtant la demande est bien présente !

Contournement

J'ai exploré le net dans tous les sens et les seules solutions disponibles sont matérielles. Il s'agit de dongle HDMI qui se branchent sur le port HDMI ou DP (ou via un adaptateur USB-S) entre le PC et les écrans. Il s'agit d'un émulateur EDID qui va faire croire à Windows (ça doit être identique sous MacOS) que l'écran est présent alors même qu'il est en veille, off ou débranché.

Fonctionnement

La première fois qu'on insère le dongle entre le PC et l'écran (ça ne se connecte pas sur l'écran mais sur le PC) il va détecter les informations transmise par l'EDID. Ensuite on débranche brièvement le câble de l'écran, la diode du dongle clignote ce qui indique qu'il enregistre la configuration EDID de l'écran. A partir de là on pourra éteindre ou déconnecter l'écran, Windows considèrera toujours qu'il est présent.

Attention : Ces informations étant propre à chaque écran, il faudra faire un reset du dongle si on change d'écran.

On trouve sur le marché plusieurs modèles à partir de 14 €, tous ne fonctionnent pas bien et certains sont limités en résolution. J'avais d'abord commandé ce modèle de chez Fueran qui dans mon cas ne fonctionne pas. C'est avec ces deux modèles Sonero (Manuel) et Digitus (fiche tech.) que j'ai eu les meilleurs résultats en 4K jusqu'à 60 Hz en ce qui me concerne, HDR non supporté). Il existe également ce modèle développé à cet effet et qui donne de bons résultats (je vais en avoir deux à revendre, ainsi qu'un modèle DP)

Sur Amazon il existe d'autres modèles et je veux bien un retour si vous testez autre chose. N'oubliez pas que chez eux le retour est gratuit, alors n'hésitez pas à tester. D'ailleurs celui-ci serait à tester car il permet un réglage manuel de la résolution...

Complications

Si dans la majorité des cas ça se passe bien, j'ai dans ma configuration j'ai un écran Samsung M7 en 43" (par ailleurs très bien pour 450 €) qui se dit intelligent et qui a eu dans mes tests parfois des comportements bizarres :

  • L'écrans n'était reconnu qu'en FHD et non 4K : la seule solution passe par une réinitialisation en config usine.
  • Ecran noir mauvaise disposition d'écrans après une déconnection ou mise en veille !

Dans ce dernier cas le fait de la basculer entre 30 et 60 Hz dans les paramètres le réactive. Mais si ça se reproduit c'est fastidieux de chaque fois aller dans les paramètres (pour peu que les dits paramètres n'aillent pas s'ouvrir sur l'écrans qui est noir...). Heureusement il existe des commandes en CLI qui vont permettre de créer un raccourcis, voire de les lancer à distance (dans mon cas via Home Assistant Agent).

Forcer la résolution et la fréquence de rafraichissement

J'ai utilisé alternativement en 30 ou 60 Hz l'outil NirCMD de chez NirSoft :

C:\Tools\nircmd setdisplay monitor:DISPLAY1 3840 2160 32 30
ou
C:\Tools\nircmd setdisplay monitor:DISPLAY1 3840 2160 32 60

Changer l'échèle (DPI)

J'ai trouvé l'utilitaire SetDPI (1 étant le numéro d'écran, qui ne correspond bizarrement pas aux numéros édictés par Windows, et ensuite la valeur DPI) :

C:\Tools\setdpi 1 150

Définir l'écran principal

Avec MultiMonitorTool de chez NirSoft pour définir l'écran principal :

C:\Tools\multimonitortool /SetPrimary \\.\DISPLAY1

Et pour terminer je viens de trouver Display Changer et Display Changer II qui permettent de résumer tout ça en une seule ligne.

En // je suis en train de tester Persistent Windows qui enregistre les positions et dans l'absolu permet de créer des snapshots de positions...

EDIT 15/10/22

Petit retour d'expérience actualisé.

Les dongle dont j'ai parlé plus haut (Sonero et Digitus) fonctionnent parfaitement. On peut mettre en veille ou éteindre les écrans, les fenêtres ne bougent plus. C'est parfait. Et quand on redémarre le PC il suffit de relancer Persistant Windows pour qu'il ouvre les programmes et positionne les fenêtres à leur place. What else !

Sources

 

 

 
 

 

 

Home Assistant & Cloudflare Zero Trust

Une fois de plus on va parler de VPN. J'avais ici évoqué Zerotier (gratuit pour 25 nodes) que j'utilise toujours notamment pour interconnecter plusieurs sites entre eux en remplacement d'IPSEC. Ca fonctionne très bien et ça se fait oublier. Entre temps on a découvert Wireguard qui est très performant et peut être utilisé en natif (faut faire le taff) ou via des intégrations comme Tailsacle (entre autres) dont la version gratuite sera suffisante pour bien des usages.

Aujourd'hui on va parler de Cloudflare Zero Trust. Au départ je voulais juste tester sous Home Assistant car cela permet de publier son Home Assistant sans ouvrir de ports sur le routeur, de la même façon que l'on peut le faire si l'on dispose d'un abonnement Nabu Casa. J'ai cet abonnement, mais je ne veux pas l'imposer aux utilisateurs que j'aide.

Si Zero Trust est basé sur Wireguard il n'a rien d'open source. Certains n'aimeront pas quelque chose qui passe par Cloudflare qui comme beaucoup d'acteurs du marché pratique la collecte de donnée. C'est le business de l'époque, d'autres font pire mais ce n'est pas le débat ici, alors épargnez moi vos digressions sur ce sujet, ce n'est pas l'objet. Si vous choisissez cette solution c'est en connaissance de cause. Il existe des alternatives, moins simples à mettre en œuvre.

Zero Trust est un VPN orienté client qui permet notamment deux approches :

  • Publier et sécuriser, sans ouvrir de ports, un (ou plusieurs) site hébergés en premise (premise = chez vous, dans votre entreprise) et le rendre accessible publiquement avec des restrictions qui assureront sa sécurité (MFA) et surtout des restrictions géographiques qui sont quasi impossibles avec les autres solutions, notamment à cause de Let'Encrypt.
  • Rendre accessible des réseaux privés (VPN) en passant par le client Warp de Cloudflare) et ainsi accéder à toutes les machines du réseau (RDP, SMB, SSH, etc...).

Ce qui fait la force de cette solution ce sont les policies qui permettent une très grande granularité. Cloudflare Zero Trust est gratuit jusqu'à 50 utilisateurs. Et dans l'absolu pour sécuriser Home Assistant on a même pas besoin du moindre utilisateur.

Home Assistant

Un Add-on est disponible ici et sa mise œuvre est 'une simplicité enfantine mais il y a une petite subtilité. En effet il y a deux façons pour gérer un tunnel :

  • En local et en CLI
  • Depuis le dashboard de Zero Trust

On part du principe que vous avez un compte Cloudflare et qu'un de vos domaines y est géré. Vous avez également activé Zero Trust. A faire avant toute chose.

Dans les deux cas on ajoute ou modifie le fichier de configuration de Home Assistant ainci :

http:
  use_x_forwarded_for: true
  trusted_proxies:
    - 172.30.33.0/24

Option 1, gestion en local

On installe l'add-on sur Home Assistant, on choisit un host pour Home Assistant, ha.domaine.com par exemple et on lance l'add-on. Il suffit simplement ensuite d'aller copier dans le log l'url de validation et de la copier dans votre navigateur.

Et ça fonctionne, installation du certificat intermédiaire comprise. On pourra ensuite sécuriser et jouer avec les options, la doc de l'add-on est ici et cette  de Zero Trust . Si vous ne pensez pas utiliser Zero Trust pour autre chose c'est la solution la plus simple.

Option 2, gestion en remote

Vu que je compte utiliser Zero Trust à d'autres fin, c'est l'option que j'ai choisit.

  • Dans la console (Access/Tunnels) je crée un nouveau tunnel que ne configure pas.
  • Je copie le token que je viens reporter dans l'add-on et je lance l'add-on
  • Je vais dans le log et je copie l'url de validation que je colle dans le navigateur afin de finaliser l'installation et valider le certificat. 
  • Dans la gestion du tunnel je vais créer un Public Hots Name qui va correspondre à mon serveur et sera exposé avec le nom de domaine choisit :

Votre Home Assistant est maintenant accessible, ici https://test-ha.canaletto.fr (sans le port).

Aller plus loin...

En premier lieu je vous conseille de définir une policie dans Access/Applications afin que votre serveur ne soit accessible que depuis votre pays et surtout pas depuis des états plein de black hat's ...

Ensuite il faut savoir que vous avez installé sur votre serveur une passerelle VPN qui va vous permettre d'accéder à tout votre réseau local en passant par le client Warp. Pour cela il faut dans la configuration du tunnel déclarer un Private Network.

Ensuite dans les SettingsGeneral on va définir le nom de (Team) :

Dans Settings/Network on va changer le mode des tunnels. De base, dès lors que le client Warp est activé, Zero Trust va faire passer tout ce qui ne ressemble pas à une adresse privée dans ses tuyaux, c-a-d tout votre trafic, probablement à des fins de collecte de donnée... On va donc remplacer le mode Exclude par le mode Include et y déclarer uniquement notre réseau privé. Ainsi seul le trafic tunnelisé transitera par Cloudflare, et comme il est dans un tunnel ce sera théoriquement incognito. Je dis théoriquement car dans cette solution ce n'est pas vous mais Cloudflare qui a les clés... Mais nous sommes dans le cadre d'un service de classe entreprise et les CGU garantissent la confidentialité des données...

Dernier point, déclarer une méthode d'authentification. De base une authentification par code PIN est proposée, vous déclarez un domaine ou une adresse mail et vous revenez un code PIN à 6 chiffres qu'il suffit de rentrer... En option il est possible de configurer un SSO en utilisant une authentification que l'on exploite déjà (Azure AD, Centrify, Facebook, GitHub, Google Workspace, Google, LinkedIn, Okta, OneLogin, Saml, OpenID Connect, etc...). Plus complet, mais ça peut répondre à certains besoins en entreprise.

A partir de la on installe le client et on se connecte avec le nom que l'on a défini plus haut. On teste un RDP, SMB ou SSH sur une IP du réseau privé, et ça marche. Ca veut dire qu'à ce stade tout est ouvert dès lors que l'on a connecté le client, pourquoi pas dans le cadre d'une utilisation personnelle, mais je ne saurait trop vous conseiller de tout interdire et de n'autoriser que ce qui est utile (Gateway/Policies/Network).

Cet outil étant avant tout destiné à une utilisation en entreprise les possibilités sont immenses. Pour autant l'administration n'est pas très compliquée, avec quelques connaissance de base dans la gestion des réseaux.

Echanger

J'ai créé un sujet sur HACF, plus pratique qu'ici pour échanger.

 

Home Assistant & ECS

Mon chauffe eau électrique était géré par une automation datant de mes débuts sur Home Assistant. Ca fait le job mais je me disais que je pourrais améliorer la  chose afin de pouvoir ajuster plus facilement la plage horaire et les jours de chauffe. En effet faute d'avoir la température de l'eau (il faudrait y insérer une sonde, et comme je viens de le changer dans l'urgence je veux pas bricoler), bref, quand je suis seul dans la maison chauffer l'eau un jour sur deux est bien suffisant.

Bien sur je pourrait améliorer ça en me basant sur la présence ou non des enfants ou des invités. Mais parfois il faut savoir faire simple...

Interface

Je suis donc parti de l'interface car c'était le but premier. Pouvoir facilement et rapidement changer les heures et jours de chauffe. J'aurais pu me servir du Scheduller (moins pratique d'accès) ou de la nouvelle entité Agenda (pas encore aboutie). J'ai donc fait à ma sauce.

J'utilise quelques composants que vous allez retrouver dans le code de la carte :

type: vertical-stack
cards:
  - type: entities
    entities:
      - entities:
          - entity: automation.ecs_on
            name: false
          - entity: sensor.energy_total_yearly_1pm_ecs
            name: false
            unit: kWh
            format: precision2
          - entity: sensor.pm_ecs_power
            name: false
        entity: switch.pm_ecs
        name: ECS
        icon: mdi:waves
        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.ecs_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.ecs_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.ecs_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.ecs_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.ecs_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.ecs_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.ecs_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.ecs_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> Chauffe Eau'
            - type: markdown
              content: '#### <center> Heure de Fin'
        - type: horizontal-stack
          cards:
            - entity: input_datetime.ecs_start
              type: custom:time-picker-card
              name: Début
              layout:
                align_controls: center
                embedded: true
              hide:
                name: true
            - type: glance
              show_state: true
              show_name: false
              entities:
                - switch.pm_ecs
            - entity: input_datetime.ecs_stop
              type: custom:time-picker-card
              layout:
                align_controls: center
                embedded: true
              hide:
                name: true

Automation

Bien plus simple que la carte Lovelace. On se base sur des input_datetime:

input_datetime:
  ecs_start:
    has_date: false
    has_time: true
  ecs_stop:
    has_date: false
    has_time: true

Et des input_boolean:

input_boolean:
  ecs_day_monday:
    name: "ECS : Lundi"
    icon: mdi:toggle-switch
  ecs_day_tuesday:
    name: "ECS : Mardi"
    icon: mdi:toggle-switch
  ecs_day_wednesday:
    name: "ECS : Mercredi"
    icon: mdi:toggle-switch
  ecs_day_thursday:
    name: "ECS : Jeudi"
    icon: mdi:toggle-switch
  ecs_day_friday:
    name: "ECS : Vendredi"
    icon: mdi:toggle-switch
  ecs_day_saturday:
    name: "ECS : Samedi"
    icon: mdi:toggle-switch
  ecs_day_sunday:
    name: "ECS : Dimanche"
    icon: mdi:toggle-switch

Et ensuite une automations :

- id: '678d0e1-fcb6-4412-abvfr-99c4d37dfgaa'
  alias: 'ECS Schedule'
  trigger:
  - platform: template
    value_template: '{{ states.sensor.time.state == states.input_datetime.ecs_start.state[0:5] }}'
    id: to_on
  - platform: template
    value_template: '{{ states.sensor.time.state == states.input_datetime.ecs_stop.state[0:5] }}'
    id: to_off
  condition:
    condition: or
    conditions:
      - '{{ (now().strftime("%a") == "Mon") and is_state("input_boolean.ecs_day_monday", "on") }}'
      - '{{ (now().strftime("%a") == "Tue") and is_state("input_boolean.ecs_day_tuesday", "on") }}'
      - '{{ (now().strftime("%a") == "Wed") and is_state("input_boolean.ecs_day_wednesday", "on") }}'
      - '{{ (now().strftime("%a") == "Thu") and is_state("input_boolean.ecs_day_thursday", "on") }}'
      - '{{ (now().strftime("%a") == "Fri") and is_state("input_boolean.ecs_day_friday", "on") }}'
      - '{{ (now().strftime("%a") == "Sat") and is_state("input_boolean.ecs_day_saturday", "on") }}'
      - '{{ (now().strftime("%a") == "Sun") and is_state("input_boolean.ecs_day_sunday", "on")}}'
  action:
    - choose:
        - conditions: "{{ trigger.id in ['to_on'] }}"
          sequence:
            - service: switch.turn_on
              entity_id: switch.legrand_contactor

        - conditions: "{{ trigger.id in ['to_off'] }}"
          sequence:
            - service: switch.turn_off
              entity_id: switch.legrand_contactor

Bonus

Pour suivre la période de chauffe on peut se servir du switch associé dans un history graph. Mais il y a plus malin à faire, en se basant sur la consommation, on va créer un binary afin de connaitre la période pour le chauffe eau chauffe réellement, et pas seulement la période ou il est on :

template:
  - binary_sensor:
      - name: "ECS Power On"
        delay_on:
          minutes: 1
        delay_off:
          minutes: 1
        state: >
          {{ states('sensor.legrand_contactor_power')|float > 0 }}

Et on aura une seconde ligne afin de savoir quand le chauffe eau était en chauffe.

 

Home Assistant, ZHA & Legrand

Attention : voir l'Edit important plus bas !

Il existe des devices plus ou moins bien intégrés et c'est le cas du contacteur Legrand 412170 (16A) ou 412171 (20A) (doc) qui de base est configuré en HP/HC via le signal fourni par le compteur et ou rien dans l'intégration ne permet à ce jour de la passer en mode on/off. On verra plus loin qu'il existe également une sortie de câble connectée avec ses particularités...

Vous allez me dire qu'il y est très bien géré en Zigbee2MQTT, ou que je pourrais utiliser quelque chose de moins cher (120 €). Là n'est pas la question, mon client (et ami) ne veut que du Legrand dans son tableau et pour simplifier au maximum je ne veux pas de modules externes, d'où ZHA.

L'intégration du contacteur sous ZHA se fait avec le petit bouton qui passe en rouge.

  • Assurez-vous que la passerelle (ZHA) n'est pas en mode d'appairage
  • Appuyez 5 à 8 secondes environ jusqu'à ce qu'il devienne rouge (reset)
  • Passez maintenant votre passerelle ZHA en mode d'appairage
  • Appuyez sur le bouton de réinitialisation 5 à 8 secondes environ pour lancer la procédure d'appairage
  • Effectuez des clics successifs sur ce bouton toutes les secondes, jusqu'à ce que la LED devienne verte

La légende dit que les produits Legrand ne fonctionneraient que sur le canal 11, mon réseau est en 15 et d'autres l'on fait fonctionner en 25...

En cherchant sur la toile je me suis aperçu que nos collègues amateurs de Jeedom avaient réussit à changer les choses via deconz/Phoscon. J'avais donc les valeurs à changer, mais je n'ai pas réussit à les intégrer. 

Pour info le cluster 64513 (en décimal) = FC01 (en hexa)

{"endpoint" : 1,"cluster":64513,"attribute":0,"manufacturer":64513,"name":"Mode","type":"select","values":[{"value":3,"name":"on/off"},{"value":4,"name":"hp/hc"}]},

Sous ZHA en natif on ne peut rien faire sur les clusters à ce niveau. Avec l'excellent ZHA Toolkit il y beaucoup plus de possibilités. Encore fallait t'il bien connaitre le domaine Zigbee afin de trouver le type de valeur d'attribut à configurer. Et là je remercie mdeweerd pour sa gentillesse et sa patience (je vous laisse lire l'échange ici).

Mise en place

Très simple !

  1. On commence par installer ZHA Toolkit
  2. Ensuite il n'y a qu'à lancer cette séquence dans les outils de développement (et on replace la valeur de l'attribut à 4 si on veut revenir au mode HP/HC)
service: zha_toolkit.attr_write
data:
  ieee: 00:04:74:00:00:83:f4:f6
  endpoint: 1
  cluster: 64513
  attribute: 0
  attr_val: [3, 0]
  attr_type: 0x09  # Devrait être facultatif si la lecture précède l'écriture.
  # manf: 4129     # Ne pas définir le fabricant car cela ne semble pas nécessaire dans le cas présent.
  event_done: legrand_done
  write_if_equal: false

EDIT 01/10/2024

Oubliez tout ça, il y a enfin quelqu'un qui a écrit un custon quirk. Et ça change tout ! Qu'il en soit remercié !

Bonus

Sur le même principe il est possible de configurer le comportement de la Led. Ca ne m'a pas intéressé mais voici les valeurs.

    {"endpoint" : 1,"cluster":64513,"attribute":1,"manufacturer":64513,"name":"Led dark","type":"select","values":[{"value":0,"name":"Off"},{"value":1,"name":"On"}]}
    {"endpoint" : 1,"cluster":64513,"attribute":2,"manufacturer":64513,"name":"Led if on","type":"select","values":[{"value":0,"name":"Off"},{"value":1,"name":"On"}]}

Consommation

Pour l'instant l'intégration ne présente que la puissance en W ou A (encore que je n'ai pas testé). Je vais voir quand j'aurais du temps si on peut ajouter le cumul en kWh, mais c'est toujours possible sous HA avec Reiman ou Powercalc. Voici avec Powercalc qui s'il est bien configuré a l'avantage de créer les utilility_meter: à coller dans Energy...

sensor:
  - platform: powercalc
    name: ECS
    entity_id: switch.legrand_ecs
    power_sensor_id: sensor.legrand_ecs_active_power

J'ai passé pas mal de temps (trop car j'ai aussi un job...) sur cette affaire, mais ça m'a permis d'explorer un peu les possibilité de ZHA Toolkit et comprendre qu'il est possible d'intégrer des objets ou des fonctions non reconnues.

Le cas de la sortie de câble connectée

Dans le même genre on trouve une sortie de câble connectée sous différentes références (0 648 79/82/83/98). Ici encore l'intégration ZHA est très incomplète, contrairement à Z2M comme on peut le voir ici. En effet ce module supporte plusieurs modes, alors que le seul appairage est géré directement sous ZHA, ainsi que la puissance instantanée en watts.

Mode dimmer : (ce mode nécessite un firmware récent)

  • 0x0100 : dimmer_on :
  • 0x0100 : dimmer_off

Mode contacteur :

  • 0x0003 : mode switch : Fonctionnement en on/off
  • 0x0004 : mode auto : Fonctionnement en auto, je suppose en HP/HC mais il n'y a pas d'entrée pour le pilotage. Ou domotique Legrand...

Mode fil pilote : (pilot wire)

  • 0x0002 : pilot_on :  Attente des commandes
  • 0x0001 : pilot_off :  Désactivation, on repasse en on/off ?

L'idée est bien sur de contourner ce manque, et si c'est faisable avec Z2M, il n'y a pas de raisons de ne pas y parvenir avec ZHA afin de pouvoir soutenir cet objet sur des installations les plus légères possible.

Changer de mode

service: zha_toolkit.attr_write
data:
  ieee: 00:04:74:00:00:23:3d:b5
  cluster: 64513
  attribute: 0
  manf: 4129
  attr_type: 9
  attr_val:
    - 2      #  Pilot Wire mode
    - 0
  event_done: legrand_done

Piloter un convecteur disposant d'un fil pilote

Le fil pilote est un truc bien Français né de l'abondance de l'électricité atomique qu'il fallait alors promouvoir. Pour faire simple on envoie des commandes qui vont faire adopter une consigne pré réglée sur le convecteurs et qui interagira avec la sonde interne. Bien sur la sonde interne est nécessairement faussée car trop proche des éléments d chauffe. C'est pourquoi sous Home Assistant on dispose de plusieurs composant de thermostats virtuel (le tout dernier est ici) plus ou moins évolués, mais qui se basent sur une sonde externe bin plus réaliste de la température ambiante.

Avec un convecteur ainsi piloté, on peu don soit envoyer des commandes prédéfinie, soit faire un fake switch avec confort (une sorte de on avec un préréglage haut sur le convecteur) et off et le piloter avec un thermostat virtuel.

Il faut savoir qu'un convecteur avec fil pilote ne répond pas à un simple on/off (sauf à insérer une diode dans le circuit). Il va donc falloir sous ZHA pouvoir envoyer les bonnes commandes, et à minima Confort et Off.

Commandes disponibles :

  • 0x00 : Confort
  • 0x01 : Confort -1
  • 0x02 : Confort -2
  • 0x03 : Eco
  • 0x04 : Hors Gel
  • 0x05 : Off

Il ne s'agit pas ici d'écrire un attribut comme pour changer le mode, mais d'envoyer une commande. Et c'est ici que ça se complique

service: zha_toolkit.zcl_cmd
data:
  ieee: 00:04:74:00:00:23:3d:b5
  cmd: 0
  args: [3]
  cluster: 64576
  endpoint: 1
  manf:  0x1021
  event_done: legrand_done

Ensuite on peut lire l'attribut afin de considérer que la commande est acceptée :

service: zha_toolkit.attr_read
data:
  ieee: 00:04:74:00:00:23:3d:b5
  endpoint: 1
  cluster: 64576
  attribute: 0
  event_done: legrand_done

Ce qui va nous retourner :

event_type: legrand_done
data:
  zha_toolkit_version: v0.8.35
  zigpy_version: 0.53.0
  zigpy_rf_version: 0.9.2
  ieee_org:
    - 181
    - 61
    - 35
    - 0
    - 0
    - 116
    - 4
    - 0
  ieee: 00:04:74:00:00:23:3d:b5
  command: attr_read
  command_data: null
  start_time: "2023-02-17T14:54:41.625317+00:00"
  errors: []
  params:
    cluster_id: 64576
    attr_id: 0
    dir: 0
    manf: 4129
    tries: 1
    expect_reply: true
    args: []
    state_id: var.legrand
    state_attr: unique_attr_name_for_ieee
    allow_create: true
    event_done: legrand_done
    read_before_write: true
    read_after_write: true
  attr_type: "0x30"
  write_is_equal: false
  result_read:
    - "0": 5
    - {}
  success: true
origin: LOCAL
time_fired: "2023-02-17T14:54:41.737600+00:00"
context:
  id: 01GSFXXJJ9GYVB5E0S54DVB2YP
  parent_id: null
  user_id: null

Afin de pouvoir l'exploiter on va écrire le résultat dans un état :

service: zha_toolkit.attr_read
data:
  ieee: 00:04:74:00:00:23:3d:b5
  cluster: 0xFC40
  attribute: 0
  manf:  0x1021
  event_done: legrand_done
  state_id: var.legrand
  state_attr: unique_attr_name_for_ieee
  allow_create: true          

Que l'on pourra plus facilement lire :

"{{ is_state_attr('var.legrand', 'unique_attr_name_for_ieee', 5) }}"

Fake Switch

Etant donné que je ne vais pas utiliser le fil pilote autrement que pour faire du on/off afin de commander mon convecteur par un thermostat virtuel associé à une sonde externe, il me faut un switch: à associer au thermostat.

Je vais commencer par faire deux scripts: ON et OFF. Ceux ci ont deux fonction :

  • Envoyer la commande Confort ou OFF
  • Lire l'état afin de confirmer sa prise en compte
script:
  pilot_wire_on:
    alias: "Pilot Wire ON"
    sequence:
      - service: zha_toolkit.zcl_cmd
        data:
          ieee: 00:04:74:00:00:23:3d:b5
          cmd: 0
          args: '0'
          cluster: 64576
          endpoint: 1
          manf:  0x1021
          event_done: legrand_done     
      - service: zha_toolkit.attr_read
        data:
          ieee: 00:04:74:00:00:23:3d:b5
          cluster: 0xFC40
          attribute: 0
          manf:  0x1021
          event_done: legrand_done
          state_id: var.legrand
          state_attr: unique_attr_name_for_ieee
          allow_create: true

Ensuite je crée mon switch: virtuel (pour l'instant je n'ai pas trouvé mieux que de l'associer à un input_boolean: ... à retravailler) :

input_boolean:
  dummy:

switch:
  - platform: template
    switches:
      pilot_wire_sdb:
        friendly_name: 'Convecteur : Salle de Bain'
        # value_template: "{{ is_state('switch.pilot_wire_sdb', 'on') }}"
        value_template: "{{ is_state('input_boolean.dummy', 'on') }}"
        turn_on:
          - service: input_boolean.turn_on
            entity_id: input_boolean.dummy
          - service: script.pilot_wire_on

        turn_off:
          - service: input_boolean.turn_off
            entity_id: input_boolean.dummy          
          - service: script.pilot_wire_off

Et pour terminer je vais créer un binary_sensor: qui va me permettre d'afficher l'état réel en fonction de la lecture :

template:
  - trigger:
      - platform: event
        event_type: legrand_done
        event_data:
          ieee: 00:04:74:00:00:23:3d:b5
          command: attr_read
      - platform: state
        entity_id: binary_sensor.pilot_wire_3
        to: "off"
    binary_sensor:
      name: pilot_wire_3
      icon: "{{ (is_state_attr('var.legrand', 'unique_attr_name_for_ieee', 5)) | iif('mdi:radiator', 'mdi:radiator-off') }}"
      state: "{{ is_state_attr('var.legrand', 'unique_attr_name_for_ieee', 5) }}"

Pour l'instant la puissance en watts (entre autres mais c'est celle ci qui serait utile) ne remonte pas. Je continue à chercher, mais sur une charge fixe, un convecteur par exemple, le contournement simple consiste à utiliser PowerCalc pour la déduire...

Tout cela est certainement perfectible, mais ça nous donne les base pour exploiter totalement ce couteux objet ! En attendant une hypothétique réelle intégration, comme cela a été fait sous Z2M.

Un grand merci à Mario, l'auteur de ZHA Toolkit, pour sa grande patience !

Liens

En vrac, mes sources :