Modbus: read coils not as binary

Hi,

I have the following Modbus RTU Relay unit (Protocol Manual of Modbus RTU Relay - Waveshare Wiki) that integrates 8 switches that are controlled using simple WRITE COIL registers (one for each of the 8 switches). This control can be easily implemented in HA using switches. Unfortunately to get the status of a single switch, there are no dedicated READ COIL registers but just a single COIL register (Address: 0x00FF) which exposes (in a byte) all the 8 switch states i.e. bit0 identifies switch 0 state (if set to ‘1’ switch 0 is on, if set to ‘0’ switch 0 is off) and so on.
In HA verify function for switches cannot be used due to the fact that it is possible to define a single value for the “off” state (state_off) and another one for the “on” state (state_on).

Do you have any suggestion on how to implement such verify functionality?
Thanks
Andrea

2 Likes

Hi,
I have the same problem as you. I don’t know how to retrieve relay states from waveshare. Did you find a solution ?
Jean Paul

Hi,
unfortunately I was not getting any answer so I don’t know yet how to get rid of this problem…since modbus implementation relies on pymodbus==1.2.0, we should find a way to customize a new command following this example Custom Message Example — PyModbus 3.0.0.dev3 documentation but I don’t know how to integrate it into HA

Thanks for the informations, I’ll see if I understand anything…
On my side, I found other relays (like Waveshare) which have status returns that HA can display:

They work very well, I have an 8 relay…
Jean Paul

1 Like

Hello
any solution was found for this issue ? (or behaviour) ?

Hi, I’m currently workaround this by implementing a fastapi python program able to use pymodbus as basis and doing the “coil” selection within the read byte based on selected switch. The program is reading exact yaml format of HA, but I added on verify item the new attribute bit in order to identify the bit position like this:

/config/devices/sensors/modbus/waveshare/RELAY.yam

  • name: Switch1
    slave: 1
    address: 0
    write_type: coil
    timeout: 2
    verify:
    address: 255
    input_type: coil
    bit: 0
  • name: Switch2
    slave: 1
    address: 0
    write_type: coil
    timeout: 2
    verify:
    address: 255
    input_type: coil
    bit: 1

I am also stuck with same problem, any updates on this?

any news with this problem?

Hé Guys,

I’m not sure if this is helpful but I have that Waveshare 8 port relay working fine. This is how I get the status of all coils:

modbus:
  - name: hub1
    type: tcp
    host: 192.168.x.x
    port: 502
    binary_sensors:
      - name: my_relay
        address: 0
        input_type: coil
        slave: 1
        slave_count: 7
        unique_id: my_relay

They show up at my dashboard as: my_relay_1 to 7. You could add a device class as well.

This is my config with nodered: with switch verify


Modbus [001].json

So today through templating I created the switches with feedback. There is probably a smarter way to do this. But this works :slight_smile:

modbus:
  - name: Waveshare_relay
    type: tcp
    host: 192.168.x.x
    port: 502
    binary_sensors:
      - name: Relay_sensors
        address: 0
        input_type: coil
        scan_interval: 2
        slave: 1
        slave_count: 7
        unique_id: Relay_sensor
    lights:
      - name: "light_1"
        address: 0
        write_type: coil
        slave: 1
        unique_id: my_relay_1
      - name: "light_2"
        address: 1
        write_type: coil
        slave: 1
      - name: "light_3"
        address: 2
        write_type: coil
        slave: 1
      - name: "light_4"
        address: 3
        write_type: coil
        slave: 1
      - name: "light_5"
        address: 4
        write_type: coil
        slave: 1
      - name: "light_6"
        address: 5
        write_type: coil
        slave: 1
      - name: "light_7"
        address: 6
        write_type: coil
        slave: 1
      - name: "light_8"
        address: 7
        write_type: coil
        slave: 1

