Home Assistant & Mi Boxer

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

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

Ce qui fonctionne :

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

EDIT 11/01/2024

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

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

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

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

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

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

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

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

EDIT 11/01/2024

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

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

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

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

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

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

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

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

 
 

 

 

Home Assistant & Alarm, encore...

J'ai souvent parlé d'alarme ici, de télécommandes, de claviers et de sirènes. Je pense cette fois être parvenu à quelque chose de fonctionnel et je vais vous en parler. Pour faire face aux différentes contraintes, notamment la gestion bizarre des télécommandes sous ZHA, il va falloir un peu ruser. Avant que vous me demandiez pourquoi je m'obstine sous ZHA alors que ces mêmes télécommandes sont bien gérées sous Z2M, je vous répondrait que mon objectif est la simplification et donc d'éviter le plus possible les adons qui complexifient une installation, pas forcément pour moi ou je dispose de toutes les passerelles possibles, mais sur des installations que je gère à distance ou je me dois de faire simple et fiable.

Attention :  on parle ici d'un système de sécurité DIY, donc non agrée par les assurances et autres... Ca ne veut pas dire que ça ne fonctionne pas, juste que ça ne répond pas aux normes NF en vigueur dans ce domaine

Afin de gérer toutes les contraintes, je vais principalement m'appuyer sur deux automations:, quelques scripts: et un alarm_control_panel: virtuel.

L'objectif est de gérer :

  • Un mode absent (away) (avec une variable pour simuler un peu de présence).
  • Un mode présent/nuit armé (home) (plus ou moins utile mais mais ça fait partie de tout système d'alarme face au home jacking.
  • Un mode alerte (emergency) qui va permettre de déclencher une action d'urgence en appuyant sur un bouton de télécommande ou médaillon (je pense à mes vieux jours).

De l'armement / désarmement vont également découler :

  • La fermeture complète ou partielle des volets roulants, leur réouverture cohérente avec la programmation en cours et éventuellement le passage en manuel des volets des chambres des enfants / invités s'ils sont présents.
  • La gestion du climatiseur et des convecteurs avec passage en mode éco ou absent en fonction du type d'armement).
  • La gestion du chauffe eau en cas d'absence de longue durée.
  • La gestion des éclairages et la mise en veille des écrans et ordinateurs.
  • ...

Etant donné que j'ai deux systèmes d'alarme qui fonctionnent en parallèle (Alarmo et Visonic), j'ai commencé par créer une alarme virtuelle et je me servirait d'elle pour les différentes actions.

alarm_control_panel:
  - platform: manual
    name: Home Alarm Command
    code: 1234
    code_arm_required: false
    disarm_after_trigger: false
    arming_time: 0
    delay_time: 0
    trigger_time: 600
    disarmed:
      trigger_time: 0
    armed_home:
      arming_time: 0
      delay_time: 0

L'Armement / Désarmement

L'armement / désarmement va pouvoir se faire de plusieurs façons :

  • Clavier à code
  • Télécommande dédiée
  • Application mobile
  • Tag RFID (pour désarmer dans mon cas)

J'ai volontairement écarté les télécommandes radio en 433 Mhz dont j'avais parlé ici, d'une part parce qu'elles sont facilement piratables, et d'autre part parce qu'elles ne permettent pas de savoir qui a désarmé le système.

Je vais utiliser deux automations et les découper ce dessous/

  • La première pour gérer les armements / désarmements
  • La seconde pour gérer le désarmement des télécommandes, claviers à code afin d'intégrer les particularités ZHA (en attendant une amélioration de la part des développeurs de Home Assistant qui pour l'instant font la sourde oreille, parfois plus concentrés sur les nouveautés que l'affinage de l'existant).

Gestion de l'armement / désarmement et des boutons d'urgence

Les déclencheurs : Ici on va empiler nos déclencheurs d'armement, qu'ils soient gérés par ZHA, Z2M ou toute autre source. 3 par fonction, armed_away, armed_home, triggered, mais cela peut également être un bouton virtuel pour Lovelace, voire n'importe quelle télécommande ou bouton poussoir.

- id: 078fsdg412-3545-4f37-ba02-bccsfds5646sf
  alias: "Alarm : Global ON/OFF"
  mode: restart
  trigger:
    - platform: device
      device_id: c036b6547a0347878dcc6d06152267ab
      domain: alarm_control_panel
      entity_id: alarm_control_panel.lk_zb_keypad
      type: armed_away
      id: "KeyPad Away"
    - platform: device
      device_id: c036b6547a0347878dcc6d06152267ab
      domain: alarm_control_panel
      entity_id: alarm_control_panel.lk_zb_keypad
      type: armed_home
      id: "KeyPad Home"
    - platform: device
      device_id: c036b6547a0347878dcc6d06152267ab
      domain: alarm_control_panel
      entity_id: alarm_control_panel.lk_zb_keypad
      type: triggered
      id: "KeyPad Triggered"
    - platform: state
      entity_id: input_button.arm_alarm_away
      id: "Push Button Away"

Et un déclencheur de désarmement activé par une seconde automation que l'on verra plus loin :

    - platform: state
      entity_id:
        - alarm_control_panel.home_alarm_command
      to: disarmed
      id: "Remote or Keypad"

Les conditions : Dans mon cas je n'en ai pas utilisé. Chacun adaptera.

  condition:

Les actions

Je commence par arrêter les éventuels scripts en cours. Cela est principalement utile quand on a fermé la porte, armé le système et que l'on doit rapidement désarmer car on a oublié quelque chose dans la maison.

  action:
    - service: homeassistant.turn_off
      target:
        entity_id:
          - script.privacy_on
          - script.privacy_off
          - script.alarmo_after_arm
          - script.alarmo_after_disarm
          - script.alarm_actions_on_leave_common_tasks
          - script.alarm_actions_on_return_common_tasks

