Modbus openHAB2 binding available for alpha testing

I’m planning to add support for openhab2 REFRESH command that should do the trick. Agree that it makes sense to have actions for polling devices.

Endpoint corresponds to the physical slave device, identified by ip+port or serial device.

Poller corresponds to regularly executed modbus read requests, reading discrete inputs, holding registers, input registers or coils.

Read definition extracts data from the read data. Together with value type, transformation etc. the raw bits and bytes are converted to openhab state.

Write definition tells how openhab commands should be encoded to registers or coils for writing.

Readwrite definition binds read and write definitions together. Item would be bound to a Readwrite channel.

Best
Sami

Oh yes, I’d forgotten REFRESH :smile:

Maybe that is the place for Modbus id / slave address? Different id usually correspond to separate physical slaves. Obvious for serial, not so obvious where TCP gateway in use.


[quote=“ssalonen, post:1, topic:27657”]lots of configuration for simple case? should we provide simpler read-write things for the typical case?
[/quote]

Not convinced. Configuring Modbus seems to already cause brain-ache in even the simplest case. Adding another way to configure may just add more choice/confusion.

The logical concept of defining read and write paths separately, then combining into a common “thing” does not seem too difficult to grasp.
We do expect the binding to follow different behaviour in the usual polled-read + on-demand-write setup.

I certainly don’t have enough OH2 knowledge to see why the common readwrite “thing” is a Thing and not straight to a Channel. I think I have a clue that a readwrite Thing would have several Channel ‘children’ - one for Number, one for Contact, one for Rollershutter etc.


Question: is it possible to influence bridge Thing settings from rules?
( I obsess about fault management, and have in mind the use-case to reduce/stop polling a broken slave, and so avoid excessive waiting on timeouts )
I don’t know enough about OH2 to see if there is an equivalent method to the the old ConfigAdmin binding.
After some reading - Ah, is this where a Channel could optionally expose a Thing setting?

But perhaps that is an unusual enough requirement to ignore - with a REFRESH capability it would be possible for oddballs to build our own polling service in rules and do what we like with it.

Maybe that is the place for Modbus id / slave address? Different id usually correspond to separate physical slaves. Obvious for serial, not so obvious where TCP gateway in use.

Yeah, it would make sense to include it here. Then one does not need to repeat the id many times.

Connection sharing would work as currently, based on host+port or serial device

We do expect the binding to follow different behaviour in the usual polled-read + on-demand-write setup.

What did you mean by this?

I certainly don’t have enough OH2 knowledge to see why the common readwrite “thing” is a Thing and not straight to a Channel. I think I have a clue that a readwrite Thing would have several Channel ‘children’ - one for Number, one for Contact, one for Rollershutter etc.

Well, if it would be a channel and the read and write definitions would be configuration, I think the channel’s parent thing would be tied to those read & write definitions. Since we want to allow having many read & write definition pairings, separate thing type is required… Or at least that’s how I understand it.

( I obsess about fault management, and have in mind the use-case to reduce/stop polling a broken slave, and so avoid excessive waiting on timeouts )

This is hopefully not so much an issue as all the polling will be in different threads in openHAB2 version… Do not have answer for ConfigAdmin analogy.

Alternative proposal (better?) version:

endpoint thing (bridge) {
    // thing config parameter: ip port

    poller thing (bridge) {
        // thing config parameter: poll period
        // thing config parameter: start, length of registers/coils to read
        // thing config parameter: type of items to read (coils, discrete inputs, holding registers, or input registers)
        

        readwrite thing {
            // note: not part of bridge!
            // analogous to old binding item config
            // thing config parameter: read definitions (thing UIDs as comma separated)
            // thing config parameter: write definitions (thing UIDs as comma separated)

            // channel: switch, number, string, ... (all known channel types, similar to openhab 1 binding supports all items as long as correct transformation is in place)

            (zero or more) read definition thing {
                // config parameter: what to read (index of register/coil)
                // config parameter: how to read 
                // - trigger, 
                // - value type (e.g. 16bit integer vs 32bit integer)
                // - and transformation
            
                // channel for different item types: switch, number, string, etc.
            }
       
            (zero or more) write thing {
                // thing config parameter: where to write (index of register/coil)
                // thing config parameter: what kind of data to write (coil or holding register)
                // thing config parameter: how to process data for modbus
                // - trigger
                // - transformation, 
                // - value type (e.g. 16bit integer vs 32bit integer)
            }
       }
        
    }
}


Upside compared to first alternative

  • GUI configurable, no need to refer to “channel IDs” in thing configuration

Obvious downside

  • not possible to combine coils with input registers, or read holding registers with coils, etc.
  • not really elegant for write-only outputs, needs poller definition which is semantically wrong

I tried looking for a example (or convention) to follow but I could not find any general purpose binding that would have been ported for openHAB2, all the similar protocols (KNX, MQTT, HTTP, …) have not yet made it. As far as I can see, the things in other bindings currently refer to real physical entities, not abstract items like proposed here. I’m thinking if we are misusing the thing / channel abstraction here.

