Home Assistant & Shelly

Il y a un an quand j'ai commencé à utiliser des Shelly sous Home Assistant l'évidence était d'utiliser l'intégration tierce Shelly4HASS. Depuis la compatibilité MQTT s'est bien améliorée et j'y ait trouvé un intérêt, alors même  que les équipes de Home Assistant ingéraient le support natif de Shelly au core. Donc aujourd'hui il n'y a plus vraiment d'intérêt à utiliser cette intégration tierce, toujours dans la logique de faire au plus simple. Bien que Shelley4HASS fonctionne toujours très bien et présente l'avantage de fournir beaucoup d'informations dans les attributs.

Deux options

  1. Vous débutez en domotique ou vous voulez juste allumer deux ampoules et actionner un relaie. Laissez vous guider, HA découvrira vos modules et vous les piloterez en deux clics afin d'n exploiter toutes les possibilités, l'intégration de base supporte toutes les possibilités et s'améliore de releases en releases.
  2. Vous passez vos nuits sur votre serveur domotique, vous fréquentez des barbus qui vous poussent à souder des cartes électroniques, votre facteur vous regarde bizarrement depuis que vous recevez plusieurs fois par semaine des paquets en provenance de Chine. Attention, bientôt vous n'aurez plus de famille, d'ailleurs votre femme pense à demander le divorce. Mais faites vous plaisir prenez la route MQTT, en attendant de retrouver la votre, c'est aussi une forme de liberté.

Je ne vais pas vous expliquer MQTT, d'autres l'ont fait, mais MQTT est un vrai protocole domotique en devenir. Attention toutefois, chez Shelly, c'est Cloud (App mobile, Alexa, GH) ou MQTT. Il faut choisir. Attention également aux modules Shelly fonctionnant sur piles, personnellement j'ai abandonné ces modules car même avec du WI-FI Low Energy les piles sont trop rapidement à changer, et il y a des chances qu'en MQTT ce soit encore pire. Donc pour les sondes et autres capteurs, Zigbee est à mon sens plus adapté.

MQTT sur Home Assistant

Je ne vais pas détailler ici l'a mise en œuvre de MQTT, ce n'est pas le propos, mais en gros on installe un broker (dans les adons) et ensuite on ajoute l'intégration MQTT depuis la page des intégrations. Et si on ne veut pas se taper la configuration individuelle des modules, on installe Shelly Discovery qui est un script Python qui va le faire pour vous. Pourquoi ça alors que d'autre modules vont en MQTT créer tout ce qui est nécessaire sous HA ? Simplement parce que Shelly se veut générique et ainsi ils n'ont pas à gérer cette partie. Ca se défend.

Migration vers MQTT

On commence par imprimer une liste des Shelly existants sous Shelly4HASS avec leur adresse et leur usage afin de pouvoir les repérer en MQTT.

Dans l'intégration MQTT qui a remonté nos modules c'est le moment de penser au renommage. C'est un point important et il sera bien moins aisé d'y revenir. Il y a plusieurs écoles.

  • Renommage soft ou on renomme juste le display name.
  • Renommage hard ou l'on renomme le display name et l'entité. Dans ce cas il faut le faire avant d'aller faire le travail suivant car ça aura des conséquences sur le travail d'intégration.
  • Renommage unique du display name de l'entité qui actionne (light ou switch). Ca sera utile pour le présenter dans Alexa ou GH.
  • Dans tous les cas il ne faut pas oublier d'affecter une pièce (qui sera également reprise dans Alexa et GH)
  • Et sur la config des Shelly de type relais (1, 1PM, 2.5 ou prises) utilisés pour les éclairages, aller dans Appliance type et changer general pour light.

A ce stade on veut virer Shelly4HASS dans les intégrations et aussi le composant dans HACS. Avantage on va voir tout de suite ce qui ne fonctionne plus. Mais on peu aussi le faire après avoir migré en MQTT si on ne pense pas pouvoir faire ce travail d'une traite. Quand Shelly4HASS n'est plus présent on va voir remonter automatiquement les modules via l'intégration de base Shelly. On peut éviter ça si on en a beaucoup ou simplement clique sur ignorer dans les intégrations.

discovery:
  ignore:
    - shelly

Ensuite il va falloir de la patience et comme toujours de la rigueur.

Point à vérifier pour chaque module :

  • S'ils sont affichés dans Lovelace (relais et conso).
  • S'ils sont télécommandés (par quoi, automation, BP ou ComanderX).
  • S'ils sont déclarés en utility_meter:
  • S'ils sont utilisé dans les automations ou des thermostats
  • S'ils sont utilisés dans d'autres cas particuliers.

On les faits les uns après les autres et on valide chaque étape en en vérifiant le bon fonctionnement.

Bienvenue dans MQTT !

En bonus, MQTT Explorer qui sera bien utile pour mettre au point des choses complexes et vérifier ce qui se trame sur votre broker. Broker que l'on a ici monté sur HA, mais qui dans l'absolu pourrait être sur une autre machine, un NAS, voire même sur un autre site. Il existe d'ailleurs des brokers publics pour faire communiquer différents objets entre eux. Vous allez me dire que c'est une façon de recentraliser l'information, oui, mais ça peut être nécessaire en IoT avec des objets volatiles car si l'objet A ne parvient pas à joindre l'objet B, le broker conservera alors le message le temps que l'objet B soit disponible... D'où l'intérêt d'une certaine centralisation qui peut d'ailleurs être répartie...

EDIT : un article très bien fait : https://henriksozzi.it/2021/02/shelly-e-home-assistant/ (clic droit traduire si vous ne maitrisez pas l'italien...)

 

Home Assistant & UPS

Vous allez me demander pourquoi gérer les onduleurs sur Home Assistant ? Simplement pour être avertit en cas de coupure électrique via une notification (si on est en déplacement il peut être intéressant d'envoyer une personne de confiance réarmer en cas d'une défaillance locale, histoire de ne pas perdre le contenu du congélateur (vécu)), ensuite exécuter des actions sur ce qui est secouru et en dernier ressort éteindre le serveur. Les informations ainsi remontées donneront également des indication sur l'état des batteries afin de les changer préventivement.

J'ai souvent des coupures à la campagne, j'ai deux gros onduleurs réseau de marque APC et je me suis dès mes débuts intéressé à eux avec ce que j'ai alors trouvé de plus simple.

APC UPS Daemon

ApcUpsd s'installe sous la forme d'un addon et la suite est intégrée à Home Assistant.

On ajoute aux addons ce repository : https://github.com/korylprince/hassio-apcupsd et on installe la version IP ou USB qui nous convient. Et on configure.

name: APC UPS
cable: ether
type: snmp
device: 192.168.210.6

Ensuite on ajoute ça dans configuration.yaml :

apcupsd:

Ainsi que quelques sensors :

- platform: apcupsd
  resources:
    - apc
    - date
    - hostname
    - version
    - upsname
    - cable
    - driver
    - upsmode
    - starttime
    - model
    - status
    - linev
    - loadpct
    - bcharge
    - timeleft
    - mbattchg
    - mintimel
    - maxtime
    - maxlinev
    - minlinev
    - outputv

Et on termine avec un binary :

- platform: apcupsd
  name: UPS

Les paquets sont marqués obsolètes, mais pour l'instant j'utilisait ça depuis un an et ça fonctionne très bien.

SNMP

Si on dispose d'un onduleur réseau, ici APC, voici un "package" (mode pakage de HA) pour le faire en SNMP. Le gros avantage c'est qu'il n'y a absolument rien à installer, SNMP étant supporté de base dans Home Assistant. Attention c'est un peu long...

sensor:
  - platform: snmp
    name: ups_smart_750_capacity
    host: 192.168.210.7
    baseoid: 1.3.6.1.4.1.318.1.1.1.2.2.1.0
    accept_errors: true
    unit_of_measurement: '%'
  - platform: snmp
    name: ups_smart_750_runtime_remaining
    host: 192.168.210.7
    baseoid: 1.3.6.1.4.1.318.1.1.1.2.2.3.0
    accept_errors: true
    value_template: >-
      {% set time = (value | int) / 100 | int %}
      {% set minutes = ((time % 3600) / 60) | int %}
      {% set hours = ((time % 86400) / 3600) | int %}
      {% set days = (time / 86400) | int %}
    
      {%- if time < 60 -%}
        Less than a minute
        {%- else -%}
        {%- if days > 0 -%}
          {{ days }}d
        {%- endif -%}
        {%- if hours > 0 -%}
          {%- if days > 0 -%}
            {{ ' ' }}
          {%- endif -%}
          {{ hours }}h
        {%- endif -%}
        {%- if minutes > 0 -%}
          {%- if days > 0 or hours > 0 -%}
            {{ ' ' }}
          {%- endif -%}
          {{ minutes }}m
        {%- endif -%}
      {%- endif -%}
  - platform: snmp
    name: ups_smart_750_load_percentage
    host: 192.168.210.7
    baseoid: 1.3.6.1.4.1.318.1.1.1.4.2.3.0
    accept_errors: true
    unit_of_measurement: '%'
  - platform: snmp
    name: ups_smart_750_battery_temperature
    host: 192.168.210.7
    baseoid: 1.3.6.1.4.1.318.1.1.1.2.2.2.0
    accept_errors: true
    unit_of_measurement: '°C'
  - platform: snmp
    name: ups_smart_750_battery_status
    host: 192.168.210.7
    baseoid: 1.3.6.1.4.1.318.1.1.1.2.2.4.0
    accept_errors: true
    value_template: >-
      {%if value == '1' %}
        Good
      {% elif value == '2' %}
        Failed
      {% endif %}
  - platform: snmp
    name: ups_smart_750_type
    host: 192.168.210.7
    baseoid: 1.3.6.1.4.1.318.1.1.1.1.1.1.0
    accept_errors: true
  - platform: snmp
    name: ups_smart_750_input_voltage
    host: 192.168.210.7
    baseoid: 1.3.6.1.4.1.318.1.1.1.3.2.1.0
    accept_errors: true
    unit_of_measurement: 'V'
  - platform: snmp
    name: ups_smart_750_last_transfer_reason
    host: 192.168.210.7
    baseoid: 1.3.6.1.4.1.318.1.1.1.3.2.5.0
    accept_errors: true
    value_template: >-
      {%if value == '1' %}
        No events
      {% elif value == '2' %}
        High line voltage
      {% elif value == '3' %}
        Brownout
      {% elif value == '4' %}
        Loss of mains power
      {% elif value == '5' %}
        Small temporary power drop
      {% elif value == '6' %}
        Large temporary power drop
      {% elif value == '7' %}
        Small spike
      {% elif value == '8' %}
        Large spike
      {% elif value == '9' %}
        UPS self test
      {% elif value == '10' %}
        Excessive input voltage fluctuation
      {% endif %}
  - platform: snmp
    name: ups_smart_750_output_load
    host: 192.168.210.7
    baseoid: 1.3.6.1.4.1.318.1.1.1.4.2.3.0
    accept_errors: true
    unit_of_measurement: '%'
  - platform: snmp
    name: ups_smart_750_output_current
    host: 192.168.210.7
    baseoid: 1.3.6.1.4.1.318.1.1.1.4.2.4.0
    accept_errors: true
    unit_of_measurement: 'A'
  - platform: snmp
    name: ups_smart_750_last_self_test_result
    host: 192.168.210.7
    baseoid: 1.3.6.1.4.1.318.1.1.1.7.2.3.0
    accept_errors: true
    value_template: >-
      {%if value == '1' %}
        OK
      {% elif value == '2' %}
        Failed
      {% elif value == '3' %}
        Invalid Test
      {% elif value == '4' %}
        Test In Progress
      {% endif %}
  - platform: snmp
    name: ups_smart_750_last_self_test_date
    host: 192.168.210.7
    baseoid: 1.3.6.1.4.1.318.1.1.1.7.2.4.0
    accept_errors: true
  - platform: snmp
    name: ups_smart_750_communication_status
    host: 192.168.210.7
    baseoid: 1.3.6.1.4.1.318.1.1.1.8.1.0
    accept_errors: true
    value_template: >-
      {%if value == '1' %}
        on
      {% elif value == '2' %}
        off
      {% endif %}
  - platform: snmp
    name: ups_smart_750_status
    host: 192.168.210.7
    baseoid: 1.3.6.1.4.1.318.1.1.1.4.1.1.0
    accept_errors: true
    value_template: >-
      {%if value == '1' %}
        Unknown
      {% elif value == '2' %}
        On Line
      {% elif value == '3' %}
        On Battery
      {% elif value == '4' %}
        On Smart Boost
      {% elif value == '5' %}
        Timed Sleeping
      {% elif value == '6' %}
        Software Bypass
      {% elif value == '7' %}
        Off
      {% elif value == '8' %}
        Rebooting
      {% elif value == '9' %}
        Switched Bypass
      {% elif value == '10' %}
        Hardware Failure Bypass
      {% elif value == '11' %}
        Sleeping Until Power Returns
      {% elif value == '12' %}
        On Smart Trim
      {% endif %}