switch:
  - platform: template
    switches:
      mb_switch1:
        value_template: "{{ is_state('binary_sensor.relay_sensors', 'on') }}"
        unique_id: mb_switch1
        turn_on:
          service: light.turn_on
          target:
            entity_id: light.light_1
        turn_off:
          service: light.turn_off
          target:
            entity_id: light.light_1
      mb_switch2:
        value_template: "{{ is_state('binary_sensor.relay_sensors_1', 'on') }}"
        unique_id: mb_switch2
        turn_on:
          service: light.turn_on
          target:
            entity_id: light.light_2
        turn_off:
          service: light.turn_off
          target:
            entity_id: light.light_2
      mb_switch3:
        value_template: "{{ is_state('binary_sensor.relay_sensors_2', 'on') }}"
        unique_id: mb_switch3
        turn_on:
          service: light.turn_on
          target:
            entity_id: light.light_3
        turn_off:
          service: light.turn_off
          target:
            entity_id: light.light_3
      mb_switch4:
        value_template: "{{ is_state('binary_sensor.relay_sensors_3', 'on') }}"
        unique_id: mb_switch4
        turn_on:
          service: light.turn_on
          target:
            entity_id: light.light_4
        turn_off:
          service: light.turn_off
          target:
            entity_id: light.light_4
      mb_switch5:
        value_template: "{{ is_state('binary_sensor.relay_sensors_4', 'on') }}"
        unique_id: mb_switch5
        turn_on:
          service: light.turn_on
          target:
            entity_id: light.light_5
        turn_off:
          service: light.turn_off
          target:
            entity_id: light.light_5
      mb_switch6:
        value_template: "{{ is_state('binary_sensor.relay_sensors_5', 'on') }}"
        unique_id: mb_switch6
        turn_on:
          service: light.turn_on
          target:
            entity_id: light.light_6
        turn_off:
          service: light.turn_off
          target:
            entity_id: light.light_6
      mb_switch7:
        value_template: "{{ is_state('binary_sensor.relay_sensors_6', 'on') }}"
        unique_id: mb_switch7
        turn_on:
          service: light.turn_on
          target:
            entity_id: light.light_7
        turn_off:
          service: light.turn_off
          target:
            entity_id: light.light_7
      mb_switch8:
        value_template: "{{ is_state('binary_sensor.relay_sensors_7', 'on') }}"
        unique_id: mb_switch8
        turn_on:
          service: light.turn_on
          target:
            entity_id: light.light_8
        turn_off:
          service: light.turn_off
          target:
            entity_id: light.light_8

You will end up with 8 switches called mb_switch1 to 8. Who will represent the actual state of the ‘switch’.

Below is my version of this implementation. The idea was taken from Kymc0’s implementation, but mine is a bit shorter and is fully synchronous (does not require polling of the status).

The Modbus part:

modbus:
  - name: <your_modbus_converter>
    <your_modbus_converter_config>
    binary_sensors:
      - name: Waveshare relay status
        address: 0x0000
        input_type: coil
        scan_interval: 0
        slave: 0x01
        slave_count: 7
        unique_id: waveshare_relay_sensor
    sensors:
      - name: Waveshare relay current device address
        slave: 0x01
        input_type: holding # 0x03
        address: 0x4000
        data_type: uint16
        scan_interval: 0
      - name: Waveshare relay software version
        slave: 0x01
        input_type: holding # 0x03
        address: 0x8000
        data_type: uint16
        scale: 0.01
        offset: 0
        precision: 2
        scan_interval: 0
    switches:
      - name: Waveshare relay channel 1
        slave: 0x01
        address: 0x0000
        write_type: coil
        command_on: 0xFF00
        command_off: 0x0000
      - name: Waveshare relay channel 2
        slave: 0x01
        address: 0x0001
        write_type: coil
        command_on: 0xFF00
        command_off: 0x0000
      - name: Waveshare relay channel 3
        slave: 0x01
        address: 0x0002
        write_type: coil
        command_on: 0xFF00
        command_off: 0x0000
      - name: Waveshare relay channel 4
        slave: 0x01
        address: 0x0003
        write_type: coil
        command_on: 0xFF00
        command_off: 0x0000
      - name: Waveshare relay channel 5
        slave: 0x01
        address: 0x0004
        write_type: coil
        command_on: 0xFF00
        command_off: 0x0000
      - name: Waveshare relay channel 6
        slave: 0x01
        address: 0x0005
        write_type: coil
        command_on: 0xFF00
        command_off: 0x0000
      - name: Waveshare relay channel 7
        slave: 0x01
        address: 0x0006
        write_type: coil
        command_on: 0xFF00
        command_off: 0x0000
      - name: Waveshare relay channel 8
        slave: 0x01
        address: 0x0007
        write_type: coil
        command_on: 0xFF00
        command_off: 0x0000
      - name: Waveshare relay all channels
        slave: 0x01
        address: 0x00FF
        write_type: coil
        command_on: 0xFF00
        command_off: 0x0000

The only non-Modbus extra piece is the following automation that reacts to the status change of any of the switches and initiates the update of the Modbus binary sensor (status of all channels).