Of course one option is to keep the binding simple, and leave it to the rules to have transformations etc.

Best,
Sami

As laid out that way, endpoint->poller->readwrite->read + write
seems to read as a natural hierarchy i.e. understandable

Yes. I do think though that there is a place for a “null” poller, a poller setting that does not poll (presumably still allowing reads upon REFRESH only) which also happens to sit better with write-only. Maybe this element just wants another name! Can’t think of a good one.

Simply meant Modbus reads are (generally) by polling ; Modbus writes are on-change. So defining read and write paths/methods separately is not unexpected.

Thanks @rossko57, really appreciate the comments!

there is a place for a “null” poller, a poller setting that does not poll

Well, come to think of it, I have already experimented with period=0 to mean “no polling”, so I think that could be used here…

I like the alternative 2 better now – it’s a great bonus not to refer to channel UIDs, sounds too manual and beats the point of whole thing hierachy.

The only one downside remains. Is it common to have a use case where we would like to read and write different “types”, e.g. reading holding registers and writing coils with same item? I think the most complex case we support with the current binding is the rollershutter items, and in the original pull request (and the links therein) I could not find an example where this would have been done.

Of course, even in such use cases one build proxy items, rules etc. to make it work.

Best,
Sami

Edit : additional caveat with alternative 2. If one has to read the data in two pieces (e.g two sets of registers), those cannot be combined into same readwrite thing.

Not something I have seen or can imagine using. Given the huge diversity of Modbus devices and slackness in interpreting the “rules”, I think you’d be on a hiding to nothing (if you follow the idiom!) trying to accommodate complex machines.
Modbus is simple at heart, indeed dumb by modern standards, but simple building blocks can allow for whole factory processes. I would say OH should follow that philosophy and keep the binding relatively simple.

So long as we can define in/out separately and optionally, and can use transforms - something like a rollershutter should be manageable with rules? Build a library of templates for Brand X rollershutters, Brand Z airconditioner etc.

As another “test of concept”, would this approach work with that weird Phoenix Contact setup from a while back? I think so, as ins & outs can separated, and REFRESH would be usable.

Unrelated thoughts - supporting 32-bit write? Implies triggering a write from OH Item change as usual, and a multi-register FC16 write, not too difficult?

Yeah with that phoenix one of the issues was writing individual bits to register. That would not be solved by above Thing setup alone. Have to remember the write multiple / write single register support, though.

As discussed else where writing values that are less than 16 bits (bit, int8) are problematic conceptually. With 32bit types it’s easy as you said, just not implemented.

I’m thinking of removing broken features such as writing 8bit integers (current binding writes 16bit integers), and logging warning that write was discarded:

  • <16 bit (bit, int8) read: will be supported
  • <16 bit (bit, int8) write: will not be supported (at least in the first phase), will log warning. Current binding writes the value as 16bit integer (overwriting the whole register with 0/1 value, for example) which is quite ockward.
  • =16bit (int16) read & write: will be supported
  • 16 bit read (int32, float32): will be supported

  • ``>16 bit write (int32, float32): might be supported, will consider this

Other features that I’m planning to drop

  • support for UP/DOWN & INCREASE/DECREASE commands. Current binding increases or decreases last polled value by one (buggy once again with value types, and has the same conceptual issues as writing of <16bit types). With transformations and rules one can convert the commands to numeric values of course.

I would say OH should follow that philosophy and keep the binding relatively simple.

So long as we can define in/out separately and optionally, and can use transforms - something like a rollershutter should be manageable with rules? Build a library of templates for Brand X rollershutters, Brand Z airconditioner etc.

Indeed, I think this is something to look after. I argumented against having the “single-brand” roller shutter implementation in the modbus binding here.

On the other hand, it seems that rules and “proxy items” are really something the community hated with roller shutters, see this response for example. The extended item syntax helped the users to formulate these kind of cases in a straightforward fashion, without additional rules and proxy items.

I do agree with you that it makes sense to have the bindings simple, otherwise we end up having custom logic in each and every binding, which makes it hard for the user to learn the system. Also the binding maintenance burden increases. On other hand, I think we agree that some sort of abstraction and complexity is required, to support the typical use cases such as 32bit floats over modbus (instead of just exposing 16bit integers and letting users to do the conversions with rules).

The functionality provided by the extended item syntax goes to the gray area, I think. Perhaps it is too powerful (read: complex) to be included in the binding, and we should encourage users to use rules instead. Might be tough to migrate existing configuration though if the functionality requires a lot more logic etc…

I keep reading about “re-usable” rules and “script libraries” with openHAB2, so I think we might have something coming that way. If we would have rule libraries, perhaps one could share e.g. “roller shutter logic” in a easy way, and the binding itself could remain simple.

Let’s see if others have any feedback, have to think this for a while and decide what would be the best way.

Best
Sami

That seems reasonable. Or maybe incorporate in initial config validation, there has been a moan because impossible settings fail at runtime instead of bootup.

Yes, I see that. Personally I find the rollershutter Item concept difficult to follow - many different real-world implementations in terms of up/down/stop/go, position etc. But thats just me, I don’t have any! I understand the attraction for others, instant UI and so on.