homeassistant:
  customize:
    sensor.ups_smart_750_status:
      device_class: connectivity
      friendly_name: Smart-UPS status
    sensor.ups_smart_750_capacity:
      device_class: battery

NUT

Enfin on peut aussi utiliser NUT (Network UPS Tools) que beaucoup ici connaissent et qui est une légende dans le monde des UPS.

Pour ça il faut installer le serveur NUT que l'on trouvera dans les addons et qui communiquera avec vos onduleurs. Voici deux configurations à adapter selon que l'onduleur soit connecté en USB ou en IP. La documentation de NUT est une véritable bible des UPS et vous y trouverez ce qui vous manque.

USB

users:
  - username: nut
    password: MyPassword
    instcmds:
      - all
    actions: []
devices:
  - name: apc
    driver: usbhid-ups
    port: auto
    config:
      - desc = "APC Back-UPS 600VA"
      - vendorid = 051d
mode: netserver
shutdown_host: 'false'

IP

users:
  - username: nut
    password: MyPassword
    instcmds:
      - all
    actions: []
devices:
  - name: apc_1400
    driver: snmp-ups
    port: 192.168.210.6
    community: public
    snmp_version: v1
    pollfreq: 15
    config:
      - desc = "APC Smart-UPS 1400VA"
  - name: apc_750
    driver: snmp-ups
    port: 192.168.210.7
    community: public
    snmp_version: v1
    pollfreq: 15
    config:
      - desc = "APC Smart-UPS 750VA"
mode: netserver
shutdown_host: 'false'

A partir de là il faut aller dans les intégrations, ajouter l'intégration NUT, la configurer avec ces informations :

  • Host : a0d7b954-nut
  • Port : 3493
  • Username : nut
  • Password : MyPassword

Et ensuite choisir les seniors que l'on souhaite créer, utiliser et superviser.

Automations

Une fois que l'on dispose des sensors il sera possible d'effectuer des actions selon le comportement de ceux ci. Libre à vous d'imaginer, ou par exemple utiliser l'intégration Alert pour recevoir des notifications répétées.

ups_1:
  name: UPS APC 1
  entity_id: binary_sensor.ups
  state: 'off'   # 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}} > A L A R M  U P S | Coupure EDF" 
  done_message: "{{ states.sensor.date_time.state}} > A L A R M  U P S | Rétablissement EDF"
  notifiers:
    - slack_hass_canaletto
    - Free_Mobile

Voilà, un peu soporifique, je suis d'accord, mais le sujet n'est pas rigolo !

 

 
 

 

 

Home Assistant & Planification, Schedy !

l'inconvénient du Scheduler que je vous avait présenté ici c'est qu'il ne fait pas de replanification et il se contente uniquement d'une action (avec ses contraintes) en début de plage, ce qui impose de devoir programmer la plage suivante. De fait si pour une raison quelconque l'appareil ou le thermostat n'a pas reçu l'ordre, c'est raté. De même il est impossible d'imposer une contrainte supplémentaire après le départ, la notion d'humidité utile pour la clim par exemple, ou encore l'arrivée d'une personne qui ne supporte pas la clim. Pour résumer le Scheduler c'est une action avec des contraintes en début de plage uniquement, là ou Schedy va savoir replanifier dynamiquement en fonction des nouvelles contraintes pendant le déroulement d'une plage. Et ça change tout !

Je vous passe l'installation, ça sous entend app_daemon et j'en ai déjà parlé ici. L'utilisation de Schedy est très simple. Tout se passe dans un seul fichier .yaml et si vous êtes le seul occupant de la demeure ce sera parfait car il suffit d'aller changer les valeur et de sauvegarder pour que les modifications soient prises en compte dynamiquement. Ce mode dynamique est le gros plus des applications app_daemon. Je vous la fait courte car la doc est très bien faite et vous y trouverez d'autres exemples, qui d'ailleurs ne s'appliquent pas uniquement au chauffage. Voici la partie principale du fichier de configuration de Schedy :

      schedule:
      - v: 20
        rules:
        - weekdays: 1-5
          rules:
          - rules:
            - x: "Next() if heating_mode() == 'Normal' else Break()"
            - { start: "06:00", end: "07:30" }
            - { start: "15:00", end: "22:30" }
          - rules:
            - x: "Next() if heating_mode() != 'Normal' else Break()"
            - { start: "08:00", end: "23:30" }
        - weekdays: 6-7
          rules:
          - { start: "08:00", end: "23:30" }

Si vous voulez changer un horaire, un mois ou une saison, il suffit le le faire ici.

Un GUI pour Schedy...

A la base Schedy ne dispose pas d'une interface et n'a pas été développé dans ce sens. Le produit est très stable et son auteur n'a plus trop le temps de le faire évoluer, pour l'heure il se contente de la maintenance.

L'idée ici n'est pas de fournir une planification plug & play pour l'administrateur, mais que celui-ci permette à un utilisateur lambda de modifier les plages et la température de garde associée à chacune d'elles. On va gérer ici 4 plages par thermostat (matin, midi, soir et nuit), sachant que l'on pourrait juste les numéroter et en créer plus ou moins. On dispose également d'une consigne pour la température qui sera appliquée en dehors de ces plages (et qui n'a rien à voir avec le mode hors gel qui lui se gère sur le thermostat.

On va se servir du mode mode "package" de Home Assistant, ce qui va nous permettre d'avoir dans un seul fichier .yaml tous les composants nécessaires pour accompagner notre thermostat. Pour ça il vous faudra faire une petite modification dans le fichier de configuration :

homeassistant:
  packages: !include_dir_named packages

Schedy n'a pas de GUI mais dispose toutefois d'une mince ouverture pour communiquer avec Lovelace et on va ainsi pouvoir lui adjoindre une interface minimale, mais sur mesure. On aurait pu penser à ce qu'il utilise des input_datetime: pour les horaires, mais non la seule possibilité réside dans des input_number: ou sensor: au travers desquels on va faire passer les températures de consigne et les heures de début et de fin des plages. Et pour les horaires (ça m'a pris du temps à comprendre) il faut lui donner l'heure sous la forme d'un nombre en minutes écoulées depuis minuit. Donc si on veut qu'une plage débute à 02:00 il faut lui donner 120. Ca ne s'invente pas !

Il va donc nous falloir traduire les input_datetime: qui vont permettre la saisie d'un horaire (à dupliquer par le nombre de plages à gérer) :

input_datetime:
  ac_start_1:
    has_date: false
    has_time: true
  ac_stop_1:
    has_date: false
    has_time: true

En sensor: afin de ne pas avoir à saisir le nombre de minutes... (Merçi @mathieu !) (à dupliquer par le nombre de plages à gérer) :

sensor:
  platform: template
  sensors:
    ac_start_1:
      friendly_name: "AC Start 1"
      icon_template: mdi:timer-sand
      value_template: "{{ (state_attr('input_datetime.ac_start_1', 'timestamp') / 60)|int }}"
    ac_stop_1:
      friendly_name: "AC Stop 1"
      icon_template: mdi:timer-sand
      value_template: "{{ (state_attr('input_datetime.ac_stop_1', 'timestamp') / 60)|int }}"

On va également créer des input_number: pour les températures de consigne (à dupliquer par le nombre de plages à gérer, sans oublier la température hors plages) :

input_number:
  ac_max_1_temp:
    name: Ac Temp 1
    min: 14
    max: 26
    step: 0.5
    unit_of_measurement: °C

On ajoute un input_boolean: pat plage, il va nous permettre d'activer ou désactiver la plage :

input_boolean:
  ac_1:
    name: AC 1
    icon: mdi:account-check

De façon plus globale on se servira également d'un binary_sensor:  sur lequel reposera l'activation du chauffage, un autre pour la climatisation (je pense que ça peut également être des input_boolean:). Au chapitre des contraintes j'ai déjà un input_boolean: qui me sert au mode absent. Il est également possible d'utiliser workday: dans les contraintes et ainsi définir des plages qui s'exécuteront soit les jours de travail, soit le week-end. Mais on peut s'en passer et gérer ça dans Schedy, l'avantage restant à workday: qui lui gère les jours fériés.

Voici la première partie du fichier de configuration de la partie Schedy :

schedy_heating:  # This is our app instance name.
  module: hass_apps_loader
  class: SchedyApp

  actor_type: thermostat

  expression_environment: |
    def time_between(start, end):
        current = time.hour * 60 + time.minute + 1
        if start >= end:
            return current >= start or current < end
        return current >= start and current < end
  
  schedule_prepend:
  - x: "Mark(OFF, Mark.OVERLAY) if not is_empty(filter_entities('binary_sensor', state='on', window_room=room_name)) else Next()"
  - x: "OFF if is_off('binary_sensor.heating_enabled') else Next()"

  watched_entities:
  - binary_sensor.heating_enabled

La première partie  concerne la déclaration de l'application app_daemon. Ensuite le type d'utilisation et l'environnement qui va nous permettre de récupérer les informations de planification depuis Lovelace. On trouve ensuite la gestion des ouvertures (Voir plus bas en détail) et du mode OFF du chauffage. La dernière ligne concerne la déclation des entités HA que nous utilisons dans cette partie, ici le binary_sensor: du ON/OFF.

La suite concerne les pièces avec leurs thermostats associés :

rooms:
    bureau:
      rescheduling_delay: 120
      actors:
        climate.thermostat_bureau:
       
      watched_entities:
      - binary_sensor.bureau_door_delayed
      - input_number.day_temperature
      - sensor.ac_start_1
      - sensor.ac_stop_1
      - input_boolean.thermostats_away        # Mode Absent qui pourrait également être dans les paramètres globaux
      - input_boolean.ac_1
      # - binary_sensor.workday_sensor

      schedule:
      - months: 1-4
        weekdays: 1-6
        rules:
        - x: state("input_number.day_temperature") if (state("input_boolean.ac_1") == "on") and (state("binary_sensor.bureau_door_delayed") == "off") and  (state("input_boolean.thermostats_away") == "off") and time_between(int(state("sensor.ac_start_1")), int(state("sensor.ac_stop_1"))) else Next()
      - v: 19

