Writing values in modbus binding not considering valuetype and binding state

Hi,

1)
I noticed that current implementation does not seem to respect valuetype in when writing commands to modbus.

If we look at how openhab commands are translated to write requests in modbus (ModbusSlave.setRegister), we can see that the request is either WriteSingleRegisterRequest (when writeMultipleRegisters=false) or WriteMultipleRegistersRequest with register size of 1. ModbusSlave.setCoil always writes bits as it should.

Since modbus register equals 16bits of data, it is impossible to represent 32bit floats or 32bit integers with only single register. Similarly one can see that valuetypes such as int8 and uint8 are currently not supported properly during writing.

2)
Furthermore, in ModbusSlave.setRegister should the current value be retrieved from item’s State instead of cached register value? Similar observation applies for ModbusSlave.setCoil. I think this would follow the logic that bindings should be stateless.

What do you think of these changes?

Best,
ssalonen

Related issue: https://github.com/openhab/openhab/issues/428

  1. We should expand this to support all the data types, possibly including increment and decrement for floats, maybe even allow passing values other than 1 for the change. For 32 bit data types it should be strongly recommended that WriteMultipleRegisters be true since it could be possible for a 32 bit value to change between successive reads giving incoherent results.

I have not tested 8 bit data types, but there are only two use cases I can think of at the moment; an 8 bit value (signed or not) stored in a single modbus register and an array of bytes, such as an ASCII string.

  1. I can see strong arguments for both ways, the reason is that the choice is application specific, which device is the source of the data openHAB, MB Slave or both?

One related thought on this is currently all slaves defined are all polled at the same rate, if we added a slave specific poll rate (to override the modbus:poll value) we could slow some items down and totally disable polling for other items.

If we poll the slave then when we increment it we should read/modify/write but if it is not polled we may be able to assume OH is the source of the data and just modify/write

Thoughts?
Tom

  1. you have very good points there. Agree completely about extending support to other data types.

Please note that Currently the writemultipleregisters is global setting. What if we would use write multiple automatically when item size requires more than one register? Alternatively one could easily make slave specific version of writemultipleregisters… Perhaps the default could depend on valuetype even.

I do see why <16bit data types are implemented, to save memory space with slaves. For example, I have a use case where I would like to store booleans (bit) in a holding register. This is currently not possible without building somewhat complicated set of rules to transform boolean openhab items to 16bit integer and writing that one… Btw, same approach can be used to write float32 to the binding? Downside is that write will not be atomic?

  1. you are certainly right there. Actually quite lengthy discussion regarding this topic is ongoing on my pull request.

… Slave specific poll rate

I see your point in introducing slave specific poll rates. Certainly there are cases where we are just interested in writing the value to the slave.

If we poll the slave then when we increment it we should read/modify/write but if it is not polled we may be able to assume OH is the source of the data and just modify/write

Do you mean that in the first case we would poll the value instantly when processing INCREASE or DECREASE commands…And after that modify the value and write the updated value?

What did you mean by "just modify / write " in the latter case? would we use openhab item state/value as base value we increase / decrease?

I do like your logic of marking openhab as the source of data by disabling polling.

Btw

I have a pretty good test coverage in my puolet connections branch when it comes to how different value types and read and written.

Within a week or two I’m going to make a pull request of the branch and I expect it to take quite some time before the branch gets merged since it contains quite many changes.

Still, during development we might want to add new tests to verify the behavior. Actually many of the issues documented in the wiki I found with the test cases.

Do we need to maintain backward compatibility with writemultipleregisters?

Would we be lynched if the global setting was removed and replaced by a slave specific one?

Wait a second! With the way WRITE works now, would we ever write more than one register at a time?
That may simplify things!

The best default would be to automatically use FC16 with 32bit values, but each slave should have a setting as some (very old) slaves may not support FC16. (core point FC16 is not required to be supported)

