Home Assistant & ZigBee

ZigBee est un protocole de haut niveau permettant la communication d'équipements personnels ou domestiques équipés de petits émetteurs radios à faible consommation ; il est basé sur la norme IEEE 802.15.4 pour les réseaux à dimension personnelle (Wireless Personal Area Networks : WPAN). Wikipédia et Google vous raconteront le reste... Mais sous Home Assistant il y (principalement) trois façons d'approcher Zigbee :

Deconz / Phoscon

La clé Combee II dépend ici de l’environnement logiciel de son éditeur, qu'il soit installé de façon indépendante ou plus ou moins mergé à Home Assistant (ou une autre solution). C'est donc une une solution qui peut s'utiliser de façon autonome, ce qui était leur but de départ, remplacer simplement quelques passerelles propriétaires (Hue, Ikea, etc..). ils fournisse d'ailleurs des images RPI pour se passer de leur boitier et c'’est d'ailleurs ainsi que je l'avait monté sur un RPI2 auquel j'accédait depuis Jeedom, et auquel j'accède maintenant avec Home Assistant.

Le fait que ce soit autonome permet de réaliser des opérations sans passer par une plateforme domotique, tout en disposant des équipements sur une ou plusieurs solutions domotique. Par exemple, pour associer un interrupteur avec une ampoule, il est plus simple de le faire sous Phoscon, sachant que de toutes façons l'état de l'ampoule remontera dans Home Assistant et que je pourrais toujours l'éteindre avec une automation...

Enfin, les équipements sont également accessibles en parallèle depuis Alexa...

C’est donc la solution la plus proche d'une passerelle propriétaire, de ses avantages, de sa façon de fonctionner et d'évoluer. C’est celle que je conseillerais pour installer un HA chez un tiers, la plus grand public qui s'appuie sur des équipements l'ont peut facilement acquérir dans le commerce.

ZHA

Zigbee Home Automation est la solution la plus intégrée à Home Assistant. Elle s'appuie sur à peu près toutes les clés Zigbee du marché et fonctionne plutôt bien. Par contre ici on est sur une intégration fermée dans et pour HA. Elle supporte (à titre expérimental) même la Zigate dont j'avais fini par me débarrasser sous Jeedom...

Rien à ajouter de plus, pour faire simple et rester dans HA c’est la solution à adopter et l'on retrouvera les menus de configurations dans la configuration HA

zigbee2mqtt

C'est la solution à la mode, parce que MQTT est à la mode. Mais au delà de l'effet de mode, MQTT est le protocole qui fait son chemin et risque de devenir un standard bien au delà de nos petits bricolages domotique. Ici on passe par une passerelle que l'on va monter ou on le souhaite (RPI Zero indépendant, HA remote, etc...), qui va transmettre ses infos à un brooker qui lui aussi peut être n'importe ou (LAN/WAN) et notre HA ne sera qu'un client de ce brooker. L'étape suivante étant bien sur que les équipements intègrent ce protocole, ça arrive, notamment sur du DIY avec le firmware Tasmota et on peut imaginer que le marché adopte MQTT, c’est d'ailleurs le cas des équipements Shelly en WI-FI qui proposent (timidement) ce protocole de façon native, ou d'autres passerelles comme ble2mqtt...

Pour revenir à zigbee2mqtt le projet est très actif, plutot stable et c'est par exemple le seul qui propose les mises à jours bios de certains équipements. Pour ce test je l'ai monté sur un HA remote et j'ai utilisé une intégration sous forme d'addon. En fait simplement parce que j'avais ce HA remote sous la main, mais pour le coup la com ne se fait pas en remote mais en MQTT. C'est une solution ultra paramétrable, chaque équipement est ajustable à la source et les infos remonteront vers les clients, je dis bien les clients car on peut tout à fait imaginer qu'in équipement soit utilisable avec plusieurs solutions, un capteur de température vu par HA mais aussi par une solution externe, etc...

A noter que contrairement aux deux précédentes solution j'ai bien la remontée de l'état des piles sur les révisions récentes (fin 2019) des capteurs Aqara, ce n'est toujours pas les cas des deux solutions concurrentes, preuve de plus que le projet est très actif.

Enfin zigbee2mqtt s'appuie sur une clé DIY, ce qui veut dire qu'il faudra bricoler un peu et acheter quelques accessoires. Mais ça reste easy !

EDIT 22/01/2021 : Pensez à mettre à jour le firmware de vos clés, ça fonctionnera mieux avec les dernières versions...

Alternatives...

D'autres continuent à utiliser l'intégration Xiaomi avec la passerelle de première génération. Ça fonctionne, mais pour moi ce n'est pas une solution Zigbee, mais une solution Xiaomi qui repose sur l'utilisation d'un serveur Chinois, dépendant de la volonté de Xiaomi d'en laisser l'usage détourné possible, voire de la Chine de laisser passer ou non les flux. Si le fonctionnement se fait en local, c’est également un potentiel cheval de Troie, mais ça c'est un autre débat. Vous aurez compris que je ne suis pas fan.

EDIT 22/01/2021 : SLS, vous risquez d'en entendre parler cette année...

Conclusion

Conclusion il faut choisir. Choisir n'est jamais simple, et en l'espèce ce n'est pas moi qui vais vous dire quoi choisir ! Il faut tout de même savoir que si les produits les plus courants sont supportés par toutes les solutions, d'autres plus confidentiels ne le seront que par l'une ou l'autre.

Sources

 

Home Assistant et les coupures électriques

Pour surveiller des parties de mon réseau électrique, on va dire chaque rangées de mon tableau, j'utilisais auparavant des modules ITS23 en 433 Mhz. qui fonctionnait sur piles et envoyaient une alerte en cas de coupure. Exit le 433 Mhz, je cherche donc une solution alternative adaptée à Home Assistant, l'idée étant de recevoir un SMS si le différentiel qui alimente le congélateur tombe à cause d'un orage par exemple... Sachant que pour une coupure générale j'ai la remontée SNMP des onduleurs...

Vu que j'ai des modules Shelly un peu partout, je me suis dit que ce serait une bonne piste...

Ping

Avec l'intégration ping: il est facilement possible de surveiller et d'alerter. Hélas, il arrive parfois que ça fasse de faux positifs, peut être si le ping se fait à un moment ou le Shelly fait une maintenance ? Il doit y avoir moyen de consolider ça avec un template pour prendre en compte une période plus large de test. On crée un binary_sensor: et si off on envoie une notification avec une petite automation.

- platform: ping
  host: 192.168.210.31
  name: Switchboard 1
  count: 2

MQTT

On peut activer MQTT et ainsi avoir un retour du status online. Mais activer MQTT fait sauter le Cloud Shelly et devient impossible de piloter les équipements depuis Alexa... Ici aussi un binary_sensor: et si off on envoie une notification avec une petite automation.

- platform: mqtt
  name: "Shelly Plug 2"
  state_topic: "shellies/shellyplug-s-51xx67/relay/0"
  payload_on: "on"
  payload_off: "off"
  availability_topic: "shellies/shellyplug-s-51xx67/online"
  payload_available: "true"
  payload_not_available: "false"
  qos: 1
  device_class: power

Les attributs

Un Shelly, ou d'autres modules, retournent plusieurs attributs qui passeront à indisponible si le Shelly n'est plus alimenté. Reste à faire un template pour palier à une indisponibilité temporaire...

 
shelly_type: Shelly 1 PM
shelly_id: 76xx39
ip_address: 192.168.210.119
protocols:
  - CoAP-msg
  - poll
  - mDns
  - CoAP-discovery
over_temp: false
has_firmware_update: false
cloud_status: connected
switch: false
over_power: false
friendly_name: Shelly 1 PM - 76xx39
 
Ensuite on va bricoler un peu pour tester un des attributs, temporiser et notifier...

Le Graal !

Tout en cherchant je me disais qu'il devait bien y avoir quelque part une solution clé en main sous Home Assistant. J'ai commencé par trouver ce projet qui peut s'avérer très intéressant, mais c’est une brique en plus et je ne sais pas comment il sera maintenu. Et puis je suis tombé sur l'intégration alert: qui sera parfaite pour ce boulot !
tableau_1:
  name: Diff 1 is down
  entity_id: switch.shelly_1_fp
  state: 'unavailable'   # Optional, 'on' is the default value
  repeat:
    - 10
    - 30
    - 60
    - 300
  can_acknowledge: true  # Optional, default is true
  skip_first: true  # Optional, false is the default
  message: "{{ states.sensor.date_time.state}} > ALERTE | Différentiel 1 : OFF"
  done_message: "{{ states.sensor.date_time.state}} > ALERTE | Différentiel 1 : OK"
  notifiers:
    - slack_hass_canaletto
    - free_mobile
Je ne notifie pas tout de suite, j'attends 10 minutes et je répète ensuite quelquefois... Simple et efficace, on peut également s'en servir pour notifier autre chose, en combinaison avec un Template pour surveiller les piles ou pour garder un œil sur un capteurs capricieux...
 
 
 
 

 

 

Home Assistant & Google Agenda

Dans plusieurs articles je vous ai beaucoup parlé de planification. Simplement parce que quand on veut gérer du chauffage électrique c’est une composante obligatoire. J'avais d'abord reproché à HA de ne pas proposer un véritable agenda, j'ai écarté l'agenda Google pour ne pas être dépendant du net et j'ai ainsi pu constater qu'il était possible de définir ses propres planifications, du véritable sur mesure, interface comprise. C’est un peu lourd à faire, mais HA permet de faire absolument tout ce que l'on souhaite.

Et puis je me suis retrouvé sur une planification un peu plus complexe, et comme je suis un peu flemmard et que je voulais laisser à son utilisateur une grande part de liberté, je suis allé explorer Google Agenda. Et ma première surprise a été que cette intégration n'est pas totalement dépendante du net. En effet HA synchronise l'agenda et en conserve les entrées sur une durée configurable. Ce qui veut dire qu'il est possible d'envisager un cache local qui nous permettra une déconnexion plus ou moins longue du cloud. Donc dans ces conditions c'est jouable.

Préparation

Google Agenda sous HA fait partie des intégrations de base. Donc rien à ajouter si ce n'est une carte spécialisée (ou celle-ci) si l'on souhaite un visuel. Par contre il va falloir activer l'API Google Agenda sur la console développeur de votre compte Google comme indiqué sur l'intégration. Une fois que l'on a notre clé API et son secret on crée cette entrée dans le fichier de configuration.

google:
  client_id: !secret google_api_id
  client_secret: !secret google_api_secret
  track_new_calendar: true
google:
  client_id: !secret google_api_id
  client_secret: !secret google_api_secret
  track_new_calendar: true

Après avoir redémarré HA on doit se retrouver avec un fichier google_calendars.yaml qui contiendra lune entrée pour chaque calendriers. On pourra y ajouter une entré max_results: pour choisir le nombre de résultats synchronisés par calendrier qui par défaut est de 5.

- cal_id: [email protected]
  entities:
  - device_id: thermostat_bureau
    ignore_availability: true
    name: Thermostat (Bureau)
    track: true
    max_results: 7

Pour ma part j'ai fait le choix de créer un calendrier Google par thermostat, mais il est possible de les superposer, on peut également n'en utiliser qu'un seul, mais choisissez d'en créer un en plus de celui de base, même si aujourd'hui vous ne l'utilisez pas.

A partir de là on peut ajouter notre carte Lovelace et visualiser nos entrées. On notera le spider présent sur les événements en cours.

Maintenant il va falloir s'en servir pour des automations. Pour chaque événement on va disposer de plusieurs informations qui seront utilisables, soit directement, soit grâce à des templates :

message: Salle d'Eau
all_day: false
start_time: '2020-05-17 02:30:00'
end_time: '2020-05-17 03:00:00'
location: ''
description: '23'
offset_reached: false
friendly_name: Thermostat (SdB)

Ce qui va correspondre à :

Le message: correspond à l'entrée de l'agenda, on va pouvoir y coller plusieurs informations exploitables par un template, ou faire le choix plus esthétique de coller ces information dans le champs description: qui lui ne sera pas visible directement dans l'agenda Google ou sa réplique dans HA. Ici j'ai juste mis "23" pour indiquer que je vais passer mon thermostat à la température de consigne de 23°. Mais j'airais pu ajouter d'autres mots clé pour y associer d'autres actions à déclencher, voire utiliser un lieu, ce qui peut être intéressant pour des interactions liées à la géolocalisation. On est donc face à une solution souple et sans limites.

Exploitation

On va maintenant passer à l’exploitation en tant que trigger dans une automation. On peut le faire de façon simple avec le passage d'un état sur on ou sur off, ou plus complexe en décodant des informations liées grâce à un template, informations utilisables également en tant que condition ou pour des actions, voire pour créer un sensor: ou un binary-sensor: ce qui laisse pas mal de liberté en fonction des besoins et de l'imagination de chacun.

  trigger:
    platform: state
    entity_id: calendar.thermostat_andre
    to: 'on'

Ici par exemple je vérifie si une température est disponible dans le champ d'information avec un simple test > à 0, et dans le cas contraire j'applique la consigne globale définie dans un input_number:

  action:
  - service: climate.set_temperature
    entity_id: climate.thermostat_andre
    data_template:
      temperature: '{% if states.calendar.thermostat_andre.attributes.description | float > 0 %}
                      {{ states.calendar.thermostat_andre.attributes.description }}
                    {% else %}
                      {{ states.input_number.consigne_confort.state }} 
                    {% endif %}'

J'aurais bien entendu pu définir une autre option pour déclencher par exemple un ventilateur... seulement si la température est de de...

Restrictions

Il y a une chose que je n'ai pas vraiment résolue. Les jours fériés. J'aurais voulut appliquer la programmation du dimanche aux jours fériés. Pour ça sous HA on dispose de workday: qui fait très bien son job, mais sans y passer beaucoup de temps je n'ai pas trouvé une façon simple de le faire.

