Modbus writing a specific bit of a register

Hi,
I have the home automation base on a WAGO PLC with modbus support.

I try to describe my scenario.

The state on/off of a light is stored as unsigned int in a byte of a specific address. Each address contains the state of 2 different lights (16 bit or 8+8 bit or two different byte)
I created each light’s binary sensor with the split function of a multi register sensor as below and it works fine.

modbus:

  • name: casa
    type: tcp
    host: !secret domotica
    port: 502
    sensors:
    • name: luci.notte.group
      address: 21988
      input_type: holding
      count: 9
      scan_interval: 10
      data_type: custom
      swap: byte
      structure: “18B”

binary_sensor:

  • platform: template
    sensors:
    notte_corridoio:
    friendly_name: ‘Corridoio’
    device_class: light
    value_template: “{{ states(‘sensor.luci_notte_group’).split(’,’)[0] }}”

Now the problem.

To change the state of a light I need to write an int value (255) in two different registers, one to switch on the light and other one to switch off it. It works fine, but only for the light managed by the first byte (first 8 bits) of the address. I don’t know how to write the 255 int value in the second byte of the address (second 8 bits).

switch:

  • platform: template
    switches:
    sw_notte_corridoio:
    friendly_name: “Luce Corridoio”
    value_template: “{{ is_state(‘sensor.notte_corridoio’, 'on) }}”
    turn_on:
    service: modbus.write_register
    data:
    unit: 1
    address: 22568
    value: 255
    hub: casa
    turn_off:
    service: modbus.write_register
    data:
    unit: 1
    address: 22644
    value: 255
    hub: casa

Anyone can give me some help ?

Hi,
as far as I understood modbus (I use it from within a C-program) simply set the leading bits to 1 as well.
So for your example with 255 the lower eight bits are all set to “1” and the upper ones are zero. Instead of sending 255 (0000000011111111) you should send 65,535 (1111111111111111) if you want to use both or 65,280 (1111111100000000) just for the second one.

Give it a try, I had to do try and error a lot with this modbus stuff. In the end it is not too complicated.

/KNEBB

Hi @knebb.

I need to change only the second byte (or second group of 8 bits) without changing the first one.
A part from that, I still don’t know how to set the modbus.write_register service of ha to do this.

thank you

Well, in this case, do a modbus.read before writing it. Then you have the current settings and you can match your value for the following write…

As I am currently as well trying to configure modbus I just realized there might not be a “read” function… strange.

In this case I am out of ideas, indeed. I would just suggest to keep track of all changes so you should always know if the light is on or not. And set the register accordingly.

I will have to go through the basic steps of configuring modbus on hoassio. Look like this is a strange implementation. I am currently struggling with the basics here. How to read a modbus sensor???

/KNEBB

Another addition from me as I am trying to get it up and running, too.

There seems to be not explicit “read” command. When configuring a sensor you have to enter its registeraddress which will be read then.
To write you can enter a different address as shown here. “target_temp_register”.

Give it a try.

Yes, there isn’t a specific “read” command neither an HA modbus service to try readings. The only solution is to define modbus sensors (or binary_sensors, switch and so on) based on which you have to do and based on your modbus PLC specifications (If you need some help, I could try to help you) .

To do what you said in you post about tracing all changes, the solution is to define specific sensors for the first byte and second one and based on the value of that sensors do the write with the specific value.

At the moment, the solution of 255 (0000000011111111) and 65280 (1111111100000000) works for me. I noticed that when I use the specific registers to change the state (eg: light) by writing 255, they return to 0 after action execution in PLC.

So, for me, the problem is quite “solved”.

Thanks for updateing and offering. For me it is not yet solved, unvoftunately.

I have a device which measures CO2, temperature and so on. It offers a modbus connection which I enabled (verified by a port scan, 502 is open).

The documentation states the temperature as flow is seen on register “0”.
I have configured it as follows in configuration.yaml:

modbus:
  - name: "zentrale"
    type: tcp
    host: 192.168.22.60  
    port: 502
    sensors:
      - name: Sensor1
        unit_of_measurement: °C
        address: 0

But am getting the sensor is not available and the following in the logs:

 Logger: homeassistant.components.modbus.modbus
Source: components/modbus/modbus.py:250
Integration: Modbus (documentation, issues)
First occurred: 07:42:01 (1 occurrences)
Last logged: 07:42:01
Pymodbus: zentrale: Modbus Error: [Input/Output] Modbus Error: [Invalid Message] No response received, expected at least 8 bytes (0 received)

Any clue?

Thanks for reading anyways!

/KNEBB

data_type: float32

for sure is needed, but I do not think that is why it is not reading, since you got 0 bytes
Can you pull data using the REST API?

http://192.168.22.60/api/v1/data.json/format=1&meta=1

Hi,

changed to float32 with the same results:

Logger: homeassistant.components.modbus.modbus
Source: components/modbus/modbus.py:250
Integration: Modbus ([documentation](https://www.home-assistant.io/integrations/modbus), [issues](https://github.com/home-assistant/home-assistant/issues?q=is%3Aissue+is%3Aopen+label%3A%22integration%3A+modbus%22))
First occurred: 08:09:31 (1 occurrences)
Last logged: 08:09:31

Pymodbus: zentrale: Modbus Error: [Input/Output] Modbus Error: [Invalid Message] No response received, expected at least 8 bytes (0 received)

Current configuration.yaml:

  - name: "zentrale"
    type: tcp
    host: 192.168.22.60  
    port: 502
    sensors:
      - name: Sensor1
        unit_of_measurement: °C
        address: 0
        input_type: input
        data_type: float32

I have not tried using RESTA API but using MQTT works fine. Although this is not really a solution as I have devices which do not offer MQTT so am I stuck with modbus…

/KEBB

Hi.

I notice that from the first code you posted and the second one you changed the input_type property of the sensor.
Same error with input_type: holding?

From documentation: “Both serial line parameters and TCP listening port (502 by default) can be configured – see Configurable parameters description. The sensor supports only a single open TCP connection at once.”
May be you have to enable/configure modbus support on sensor?
The sensor support only a single open TCP connection: sure that there are not any other modbus client connected?

I am getting similar issue. In my case there is only 1 connection via EW11 to Epever charge controller.

My config

modbus:
- type: rtuovertcp
  name: ew11
  host: 192.168.5.249
  port: 502
  close_comm_on_error: false
  timeout: 9
  delay: 9
  message_wait_milliseconds: 50
  retry_on_empty: true
  retries: 10
  sensors:
    - name: "Battery Remaining Capacity"
      address: 12570
      slave: 1
      data_type: uint16
      input_type: input
      unit_of_measurement: '%'
      scale: 0.01
      precision: 3
      scan_interval: 10

Here is the error i am getting

2021-09-29 17:02:05 DEBUG (SyncWorker_1) [pymodbus.transaction] Transaction failed. (Modbus Error: [Invalid Message] No response received, expected at least 2 bytes (0 received))

i have been searching but have not found a solution

Here is my simple modbus configuration:

  • name: home
    type: tcp
    host: xxx.xxx.xxx.xxx
    port: 502

Other parameters are for serial connection. I think the “rtuovertcp” value is deprecated. Try using “tcp” instead.
“No response” means that the modbus controller doesn’t correctly respond.
About “input_type”: have you try to set “holding” ?

Thanks for the help. I tried that also but still same result

Config

modbus:
- type: tcp
  name: ew11
  host: 192.168.5.249
  port: 502
  sensors:
    - name: "Battery Remaining Capacity"
      address: 12570
      slave: 1
      data_type: uint16
      input_type: holding
      unit_of_measurement: '%'
      scale: 0.01
      precision: 3
      scan_interval: 10

Error log

2021-10-05 08:21:57 DEBUG (SyncWorker_3) [pymodbus.client.sync] Connection to Modbus server established. Socket ('192.168.5.74', 52923)
2021-10-05 08:22:07 DEBUG (SyncWorker_3) [pymodbus.transaction] Current transaction state - IDLE
2021-10-05 08:22:07 DEBUG (SyncWorker_3) [pymodbus.transaction] Running transaction 1
2021-10-05 08:22:07 DEBUG (SyncWorker_3) [pymodbus.transaction] SEND: 0x0 0x1 0x0 0x0 0x0 0x6 0x1 0x3 0x31 0x1a 0x0 0x1
2021-10-05 08:22:07 DEBUG (SyncWorker_3) [pymodbus.client.sync] New Transaction state 'SENDING'
2021-10-05 08:22:07 DEBUG (SyncWorker_3) [pymodbus.transaction] Changing transaction state from 'SENDING' to 'WAITING FOR REPLY'
2021-10-05 08:22:16 DEBUG (SyncWorker_3) [pymodbus.transaction] Transaction failed. (Modbus Error: [Invalid Message] No response received, expected at least 8 bytes (0 received))

Not sure what solved it but it is working now. I unplugged the cable from the charge controller and plugged it again and it worked.