Modbus - bits de mots et correspondance état/valeur d'un registre

Bonjour a tous.

Je viens du monde de l’automatisme industriel, la domotique et l’informatique sont des domaines a la fois proches et loin de mon champ de compétences et de connaissances.

J’essaie de l’auto former a Home Assistant par curiosité, pour voir les différences avec WinCC, Vidéo Designer, voire PCVue que je pratique bien plus facilement.

Pour débuter je me suis crée un petit programme de feu rouge dans un automate, que j’interroge en modbus TCP. Plus simple pour commencer c’est pas facile :slight_smile:

J’ai modifié le fichier config.yaml pour y déclarer mon automate et lire quelques variables.
Jusque là, ça va.

C’est après que ça se gâte.

Déjà j’aimerais pouvoir afficher ‹ Rouge › ‹ Vert › ‹ Orange › au lieu de 10/11/12 qui sont les etapes de mes grafcets.

Ensuite j’aimerais pouvoir ‹ grouper › des booléens dans %mw et récupérer plusieurs Sensors dans un seul registre.

Mais pour ces deux points je ne sais même pas ‹ ou creuser › dans la Doc, et j’ai aucune idée de comment m’y prendre.

Merci.

Bonjour,

Je vais essayer de vous aider, mais je n’ai pas de connaissance en automatisme, ni le vocabulaire.
J’utilise jute le modbus pour ma chaudière et les compteurs d’énergies (en plus en python et minimodbus et non directement avec l’intégration modbus de HA), donc désolé par avance si je suis à coté.

Pour cela vous pouvez utiliser un template, qui repend votre sensor modbus et en fonction de la valeur prendra la valeur souhaitée, un peu comme ceci.