J'ai donc opté pour une solution de contournement. Il est très facile sous Google Agenda de superposer les calendriers, donc le plus simple est de superposer le calendrier des jours fériés à mes autres agendas et ainsi d'aller modifier manuellement les entrés répétés qui tombent sur un jour férié et bien sur de sauvegarder uniquement cette entrée. Le choix d'une tache manuelle à répéter chaque année en attendant de trouver mieux !

Inspirations

Une autre possibilité offerte par cette intégration nous permettre d'automatiser la création d’événement depuis Home Assistant. Pour quoi faire ? Pour l’heure je n'en sait rien, mais ça peut être une possibilité intéressante...

Alternatives

J'ai fait la même chose avec Microsoft 365. Ça fonctionne, un peu moins réactif, mais ça je pense que ça vient du composant. Par contre certains disent que l'API est moins stable, plus jeune, et nécessite plus souvent l'intervention des développeurs du composant. De toutes façons chaque dépendance extérieure affaiblit un système, quel qu'il soit.

Conclusion

Çà fait le job et même bien. Je regrette un peu de ne pas avoir testé avant, mais seulement un peu car faire tous ça à la main m'a permis de beaucoup explorer et d'apprendre plein de choses !

Edit

Il n'y a pas que Google Agenda dans la vie, allez voir ce projet de scheduler très prometteur...

Sources

 

Home Assistant & Energie

Jadis certains justifiaient l'achat d'un ordinateur personnel par la gestion des comptes familiaux, aujourd’hui d'autres viennent à la domotique en espérant faire des économies. Soyons sérieux, la domotique ça coûte de l'argent et il faut y venir dans un objectif de confort ! Il n'en reste pas moins que l'on peut s'amuser à calculer ce que l'on consomme, c’est ce que je vais vous montrer ici.

Home assistant dispose d'une fonctionnalité de base nommée utility_meter: Il s'agit en fait de compteurs qui fonctionnent en cycles (heure, jour, mois, trimestre, année), pour l'instant il manque le mode bi-mensuel et un mode paramétrable. L'idée est de se calquer sur une facturation, ou de créer une facturation, pour une location par exemple. Ce capteur suivra les valeurs d'un capteur source, réinitialisant automatiquement le compteur en fonction du cycle configuré. Lors de la réinitialisation, on stockera la valeur précédente du compteur, fournissant les moyens d'effectuer des opérations de comparaison (par exemple, "ai-je dépensé plus ou moins ce mois-ci?"), ou d'estimation de facturation. Certains fournisseurs de services ont des tarifs différents en fonction du temps / de la disponibilité des ressources / etc. Le compteur de services publics vous permet de définir les différents tarifs pris en charge par votre fournisseur. Lorsque les tarifs sont définis, une nouvelle entité apparaîtra indiquant le tarif actuel. Pour modifier le tarif, l'utilisateur doit appeler un service, généralement via une automatisation qui peut être basée sur le temps ou sur une autre source externe (par exemple un capteur REST).

Je n'ai pas trouvé beaucoup d'informations et j'y ai passé d'autant plus de temps que j'ai voulu l'adapter à mon abonnement électrique. Le plus simple ou j'ai deux tarifs, les Heures Pleines de 05:00 à 21:30, le reste étant des Heures Creuses (HC). Il est toutefois possible d'adapter facilement tout ça à des tarifs plus complexes comme Tempo ou EJP.

La première chose à faire est de décortiquer la facture EdF afin d'obtenir les valeurs de base. Pour cela chacun fera appel à Excel car au delà des tarifs fixes du kWh il existe un certain nombre de taxes locales et régionales qui font qu'en France personne ne paie vraiment son Electricité au même prix.

La liste des courses

Pour compter il va nous falloir un sensor: qui sache nous remonter cette information. J'ai pour ma part utilisé un Shelly EM, il propose deux comptages et on va ici utiliser uniquement le premier que j'ai branché sur l'arrivée EdF de la maison. Il y a plusieurs façons d'en extraire les informations (Intégration, MQTT, ...) ici je vais créer un sensor rest, simplement car c’est le premier exemple que j'ai trouvé et que c'est resté ainsi.

    - platform: rest
      name: Shelly EM EdF # Général
      resource: http://192.168.210.111/status
      # username: !secret shelly_usr
      # password: !secret shelly_pwd
      authentication: basic
      value_template: '{{ (value_json.emeters.0.total | float /1000)|round(3) }}' # Wh to kWh
      scan_interval: 300 # no point updating faster than this. The Shelly only updates every 5 minutes
      unit_of_measurement: kWh

Ensuite on va créer nos utility_meter:, dans mon ça j'en ai créé 5, ce qui va me permettre de gérer le jour, la semaine, le mois, le trimestre et l'année en cours. Ces compteurs se remettrons à zéro en début de cycle et si l'on souhaite traiter les informations au delà il conviendra d'en sauvegarder les valeurs dans un fichier extere (.CSV par exemple) ou une BDD.

utility_meter:
  energy_total_usage_daily:
    source: sensor.shelly_em_edf
    cycle: daily
    tariffs:
      - day
      - night

  energy_total_usage_weekly:
    source: sensor.shelly_em_edf
    cycle: weekly
    tariffs:
      - day
      - night

  energy_total_usage_monthly:
    source: sensor.shelly_em_edf
    cycle: monthly
    tariffs:
      - day
      - night

  energy_total_usage_quarterly:
    source: sensor.shelly_em_edf
    cycle: quarterly
    tariffs:
      - day
      - night

  energy_total_usage_yearly:
    source: sensor.shelly_em_edf
    cycle: yearly
    tariffs:
      - day
      - night

Comme vous le voyez j'ai créé deux tarifs, ne me demandez pas pourquoi je les ai nommés Jour et Nuit, mais en fait cela correspond à HP et HC que l'on retrouvera plus loin. Mais comme j'ai créé deux tarifs il va me falloir faire l'addition des deux comptages pour obtenir la consommation de la journée en kWH si je le souhaite. Dans l'absolu c’est inutile car le but est d'avoir des valeurs finales en Euros...

Pour faire tous nos calculs on va se servir de sensors et de templates, là ou systèmes auraient utilisé des scénarios et des variable. Bref, peu importe, ce qui compte c’est le résultat et que ce résultat soit dynamique. Voici donc de quoi obtenir la conso journalière en kWH dans un sensor, une simple addition qu'il conviendra de dupliquer pour les différentes périodes :

    - platform: template # Consommation journalière HP + HC
      sensors:
        energy_total_daily:
          friendly_name: 'Energie journalière consommée'
          entity_id:
            - sensor.energy_total_usage_daily_day
            - sensor.energy_total_usage_daily_night
          value_template: "{{ (states('sensor.energy_total_usage_daily_day')|float + states('sensor.energy_total_usage_daily_night')|float)|round(3) }}"
          unit_of_measurement: "kWh"

Ensuite on va créer d'autres sensor: afin de passer aux euros... Mais avant on va définir quelques input_number: afin d'y saisir les valeurs du prix du kWh et de l'abonnement au prorata des périodes HP et HC. Valeurs que l'on saisira dans une carte Lovelace que l'on verra plus loin.

  hp_daily_cost:
    name: HP - Cout journalier
    mode: box
    min: 0
    max: 100
    unit_of_measurement: "€/day"
    icon: mdi:currency-eur

  hp_energy_cost:
    name: HP - Coût du Kwh
    mode: box
    min: 0
    max: 100
    unit_of_measurement: "€/kWh"
    icon: mdi:currency-eur

  hc_daily_cost:
    name: HC - Cout journalier
    mode: box
    min: 0
    max: 100
    unit_of_measurement: "€/day"
    icon: mdi:currency-eur

  hc_energy_cost:
    name: HC - Coût du Kwh
    mode: box
    min: 0
    max: 100
    unit_of_measurement: "€/kWh"
    icon: mdi:currency-eur

Maintenant que l'on dispose de valeurs en kWh et de coûts on va pouvoir calculer ce que l'on consomme en HP et HC et additionner le tout pour obtenir une résultat journalier. Pour cela on va créer 3 sensor / template. On reste toujours sur la journée mais il faudra le dupliquer pour les autres cycles.

    - platform: template # Coût journalier HP
      sensors:
        hp_cost_today:
          friendly_name: 'HP Cost Today'
          entity_id:
            - sensor.energy_total_usage_daily_day
            - input_number.hp_daily_cost
            - input_number.hp_energy_cost
          value_template: "{{ (states('sensor.energy_total_usage_daily_day')|float * states('input_number.hp_energy_cost')|float + states('input_number.hp_daily_cost')|float)|round(2) }}"
          unit_of_measurement: "€"

    - platform: template # Coût journalier HC
      sensors:
        hc_cost_today:
          friendly_name: 'HC Cost Today'
          entity_id:
            - sensor.energy_total_usage_daily_night
            - input_number.hc_daily_cost
            - input_number.hc_energy_cost
          value_template: "{{ (states('sensor.energy_total_usage_daily_night')|float * states('input_number.hc_energy_cost')|float + states('input_number.hc_daily_cost')|float)|round(2) }}"
          unit_of_measurement: "€"

    - platform: template # Coût journalier HP + HC
      sensors:
        cost_today:
          friendly_name: "Aujourd'hui"
          entity_id:
            - sensor.hp_cost_today
            - sensor.hc_cost_today
          value_template: "{{ (states('sensor.hp_cost_today')|float + states('sensor.hc_cost_today')|float)|round(2) }}"
          unit_of_measurement: "€"

Je la fait un peu à l'envers, mais maintenant qu'on a nos bases de calculs on va avoir besoin de quelques automations, les deux premières vont nous servir à basculer nos UM entre HP et HC, un peu comme le faisait le fil signal fourni par EdF pour actionner le chauffe eau en heures creuses...

- id: set_night
  alias: 'Set Night'
  initial_state: true
  trigger:
    platform: time
    at: '21:30:00'
  action:
  - service: utility_meter.select_tariff ###### On passe en HC (nuit)
    data:
      entity_id:
      - utility_meter.energy_total_usage_daily
      - utility_meter.energy_total_usage_weekly
      - utility_meter.energy_total_usage_monthly
      - utility_meter.energy_total_usage_quarterly
      - utility_meter.energy_total_usage_yearly
      tariff: night

- id: set_day
  alias: 'Set Day'
  initial_state: true
  trigger:
    platform: time
    at: '05:00:00'
  action:
  - service: utility_meter.select_tariff ###### On passe en HP (jour)
    data:
      entity_id:
      - utility_meter.energy_total_usage_daily
      - utility_meter.energy_total_usage_weekly
      - utility_meter.energy_total_usage_monthly
      - utility_meter.energy_total_usage_quarterly
      - utility_meter.energy_total_usage_yearly
      tariff: day

Ensuite on va créer deux input_number: que l'on utilisera avec l'automation suivante pour conserver le coût cumulé et les coûts de la journée précédente. Encore une fois ce ne sont que des exemples, le reste étant à votre imagination...

  cumulative_energy_cost:
    name: Cumulative Energy Cost
    mode: box
    min: 0
    max: 5000
    unit_of_measurement: "€"
    icon: mdi:currency-eur

  yesterday_energy_cost:
    name: Yesterday Energy Cost
    mode: box
    min: 0
    max: 5000
    unit_of_measurement: "€"
    icon: mdi:currency-eur

Et comme un input_number: c’est pas joli sur Lovelace, on va leur associer des sensor:

    - platform: template # pour lovelace display à partir de l'input_number mis à jour à 23.59
      sensors:
        cost_yesterday_display:
          friendly_name: "Hier"
          entity_id:
            - input_number.yesterday_energy_cost
          value_template: "{{ (states('input_number.yesterday_energy_cost')|float)|round(2) }}"
          unit_of_measurement: "€"

L'automation finale que vous adapterez à vos envies et que l'on déclenchera en fin de journée va nous servir à plusieurs choses :

  • Stocker le cumul de consommation
  • Stocker le coût de la journée précédente
  • Envoyer une notification anxiogène sur ce que l'on vient de consommer...
  • Enregistrer un log avec toutes les valeurs possibles et imaginables...
- id: daily_energy_use_message
  alias: '000 - Daily Energy Use Message'
  trigger:
    platform: time
    at: '23:59:50'
  action:
  - service: input_number.set_value # Stocker le cumul de consommation...
    data_template:
      entity_id: input_number.cumulative_energy_cost
      value: "{{ states('input_number.cumulative_energy_cost')|float + states('sensor.cost_today')|float }}"

  - service: input_number.set_value # Stocker le coût de la journée précédente
    data_template:
      entity_id: input_number.yesterday_energy_cost
      value: "{{ states('sensor.cost_today')|float }}"

  - service: notify.slack_hass_canaletto
    data_template:
      title: '*Information*' # Envoyer un message en fin de journée...
      message: "La consommation de la journée écoulée est de {{ states('sensor.energy_total_daily') }} kWh., soit {{ states('sensor.cost_yesterday_display') }} €"

  - service: notify.file_notify_power # Ecrire un log exploitable dans un fichier .csv
    data_template:
      message: "{{ states('sensor.date') }},{{ states('sensor.energy_total_usage_daily_day') }},{{ states('sensor.energy_total_usage_daily_night') }},{{ states('sensor.energy_total_daily') }},{{ states('sensor.cost_today') }}"

Et ainsi recevoir un message du genre...

La consommation de la journée écoulée est de 25.561 kWh., soit 4.56 €

Voila pour le code. Maintenant on dispose de plein de nouveaux sensor: que l'on va pouvoir exploiter dans d'autres automations à imaginer, mais on va commencer par afficher ces informations sur une carte Lovelace et faire quelques graphiques... Comme c'est riche en formation j'ai choisi une carte qui se déplie, Fold-Entity-Row, et Multiple-Entity-Row pour compacter un peu les informations et dont voici le code :