Outre le thermostat on déclare ici les différentes entités que l'on va utiliser.

La ligne importante est la plus longue à la fin. On commence par la température, l'activation ou nom de ce planning, la gestion de l'ouverture, le mode absent qu'il me faudra déplacer dans les paramètres globaux et l'heure de début et de fin. On remarque également que je n'ai ici pas utilisé workday: mais que j'ai choisit de laisser (pour l'exemple) les jours et mois ou cette planification peut s'exécuter (on peut également utiliser la saison). La dernière ligne concerne la température de consigne qui sera appliquée en dehors des plages. Il est également possible de la gérer depuis Lovelace avec l'input_number: idoine.

Les ouvertures

Curieusement l'auteur a prévu de gérer les ouvertures, mais il n'a pas intégré la notion de délai. Ainsi de base si on ouvre une porte ou une fenêtre on coupe le convecteur immédiatement, ce qui n'a pas de sens si on ne fait que rentrer ou sortir, alors que ça en aurait si on ouvre une fenêtre pour aérer une pièce plus longuement. D'ailleurs si ça n'a pas d'impact sur un convecteur, le résultat sera bien différent pour un climatiseur pour lequel les changements d'état on souvent une grande latence. On va donc devoir jouer des avec les templates et ainsi créer des retardateurs pour les ouvertures (et non je ne pousserait pas le vice jusqu'à aller gérer les delais dans Lovelace...) (la partie icon_template: est vraiment là pour l'exemple car il n'y aucun intérêt à afficher ça dans Lovelace) :

binary_sensor:
  - platform: template
    sensors:
      garage_door_delayed:
        friendly_name: "Delayed Garage Door"
        #window_room: bedroom
        delay_on: 
          seconds: 180
        delay_off:
          seconds: 360
        value_template: >-
          {{ is_state('binary_sensor.porte_garage', 'on') }}
        icon_template: >-
          {% if is_state('binary_sensor.porte_garage', 'on') %}
            mdi:door-open
          {% else %}
            mdi:door-closed
          {% endif %}

Le froid

Toute cette partie peut s'appliquer à des convecteurs ou climatiseurs en mode chauffage. Pour le mode froid le fonctionnement est un peu différent, on va gérer un seuil de déclenchement et une température de maintient, alors qu'en dehors des plage on éteindra le climatiseur (ici dans la dernière partie).

Epilogue...

Pour cet article, qui m'a pris un peu trop de temps, je me suis bien sur inspiré de mon expérience puisée dans le documentation de Schedy et le fil de discutions du forum Home Assistant. Mais j'ai également trouvé le GitHub d'un utilisateur ou il présente sa configuration. Je vous invite à aller y puiser des idées, et vous remarquerez qu'il a choisit une présentation un peu différente pour la saisie des plages horaires à l'aide de sliders. En ce qui me concerne j'ai préféré compacter au maximum cette partie, même si toutes les fantaisies sont possibles. Pensez à revenir car j'enrichirait cet article dès que j'aurais le temps de continuer.

Replay. La suite...

J'avais un peu laissé en plan cette idée mais mon climatiseur Daikin perd parfois le WI-FI, donc la notion de replanification de Schedy prend toute son importance. Entre temps @PYG a publié un script qui simplifie grandement la création des différentes entités nécessaires, script à lancer en SSH et que l'on pourra adapter à souhait, ce que j'ai fait ici pour mon climatiseur en mode chauffe, et qu'il me faudra adapter en mode froid (on gère les pièces en ligne 10 et le nombre de périodes en 12).

/bin/bash
test -d /config/packages || mkdir /config/packages
cd /config/packages
cat >heating_global.yaml<<EOF
input_boolean:
  heating_enabled:
    name: Heating Global
    icon: mdi:toggle-switch
EOF
for room in hall_ac
do
for period in {1..4}
do
cat >${room}_heating_period_${period}.yaml<<EOF
input_datetime:
  ${room}_heating_period_${period}_start:
    name: "Heating Period ${period} Start Time"
    has_date: false
    has_time: true
  ${room}_heating_period_${period}_end:
    name: "Heating Period ${period} End Time"
    has_date: false
    has_time: true
sensor:
  platform: template
  sensors:
    ${room}_heating_period_${period}_start:
      value_template: "{{ (state_attr('input_datetime.${room}_heating_period_${period}_start', 'timestamp') / 60)|int }}"
    ${room}_heating_period_${period}_end:
      value_template: "{{ (state_attr('input_datetime.${room}_heating_period_${period}_end', 'timestamp') / 60)|int }}"
input_number:
  ${room}_heating_period_${period}_temperature:
    name: Heating Period ${period} Temperature
    min: 18
    max: 25
    step: 1
    unit_of_measurement: °C
    icon: 'mdi:thermometer-lines'
input_boolean:
  ${room}_heating_period_${period}:
    name: Heating Period ${period} Enabled
    icon: mdi:toggle-switch
EOF
done
done
exit

Ensuite j'ai un peu modifié sa config Schedy afin de l'adapter à mon besoin...

schedy_heating:
  module: hass_apps_loader
  class: SchedyApp
  
  actor_type: thermostat
  
  actor_templates:
    default:
      send_retry_interval: 30
      send_retries: 10
      supports_hvac_modes: true
      off_temp: 18
  
  watched_entities:
  - input_boolean.homeoffice
  - binary_sensor.workday_sensor
  # - binary_sensor.holiday_sensor
  - input_boolean.heating_enabled
  
  expression_environment: |
    def homeoffice():
      return is_on("input_boolean.homeoffice")
    def workday():
      return is_on("binary_sensor.workday_sensor")
    # def holiday():
      # return is_on("binary_sensor.holiday_sensor")
    def time_between(start, end):
        start = int(state(start))
        end = int(state(end))
        current = time.hour * 60 + time.minute + 1
        if start >= end:
            return current >= start or current < end
        return current >= start and current < end

  schedule_prepend:
  - x: "14 if is_off('input_boolean.heating_enabled') else Next()"
  
  rooms:
    hall_ac:
      allow_manual_changes: true
      rescheduling_delay: 1
      actors:
        climate.daikin:
          template: default
      watched_entities:
      - input_number.hall_ac_heating_period_1_temperature
      - input_boolean.hall_ac_heating_period_1
      - sensor.hall_ac_heating_period_1_start
      - sensor.hall_ac_heating_period_1_end
      - input_number.hall_ac_heating_period_2_temperature
      - input_boolean.hall_ac_heating_period_2
      - sensor.hall_ac_heating_period_2_start
      - sensor.hall_ac_heating_period_2_end
      - input_number.hall_ac_heating_period_3_temperature
      - input_boolean.hall_ac_heating_period_3
      - sensor.hall_ac_heating_period_3_start
      - sensor.hall_ac_heating_period_3_end
      - input_number.hall_ac_heating_period_4_temperature
      - input_boolean.hall_ac_heating_period_4
      - sensor.hall_ac_heating_period_4_start
      - sensor.hall_ac_heating_period_4_end
      schedule:
      - rules:
        # not workday
        - rules:
          - x: "Break() if workday() else Next()"
          - x: >
              state("input_number.hall_ac_heating_period_1_temperature")
              if (is_on("input_boolean.hall_ac_heating_period_1")
              and time_between("sensor.hall_ac_heating_period_1_start", "sensor.hall_ac_heating_period_1_end"))
              else Next()
          - x: >
              state("input_number.hall_ac_heating_period_2_temperature")
              if (is_on("input_boolean.hall_ac_heating_period_2")
              and time_between("sensor.hall_ac_heating_period_2_start", "sensor.hall_ac_heating_period_2_end"))
              else Next()
          - x: "Break(2)"
        # workday
        - rules:
          - x: >
              state("input_number.hall_ac_heating_period_3_temperature")
              if (is_on("input_boolean.hall_ac_heating_period_3")
              and time_between("sensor.hall_ac_heating_period_3_start", "sensor.hall_ac_heating_period_3_end"))
              else Next()
          - x: >
              state("input_number.hall_ac_heating_period_4_temperature")
              if (is_on("input_boolean.hall_ac_heating_period_4")
              and time_between("sensor.hall_ac_heating_period_4_start", "sensor.hall_ac_heating_period_4_end"))
              else Next()
          - x: "Break(2)"
      # default
      - v: 18

Et j'ai créé la carte Lovelace qui va avec...

type: grid
square: true
cards:
  - type: vertical-stack
    cards:
      - type: entities
        entities:
          - entity: binary_sensor.heating_enabled
            name: Etat du chauffage
          - entity: input_boolean.heating_enabled
            name: Activation du chauffage
          - entity: binary_sensor.workday_sensor
            name: Jour de semaine
        theme: teal
        title: AC Daikin
      - type: entities
        entities:
          - entity: input_boolean.hall_ac_heating_period_1
          - entity: input_datetime.hall_ac_heating_period_1_start
          - entity: input_datetime.hall_ac_heating_period_1_end
          - entity: input_number.hall_ac_heating_period_1_temperature
          - entity: input_boolean.hall_ac_heating_period_2
          - entity: input_datetime.hall_ac_heating_period_2_start
          - entity: input_datetime.hall_ac_heating_period_2_end
          - entity: input_number.hall_ac_heating_period_2_temperature
        title: Week-End & Jours fériés
        show_header_toggle: false
        theme: teal
        state_color: true
      - type: entities
        entities:
          - entity: input_boolean.hall_ac_heating_period_3
          - entity: input_datetime.hall_ac_heating_period_3_start
          - entity: input_datetime.hall_ac_heating_period_3_end
          - entity: input_number.hall_ac_heating_period_3_temperature
          - entity: input_boolean.hall_ac_heating_period_4
          - entity: input_datetime.hall_ac_heating_period_4_start
          - entity: input_datetime.hall_ac_heating_period_4_end
          - entity: input_number.hall_ac_heating_period_4_temperature
        title: Semaine
        show_header_toggle: false
        theme: teal
        state_color: true
columns: 1

Et voilà !

 

 
 

 

 

Home Assistant, restauration d'état après une coupure secteur

Comme d'aucuns ont pu le remarquer, les ampoules connectées s'allument après une coupure secteur (Mi, Hue, Ikea, Tuya, etc...)., c'est logique car si on les actionne depuis un inter d'origine il faut bien que l'ampoule répondre en dehors de tout contexte domotique, bien que certaines, Shelly par exemple, permettent comme les prises commandées et modules de choisir cet état.