Ensuite on va utiliser chose: pour exécuter les différentes actions en fonction de la source et de l'état.

On commence par l'armement en mode absent :

  • On envoie les bips d'armement sur la sirène. En MQTT pour l'instant car elle aussi est très mal gérée sous ZHA
  • On arme Alarmo
  • On arme Visonic (en mode Home sans les PIR qui déraillent).
  • On arme notre panneau d'alarme virtuel qui nous servira au désarmement
  • On arme également le clavier, ça ne change rien à l'usage mais quand on se présentera pour désarmé il apparaitra comme étant armé. Dans la pratique ça relance de fait l'automation avec la même automation, et donc ça fausse le message, j'ai donc retiré cette option pour l'instant. (D'ailleurs si vous êtes sous Z2M il le développeur d'Alarmo a fait un joli travail pour ce clavier).
  • On inscrit un message texte dans un input_text: que l'on affiche dans Lovelace et qui nous permet de savoir qui fait quoi. A terme je remplacerait les id: par le prénom de l'utilisateur pour plus de lisibilité.
    - choose:
        - conditions: "{{ trigger.id in ['KeyPad Away', 'Heiman RC1 Away', 'Heiman RC2 Away', 'Woox RC1 Away'] }}"
          sequence:
            - service: mqtt.publish
              data:
                topic: zigbee2mqtt/Sirène SMaBiT/set
                payload: >-
                  {"squawk": {"state": "system_is_armed", "level": "veryhigh", "strobe": "true"}}     
            - service: alarm_control_panel.alarm_arm_away # ALARMO Away
              data:
                code: !secret alarm_code
              entity_id: alarm_control_panel.alarmo
            - service: alarm_control_panel.alarm_arm_home # VISONIC Home (ne jamais armer AWAY à cause des détecteurs HS)
              data:
                code: !secret alarm_code_visonic
              entity_id: alarm_control_panel.visonic_alarm
            - service: script.alarm_actions_on_leave_common_tasks
            - service: alarm_control_panel.alarm_arm_away # FAKE ALARM PANEL Away
              target:
                entity_id: alarm_control_panel.home_alarm_command
            - service: alarm_control_panel.alarm_arm_away # On arme le clavier afin qu'il apparaisse armé
              data:
                code: !secret alarm_code_zha
              target:
                entity_id: 
                  - alarm_control_panel.lk_zb_keypad
            - service: input_text.set_value
              target:
                entity_id: input_text.last_arm
              data:
                value: "{{now().strftime('%d/%m/%Y, %H:%M:%S')}} > Arm Away by : {{ trigger.id }}"                            