entities:
  - entity: utility_meter.energy_total_usage_daily
    name: Tarif actuel
  - label: 'Coûts HP / HC :'
    type: section
  - entities:
      - entity: sensor.hp_cost_today
        name: HP
      - entity: sensor.hc_cost_today
        name: HC
    entity: sensor.cost_today
    icon: 'mdi:currency-eur'
    name: Journée en cours
    secondary_info: last-changed
    show_state: false
    type: 'custom:multiple-entity-row'
  - entities:
      - entity: sensor.hp_cost_weekly
        name: HP
      - entity: sensor.hc_cost_weekly
        name: HC
    entity: sensor.cost_weekly
    icon: 'mdi:currency-eur'
    name: Semaine en cours
    secondary_info: last-changed
    show_state: false
    type: 'custom:multiple-entity-row'
  - entities:
      - entity: sensor.hp_cost_monthly
        name: HP
      - entity: sensor.hc_cost_monthly
        name: HC
    entity: sensor.cost_monthly
    icon: 'mdi:currency-eur'
    name: Mois en cours
    secondary_info: last-changed
    show_state: false
    type: 'custom:multiple-entity-row'
  - entities:
      - entity: sensor.hp_cost_quarterly
        name: HP
      - entity: sensor.hc_cost_quarterly
        name: HC
    entity: sensor.cost_quarterly
    icon: 'mdi:currency-eur'
    name: Trimestre en cours
    secondary_info: last-changed
    show_state: false
    type: 'custom:multiple-entity-row'
  - entities:
      - entity: sensor.hp_cost_yearly
        name: HP
      - entity: sensor.hc_cost_yearly
        name: HC
    entity: sensor.cost_yearly
    icon: 'mdi:currency-eur'
    name: Année en cours
    secondary_info: last-changed
    show_state: false
    toggle: true
    type: 'custom:multiple-entity-row'
  - label: 'Coût cummulé :'
    type: section
  - entities:
      - entity: sensor.cost_today
        name: Aujourd'hui
      - entity: sensor.cost_yesterday_display
        name: Hier
    entity: sensor.cost_yearly
    icon: 'mdi:currency-eur'
    name: Journées
    secondary_info: last-changed
    show_state: false
    toggle: true
    type: 'custom:multiple-entity-row'
  - label: 'Coût :'
    type: section
  - entity: sensor.cost_yearly
    icon: 'mdi:currency-eur'
  - entities:
      - entity: input_number.hp_daily_cost
      - entity: input_number.hp_energy_cost
      - entity: input_number.hc_daily_cost
      - entity: input_number.hc_energy_cost
    head:
      label: Tarifs EDF
      type: section
    padding: 0
    type: 'custom:fold-entity-row'
  - entities:
      - entity: utility_meter.energy_total_usage_daily
        name: Tarif actuel
      - label: Journée en cours
        type: section
      - entity: sensor.energy_total_usage_daily_day
        name: Tarif HP
      - entity: sensor.energy_total_usage_daily_night
        name: Tarif HC
      - entity: sensor.energy_total_daily
        name: Total
      - label: Semaine en cours
        type: section
      - entity: sensor.energy_total_usage_weekly_day
        name: Tarif HP
      - entity: sensor.energy_total_usage_weekly_night
        name: Tarif HC
      - entity: sensor.energy_total_weekly
        name: Total
      - label: Mois en cours
        type: section
      - entity: sensor.energy_total_usage_monthly_day
        name: Tarif HP
      - entity: sensor.energy_total_usage_monthly_night
        name: Tarif HC
      - entity: sensor.energy_total_monthly
        name: Total
      - label: Trimestre en cours
        type: section
      - entity: sensor.energy_total_usage_quarterly_day
        name: Tarif HP
      - entity: sensor.energy_total_usage_quarterly_night
        name: Tarif HC
      - entity: sensor.energy_total_quarterly
        name: Total
      - label: Année en cours
        type: section
      - entity: sensor.energy_total_usage_yearly_day
        name: Tarif HP
      - entity: sensor.energy_total_usage_yearly_night
        name: Tarfif HC
      - entity: sensor.energy_total_yearly
        name: Total
      - type: divider
      - entity: input_number.cumulative_energy_cost
      - entity: input_number.yesterday_energy_cost
    head:
      label: Compteurs d'énergie
      type: section
    padding: 0
    type: 'custom:fold-entity-row'
  - entities:
      - entity: sensor.shelly_shem_0560de_1_current_consumption
        name: 'Maison : Consommation instantanée'
      - entity: sensor.shelly_shem_0560de_1_total_consumption
        name: 'Maison : Consommation cummulée'
    head:
      label: Equipements surveillés
      type: section
    padding: 0
    type: 'custom:fold-entity-row'
show_header_toggle: false
style: |
  ha-card {
    border: solid 2px var(--primary-color);
  }
theme: teal
title: Consommation électrique
type: entities

Encore une fois c'est a adapter à vos besoins. Coté graphiques je n'ai rien inventé non plus, j'ai juste adapté ce que j'ai trouvé en me servant de Mini-Graph-Card. Pour les graphiques suivants je suis allé chercher les informations MQTT après avoir configuré le Shelly EM en MQTT vers mon broker. Mais c’est juste pour l'exemple car j'aurais tout aussi bien put utiliser les valeurs du sensor: créé par l'intégration Shelly...

    - platform: mqtt
      name: "Shelly EM : Arrivée EdF"
      state_topic: "shellies/shellyem-0560DE/emeter/0/power"
      value_template: '{{ value|round(1) }}'
      qos: 1
      unit_of_measurement: "W"
      icon: mdi:gauge

    - platform: mqtt
      name: "Shelly EM : Baie Informatique"
      state_topic: "shellies/shellyem-0560DE/emeter/1/power"
      value_template: '{{ value|round(1) }}'
      qos: 1
      unit_of_measurement: "W"
      icon: mdi:gauge

    - platform: mqtt
      name: "Shelly EM : Voltage"
      state_topic: "shellies/shellyem-0560DE/emeter/0/voltage"
      qos: 1
      unit_of_measurement: "V"
      icon: mdi:flash

Pour mettre en évidence les heures creuses, on se fait un petit binary_sensor: dédié (on pourrait s'en servir dans l'automation plus haut...).

- platform: tod
  name: Heures Creuses
  after: '21:30'
  before: '05:00'

Et pour terminer, le code de la carte qui va générer mes 3 graphiques. C’est un peu compliqué car je suis parti d'un exemple ou l'auteur, bien plus chevronné que moi s'est servi de la luminosité en temps réel pour générer des valeurs Jour et Nuit afin de calculer sa productivité en énergie solaire.

cards:
  - color_thresholds:
      - color: '#039BE5'
        value: 0
      - color: '#0da035'
        value: 600
      - color: '#e0b400'
        value: 1200
      - color: '#e45e65'
        value: 2400
    color_thresholds_transition: hard
    entities:
      - sensor.shelly_em_arrivee_edf
      - color: 'rgba(0,0,255,1)'
        entity: binary_sensor.dark_outside
        show_line: false
        y_axis: secondary
    group: false
    hour24: true
    hours_to_show: 24
    line_width: 4
    name: Total
    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'
    style: |
      ha-card {
        border: solid 2px var(--primary-color);
      }
    type: 'custom:mini-graph-card'
  - color_thresholds:
      - color: '#039BE5'
        value: 0
      - color: '#0da035'
        value: 600
      - color: '#e0b400'
        value: 1200
      - color: '#e45e65'
        value: 2400
    color_thresholds_transition: hard
    entities:
      - sensor.shelly_em_baie_informatique
      - color: 'rgba(0,0,255,1)'
        entity: binary_sensor.dark_outside
        show_line: false
        y_axis: secondary
    group: false
    hour24: true
    hours_to_show: 24
    line_width: 4
    name: Baie Informatique
    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'
    style: |
      ha-card {
        border: solid 2px var(--primary-color);
      }
    type: 'custom:mini-graph-card'
  - color_thresholds:
      - color: '#039BE5'
        value: 0
      - color: '#0da035'
        value: 600
      - color: '#e0b400'
        value: 1200
      - color: '#e45e65'
        value: 2400
    color_thresholds_transition: hard
    entities:
      - sensor.shelly_em_voltage
      - color: 'rgba(0,0,255,1)'
        entity: binary_sensor.dark_outside
        show_line: false
        y_axis: secondary
    group: false
    hour24: true
    hours_to_show: 24
    line_width: 4
    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'
    style: |
      ha-card {
        border: solid 2px var(--primary-color);
      }
    type: 'custom:mini-graph-card'
type: vertical-stack

Voilà, à vous de jouer !

Bonus

Suite à une demande : Extraction en .csv et envoie par mail.

automation:
- id: '1901208243990'
  alias: 'Energy - Sensor values to file - Day'
  description: ''
  trigger:
  - platform: time 
    at: '23:59:55'     
  condition: []
  action:
  - service: notify.file_csv_month
    data_template:
      message: '{{now().strftime("%d.%m.%Y")}};{{now().strftime("%H:%M:%S")}};{{ states.sensor.linky_3a99d205_smartenergy_metering_summation_delivered.state}};kW/h'
  mode: single