Pour palier à ce problème et ne pas retrouver toutes mes ampoules allumées quand je rentre à cause d'une coupure ayant eu lieu dans la journée, j'ai fait un groupe d'ampoules (dans light.yaml) à éteindre après que l'onduleur ait signalé la reprise électrique (ça sous entend bien sur d'avoir configuré un addon sur l'onduleur afin d'avoir le binay_sensor: idoine).

- platform: group
  name: Groupe de Coupure
  entities:
    - light.tuya_cour_1
    - light.tuya_cour_2
    - light.tuya_chevet
    - light.tuya_strip_antoine
    - light.hall_1
    - light.hall_2
    - light.cuisine_led
    - light.sejour_led
    - light.cuisine_lampe_de_table
    - light.bureau_led_bt
    - light.ikea_r14_entree
    - light.ikea_e27_tv

Et une petite automation :

- alias: P - Light OFF après reprise électrique
  description: ''
  trigger:
  - platform: state
    entity_id: binary_sensor.ups
    from: 'off'
    to: 'on'
  condition: []
  action:
  - service: light.turn_off
    data: {}
    entity_id: light.groupe_de_coupure

Ca fonctionne mais ce n'est pas satisfaisant car ça éteint toutes les ampoules, et pas seulement celles qui étaient éteintes avant la coupure. J'ai commencé par me dire qu'idéalement il faudrait connaitre leur état avant la coupure, le stocker dans des input quelque chose et faire une automation de malade à exécuter lors du rétablissement électrique. Ca m'a donné mal au crane et j'ai procrastiné la chose...

Et puis, en discutant dans notre groupe préféré et confidentiel, la lumière jaillit ! Il y a une fonctionnalité souvent peu utilisée dans Home Assistant, ce sont les scènes. En général on crée une scène, genre j'allume des ampoules à telle ou telle intensité ou couleur, je baisse les stores, et je lance un film sur Netflix... Mais, si on lit la doc jusqu'au bout on découvrira que l'on peut également créer des scènes à la volée, un peu comme un snapshoot de l'état de certaines entités.

Et là ça devient très simple. Si une ampoule n'est plus alimentée, elle ne signale pas son état à Home Assistant. Il suffit alors d'enregistrer son état dans une scène dès lors que le binary de l'onduleur passe à OFF :

- alias: P - Sauve l'état des lampes lors d'une coupure
  trigger:
  - platform: state
    entity_id: binary_sensor.ups
    from: 'on'
    to: 'off'
  condition: []
  action:
  - service: scene.create
    data:
      scene_id: light_state
      snapshot_entities:
      - light.tuya_cour_1
      - light.tuya_cour_2
      - light.tuya_chevet
      - light.tuya_strip_antoine
      - light.hall_1
      - light.hall_2
      - light.cuisine_led
      - light.sejour_led
      - light.cuisine_lampe_de_table
      - light.bureau_led_bt
      - light.ikea_r14_entree
      - light.ikea_e27_tv

Et de restaurer la scène quand celui ci passe à ON :

- alias: P - Restaure l'état des lampes lors d'une coupure
  trigger:
  - platform: state
    entity_id: binary_sensor.ups
    from: 'off'
    to: 'on'
  condition: []
  action:
  - delay : '00:00:60' # On ajoute une temporisation afin que les ampoules se reconnectent
  - service: scene.turn_on
    data:
      entity_id: scene.light_state

Et on retrouve l'état de l'éclairage avant qu'Enedis ait sévit. Car si les coupures électriques sont peu fréquentes en ville, à la campagne le moindre aléa climatique en provoque, ce qui en dit long sur l'état du réseau. 

J'ai pris ici l'exemple de l'éclairage lors d'une coupure secteur. Mais il est tout à fait possible de restaurer ainsi l'état d'autres entités, mais également de s'en servir dans d'autres contextes, par exemple sauvegarder un état d'éclairage avant de fermer les volets ou de regarder un film, et de le restaurer ensuite. Avec Emby (et surement d'autres triggers) on peu par exemple jouer deux états selon que l'on appuie sur PLAY ou PAUSE... La suite n'étant qu'une question d'imagination ;-)

 

 

Home Assistant & Planification, la suite !

Ce qui déroute souvent quand on débute avec Home Assistant c'est l'absence de planificateur intégré, alors même que la chose parrait évidente. Il y a tout de même plusieurs façons de planifier des évènements et on a déjà examiné ici plusieurs solutions :

  • En codant des des automation basées sur des input_time, etc... On peut obtenir quelque chose de très personnalisé. Mais il faut pas mal d'huile de coude.
  • Avec des agendas externes comme Google Agenda ou Microsoft 365, ou encore des agendas plus geeks... (ics, etc).

Il y a une autre solution qui bien que dépourvue d'interface est vraiment très puissante, mais un peu compliquée à appréhender. Je veux parler de Shedy. Ca impose d'installer AppDaemon et ensuite ça se passe en YAML, à ceci près que sous AppDaemon la prise en compte des modifications apportées au code YAML est dynamique, et ça c'est très sympa.  AppDaemon c'est un addon qui s'installe dans la section addon de HA et je m'en sert également pour ControlerX. Dans toutes ces solutions, seul Shedy sait faire de la replanification dynamique, c-a-d que toutes les x minutes il reconsidère l'état de tous les paramètres, là ou les autres se contentent de faire ON au début et OFF à la fin (ou augmenter la consigne et la baisser).

Depuis peu il y a aussi les BluePrint, ça va changer beaucoup de choses sous HA et surement permettre de proposer des planifications simples et prêtes à l'emploi.

On a peut être aussi des possibilités avec NodeRed, mais pour moi c'est non, vous le savez, je n'aime pas. Bon, blague à part, c'est bien et même intéressant, surtout pour ceux qui ne réussissent pas à entrer dans la logique yaml, ce qui se comprends très bien. Mais dans l'absolu ça n'a pas besoin de HA, à part pour l'interface, ah oui NR n'a pas d'interface utilisateur, juste une interface dev. Bon, après chacun son truc.

Et puis il y a le Scheduler dont je veux vous parler aujourd'hui et pour lequel je vous conseille de suivre cette conversation.

L'idée de son auteur est de créer un scheduler entièrement graphique, donc à l'opposé de Schedy. A vrai dire j'aurais préféré qu'il fasse une interface pour Schedy. Mais les développeurs sont ce qu'ils sont et lui est parti sur deux modules, un composant moteur et une carte d'interface. Du coup si l'interface est très réussie il reste encore des choses à voir coté motorisation pour arriver au niveau de Schedy, qui lui gère notamment la notion de re planification dynamique. Attention, ce n'est pas un reproche, Niels a fait un travail remarquable en très peu de temps, et comme c'est un perfectionniste, je ne doute pas qu'au fil des semaines cet outil, déjà totalement utilisable, gagnera en fonctionnalités.

Je vous passe les détails de l'installations décrits ici, et , en gros on installe le composant depuis HACS, on redémarre et on installe la carte. Ensuite on va créer une carte à laquelle on attribuera des objets à planifier avec des conditions. Par exemple, je veux que le thermostat de la cuisine passe à 21° tous les matins à 07:15 et qu'il repasse à 19.5° à 09:00 (avec plusieurs plages possibles dans la journée), mais à condition que nous soyons en semaine, que le commutateur qui autorise le chauffage soit à ON et que je ne soit pas en voyage, etc...

On va donc créer une carte avec les objets dont on a besoin que l'on peut choisir par type ou mieux individuellement. Par exemple un thermostat, et les input_bolean: Chauffage ON/OFF et Mode Absent ON/OFF : 

Je prends l'exemple des thermostats qui me préoccupait, mais on peut bien sur planifier tout ce qui est actionnable, directement, via des scripts ou des scènes.

Il est bien sur possible de faire ça par le code, ce qui permet en plus d'ajouter des options de présentation de la carte. Personnellement j'ai choisit d'utiliser une carte de type "Vertical Stack" "Panel Mode", ce qui sera bien plus agréable à utiliser pour planifier une journée. Ce mode n'est pas très adapté au mobile, mais c'est le genre de choses que je fais depuis mon PC.

type: vertical-stack
cards:
  - type: 'custom:scheduler-card'
    discover_existing: false
    display_options:
      primary_info:
        - '<b>{entity} / {name}</b>'
      secondary_info:
        - >-
          <b>Next</b> : {relative-time} ({days} {time}) | <b>Action</b> :
          {action} ({additional-tasks})
      icon: 'mdi:radiator'
    include:
      - climate.daikin
      - input_boolean.thermostats_ac_on_off
      - input_boolean.thermostats_away
      - input_boolean.thermostats_on_off
      - input_select.chauffage
    title: AC Daikin
  - type: 'custom:scheduler-card'
    discover_existing: false
    display_options:
      primary_info:
        - '<b>{entity} / {name}</b>'
        - '<b>Next</b> : {relative-time} | <b>Action</b> : {action}'
        - additional-tasks
      secondary_info:
        - '{days} {time}'
      icon: 'mdi:radiator'
    include:
      - climate.thermostat_lionel
      - input_boolean.thermostats_ac_on_off
      - input_boolean.thermostats_away
      - input_boolean.thermostats_on_off
      - input_select.chauffage
    title: Thermostat Chambre Lionel

J'utilise ici une carte de la pile pour chaque thermostat et dans chaque carte je vais pouvoir ajoute plusieurs planifications. Par exemple une pour la semaine et une pour les week-end et jours fériés. A noter que workday: est supporté, ce qui simplifie grandement la gestion des jours férié. A droite de chaque planification on a un interrupteur qui permet d'activer ou désactiver la planification, fonction également possible par une automation. On peut également la laisser activée et la soumettre à une condition pour peu qu'on ait associé l'objet idoine, un input_bolean: par exemple...

Quand on ajoute une entrée on choisit l'objet sur lequel on peut agir, ici un thermostat, on précise l'entité et le type d'action unique à exécuter (allumer, éteindre plus adapté à d'autres équipements, ou mieux de faire un schéma, ce qui sera pleinement adapté à un thermostat :

Par exemple ici j'ai choisit de chauffer le séjour, le week-end, de 08:00 à 22:30 à 21.5°. Sauf que si on laisse la chose en l'état à 22:30 le thermostat continuera à chauffer à 21.5°. La logique actuelle veut que l'on crée une plage suivante avec une autre température, mais également une précédente, contrairement à Schedy qui lui va considérer une température de base (Eco) et uniquement augmenter les plages définies pour revenir ensuite à sa température de base.

Le développeur me répond qu'il ne veut pas faire un planificateur trop spécifique au chauffage. Mais je pense l'avoir convaincu de changer sa logique, et pour chaque plage définie ainsi prévoir une action de début et une action de fin, ce qui me paraitrait un bon début.

Il n'y a pas ici d'options de replanification dynamique. Si Home Assistant redémarre, le thermostat conservera son état (à condition de ne pas utiliser l'option initial_hvac_mode:), par contre face à d'éventuelles coupures secteur, il faut utiliser des actionneurs capables de retrouver leur état avant coupure et de les configurer ainsi. C'est les cas des Shelly ou des cartes IPX800, mais certains actionneurs resteront muets après coupure et ne sont donc pas conseillés pour cette utilisation.

Avec le bouton Options en bas à droite on va pouvoir ajouter des conditions supplémentaires basées sur l'état des entités que l'on aura choisies, ici un input_bolean: qui conditionne le fonctionnement du chauffage. Donc si cette condition n'est pas remplie la planification ne s'exécutera pas, la validation se faisant en début de planification. 

J'ai par exemple un input_bolean: qui conditionne le chauffage des chambres de ma fille et mon fils qui vivent à l'autre bout de la France. Ce commutateur s'actionne soit manuellement, soit en en fonction de leur date d'arrivée que j'aurais saisie (et peut être un jour automatisée en fonction des billets TGV reçus... ou en fonction de leur localisation...).

Voilà pout un petit tour rapide. Alors vous allez me demander pourquoi utiliser une solution plutôt qu'une autre ? Il y a plusieurs questions à se poser, la plus évidente étant de savoir si vous êtes le seul à agir ou si vous voulez un système plus WAF accessible à tous les membre de la maison.

Par exemple j'ai monté un Home Assistant chez mon frère, ce n'est pas un geek et je n'avais pas l'intention d'intervenir chaque fois qu'il souhaite ajuter ses plages de températures. Au départ j'avais basé ses planifications sur Google Agenda, une solution qui fonctionne très bien, mais pas idéale coté expérience utilisateur, en effet cela nécessitait deux interfaces, celle de HA et celle de Google Agenda. De plus les jours fériés n'étaient pas pris en compte (il aurait fallut faire des automations plus complexes). J'ai donc remplacé tout ça par ce Scheduler et ça lui va très bien.

En ce qui me concerne j'ai le nez dans le code et j'avais dès le début fait pas mal d'automations pour gérer les différentes situations (présent, absent, j'ai du monde à diner, à coucher, des amis passent le week-end ici, etc...) et pour l'instant ça reste ainsi. Mais mon installation est également un labo et j'ai installé Schedy pour le tester en live, notamment au niveau des conditions et situations particulières. J'aimerais aussi pouvoir le personnaliser avec un minium de GUI. Je ne suis pas un bon exemple à suivre...

