Modbus support for transformations, roller shutter items, read-only items, write-only items, and others

Update: This feature is now part of modbus binding 1.10.0.

Hello everyone!

Originally discussed in here, there has been a need for having transformation support for opnehab. Some of the more complicated use cases (e.g. rollershutter items) could be implemented simply using transformations.

I have been implementing this support for a while now, and feel confident sharing the first test version with the community. Along this update comes support for

  • writing to different address based on the command received
  • declaring/overriding value type in the items
  • read-only and write-only items (use case with some slave manufacturers)
  • support for all item types, as long as necessary transformations are used (see rollershutter example below)

The item configuration syntax was extended to support these new use cases. You can notice that MQTT and HTTP bindings have been the inspiration.

All feedback is most welcome!

Extended item configuration

Now the item configuration string can consist of one or more “IO-definitions”, describing how the data is read from modbus, or data written to modbus.

Read definition:

<[slaveName:readIndex:trigger=TRIGGER,transformation=TRANSFORMATION,valueType=VALUETYPE]

Write definition:

>[slaveName:writeIndex:trigger=TRIGGER,transformation=TRANSFORMATION,valueType=VALUETYPE]

All the keyword arguments after index are optional. Defaults are such that they correspond to binding behaviour currently. Multiple read/write definitions can be specified with commas. Old item syntax is still supported for backwards compatibility.

Explanation of different arguments

  • trigger: a string matching command (write definitions) or state (read definitions). If the command/state does not match the trigger value, the command/state is not processed by this write/read definition. Use * to process all (overrides slave’s updateunchangeditems). Use CHANGED with read entries to handle only changed values (similar to updateunchangeditems=false). Use default to handle all or just the changed values, depending on slave updateunchangeditems parameter (this might be buggy at the moment – will fix it later). If omitted, uses default.
  • transformation: transformation to use interpreting the result. Can be either default (no transformation, i.e. pass value as is), or SERVICE(ARG) to refer to transformation service. Any other value than the above types will be interpreted as static text, in which case the actual content of the message is ignored. Can If omitted, uses default. The transformations can convert to string representing command and state types of the item. You can also always use numbers (DecimalType), ON/OFF and OPEN/CLOSED.
  • valueType: valueType to use when interpreting the register. Use DEFAULT to refer to slave definition’s valueType. If omitted, uses default.

Examples

JS transformation (scaling)

This example multiplies the DecimalType commands by 10 when writing to modbus, and divides the values by 10 when reading from modbus.

default.items:

// 
Number NumberItem "Number [%.1f]" <temperature> {modbus=">[slave1:0:transformation=JS(multiply10.js)],<[slave1:0:transformation=JS(divide10.js)]"}

transform/multiply10.js:

// Wrap everything in a function
(function(i) {
    return Math.round(parseFloat(i, 10) * 10);
})(input)
// input variable contains data passed by openhab

transform/divide10.js:

// Wrap everything in a function
(function(i) {
    return parseFloat(i) / 10;
})(input)
// input variable contains data passed by openhab

Rollershutter example