- id: '1708208243990'
  alias: 'Energy - Sensor values to file - Mouth'
  description: ''
  trigger:
  - platform: time 
    at: '23:59:55'     
  condition:
  - condition: state
    entity_id: binary_sensor.dernier_jour_du_mois
    state: 'on'  
  action:
  - service: notify.file_csv_day
    data_template:
      message: '{{now().strftime("%d.%m.%Y")}};{{now().strftime("%H:%M:%S")}};{{ states.sensor.linky_3a99d205_smartenergy_metering_summation_delivered.state}};kW/h'
  - service: notify.mail
    # data_template:
    data:
      target: 
        - [email protected]
      message: 'Linky {{ now().strftime(''%H:%M:%S'')}}'
      title: Mise à jour Linky
      data:
        images:
          - '/share/linky_month.csv'

        html: >
          <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
          <html lang="en" xmlns="http://www.w3.org/1999/xhtml">
              <head>
                  <meta charset="UTF-8">
                  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
                  <meta name="viewport" content="width=device-width, initial-scale=1.0">
                  <title>Intruder alert</title>
                  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.5/css/bootstrap.min.css">
                  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css">
                  <style type="text/css">
                      @font-face {
                        font-family: 'Open Sans';
                        font-style: normal;
                        font-weight: 300;
                        src: local('Open Sans Light'), local('OpenSans-Light'), url(http://fonts.gstatic.com/s/opensans/v13/DXI1ORHCpsQm3Vp6mXoaTZS3E-kSBmtLoNJPDtbj2Pk.ttf) format('truetype');
                      }
                      h1,h2,h3,h4,h5,h6 {
                          font-family:'Open Sans',Arial,sans-serif;
                          font-weight:400;
                          margin:10px 0
                      }
                  </style>
              </head>
              <body>
                <div class="jumbotron jumbotron-fluid" style="background-color: white; color: blue;">
                    <div class="container py-0">
                        <h3>Mise à jour mensuelle : \\192.168.66.150\share
                        <br>
                        Pour plus de détails : https://ha.xx.xx:8123/energy</h3>
                    </div>
                </div>
              </body>
              <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
              <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.5/js/bootstrap.min.js"></script>
          </html>
  mode: single                  

Sources

 

 

De ISA/TMG à pfsense / HA Proxy

Il y a 20 ans Microsoft s’était mis en tête de proposer un firewall / reverse proxy maison. A l’époque on ne parlait pas encore de cloud à toutes les sauces, mais juste de permettre aux itinérants de se connecter aux applications d’entreprise, quelques une en web, mais surtout des applications lourdes via le VPN maison (PPTP). Mais surtout Microsoft a réussit à imposer ISA Serveur à beaucoup de ses clients disposant de serveurs Exchange, qui succédait alors à MS Mail, en saupoudrant le tout d’un peu de complexité plus ou moins utile et en imposant de coûteux certificats SAN. Ainsi nous avons eu ISA 2000, ISA 2004, ISA 2006, au passage Microsoft a même produit des appliances avec HP pour terminer par TMG 2010 qui était la dernière itération de la série.

Et après ? Et bien Microsoft a (quasiment) du jour au lendemain décidé que la sécurité d’accès ce n’était pas leur job et en gros ils ont planté là tout le monde. Démerdez vous. Bien sur d’autres éditeurs et constructeurs ont pris le relais (Kemp par exemple) mais la transition n’a pas été facile pour tout le monde, principalement pour des questions de coût. Résultat on trouve encore aujourd’hui des installations basées, dans le meilleur des cas, sur la dernière itération du produit Microsoft, qui dans le meilleur des cas tourne sur un Windows 2008R2 qui comme toute la famille W7 ne reçoit plus de mises à jour, sans passer à la caisse.

Il arrive un moment ou il faut se résoudre à détruire ces vieilleries et se tourner vers quelque chose de plus moderne, et ce d'autant plus qu'on parle ici de sécurité, en gros la porte d'entrée numérique de l'entreprise. Si les grands comptes ont les moyens de leur sécurité en s’offrant des pare-feu et autres équilibreurs de charge à plusieurs milliers d’Euros, voire dizaine de millier d’euros, les PME, quand elles sont malines, peuvent se tourner vers l’open source.

Après avoir un peu cherché, il existe plusieurs pistes, j’ai choisit une base pfsense (on peut partir aussi sur OPNsense) avec HA Proxy comme composant reverse proxy. On peut également utiliser Squid, l’avantage de HA Proxy étant qu’il s’agit d’un bon équilibreur de charge et qu'il sera également possible de s'en servir pour publier d'autres sites sur une ou plusieurs IP publiques. L’autre avantage de pfsense est le support total de Acme et qu’il est ainsi possible de générer automatiquement un certificat SAN nécessaire à Exchange.

En version eco point d’appliance pfsense, je l’ai donc installé sur une VM ESXi selon les recommandation de l’éditeur, avec un WAN et un LAN. Je ne vais pas vous décrire, c’est très bien expliqué ici.

Une fois notre pfsense installé on va lui ajouter quelques packages en allant dans System/Packages ou est disponible tout un catalogue de composant additionnels. Encore une fois la règle est la même, moins on installe de choses, mieux on se porte...

  • Open VMWare Tools : pour faire le lien avec l'hyperviseur
  • Acme : pour générer des certificats SSL Let'Encrypt en se basant sur les API des DNS (chez nous Gandi ou OVH par exemple).
  • HA Proxy : car on est venu pour lui !

Je passe sur Acme qui est assez intuitif et on va voir comment publier un serveur Exchange. Dans cet exemple je l'ai fait sans répartition de charge, mais il est tout à fait possible de publier un (ou plusieurs) FrontEND et coté BackEND répartir la charge sur plusieurs serveurs Exchange selon des règles à définir, soit en spécialisant les serveurs (EAS, Mapi, etc...) soit en hiérarchisant leur importance et leur besoin de disponibilité en fonction du type d'utilisateurs (petit peuple, VIP, etc...). Ce ne sont que des exemples et les serveurs peuvent êtres (ou pas) multipliés (plusieurs serveurs, plusieurs hyperviseurs, plusieurs SAN, etc...) selon la sensibilité de l'infrastructure.

Alors vous allez me dire, pourquoi encore maintenir des serveurs Exchange à l'heure du cloud ? Si pour de petites structures ça n'a pas trop de sens, pour certaines entreprise sensibles il peut s'agit d'une question de confidentialité qu'aucun cloud ne pourra offrir, et pour d'autres simplement pour une question de coût, car même en additionnant le coût des licences (prohibitif, genre 80% d'un projet), le matériel, l'infrastructure, l’exploitation et de bons consultants, au delà d'un certain seuil c'est très rentable par rapport à des licences 365 à 15 € / mois.

Mais au lieu de polémiquer, revenons à notre HA Proxy...

HA Proxy se décompose en deux parties principales. Le FrontEND, c'est ce qui va recevoir les connections entrantes, et le BackEND ou seront connecté les serveurs internes et ou on redirigera les flux après les avoir isolés. Je dis bien isolés car ici on ne fait pas de routage mais du proxy. D'ailleurs pour s'en rendre compte, le serveur Exchange n'a pas besoin d'avoir le serveur pfsense / HA Proxy en passerelle par défaut...

Dans les paramètres généraux on déterminera le nombre de connexions maximum, ce qui a une incidence directe sur l'occupation mémoire, mais également un serveur SysLog si on veut deboguer un peu la chose...

Sur le FrontEND on va configurer une entrée en utilisant une des IP publique disponibles et on va la configurer en type http/https (offloading). Logique et important.

En option et pour plus de sécurité on va fixer des ACL sur les chemins utilisés par Exchange. Çà fonctionne bien sur sans, mais c’est une sécurité supplémentaire recommandable. C'est également la possibilité de rediriger des chemins (path), donc des services vers des serveurs différents via plusieurs BackEND, par exemple le web mail /OWA vers un serveur et les mobiles /Microsoft-Server-ActiveSync vers un ou plusieurs autres serveurs via un second BackEND.

Sur cette même page de configuration au chapitre SSL Offloading on choisira notre certificat (préalablement créé avec Acme ou simplement importé) et surtout on cochera la bonne case afin de restreindre les requêtes aux seul domaines et sous domaines déclarés dans en Subjet Alternative Name de notre certificat SAN, cela nous évite d'avoir à déclarer d'autres ACL plus haut ou en des entrées en SNI.

Il est bien sur possible d'ajouter d'autres sécurités, comme des certificats client, mais comme je ne bosse pas pour un service secret je me suis abstenu.

Passons maintenant au BackEND. On va ici définir le ou les serveur(s) qui seront utilisés pour nos différents services. En l’occurrence je n'en ai qu'un seul sans quoi j'aurais créé plusieurs entrées ou plusieurs BackEND si je souhaitait répartir les services.

Je vais identifier mon serveur par son adresse IP et son port. Ensuite je vais choisir si ce serveur répond en SSL et s'il est nécessaire de vérifier la validité du certificat. Exchange répond en SSL, mais s'agissant de trafic interne je pourrais très bien à l'avenir choisir de ne pas vérifier la validité de son certificat ou utiliser un certificat ausigné. Le poids n'est à renseigner que si on a plusieurs serveurs en BackEND à équilibrer.

Pour d'autres types de serveurs web je peux également y accéder seulement en HTTP en interne, sachant que le client externe lui le verra en HTTPS. C'est un choix lié au niveau de sécurité de l'infrastructure, mais dans bien des cas on ne se préoccupe pas de chiffrer l'interne.

Le cas échéant on réglera plus loin la méthode d'équilibrage, un Timeout à passer 10000 pour Exchange, une méthode pour tester la disponibilité des serveurs et si l'on souhaite ou pas des statistiques, statistiques très utiles pour valider une répartition / équilibrage de charge.


Le FrontEND


Le BackEND

Voilà, à partir de là on a quelque chose de fonctionnel pour tous les ports HTTPS. Il va nous reste à traiter les ports TCP nécessaires au fonctionnement d'un serveur de messagerie (SMTP, POP, IMAP). Si POP et IMAP sont peu en vogue dans les entreprises qui utilisent Exchange, le port SMTP (25) sera nécessaire pour le trafic entrant. Cependant Exchange assurant un service minimum au niveau de la protection certains choisiront de faire transiter le trafic entrant par une passerelle de sécurité (Anti Spam, Anti Virus, etc...).

Dans l'absolu il est possible d'utiliser HA Proxy pour répartir la charge du trafic TCP en configurant un FrontEND TCP et en lui associant un ou plusieurs BackEND.

J'ai du louper quelque chose car le trafic sur ces ports n'était pas stable, alors que d'autres l'ont fait avec de bons résultats. J'ai donc fait un rétropédalage rapide sur ce point et pour l’instant je me suis contenté de faire du NAT classique, donc sans possibilité de répartition de charge. A suivre prochainement.

DNS public

Pour ce qui est du DNS public j'ai fait le choix le plus simple consistant à utiliser uniquement mon nom de domaine. D'autres feront le choix d'utiliser un sous domaine du genre mail.domaine.tld...

@ 3600 IN A 55.235.45.30
@ 3600 IN MX 10 domaine.tld. 
@ 3600 IN TXT "v=spf1 mx mx:domaine.tls~all" 
_autodiscover 3600 IN SRV 10 10 443 domaine.tld. 
autodiscover 3600 IN CNAME  domaine.tld.

Il ne reste plus qu'à tester en configurant les trois types de clients utilisant HTTPS :

  • Un client Outlook sur Mac ou PC sous MAPI qui va utiliser le processus AutoDiscovery pour trouver son serveur en se basant uniquement sur l'adresse mail de l'utilisateur.
  • Un client mobile IOS ou Android qui utilisera ActiveSync (EAS) et AutoDiscovery pour s'y retrouver. A noter que l'application Courrier proposée sur Windows 10 utilise ce même protocole.
  • Et enfin un client web mail en pointant sur domaine.tld/owa

Si tout se passe bien on valide le SMTP entrant / sortant, éventuellement IMAP et POP et il est possible de facturer le client.

Sources

 

Home Assistant & Planification

ARTICLE EN COURS d'ECRITURE, N’HÉSITEZ PAS A REVENIR...

 

Comme je l'ai déjà dit une des forces de Jeedom était son agenda, ici il n'y en a pas pour l'instant. Il existe bien Schedy mais j'ai le choix de ne pas y recourir. J'avais commencé à ébaucher la chose dans l'article sur le chauffage, on va continuer ici de façon plus poussée, sachant que si je poursuit avec mes thermostats, cette partie pourra s'appliquer à d'autres choses comme l’arrosage ou la gestion d'une piscine par exemple.

Si on utilise Home Assistant tout seul et que l'on maîtrise son code, dans l'absolu il n'y a pas besoin de ce que je vais expliquer. Par contre si on déploie pour un tiers, ou si l'ont veut que toute la famille puisse ajuster le fonctionnement, il vaut mieux penser à une interface graphique.

J'ai donc commencé à dessiner cette interface et ensuite je me suis attaqué au codage correspondant. Dans ce projet j'ai plusieurs thermostats à gérer, il suffira simplement de dupliquer le premier ainsi que toutes les ressources qui lui sont nécessaire. Je vous conseille de bien finaliser le premier thermostat, de tester dans tous les sens avant de de dupliquer.

Dans le cas présent je vais travailler sur le HA de mon frère afin de remplacer son vieux Jeedom, il me faut donc à minima que le résultat final ne souffre d'aucune régression et si possible que ça apporte plus de confort et de facilité d'usage. Par exemple sous Jeedom il devait aller changer ses consignes manuellement, jouer avec l'agenda, facile pour moi mais pas vraiment à la portée de l'utilisateur final. L'objectif ici c’est de lui limiter l'accès, mais qu'il puisse pour autant faire tout ce qui a été défini lui même. En plus il m'a collé un challenge, faire en sorte que sa salle de bain soit à la bonne température quand son réveil sonne. Sauf que son réveil est un EchoShow 5 avec Alexa, qu'il change l'heure avant de se coucher et qu'il n’est pas question de payer pour la passerelle Alexa officielle... A Suivre !

On ne parlera pas ici de capteur de température, ni d'actionneur, ça a déjà été évoqué dans d'autres articles.

On va gérer 3 journée type, les jours de semaine, le samedi car il travaille le samedi matin, et le dimanche ou jour férié. L’application des conditions utilisera le sensor Workday afin de pouvoir affecter dynamiquement les jours fériés.

Liste des courses

    • des input_datetime: un START un STOP afin de définir le début et la fin d'une plage horaire.
      # input_datetime: SEMAINE - THERMOSTAT SEJOUR
       sejour_start_semaine_matin:
       has_date: false
       has_time: true
       sejour_stop_semaine_matin:
       has_date: false
       has_time: true
       sejour_start_semaine_midi:
       has_date: false
       has_time: true
       sejour_stop_semaine_midi:
       has_date: false
       has_time: true
       sejour_start_semaine_soir:
       has_date: false
       has_time: true
       sejour_stop_semaine_soir:
       has_date: false
       has_time: true
      ...
    • des input_number: un par consigne de température. Afin de simplifier je suis parti sur des consignes globales, mais il est tout à fait possible d'avoir des consignes indépendantes pour chaque thermostat à gérer. Je n'ai pas de Hors Gel car celui ci est géré statiquement au niveau de chaque thermostat. J'ai ajouté Confort+ et Boost, le mode Boost servira essentiellement à surchauffer la salle de bain, comme on le verra plus loin.
      consigne_confort_plus:
       name: Confort +
       min: 14
       max: 24
       step: 0.1
       unit_of_measurement: °C
      ...
    • des input_boolean: un par plage horaire, ils serviront de drapeau pour chaque plage horaire si on souhaite activer la consigne Confort+ ou Boost pour une plage spécifique.
      boost_sejour_semaine_matin:
      boost_sejour_semaine_midi:
      boost_sejour_semaine_soir:
      ...
    • des binary_sensor: un par plage horaire, que je vais utiliser sur les conseils d'un collègue afin de convertir une heure de début de plage horaire, les utiliser en trigger: et récupérer celui qui est la source du déclenchement afin d'y affecter un flag pour activer le mode Confort+ ou Boost à une plage spécifique. On trouve également ici workday: pour gérer les jours fériés.
      - platform: template
        sensors:
          sejour_start_semaine_matin:
          friendly_name: 'Séjour : Start Semaine Matin'
          delay_off:
            minutes: 2
          value_template: >-
            {%- if states.sensor.time.state == states.input_datetime.sejour_start_semaine_matin.state[0:5] %}
              true
            {% else %}
             false
           {%- endif %}
      ...
      - platform: workday
        country: FRA
        workdays: [mon, tue, wed, thu, fri]
        excludes: [sun, holiday]
        add_holidays:
        - '2020-02-24'
      
    • des sensor: en fait surtout time_date: que l'on va utiliser pour comparer la date et l'heure courante avec nos interactions. J'y ai ajouté Season pour éviter de chauffer en été (...joke).

      - platform: time_date
        display_options:
        - 'time'
        - 'date'
        - 'date_time'
        - 'date_time_utc'
        - 'date_time_iso'
        - 'time_date'
        - 'time_utc'
        - 'beat'
      - platform: season

Définitions des cartes

On commence par le code de la carte entities:. Ce thermostat gère 3 convecteurs dans une pièce ouverte. La carte reprend également les détecteurs d'ouverture qui serviront à désactiver le thermostat quand on aère... (j'ai volontairement coupé le code sur la partie semaine).

entities:
  - entity: climate.thermostat_sejour
  - entity: switch.ipx800_1_sejour
  - entity: switch.ipx800_5_cuisine
  - entity: switch.ipx800_4_hall
  - entity: binary_sensor.window_door_sensor
  - label: SEMAINE
    type: section
  - entities:
      - entity: input_boolean.boost_sejour_semaine_matin
        name: false
        toggle: true
      - entity: input_datetime.sejour_start_semaine_matin
        name: false
      - entity: input_datetime.sejour_stop_semaine_matin
        name: false
    entity: input_fake
    name: Matin
    show_state: false
    type: 'custom:multiple-entity-row'
  - entities:
      - entity: input_boolean.boost_sejour_semaine_midi
        name: false
        toggle: true
      - entity: input_datetime.sejour_start_semaine_midi
        name: false
      - entity: input_datetime.sejour_stop_semaine_midi
        name: false
    entity: input_fake
    name: Midi
    show_state: false
    type: 'custom:multiple-entity-row'
  - entities:
      - entity: input_boolean.boost_sejour_semaine_soir
        name: false
        toggle: true
      - entity: input_datetime.sejour_start_semaine_soir
        name: false
      - entity: input_datetime.sejour_stop_semaine_soir
        name: false
    entity: input_fake
    name: Soir
    show_state: false
    type: 'custom:multiple-entity-row'
show_header_toggle: false
state_color: true
theme: teal
title: Thermostat Séjour
type: entities

Automation

Pour gérer l'ensemble des plages (3 ici) d'une journée type il nous faut 1 automation START et une automation STOP. On pourrait bien sur utiliser un delay:, mais ce n'est vraiment pas conseillé car ça obligerait l'automation à rester active et ça résisterait mal à une coupure / redémarrage (encore que...). J'aurais pu choisir de gérer toutes les journées type dans une même automation, mais ça voudrait dire de se passer des conditions: pour tout gréer dans un monstrueux template: dans action:. Simplifions sans complexifier.

Automation Start Confort Séjour Semaine :

  • Un bloc trigger: avec 3 binary_sensor:
  • Un bloc condition: en mode and avec :
    • Un input_boolean: qui va déterminer si le chauffage est ON ou OFF dans la maison.
    • Un input_boolean: qui va déterminer le mode absent (auquel cas les thermostats sont en mode hors gel et on ne poursuit pas). Le mode absent peut être géré manuellement ou par une règle liée de géolocalisation.
    • Une condition time: pour poursuivre uniquement les jours de semaine dans le cas de cette journée type.
    • Une condition workday: afin de s'assurer que l'on n'est pas en présence d'un jour férié.
  • Un bloc action avec :
    • Un sevice: basé sur un data_emplate: pour affecter la bonne consigne de température de Confort ou Confort+ si la plage horaire comporte ce flag.
    • Un notify: basé sur un data_emplate: de notification que je redirige vers un canal Slack et qui constituera le journal de mon thermostat.
- alias: '100 : START CONFORT Séjour Semaine'
  description: 'Confort et Confort+ Séjour Semaine sauf jours fériés'
  trigger:
    - entity_id: binary_sensor.sejour_start_semaine_matin
      platform: state
      to: 'on'
    - entity_id: binary_sensor.sejour_start_semaine_midi
      platform: state
      to: 'on'
    - entity_id: binary_sensor.sejour_start_semaine_soir
      platform: state
      to: 'on'

  condition:
    condition: and
    conditions:
      - condition: state
        entity_id: input_boolean.thermostats_on_off
        state: 'on'
      - condition: state
        entity_id: input_boolean.thermostats_away
        state: 'off'

      - condition: time
        weekday:
          - mon
          - tue
          - wed
          - thu
          - fri

      - condition: state
        entity_id: binary_sensor.workday_sensor
        state: 'on'

  action:
  - service: climate.set_temperature
    entity_id: climate.thermostat_sejour
    data_template:
      temperature: '{% if trigger.entity_id == "binary_sensor.sejour_start_semaine_matin" and is_state("input_boolean.boost_sejour_semaine_matin", "on") %}
                      {{ states.input_number.consigne_confort_plus.state }}
                    {% elif trigger.entity_id == "binary_sensor.sejour_start_semaine_midi" and is_state("input_boolean.boost_sejour_semaine_midi", "on") %}
                      {{ states.input_number.consigne_confort_plus.state }}
                    {% elif trigger.entity_id == "binary_sensor.sejour_start_semaine_soir" and is_state("input_boolean.boost_sejour_semaine_soir", "on") %}
                      {{ states.input_number.consigne_confort_plus.state }}
                    {% else %}
                      {{ states.input_number.consigne_confort.state }}
                    {% endif %}'

  - service: notify.slack_hass_canaletto
    data_template:
      message: >
        {% if trigger.entity_id == "binary_sensor.sejour_start_semaine_matin" and is_state("input_boolean.boost_sejour_semaine_matin", "on") %}
          {{ states.sensor.date_time.state}} > Confort+ ({{ states.input_number.consigne_confort_plus.state }}°), Séjour : {{ states('sensor.mi_t_clock') }}°, Extérieur : {{ states('sensor.ext_temperature') }}°
        {% elif trigger.entity_id == "binary_sensor.sejour_start_semaine_midi" and is_state("input_boolean.boost_sejour_semaine_midi", "on") %}
          {{ states.sensor.date_time.state}} > Confort+ ({{ states.input_number.consigne_confort_plus.state }}°), Séjour : {{ states('sensor.mi_t_clock') }}°, Extérieur : {{ states('sensor.ext_temperature') }}°
        {% elif trigger.entity_id == "binary_sensor.sejour_start_semaine_soir" and is_state("input_boolean.boost_sejour_semaine_soir", "on") %}
          {{ states.sensor.date_time.state}} > Confort+ ({{ states.input_number.consigne_confort_plus.state }}°), Séjour : {{ states('sensor.mi_t_clock') }}°, Extérieur : {{ states('sensor.ext_temperature') }}°
        {% else %}
          {{ states.sensor.date_time.state}} > Confort ({{ states.input_number.consigne_confort.state }}°), Séjour : {{ states('sensor.mi_t_clock') }}°, Extérieur : {{ states('sensor.ext_temperature') }}°
        {% endif %}

Améliorations à envisager : EJP ou Tempo à gérer dans le template d'affection des consignes afin de réduire la température de 1° les jours rouges et de démontrer ainsi la nécessité de la domotique. Prévoir un boolean global afin d'activer ou pas cette option.

Automation Stop Confort Séjour Semaine :

  • Un bloc trigger: avec 3 templates afin de récupérer les heures STOP. Inutile de créer des binary_sensor ici car on n'a pas besoin de connaitre la source de déclenchement dans action: ou on se contenter d'affecter la consigne Eco dans tous les cas.
  • Un bloc condition: ou l'on reprend les mêmes conditions que pour START.
  • Un bloc action: avec
    • Une action ou on défini la consigne de température Eco.
    • Une action de notification pour le journal.

INSERT CODE

Autre méthode

En fait la méthode classique consiste à créer un trigger: basé sur un template qui va comparer une ou plusieurs fois l'heure locale avec l'heure de l'input_datetime:

  trigger:
  - platform: template
    value_template: '{{ states.sensor.time.state == states.input_datetime.pompe_stop_p1.state[0:5] }}'
  - platform: template
    value_template: '{{ states.sensor.time.state == states.input_datetime.pompe_stop_p2.state[0:5] }}'

Ça fonction très bien, mais imaginons que nous ayons défini plusieurs plages et qu'on décide de ne pas utiliser certaines.

Si on les laisse bêtement à 00:00 00:00 on pourrait imaginer qu'il ne se passe rien. En fait si, on se retrouve avec un ON/OFF et parfois même un OFF/ON ce qui est plus gênant. Pour y remédier, et ça m'a pris un peu de temps car je n'ai aucune notion de développement, j'ai fini par améliorer mon template en associant une condition AND, en gros, si l'heure locale est égale à l'heure définie ET si l'heure définie pour le START est différente de l'heure définie en STOP, alors TRUE...

  trigger:
  - platform: template
    value_template: '{{ (states.sensor.time.state == states.input_datetime.pompe_stop_p1.state[0:5]) and (states.input_datetime.pompe_start_p1.state != states.input_datetime.pompe_stop_p1.state) }}'
  - platform: template
    value_template: '{{ (states.sensor.time.state == states.input_datetime.pompe_stop_p2.state[0:5]) and (states.input_datetime.pompe_start_p1.state != states.input_datetime.pompe_stop_p2.state) }}'

Alternatives

Home Asssitant ne dispose toujours pas du véritable agenda qui fait la force de Jeedom. En général je préfère le faire à la main ce qui permet de réaliser exactement ce que l'on souhaite. Mais j'ai trouvé deux embryons d'agenda. Pour l'instant ça ne va pas très loin, mais ça permettra de planifier des choses simples sans se plonger dans le code...

Conclusion

Voilà, il ne vous reste plus qu'à dupliquer ça à l'infini pour gérer autant de journées type, plages horaires et thermostats. Merci à Phillip et Mathieu dans notre fil Telegram pour leurs idées et aide, notamment sur les templates qui m'ont pris pas mal de temps.

Sources

 

 

Home Assistant & BLE

Si le plus fiable à mon sens est d'utiliser des sondes de température / humidité Aquara en Zigbee, on peut avoir envie d'utiliser des sondes avec afficheur, mais celles ci utilisent du Bluetooth Low Energy (BLE) et toutes ne sont pas intégrables automatiquement.

  • LYWSDCGQ
    Celle ci est la plus ancienne, ronde en LCD, intégrable automatiquement.

  • LYWSD02
    Sous la forme d'une horloge rectangulaire, affichage e-Ink, elle ne remonte pas les informations liées à ses piles. Le réglage de l'heure passe par Mi Home sur le serveur Chine.

  • CGG1
    Mise à jour de la première en e-Ink, c'est à mon gout la plus esthétique. intégrable automatiquement.

  • HHCCJCY01
    MiFlora, outre la température elle remonte d'autres informations sur la santé de vos plantes... mais pas l'état de ses piles.

  • GCLS002
    Un vase... fonctionnement similaire à la MiFlora.

  • LYWSD03MMC
    Une petite sonde carrée en LCD. Très peu coûteuse, mais je ne suis pas sur que ce soit la plus fiable. L'intégration nécessite la récupération de la BindKey..

  • CGD1
    Un réveil qui servira également de sonde. Le réglage de l'heure se fait via Mi Home sur le serveur Chine et l'intégration nécessite la récupération de la BindKey.

Intégration dans Home Assistant

Pour intégrer ces sondes dans home assistant je conseille d'utiliser le composant MiTemp_BT (Edit : ça s'appelle maintenant BLE Monitor) plutôt que l'intégration de base que l'on trouve dans HA. L'installation se fait via HACS et on ajoutera la configuration suivante à notre fichier configuration.yaml :