En conclusion je dirais que ce Scheduler est vraiment ce que tout le monde attendait et qu'il couvrira la majorité des besoins. Après il y avait un vague projet de scheduler intégré au core, mais pour l'heure ça reste une arlésienne.

 

Home Assistant & Tuya zéro cloud

On le sait tous, la domotique nous fait acheter beaucoup de bricoles qui souvent deviennent obsolètes, bref il y a toujours mieux. Par exemple les prises et autres objets Tuya ou Sonoff qui nécessitent le cloud, alors qu'un prise Shelly dispose de base de MQTT, peut être flashée avec ce que l'on souhaite et dans tous les cas fonctionne en local. Bien sur on ne va pas parler des prises en RF433 genre DIO mise au rebus faute de retour d'état, pas plus que des solutions Zigbee qui se traitent autrement. Tuya c'est du matériel OEM disponibles en marque blanche que des entreprises peuvent distribuer sous leur étiquette. Je trouve d'ailleurs scandaleux qu'une marques comme Konyks soit labelisée French Tech alors qu'il se contente de distribuer de produits chinois sous leurs marque sans aucune R&D... Bref !

EDIT 10/08/2021 : Pour ceux que ça intéresse il existe maintenant un développement officiel Tuya2 réalisé par Tuya en accord avec les équipes Home Assistant. A terme ce projet devrait remplacer l'intégration Tuya native et supporter le mode local, comme le fait maintenant Sonoff.

EDIT 10/10/2024 : En parcourant le forum je vois que tout le monde galère un peu sur les équipements Tuya en WI-FI. Pour ma part ça fait des année que j'ai viré cette camelote chinoise. Si je veux du WI-FI c'est du Shelly qui pour quelques euros de plus est ouvert, reconnu de base pat HA et surtout au normes en vigueur. Par contre en Zigbee il y a plein de choses plus ou moins intéressantes sous le label Tuya.

Nous avons donc en Wi-Fi...

  • L'écosystème Sonoff : en dehors de quelques modèles DIY, il faudra en général ouvrir et souder pour flasher. Heureusement il existe une intégration qui permet leur utilisation en local / cloud. En gros l'intégration mets à jour à intervalles réguliers ce qu'il trouve sur le cloud Sonoff et les actions sont ensuite locales.
  • L'écosystème Tuya : de base 100% cloud et géré nativement par HA, mais on va voir plus loin comment contourner ça.
  • L'écosystème Shelly : Cloud ou 100% nativement local et MQTT, flashable si vous aimez ça. C'est clairement ce que je vous conseille pour de nouveaux achats.

Tuya sans cloud

Heureusement il y a des petits malins qui adorent faire du reverse engineering, ce qui va nous permettre d'utiliser nos produits Tuya localement avec bien souvent plus de fonctionnalités, comme par exemple la remontée des information de consommation qui ne se fait pas de base sous HA.

Dans tous les cas, comme pour les produits Xiaomi/Aqara, il faudra trouver la clé... Au fil du temps les méthodes changent, mais aujourd'hui ça n'a jamais été aussi facile. Je vous conseille donc de récupérer vos clés, même si vous ne comptez pas les utiliser tout de suite.

On part du principe que vous avez un compte Tuya/ SmartLife (ou une application OEM comme celle de Konyks, c'est la même chose) et que vos équipements y sont enregistrés. En substance on va passer par la plateforme IoT de Tuya sur lequel vous allez vous créer un compte développeur et suivre les instructions de cet article dont je me suis inspiré. (Je ne suis pas sur que tout soit utile, vous me direz...).

  1. Créez un nouveau compte sur iot.tuya.com et assurez-vous que vous êtes connecté. Allez dans Cloud -> Projet dans le tiroir de navigation de gauche et cliquez sur "Create". Après avoir créé un nouveau projet, cliquez dessus. L'ID d'accès et la clé d'accès sont équivalents à la clé d'API et aux valeurs secrètes d'API requises.
  2. Allez dans App -> App SDK -> Development dans le tiroir de navigation. Cliquez sur "Create" et entrez ce que vous voulez pour les noms de package et Channel ID (pour le nom du package Android, vous devez entrer une chaîne commençant par com.). Prenez note de l' ID de chaîne que vous avez entré. Cela équivaut à la valeur schema requise plus loin. Ignorez les clés d'application et les valeurs secrètes d'application que vous voyez dans cette section car elles ne sont pas utilisées.
  3. Allez dans Cloud -> Projet et cliquez sur le projet que vous avez créé précédemment. Cliquez ensuite sur "Link Device". Cliquez sur l'onglet «Link devices by Apps», puis sur «Add Apps». Vérifiez l'application que vous venez de créer et cliquez sur "Ok".
  4. Toujours dans Cloud -> Projet et cliquez sur le projet que vous avez créé précédemment. Cliquez ensuite sur "Link Device". Cliquez sur l'onglet «Link devices by App Account», puis Add App Account et ajouter votre compte Tuya/SmartLife et vous devriez retrouver vos petits....
  5. Sur la même page, cliquez sur "Groupe d'API" sur le côté gauche. Modifiez le statut en Ouvert pour les trois groupes d'API suivants en cliquant sur "Appliquer" pour chaque ligne, en saisissant une raison quelconque et en cliquant sur "OK": "Authorization Management", "Device Management", "Device Control", "User Management", "Network Management", "Data Service", "Home Management", "Device User Mangement" and "Device Statistics".. Cela peut prendre 10 à 15 minutes pour que ces modifications prennent effet.
  6. Ensuite sur Device List / App Account / Europe vous listez vos devices et vous récupérez les devices ID
  7. Enfin on va dans API Explorer / Get Device details, on choisit Europe et on rentre le device ID et par magie la local_key apparaitra.
{
  "result": {
    "active_time": 1609598200,
    "biz_type": 0,
    "category": "cz",
    "create_time": 1609598200,
    "icon": "smart/icon/154028815822y4yx2k5jz_0.jpg",
    "id": "871720fsdfsdfsfd8e997fec",
    "ip": "70.22.16.3",
    "local_key": "8dfsdfsdfsgggsg10ecb6",
    "name": "Konyks Priska Plus 6",
    "online": true,
    "owner_id": "19956557",
    "product_id": "j6cVsdgfsdfgsdfsdfeYpli",
    "product_name": "Konyks Priska Plus",
    "status": [
      {
        "code": "switch_1",
        "value": false
      },
      {
        "code": "countdown_1",
        "value": 0
      },
      {
        "code": "cur_current",
        "value": 0
      },
      {
        "code": "cur_power",
        "value": 0
      },
      {
        "code": "cur_voltage",
        "value": 2339
      }
    ],
    "sub": false,
    "time_zone": "+01:00",
    "uid": "eu15345fgsdfsdfdsf9crK3G",
    "update_time": 1609565564,
    "uuid": "8717244465sd6f46sdf7fec"
  },
  "success": true,
  "t": 1609606041296
}

Ceux qui sont familiers de Node JS pourront lancer le script comme décrit ici et obtenir toute les clés en une seule manipulation.

Ensuite on a deux solutions :

  • La première, Trade Face Tuya Gateway est indépendante de la solution domotique choisie car full MQTT, elle peut s'installer dans un Docker et nos amis encore sous Jeedom pourront ainsi en profiter.
  • La seconde, Local Tuya, est une simple intégration pour Home Assistant qui permettra de reconnaitre nos équipements en quelques clics et s'installe depuis HACS. Le discovery fera le reste et il faudra juste tâtonner un peu quand on configure un équipement Tuya pour faire correspondre les bonnes valeurs, mais c'est expliqué ici.

Vous aurez compris, ce qui compte encore une fois c'est d'avoir les clés. Ensuite il existe surement d'autre solutions pour exploiter. Attention : Pour toutes ces manips pensez à fermer l'application mobile (Tuya/SmartLife) car un équipement Tuya ne supporte qu'une seule connexion simultanée.

Merci Yvon pour cette exploration nocturne et conjointe d'un jour de l'an sous couvre-feu !

EDIT 04/01/2021 : Il y a un soucis dans le v3.2 ou on perd certains équipement au reboot. Revenir à la 3.1 résout le problème en attendant mieux.

EDIT 21/02/2021 : Contrairement aux Shelly les appareils Tuya ne fournissent que la consommation instantanée. Donc pas exploitable directement avec un utility_meter: par exemple. Il va donc falloir ruser un peu :

  1. Sortir la consommation instantanée disponible en attribut pour en faire un sensor :
    sensor:
      - platform: template
        sensors:
          tuya_plug_1_current_consumption:
            value_template: >-
              {{ states.switch.tuya_plug_1.attributes.current_consumption }}
            unit_of_measurement: 'W'
  2. Utiliser l'intégration Riemann pour convertir la la consommation instantanée (en Watts) en consommation cumulée (en kW/h)
    sensor:
      - platform: integration
        source: sensor.tuya_plug_1_current_consumption
        name: 'Tuya Plug 1 : Cumul'
        unit_prefix: k
        round: 2
        method: left
  3. Si l'on souhaite conserver l'historique (ici année et année précédente) on va utiliser un utility_meter:
    utility_meter:
      tuya_plug_1_energy_yearly:
        source: sensor.tuya_plug_1_cumul
        cycle: yearly


Enjoy ;-)

 

 

Home Assistant & Notifications d'état

Avant, je planifiait mon chauffage avec des automations qui s'appuyaient sur des input_date, input_time pour actionner et input_number pour sélectionner la température de consigne souhaitée et je notifiait dans un journal sur Slack, ce qui me permet un debug facile. J'en avait largement parlé ici, mais maintenant il existe un vrai scheduler et je vais changer ma façon de faire. Sauf que ce scheduler, dont je vous parlerais bientôt, ne dispose pas d'une option de notification. Ca viendra peut être, et ce travail sera peut être à jeter, bien que le principe puisse être adapté à d'autre notifications.

Le scheduler pilotant dans mon cas les thermostats, je vais donc me baser sur les changement d'était du thermostat pour notifier l'état à Slack (voire faire autre chose...). Pour cela je vais stocker les états qui ont changés dans des input_number et des input_text et m'en servir pour notifier avec les bonnes variables.

La liste des courses

J'ai essayé de simplifier en minimisant les besoins, mais il nous faut des input_number: et des input_text:

input_number
  trigger_source_notify_temp_current:
    name: Température Ambiante
    mode: box
    min: 0
    max: 30
    unit_of_measurement: "°C"

  trigger_source_notify_temp_target:
    name: Température de consigne
    mode: box
    min: 0
    max: 30
    unit_of_measurement: "°C"

input_text:
  trigger_source_notify_name:
    name: Trigger Source Name

  trigger_source_notify_hvac_mode:
    name: Trigger Source HVAC Mode

  trigger_source_notify_hvac_action:
    name: Trigger Source HVAC Action
  
  trigger_source_notify_preset_mode:
    name: Trigger Source Preset Mode

  trigger_source_notify_state:
    name: Trigger Source State