template:
  sensor:
      - name: "mon_template"
        unique_id: "mon_template_001"
        state: >
            {% if is_state (mon_entité_modbus', '10')%}
                 "rouge"
            {% elif is_state ('mon_entité_modbus', '11')%}
                  "vert"
            {% elif is_state ('mon_entité_modbus', '12')%}
                  "orange"
            {% else %}
                  "erreur"
            {% endif %}

l’aide pour les templates est ici:

Ensuite:

%mw, c’est plusieurs registre, c’est cela ?

Si vous voulez avoir plusieurs sensors depuis un registre multiple, je tenterai quelque chose comme cela:

un premier sensor qui récupère tout:

sensor:
- platform: modbus
  registers:
    - name: mon_capteur_de_depart
      hub: modbus1
      slave: 8
      register: 1
      register_type: input
      count: xx
      data_type: custom
      structure: ">xxh"

avec pour « count: » le nombre de registre à lire (merci de me corriger si cela n’est pas le bon terme) et aussi pour « structure: » (exemple si 5 alors tructure: « >5h »

La sortie de ce sensor sera avec une virgule entre chaque: 10,50,600,etc…

Une fois cela, je ferai un sensor pour chaque élément de mon sensor de départ, en utilisant celui-ci comme un tableau de valeur [xxx,xxxx,xxxx,xxx]

- platform: template
  sensors:
    titi:
        friendly_name: "titi"
        value_template: "{{ states('sensor.mon_capteur_de_depart').split(',')[0] }}"
    toto:
        friendly_name: "toto"
        value_template: "{{ states('sensor.mon_capteur_de_depart').split(',')[1] }}"
    tata:
        friendly_name: "tata"
        value_template: "{{ states('sensor.mon_capteur_de_depart').split(',')[2] }}"

Voila, ce n’est qu’une idée, à adapter je pense

1 « J'aime »

Si je comprend bien, tu veux regrouper plusieurs entrées logiques du PLC dans un seul registre pour ne faire qu’une lecture ?
Ne peux tu pas faire ce regroupement sur le PLC ?

Trouvé mais pas encore lu :

Si je me souviens bien %MW est un registre 16 bits.

Merci pour le tuyau sur les templates ! C’est exactement ce dont j’ai besoin pour mon premier problème.
J’ai laissé l’automate sur mon bureau au boulot, mais je pense que le premier ‹ script › que vous m’avez donné doit fonctionner ou presque. Au pire si il marche pas (ça m’étonnerais) maintenant que je sait ou fouiller.

Pour l’histoire de ‹ grouper › des bits, je me suis sans doute pas bien expliqué.
Un registre Modbus, vu coté automate c’est un entier 16 bits (la plupart du temps non signé, mais ça dépends).
Les cartes d’entrées et de sorties automate offrent la plupart du temps un nombre de voies multiple de 16.
Et de manière générale coté automate tout est plus ou moins fait pour que ça soit pratique de travailler par paquets de 16 bits a la fois. (Ça devient de moins en moins vrai avec les automates ‹ modernes ›, mais le poids des conventions historiques reste très très fort dans le domaine)

Bref, en récupérant des registres modbus (en int16 pour home assistant) je récupère donc 16 informations binaires d’un coup.
Le bit 15 va correspondre au bit de signe, le bit 0 a la parité du nombre lu, etc
Avec les template et des masques je pense qu’il y’a un truc a faire du coup.

Je vais creuser.

Templating - Home Assistant donne :

Tests_logiques

1 « J'aime »

@miga_nuts bonsoir, je serais curieux de voir comment tu t’y prends sous HA pour lire / décrypter les registres reçus via modbus/tcpip. Ce serait sympa de partager ta manière de faire. Ca me permettra d’apprendre comment s’y prendre sous HA

De mon coté je fais cela via Nodered qui s’intègre d’une manière élégante à HA. Voici juste pour info comment cela se passe.
le nœud de décryption:


le nœud de lecture du port physique:
buffer-parser4

Merci a vous !

Voila ce que j’ai reussi a obtenir grace a votre aide :

Et voici le bout de ‹ script › que j’ai utilisé pour ce résultat


#test M221
modbus :
- name: "M221"
  type: tcp
  host: 192.168.1.107
  port: 502
  sensors:
    - name: G7_feu_1
      address: 0
      input_type: holding
      state_class: measurement
      data_type: int16
      scan_interval: 1
    - name: G7_feu_2
      address: 1
      input_type: holding
      state_class: measurement
      data_type: int16
      scan_interval: 1
    - name: Bitfield_1
      address: 2
      input_type: holding
      state_class: measurement
      data_type: uint16
      scan_interval: 1
template:
  sensor:
    - name: "Couleur_Feu1"
      state: >
          {% if is_state ('sensor.G7_feu_1', '10')%}
                "rouge"
          {% elif is_state ('sensor.G7_feu_1', '11')%}
                "vert"
          {% elif is_state ('sensor.G7_feu_1', '12')%}
                "orange"
          {% else %}
                "erreur"
          {% endif %}
    - name: "Couleur_Feu2"
      state: >
          {% if is_state ('sensor.G7_feu_2', '10')%}
                "rouge"
          {% elif is_state ('sensor.G7_feu_2', '11')%}
                "vert"
          {% elif is_state ('sensor.G7_feu_2', '12')%}
                "orange"
          {% else %}
                "erreur"
          {% endif %}
  binary_sensor:
    - name: "Bitfield_1_X00"
      state: >
         {% if states ('sensor.Bitfield_1') | int | bitwise_and(1)%}
                true
         {% else %}
                false
         {% endif %}
    - name: "Bitfield_1_X01"
      state: >
         {% if states ('sensor.Bitfield_1') | int | bitwise_and(2)%}
                true
         {% else %}
                false
         {% endif %}
    - name: "Bitfield_1_X02"
      state: >
         {% if states ('sensor.Bitfield_1') | int | bitwise_and(4)%}
                true
         {% else %}
                false
         {% endif %}
    - name: "Bitfield_1_X03"
      state: >
         {% if states ('sensor.Bitfield_1') | int | bitwise_and(8)%}
                true
         {% else %}
                false
         {% endif %}
    - name: "Bitfield_1_X04"
      state: >
         {% if states ('sensor.Bitfield_1') | int | bitwise_and(16)%}
                true
         {% else %}
                false
         {% endif %}
    - name: "Bitfield_1_X05"
      state: >
         {% if states ('sensor.Bitfield_1') | int | bitwise_and(32)%}
                true
         {% else %}
                false
         {% endif %}
    - name: "Bitfield_1_X14"
      state: >
         {% if states ('sensor.Bitfield_1') | int | bitwise_and(16384)%}
                true
         {% else %}
                false
         {% endif %}
    - name: "Bitfield_1_X15"
      state: >
         {% if states ('sensor.Bitfield_1') | int | bitwise_and(32768)%}
                true
         {% else %}
                false
         {% endif %}
         

Il me reste encore du boulot pour mettre ça en forme plus joliement, mais fonctionnellement ça fait le taff. C’est nickel.
Merci encore.

2 « J'aime »

Parfait.

Pour la 2ieme partie, le ET bit à bit était je pense l’unique solution.

Juste pour fixer ma compréhension de la syntaxe Jinja2, peux tu essayer :

- name: "Bitfield_1_X15"
  state: >
     {% states ('sensor.Bitfield_1') | int | bitwise_and(32768) %}

Merci.

Si j’enlève les « if » je me retrouve avec des insultes dans les logs :

 Logger: homeassistant.config
Source: config.py:864
First occurred: 17:22:35 (1 occurrences)
Last logged: 17:22:35
Invalid config for [template]: invalid template (TemplateSyntaxError: Encountered unknown tag 'states'.) for dictionary value @ data['binary_sensor'][0]['state']. Got "{% states ('sensor.Bitfield_1') | int | bitwise_and(1)%}\n". (See /config/configuration.yaml, line 47). 

dommage, je trouvait ça plus « joli » en version courte.

Le code ci-dessous devrait fonctionner :

Sans les % home assistant démarre sans rien écrire dans le log, échange des requêtes avec l’automate, par contre ma variable reste toujours a <désactivé> quelle que soit sa valeur dans l’automate :smiley:
C’est pas très grave, la version ‹ verbeuse › du code fonctionne très bien et est a peu près explicite a la relecture.