sensor:
  - platform: mitemp_bt
    rounding: True
    decimals: 2
    period: 60
    log_spikes: False
    use_median: False
    active_scan: False
    hci_interface: 0
    batt_entities: False
    encryptors:
               'A4:C1:38:2F:86:6C': '217C568CF5D22808DA20181502D84C1B'
    report_unknown: False

Récupération de la BindKey 

Afin de pouvoir utiliser les deux derniers modèles proposés par Xiaomi, et probablement les prochains, il va falloir tricher un peu. On va donc installer sur Android une version hackée de Mi Home que l'on récupère ici.

ATTENTION : On fait ça de préférence sur un vieux mobile que l'on utilise plus et qui n'est pas connecté à vos comptes habituels, car s'agissant d'une version hackée, si elle va nous aider, on ne sait pas vraiment ce qu'elle fait et elle peut contenir d'autres choses malveillantes...

Dans Mi Home connecté au serveur Chine (possible également sur le serveur Europe depuis juin 2020) on associe notre sonde ou le réveil, ça mettra le réveil à l'heure. Ensuite on ouvre un explorateur de fichier sur le mobile pour aller chercher le fichier /vevs/logs/pairings.txt ou l'on va trouver les informations qui nous intéressent...

Did: blt.3.12bq5vom4lg00
Token: ec104xxddrrgghhjj01dbe6b
Bindkey: d26dbddffggrrttyy5cf0050e5039d02
Mac: A4:XX:38:AB:XX:F7

Did: blt.3.12in66gtolg00
Token: 47eeerrttyyuuii1a5369db0
Bindkey: a2fcb4edddffgghhjjkkf7d264600320c
Mac: 58:2D:55:51:44:92

Easy ! En fait il m'a fallut un peu de temps et de recherches pour arriver à trouver ça facile. Les sondes qui ne nécessitent pas de BindKey seront reconnues toute seules par HA, pour les autres il faudra renseigner la ligne encryptors: dans le fichier de configuration.

Étalonnage

Il ne faut toutefois jamais perdre de vue que toutes ces sondes à bas prix, Xiaomi ou autres, ne sont jamais étalonnées et qu'il n'est pas rare d'observer des écarts. Dans l'exemple ci dessus, les 4 sondes signalées en rouge sont placées sur mon bureau depuis une heure et aucune n'indique la même valeur.... Un offset sera donc parfois à prévoir dans Home Assistant.

Source

 

 
 

 

 

Redimensionner un disque Hassio sur ESXi

Pour redimensionner un disque ESXi sous Windows c'est facile. On change la taille du disque dans la console VMWare et on agrandit la partition avec le gestionnaire de disque Windows. Il est également possible de réduire, mais c’est plus compliqué et je vous laisse un peu chercher car ce n’est pas le but de cet article.

Dans le cas d'une partition Linux c’est un peu différent. J'avais le cas avec ma VM Home Assistant HASSIO qui de base est configurée avec 6 GO, ce qui s'avère rapidement trop juste.

Avec les dernières versions de ESXi on doit pouvoir faire la partie VMWare directement en augmentant directement la taille dans la la console (à condition de ne pas avoir de snapshot), sauf que dans mon cas (ESXi 5.5) c'est impossible, grisé dans le client VShere et erreur dans le client web. Et sans ça impossible d'aller plus loin.

La solution

Elle passe par SSH après avoir arrêté la VM :

1 - on va dans le répertoire ou se trouve notre disque virtuel
cd /vmfs/volumes/datastore1/hassio/
2 - on clone le disque virtuel existant
vmkfstools -i hassio.vmdk hassio_clone.vmdk
3 - on redimensionne le clone
vmkfstools -X 40g hassio_clone.vmdk
4 - on le renomme si on le souhaite...
vmkfstools -E "originalname.vmdk" "newname.vmdk"

Redimensionner

Maintenant on va pouvoir réellement redimensionner la partition :

  1. Dans les paramètres de la machine on supprime l'ancien disque et on ajoute le nouveau et on sauvegarde.
  2. On ouvre à nouveau les paramètres pour ajouter un lecteur de CD qui pointe sur l'ISO de GParted que l'on aura au préalable téléchargé ici.
  3. Dans les options de la VM on change le boot de EFI vers BIOS et on sauvegarde.
  4. On lance la VM qui va démarrer sur le CD de GParted (une petite vidéo pour vous faire une idée).
  5. Important, quand GParted vous demande de réparer (fix) la partition vous répondez OUI !
  6. Ensuite il suffit de redimensionner la partition /dev/sda8 sans oublier d'appliquer votre choix.
  7. On ferme tout ça et on édite la VM pour retirer le lecteur de CD virtuel et surtout repasser le boot en mode EFI.
  8. On sauvegarde et on peu relancer la VM avec son disque ainsi redimensionné. Si tout va bien on fera le ménage en supprimant l'ancien VMDK.