Ces "inputs" vont servir à stocker temporairement les valeurs que je vais afficher dans mes notifications.

Une seule automation

Ensuite on va avoir besoin d'une automation qui va :

  1. Se déclencher (trigger) sur les changements d'état pour lesquels on souhaite envoyer une notification. Ici les attributs de deux thermostats.
  2. Ecrire (action) les valeurs liées à la source de déclenchement dans les input_number: et input_text:
  3. Notifier (action) en se servant des valeurs écrite précédemment.
- alias: Notifications des Thermostats
  trigger:
  - platform: template
    value_template: "{{ state_attr('climate.daikin','temperature')  }}"
  - platform: template
    value_template: "{{ state_attr('climate.daikin','preset_mode')  }}"
  - platform: template
    value_template: "{{ state_attr('climate.daikin','hvac_modes')  }}"

  - platform: template
    value_template: "{{ state_attr('climate.thermostat_antoine','temperature')  }}"
  - platform: template
    value_template: "{{ state_attr('climate.thermostat_antoine','preset_mode')  }}"
  - platform: template
    value_template: "{{ state_attr('climate.thermostat_antoine','hvac_modes')  }}"

  action:
  - data_template:
      entity_id: input_number.trigger_source_notify_temp_target
      value: '{{ trigger.to_state.attributes.temperature }}'
    service: input_number.set_value
  - data_template:
      entity_id: input_number.trigger_source_notify_temp_current
      value: '{{ trigger.to_state.attributes.current_temperature }}'
    service: input_number.set_value
  - data_template:
      entity_id: input_text.trigger_source_notify_name
      value: '{{ trigger.to_state.attributes.friendly_name }}'
    service: input_text.set_value
  - data_template:
      entity_id: input_text.trigger_source_notify_hvac_action
      value: '{{ trigger.to_state.attributes.hvac_action }}'
    service: input_text.set_value
  - data_template:
      entity_id: input_text.trigger_source_notify_preset_mode
      value: '{{ trigger.to_state.attributes.preset_mode }}'
    service: input_text.set_value
  - data_template:
      entity_id: input_text.trigger_source_notify_state
      value: '{{ trigger.to_state.state }}'
    service: input_text.set_value

  - service: notify.slack_hass_canaletto
    data:
      message: "{{ states.sensor.date_time.state}} > {{ states.input_text.trigger_source_notify_name.state }} : Consigne à {{ states.input_number.trigger_source_notify_temp_target.state }}° |  
                Température ambiante : {{ states('input_number.trigger_source_notify_temp_current') }}° | 
                Etat : {{ states.input_text.trigger_source_notify_hvac_action.state }} / {{ states.input_text.trigger_source_notify_preset_mode.state }} / {{ states.input_text.trigger_source_notify_state.state }}

Et on obtient une notification dans le journal Slack

2020-12-06, 20:24 > Thermostat : Antoine : Consigne à 13.0° | Température ambiante : 17.1° | Etat : idle / away / heat

Bonus

On peut s'amuser à traduire les messages d'état et ainsi les insérer en clair et en français dans la notification... En bricolant quelque chose du genre :

  {% if is_state('input_text.trigger_source_notify_hvac_action', 'heating') %}
    Etat : Chauffe
  {%-elif is_state('input_text.trigger_source_notify_hvac_action', 'cooling') %}
    Climatise
  {%-elif is_state('input_text.trigger_source_notify_hvac_action', 'dry') %}
    Désumidifie
  {%-elif is_state('input_text.trigger_source_notify_hvac_action', 'fan_only') %}
    Ventile
  {%-elif is_state('input_text.trigger_source_notify_hvac_action', 'heat_cold') %}
    Auto
  {% else %}
    Etat : Inactif
  {% endif %}

  {% if is_state('input_text.trigger_source_notify_preset_mode', 'away') %}
    Préréglage : Absent
  {%-elif is_state('input_text.trigger_source_notify_preset_mode', 'eco') %}
    Préréglage : Eco
  {%-elif is_state('input_text.trigger_source_notify_preset_mode', 'boost') %}
    Préréglage : Boost
  {% else %}
    Préréglage : Normal
  {% endif %}

  {% if is_state('input_text.trigger_source_notify_state', 'heat') %}
    Mode : Chauffage
  {%-elif is_state('input_text.trigger_source_notify_state', 'cold') %}
    Mode : Climatisation
  {%-elif is_state('input_text.trigger_source_notify_state', 'dry') %}
    Mode : Désumidifiation
  {%-elif is_state('input_text.trigger_source_notify_state', 'fan_only') %}
    Mode : Ventilation
  {%-elif is_state('input_text.trigger_source_notify_state', 'heat_cold') %}
    Mode : Auto
  {% else %}
    Mode : Arrêt
  {% endif %}

Voilà, bien entendu tout ça est adaptable à d'autres besoins....

 

Home Assistant, EJP & Tempo

En France EDF nous propose différents contrats associés à différents types de facturation. La gestion du plus classique avec les heures pleines et les heures creuses est facile, il suffit de faire tourner la nuit les appareils les plus énergivores et on connait d'avance les bonnes heures Par contre pour EJP et Tempo, la couleur est annoncée la veille et il peut être intéressant d'adapter le fonctionnement de certains appareils quand le cout de l'électricité est surtaxé, par exemple en baissant le chauffage électrique de 1 ou deux degrés ou en verrouillant l'usage de certains appareils...

Mais encore faut t'il sous Home Assistant disposer de cet état que l'on reçoit généralement par SMS la veille. Ces informations sont disponibles sur le site Web du fournisseur au format JSON et voici comment faire pour en disposer sous Home Assistant

Tempo

On crée quelques sensor:

  - platform: rest
    name: 'Tempo Demain'
    resource_template: https://particulier.edf.fr/bin/edf_rc/servlets/ejptemponew?Date_a_remonter={{now().strftime("%Y-%m-%d")}}&TypeAlerte=TEMPO
    value_template: '{{ value_json.JourJ1.Tempo }}'
    headers:
      Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
      Content-Type: application/json
      User-Agent: Wget/1.20.3 (linux-gnu)
  - platform: rest
    name: "Tempo Aujourd'hui"
    resource_template: https://particulier.edf.fr/bin/edf_rc/servlets/ejptemponew?Date_a_remonter={{now().strftime("%Y-%m-%d")}}&TypeAlerte=TEMPO
    value_template: "{{ value_json['JourJ'].Tempo }}"
    headers:
      Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
      Content-Type: application/json
      User-Agent: Wget/1.20.3 (linux-gnu)
  - platform: rest
    name: 'Jours Rouge restants'
    resource: https://particulier.edf.fr/bin/edf_rc/servlets/ejptempodaysnew?TypeAlerte=TEMPO
    value_template: '{{ value_json.PARAM_NB_J_ROUGE }}'
    headers:
      Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
      Content-Type: application/json
      User-Agent: Wget/1.20.3 (linux-gnu)
  - platform: rest
    name: 'Jours Blanc restants'
    resource: https://particulier.edf.fr/bin/edf_rc/servlets/ejptempodaysnew?TypeAlerte=TEMPO
    value_template: '{{ value_json.PARAM_NB_J_BLANC }}'
    headers:
      Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
      Content-Type: application/json
      User-Agent: Wget/1.20.3 (linux-gnu)
  - platform: rest
    name: 'Jours Bleu restants'
    resource: https://particulier.edf.fr/bin/edf_rc/servlets/ejptempodaysnew?TypeAlerte=TEMPO
    value_template: '{{ value_json.PARAM_NB_J_BLEU }}'
    headers:
      Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
      Content-Type: application/json
      User-Agent: Wget/1.20.3 (linux-gnu)

Et après un redémarrage on doit obtenir ça :

EJP

Ici aussi on crée quelques sensor:

  - platform: rest
    name: "EJP Aujourd'hui"
    resource_template: https://particulier.edf.fr/bin/edf_rc/servlets/ejptemponew?Date_a_remonter={{now().strftime("%Y-%m-%d")}}&TypeAlerte=EJP
    value_template: '{{ value_json.JourJ.EjpSud }}'
    headers:
      Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
      Content-Type: application/json
      User-Agent: Wget/1.20.3 (linux-gnu)
      
  - platform: rest
    name: 'EJP Demain'
    resource_template: https://particulier.edf.fr/bin/edf_rc/servlets/ejptemponew?Date_a_remonter={{now().strftime("%Y-%m-%d")}}&TypeAlerte=EJP
    value_template: "{{ value_json['JourJ1'].EjpSud }}"
    headers:
      Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
      Content-Type: application/json
      User-Agent: Wget/1.20.3 (linux-gnu)
      
  - platform: rest
    name: 'Jours restants'
    resource: https://particulier.edf.fr/services/rest/referentiel/historicEJPStore?searchType=ejp
    value_template: '{{ 22 - value_json.SUD.TotalCurrentPeriod }}'
    headers:
      Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
      Content-Type: application/json
      User-Agent: Wget/1.20.3 (linux-gnu)

Et on obtient :

Exploitation

Pour exploiter ces information dans Home Assistant il sera souvent plus facile d'utiliser un binary_sensor:, voici donc l'exemple pour le tarif EJP :

- platform: template
  sensors:
    ejp_on:
      friendly_name: "Edf : EJP"
      value_template: "{{ is_state('sensor.ejp_aujourd_hui', 'EST_EJP') }}"
      device_class: power   

- platform: template
  sensors:
    ejp_on_demain:
      friendly_name: "EdF : EJP Demain"
      value_template: "{{ is_state('sensor.ejp_demain', 'EST_EJP') }}"
      device_class: power

Ce qui donne :

Chacun pourra fignoler à sa guise, en modifiant la couleur des icônes en fonction de l'état ou en envoyant les notifications idoines... Merci à Patrice pour son aide !

Sources

 

 

Home Assistant, ESP & Téléinfo

On a vu précédemment qu'il était possible de récupérer la consommation électrique via le site Enedis, mais que c'était compliqué et lié au compteur Linky. On va explorer ici une méthode pour récupérer ces informations, plus complètes, directement sur le compteur, avec pour avantage que ça fonctionne également sur les anciens compteurs.

Je n'ai pas écrit cet article et encore moins réalisé ce montage (pour l'instant). Mais la nuit, on discute au sein d'une groupe Telegram des plus confidentiels (sur invitation et parrainage s'il vous plait) et c'est Mathieu (@Bibinsa) qui a réalisé ce montage et le code qui va avec. Face à la demande je lui ai donc demandé de me faire un récap et il m'a envoyé un fichier texte dans la plus pure tradition des codeurs. Je vais donc faire le secrétaire.

L'objectif ici est de récupérer les informations du compteur électrique.

  • compteurs à informations numériques (testé sur les compteurs pré-Linky mais devrait fonctionner aussi avec Linky)
    information Téléinfo TIC diffusées sur les afficheurs
  • Dans les installations "modernes", le compteur se situe dans le bâtiment (maison, ...) et un report Teleinfo est positionné sur le domaine public (rue, ...).

Cela permet aux agents (ENEDIS/Régie locale/Sous-traitant/...) de récupérer l'information sans demander l'accès au compteur dans la maison. Linky et son infrastructure de téléreport déployée en mode "cloud" devrait à terme changer ce mode de fonctionnement. Pour autant, les compteurs Linky sont toujours munis de la sortie TIC.

Pour les spécifications techniques, Google est votre ami :