So if you have a register packed with 16 Boolean values, on the slave it will still appear as a UINT16, I guess your slave application defines that register that way?

With that application implementation, I am not sure how that is a MODBUS layer issue, to MODBUS it is still just a single 16 bit register…

A float32 is just the same as an INT32, two words written together, no?
It can be atomic if FC16 is used. (or as close as we can possibly get)

If we are setup to poll a specific slave definition (ie ONE item value) then we are suggesting that the slave is allowed to change the value, so when we INCREASE it we should get the current value, change it and write it to the slave (read/modify/write).

If we do not poll that slave definition then the slave does not modify the value, so the setting we have is always right, so there is no need to read it.

Tom

I think it could be easy to keep compatibility, if enabled, we would always write everything with fc 16? We can introduce slave specific setting as well, it does not hurt, right?

That’s correct

The best default would be to automatically use FC16 with 32bit values, but each slave should have a setting as some (very old) slaves may not support FC16. (core point FC16 is not required to be supported)

This is exactly what I have been thinking as well. Actually my tests already predict this behaviour :slight_smile:

In case of 16 booleans, probably openhab user would like to mark it with valuetype=bit to make it easy to use the actual boolean items in the sitemap and rules?

Same logic applies for the float32 and int32?

Or am I following you?

Best, Sami

Yes OH bit would map to MODBUS boolean
INT16 and UINT16 map to a single MODBUS register
INT32, UINT32 and FLOAT32 map to 2 MODBUS registers

I just do not know how the INT8/UINT8 type is handled

tom

What I am suggesting is that since the current write code only writes a single register then we can eliminate the global writemultipleregisters setting and it would not effect anyone…

tom

Ok now I get it. I think not many use the global parameter, after all it was undocumented for a long while…

It might be useful for some users, see this post. Not sure though was it misunderstanding, but we understood that the users slave did not support fc 6 but it did support fc 16 (yes this is not a typo!). Like you said, in the current binding, the register write requests contain only one register… Even with the writemultipleregisters=true!

Edit : the limitation might be true, a while ago I actually found similar functionality implemented in a another modbus library, modbus4j. See this code and the multipleWritesOnly proper tykkää.

Best
Sami

Sorry I’m not sure I still follow what you mean…

For example, With datatype int8 the binding requests the registers as usual but then extracts single byte (8 bits), either low or hi byte from some register.

Openhab Item definition has the index in the configuration string which specifies whether we pick the low / high byte and from which register.

Finally this byte of data is converted to openhab DecimalType by interpretating the bits with twos complement format.

I have tried to document the process in the wiki but I’m sure that it could be clarified more…

So if you have a register packed with 16 Boolean values, on the slave it will still appear as a UINT16, I guess your slave application defines that register that way?

With slave application you meant the actual slave device? I think you would like to define the register similar to the valuetype? For example in my siemens plc (acting as modbus tcp slave or modbus tcp server) I can configure two registers as single float32 value. With siemens the ordering of the registers even matches the convention in the openhab binding. When configuring such item in openhab, I would definitely use float32 valuetype since it allows ease of use.

Naturally on the modbus protocol level there is no such thing as float32, just registers, each of which contain 16bits of data. I think this was your point as well?

I think we are saying a lot of the same things…

when we get there we will figure it all out

right now I still can’t build, I am going to do another install and pay extra attention to each step, maybe I left something out

1 Like

I was thinking more about the Increase/Decrease and polling…

There is no reason to tie the polling (or lack thereof) to the data source used in an INCREASE.
If you are issuing a MODBUS send_command to INCREASE a Modbus Register then the actual MODBUS register is the SOURCE, if you want to use the local value as the source then do a send_command to write the CurrentValue+1

That is not to say that being able to disable automatic polling is not a useful feature, I am just suggesting it could be a SEPARATE feature. Along with it we may need a READ command if there is not already one to manually poll the current value

tom