Sources

 

Windows 10 au long cours....

Suite à ma migration tardive vers Windows 10 je continue à éplucher les problèmes que je n'avais pas sous Windows 7 et qui me donnent ce sentiment de régression, là ou la tech est censée apporter plus de progrès. Je reviendrais vous parler de la gestion calamiteuse de mes écrans, mais ce dossier est loin d'être clos !

Un autre problème est la gestion de la mémoire.

Je fais partie de ces personnes qui n'éteignent jamais leur PC, je sais ce n'est pas très écolo, on ne peut pas l'être sur tout. Bref, là ou j'avais dressé mon Windows 7 à tenir des mois sans redémarrage, avec une stabilité déconcertante (à condition d'éviter certaines mises à jour destinées à le tuer), force est de constater que je suis obligé de redémarrer mon Windows 10 régulièrement car il devient inutilisable au bout d'une semaine...

J'ai alors ouvert une enquête, inutile bien sur de faire appel au support, sur les forums les agents mandatés par Microsoft ne savent que conseiller un redémarrage, voire une réinstallation, sérieux !

Dans les faits le processus System occupe de plus en plus la CPU, environ 1 à 2 % de plus par jour. En allant chercher des détails avec Process Explorer, je me suis rendu compte que mon PC passait son temps à compresser la mémoire. Il se trouve que j'ai 32 GO de RAM et qu'il en reste toujours au moins 1/3 de libre, je considère donc que cette option est inutile et contre productive.

Dans la pratique ça peut s'expliquer. Microsoft force tout le monde à migrer vers Windows 10, mais W10 consomme plus de CPU et pour ceux ceux qui migrent de vieux PC avec 2 ou 4 GO de RAM, heureusement qu'il existe quelques artifices, même s'il me semblent illusoires ! Il ne faut pas non plus oublier que Windows 10 n'est jamais que le résultat du tripatouillage d'un code hérité au fil des décennies, ainsi des artifices utiles avec un PC des années 90 et son disque dur lent sont inutile avec un PC actuel pourvut d'un SSD, pourtant des réglages persistent !  Et de toutes façons la majorité des utilisateurs allument leur PC, puis l'éteignent quand ils ne l'utilisent plus. Donc leur PC est à nouveau frais et dispo le lendemain...

Utilisant par ailleurs des serveurs, ça m'a poussé à regarder si le problème constaté sous Windows 10 est présent sous Windows Server 2016/2019, et la réponse est non. En effet le code est proche, mais les réglages différents. Je n'ai pas ce problème sur les versions serveur, on peu penser que l'éditeur considère que sur un serveur l'administrateur dimensionne les ressources en fonction des besoins et que ces artifices sont inutiles. Pour vérifier ce point il existe une commande PowerShell :

Résultat sous Windows 10

PS C:\WINDOWS\system32> get-mmagent
ApplicationLaunchPrefetching : True
ApplicationPreLaunch : True
MaxOperationAPIFiles : 256
MemoryCompression : True
OperationAPI : True
PageCombining : True

Résultat sous Windows Server 2016/2019

PS C:\Users\Administrator> get-mmagent
ApplicationLaunchPrefetching : False
ApplicationPreLaunch : False
MaxOperationAPIFiles : 256
MemoryCompression : False
OperationAPI : False
PageCombining : False

Inutile d'être un expert pour constater des réglage bien différents de la gestion et l'inutilisation de la mémoire. On va donc changer quelques réglages, tout ceci n'étant pas sans risque, si vous ne savez pas ce que vous faites, je vous conseille d'aller jouer ailleurs ou de faire appel à un expert.

On va commencer par désactiver la compression mémoire et redémarrer :

PS C:\Windows\system32> disable-mmagent -mc
PS C:\Windows\system32> Restart-Computer

Etant donné qu'il ne sera pas possible d'apprécier immédiatement le résultat je propose de désactiver également Prefetch et SuperFetch avec regedit (on désactive  EnablePrefetcher et EnableSuperfetch, (au besoin on crée les entrée si elles ne sont pas présentes)

HKEY_LOCAL_MACHINE>SYSTEM>CurrentControlSet>Control>Session Manager>Memory Management>PrefetchParameters
  • 0 = Désactivé
  • 1 = Actif sur les applications
  • 2 = Actif au démarrage
  • 3 = Actif sur tout

Et on termine en désactivant les services associés (SysMain, ou SuperFetch sur des versions antérieures) avec le gestionnaire des services (WIN+R + services.msc), ou en PowerShell si vous y êtes plus à l'aise :

PS C:\Windows\system32> Set-Service SysMain -StartupType Disabled

Après un redémarrage on obtient :

PS C:\Windows\system32> Get-mmagent
ApplicationLaunchPrefetching : False
ApplicationPreLaunch : False
MaxOperationAPIFiles : 256
MemoryCompression : False
OperationAPI : False
PageCombining : False

 

Je touche du bois car mon PC est beaucoup plus stable depuis une semaine, j'espère que ça va durer et qu'une nouvelle mise à jour ne va pas me contrarier !

EDIT Avril 2020 : deux mois après je constate que oui le PC est bien plus stable, mais si je n'ai plus de processus qui me bouffe la CPU, Windows gère toujours très mal la RAM et j'ai beau fermer toutes les applications gourmandes, je me retrouve au mieux avec 16 GO sur 32... Mais il parait que c'est normal, que j'utilise mal mon ordi et qu'il faut le redémarrer. Je tenterais bien un Mac équivalent, mais quand je vois le comportement de mon Mac Book Pro qui souffle comme un âne dès que je lance une vidéo et deux trois sites, j'hésite à confier mes économie à Apple !

EDIT Juin 2020 : Après la mise à jour 2004, surprise, toutes ces customisations sont remises à leur valeur initiale.

Sources

De Jeedom à Home Assistant : le chauffage

ARTICLE INCOMPLET EN COURS DE RÉDACTION

Ce ne sont que mes notes compilées au fil de l'eau... Et vous pouvez poser des questions !
N'hésitez pas à revenir ou d'utiliser la touche F5, et de me signaler les erreurs :-)

Comme je l'ai déjà expliqué dans les articles précédents (1 | 2), Jeedom, qui a remplacé la ZiBase, me sert essentiellement à gérer mes convecteurs. Jeedom est plutôt bien fait sur ce point grâce aux plugin Thermostat, Mode et Agenda. On va voir ici que l'on peut faire la même chose avec Home Assistant, on ne se contentera par contre pas de cliquer sur des boutons, il faudra un peu de codage, rien de bien méchant et surtout du copié / collé. Mais une fois que l'on a compris le concept c'est bien plus rapide et surtout extrêmement fiable. Home Assistant ne fait pas tout, mais il fait très bien ce qu'il propose.

Ici pas de plugins mais des fonctions que l'on assemble. Et donc à chaque étape, on vérifie que ça fonctionne (en exécutant ce que l'on fait), et avec le validation intégrée à HA au cas ou l'on aurait codé n'importe quoi ou simplement pas respecté les indentations. Certaines modifications apportées à configuration.yaml et ses sous ensembles nécessitent un redémarrage, par contre on peut recharger à la volée les modifications apportées aux scripts et automations.

HA dispose d'un éditeur de scripts et automations, c’est bien pour faire de petites choses et pour se familiariser, mais dès que l'on souhaite taper dans le dur je vous conseille vivement d'éditer les fichiers .yaml avec un éditeur de code (comme Notepad++, Sublime ou VSCodium (je viens de me prendre un virus avec ce dernier, surement par le biais d'une extension, du coup je suis retourné à Visual Studio Code). Attention c’est l'un ou l'autre, mais pas les deux en même temps, et ce qui sera édité à la mano ne le sera plus avec l'interface.

Alors c'est parti ! Le propre d'une solution domotique est d'obtenir un résultat final calqué à ses besoins, il faut donc les définir, ce qui doit déjà être fait si vous venez de Jeedom. Par contre il ne faudra pas chercher à reproduire exactement la même chose, mais à profiter de ce qu'offre HA.

Dans ce projet j'aurais tout pu faire en code, mais mon objectif de départ est que n'importe qui puisse ensuite changer les plages horaires de base et les températures de consigne sans aller dans le code.

Je pars du principe que vous avez déjà joué avec Home Assistant et intégré ses concepts de base, si ce n'est pas le cas commencez par là et revenez plus tard. Je vais présenter ici quelques exemple, mais ensuite je publierait toute la configuration sur Git-Hub, publication possible et intégrée à HA bien entendu.

Concepts de base

Pour gérer le chauffage on va utiliser plusieurs plusieurs composants et fonctions :

  • Climate, qui est en fait un thermostat générique que l'on adaptera à nos besoins.
  • Input_Select, Input_Boolean, Input_Number et Input_DateTime qui vont nous permettre de saisir, afficher et d'utiliser des valeurs, un peu comme des données variables, mais qui seront persistantes dans le système tant qu'on ne les change pas (donc même après un redémarrage).
  • Des automations (des scénarios) qui vont nous permettre de planifier les plages horaires.
  • Des scripts pour exécuter de rapides routines.
  • Des sources de température, les capteurs que l'on placera judicieusement dans les pièces à chauffer. J'utilise des sondes Xiaomi Aqare en Zigbee via Deconz / Phoscon et des sondes Xiaomi avec afficheur en Bluetooth. Mais n'importe quel type de sonde fera l'affaire pourvu qu'elle remonte la température quand elle change.
  • Des actionneur ON/OFF pour chaque convecteur, j'utilise une vieille carte IPX800 v2, mais ça peut être du Shelly, du Zwave, du fil pilote, bref n'importe quoi capable d'allumer un convecteur en respectant les normes en vigueur (on évite de commander un convecteur avec une chinoiserie. Et on évité également des équipements qui ne sont pas pilotables en local afin d'éviter de se retrouver sans chauffage en cas de coupure internet).

Le thermostat

La première chose à faire pour pouvoir jouer est de créer un premier Thermostat en éditant le fichier climate.yaml que l'on aura inclut dans configuration.yaml (je vous conseille de faire ainsi pour tout afin d'aérer votre code, !include_dir_merge_list permettant d'inclure tout ce qui est dans un sous répertoire pour une type donné) :

group: !include groups.yaml
#automation: !include automations.yaml
automation: !include_dir_merge_list automations/
script: !include scripts.yaml
scene: !include scenes.yaml
switch: !include switch.yaml
climate: !include climate.yaml
notify: !include notify.yaml
sensor: !include sensor.yaml
input_boolean: !include input_boolean.yaml
input_datetime: !include input_datetime.yaml
input_number: !include input_number.yaml
input_text: !include input_text.yaml
input_select: !include input_select.yaml

Et ensuite dans climate.yaml on va placer notre premier thermostat. Attention à toujours respecter l'indentation propre aux fichier .yaml (d'ou un éditeur de code).

  - platform: generic_thermostat
    name: Thermostat Cuisine
    heater: switch.study_heater
    target_sensor: sensor.mi_cuisine
    min_temp: 15
    max_temp: 21
    ac_mode: false
    target_temp: 17
    cold_tolerance: 0.3
    hot_tolerance: 0
    min_cycle_duration:
      seconds: 5
    keep_alive:
      minutes: 3
    initial_hvac_mode: "off"
    away_temp: 16
    precision: 0.1

Je ne vais pas vous expliquer le paramétrage du thermostat, il y a des docs (paramétrage | utilisation) pour ça, et sous HA elles sont très bien faites, documentées et fournies avec des exemples.

J'ai géré des convecteurs, mais il est également possible de gérer des climatiseurs réversibles ou d'autres types d'appareils. Il faudra bien sur ajuster ces valeurs, on constate d'emblée la présence d'une valeur du mode absence qui dans certains cas constituera un seuil, le reste consistant à chauffer ou pas. C'est adapté à un poêle ou du chauffage central, mais pas à du chauffage électrique ou il faudra être plus précis et gérer des mode Eco/Confort.

A partir de la on ajoute notre thermostat dans l'interface avec une carte Thermostat et on peut commencer à jouer avec (j'ai un peu customisé le thermostat de base...).

Les Input

Ils vont nous servir de variables de base pour planifier le fonctionnement de nos thermostats avec différentes températures de consigne et différentes plages horaires.

Input_Select : c'est une sorte de combo qui me permettra de passer d'un mode à un autre pour déclencher un script qui va reparamétrage l'ensemble (planification et consignes) en fonction d'une situation. Dans mon cas j'ai un mode Normal, un mode Dîner ou j'élargit les plages horaires et je chauffe un peu plus certaines pièces quand je reçoit du monde (avec option "elle" reste dormir auquel cas je chauffe un peu plus la chambre si c'est une frileuse, ou la chambre d'amis), le mode Week-End si je reçoit des amis avec chauffage de la chambre d'amis, etc..

input_select: # ligne à supprimer quand on place ça dans un sous-fichier
  chauffage:
    name: Etats du Chauffage
    icon: mdi:home-minus
    options:
     - Normal
     - Diner
     - Week-End
     - Abscent

Cette fonction va généralement déclencher un script de mise en situation qui activera les planifications idoines, il faudra également déclencher un script de sortie pour repasser en mode Normal.

Enfin on se servira du mode défini en tant que condition  pour l'exécution d'une planification. Par exemple je chauffe le groupe (on verra plus tard la notion de climate_group) des pièces de vie en mode Confort+ à la condition que que le mode Dîner soit activé.

Input_Boolean : c’est une sorte d’interrupteur virtuel qui va me permettre de passer à ON tous les thermostats à au début de l'hiver (ce que je pourrais également programmer à l'aide des données météo externes), ou de signaler la présence des enfants en vacances chez moi et d'activer la planification du chauffage de leurs chambres (ce que je pourrais également automatiser grâce à leur géolocalisation sur une zone élargie, genre leur TGV approche à moins de 100 km, le temps d'aller les chercher à la gare et leur chambre est chauffée.

