OK, so I can see that you have been asking this question for some time. I don’t use Modbus in HA directly as I do this in Node-RED (I find that it is just easier, more adaptable, and quicker to develop and change).
However, I have looked at HA Modbus, and decided that here was an opportunity to try and gain better understanding in how it works by looking (again) at your problem.
I do not have a Modbus device with coils, so I downloaded a free Modbus slave simulator and set that up on my PC. I added some Modbus setup code to my config yaml, and I have experimented with three binary/coil entities in HA.
I can confirm that
Modbus (over TCP) works on HA as expected
Switches and binary sensors work as expected
The ‘verify’ option for switches works as expected
Here is my config entry for the Modbus testing. Note that my test slave has unit/slave id of 1
modbus:
- name: testslave
type: tcp
host: 192.168.0.137
port: 502
binary_sensors:
- name: mbbSensor3
slave: 1
address: 3
scan_interval: 20
device_class: connectivity
input_type: coil
switches:
- name: mbSwitch2
slave: 1
address: 2
write_type: coil
- name: mbSwitch4V
slave: 1
address: 4
write_type: coil
verify:
delay: 10
And here is my testbed setup.
I am using a simulated Modbus client on my PC, which allows me to change coil register values, to see when the change, and importantly to trace the Modbus communication (top left).
I added three entities in my config.
mbbSensor3 is a binary sensor, which just polls the slave coil address 3 every 20 seconds and reads the value of the coil. This cannot be changed in HA, but it responds to any changes made in the slave at the next poll read.
mbSwitch2 is a switch, connected to coil address 2. Being a switch I can change it in HA. On change, it sends a write command to the slave (0 or 1 according to the updated HA switch setting) and toggles the switch. Changing the coil in the slave has no change on the switch as this switch does not read, just write. In effect, HA assumes that the switch and the coil are following each other.
mbSwitch4V is also a switch, connected to coil address 4, but with the ‘verify’ option. This causes the switch to write any changes to the coil, and then to attempt to read back from the coil and update the switch accordingly. This is positive feedback.
Without ‘verify’ HA will only write to a coil. Adding ‘verify’ turns on a read after the write. Playing around with the verification option shows that, as just the default with no sub-values, HA attempts to read the same coil after each switch change. This means a manual toggle of the HA switch causes HA to immediately toggle the switch status, write to the coil, toggle the switch back again, read from the coil, and finally set the switch according to the true coil value. Thus HA is, assuming a successful write, then restoring the switch, and finally reading the coil to set the switch value.
Adding a delay option to the verify option caused HA to being polling the coil every 10 seconds - and this was ongoing, so that any change to the coil in the slave would cause the switch to update at the next poll read.
Conclusion: it all works and was very easy to set up, however the resulting functionality is very dependent on the precise settings, and I would always want to test this very carefully before using it. Especially if I wanted the switch to follow the coil (ie if I wanted to switch in HA and change the coil and I also wanted to change the coil elsewhere and for this to update the HA switch setting).
So, now to your problem.
Using the trace option I captured the communication between HA and the test slave on my PC.
Transaction ID 2 : Protocol ID 2 : Length field 2 : Unit ID 1 : Function Code 1 : Data n (address / value to write)
ID FC <add> <val>
<no v>
[TCP]>Rx > 11:33:40:854 - 00 4D 00 00 00 06 01 05 00 04 00 00 write coil, address 4, value 0
[TCP]>Tx > 11:33:40:856 - 00 4D 00 00 00 06 01 05 00 04 00 00 response
[TCP]>Rx > 11:33:50:850 - 00 4E 00 00 00 06 01 01 00 04 00 01 read coil, address 4, one value
[TCP]>Tx > 11:33:50:850 - 00 4E 00 00 00 04 01 01 01 00 response 0
[TCP]>Rx > 11:33:52:079 - 00 4F 00 00 00 06 01 01 00 03 00 01 read coil, address 3
[TCP]>Tx > 11:33:52:079 - 00 4F 00 00 00 04 01 01 01 01 response 1
[TCP]>Rx > 11:33:52:337 - 00 50 00 00 00 06 01 01 00 04 00 01 read coil, address 4
[TCP]>Tx > 11:33:52:337 - 00 50 00 00 00 04 01 01 01 00 response 0
[TCP]>Rx > 11:34:07:338 - 00 51 00 00 00 06 01 01 00 04 00 01 read coil, address 4
[TCP]>Tx > 11:34:07:338 - 00 51 00 00 00 04 01 01 01 00 response 0
[TCP]>Rx > 11:34:12:076 - 00 52 00 00 00 06 01 01 00 03 00 01 read coil, address 3
[TCP]>Tx > 11:34:12:076 - 00 52 00 00 00 04 01 01 01 01 response 1
[TCP]>Rx > 11:34:22:335 - 00 53 00 00 00 06 01 01 00 04 00 01 read coil, address 4
[TCP]>Tx > 11:34:22:335 - 00 53 00 00 00 04 01 01 01 01 response 1
[TCP]>Rx > 11:34:32:077 - 00 54 00 00 00 06 01 01 00 03 00 01 read coil, address 3
[TCP]>Tx > 11:34:32:077 - 00 54 00 00 00 04 01 01 01 01 response 1
As this is Modbus over TCP, the message is the transaction ID, protocol ID, length field
then the important bits - unit id (the slave address), the Modbus function code, and the data
So, for a write to a coil (I change HA switch, HA turns coil off) for address 4 the command is:
Function code 5, address 00 04, value 00 00
Then for the read coil verification, by default HA will just read back from the same register
Function code 1, address 00 04, value 00 01
NOTE HA is sending 00 04 00 01 and getting back 01 00
Here the Modbus command being issued is the command to read one value from address 4. And my test slave responds accordingly sending back the value 01 00 - which is “I am sending you back 1 byte, and the value is 00”. In Modbus, a read of coils sends back the number of bytes of data and a value where the individual bits hold the results (with extra packing up to multiples of 8 bits).
In other words, if I asked for 3 values and they were 1, 0, 1 I would get back 01 05.
Now, if I turn to your device (Ahatos - REL 0808) user guide, I see that the ‘read channel state’ request, read coil function code 1, requires a data block of
“start channel number to read 0x00, 0x00-0x07, number of channels to read 0x00-0x01…0x08”
and the important bit is that
“number of channels to read should be 8 - (minus) starting channel to be read”
I don’t have your device to test, but this suggests to me that what your device wants, in order to read just one coil at address 4 is , 00 04 00 04
And it puts the values of coil 4, 5, 6 and 7 into the return.
I think that, to read 1 coil at address 1 requires 00 01 00 07, but HA is sending 00 01 00 01, and so on.
I think your problem actually is - your device requires 00 04 00 04 to read coil 4, but HA is sending 00 04 00 01 with the verify setting.
My suggestion is that you set up a test with your device and check out what is actually required in order to read just one coil. These manuals are not always correct or helpful - and I would personally want to check what is required to read, for example, coil 4.
After that, if I am right, your problem becomes one of how to send the verify read command correctly.