Hello thank you , can you help me ?
Sorry for my bad English…
Recently I discovered OPenHab , and I am using it to monitor the home
automation system at home .
Via The me the Modbus RTU RS232 port to connect DFTS DUEMMEGI module that
contains an organized RAM in 16-bit registers each ( Word ) .
Each Word contains information regarding the status of Domino connected bus
modules
Example
001 to 255 word by word you can read the status of inputs in bits or value
257 to 511 word by word you can read / scriere status bit or output value.

Tech support told me to use the function 16

The tests have not been entirely positive
The state of the input word / bit and word / bit can not see properly
while the command of the outputs can only drive the bit 0 of each word all
the other ( 1 -bit / 2 bits / bit 3 ) do not work

What can be the cause ?
THANK YOU

Da: Ssalonen [mailto:bot@community.openhab.org]
Inviato: sabato 19 marzo 2016 08:48
A: premoliomar@tiscali.it
Oggetto: [openHAB] [Add-ons/Bindings] Writing values in modbus binding not
considering valuetype and binding state

<https://community.openhab.org/user_avatar/community.openhab.org/ssalonen/45
/1268_1.png> ssalonen https://community.openhab.org/users/ssalonen
March 19

Ok now I get it. I think not many use the global parameter, after all it was
undocumented for a long while…

It might be useful for some users, see this
https://community.openhab.org/t/modbus-rtu-function-code/7045 post. Not
sure though was it misunderstanding, but we understood that the users slave
did not support fc 6 but it did support fc 16 (yes this is not a typo!).
Like you said, in the current binding, the register write requests contain
only one register… Even with the writemultipleregisters=true!

Best
Sami

Visit
<https://community.openhab.org/t/writing-values-in-modbus-binding-not-consid
ering-valuetype-and-binding-state/5247/10> Topic or reply to this email to
respond

In Reply To

<https://community.openhab.org/user_avatar/community.openhab.org/w2vy/45/218
1_1.png> w2vy https://community.openhab.org/users/w2vy Thomas
https://community.openhab.org/users/w2vy Moulton
March 19
What I am suggesting is that since the current write code only writes a
single register then we can eliminate the global writemultipleregisters
setting and it would not effect anyone… tom

Visit
<https://community.openhab.org/t/writing-values-in-modbus-binding-not-consid
ering-valuetype-and-binding-state/5247/10> Topic or reply to this email to
respond

To stop receiving notifications for this particular topic, click
<https://community.openhab.org/t/writing-values-in-modbus-binding-not-consid
ering-valuetype-and-binding-state/5247/unsubscribe> here. To unsubscribe
from these emails, change your user
https://community.openhab.org/my/preferences preferences

Hi ssalonen, would like to wirte/read variables from a Beckhoff PLC with the modbus TCP binding in OpenHab 2.2.
Basicly it works perfect, but the valuetype in the modbus.cfg does not have any effect. When I set ‘bit’ or ‘uint8’ the binding still uses ‘int16’ as datatype.
Maybe you can help me. My Configuration looks like this:

tcp.slave1.connection=192.168.1.101:502:60:0:0:50:100
tcp.slave1.start=12288
tcp.slave1.valuetype=uint8
tcp.slave1.length=8
tcp.slave1.type=holding

Thank you in advance.
BR Sebastian

Woah, seems like it revived very old thread!

Please note that the binding cannot write anything else than 16 bit values. From the docs:

Note: The way Decimal commands are handled currently means that it is probably not useful to try to use Decimal commands with non-16bit valuetypes.

With <16 bit value types, the reason is that there is no such thing as writing 8 bit values or single bit values to holding registers.

You most likely need to have rules and proxy items, and construct the whole register you want to write.

For further discussion, see Phoenix Contact Buscoupler no coils or discrete inputs

1 Like

Hi, thank you for the quick response.
:slight_smile: that ist what I was worried about. But OK I need to start the better handling with rules and items anyway.