(inspired by [modbus] enhance modbus binding for rollershutter items #4654)

This is an example how different Rollershutter commands can be written to MODBUS.

Roller shutter position is read from register 0, UP(=1)/DOWN(=-1) commands are written to register 1, and MOVE(=1)/STOP(=0) commands are written to register 2.

default.items:

Rollershutter RollershutterItem "Roller shutter position [%.1f]" <temperature> {modbus="<[slave1:0],>[slave1:1:trigger=UP,transformation=1],>[slave1:1:trigger=DOWN,transformation=-1],>[slave1:2:trigger=MOVE,transformation=1],>[slave1:2:trigger=STOP,transformation=0]"}

default.sitemap:

sitemap demo label="Main Menu" {
    Switch item=RollershutterItem label="Roller shutter [(%d)]" mappings=[UP="up", STOP="X", DOWN="down"]
}

Read-only items

Number NumberItem "Number [%.1f]" <temperature> {modbus="<[slave1:0]"}

Write-only items

Number NumberItem "Number [%.1f]" <temperature> {modbus=">[slave1:0]"}

Set coil to true on any command

(inspired by [Modbus] Coil reset only after item update to ON (OFF excepted) #4745)

Reads from index 0, writes to index 1. All writes (no matter what command) are converted to 1.

Number NumberItem "Number [%.1f]" <temperature> {modbus="<[slave1:0],>[slave1:1:transformation=ON]"}

Related github issues

Best,
Sami

7 Likes

Hey!
Great thing! Thank you very much for your work!!!
I installed the Debian Package and use the Modus binding 1.9 … How do I replace it with your version?

I think the docs (http://docs.openhab.org/developers/development/compatibilitylayer.html#how-to-use-openhab-1x-add-ons-that-are-not-part-of-the-distribution) are not the solution, right?

Thanks!
Helmut

You should be fine following the instructions

  • As with openHAB 1.x, simply take the jar file of your add-on and place it in the ${openhab.home}/addons folder

Best,
Sami

Edit : you might want to uninstall the modbus debian package first

… I already placed it in the addon folder with no success. Unfortunately, there is no “modbus” debian package to uninstall. There is openhanded “itself”, all addons and legacy.

I’m not sure what to do… I’m more a user than an developer in this field…

:slight_smile:

You are using openhab2 right? Do you get errors following the official docs? What does the logs say?

If the guide does not work, perhaps we need to make a separate thread about it…

Best
Sami

Hello.

The module works for me as expected. I just have a problem with many modbus TCP connections in TIME_WAIT state. Seems that module open new connection for each request, but not close them. I don’t know if it is a solution, but could you check if you have incorporated / can iconrporate the code described here:


I don’t have the sources of 1-10-SNAPSHOT, so I cannot do it myself.

Regards,
ANdrzej Kowalczyk
I

I’m sorry…

My mistake. I’ve dumped the traffi and it seems, that connections are closed normally. Please forget about my request.

Andrzej

Hallo Sami!
I’m sorry but it took me a while to test your binding. For my purpose (roller shutter) it is working fine.

The only thing is, that the event “move” is not triggered.

Enjoy your weekend!
:slight_smile:

1 Like

The only thing is, that the event “move” is not triggered.

So there is an issue? Could you please clarify what do you mean by this?

Please could you provide me verbose logs (follow this guide for openhab1 and this guide for openhab2) with the relevant configuration?

Best,
Sami

Hey!
I mean that I can see in the openhanded log, the events “up”, “down”, “stop” but not the event “move”… so obviously I can’t the any value change via modbus :wink:

Sprocky

OK got it! So in your case you are not using MOVE event at all :slight_smile: You can remove it from configuration then, if you like

Best,
Sami

… so to understand me correctly. I tried to use it without success. Nevertheless I do not need it :wink:

Sprocky

Oh! In that case I would be interested to see how you tried to test the MOVE command. Could you please post that here? Modbus configuration, Item configuration, sitemap and relevant rules should be enough.

I have posted pull request in github to merge this feature to the official code base and thus all possible bugs are of interest.

Best
Sami

Hey!

This is the openhab log after pressing the “up”, “down” and “stop” button.

19:24:30.645 [INFO ] [smarthome.event.ItemCommandEvent    ] - Item 'RollershutterItem' received command UP
19:24:31.279 [INFO ] [smarthome.event.ItemCommandEvent    ] - Item 'RollershutterItem' received command STOP
19:24:32.558 [INFO ] [smarthome.event.ItemCommandEvent    ] - Item 'RollershutterItem' received command DOWN

Additionally, I expect the event “move” after pressing “up” or “down” but nothing happens…

The modbus config is like that…

tcp.shutter_down.connection=10.0.1.2:502:60:0:0:3:100
tcp.shutter_down.id=0
tcp.shutter_down.type=coil
tcp.shutter_down.start=12333
tcp.shutter_down.length=13
tcp.shutter_down.valuetype=bit

And the item file …

Rollershutter 	RollershutterItem 				"Roller shutter position [%d %%]" 		(gArbeitszimmer,gModbus){modbus="<[shutterposition:11],>[shutter_up:11:trigger=UP,transformation=1],>[shutter_down:11:trigger=DOWN,transformation=1],>[shutter_up:11:trigger=STOP,transformation=0],>[shutter_down:11:trigger=STOP,transformation=0],>[shutter_move:11:trigger=MOVE,transformation=1]", autoupdate="false"} 

… so it is :wink:

You’ll need to change your UI to make a MOVE button, or construct a rule triggered by other button presses if you want a MOVE. What are you wanting to do with it?

1 Like

Hey!
Personally nothing. I just tried the example from the first post and checked what is happening. So I recognized that no event was triggered …

:wink:

Good thing we sorted this out. This is by design. It does not generate events, the configuration just tells which commands to process and how to do it. If you do not send MOVE, then that part of item configuration is not activated. Essentially the MOVE is handled exactly the same way as STOP or UP, for example.

Hope this clarifies it!

Best
Sami

1 Like

This feature is now merged, and is part of standard 1.10.0 (SNAPSHOT).

2 Likes

Hi @ssalonen,
first of all many thanks for the great extensions, they are beautifying a lot!

Second I’m testing the extended config format of the 1.10. Snapshot artifact #1457 with OH2 and I’m receiving the following config-parsing error.

Am I missing something? Could you copy?

Config:

Switch nilan_onoff "Device main power" {modbus="nilan_modes:0"}
Number nilan_user_tempset "Target air temp [%d °C]" {modbus="<[nilan_modes:3]"} 

Log:

2017-04-16 23:25:19.686 [INFO ] [el.core.internal.ModelRepositoryImpl] - Refreshing model 'nilan.items'
2017-04-16 23:25:19.698 [ERROR] [el.item.internal.GenericItemProvider] - Binding configuration of type 'modbus' of item 'nilan_user_tempset' could not be parsed correctly.
org.eclipse.smarthome.model.item.BindingConfigParseException: For input string: "3]"
	at org.openhab.core.binding.internal.BindingConfigReaderDelegate.processBindingConfiguration(BindingConfigReaderDelegate.java:50)[177:org.openhab.core.compat1x:2.1.0.201703310852]
	at org.eclipse.smarthome.model.item.internal.GenericItemProvider.internalDispatchBindings(GenericItemProvider.java:312)[124:org.eclipse.smarthome.model.item:0.9.0.201703201701]
	at org.eclipse.smarthome.model.item.internal.GenericItemProvider.internalDispatchBindings(GenericItemProvider.java:284)[124:org.eclipse.smarthome.model.item:0.9.0.201703201701]
	at org.eclipse.smarthome.model.item.internal.GenericItemProvider.processBindingConfigsFromModel(GenericItemProvider.java:167)[124:org.eclipse.smarthome.model.item:0.9.0.201703201701]
	at org.eclipse.smarthome.model.item.internal.GenericItemProvider.modelChanged(GenericItemProvider.java:346)[124:org.eclipse.smarthome.model.item:0.9.0.201703201701]
	at org.eclipse.smarthome.model.core.internal.ModelRepositoryImpl.notifyListeners(ModelRepositoryImpl.java:281)[123:org.eclipse.smarthome.model.core:0.9.0.201703201701]
	at org.eclipse.smarthome.model.core.internal.ModelRepositoryImpl.addOrRefreshModel(ModelRepositoryImpl.java:136)[123:org.eclipse.smarthome.model.core:0.9.0.201703201701]
	at org.eclipse.smarthome.model.core.internal.folder.FolderObserver.checkFile(FolderObserver.java:240)[123:org.eclipse.smarthome.model.core:0.9.0.201703201701]
	at org.eclipse.smarthome.model.core.internal.folder.FolderObserver.processWatchEvent(FolderObserver.java:308)[123:org.eclipse.smarthome.model.core:0.9.0.201703201701]
	at org.eclipse.smarthome.core.service.WatchQueueReader.run(WatchQueueReader.java:209)[99:org.eclipse.smarthome.core:0.9.0.201703201701]
	at java.lang.Thread.run(Thread.java:745)[:1.8.0_121]

P.s. If I should rather open an issue next time, please let me know.

Hi @nickma82!

Unfortunately I cannot reproduce the issue you mentioned. Perhaps you have old binding installed? Try running bundle:list |grep -i modbus

Or perhaps you are suffering from this openHAB2 issue? https://github.com/openhab/openhab1-addons/issues/5084

Best,
Sami