On fait la même chose pour le mode home. Je fais l'impasse sur Visonic, par contre j'émet un son de confirmation sur un buzzer (on verra plus loin l'utilisation possible d'un TTS sur une enceinte.

        - conditions: "{{ trigger.id in ['KeyPad Home', 'Heiman RC1 Home', 'Heiman RC2 Home', 'Woox RC1 Home'] }}"
          sequence:
            - service: alarm_control_panel.alarm_arm_home # ALARMO Home
              data:
                code: !secret alarm_code
              entity_id: alarm_control_panel.alarmo
            - service: alarm_control_panel.alarm_arm_home # FAKE ALARM PANEL Home
              target:
                entity_id: alarm_control_panel.home_alarm_command
            - service: alarm_control_panel.alarm_arm_home # On arme le clavier afin qu'il apparaisse armé
              data:
                code: !secret alarm_code_zha
              target:
                entity_id: 
                  - alarm_control_panel.lk_zb_keypad

            - service: button.press
              target:
                entity_id: button.up_chime_play_buzzer
            - service: input_text.set_value
              target:
                entity_id: input_text.last_arm
              data:
                value: "{{now().strftime('%d/%m/%Y, %H:%M:%S')}} > Arm Home by : {{ trigger.id }}"                                    

Ensuite on passe au désarmement du mode absent. On remarque que l'on écrit pas d'input_text: car ici on ne sait pas qui a fait quoi car l'ordre vient de la seconde automation que l'on verra plus loi. C'est donc elle qui écrira. Par contre on émet le son de désarmement sur la sirène.

        - conditions: "{{ trigger.id in ['Remote or Keypad'] and is_state('alarm_control_panel.alarmo', 'armed_away') }}"
          sequence:              
            - service: alarm_control_panel.alarm_disarm
              data:
                code: !secret alarm_code
              entity_id:  
                - alarm_control_panel.alarmo
                - alarm_control_panel.visonic_alarm
            - service: mqtt.publish
              data:
                topic: zigbee2mqtt/Sirène SMaBiT/set
                payload: >-
                  {"squawk": {"state": "system_is_disarmed", "level": "veryhigh", "strobe": "true"}}       

Pareil pour le mode Home. Ici on joue un son sur le buzzer.

        - conditions: 
            - "{{ trigger.id in ['Push Button'] }}"
            - "{{ is_state('alarm_control_panel.alarmo', 'armed_home') }}"
          sequence:              
            - service: alarm_control_panel.alarm_disarm
              data:
                code: !secret alarm_code
              entity_id:  
                - alarm_control_panel.alarmo
            - service: button.press
              target:
                entity_id: button.up_chime_play_buzzer

On continue avec la gestion du bouton d'urgence :

  • On joue un son pour confirmer
  • On arme notre panneau d'alarme virtuel dans un mode inutilisé (Nuit) pour ensuite pouvoir désarmer.
  • On envoie un SMS d'Au Secours, ou toute autre action à imaginer.
  • On écrit un input_text: pour avoir une trace.
        - conditions: "{{ trigger.id in ['KeyPad Triggered', 'Heiman RC1 Triggered', 'Heiman RC2 Triggered', 'Woox RC1 Triggered'] and is_state('alarm_control_panel.alarmo', 'disarmed') }}"
          sequence:              
            - service: button.press
              target:
                entity_id: button.up_chime_play_chime
            - service: alarm_control_panel.alarm_arm_night # FAKE ALARM PANEL Night pour pouvoir désarmer
              target:
                entity_id: alarm_control_panel.home_alarm_command
            - service: notify.free_mobile_andre
              data:
                message: "{{ states.sensor.date_time.state}} > TEST Alerte au secours par télécommande TEST"
            - service: input_text.set_value
              target:
                entity_id: input_text.last_arm
              data:
                value: "{{now().strftime('%d/%m/%Y, %H:%M:%S')}} > Triggered by : {{ trigger.id }}"   

Enfin, on désarme cette alerte. A ce stade on peut aussi envoyer un SMS pour dire que c'était une fausse alerte... Je vais me contenter de jouer du buzzer...

        - conditions: 
            - "{{ trigger.id in ['Remote or Keypad'] and is_state('alarm_control_panel.alarmo', 'disarmed') }}"
          sequence:              
            - service: button.press
              target:
                entity_id: button.up_chime_play_buzzer

Le cas des tag RFID

Les tags RFID c'est sympa, mais hormis en coller deux cote à cote on ne pourra basiquement gérer qu'un seule information : tag_scanned

Hors, l'idée est de se servir d'un même tag collé à la porte pour armer ou désarmer. S'il s'agissait d'un switch on ferait un switch.toggle, mais pas pour une alarme. Il va falloir ruser.

Bien sur on pourrait mettre une condition pour savoir connaitre l'état de l'alarme, mais je ne veux pas utiliser de condition et uniquement un trigger avec son id:. J'ai passé des heures à essayer de faire un trigger template pour combiner le scan du tag + l'état de alarm_control_panel, mais sans succès car le tag n'est pas un device ou un entity ou l'on peut facilement lire l'état.

La solution consiste à créer un binary_sensor: temporisé :

template:
  - trigger:
      - platform: event
        event_type: tag_scanned
        event_data:
          tag_id: bf5018c7-c1a9-4220-a01a-66f885176795
#          name: Tag Green
#          device_id: 1d3ddfgy45805354ce090774e3f22510
    binary_sensor:
      name: Tag Green
      state: "{{ trigger.platform == 'event' }}"
      auto_off:
        seconds: 1

A noter que name: peut être utilisé à la place de tag_id: et que l'on peut jouer avec les autres informations que l'on trouve dans l'event afin par exemple de savoir quel appareil a scanné le tag et ainsi savoir qui a armé ou désarmé... 

Et ensuite il sera facile de créer un trigger basé sur un petit template et se servir de son id: pour action dans le chose:

  - platform: template
    value_template: "{{ is_state('binary_sensor.tag_green', 'on') and is_state('alarm_control_panel.alarmo', 'armed_home') }}"
    id: tag_to_disarm

Gestion des commandes de désarmement

Au risque de me répéter, cette partie aurait pu être intégrée à la première automation, si ZHA ne posait pas problème... Je le ferait probablement, mais pour l'exemple on va pour l'instant scinder cette partie.

Donc, pour les télécommandes d'alarme sous ZHA on va devoir écouter un event:, s'en servir pour désarmer nos système d'alarme mais également pour la désarmer et désarmer ses copines ainsi que le clavier. Simple ! J'avais exploré dans un précédent article plusieurs pistes afin de ne prendre en compte qu'un seul de ses "events" (en + elle en envoie 3 ou 4 identiques selon l'humeur et le modèle). J'ai un peu avancé et on ne va pas les écouter dans l'automation, mais se servir de l'état temporaire d'un binary_sensor: que l'on va pouvoir temporiser et ainsi ne prendre en compte qu'un seul event:

template:
  - trigger:
      - platform: event
        event_type: zha_event
        event_data:
          device_ieee: a4:c1:38:96:0b:cf:c9:61 # Woox RC1
          command: 'arm'
          args:
            arm_mode: 0
            arm_mode_description: 'Disarm'
            code: ''
            zone_id: 0
    binary_sensor:
      name: Woox RC1 to Disarmed
      icon: "{{ (trigger.platform == 'event') | iif('mdi:remote-off', 'mdi:remote') }}"
      state: "{{ trigger.platform == 'event' }}"
      auto_off:
        seconds: 5

Les déclencheurs : Ici on va écouter des actions de désarmement, que cela provienne d'un clavier, une télécommande (via leur binary_sensor:), ou en direct pour une source classique (tag RFID, MQTT, ...).

- id: '2bd0ertyyf-43fa-45f98f-aed0-disarm'
  alias: "Alarm @ Remote Disarm"
  description: 'Disarm Remote Control panel'
  mode: single
  trigger:
    - platform: state
      entity_id: binary_sensor.heiman_rc1_to_disarmed
      to: "on"
      id: "Heiman RC 1"  
    - platform: tag
      tag_id: 2b855225-c999-4b5558123-6c7d12345641
      id: "TAG Jaune"
    - platform: device
      domain: mqtt
      device_id: 139eb4ce27246465b0d5aa7560a953601
      type: action
      subtype: disarm
      discovery_id: 0x84fd27fffe915905 action_disarm
      id: "Heiman RC2"

Les conditions : Aucune, mais on pourrait imagine un flag de blocage activé à distance après une alerte...