Ces compteurs sont donc munis d'un bornier avec les indications I1 et I2. Ce bornier n'est pas protégé par un scellé et est donc accessible sans sortir du cadre contractuel. Plusieurs solutions de récupération de l'information Teleinfo sont disponibles, Google est à nouveau votre ami. Nous allons ici voir une solution :

  • économe
  • pas si compliquée à mettre en œuvre pour qui connait un peu les différents éléments mis en place
  • ouverte (open source)
  • utilisant des protocoles de communication orientés domotiques

Le matériel

L'idée ici est de ne pas utiliser un système complexe (ordinateur Linux/Windows/...) pour récupérer simplement une information texte. Dans le monde de l'IoT, des chipsets très pratiques inondent nos équipements WiFi : les ESP8266 et dérivés. N'importe quel module basé sur un ESP82xx convient, pour peu que celui-ci dispose d'un GPIO RX accessible facilement. Donc des Sonoff, des Wemos, ...

Pour ce besoin spécifique, un Wemos D1 mini est le candidat idéal :

  • petit (pourra s'intégrer dans le compartiment du bas sur les compteur classiques)
  • bien pratique car muni d'une port micro-USB pour alimentation et pour le "flash"

Ce module servira d'intelligence, c'est lui qui fera tourner le petit système d'exploitation qui récupèrera les infos et les transmettra. A ce module, il faut ajouter un module TiC de type Serial qui se connecte aux bornes I1/I2 et permet la conversion du signal au format série. De la même manière, de nombreux montages sont disponibles sur Internet. Qu'on peut se faire soi-même ou commander.

Un français (forcément... on est un peu les seuls à avoir ce système... Minitel, TousAntiCovid toussa toussa) "Charles Halard" propose des modules tout prêts appelés PitInfo. Plusieurs shield disponibles dont le PitInfo light qui convient très bien. Ce module est compatible physiquement avec les Raspberry Pi (Zero, Zero W) mais ces ordinateurs sont bien trop puissant pour notre besoin. je vous conseille de commander ce module avec les connecteurs pré-soudés, ce n'est pas l'écart de prix qui va changer grand chose...

Nous allons donc nous servir de la capacité de l'ESP8266 à se connecter à n'importe quel shield. Et côté câblage ça donne :

  1. PitInfo TiC vers les bornes I2/I2
  2. Wemos D1 3,3V vers PitInfo Vcc
  3. Wemos GND vers PitInfo GND
  4. PitInfo Tx vers Wemos D1 Rx pour la communication et c'est tout

On n'oublie pas d'alimenter le Wemos en USB bien sûr. Le tout fonctionne donc en 3,3V et est alimenté par un simple câble micro-USB (5V). Il est également possible de s'alimenter sur la sortie idoine low voltage directement sur le compteur, mais dans ce cas cela nécessitera un convertisseur. A noter que si le compteur est situé en dehors du domicile, il sera souvent possible d'utiliser l'ancien câble servant au HP/HC pour y faire transiter les information série (les commandes HP/HC pouvant avantageusement être gérées par Home Assistant).

Mais avant de câbler tout ça, on va trouver un Firmware à mettre sur le Wemos D1 mini. On débranche PitInfo du Wemos... on va avoir besoin de libérer le port série.

Le firmware

Je suis un grand fan de Tasmota (ntlr : tout mon monde le sait), l'OS open source initialement inventé par Theo Arends pour piloter les modules chinois SonOff. Ce firmware alternatif est rapidement devenu compatible avec tous les ESP82xx (et bientôt les ESP32). On ne va pas parler ici de Tasmota, mais de comment récupérer la Teleinfo avec Tasmota.

Depuis la version 8.4, Tasmota embarque de quoi interpréter les infos Teleinfo. Et c'est grace en partie, au développeur de PitInfo. Seul bémol, les binaires Tasmota précompilés n'embarquent pas le code Teleinfo. Il faut donc le compiler soi-même... enfin presque. Une plate-forme de développement online, qui fonctionne avec un compte github, permet de compiler très simplement et sans compétence particulière un firmware Tasmota avec des options particulière. Cette plate-forme c'est GitPod. On se loggue sur github, on donne les droits à Gitpod. La doc Tasmota expique tout en détail et deux options sont possibles :

  1. - firmware stable
  2. - firmware dévellopement

Une dernière option, encore plus simple est disponible avec gitpod : tasmocompiler. C'est une interface web qui permet en quelques clic de compiler son firmware. Nous allons utiliser celle-ci. On charge l'URL dans un navigateur et on va prendre un café (c'est un peu long... ça compile au premier démarrage). Ensuite on check les autorisations de popup aussi, TasmoCompiler va lancer un popup avec l'interface web. Une fois le café ingurgité on est en face de l'interface web de Tasmocompiler en 5 étapes :

  1. on clic sur Download Source Code + Next
  2. La configuration WiFi : on peut passer cette étape si on maitrise l'onboarding Tasmota WiFi sinon c'est ici qu'on peut préconfigurer le SSID+Password (+ conf IP statique si besoin... pas conseillé !!!)
  3. Select Features : on ne va pas se mentir... Teleinfo n'est pas dans les features les plus réclamées par la communauté. Nous n'avons donc pas notre petite case à cocher ici.
    • Laisser les features pré remplies
    • Sélectionner des features supplémentaires si besoin (sensors T° ?)
  4. Custom parameters : c'est la partie qui nous intéresse, on ajoute :
     #ifndef USE_TELEINFO
     #define USE_TELEINFO
     #endif
  5. Select version and compile
    • sécurité : version prod (9.1.0 à la date de cet article)
    • core : 2.7.4
    • language : english - french ?
    • board : on peut spécifier Wemos D1 mini
    • speed : 80 MHz c'est largement suffisant

Compile ! (et second café... ). On récupère le binaire (firmware.bin) et c'est presque gagné. Il nous reste à uploader Tasmota sur le Wemos. Le Wemos D1 mini a de grands avantages :

  • un port micro-USB qui permet de communiquer avec lui
  • le mode flash par défaut, aucune manipulation

On va utiliser ici l'outil qui a grandement simplifié le flash des modules ESP82xx : Tasmotizer, Sous Windows, Mac ou Linux, une fois l'outil installé proprement :

  • Brancher le Wemos à votre ordinateur
  • Lancer tasmotizer
  • Sélectionner le bon port COM
  • Select Image : votre firmware.bin précédemment compilé
  • Erase flash before flashing (c'est toujours plus propre)
  • Tasmotize !!!

Quelques secondes plus tard, votre module est prêt. On peut procéder au câblage comme indiqué au début de l'article. Une fois le module démarré, et selon votre configuation WiFi dans tasmocompiler :

  • il diffuse un hotspot pour l'onboarding (se connecter au SSID diffusé, portail captif qui permet de configurer les paramètres wifi du module)
  • il est accroché au SSID préconfiguré dans tasmocompiler

On peut se connecter à l'interface web de celui-ci pour effectuer sa configuration Tasmota :

La première étape de configuration est la déclaration du template. Un template c'est une sorte de préconfiguration du module. C'est ici qu'on spécifie le type de module utilisé (Teleinfo) et la réception des infos sur le connecteur Rx du Wemos. Le plus simple ici est d'aller sur la Console web et entrer les commandes :

  • Template {"NAME":"Wemos PitInfo","GPIO":[255,255,255,210,255,255,255,255,255,255,255,255,255],"FLAG":15,"BASE":18}
  • module 0

Le module redémarre. Si tout est bien connecté, vous devriez voir les informations Teleinfo sur la page web principale de Tasmota. Par défaut, le module utilise 1200 bps pour le port série. C'est la vitesse du port Teleinfo des compteurs classiques. Les compteurs Linky fonctionnent en 9600 bps, il faut donc modifier la vitesse en mode console SetOption102 1 et là ça devrait fonctionner pour les compteurs Linky, C'est pas mal mais ce n'est pas l'objectif.

Tasmota est surtout connu pour son support MQTT. On peut le configurer et récupérer toutes les informations via ce protocole. On va supposer ici que vous connaissez MQTT et que vous avez un broker de configuré. Dans Tasmota nous allons devoir entrer les informations suivantes (dans l'interface web de configuration ou sur la page console qui permet d'entrer des commandes) :

  • broker : addresse IP
  • topic : le topic de base du module (exemple ici : mon_wemos_teleinfo)
  • fulltopic : l'arboresence complète avec les variables
       exemple ici : maison/tasmota/%topic%/%prefix%/

Le module redémarre et est désormais accroché en MQTT à votre broker. Il peut se configurer, se piloter via ce protocole grâce auquel il envoie sa télémétrie. Nous allons maintenant régler cette dernière information. Deux possibilités :

  • Message MQTT à chaque modification sur le compteur 
  • Message MQTT à intervalle régulier (mode par defaut)

Pour ma part j'ai essayé la première option : c'est trop verbeux. Chaque seconde un message MQTT c'est trop souvent pour ce qu'on souhaite récupérer. Cependant, pour un monitoring très précis de la puissance (encore que... le Power n'est pas si précis que ça avec les moteurs, ...) le premier mode peut s'avérer utile. Pour l'activer on passe en mode console SetOption108 1. Si vous êtes resté sur le mode Télémétrie Energy (par défaut), vous allez avoir les informations dans le topic :

maison/tasmota/mon_wemos_teleinfo/tele/SENSOR

avec comme valeur quelque chose comme ça :

{"Time":"2020-11-18T12:16:28","ENERGY":{"TotalStartTime":"2020-10-18T00:00:00","Total":1861.951,"Yesterday":61.250,"Today":36.852,"Period":0,"Power":630,
"Current":3.000,"Load":6,"ADCO":"xxxxxxx","OPTARIF":"HC..","ISOUSC":45,"HCHC":62617552,
"HCHP":67058436,"PTEC":"HP..","IINST":3,"IMAX":52,"PAPP":630,"HHPHC":"A","MOTDETAT":0},"BME280":{"Temperature":9.8,"Humidity":53.6,"DewPoint":0.8,"Pressure":1009.0},"PressureUnit":"hPa",
"TempUnit":"C"}(spoiler : il y a un capteur de T°/Hum/Pression en + ici)

Pour ajuster la fréquence de report de la télémétrie, en console teleperiod <valeur en secondes>, pour garder le contenu en mémoire du broker (retain), toujours sous la console sensorretain 1.

Tasmota intègre nativement un suivi de consommation d'énergie. Le mode Teleinfo prend comme source le champ PAPP de Teleinfo et s'en sert de Wattmètre. Tasmota génère ensuite 3 compteurs :

  1. Daily (reset à 00h00)
  2. Yesterday (valeur de la veille)
  3. Total (valeur depuis la première initialisation)

On va s'en servir ensuite dans Home Assistant. il est possible de modifier ces valeurs, en particulier Total, pour s'en servir de compteur mensuel, annuel, ...

Configuration Home Assistant

C'est ici qu'on va voir toute la souplesse et la puissance de HA lorsqu'il récupère des informations de Tasmota. Nos objectif sont :

  • L'affichage des infos via des sensors dans Lovelace (Power, HC/HP, ...) et l'utilisation de certaines afin de conditionner des automations (HP/HC; EJP, ...)
  • Le suivi conso énergie via utility_meter: (autre article à venir...)

Toute la configuration se fait en mode sensor. On créée un sensor MQTT qui va se sourcer des informations JSON ENERGY généré par Tasmota toutes les x secondes (teleperiod), on créée également des sensor template qui vont parser les attributs du sensor MQTT pour extraire les infos souhaitées. Exemple :

Par exemple 

sensor:

# Teleinfo

#### Wemos D1 Mini + PitInfo : Teleinfo
#    - sensor = Energy Today (consommation journalière)
#    - attributs = tout le reste du JSON

- platform: mqtt
  name: 'Wemos PitInfo'
  state_topic: "maison/tasmota/mon_wemos_teleinfo/tele/SENSOR"
  value_template: "{{ (value_json['ENERGY'].Today) |float }}"
  unit_of_measurement: "kWh"
  device_class: energy
  availability_topic: "maison/tasmota/mon_wemos_teleinfo/tele/LWT"
  payload_available: "Online"
  payload_not_available: "Offline"
  json_attributes_topic: "maison/tasmota/mon_wemos_teleinfo/tele/SENSOR"
  qos: 1
#
#### Teleinfo attributes from Wemos_PitInfo
#
- platform: template
  sensors:
    #
    # Power
    teleinfo_puissance:
      value_template: '{{ state_attr("sensor.wemos_pitinfo","ENERGY").Power }}'
      unit_of_measurement: "W"
    #
    # EnergyHC
    teleinfo_energyhc:
      value_template: '{{ state_attr("sensor.wemos_pitinfo","ENERGY").HCHC }}'
      unit_of_measurement: "Wh"
    #
    # EnergyHP
    teleinfo_energyhp:
      value_template: '{{ state_attr("sensor.wemos_pitinfo","ENERGY").HCHP }}'
      unit_of_measurement: "Wh"
    #
    # Energy Total + attr HP/HC
    teleinfo_energy:
      value_template: '{{ state_attr("sensor.wemos_pitinfo","ENERGY").HCHC + state_attr("sensor.wemos_pitinfo","ENERGY").HCHP }}'
      unit_of_measurement: "Wh"
      attribute_templates:
        Index HP: >-
          {{ state_attr("sensor.wemos_pitinfo","ENERGY").HCHP }}
        Index HC: >-
          {{ state_attr("sensor.wemos_pitinfo","ENERGY").HCHC }}
    #
    # Energy yesterday
    teleinfo_energy_yesterday:
      value_template: '{{ ( state_attr("sensor.wemos_pitinfo","ENERGY").Yesterday *1000 ) |int }}'
      unit_of_measurement: "Wh"
    #
    # Energy total (year)
    teleinfo_energy_total:
      value_template: '{{ ( state_attr("sensor.wemos_pitinfo","ENERGY").Total *1000 ) |int }}'
      unit_of_measurement: "Wh"
    #
    # Periode Tarifaire
    teleinfo_periode_tarifaire:
      value_template: '{{ (state_attr("sensor.wemos_pitinfo","ENERGY").PTEC) |replace("..","") }}'

A partir de là vous voilà avec des sensors qui peuvent servir de sources de données pour faire du suivi de consommation (energy_meter) comme vu dans d'autres articles.

  • sensor.teleinfo_puissance : Puissance instantanée
  • sensor.teleinfo_energyhc : Index Heures Creuses (pour calcul coût)
  • sensor.teleinfo_energyhp : Index Heures Pleines (pour calcul coût)
  • sensor.teleinfo_energy : Sommes des 2 index HC et HP (pour calcul consommation Wh)
  • sensor.teleinfo_energy_yesterday : consommation de la veille
  • sensor.teleinfo_energy_total : consommation totale depuis initialisation du module (reset manuel, peut-être programmé en début d'année pour calculer une consommation annuelle avec Tasmota)
  • sensor.teleinfo_periode_tarifaire : période tarifaire (pour calcul coût)

Avec tout cela vous pouvez avoir le suivi d'énergie journalier global de votre installation avec ces sensors. A coupler avec un utility_meter pour avoir le suivi. Il est possible d'y associer le coût, en ajoutant à HA les informations de votre abonnement (la séparation HC/HP est faites pour ça !)

Amusez-vous bien !

Sources

 

Home Assistant, RC & Lights

Me voici bien installé sous Home Assistant, j'ai choisi au départ Zigbee pour les capteurs de température et d'ouverture, puis au hasard des pubs sur Ali Express et de mes passages chez Ikea j'ai acheté diverses télécommandes en me disant que j'en ferait bien quelque chose... L'usage principal étant de piloter des éclairages ou des scènes, du son, ou encore une action du genre "chauffe la salle de bain" et dis à Alexa de me prévenir quand la température sera idéale". Bien sur on peut remplacer les télécommandes par Alexa ou GH, mais ça me fait toujours bizarre de parler à ces objets, surtout quand je ne suis pas seul...

Bref, pour piloter un éclairage depuis une télécommande Zigbee il existe plusieurs approches plus ou moins facile à mettre en œuvre. On part du principe que Zigbee s'appuie sur ZHA, Zigbee2Mqtt, Deconz ou directement en MQTT.

Phoscon

Il s'agit ici de l'interface de Deconz qui est la solution la plus répandue et à mon gout la plus performante. Cette passerelle va plus loin que les autres en ce sens qu'elle intègre une interface qui permet facilement d'associer les touches d'une télécommande à des ampoules ou des prises. En fait au départ Phoscon est juste fait pour remplacer les passerelles propriétaires (Hue, Ikea, etc.) sans pour autant disposer de Home Assistant et il est même possible de créer des scènes et de disposer des fonctionnalités des passerelles émulées.

C'est donc la solution idéale quand on ne dispose que d'ampoules ou prises Zigbee, d'autant plus que ces éléments seront toujours disponibles sous HA pour d'autres actions et que cette passerelle est compatible Alexa. Personnellement je recommande l'installer sur un vieux RPI à part et ainsi la placer au centre du logement.

Automations

Mais, ça va se compliquer quand on va vouloir associer une télécommande Zigbee à un équipement non Zigbee. J'ai par exemple quelques variateurs Shelly et je voulais y associer une télécommande Opple afin de plus bouger mon cul du canapé, bien que dans la vraie vie je passe tout de même plus de temps dans mon fauteuil de bureau.

La solution consiste donc à écrire des automations en se basant sur les devices et les codes retournées par ces télécommandes. C'est long, fastidieux et encombrant quand on sait qu'il faut 4 automations pour gérer les fonctions de base d'une ampoule variable , et je ne parle pas de la gestion des couleurs. C'est lourd, mais ça fonctionne à coup de copié / collé, et le faire sous NodeRed sera tout aussi fastidieux.

ControllerX

Alors j'ai longtemps laissé ces télécommandes en déshérence, puis un soir je me suis mis à explorer la communauté HA (celle en anglais) à la recherche d'une alternative, et je suis tombé sur ControllerX. Au départ je n'ai pas aimé car ça s'appuie sur AppDaemon qu'il me fallait installer, ce qui alourdit mon serveur HA. Et puis en lisant je me suis dit que ça valait le coup de creuser la chose.

Je vous laisse installer AppDaemon 4, c'est un AddOn qui s'installe comme les autres depuis le superviseur sur Hassio. On peu aussi l'installer en Docker pour ceux qui aiment se compliquer la vie. Il faut juste créer un fichier de config basic qui sera suffisant pour ce que l'on va en faire dans :

secrets: /config/secrets.yaml
appdaemon:
  latitude: 52.379189
  longitude: 4.899431
  elevation: 2
  time_zone: Europe/Paris
  plugins:
    HASS:
      type: hass
http:
  url: http://127.0.0.1:5050
hadashboard:
admin:
api:

/config/appdaemon/appdaemon.yaml

Ensuite on va installer ControllerX depuis HACS et une fois fait créer le fichier de config, non pas de ControllerX mais des apps AppDaemon :

sejour_halogène: 
  module: controllerx
  class: WXCJKG13LMLightController
  controller: aqara_opple
  integration: deconz
  automatic_steps: 30
  mapping:
    3001: hold_brightness_toggle
    3002: toggle
    3003: release
    3004: toggle_full_brightness
    3005: toggle_min_brightness
  light: light.shelly_shdm_1_f3758  

/config/appdaemon/apps/apps.yaml

Et la lumière fut ! Ces quelques lignes assurent les 5 fonctions d'une touche de ma télécommande qui en comporte 6. Et encore ici j'ai choisit un mapping personnalisé car je souhaite que chaque touche ne commande qu'un seul point lumineux en me servant du multiclic, mais ça serait encore plus simple si je voulais juste reproduire les fonction d'une télécommande Ikea ou Hue avec l'ampoule ivrée avec.

Explications lignes par lignes :

  1. un nom d'app que vous choisissez.
  2. le nom du module AppDaemon, ici ControllerX.
  3. le code de la télécommande utilisée : ici le controleur Opple avec 6 boutons (ici la liste des contrôleurs supportés).
  4. l'ID du device fournit par la passerelle (controller_id ou adresse IEEE (voir ici comment récupérer cette information).
  5. L'intégration utilisée (deconz, mqtt, zha, state) (plus d'informations ici).
  6. Des options (multiple_click_delay: 500, delay: 50, automatic_steps: 30, manual_steps: 10 (je vous laisse cherche run peu car il y en d'autres).
  7. Les mapping, ce qui qui va consister à associer les codes envoyés par la télécommande aux fonctions possibles.
  8. Enfin, on pointe sur l'éclairage déclaré dans Home Assistant, ici un Dimmer Shelly.

Je n'ai parlé ici que de ce que j'ai utilisé. Mais ControllerX va beaucoup plus loin. Il est bien sur possible de piloter des scènes, des automation ou encore des lecteurs multimédia, et par exemple d'associer le bouton rotatif Ikea à votre lecteurs Sonos. Je vous conseille la lecteur du sujet dédié et bien sur de la doc sur GitHub, même si ce développeur est bien dans le codage de ses url qu'il faudra souvent reconstituer...

Bonus

Il existe deux intégration intéressantes à associer à ces problématiques, d'abord Light Switch qui va permettre de créer une entité de type lampe à partir d'un switch, et ensuite Light Group qui va permettre de grouper plusieurs lampes pour en faire une seule...

Edit

Alors depuis que j'ai écrit cet article il y une nouveauté dans Home Assistant : Blue Print. Cela va permettre de télécharger des automations (partagées ici par exemple, et bientôt sur HACF) qui vont permettre de gérer des télécommandes en quelques clics et sans rentre dans le code. Le catalogue s'étoffe de jours en jours, donc n'hésitez pas à y retourner.

Il n'en reste pas moins qu'il y a une chose que je n'ai pas trouvé en Blue Print. Je voulais avec une télécommande Ikea 5 boutons, pouvoir passer d'une ampoule à une autre avec les touches directionnelles.  Et ça je n'ai réussit à le faire qu'avec ControllerX, en créant un input_select: et en me servant des options de contrainte, voilà un exemple pour deux lampes :

select_light_app:
  module: controllerx
  class: CallServiceController
  controller: ikea_tradfri_rc
  integration: deconz
  mapping:
    4002:
      service: input_select.select_previous
      data:
        entity_id: input_select.rc_ikea_1
    5002:
      service: input_select.select_next
      data:
        entity_id: input_select.rc_ikea_1

light_app_1:
  module: controllerx
  class: E1810Controller
  controller: ikea_tradfri_rc
  integration: deconz
  light: light.shelly_shdm_1_f3d426
  constrain_input_select: input_select.rc_ikea_1,light_1
  excluded_actions: [4002, 5002]

light_app_2:
  module: controllerx
  class: E1810Controller
  controller: ikea_tradfri_rc
  integration: deconz
  light: light.shelly_shdm_1_f3a100
  constrain_input_select: input_select.rc_ikea_1,light_2
  excluded_actions: [4002, 5002]