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.
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.
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
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?
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.
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.
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
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?
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…
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ää.
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 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
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
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!
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: