Modbus Read Byte and bit register from inverter

Hi, be patient I’m a newbie
Already I read the registers of my inverter successfully. But there are registers concerning fault that I’ not capable to read.
This is sensor that read Fault1:

      - name: "Modbus ZCS Inverter Fault 1"
        slave: 1
        address: 0x0405
        input_type: holding
        data_type: uint16
        scan_interval: 60
        lazy_error_count: 3

This is a fault table of my modbus register

I tried to write this code in modbus.yaml without success

binary_sensor:
  - platform: template
    sensors:
      grid_ovp:
        friendly_name: GridOVP
        value_template: {{ states('sensor.Modbus_ZCS_Inverter_Fault_1') | int |
          bitwise_and(0) > }}
      grid_uvp:
        friendly_name: GridUVP
        value_template: {{ states('sensor.Modbus_ZCS_Inverter_Fault_1') | int |
          bitwise_and(1) > }}

I don’t know if it’s correct also because the configuration check is in error

Error loading /config/configuration.yaml: invalid key: "{"states('sensor.modbus_zcs_inverter_fault_1') | int | bitwise_and(0) >": None}"
  in "/config/packages/modbus.yaml", line 848, column 0

please, can anyone help me to write the correct code?

I suggest you experiment a bit with

“{{ states(‘sensor.Modbus_ZCS_Inverter_Fault_1’) | int | bitwise_and(1) }}”

in the template editor under developer tools until you have what you need, which i did, and i ended up with something like this:

template:
  - binary_sensor:
     - name: grid_ovp:
       friendly_name: GridOVP
       state: >
         {% if(( states('sensor.Modbus_ZCS_Inverter_Fault_1')  | int | bitwise_and(0)) == 1) %}
           true
         {% else %}
           false
         {% endif %}
     - name: grid_ovp:
       friendly_name: GridUVP
       state: >
         {% if(( states('sensor.Modbus_ZCS_Inverter_Fault_1')  | int | bitwise_and(1)) == 1) %}
           true
         {% else %}
           false
         {% endif %}

It seems to work but since it doesn’t always, fortunately, there are errors at the moment I get this in the template editor:

template:
  - binary_sensor:
     - name: grid_ovp:
       friendly_name: GridOVP
       state: >
         
           false
         
     - name: grid_ovp:
       friendly_name: GridUVP
       state: >
         
           false

So, if I understand correctly, I just continue the same code for each bit, like this for example: add bit 2

template:
  - binary_sensor:
     - name: grid_ovp:
       friendly_name: GridOVP
       state: >
         {% if(( states('sensor.Modbus_ZCS_Inverter_Fault_1')  | int | bitwise_and(0)) == 1) %}
           true
         {% else %}
           false
         {% endif %}
     - name: grid_uvp:
       friendly_name: GridUVP
       state: >
         {% if(( states('sensor.Modbus_ZCS_Inverter_Fault_1')  | int | bitwise_and(1)) == 1) %}
           true
         {% else %}
           false
         {% endif %}
     - name: grid_ofp
       friendly_name: GridOFP
       state: >
         {% if((states('sensor.Modbus_ZCS_Inverter_Fault_1') | int | bitwise_and(2)) ==1) %} # bit 2
         true
         {% else %}
           false
         {% endif %}

It’s correct?
Can I write event code in place of true? Example ID001
And for Byte 1?

Oh, you are supposed to use everything behind the > sign in the template editor:

{% if( states('sensor.Modbus_ZCS_Inverter_Fault_1')  | int | bitwise_and(1))  %}
           true
         {% else %}
           false
         {% endif %}

Btw, looks like they don’t start at bit 0 but bit 1…
so bit 3 is “4”
and you can also ommit == 1

     - name: grid_ofp
       friendly_name: GridUFP
       state: >
         {% if(states('sensor.Modbus_ZCS_Inverter_Fault_1') | int | bitwise_and(4)) %} # bit 3
           true
         {% else %}
           false
         {% endif %}

Also found an example of someone adding attributes to the original sensor

- sensor:
  - name: "Modbus_ZCS_Inverter_all_data"
    state: "{{ states(‘sensor.Modbus_ZCS_Inverter_some_sensor') }}"
    attributes:
      grip_ovp: "{% if states('sensor.Modbus_ZCS_Inverter_Fault_1') | int | bitwise_and(1) %}true{% else %}false{% endif %}"
      grid_uvp: "{% if states('sensor.Modbus_ZCS_Inverter_Fault_1') | int | bitwise_and(2) %}true{% else %}false{% endif %}"
      grid_ofp: "{% if states('sensor.Modbus_ZCS_Inverter_Fault_1') | int | bitwise_and(4) %}true{% else %}false{% endif %}"
      grid_ufp: "{% if states('sensor.Modbus_ZCS_Inverter_Fault_1') | int | bitwise_and(8) %}true{% else %}false{% endif %}"
 
etc

This uses some ‘other sensor’ from your ZCS inverter, copies its state and adds the faults as attributes, so everything stays neatly in one sensor :grin:
(note that it might be a bit easier to use a sensor instead of a binary_sensor, it is a bit more flexible :thinking:)

It seems in the template editor works fine. I’ve created a zcs_fault.yaml in packages and paste the code in:

- sensor:
    - name: zcs_faults
      state: "{{ states('sensor.ZCS_Inverter_faults') }}"
      attributes:
        grip_ovp: "{% if states('sensor.ZCS_Fault_1') | int | bitwise_and(1) %}true{%
          else %}false{% endif %}"
        grid_uvp: "{% if states('sensor.ZCS_Fault_1') | int | bitwise_and(2) %}true{%
          else %}false{% endif %}"
        grid_ofp: "{% if states('sensor.ZCS_Fault_1') | int | bitwise_and(4) %}true{%
          else %}false{% endif %}"
        grid_ufp: "{% if states('sensor.ZCS_Fault_1') | int | bitwise_and(8) %}true{%
          else %}false{% endif %}"
        island_fault: "{% if states('sensor.ZCS_Fault_1') | int | bitwise_and(128) %}true{%
          else %}false{% endif %}"

in check configuration get: expected a dictionary for dictionary value @ data[‘packages’][‘zcs_fault’]
Where am I wrong?

Also, in this way I read the first 4 bits of byte 0 of the table above. If I wanted to read the bits of byte 1 of the table what should I change in the code?

Please be patient, I’m no expert and would also like to understand what the code says.

Can you post the config for the modbus sensor(s)?

sensor:
  - platform: template
    sensors:
      zcs_modalita_operativa_inverter:
        friendly_name: "Modalità operativa inverter"
        value_template: >-
          {% set mapper =  {
              '0' : 'In attesa',
              '1' : 'Controllo Rete',
              '2' : 'Collegato',
              '3' : 'Grid UFP',
              '4' : 'Emergency Power Supply EPS',
              '5' : 'Errore risolvibile',
              '6' : 'Errore permanente',
              '7' : 'Autocaricamento' } %}
          {% set state =  states.sensor.modbus_zcs_inverter_stato_operativo.state %}
          {{ mapper[state] if state in mapper else 'Sconosciuto' }}
       


         
      prelievo_istantaneo_corrente_modbus:
        friendly_name: Prelievo istantaneo modbus
        device_class: power
        value_template: >
            {% set linea = states('sensor.modbus_inverter_rete_immisione_prelievo')|int(0) %}
            {% if linea < 0 %}
                {{ 0 - linea }}
            {% else %} {{ 0 | int }}
            {% endif %}
        unit_of_measurement: "W"
        
        
      immissione_istantanea_corrente_modbus:
        friendly_name: Immissione istantanea modbus
        device_class: power
        value_template: >
            {% set linea = states('sensor.modbus_inverter_rete_immisione_prelievo')|int(0) %}
            {% if linea >= 0 %}
                {{ linea }}
            {% else %} {{ 0 | int }}
            {% endif %}
        unit_of_measurement: "W"
        


