Modbus Integer Write Out

Are there any Modbus experts out there ? To be fair its probably just me not understanding how to configure HA.

SO I can read single digital bits OK, and I can write single digital bits OK, this I am doing with a switch component linked to a specific “Coil”

I can also read integer values OK, but where I am struggling is to write out an integer value, for example the value of a slider.

I read registers into Sensors without issue.

So the question is has anyone written out an integer via Modbus from a slider

Hope someone reads all of this, understands and helps as this is sooooo frustrating !!

Thanks
Ant

2 Likes

Maybe I’m the only one using Modbus ???

So this is the config file, a slide to create a value, automation to push it out when it changes…

input_slider:
slider1:
name: Temperature
initial: 21
min: 15
max: 25
step: 1
icon: mdi:temperature-celsius

automation:

  • alias: Set Temp
    trigger:
    platform: state
    entity_id: input_slider.slider1
    action:
    service: modbus.write_register
    data:
    unit: 1
    address: 10
    value: ‘{{ states.input_slider.slider1.state }}’

Or maybe not as nothing happens :frowning:

I’m experiencing the same problem. After some debugging I’ve noticed that the service modbus.write_register sends a modbus function code 16 (presetting multiple registers). This would be desirable if an array of values is passed, but it also does this if you only pass a single integer as value.
The modbus function code 16 is often not supported by the modbus slave, and for writing a single value function code 6 would be a better option, and this is supported by most modbus slaves.

Anyone who know how to force the service modbus.write_register to use modbus function code 6 for writing a single value? Or is this a bug in the modbus component?

I have the same problem. Did you find the solution?

Not yet at the moment, I’ve drilled down in the modbus.py code and found a where it goes wrong (that way always an array is passed to pymodbus which results in FC 16).