condition:

Les actions : On utilise un chose: et on commence par :

  • Désarmer le panneau d'alarme virtuel, ce qui déclenchera l'action idoine dans la première automation.
  • Désarmer les télécommandes et claviers qui sont également des panneaux d'alarme, avec cette particularité ZHA qui fait qu'il faut un code pour désarmer une télécommande...
  • Ecrire un input_text: afin de savoir qui a désarmé.
  • J'envoie un message dans Slack qui me sert de log. Ca va également m'informer à distance que quelqu'un est arrivé et a désarmé 
  action:
    - choose: # DISARM
        - conditions: "{{ trigger.id in ['Push Button', 'KeyPad', 'Linkind RC', 'Heiman RC 1', 'Woox RC 1', 'TAG Porte', 'TAG Jaune', 'TAG Clé', 'TAG Carte', 'Heiman RC2' ] }}"
          sequence:
            - service: alarm_control_panel.alarm_disarm   # FAKE ALARM PANEL to Command
              data:
                code: "1234"
              target:
                entity_id: alarm_control_panel.home_alarm_command
            - service: alarm_control_panel.alarm_disarm
              data:
                code: !secret alarm_code_zha
              target:
                entity_id: 
                  - alarm_control_panel.lk_zb_keypad
                  - alarm_control_panel.lk_zb_remote
                  - alarm_control_panel.heiman_remote
                  - alarm_control_panel.woox_01
            - service: input_text.set_value
              target:
                entity_id: input_text.last_disarm
              data:
                value: "{{now().strftime('%d/%m/%Y, %H:%M:%S')}} > Disarm by : {{ trigger.id }}"
            - service: notify.slack_hass_canaletto
              data:
                message: "{{now().strftime('%d/%m/%Y, %H:%M:%S')}} > Disarmed by : {{ trigger.id }}" 

On peut également faire une place à une fonctionnalité détournée du clavier. En effet au delà de l'amenée Home, Away et Emergency, on peut également lui faire avaler n'importe quel code et effectuer une action précise en fonction de celui ci. Ici si je saisit 33 et valide je vais allumer les projecteurs.

    - choose:
        - conditions: "{{ trigger.id in ['KeyPad 33'] }}"
          sequence:
            - service: light.turn_off
              target:
                entity_id:
                  - light.groupe_de_projecteurs          

Enfin j'ai quelques actions par défaut, comme éteindre les sirènes au cas ou... (ça sent le debug...).

    - service: mqtt.publish
      data:
        topic: zigbee2mqtt/Sirène SMaBiT/set
        payload: >-
          {"warning": {"mode": "stop"}}
    - service: siren.turn_off
      target:
        entity_id:
          - siren.heiman_sirene_1
          - siren.heiman_sirene_2
          - siren.sirene_terrasse                

Et surtout on ajoute un délai car ces télécommandes ont la fâcheuse idée d'envoyer 3 ou 4 event: identique pour chaque appui. Donc combiné au mode: single de cette automation, on va en capturer qu'un seul. Ce délais est bien sur à ajuster plus ou moins au pif... Maintenant que je passe par des binary_sensor: temporisés, je pense que ce délai est devenu inutile.

    - delay : '00:00:08'

Les actions POST Armement / Désarmement

