Utilisation de switch REST pour piloter un IPX800

Hello,
J’ai commencé il y a peu de temps aussi sur HA, et j’essaie de visualiser/piloter mon ipx800.

Mon retour d’expérience avec HA et IPX800 v3

Ce qui me semblait le plus intéressant, c’était d’utiliser le push de l’ipx évitant de scanner l’ipx selon un intervale régulier… mais l’utilisation de l’API HA n’est pas trop jouable avec une clé API sur l’ipx800 v3, en plus, avec l’utilisation de let’s encrypt, il faut un accès internet pour accéder à une machine local… je trouve cela un peu « bizarre »…
Nodered
J’ai donc commencé par utiliser Nodered, dont l’avantage est de pouvoir créer facilement un endpoint http et d’utiliser le push de l’IPX lorsque l’une des E/S est modifiée… donnant une très faible empreinte réseau. Je n’ai pas optimisé le flow… ça marche mais il faut jongler entre nodered et les entites créées sur HA.

API JSON
Du coup, je me suis lancé dans la config des fichiers yaml…
Je suis parti au départ sur l’utilisation de plusieurs sensor rest pour récupérer l’état des différentes E/S en passant par l’API retournant du json…
Car le problème de l’API json de l’IPX c’est d’utiliser une requête différente pour les entrées, les sorties, les compteurs… et les appels depuis HA sont fait à la suite vers l’IPX, et celui-ci n’a pas le temps de répondre à toutes les requêtes…; en jouant sur le paramètre scan_interval, cela évite dans la majorité des cas que les commandes ne soient pas lancé en même temps…et l’idéal, ce serait de pouvoir faire un délai entre les requêtes… mais bon, ça marche…
Voici un exemple de configuration:

#/config/sensors.yaml

# Récup état Entrées numeriques
- platform: rest
  resource: 'http://ipx800.local/api/xdevices.json?cmd=10'
  name: 'IPX800 entrees num'
  value_template: '{{ value_json["product"] }}'
  scan_interval: 30
  json_attributes:
    - IN1
    - IN2
    - IN3
    - IN4
    - IN5
    - IN6
    - IN7
    - IN8
    
    
# Récup état Sorties numeriques
- platform: rest
  resource: 'http://ipx800.local/api/xdevices.json?cmd=20'
  #resource: 'http://{{ IP_ipx800 }}/api/xdevices.json?cmd=20'
  name: 'IPX800 sorties num'
  value_template: '{{ value_json["product"] }}'
  scan_interval: 29
  json_attributes:
    - OUT1
    - OUT2
    - OUT3
    - OUT4
    - OUT5
    - OUT6
    - OUT7