input_boolean:
  presence_antoine:
    name: Présence Antoine
    initial: off
    icon: mdi:account-switch
  presence_marie:
    name: Présence Marie
    initial: off
    icon: mdi:account-switch
  thermostats_on_off:
    name: Chauffage On / Off
    initial: off
    icon: mdi:thermostat-box

Input_DateTime : va nous servir à définir nos plages horaires de chauffage. Mais afin de pouvoir s'en servir il faut au préalable définir le sensor Date & Time(je n'ai pas encore compris ce point, mais il est indispensable).

sensor:
    - platform: time_date
      display_options:
      - 'time'
      - 'date'
      - 'date_time'
      - 'date_time_utc'
      - 'date_time_iso'
      - 'time_date'
      - 'time_utc'
      - 'beat'

Ensuite on défini autant de plages horaires que nécessaire. Je me suis abstenu à une plage par pièce, mais il est tout à fait possible d'en ajouter, par exemple sdb_start_confort_matin, de même que j'ai fait un start/stop_confort et qu'explicitement de bascule ensuite en consigne eco, mais j'aurais également pu créer un start_eco ou start_confort_plus, etc...

input_datetime:
  sejour_start_confort:
    has_date: false
    has_time: true
  sejour_stop_confort:
    has_date: false
    has_time: true
  sdb_start_confort:
    has_date: false
    has_time: true
  sdb_stop_confort:
    has_date: false
    has_time: true

On peut également pour chaque entrée ajouter un name:, je ne l'ai pas fait car je vais me servir du plugin multiple-entity-row (à installer depuis HACS) pour afficher tous ça sur une ligne horizontale dans une carte.

Input_Number : va lui me servir à définir mes consignes de température. Je les ai définie globalement, mais comme pour le reste on pourrait affiner. De base c'est c'est affiché en tant que slider, mais il est possible de faire un affichage box et une saisie manuelle, ou comme je l'ait fait de regrouper ces valeurs sur une seule ligne avec multiple-entity-row. Et on peut en ajouter à souhait !

input_number:
  consigne_confort:
    name: Confort
    initial: 20
    min: 19
    max: 24
    step: 0.1
    unit_of_measurement: °C
  consigne_eco:
    name: Eco
    initial: 17
    min: 15
    max: 19
    step: 0.1
    unit_of_measurement: °C

On en a maintenant terminé avec les Input, sachez toutefois qu'il existe également Input_Text qui pourra servir à définir le contenu des messages de notification (SMS, Slack, Telegram ou vocaux via Google Home ou Alexa). Voici le résultat en image :

Vous remarquerez que c'est en anglais, c'est volontaire le temps du développement. En effet toutes les docs étant en langue anglaise, il est bien plus facile pour la compréhension de travailler avec une interface dans cette même langue. En un clic tout peut repasser dans une autre langue.

A ce stade on peut cliquer sur les valeurs pour changer les horaires de début et de fin ainsi que les consignes (elles seront persistantes après un redémarrage car on à pas défini de valeur par défaut dans les Input).

Planification

Si à ce stade on peut commencer à utiliser manuellement nos thermostats, l’intérêt d'une solution domotique est bien sur d'automatiser afin que la domotique nous apporte une expérience confortable adaptée à notre mode de vie.

Pour y parvenir on va planifier les horaires pour adapter le confort (températures) souhaité à notre mode de vie. On commencer par la vie courante (je me lève, je travaille, je dors) et on s'occupera ensuite des cas particuliers (je voyage, je reçoit, je prends une douche à un horaire non planifié, je regarde un film, etc...). On va également gérer les cas particuliers récurrents comme la présence durant les vacances scolaires des enfants pendant x jours, ensemble ou séparément.

Autant vous dire qu'on va rentrer dans le code et notamment se servir de la notion de Template (& Templating) afin d'utiliser les valeurs définies dans nos Imput's pour nos automatisations à base d'Automation ou de Scripts. Mais n'ayez pas peur, je parle de code car ça y ressemble et que je vous recommande un éditeur de code, mais il ne s'agit jamais que de bouts de code généralement issus de nos recherches, le copié / collé est roi, heureusement car je vous rappelle que je ne sais pas coder !