On va utiliser deux scripts qui seront exécutés par Alarmo après l'armement et après le désarmement. Chez moi ils vont servir à :

  • Jouer une annonce vocale en TTS sur une enceinte extérieure pour annoncer l'état armé ou désarmé.
  • Activer ou désactiver la vidéo surveillance.
  • Passer les volets en mode manuel et automatique au retour (voir l'automatisation des volets).
  • Gérer le mode ECO/Absent du climatiseur et des convecteurs.
  • Gérer les éclairages et le mode veille de mon PC.
  • Et plus encore selon votre imagination....

Les notifications d'alarme et sirènes

  • Notifications SMS pour l'intrusion, la détection incendie ou fuite d'eau. (notifications gérées par Alarmo).
  • Sirènes et projecteurs en cas d'intrusion :
    • la législation autorise au maximum 3 minutes pour chaque lancement de sirène.
    • Pas de limite pour les projecteurs. Et éclairer comme en plein jour peut également faire fuir et permettra d'avoir des images bien nettes sur les caméras.
    • Si vous avez un système audio multi room bien puissant, vous pouvez également envoyer une bonne salve d'AC-DC, ça peu perturber... ou inciter les voisins à appeler la maréchaussée.
    • Les armes, explosifs et autres gaz toxiques sont à proscrire.

Pour cela on va utiliser des scripts: qui seront lancés par Alarmo selon les conditions choisies (voir ici).

Etant donné que j'ai des détecteurs d'ouverture sur mes volets roulants, je peux également imaginer l'éclairage extérieur avant de déclencher l'alarme si un de ces volets est touché. Il faut être prévenant et éclairer l'intrus. Cela peut se gréer dans une partition secondaire d'Alarmo, ou simple une automation. Les caméras Unifi Protect (G4) font également de la détection de personne qui remonte dans Home Assistant.

Voilà, ce n'est pas exhaustif, vos idées son les bienvenues, ici ou sur HACF.

 

 

Home Assistant & Remote Alarm

Ici je vais explorer un nouvel objet qui paraissait simple à exploiter mais s'est avéré un peu compliqué. J'ai acheté une télécommande d'alarme Heiman HS1RC en me disant que l'intégration allait être simple. Sauf que, comme ce clavier, sous ZHA cette télécommande n'est pas vue comme une classique télécommande mais comme un panneau de contrôle d'alarme. A noter que l'on retrouve le même comportement sur la télécommande Woox ou Linkind.

Pourquoi pas, il doit y avoir une raison à ce choix (probablement le bouton du bas qui passe en mode "triggered" quelque soit l'état). Sauf que pour gérer les clavier on configure un code dans ZHA, code que va attendre cette télécommande pour se désarmer. Dans ZHA on peu se passer de code pour armer, mais pas pour désarmer. Et comme le bouton désarmer de la télécommande n'envoie pas ce code elle ne désarme pas. De fait on ne peut pas se servir de sont état "disarmed" pour désarmer Alarmo...

Il va donc falloir passer par une petite automation intermédiaire afin de lui faire manger ce code et ensuite avoir un comportement normal de ce panneau d'alarme pour le désarmement... enfin je pensais que ça suffirait....

- id: '2bd0ertyyf-43fa-45f98f-aed0-heiman-001'
  alias: "Alarm @ Heiman RC Home"
  description: 'Disarm RC Control Panel to use events'
  mode: single
  trigger:
    - platform: event
      event_type: zha_event
      event_data:
        device_ieee: 5c:02:72:ff:fe:e9:2f:ff
        command: 'arm'
        args:
          arm_mode: 0
          arm_mode_description: 'Disarm'
          code: ''
          zone_id: 255
      id: "rc_1"
  condition: []
  action:
    - service: alarm_control_panel.alarm_disarm
      data:
        code: !secret alarm_code_zha
      target:
        entity_id: alarm_control_panel.heiman_rc_ef_3_0_alarmcontrolpanel
    - delay : '00:00:05'

A noter qu'il y a une particularité, quand on appuie sur un des 3 boutons du haut ça envoie 3 event's identiques. Bug ou sécurité supplémentaires liée à l'usage original de cette télécommande ? Je n'ai pas trouvé d'explications vraiment acceptables, certains disent qu'il s'agit d'event's transmis par des équipements relais, d'autres non.... Et le seul contournement que j'ai trouvée pour l'instant consiste à passer mon automation en mode single et d'ajouter un petit delay à la fin afin de ne pas exécuter cette automation trois fois de suite...

A noter que si on utilise plusieurs télécommandes (celle ci ou celle de chez Woox, ou un clavier), il conviendra de tout désarmer toutes les autres unités qui auraient pu êtres utilisées pour l'armement.

Bon, c'est une solution, mais on ne peut pas dire que ce soit très propre...

A noter que ces mêmes télécommandes sous Z2M transmettent des informations exploitables...

> arm_day_zones
> arm_all_zones
> disarm
> emergency

Alternative

En attendant que les développeurs prennent en compte nos demandes, j'ai peut être trouvé une alternative un peu moins sale. J'utilise ControllerX sous AppDaemon pour gérer toutes mes télécommandes et il se trouve qu'il sait traiter les Events sous forme de template. Je peux donc facilement remplacer mon automation par ce code :

remote_alarm:
  module: controllerx
  class: Controller
  controller: 
    - "a4:c1:48:96:0c:cf:c9:68:1:0x0501"  # Woox RC
    - "58:8e:81:zz:fe:26:12:64:1:0x0501"  # Linkind RC
    - "5c:02:72:xx:fe:e9:2f:9a:1:0x0501"  # Heiman RC
    - "68:0a:e2:af:fe:ea:89:22:1:0x0501"  # Linkind Keypad
  light: light.my_fake_light
  integration:
    name: event
    event_type: zha_event
    controller_key: unique_id
    action_template: "{command}_{args[arm_mode]}_{args[arm_mode_description]}_{args[code]}#"    # Ici il n' a pas de code reçu
  mapping:
    arm_0_Disarm_#:   # Ici il n' a pas de code reçu
      - service: input_button.press
        target:
          entity_id: input_button.disarm_alarm    
      - service: alarm_control_panel.alarm_disarm
        data:
          code: !secret alarm_code_zha
          entity_id:
            - alarm_control_panel.lk_zb_keypad 
            - alarm_control_panel.lk_zb_remote
            - alarm_control_panel.heiman_remote
            - alarm_control_panel.woox_01

    arm_0_Disarm_1234#:   # Ici on a le code du clavier défini dans ZHA
      - service: input_button.press
        target:
          entity_id: input_button.disarm_alarm          
      - service: alarm_control_panel.alarm_disarm
        data:
          code: !secret alarm_code_zha
          entity_id: 
            - alarm_control_panel.lk_zb_remote
            - alarm_control_panel.heiman_remote
            - alarm_control_panel.woox_01

    arm_0_Disarm_314#:   # Ici on peut traiter n'importe quel code reçu par le clavier et générer une action...
      - service: notify.slack_hass_canaletto
        data:
          message: "{{now().strftime('%d/%m/%Y, %H:%M:%S')}} > Keyboard 314" 

Ici je désarme en plus le sirènes (une sous Z2M qui ne l'expose pas en tant que sirène et les autres en ZHA. Ensuite je notifie Slack qui me sert de log et me permettra de savoir quelle télécommande à désarmé le système. En ce qui concerne le clavier il est également possible d'utiliser plusieurs codes pour désarmer, les traiter via les events et ainsi savoir quel code (confié à une seule personne) à désarmé le système...

    - service: mqtt.publish
      data:
        topic: zigbee2mqtt/Sirène SMaBiT/set
        payload: >-
          {"warning": {"mode": "stop"}}
    - service: siren.turn_off
      target:
        entity_id:
          - siren.heiman_sirene_1
          - siren.heiman_sirene_2
          - siren.sirene_terrasse        
    - delay : '00:00:08'
    - service: notify.slack_hass_canaletto
      data:
        message: "{{now().strftime('%d/%m/%Y, %H:%M:%S')}} > Disarm all remotes by : {{ trigger.id }}" 

Exploitation

Armement de l'alarme

Dans l'automation qui sert à armer on va utiliser l'état de l'entité Alarm Control Panel de la télécommande avec un ID afin de dérouler la séquence souhaitée et tout ce qui s'en suit (on peu imaginer faire de choses différentes selon le bouton sur lequel on appuie) :

    - platform: state
      entity_id: alarm_control_panel.heiman_rc_ef_3_0_alarmcontrolpanel
      to: "armed_home"
      id: "rc_1_home"

A noter que l'on peut également au besoin utiliser to : "triggered" afin de déclencher une autre action immédiate. Genre je me fait agresser quand j'ouvre la porte....

Désarmement de l'alarme

Paradoxalement c'est un peu plus compliqué. En effet si on a armé avec la télécommande et qu'elle se trouve en armed_home il n'y aura pas de soucis quand on va désarmer avec cette même télécommande car elle enverra un disarmed. Par contre si on veut désarmer avec une seconde télécommande ou un clavier qui n'aura pas servi à armer, celui-ci se trouvant déjà en disarmed il n'y aura pas de changement d'état et il ne se passera rien.

Donc dans l'automation qui sert à désarmer on ne va donc pas utiliser l'état de l'entité Alarm Control Panel des différents devices (télécommandes, claviers) mais un input_button: (à créer) :

    - platform: state
      entity_id: input_button.disarm_alarm
      id: "button"

Et cet input_button: sera commandé par l'automation de départ (plus haut) que j'ai adaptée :

  1. Elle se déclenche à partir des event's des différents devices
  2. Elle change l'état de l'entité Alarm Control Panel des différents devices
  3. Elle envoie un input_button.press qui va déclencher l'automation de désarmement.

Ainsi quand on désarme une télécommande on désarme les autres qui seront disponibles pour un futur armement. Et vu qu'on désarme avec un push button, on peu également envoyer depuis Lovelace ou toute autre automation.

Bref, voilà comment perdre un après midi... J'ai réédité cet article plusieurs fois et j'y reviendrait certainement.

Les commentaires de mon blog n'étant pas des plus pratiques, il est également possible d'échanger sur cet article ici, sur HACF.

EDIT du 27/07/2023

Toujours pour ces télécommandes sous ZHA j'ai depuis trouvé une autre solution en passant par un template: qui va changer l'état d'un binary_sensor:. L'idée est d'écouter un event et de basculer l'état du binary_sensor: quelque secondes. Bien sur la télécommande passe en mode triggered, mais on peut annuler facilement cet état dans l'automation de traitement ou on se sert de l'état du binary_sensor: pour désactiver :

template:
  - trigger:
      - platform: event
        event_type: zha_event
        event_data:
          device_ieee: a4:c1:38:96:0b:cf:c9:61 # Woox RC1
          command: 'arm'
          args:
            arm_mode: 0
            arm_mode_description: 'Disarm'
            code: ''
            zone_id: 0
    binary_sensor:
      name: Woox RC1 to Disarmed
      icon: "{{ (trigger.platform == 'event') | iif('mdi:remote-off', 'mdi:remote') }}"
      state: "{{ trigger.platform == 'event' }}"
      auto_off:
        seconds: 5

Ensuite une automation sur trigger/state (j'en mets qu'un seul ici mais dans la pratique il y a toutes les télécommandes, claviers et RFID qui me servent à désactiver mes alarmes Alarmo et Visonic)

automation:
- id: '2bd0ertyyf-43fa-45f98f-aed0-disarm'
  alias: "Alarm @ Remote Disarm"
  description: 'Disarm Remote Control panel'
  trigger:
    - platform: state
      entity_id: binary_sensor.woox_rc1_to_disarmed
      to: "on"
      id: "Woox RC 1"

Et dans les actions la première chose à faire est de désactiver le triggered de la télécommande. On peut conditionner avec un tigger.id ou le faire pour toutes :

  action:
    - choose: # DISARM
        - conditions: "{{ trigger.id in ['Woox RC 1'] }}"
          sequence:
            - service: alarm_control_panel.alarm_disarm
              data:
                code: !secret alarm_code_zha
              target:
                entity_id: 
                  - alarm_control_panel.woox_01  # Ici on désactive la télécommande

                  - alarm_control_panel.alarmo   # Ici on désactive Alarmo
                  - alarm_control_panel.visonic  # Ici on désactive Visonic

J'ai simplifié pour l'exemple car dans la pratique je désactive un faux alarm_control_panel: qui me sert à commander les deux alarmes et d'autres choses liées aux personnes, volets, etc...

            - service: alarm_control_panel.alarm_disarm
              data:
                code: !secret alarm_code_zha
              target:
                entity_id: 
                  - alarm_control_panel.home_alarm_command # Fake Alarm       

L'idéal serait de pouvoir modifier le comportement de ces télécommandes avec un Quirk sous ZHA afin qu'elles se comportent comme sous Z2M. D'après mes recherches c'est faisable, mais je ne sais pas faire.

Depuis j'ai également testé les petits télécommandes Shelly en BLE avec un seul bouton multifonction, ça fait le job et c'est plus simple. Avantage on évite le temps de reconnexion au réseau.

J'ai passé beaucoup de temps (trop) à tester toutes les possibilités dans tous les sens avec l'objectif que cela fonctionne sur une base ZHA afin de le rendre facile duplicable. De fait j'ai pas mal de choses empilée et la prochaine étape consistera à simplifier au maximum et d'écrire un article plus clair...

Sources

 

Home Assistant IR, AC & More...

Pour piloter un climatiseur avec Home Assistant il existe plusieurs options, mais vu qu'il n'existe pas de protocole unifié (à par peut être KNX que l'on oublie pour des questions de coûts), ça va bien souvent se terminer en IR, là ou une option MQTT sur les interfaces WI-FI des constructeurs aurait été une bénédiction. En dehors de Dalkin qui dispose d'une intégration et Xiaomi (non importé), ces interfaces sont bien sur propriétaires et fermées.

Alors on se rabat sur l'infrarouge, ce qui n'est pas très sexy en 2020 ! D'ailleurs si vous voulez juste piloter une clim avec une application, plutôt que de payer cher une option WIFI du constructeur, pour 80/90 € offrez vous simplement un Tado ou un Sensibo, ça fera le job en mieux et ce sera compatible Alexa et Google Home, avec des intégrations Home Assistant (Tado | Sensibo) à la clé. Sauf que c’est du cloud et que je veux un pilotage local.

On va donc partir sur un Broadlink qui dispose d'une intégration. A la base ce gadget permet de piloter n’importe quel appareil IR depuis une application mobile. Ici on va faire la même chose, mais de puis Home Assistant, et on va voir qu'il existe plusieurs façons de faire, et accessoirement que j'ai perdu bien du temps en ne trouvant pas la seconde option tout de suite...

Intégration du Broadlink à Home Assistant

Ça c'est la première chose à faire dans tous les cas, sans perdre de vue que votre Broadlink sera sur l'application ou sur Home Assistant, pas les deux. Il est toutefois intéressant de l'ajouter une fois à l'application pour récupérer son IP et son adresse Mac.

  1. On supprime le Broadlink de l'application mobile.
  2. Sans le débrancher on lui fait un reset en appuyant 6 secondes avec un trombone.
  3. On ajoute le Broadlink au réseau avec l'application, mais sans le connecter au cloud Broadlink, pas maintenant, pas plus tard. On sort de l'application et on l'oublie.

Ensuite on ajoute ces quelques lignes au fichier configuration.yaml en reportant les infos précédament récupérées et on redémarre HA. Idéalement on place une réservation DHCP sur cette IP.

remote:
  - platform: broadlink
    name: rm4_mini
    type: rm4c_mini  # Ça c'est très important....
    host: 192.168.210.132
    mac: '24:AF:A2:30:0D:E2'

A partir de là on a deux possibilités. La première va consister à apprendre les codes IR et à les restituer. Pour les apprendre on va faire un petit script et se laisser guider par les notifications de Home Assistant pour presser sur les touches idoines au bon moment...

learn_tv_commands:
  alias: Apprentissage IR
  sequence:
  - data:
      command:
      - turn on
      - turn off
      - volume up
      - volume down
      - chanel up
      - chanel down
      device: television_sam
      entity_id: remote.sam
    entity_id: remote.rm4_mini
    service: remote.learn_command

Et on va se retrouver avec les fichier /config/.storage/broadlink_remote_24dfa2300de2_codes qui va contenir nos codes IR, fichier dans lequel il nous suffira d'aller récupérer les bons codes.

{
    "data": {
        "television_sam": {
            "chanel down": "JgDSAJOUEjcTNxQ1ExIUERMSExITERQ2FDYTNhMSExITEhMSFBETERQRExITEhM2FBETEhMSFDYUNRM3FDYTEhM2EzcTNhQABgKWkhQ2EzcUNRQRExITEhMSFBEUNRM3EzYUERMSFBEUERQRExITERQRExIUNhMSFBEUEBQ2EzYUNhM3FBETNhM3EzYVAAYBlpIUNhQ2FDUTEhQRFBEUERMRFDYUNhM2FBEUERQRExIUERQQFBEUERMSFDUVEBQRExIUNhQ1FDYUNhQQFDYUNhQ1FQANBQAAAAA=",
            "chanel up": "JgAYAZSTEzcTNhM3ExIUERMRFBETEhQ2FDUUNhQRExITERUQFBETEhQ2FBEUEBQ2ExIUERQRFDUTEhQ2FDUUERQ2FDUUNhQABgOUkxQ2EzcUNRMSExIUERQRFBAUNhQ2FDUUERQRFBEUERQRFBAUNhQRExIUNRQRFBETEhM2FRAVNRM3FBETNhQ2FDUVAAYClZIVNRQ2FDUVEBQRFBEUERMSFDUUNhQ2FBAVEBMSFBEUERQRFDUUERQRFDYTERUQFBEUNhMSFDUUNhMSFDUUNhM3FAAGApWTFDUUNhM3FBAUERQRFBETEhQ1FTUUNhQRExEVEBQRFBETEhQ1FRAUERQ2FBETERQREzcUERQ1FDYUERQ1FDYUNhQADQUAAAAAAAAAAAAAAAAAAA==",
            "turn off": "JgBGAJGVEzcTNhQ2ERQTEhMSExEUERM3EzcTNhMSExITEhEUExEUERM3ExITEhMREhMTEhMSEzYUERQ2ETkTNhQ2EjgTNhQADQU=",
            "turn on": "JgCMAJWTEzYTNhQ2FBETEhMSExEUERQ2EzYUNhQRFBETEhMSExEUERQ2ExITEhMRFBEUERQREzYUERQ2FDYTNhQ2FDYTNhQABgOVkhQ2FDYTNhQRFBEUERMSExITNhQ2EzYUERQRFBEUERMSExITNhQRFBETEhMSExEUERQ2ExITNhQ2FDYTNhQ2FDYTAA0FAAAAAAAAAAAAAA==",
            "volume down": "JgDSAJSTEzYTNxM3ExIRExMSExITEhM3ETgSOBMSExITERQRExITNxM2ExITNxEUExISEhMSExITEhM3ERMTNxM3EzYSOBEABgSWkxE5ETgTNxEUExITEhISEhMTNxM2EzcTEhMSExIRExMSEzcTNhITEzcRFBMSExIRExMSExITNxEUEjcTNxE4EzcTAAYDlZMTNxM2EzcTEhMSExITERQREzcTNxI3ExITEhMSExITERQ2EzcTEhM2ExITEhMSExETEhMSEzcTEhM2EzcTNxM2EwANBQAAAAA=",
            "volume up": "JgDSAJKVETgSOBE5ERQRExITEhMRFBE5ETgSOBEUERQRExITEhMRORE4EjgRFBEUERQRExITEhMRFBEUETgSOBE5ETgSOBIABgSVkxQ2EzYUNhMSExITERQRFBEUNhM2FDYUERMSExITERQRFDYTNhQ2FBETEhMSExITERQRFBETEhM2FDYUNhM2FDYUAAYClJQTNxM2FDYTEhITEhMSEhMSEzcSNxM3ExISExEUEhISExM3EjgROBITERQRFBEUERMSExITEhMROBI4EjgROBI4EQANBQAAAAA="
        }
    },
    "key": "broadlink_remote_24aca7a1dce2_codes",
    "version": 1
}

Ensuite on va créer un switch qui pourra d'ailleurs en contenir plusieurs... Et avec lesquels ont pourra interagir depuis des automation, scripts ou l'interface Lovelace...

- platform: broadlink
  host: 192.168.210.132
  mac: '24:AF:A2:30:0D:E2'
  type: rm4c_mini  # Toujours aussi important !
  timeout: 15
  switches:
    tv_on:
      friendly_name: "TV Power"
      command_on: 'JgCMAJWTEzYTNhQ2FBETEhMSExEUERQ2EzYUNhQRFBETEhMSExEUERQ2ExITEhMRFBEUERQREzYUERQ2FDYTNhQ2FDYTNhQABgOVkhQ2FDYTNhQRFBEUERMSExITNhQ2EzYUERQRFBEUERMSExITNhQRFBETEhMSExEUERQ2ExITNhQ2FDYTNhQ2FDYTAA0FAAAAAAAAAAAAAA=='
      command_off: 'JgDSAJKUFDYSOBI3ExITEhITEhMSExI2FDcSNxMSExITEhITEhMSExI3ExISExITEhITEhMSEjgSExI3EzcSOBI3EzcSNxMABgOVkxQ2EzcSOBMRFBETEhITExITNhQ2EjcUERQRFBETEhITExITNhMSExITEhMSExEUERM3ExISNxQ2EzcTNhQ2EzcTAAYClZQTNhQ2EzcTERQRFBETEhMSEzYUNhM3EhMSEhMSFBETEhITEjcTEhMSEhMSExITEhITNxITEjgSNxM3EjcTNxM3EgANBQAAAAA='

Ça c'était la version manuelle, c’est pratique car ça permet d'associer n’importe quel appareil piloté par une télécommande IR. Par contre c'est fastidieux et j'ai passé mon après-midi à me dire qu'il était impossible que quelqu'un n'ai pas fait mieux, à savoir une intégration ou je n'aurais qu'à choisir la référence de mon climatiseur pour le commander avec une carte Climate. Et ça existe !

SmarIR

SmartIR s'appuie sur le Broadlink, ou d'autres interfaces IR, qu'il s'agisse de Xiaomi, d'un ESP DIY ou d'un objet en MQTT. Pour le configurer il nous faut avoir intégré notre interface à HA, ici le Broadlink, et installer le composant depuis HACS.

Pour activer cette intégration on ajoute une entrée dans configuration.yaml :

smartir:

Une entrée dans switch.yaml :

- platform: broadlink
  host: 192.168.210.132
  mac: '24:AF:A2:30:0D:E2'
  type: rm4c_mini  # Toujours aussi important !

Et enfin une dernière dans climate.yaml ou l'on n'oubliera pas de reporter le bon code IR : 

- platform: smartir
  name: Office AC
  unique_id: office_ac
  device_code: 1260  # Ici le code IR pour les climatiseurs Toshiba
  controller_data: 192.168.210.132
  temperature_sensor: sensor.temperature  # Ici on peut associer un capteur de température externe
  humidity_sensor: sensor.humidity  # Ici on peut associer un capteur d'hygrométrie externe
  power_sensor: binary_sensor.ac_power

Un petit redémarrage et on est prêt à piloter notre climatiseur comme on le ferait pour n'importe quel thermostat, sauf qu'ici on dispose de toutes les commandes utiles (mixte, chauffage, refroidissement, de-humidification, ventilation) propre au modèle choisit (on ne voit pas

Mon projet portait sur la climatisation, mais avec SmartIR il est également possible de piloter des ventilateurs ou du matériel Audio / Vidéo, pourquoi pas votre magnétoscope VHS ! Et ce qui ne sera pas possible avec SmartIR le sera en mode manuel.

EDIT HA 0.115 : Broadlink est maintenant intégré à HA, donc on vire ce qui est dans configuration.yaml et switch.yaml et on adapte l'utilisation avec le device ID que l'on trouvera dans l'intégration, ici remote.ir_clim_remote :

- platform: smartir
  name: AC Sejour
  unique_id: ac_sejour
  device_code: 1260
  controller_data: remote.ir_clim_remote
  temperature_sensor: sensor.mi_t_carre
  humidity_sensor: sensor.mi_h_carre
  power_sensor: binary_sensor.ac_power

Sources