I did a pull request (https://github.com/home-assistant/home-assistant/pull/18425) but I had to do a PR for the docs and also alter services.yaml. Had no time to look into it, but I might resume it in the future. I’m now running my own custom modbus.py (based on my change in the PR) which works perfectly.

This is also the same problem I am having.

So the code in the pull request is on your link but is it possible that you could post the necessary changes required for services.yaml please!

Thanks in advance if you have time!

Regards Steve Wells

Thanks so much to gertdb for solving this problem. I can confirm that it does resolve the issue of writing to single registers for my needs.

I edited line 63 of the file (in my case modbus2.py) as your pull request here ( https://github.com/home-assistant/home-assistant/pull/18425 ) advises.

now my line 63 reads:
vol.Required(ATTR_VALUE): vol.Any(cv.positive_int)
was:
vol.Required(ATTR_VALUE): vol.All(cv.ensure_list, [cv.positive_int])

I can also confirm that this also works if you have followed the workaround for having more than one modbus device/hub (IE: modbus1.py and modbus2.py etc). see here Ability to add multiple modbus hubs
I started with my most urgent device (using modbus2.py) to make sure this was going to work and it does so I assume all other mods of the modbus.py will behave the same. I will report back if this is not so.

You just need to remember which register you are writing to belongs to what modbus.py.

For example my automation looks like:

  • id: IrrigationStartTime
    alias: Irrigation Start Time
    trigger:
    platform: state
    entity_id: input_number.slider1
    action:
    service: modbus2.write_register
    data_template:
    unit: 3
    address: 3074
    value: “{{ states.input_number.slider1.state|int }}”

Thanks again to the whole community here and I would encourage developers to recognise that both these issues (IE: writing to registers and multiple modbus hubs) should be included into the official version at some point in the near future and that the documentation also needs to be updated.

Cheers to all!

I’ve found some spare time and retried a PR for this issue. Hopefully it gets accepted now and is merged in the new build. In the meantime I have also been running the modbus component as a custom component and it works perfect. It is indeed a wrong implementation of pymodbus, which is already for a very long time residing in home assistant.

https://github.com/home-assistant/home-assistant/pull/21621

1 Like

Great that you have been able to get onto this gertdb!
For my own (and others) clarity could you confirm…there are two extra lines in modbus.py (a total of three have been edited) due to the line length restrictions? Doing it that way will allow both options of a single register or multiple registers right?

Also, does the services.yaml (@ homeassistant/components/modbus/services.yaml) require this edit to allow the two options to work? And if so will that also work for multiple modbus hubs do you think?

The multiple hubs solution (here Ability to add multiple modbus hubs which works seamlessly for me needs to be looked at and a better solution devised in my humble opinion.
Why?
Imagine if you had to have multiple MQTT Hubs for every new device?

I’m not a developer so I wouldn’t know if it’s possible but surely there is a way to code this to allow for multiple modbus devices within the one modbus.py system? Is there anyone working on that do you know?

Cheers for your great work again!
Regards Steve Wells

Gertdb there has been an update on the modbus documentation…

Multiple hubs and write single values or arrays are now all supported!

Fantastic news…and well done to all who contributed to this result!

Hi Steve, support for multiple modbus hubs was actually added in PR #19726 by benvm.
https://github.com/home-assistant/home-assistant/pull/19726

The single values and arrays have been officially supported for a long time, but not working because of the coding bug in the voluptuous data validation. I hope my PR gets merged, because then this is also finally resolved.

The reason that the change consists now of multiple lines of code is indeed because of the line length restrictions.

The edit in services.yaml is not necessary for the change to work, it only provides a description of the possibilities of the service. (for example shonw on the /dev-service page in Home Assistant).

Hi gertdb and thanks for the full answers…appreciate that!

From what I read and in particular this below:

@balloob balloob referenced this pull request 16 days ago

Merged

0.88.0 #21238

0.88.0 is the version with multiple hubs fixed yes?
Then your PR needs to be merged as well right?

For me I will stick with what is working…incredibly well…for now as I have 0.81.6 installed on a QNAP DOCKER and it makes me very nervous upgrading especially when I am reading so many things broken with recent updates.

For me the modbus multiple hubs MUST work as I have recently ditched a flawed SCADA solution in favour of a homeassistant solution which runs some reasonably important (to me) infrastructure I have here including, water treatment, irrigation, energy management and a number of other lesser systems. I’m still completing full control and monitoring of my 5 PLC’s at this stage.
Now that I can write to registers effectively things will become easier but I haven’t even begun work on historical data which is quite important for what I’m trying to achieve.

I think I will investigate running another docker installation with the latest version to test for a while.

Thanks again for your help and feedback!

Hi Steve, yes indeed, the multiple hub solution was merged since 0.88.0. My small code change for the single/array input support will hopefully be merged in an upcoming release.

If you want some more comfort in upgrading/downgrading I can recommend to run Hass.io on a Raspberry PI. If you “invest” in a good PSU and good quality MicroSD card (e.g. Samsung EVO Pro) it’s a really reliable solution, and the snapshot feature gives you ease to test upgrades and quickly roll back when needed.

I can second that Home Assistant, even it’s still under development is already very superior to a lot of out-of-the-box (commercial) solutions.

Yes I hope your code makes it soon as well!

Regarding your suggestion to do testing on raspi. I have in the past used a good quality setup like you described above but found that the time it took for restarts of the pi and of homeassistant or hasio took a little too long for my liking…after researching I realised that a more powerful platform may be the best wat to go.

I had already realised the eliminating my defective scada system was possible with homeassistant so I have chosen a QNAP NAS after looking at a number of other options.

I will give you an update when I setup the latest version HA (unfortunately you cannot install Hassio in a docker container) after the full solution for my modbus needs is available (with your code included) and found to be stable.

Cheers again all for this wonderful community effort here!

Oh by the way…writing to registers over 4 modbus hubs now…life’s good!

Thanks for sorting this out for the community.

I know that topic is a bit old :slight_smile:
Anyhow. Is here any modbus experienced able to advice how to write in a single bit of register?
I know that I can use a switch, nonetheless I do not know how address a specific bit.

I am reading from:

  - platform: modbus
    registers:
    - name: relays mb #  MBF_MEASURE_RELAYS_STATE
      hub: pool
      slave: 1
      register: 258
      register_type: holding
      data_type: uint

There are 5 bits for 5 relays state (bit 1,2,3,4,5) and I need to be able to change bit 3 from 0 to 1

Any advice?

@kajmaj I have not had the need to do this myself however I am pretty sure there have been posts about this type of thing so maybe you need to do some specific searching for your answer.

From memory of one discussion I believe you just have to construct an ‘array’

There is documentation here which includes this below:

Service Description
write_register Write register. Requires hub, unit, address and value fields. value can be either single value or an array

I hope that helps a little and I will continue to search myself a little to see what I can find. Try searching “write_register bit” OR “write_register array”

Perhaps if you find the answer please post back here to add your solution? I will as well.

UPDATE: Discussion and a solution here: SOLVED:How to add sensor state in an array inside an automation and send it with modbus.write_register service

NOTE: The automation is how you write the value to your register.

@wellsy Great thank you :+1:
If I understood well.
Register of my interest
RELAYS_STATE
If I needed to change bit 4 from 0 to 1 I will use following (I have slave 1, but using MODBUS TCP it should be 255)

  action:
    service: modbus.write_register
    data:
      hub: pool
      unit: 255
      address: 270
    data_template:
      value: [10,1]

If I need to change bit 6 from 1 to 0:

    data_template:
      value: [40,0]

At the end I need to change bit 2 and 6 back to original state. How to organize an array in this case?

Or it should be in a different way?

One thing is you may need to fill in all the array but I am not certain? As I understand these things there are 6 bits in the array?

So like:
value: [0,0,0.0,0,0]

You then set the fourth bit:
value: [0,0,0.40,0,0]

The key to understanding what will be sent is to test your data template in the yourIP:8123/developer-tools/template editor. Read down to the bottom of that link I posted above and you will see how all involved in that thread worked out how to get it right for a number of different requirements.

You look like you just want to write specific values right?
If you want to rewrite those values then just construct a second automation may work for your purposes?

You can also setup an input_number to provide the values and trigger the automation on state change of the input_number if that works for you?

Here is an example automation using an input_number…disregard if of no use:

- id: IrrigationPoolSetpoint
  alias: Irrigation Pool Setpoint
  trigger:
    platform: state
    entity_id: input_number.slider4
  action:
    service: modbus.write_register
    data_template:
      hub: hub3
      unit: 3
      address: 3080
      value: "{{ states.input_number.slider4.state|int }}"

Remember you just need to modify to include your array within the value template.