Modbus performance management in openHAB 2

Selective data

Just because you can read data from your Modbus slave doesn’t mean you should. Review if you really need data to end up as an Item state.

For example, slave device firmware version – there’s no point updating an Item with that every second of course. But do you need it at all?

Don’t forget you can have a poller reading a block of registers, but you do not have to have a data Thing (or Item) for every register.

Modbus writes

Since writing to Modbus device registers is carried out on demand rather than on a polling schedule, there isn’t really any “tuning” to do here. The binding is not structured to carry out block writes of many Item commands, as this is very rarely needed.

Polling frequency

It’s more or less a common standard to poll everything once per second in Modbus set ups.

The openHAB Modbus binding allows us the luxury of polling different slaves or different blocks of registers at different rates, so let’s explore the possibilities.

For example for a pushbutton input, you really do want a frequent poll, since a thumb press takes less than a second.

A room temperature sensor however – there’s probably no need to read that more than once a minute.

Polling coils to see what state a relay is in is something worth considering in more detail. If you always control the relays from openHAB, do you need to read this back often? Or even at all? The binding does allow you to configure poller Things that don’t actually poll, and data Things (registers) that are write-only.

With use of no-poll pollers, you can implement a read-on-demand scheme. Issuing a REFRESH command to a Modbus Item from a rule will cause a one-time read poll (along with any other channels/Items also belonging to that poller). That would be a rare case, but has uses. For example, initialising an otherwise write-only Item at openHAB start up, by reading the slave.

Usually you will reach a compromise here, because you will want some of the registers in a poller’s ‘block’ more often than others, but the poll rate for the whole will have to be set by the most frequently needed. There’s not much benefit in splitting a poller Thing into two or more blocks, as you would then just be increasing the total number of polls and adding Modbus workload instead.

Indeed it is worth looking at the opposite to reduce Modbus traffic – can you combine poller Things? Sometimes you will have a slave with say registers 15 and 19 of interest, but registers 16-18 are undefined by the manufacturer. Some slaves – but not all – will let you read a block of registers including undefined ones. You could try to set up one poller Thing for all registers 15-19, with data Things for just 15 and 19. (Caution – the design of Modbus protocol limits you to around 120 registers in one poll)
“But I don’t want those other registers!” That’s fine, just ignore them. The overheads for your host, network, and slave of one large poll are less than two small polls…

Most likely, after reviewing your polling setup, you could still end up with many Items being more frequently updated than you really need, just to get an important few regularly.

Update “unchanged”

This binding feature is a powerful tool to reduce unwanted Item updates. I’ve deliberately saved this for last, because there are worthwhile benefits from looking critically at the other areas already mentioned.

The binding could update each channel (and hence each Item) every time data is polled from the modbus device. But in fact the binding remembers the previous polled state. If the data does not change from one poll to the next, the binding can avoid updating the channel (and so avoid creating an Item update on the openHAB event bus).

This “remembered” state is eventually considered to go “stale”, and a channel/Item update is made even if it hasn’t changed.

If the polled data changes, an immediate update is always made.

The ‘helper’ channel lastReadSuccess is still updated at every poll, if you use that.

The data Thing parameter updateUnchangedValuesEveryMillis controls the maximum time a channel/Item will go without an update. By default this is 1000mS, but you can set a much larger number here and so avoid unnecessary Item updates for minutes, hours or even days.

This setting can be different for each data Thing, and so different for each Item. This can be useful when you want to use some Item updates to trigger periodic rules or persistence storing. You should consider if, and when, you need regular updates for charting purposes and suchlike.

Typically you might set updateUnchangedValuesEveryMillis=3600000 for updates at least hourly. This would reduce the load on openHAB’s event bus by many thousand events – per Item!

Note, that if you use the expire binding technique to detect Items that don’t get updated, you will need to set the Item’s expire time to be longer than the data Thing’s updateUnchangedValuesEveryMillis time.

Note also, that the “remembered state” is that state sent to the channel after any data Thing transformation. You may have a transform that rounds a number for example, and it is possible for the polled registers to change value without changing the channel state.

Summary

A fast polling service like Modbus used with large numbers of data inputs can highlight performance limitations in openHAB’s events bus and persistence services. With careful use of the available tools, we can greatly reduce the impact of large Modbus configurations and still have responsive and timely data available.

4 Likes