API XML
Au final, pour éviter cela, il est possible de passer par l’API IPX800 XML, qui renvoie tous les états en 1 seul fois.
(bon, par contre attention a ne pas se faire avoir: la sortie 1, c’est out1 en json et led0 en xml… pas mieux pour les états en XML, 0,1 pour les sorties, up et dn pour les entrées…

#/config/sensors/sensor_ipx800.yaml

platform: rest
name: IPX800 global status
resource: 'http://ipx800.local/globalstatus.xml'
json_attributes_path: $.response
scan_interval: 15
value_template: OK
json_attributes:
    - led0
    - led1
    - led2
    - led3
    - led4
    - led5
    - led6
    - led7
    - count0
    - count1
    - btn0
    - btn1
    - btn2
    - btn3
    - btn4
    - btn5
    - btn6
    - btn7
    - analog0
    - analog1

L’état des différentes entrées (ou sorties, cpt…) se fait donc un seul sensor principal rest

Il suffit ensuite de créer des binary-sensors pour l’état des E/S,

#/config/binary_sensors/binary_sensor_ipx800.yaml

platform: template
sensors:
  ipx800_e1:
    friendly_name: IPX800 E1
    value_template: '{{ is_state_attr("sensor.ipx800_global_status", "btn0","dn") }}'
  ipx800_e2:
    friendly_name: IPX800 E2
    value_template: '{{ is_state_attr("sensor.ipx800_global_status", "btn1","dn") }}'  
  ipx800_e3:
    friendly_name: IPX800 E3
    value_template: '{{ is_state_attr("sensor.ipx800_global_status", "btn2","dn") }}'
  ipx800_e4:
    friendly_name: IPX800 E4
    value_template: '{{ is_state_attr("sensor.ipx800_global_status", "btn3","dn") }}'
  ipx800_e5:
    friendly_name: IPX800 E5
    value_template: '{{ is_state_attr("sensor.ipx800_global_status", "btn4","dn") }}'
  ipx800_e6:
    friendly_name: IPX800 E6
    value_template: '{{ is_state_attr("sensor.ipx800_global_status", "btn5","dn") }}'
  ipx800_e7:
    friendly_name: IPX800 E7
    value_template: '{{ is_state_attr("sensor.ipx800_global_status", "btn6","dn") }}'
  ipx800_e8:
    friendly_name: IPX800 E8
    value_template: '{{ is_state_attr("sensor.ipx800_global_status", "btn7","dn") }}'
  ipx800_s1:
    friendly_name: IPX800 S1
    value_template: '{{ state_attr("sensor.ipx800_global_status", "led0") }}'
  ipx800_s2:
    friendly_name: IPX800 S2
    value_template: '{{ state_attr("sensor.ipx800_global_status", "led1") }}'
  ipx800_s3:
    friendly_name: IPX800 S3
    value_template: '{{ state_attr("sensor.ipx800_global_status", "led2") }}'
  ipx800_s4:
    friendly_name: IPX800 S4
    value_template: '{{ state_attr("sensor.ipx800_global_status", "led3") }}'
  ipx800_s5:
    friendly_name: IPX800 S5
    value_template: '{{ state_attr("sensor.ipx800_global_status", "led4") }}'
  ipx800_s6:
    friendly_name: IPX800 S6
    value_template: '{{ state_attr("sensor.ipx800_global_status", "led5") }}'
  ipx800_s7:
    friendly_name: IPX800 S7
    value_template: '{{ state_attr("sensor.ipx800_global_status", "led6") }}'
  ipx800_s8:
    friendly_name: IPX800 S8
    value_template: '{{ state_attr("sensor.ipx800_global_status", "led7") }}'

et des sensors pour l’état des compteurs et des analogiques qui se rapportent au sensor « principal »

#/config/sensors/sensor_ipx800.yaml

platform: template
sensors:
  #Compteurs
  ipx800_cpt1:
    friendly_name: IPX compteur 1
    value_template: '{{ state_attr("sensor.ipx800_global_status", "count0") }}'
    unit_of_measurement: °F
  ipx800_cpt2:
    friendly_name: IPX compteur 2
    value_template: '{{ state_attr("sensor.ipx800_global_status", "count1") }}'
    unit_of_measurement: minutes
  
  #Analogiques
  ipx800_an1:
    friendly_name: IPX800 ANA_1
    device_class: power
    value_template: '{{ state_attr("sensor.ipx800_global_status", "analog0") }}'
  ipx800_an2:
    friendly_name: IPX800 ANA_2
    device_class: energy
    value_template: '{{ state_attr("sensor.ipx800_global_status", "analog1") }}'

Tout cela permet déjà de remonter tous les états…

La commande
Pour la partie commande des E/S, utilisation de switch template

#/config/switches/switch_ipx800.yaml

platform: template
switches:
  ipx800e1:
    friendly_name: IPX800 E1
    value_template: '{{ is_state_attr("sensor.ipx800_global_status", "btn0","dn") }}'
    turn_on:
      - service: rest_command.switch_ipx800_e
        data:
          led: 100
      - service: homeassistant.update_entity
        data:
          entity_id:
            - sensor.ipx800_global_status
            - binary_sensor.ipx800_e1
    turn_off:
      - service: rest_command.switch_ipx800_e
        data:
          led: 100
      - service: homeassistant.update_entity
        data:
          entity_id:
            - sensor.ipx800_global_status
            - binary_sensor.ipx800_e1

  ipx800s7:
    friendly_name: IPX800 S7
    value_template: '{{ is_state_attr("sensor.ipx800_global_status", "led6","1") }}'
    #value_template: '{{ state_attr("sensor.ipx800_global_status", "led6") | int >=1 }}'
    turn_on:
      - service: rest_command.set_ipx800_s
        data:
          num: set7
          state: 1
      - service: homeassistant.update_entity
        data:
          entity_id:
            - sensor.ipx800_global_status
            - binary_sensor.ipx800_s7
    turn_off:
      - service: rest_command.set_ipx800_s
        data:
          num: set7
          state: 0
      - service: homeassistant.update_entity
        data:
          entity_id:
            - sensor.ipx800_global_status
            - binary_sensor.ipx800_s7

(l’appel au service: homeassistant.update_entity permet de relancer une requête API et d’avoir un retour d’état immédiat)
avec une commande rest qui va avec:

  • Fixe un état pour les sorties (on ne peut pas pour les entrées)
  • Commutation pour les entrées (on peut utiliser aussi pour les sorties si on préfère avoir une seule commande. Avec le retour d’état, ça peut être jouable.
rest_command:
  switch_ipx800_e:
    url: http://ipx800.local/leds.cgi?led={{ led }}

  set_ipx800_s:
    url: http://ipx800.local/preset.htm?{{ num }}={{ state }}

Voici une carte rapide représentant l’état des différentes E/S et des actionneurs…

Changement d’état externe → une toute petite couche de nodered
Enfin dans le cas d’un changement d’un état de l’IPX800, pour éviter d’attendre le scan, si l’on veut un retour d’état rapide, utilisation d’un simple endpoint Nodered qui lorsqu’il recevra une requête, lancera un update du sensor « principal »… (il faudra faire éventuellement un update des différents sensors si besoin)

image

[{"id":"6d000be6.d538a4","type":"http in","z":"753e90f9.ed355","name":"","url":"/ipx800/refresh","method":"get","upload":false,"swaggerDoc":"","x":240,"y":480,"wires":[["16424523.6898bb","2bedb3eb.4b5dec"]]},{"id":"2bedb3eb.4b5dec","type":"http response","z":"753e90f9.ed355","name":"","statusCode":"200","headers":{},"x":660,"y":520,"wires":[]},{"id":"16424523.6898bb","type":"api-call-service","z":"753e90f9.ed355","name":"","server":"8b0f3c25.1116b","version":1,"debugenabled":false,"service_domain":"homeassistant","service":"update_entity","entityId":"sensor.ipx800_global_status","data":"","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":570,"y":460,"wires":[[]]},{"id":"8b0f3c25.1116b","type":"server","name":"Home Assistant","addon":true}]

Le push pourra se faire sur l’ipx soit au niveau général, soit au niveau de l’entrée/sortie concernée

Voilà, il y a surement encore des améliorations à faire, je n’ai que quelques semaines de HA, donc je ne capte pas toute les subtilités encore… mais bon, ça marche pour l’instant à peu près…
La prochaine étape, je verrai peut-être intégration si je trouve un peu de temps…
Avant je vais voir pour commander ma zibase qui est toujours opérationnelle !