Pour planifier le chauffage d'une pièce ou d'une zone notre Automation va se décomposer en trois parties qui devront êtres parfaitement formatées et indentée, chaque partie peut être multiple (and ou or, je pense) :

  1. Trigger: c'est ce qui va déclencher la planification, dans notre cas on utilisera l'heure début, mais cela pourrait également être un interrupteur, un événement, un état, etc...
    PS : je pense que dans une v2 j’utiliserai un time_pattern permettant la re planification en fonction de conditions (par exemple, de telle heure à telle heure, uniquement le samedi et en fonction d'un mode défini...).
    PS2 : On oublie time_pattern pour cet usage, trop chargé, et surtout on ne peu plus dans ce cas changer la valeur de consigne manuelement.
  2. Condition: pour l'instant je vais me servir uniquement de l'état du Mode (voir input_select plus haut). 
  3. Action: c'est ici que l'on va dire ce que l'on fait. Dans mon cas je vais :
    1. Définir la température de consigne Confort du thermostat (ou d'un groupe de thermostats) en me servant d'une valeur définie plus haut (avec input_number), ensuite j'attendrait
    2. Attendre qu'il soit l'heure de repasser en mode Eco avec un wait_template: et mon heure de fin.
    3. Définir la température de consigne Eco du thermostat
    4. Éventuellement je peux ajouter d'autres actions, comme afficher un voyant sur la vieille ZiBase (qui ne sert plus qu'à ça...) pour indique l'état Confort de la pièce... Ou encore envoyer une notification à Slack qui me servira de journal d’événements... A vous d'imaginer !

Voici ce que ça peut donner :

- alias: 'Planification / Thermostat : Antoine'
  trigger:
  - platform: template
    value_template: '{{ states.sensor.time.state == states.input_datetime.antoine_start_confort.state[0:5] }}'
  condition:
  - condition: state
    entity_id: input_boolean.presence_antoine
    state: 'on'
  action:
  - service: climate.set_temperature
    entity_id: climate.thermostat_antoine
    data_template:
      temperature: '{{ states.input_number.consigne_confort.state }}'
  - wait_template: '{{ states.sensor.time.state == states.input_datetime.antoine_stop_confort.state[0:5] }}'
  - service: climate.set_temperature
    entity_id: climate.thermostat_antoine
    data_template:
      temperature: '{{ states.input_number.consigne_eco.state }}'

Et pour repasser en mode Eco, j'ai dans ce cas intégré un wait_template. Si ça fonctionne, ça n'a rien de fabuleux car pendant tout ce temps d'attente de plusieurs heures, il peut se passer plein de choses, et notamment le redémarrage de HA, et dans ce cas il ne saura plus qu'il doit repasser en mode Eco à telle heure. On va donc oublier cette façon de faire et créer une ou plusieurs automations de fin de séquence. Je dis une ou plusieurs car si pour l'instant je n'ai imaginé qu'une seule plage par jour, dans bien des cas il en aura plusieurs (matin, midi, soir...). Mais il est possible de créer une automation de déclenchement regroupant plusieurs input_time START ou STOP afin de réduire le nombre d'automations, les multiples triggers fonctionnant sur le mode OR. On peut également imaginer une automation de nuit qui repasse en Eco tous les thermostats...

trigger:
  - platform: template
    value_template: '{{ states.sensor.time.state == states.input_datetime.antoine_start_confort_matin.state[0:5] }}'
trigger:
  - platform: template
    value_template: '{{ states.sensor.time.state == states.input_datetime.antoine_start_confort_midi.state[0:5] }}'
trigger:
  - platform: template
    value_template: '{{ states.sensor.time.state == states.input_datetime.antoine_start_confort_soir.state[0:5] }}'

On peut également vouloir déclencher un trigger à un jour et heure spécifique liée à in input_datetime.

value_template: "{{ states('sensor.date_time') == (states.input_datetime.next_diner.attributes.timestamp | int | timestamp_custom('%Y-%m-%d, %H:%M', True)) }}"

Il nous faudra donc pour chaque thermostat ou groupe de thermostats une automation qui va gérer les  START et une automation pour les STOP.

Pour valider les templates il y a dans l’interface de HA un éditeur qui permet de voir et vérifier le résultat. Notez au passage [0:5] à la fin de la seconde Template qui va me permettre de ne considérer que les 5 premiers digit [20:15] d'une valeur qui en compte plus [20:15:56] (les : comptent).

Gestion des modes

J'ai fait le choix dans cet input_select de lancer des scripts pour ne pas encombrer, il il est tout à fait possible de lancer ici une suite d'action.

- alias: 'Mode : Etats du chauffage'
  description: ''
  trigger:
  - entity_id: input_select.chauffage
    platform: state
  condition: []
  action:
  - service: script.turn_on
    data_template:
      entity_id: >
        {% if is_state("input_select.chauffage", "Normal") %}
          script.mode
        {%-elif is_state("input_select.chauffage", "Diner") %}
          script.mode_boost_diner
        {%-elif is_state("input_select.chauffage", "Week-End") %}
          script.mode_boost_week-end
        {%-elif is_state("input_select.chauffage", "Abscent") %}
          script.mode_abscent
        {% endif %}

Par contre dans la gestion de cet input_bolean j'agit directement.

- alias: 'On / Off des Thermostats'
  description: ''
  trigger:
  - platform: state
    entity_id: input_boolean.thermostats_on_off
  action:
  - service: climate.set_hvac_mode
    entity_id: climate.climate_all
    data_template:
      hvac_mode: >
        {% if states.input_boolean.thermostats_on_off.state == "on" %}
          heat
        {% else %}
          off
        {% endif %}

Alors que dans cet exemple on va utiliser deux actions sur deux entités différentes :

- alias: Input Select Chauffage Antoine
  description: ''
  initial_state: true
  hide_entity: false
  trigger:
  - entity_id: input_select.thermostat_antoine
    platform: state
  condition: []
  action:
  - service: climate.set_preset_mode
    entity_id: climate.thermostat_antoine
    data_template:
      preset_mode: >
        {% if is_state("input_select.thermostat_antoine", "Présent") %}
          none
        {%-elif is_state("input_select.thermostat_antoine", "Absent") %}
          away
        {% endif %}
  - service: climate.set_hvac_mode
    entity_id: climate.thermostat_antoine
    data_template:
      hvac_mode: >
        {% if is_state("input_select.thermostat_antoine", "Marche") %}
          heat
        {%-elif is_state("input_select.thermostat_antoine", "Arrêt") %}
          off
        {% endif %}

Cas particuliers

Mode réception

Je ne suis pas frileux et j'essaie de réaliser quelques économies. J'ai donc une température de Confort entre 19 et 20°, par contre si je reçoit du monde à dîner je ne veut pas gâcher l'ambiance à cause du froid que pourraient ressentir mes invités. Je vais donc créer une dérogation à la planification normale et utiliser une température de consigne que j'appellerait Confort+ que j'aurais définie avec un input_number. Pour définir la date et l'heure du début de l’événement, je me servirait d'un input_datetime qui me servira à lancer l'automation idoine, qui va définir la température en Confort+, basculer l'état de mon input_select en mode Diner / Réception (cet état pourra me servir pour des scènes par exemple, ou à conditionner le thermostat de la chambre). 

- alias: 'TH : CONFORT+ Groupe Réception'
  description: 'Activation CONFORT+ des Thermostats du groupe Réception (CHBS)'
  trigger:
  - platform: template
    value_template: "{{ states('sensor.date_time') == (states.input_datetime.next_diner.attributes.timestamp | int | timestamp_custom('%Y-%m-%d, %H:%M', True)) }}"
  condition:
  - condition: state
    entity_id: input_select.chauffage
    state: Normal # Normal ? Dans l'absolu cette vérification est inutile)
  action:
  - service: input_select.set_options # On bascule le mode du chauffage en : Diner
    entity_id: input_select.chauffage
    data:
      options: Diner
  - service: climate.set_temperature
    entity_id: climate.climate_reception
    data_template:
      temperature: '{{ states.input_number.consigne_confort_plus.state }}'
  - service: notify.slack_hass_canaletto
    data:
      message: Passage en mode CONFORT+ ({{ states.input_number.consigne_confort_plus.state }}°) de la zone Réception (CHBS). La température moyenne est de {{ states('sensor.mi_bureau') }}°

J'utilise ici le groupe de thermostats Réception (CHS) qui comprends la cuisine, le hall et le séjour.  Vous remarquerez au passage la présence de messages vers Slack. Très utile en période de debug, cela permet également par la suite de suivre la chronologie des événements bien plus lisible que les logs.

Je n'utilise pas d'heure de fin d’événement car l'automation de clôture de nuit normale basculera en mode ECO le groupe CHBS et repassera l'état en Normal. Je déclenche ce mode à minuit par exemple, et je considère que si on se couche plus tard on pourra faire une dérogation exceptionnelle à la main directement sur les thermostats. C’est pourquoi cette automation de clôture aura un second trigger vers 03:00.

Le mode Week-End

Là c’est un peu plus compliqué. Il va falloir désactiver les automation courantes, chauffer le séjour que j'utilise peu en temps normal, chauffer les chambres des enfants qui pourront devenir des chambres d'amis...

Je vais me servir de deux input_datetime pour le début et la fin du week-end car un week-end n'est pas forcément un samedi et un dimanche mais peut être prolongé. Je pourrais ajouter un ou deux input_boolean pour valider l'utilisation des chambres des enfants en tant que chambre d'amis, mais faisons simple et consolideront simplement l'occupation de ces chambres avec une date d'arrivée et de départ comme s'il s'agissait des enfants (il faudra juste saisir les dates).

# A VENIR
# trigger à ajuster ultérieurement + select mode basé sur le mode réception...

Absence

Basculer un via un input_boolean (géré ou pas en Géo Localisation) le groupe de thermostat ALL en mode absent permettra de conserver une température minimale qui est définie dans la configuration du thermostat. A voir selon les cas d'usage, ça peut correspondre à notre fameux Hors-Gel. On peut également se dire qu'il s'agit d'une température de type Eco.

# CODE

Présence enfants

C'est un mode à part car il peut y avoir Réception avec ou sans l'un ou l'autre de mes enfants. J'ai utilisé ici des input_boolean ou le ON va définir la condition pour le fonctionnement de la planification de leur chambre, tandis que le OFF stoppera les thermostats associés.

La date et l'heure de début et de fin va être soit saisie dans un input_datetime, soit ajoutée à celui ci depuis un agenda externe (Google ou Outlook), une information publique (calendrier des vacances scolaires), tout dépends du mode de vie, mais la saisie me parait un bon début.

#CODE

J’envisage également d'utiliser la géo localisation des enfants afin d'activer ou désactiver ce commutateur. Comme ils habitent loin, on peut imaginer que s'ils entrent dans un rayon de plus de 100 km on considère qu'ils sont ici en vacances, et de fait on chauffe...

Fenêtre ouverte

Une fonction que je n'avais jamais mis en oeuvre sur Jeedom, faute d'avoir eut un résultat immédiat, couper le thermostat quand on ouvre une fenêtre (ou un groupe de fenêtres). Il faudra bien sur un détecteur d'ouverture sur la fenêtre, après quoi une paire d'automations fera le job (à répéter sur chaque thermostats ou groupes de thermostats) :

# On couppe le chauffage quand la fenêtre est ouverte
- alias: '716 : WINDOWS : OPEN'
  trigger:
    platform: state
    entity_id: binary_sensor.fenetre_antoine
    from: 'off'
    to: 'on'
    for:
      minutes: 5
  action:
  - service: climate.set_hvac_mode
    entity_id: climate.thermostat_antoine
    data:
      hvac_mode: 'off'

- alias: '717 : WINDOWS : CLOSED'
  trigger:
    platform: state
    entity_id: binary_sensor.fenetre_antoine
    from: 'on'
    to: 'off'
    for:
      minutes: 5
  action:
  - service: climate.set_hvac_mode
    entity_id: climate.thermostat_antoine
    data:
      hvac_mode: heat

Douche ponctuelle

Quand on a une vie rangée calquée sur des horaires fixes on peut bien sur préchauffer la salle de bain pour la douche du matin ou du soir. Sur ce point j'ai une vie un peu décousue et ce genre de programmation n’est pas envisageable. De plus mon radiateur sèche serviettes Acova est au normes, il n'est donc jamais brûlant et ne permet pas de chauffer rapidement la salle de bain. J'ai donc ajouté un radiateur soufflant pour obtenir une rapide montée en température (22/23° en 10/15" selon la température de départ). 

Je vais donc programmer une Automation qui aura pour trigger un double clic sur un bouton Xiaomi Aqara, voire un déclenchement vocal via GH ou Alexa, action conditionnée par un seuil de température qui lancera le radiateur soufflant et le sèche serviettes pendant 45 minutes. (cette valeur pourra être définie dans l'interface grâce à un input_timedate, input_number ou pourquoi pas un timer que je n'ai pas encore utilisé...).

# Douche ponctuelle
- alias: 'SW : Douche ON pour 45 mn.'
  description: '2 clics Inter Gauche, scèche servietets + radiateur souffant'
  trigger:
  - device_id: d800f7295af147dcad3a5f6ca4970f4a
    domain: deconz
    platform: device
    type: remote_button_double_press
    subtype: left
  condition: []
  action:
  - service: switch.turn_on
    entity_id: switch.osram
  - service: switch.turn_on
    entity_id: switch.x2d
  - service: notify.slack_hass_canaletto
    data:
      message: Passage en chauffe de la SDB. La température actuelle est de {{ states('sensor.bt_t_salle_de_bain') }}°
  - delay: '00:45:00'
  - service: switch.turn_off
    entity_id: switch.osram
  - service: switch.turn_off
    entity_id: switch.x2d
  - service: notify.slack_hass_canaletto
    data:
      message: Fin [automatique] de chauffe de la SDB. La température actuelle est de {{ states('sensor.bt_t_salle_de_bain') }}°

# Cas d'une douche rapide ou on souhaite mettre fin au chauffage avec un simlple clic
- alias: 'SW : Douche OFF'
  description: '1 click Inter Gauche'
  trigger:
  - device_id: d800f7295af147dcad3a5f6ca4970f4a
    domain: deconz
    platform: device
    type: remote_button_short_press
    subtype: left
  condition: []
  action:
  - service: switch.turn_off
    entity_id: switch.osram
  - service: switch.turn_off
    entity_id: switch.x2d
  - service: notify.slack_hass_canaletto
    data:
      message: Fin [manuelle] de chauffe de la SDB. La température actuelle est de {{ states('sensor.bt_t_salle_de_bain') }}°

VMC

Elle est programmée pour se mettre en route en fin de nuit si la température extérieure est supérieure à 5°. (prévoir la définition de cette valeur dans l'interface avec un input_number.).

- alias: 'Q : VMC : Lancement Quotiden' #5 minutes avant
  description: ''
  trigger:
    platform: time
    at: '08:00:00'
  condition:
  - condition: template
    value_template: "{{ states('sensor.bt_t_terrasse') | float > 5 }}"
  action:
  - service: switch.turn_on
    entity_id: switch.ipx800_7_vmc
  - service: notify.slack_hass_canaletto
    data:
      message: VMC Quotidienne ON à {{ states.sensor.time.state }}, la température extérieure est de {{ states.sensor.bt_t_terrasse.state }}°  
  - delay: 00:01:00
  - service: switch.turn_off
    entity_id: switch.ipx800_7_vmc
  - service: notify.slack_hass_canaletto
    data:
      message: VMC Quotidienne OFF à {{ states.sensor.time.state }}, la température extérieure est de {{ states.sensor.bt_t_terrasse.state }}° 

La VMC se mets également en route si un certain seuil d'humidité est détecté dans la salle de bain, pendant une douche par exemple. Cette consigne est définie dans l'interface par un input_number et comparé à l'humidité détectée (après avoir tâtonné pas mal je suis parti sur cet exemple.).

- alias: '"P : VMC ON/OFF : Sur Humidité excessive SDB'
  trigger:
    platform: state
    entity_id:
      - input_number.consigne_humidite
      - sensor.bt_h_salle_de_bain
  action:
    service_template: >-
      {% set hi = (states('input_number.consigne_humidite') | float) + 2.5 %}
      {% set lo = hi - 5 %}
      {% set humidity = states('sensor.bt_h_salle_de_bain') | float %}
      {% if humidity > hi %}
        switch.turn_on
      {% elif humidity < lo %}
        switch.turn_off
      {% else %}
        switch.turn_{{states('switch.ipx800_7_vmc') | lower}}
      {% endif %}
    entity_id: switch.ipx800_7_vmc

ECS

Programmée aux heures creuses, toutes nuits en hiver et un jours sur deux en été. (il me reste à bricoler un input_qq_chose pour définir les lancements car il n'y a pas que hiver ou été comme variables, le nombre de personnes présentes est également un paramètre, et comme le chauffe eau est vieillissant pour l'instant ça sera toutes les nuits).

- alias: 'Q : ECS ON : Lancement Quotiden'
  description: ''
  trigger:
    platform: time
    at: '01:00:00'
  condition:
    condition: and
    conditions:
    - condition: state
      entity_id: input_boolean.thermostats_away # Prendre en compte le mode abscent
      state: 'off'
    - condition: time
#      after: '15:00:00' # Juste pour l'exemple
#      before: '02:00:00'
      weekday:
        - mon
        - tue
        - wed
        - thu
        - fri
        - sat
        - sun
  action:
  - service: switch.turn_on
    entity_id: switch.ipx800_7_ecs
  - service: notify.slack_hass_canaletto
    data:
      message: ECS Quotidienn ON à {{ states.sensor.time.state }}

- alias: 'Q : ECS OFF : Lancement Quotiden'
  description: ''
  trigger:
    platform: time
    at: '05:00:00'
  action:
  - service: switch.turn_off
    entity_id: switch.ipx800_7_ecs
  - service: notify.slack_hass_canaletto
    data:
      message: ECS Quotidienn OFF à {{ states.sensor.time.state }}

Groupage de thermostats

By design le thermostat générique ne permet de gérer qu'un seul actionneur. Pour palier à cet inconvénient, mais également pour pouvoir appliquer des actions ou des valeurs à plusieurs thermostats il existe l'intégration climate_group qui va nous permettre de définir des groupes de thermostats qui seront ainsi vus comme un seul. Il est même possible de créer une carte avec ce groupe qui reprendra la moyenne des températures remontées sur chaque thermostat et d'y affecter une valeur de garde unique. Si cette dernière possibilité est inutile, je vais utiliser le groupe climate_jour avec de 3 thermostats dans ma zone de vie et le groupe climate_all pour allumer ou éteindre le chauffage avec le ON/OFF d'un un input_boolean.

  climate:
  - platform: climate_group
    name: 'Climate Jour'
    entities:
    - climate.thermostat_bureau
    - climate.thermostat_cuisine
    - climate.thermostat_hall

  - platform: climate_group
    name: 'Climate All'
    entities:
    - climate.thermostat_bureau
    - climate.thermostat_cuisine
    - climate.thermostat_hall
    - climate.thermostat_salle_de_bain
    - climate.thermostat_sejour
    - climate.thermostat_lionel
    - climate.thermostat_antoine
    - climate.thermostat_marie

Attention : pour l'instant ce composant ne supporte pas set_preset_mode qui permet de passer un thermostat en mode absent. C’est en discussion sur GitHub.

Surveillance

Comme expliqué plus haut j'ai choisit de générer des messages Slack pour chaque événements, delà me permet d'avoir un journal. Pour le debug on peut également surveiller ce qui est en place sur le dashboard, notamment au niveau des températures avec ce genre de graphique (interactif en passant la souris sur les courbes) :

Consommation

En ces temps ou l'énergie est de plus en plus coûteuse il devient opportun d’installer des compteurs d'énergie. Certains modules, Shelly par exemple, présentent l'avantage de remonter cette information, instantanée et cumulée. Cela pourra permettre d'afficher la consommation, mais également, avec un peu d’huile de coude, d'en calculer le coût. On peut également utiliser un Shelly EM avec des pinces pour mesurer la consommation d'un segment, ce que j'ai fait ici pour ma baie informatique et l'arrivée EdF, alors que la troisième ligne prends en compte le comptage d'un dimmer.

L’insertion de compteurs ou de pinces n'est pas facile dans un tableau existant utilisant des peignes. Legrand a bien annoncé des modules disjoncteurs ou différentiels intégrant cette fonction, mais outre leur tarif qui sera élevé, rien ne dit que le protocole (Zigbee) sera suffisamment ouvert pour s'en servir dans Home Assistant, mais c’est à considérer pour du neuf. En rénovation on préférera des module au dos des convecteurs ou les blocs de 4 relais DIN proposés par Shelly.

Re-Planification

Pour toutes ces automatisations on part du postulat que :

  1. La machine qui héberge Home Assistant est fiable et secourue par un UPS.
  2. Les actionneurs savent retrouver leur état initial après une coupure électrique. En ce qui me concerne c’est le cas des Shelly mais également de ma carte IPX800 v2. Pour les autres (modules X2D ou DI-O en 433 Mhz. par exemple, il faudra les remplacer s'ils sont stratégiques, du reste ils sont gérés par le RFPlayer sur mon Jeedom en esclave qui lui aussi devra à terme disparaître.

Si on respecte ça, une coupure du réseau électrique n'affectera pas le chauffage au retour, pas plus qu'un redémarrage de Home Assistant puisqu'on dans tous les cas on n'a pas de WAIT mais des automations de fin de cycle.

GéoLocalisation

La géolocalisation fonctionne tellement bien sous HA, que ce soit via l'application ou via le partage de position sur Google Maps, que ça me donne envie de l'utiliser. On peut également utiliser le plugin Unifi pour gérer une présence basée sur le WI-FI vraiment locale, alors que via Google Maps on pourra gérer des approches.

Avec des convecteurs la montée en chauffe est assez longue, par contre dans le cas d'un climatiseur il est possible d'obtenir un bon rafraîchissement d'une pièce en une dizaine de minutes. On peut donc facilement imaginer d'activer un climatiseur quand un utilisateur sort de sa zone Travail pour rentrer chez à son domicile et ainsi ne pas perdre en confort s'il rentre trop tôt, ou ne pas consommer de l’énergie inutile s'il rentre trop tard.

Conclusion

J'ai longtemps été sceptique sur la possibilité de remplacer Jeedom, et j'ai longtemps repoussé. J'avais peur de ne pas pouvoir faire ce que je fais avec Jeedom pour le chauffage, ce n’est pas le cas, tout est possible avec Home Assistant, par contre il faut rentrer dans le concept, ce qui finalement m'a pris bien moins de temps que quand j'ai transité de la ZiBase à Jeedom.

Le résultat est concluant et me semble bien plus fiable, on verra à l'usage, mais surtout je ne suis plus tributaire de certaines mises à jours de plugin hasardeuses. Finalement pas sur que ça m'ai pris plus de temps qu'un passage de la v3 à la v4 de Jeedom.

Maintenant que j'ai défini le concept de ma gestion du chauffage il va me falloir finaliser, dupliquer les blocs de code, les ajuster, tester encore et basculer réellement de Jeeom à HA. Je ne serait pas aidé par la météo qui est ici très clémente cet hiver (19.5° ce midi). Une fois terminé, j'ajusterais cet article en fonction des modifications éventuelles.

N’hésitez pas à commenter.

EDIT : Basculer de Jeedom m’aura pris moins de temps que je ne l'avais imaginé : moins de 3 semaines de mon temps libre et de quelques nuits... C'est bien moins de temps que j'ai du passer sur Jeedom au début et surtout pendant ! Je ne regrette absolument pas d'avoir fait cette migration, et contrairement à Jeedom je prendrais surement la peine d'installer Home Assistant chez des proches car je sais que je peux quasiment tout faire et surtout maintenir aisément cette solution.

Next !

Il me reste à nettoyer tous ces codes et à les publier sur GitHub !