#####convertitore
modbus:
  - name: hub2
    type: tcp
    host: xxx.xxx.xxx.xxx
    port: 502

        
    sensors:
      - name: "Inverter Serial Number"
        slave: 1
        address: 0x0445
        count: 7
        data_type: string
        input_type: holding

      - name: "Hardware version"
        slave: 1
        address: 0x044D
        count: 2
        input_type: holding
        data_type: string

      - name: "Software version"
        slave: 1
        address: 0x044F
        count: 4
        input_type: holding
        data_type: string

      - name: "Modbus ZCS Inverter Stato Operativo"
        slave: 1
        address: 0x0404
        input_type: holding
        data_type: uint16                      ####corretto uint####
        scan_interval: 60
        lazy_error_count: 3
        
      - name: "ZCS Fault 1"
        slave: 1
        address: 0x0405
        input_type: holding
        data_type: uint16
        scan_interval: 60
        lazy_error_count: 3
        
      - name: "ZCS Fault 2"
        slave: 1
        address: 0x0406
        input_type: holding
        data_type: uint16
        scan_interval: 60
        lazy_error_count: 3
        
      - name: "ZCS Fault 3"
        slave: 1
        address: 0x0407
        input_type: holding
        data_type: uint16
        scan_interval: 60
        lazy_error_count: 3
        
      - name: "ZCS Fault 4"
        slave: 1
        address: 0x0408
        input_type: holding
        data_type: uint16
        scan_interval: 60
        lazy_error_count: 3
        
      - name: "ZCS Fault 5"
        slave: 1
        address: 0x0409
        input_type: holding
        data_type: uint16
        scan_interval: 60
        lazy_error_count: 3
        
      - name: "ZCS Fault 6"
        slave: 1
        address: 0x040A
        input_type: holding
        data_type: uint16
        scan_interval: 60
        lazy_error_count: 3
        
      - name: "ZCS Fault 7"
        slave: 1
        address: 0x040B
        input_type: holding
        data_type: uint16
        scan_interval: 60
        lazy_error_count: 3
        
      - name: "ZCS Fault 8"
        slave: 1
        address: 0x040C
        input_type: holding
        data_type: uint16
        scan_interval: 60
        lazy_error_count: 3
        
      - name: "ZCS Fault 9"
        slave: 1
        address: 0x040D
        input_type: holding
        data_type: uint16
        scan_interval: 60
        lazy_error_count: 3

      - name: "ZCS Fault 10"
        slave: 1
        address: 0x040E
        input_type: holding
        data_type: uint16
        scan_interval: 60
        lazy_error_count: 3
        
      - name: "ZCS Fault 11"
        slave: 1
        address: 0x040F
        input_type: holding
        data_type: uint16
        scan_interval: 60
        lazy_error_count: 3
        
      - name: "ZCS Fault 12"
        slave: 1
        address: 0x0410
        input_type: holding
        data_type: uint16
        scan_interval: 60
        lazy_error_count: 3
        
      - name: "ZCS Fault 13"
        slave: 1
        address: 0x0411
        input_type: holding
        data_type: uint16
        scan_interval: 60
        lazy_error_count: 3
        
      - name: "ZCS Fault 14"
        slave: 1
        address: 0x0412
        input_type: holding
        data_type: uint16
        scan_interval: 60
        lazy_error_count: 3
        
      - name: "ZCS Fault 15"
        slave: 1
        address: 0x0413
        input_type: holding
        data_type: uint16
        scan_interval: 60
        lazy_error_count: 3
        
      - name: "ZCS Fault 16"
        slave: 1
        address: 0x0414
        input_type: holding
        data_type: uint16
        scan_interval: 60
        lazy_error_count: 3
        
      - name: "ZCS Fault 17"
        slave: 1
        address: 0x0415
        input_type: holding
        data_type: uint16
        scan_interval: 60
        lazy_error_count: 3
        
      - name: "ZCS Fault 18"
        slave: 1
        address: 0x0418
        input_type: holding
        data_type: uint16
        scan_interval: 60
        lazy_error_count: 3
                
      - name: "Modbus ZCS Temperatura Inverter"
        slave: 1
        address: 0x0418
        input_type: holding
        data_type: int16
        unit_of_measurement: "°C"
        device_class: temperature
        scale: 1
        precision: 0
        scan_interval: 60
        lazy_error_count: 3
        unique_id: "temperatura inverter"
        
#aggiunti 020623#        
      - name: "Modbus ZCS Temperatura Radiatore"
        slave: 1
        address: 0x041A
        input_type: holding
        data_type: int16
        unit_of_measurement: "°C"
        device_class: temperature
        scale: 1
        precision: 0
        scan_interval: 60
        lazy_error_count: 3
        unique_id: "temperatura radiatore"
etc

The is no (modbus) sensor.ZCS_Inverter_fault, hence you can not add atrributes to it either…

You could use sensor.modbus_ZCS_Temperatura_Inverter, so the attributes will be added to that sensor

Not sure how to read 2nd byte; it has something to do with the ‘int’ part in the {%—%} part

Sorry, do you mean zcs_fault.yaml, this is

#- sensor:
#    - name: zcs_faults
#     state: "{{ states('sensor.ZCS_Inverter_faults') }}"
#     attributes:
#       grip_ovp: "{% if states('sensor.ZCS_Fault_1') | int | bitwise_and(1) %}true{%
#          else %}false{% endif %}"
#        grid_uvp: "{% if states('sensor.ZCS_Fault_1') | int | bitwise_and(2) %}true{%
#          else %}false{% endif %}"
#        grid_ofp: "{% if states('sensor.ZCS_Fault_1') | int | bitwise_and(4) %}true{%
#          else %}false{% endif %}"
#        grid_ufp: "{% if states('sensor.ZCS_Fault_1') | int | bitwise_and(8) %}true{%
#          else %}false{% endif %}"
#        island_fault: "{% if states('sensor.ZCS_Fault_1') | int | bitwise_and(128) %}true{%
#          else %}false{% endif %}"

#        tempFault_Bat: "{% if states('sensor.ZCS_Fault_4') | int | bitwise_and(1)
#          %}Protezione Temp Batteria{% else %}false{% endif %}"
#        tempFault_Rad: "{% if states('sensor.ZCS_Fault_4') | int | bitwise_and(2)
#          %}Protezione Temp Radiatore{% else %}false{% endif %}"

You are trying to add attributes to sensor.ZCS_Inverter_faults.
However, there it is not created in the modbus sensors…
You need to add it to an existing sensor…
so try this:

- sensor:
    - name: zcs_inverter
      state: "{{ states('sensor.modbus_ZCS_Temperatura_Inverter') }}"
      attributes:
        grip_ovp: "{% if states('sensor.ZCS_Fault_1') | int | bitwise_and(1) %}true{%
          else %}false{% endif %}"

this will create a new sensor.zcs_inverter, which will have the (copied) status from sensor.modbus_ZCS_Temperatura_Inverter and faults as attributes from sensor.ZCS_Fault_1

1 Like

Ok I added attributes to an existing sensor in the modbus sensors

- sensor:
    - name: zcs_faults
      state: "{{ states('sensor.Modbus_ZCS_Voltaggio_Rete') }}"
      attributes:
        grip_ovp: "{% if states('sensor.ZCS_Fault_1') | int | bitwise_and(1) %}true{%
          else %}false{% endif %}"
        grid_uvp: "{% if states('sensor.ZCS_Fault_1') | int | bitwise_and(2) %}true{%
          else %}false{% endif %}"
        grid_ofp: "{% if states('sensor.ZCS_Fault_1') | int | bitwise_and(4) %}true{%
          else %}false{% endif %}"
        grid_ufp: "{% if states('sensor.ZCS_Fault_1') | int | bitwise_and(8) %}true{%
          else %}false{% endif %}"
        island_fault: "{% if states('sensor.ZCS_Fault_1') | int | bitwise_and(128) %}true{%
          else %}false{% endif %}"

and I get new sensor zcs_fault with state of the existing sensor plus new attributes
Screenshot

But when I check configuration I get “expected a dictionary for dictionary value @ data[‘packages’][‘zcs_fault’]

I have a feeling it has to do with the zcs_fault.yaml file in packages folder but i don’t understand how. Do you have an idea?
Sorry, I forgot “template:”