- id: "<some_unique_id>"
  alias: Waveshare relay fetch channel status
  mode: queued
  max: 10
  trigger:
    - id: any_relay_channel_toggled
      platform: state
      entity_id:
        - switch.waveshare_relay_channel_1
        - switch.waveshare_relay_channel_2
        - switch.waveshare_relay_channel_3
        - switch.waveshare_relay_channel_4
        - switch.waveshare_relay_channel_5
        - switch.waveshare_relay_channel_6
        - switch.waveshare_relay_channel_7
        - switch.waveshare_relay_channel_8
        - switch.waveshare_relay_all_channels
      not_to:
        - "unknown"
        - "unavailable"
  action:
    - alias: Get current status of all relay channels
      service: homeassistant.update_entity
      data:
        entity_id: binary_sensor.waveshare_relay_status

Statuses of the switches and statuses of individual relay channels are separate entities that should be visualized together. An example Lovelace card:

square: false
type: grid
cards:
  - type: tile
    entity: binary_sensor.waveshare_relay_status
    name: Channel 1
    show_entity_picture: false
    vertical: true
    tap_action:
      action: none
    icon_tap_action:
      action: none
    state_content:
      - state
      - last-changed
  - type: tile
    entity: binary_sensor.waveshare_relay_status_1
    name: Channel 2
    show_entity_picture: false
    vertical: true
    tap_action:
      action: none
    icon_tap_action:
      action: none
    state_content:
      - state
      - last-changed
  - type: tile
    entity: binary_sensor.waveshare_relay_status_2
    name: Channel 3
    show_entity_picture: false
    vertical: true
    tap_action:
      action: none
    icon_tap_action:
      action: none
    state_content:
      - state
      - last-changed
  - type: tile
    entity: binary_sensor.waveshare_relay_status_3
    name: Channel 4
    show_entity_picture: false
    vertical: true
    tap_action:
      action: none
    icon_tap_action:
      action: none
    state_content:
      - state
      - last-changed
  - type: tile
    entity: binary_sensor.waveshare_relay_status_4
    name: Channel 5
    show_entity_picture: false
    vertical: true
    tap_action:
      action: none
    icon_tap_action:
      action: none
    state_content:
      - state
      - last-changed
  - type: tile
    entity: binary_sensor.waveshare_relay_status_5
    name: Channel 6
    show_entity_picture: false
    vertical: true
    tap_action:
      action: none
    icon_tap_action:
      action: none
    state_content:
      - state
      - last-changed
  - type: tile
    entity: binary_sensor.waveshare_relay_status_6
    name: Channel 7
    show_entity_picture: false
    vertical: true
    tap_action:
      action: none
    icon_tap_action:
      action: none
    state_content:
      - state
      - last-changed
  - type: tile
    entity: binary_sensor.waveshare_relay_status_7
    name: Channel 8
    show_entity_picture: false
    vertical: true
    tap_action:
      action: none
    icon_tap_action:
      action: none
    state_content:
      - state
      - last-changed
  - show_name: true
    show_icon: true
    type: button
    tap_action:
      action: toggle
    entity: switch.waveshare_relay_channel_1
    name: Channel 1
    show_state: true
    icon_height: 40px
  - show_name: true
    show_icon: true
    type: button
    tap_action:
      action: toggle
    entity: switch.waveshare_relay_channel_2
    name: Channel 2
    show_state: true
    icon_height: 40px
  - show_name: true
    show_icon: true
    type: button
    tap_action:
      action: toggle
    entity: switch.waveshare_relay_channel_3
    name: Channel 3
    show_state: true
    icon_height: 40px
  - show_name: true
    show_icon: true
    type: button
    tap_action:
      action: toggle
    entity: switch.waveshare_relay_channel_4
    name: Channel 4
    show_state: true
    icon_height: 40px
  - show_name: true
    show_icon: true
    type: button
    tap_action:
      action: toggle
    entity: switch.waveshare_relay_channel_5
    name: Channel 5
    show_state: true
    icon_height: 40px
  - show_name: true
    show_icon: true
    type: button
    tap_action:
      action: toggle
    entity: switch.waveshare_relay_channel_6
    name: Channel 6
    show_state: true
    icon_height: 40px
  - show_name: true
    show_icon: true
    type: button
    tap_action:
      action: toggle
    entity: switch.waveshare_relay_channel_7
    name: Channel 7
    show_state: true
    icon_height: 40px
  - show_name: true
    show_icon: true
    type: button
    tap_action:
      action: toggle
    entity: switch.waveshare_relay_channel_8
    name: Channel 8
    show_state: true
    icon_height: 40px
title: MyTest
columns: 8
1 Like