Yes please folks :smiley:

@ssalonen: thx for working on this. I will help with testing :slight_smile:

1 Like

Hi @mbs38!

You still have that super performant modbus slave?

I would be interested what is the cpu usage with openhab2 (using current modbus binding) with all changes are updated to event bus. If it’s not an performance issue I would prefer to drop the updateunchangeditems configuration parameter.

Best
Sami

Sure. The system with about 10 devices on the bus has been running 24/7 ever since and is in constant use :slight_smile:

So you want to make updateunchangeditems=true the only behaviour? Well that is okay by me. At least we would get rid of Issue 4870 once and for all. I’ve been running the system with updateunchangeditems=true for months and the problem described in Issue 4870 hasn’t hit me again.

CPU usage is around 2,5% to 5% on both cores. The system is an Intel(R) Core™2 Duo CPU E6850 running at 3.00GHz and I’m using Arch Linux. Running openhab2+Modbus binding at a decent polling rate on a RaspberryPi however is a nightmare even with very few items :stuck_out_tongue:

Best,
Max

Thanks Max!

Yeah I would like to get rid of it exactly because of that issue.

Ok I did not know that you have beefy cpu, I think the test would require raspberry pi or similar as you mentioned.

Best
Sami

Testing on “high power” hosts (I run on a Windows dual P4) is valid and does show up different issues. I had lots of “new” race conditions to sort out when migrating from an elderly laptop. It is of course equally important to test on slower platforms.

Not really ready to go with OH2 yet myself, the lack of basic login password is off-putting. Yes I know, reverse proxy etc., but I want to avoid more subsystems to maintain.

Can’t see a problem with enforced updateunchangeditems=true. Out of interest, how does that interact with ‘expire’ binding - ‘invisible’ updates restart expiry or no?

Thanks for the reply!

According to expire binding documentation

If another binding is repeatedly updating the state of the item to be the same state it already was, the expiration timer will continue to be reset into the future. Dedicating an item to the expiration function (so it doesn't receive repeated updates from another binding) would avoid unwanted behavior, should it apply in your case.

I think the warning above would apply, correct?

Best
Sami

That is the behaviour that would be taken away. I can imagine someone currently using expire to detect e.g. a failed modbus device.

There should be alternative ways to do that, if the Modbus binding updates Items to UNDEF (or whatever it is in OH2!) upon failure.
Or by looking at status of Things.

So I do not think that should be a stopper for removing this option, and reducing overheads.

EDIT - the standard ‘Undefined’ Item value in OH2 is in fact NULL (distinct from null meaning no value).
I presume the Modbus binding should set read Items to NULL when retries all fail. We do not want some special UNDEF value or something instead, right?
What about write failure - any change in Item, or rely on Thing status for those who want to check? Most write Items would in reality be read/write so the next read poll would usually pick it up.

There should be alternative ways to do that, if the Modbus binding updates Items to UNDEF (or whatever it is in OH2!) upon failure.

Agree on this. Good point about Thing status, that sounds like the right way to handle the situation (although there is no
support in scripts as trigger, yet)… Also we could have additional channels for diagnosing issues, similar to exec binding provides exit code, time of last execution etc.

Best,
Sami

Info only - Thing status can now be used to trigger rules, which for Modbus users allows for creating error management rules.

1 Like

I’m trying to post up first version of the binding to the IOT marketplace. I have tested it very superficially but would like to start gathering first feedback already.

At this stage only TCP connections are supported, will implement serial support later.

UPDATE : the binding is now in the eclipse market place :

Both the transport and binding should be installed for a working installation

Best,
Sami

The binding follows the thing hierachy described in here (Alternative proposal (better?) version).

So you have to define the following things

  1. Connection, e.g. 192.168.1.100 port 502.
  • you can define parameters specific to endpoint, such as the the time between transactions etc. (previously in the old binding these were in the connection string)
  1. Poll definition (use connection as bridge)
  • what to poll (holding register, input register, coils, discrete inputs)
  • how often to poll (use zero to disable polling!)
  • how many items to poll, starting from what index
  1. readwrite definition (use poller as bridge): gathers different “read rules” and “write rules”, similar to item config string in the old binding
  • no configuration
  1. read definition, optional, use readwrite as bridge
  • specify the index (relative to polled items) from which to read, how to read it (valuetype), trigger and transform a bit similarly as with old binding
  • TODO: need to document this more carefully and improve the help text in UI
  1. write definition, optional, use readwrite as bridge
  • now should support non-16bit writing, e.g. writing float32
  • what modbus item to write: coil or holding register
  • address to write, not relative to polled data
  • how to write: value type
  • transform and trigger as with old binding
  • TODO: need to document this more carefully and improve the help text in UI

It’s most convenient to use readwrite channels to read the data; values from all read are aggregated from all the read things. This is similar how old binding item state reflected all the “read definitions” in the config string.

Please comment!

Best,
Sami

Serial slaves should be now supported as well, jenkins is building so tonight there should be a test version available in the IOT store.

Any feedback or testing would be much appreciated!