Modbus openHAB2 binding available for alpha testing

Almost finished migrating - This is just great, love it - way better that christmas eve :slight_smile:

It may be late in the day to consider this, but some other bindings use a form of XML to hold device specific info. I know little about this, but am thinking of it as a ā€˜templateā€™ system.

One might imagine a flexible, configurable - and therefore complicated - Modbus2 binding. With a set of pre-configured device specific XML templates or models, that can be selected from by user. They would need to configure basic info (e.g. address, ID) since discovery ainā€™t ever going to work in Modbus.

This is way over my head but looks interesting

Thanks for this idea.

Yeah, perhaps we will have device specific ā€œtemplatesā€ at some point but it seems that coding will be necessary, and itā€™s not possible to ā€œtemplateā€/create things.

One of the targets with this new development was to separate modbus protocol (transport) from the binding. I think it is now much more separated, and basically with relative ease it should be possible to a new binding that uses the modbus protocol (modbus transport) and introduces special things for particular use cases.

The link you pasted is a basic pattern to make things things configurable, something that is already done in this new thing.

Iā€™m pretty far actually with the alternative thing structure described above, will publish that for testing and letā€™s see how that feels like.

Hi

Iā€™m trying to do a simple invert, it was working with the old binding - iā€™m trying to figure out what I did wrong.
JSONPath Transformation is installed

[Things]

Bridge poller K104_BDD [ start=3422, length=3, refresh=5000, type=ā€œinputā€ ] {
Bridge readwrite Window_GF_Bryggers_Door {
Thing read I3422 [ start=2, transform=ā€œJS(mbinvert.js)ā€, trigger="", valueType=ā€œuint16ā€, type=ā€œinputā€ ]
Thing write I3422 [ start=2, transform=ā€œJS(mbinvert.js)ā€, trigger="
", valueType=ā€œuint16ā€, type=ā€œinputā€ ]

[Item]

Contact Window_GF_Bryggers_Door ā€œFordĆør [MAP(da.map):%s]ā€ (GF_Bryggers, Windows)
{ channel=ā€œmodbus:readwrite:endpointSmarthouse:K104_BDD:Window_GF_Bryggers_Door:contactā€ }

[mbinvert.js]

(function(i) {
var t = i ; // allow Undefined to pass through
if (i == ā€˜OPENā€™) {
t = ā€˜CLOSEDā€™ ;
} else if (i == ā€˜CLOSEDā€™) {
t = ā€˜OPENā€™ ;
}
return t ; // return a string
})(input)

It seems that your post is malformed, please format the code as described here

Some other comments

  • trigger is empty (or just code format issue?), matches only empty commands. Check paperUI for more information. Use wildcard * to match all
  • type is only applicable to write
  • use verbose logging to understand how the transform now works. Some specifics might be slightly differentā€¦

Sami

Hi

I have changed the trigger to * match all, removed the ā€œThing writeā€ (Only need the status) and removed type from ā€œThing readā€

My invert function still gives me the wrong state, Ill try logging in verbose to see whats happening

// function to invert Modbus binary states
// input variable i contains data passed by OpenHAB binding
(function(i) {
    var t = i ;      // allow Undefined to pass through
    if (i == 'OPEN') {
    	t = 'CLOSED' ;
    } else if (i == 'CLOSED') {
    	t = 'OPEN' ;
    }
    return t ;      // return a string 
})(input)

Any luck?

I think the transformation input has changed a little from the old binding. On read, the transformation gets the numeric data as input. With coils or discrete inputs this means 0 or 1. On write, the transformation gets the command as is.

I hope that verbose logs would tell more what is inputted to the transformation.

YES :slight_smile: As you explained, the new binding gets the inputs as 0 or 1.

I changed the transformation function to this, and it works perfect.

// function to invert Modbus binary states
// input variable i contains data passed by OpenHAB binding
(function(i) {
    var t = i ;      // allow Undefined to pass through
    if (i == '1') {
    	t = 'CLOSED' ;
    } else if (i == '0') {
    	t = 'OPEN' ;
    }
    return t ;      // return a string 
})(input)

Would you actually need slightly a different transformation for write transformation? Or you can generalize what you have to both cases.

In this case I only need to read the state of a holding register (Door/Window) contact. The holding register is in my case inverted 0=open 1=closed.

Did I understand your question correct?

OK, if you are just reading then there is no issue.

In this post you did have

Thing write I3422 [ start=2, transform=ā€œJS(mbinvert.js)ā€, trigger="", valueType=ā€œuint16ā€, type=ā€œinputā€ ]

Btw, you are reading input registers, not holding registers. Hope that is what you are after.

If you do not need the write, you can actually just remove the write thing.

Yes in this scenario iā€™m only reading, and just did a Cleanup and removed the write thing.

Can you explain how I enable ā€œWrite Multiple Holding Registersā€, I donā€™t use PaperUI?

I assume you mean that you want to use FC16 (write multiple holding registers) even when writing single register. You can set ā€œwriteMultipleEvenWithSingleRegisterā€ parameter to true in the write thing.

Note that when writing multiple registers (e.g. int32), function code 16 is always used.

One other thing to note, I will hopefully soon publish a new version of this experimental binding which has the streamlined thing structure as discussed in this thread. The idea is to get rid of read, write and readwrite; and replace them with a single thing called ā€œdataā€.

I will not remove the old things right away, to allow testing with both.

Great looking forward to try out the new version :slight_smile:

Iā€™m trying to convert the last part of my old code to the new binding, but having alot of trouble with a Modbus device that needs to have WriteMultiple=true - I did what you wrote and I can see in Paper-UI itā€™s enabled for the wanted Write thing.

I do get this when I try to write to the device:

17:14:35.308 [ERROR] [ort.modbus.internal.ModbusManagerImpl] - Error when executing write request (org.openhab.io.transport.modbus.ModbusWriteRegisterRequestBlueprintImpl@b11b43a): net.wimpi.modbus.ModbusSlaveException Error Code = 1
17:14:35.309 [ERROR] [odbus.handler.ModbusWriteThingHandler] - Unsuccessful write: net.wimpi.modbus.ModbusSlaveException Error Code = 1

My .Thing config

Bridge modbus:tcp:endpointNilan [ host="192.168.100.30", port=502, id=30 ] {
Bridge poller Nilan_Holding_Control [ start=1000, length=8, refresh=5000, type="holding" ] {
        Bridge readwrite Nilan_Control_Type { 
	         Thing read NilanH1000 [ start=0, transform="default", trigger="*", valueType="uint16" ]  
		 Thing write NilanH1000 [ start=0, transform="default", trigger="*", valueType="uint16", type="holding", writeMultipleEvenWithSingleRegister="true" ]  
		 }
	Bridge readwrite Nilan_Control_RunSet { 
		 Thing read NilanH1001 [ start=1, transform="default", trigger="*", valueType="uint16" ]    
		 Thing write NilanH1001 [ start=1, transform="default", trigger="*", valueType="uint16", type="holding", writeMultipleEvenWithSingleRegister="true" ]		 
		 }
	Bridge readwrite Nilan_Control_ModeSet {
		 Thing read NilanH1002 [ start=2, transform="default", trigger="*", valueType="uint16" ]  
		 Thing write NilanH1002 [ start=2, transform="default", trigger="*", valueType="uint16", type="holding", writeMultipleEvenWithSingleRegister="true" ]  
		 }	
	Bridge readwrite Nilan_Control_VentSet {
		 Thing read NilanH1003 [ start=3, transform="default", trigger="*", valueType="uint16" ]  
		 Thing write NilanH1003 [ start=3, transform="default", trigger="*", valueType="uint16", type="holding", writeMultipleEvenWithSingleRegister="true" ]  
	  	 }
	Bridge readwrite Nilan_Control_TempSet {
        	 Thing read NilanH1004 [ start=4, transform="JS(divide100.js)", trigger="*", valueType="uint16" ] 
		 Thing write NilanH1004 [ start=4, transform="JS(multiply100.js)", trigger="*", valueType="uint16", type="holding", writeMultipleEvenWithSingleRegister="true" ]   
		 }
	Bridge readwrite Nilan_Control_ServiceMode { 
		 Thing read NilanH1005 [ start=5, transform="default", trigger="*", valueType="uint16" ] 
		 Thing write NilanH1005 [ start=5, transform="default", trigger="*", valueType="uint16", type="holding", writeMultipleEvenWithSingleRegister="true" ]  
		 }
	Bridge readwrite Nilan_Control_ServicePct {
		 Thing read NilanH1006 [ start=6, transform="default", trigger="*", valueType="uint16" ] 
		 Thing write NilanH1006 [ start=6, transform="default", trigger="*", valueType="uint16", type="holding", writeMultipleEvenWithSingleRegister="true" ]   
		 }	
	Bridge readwrite Nilan_Control_Preset {
		 Thing read NilanH1007 [ start=7, transform="default", trigger="*", valueType="uint16" ] 
		 Thing write NilanH1007 [ start=7, transform="default", trigger="*", valueType="uint16", type="holding", writeMultipleEvenWithSingleRegister="true" ]   
	  	 }	
	

  }

}

Do you have a clue of what iā€™m doing wrong here?

Best Nanna

Hmmā€¦ According to this error code 1 means that the function code is illegal. So the slave is responding with this error codeā€¦

Could you share your old binding config just to double check and correlate for differences?

Perhaps also you can enable more verbose log, trace level for net.wimpi.modbus, org.openhab.io.transport.modbus and org.openhab.binding.modbus. (log:set TRACE org.openhab.io.transport.modbus for example if I recall correctly) and see if that reveals more.

Really appreciate the effort of testing this out. Huge Thanks!

Best
Sami

Iā€™m the one thanking YOU for your effort, making the most important binding ā€˜Modbusā€™.

I have included the relevant part of the modbus.cfg and the binding.

tcp.nilan_holding_control.connection=192.168.100.30:502:60:0:0:3:100
tcp.nilan_holding_control.id=30
tcp.nilan_holding_control.start=1000
tcp.nilan_holding_control.length=8
tcp.nilan_holding_control.type=holding

The Binding

Number Nilan_Control_Type             "Machine type select [%d]"                                             	       (gNilan) {modbus="nilan_holding_control:0"}
Switch Nilan_Control_RunSet           "User on / off select"                                           <switch>        (gNilan) {modbus="nilan_holding_control:1"}
Number Nilan_Control_ModeSet          "User operation mode select [MAP(nilan_control_modeact.map):%s]" <settings>      (gNilan) {modbus="nilan_holding_control:2"}
Number Nilan_Control_VentSet          "User ventilation step select [MAP(nilan_ventset.map):%s]"       <fan_ceiling>   (gNilan) {modbus="nilan_holding_control:3"}
Number Nilan_Control_TempSet          "User temperature setpoint [%.1f Ā°C]"                            <temperature>   (gNilan) {modbus="<[nilan_holding_control:4:transformation=JS(divide100.js)], >[nilan_holding_control:4:transformation=JS(multiply100.js)]"}
Number Nilan_Control_ServiceMode      "Service mode select [MAP(nilan_control_servicemode.map):%s]"    <lock>          (gNilan) {modbus="nilan_holding_control:5"}
Number Nilan_Control_ServicePct       "Service mode capacity [%.1f %%]"                                                (gNilan) {modbus="nilan_holding_control:6"} 
Number Nilan_Control_Preset           "Request preset to factory [%d]"                                                 (gNilan) {modbus="nilan_holding_control:7"}

Nanna

I have set log to TRACE, and this what I get when trying to write to the register:

08:23:37.116 [INFO ] [smarthome.event.ItemCommandEvent     ] - Item 'Nilan_Control_VentSet' received command 4
08:23:37.117 [INFO ] [smarthome.event.ItemCommandEvent     ] - Item 'Smarthouse_Motorventil' received command OFF
08:23:37.119 [TRACE] [ling.ModbusSlaveConnectionFactoryImpl] - Validating endpoint ModbusTCPSlaveEndpoint@4ad7be81[address=192.168.100.30,port=502] connection TCPMasterConnection@58b25fd5[socket=Socket[addr=/192.168.100.30,port=502,localport=37848]] -> true
08:23:37.119 [TRACE] [ort.modbus.internal.ModbusManagerImpl] - borrowing connection (got Optional[TCPMasterConnection@58b25fd5[socket=Socket[addr=/192.168.100.30,port=502,localport=37848]]]) for endpoint ModbusTCPSlaveEndpoint@4ad7be81[address=192.168.100.30,port=502] took 3 ms
08:23:37.137 [ERROR] [ort.modbus.internal.ModbusManagerImpl] - Error when executing write request (org.openhab.io.transport.modbus.ModbusWriteRegisterRequestBlueprintImpl@6371bc74): net.wimpi.modbus.ModbusSlaveException Error Code = 1
08:23:37.138 [TRACE] [ling.ModbusSlaveConnectionFactoryImpl] - destroyObject for connection TCPMasterConnection@58b25fd5[socket=Socket[addr=/192.168.100.30,port=502,localport=37848]] and endpoint ModbusTCPSlaveEndpoint@4ad7be81[address=192.168.100.30,port=502] -> closing the connection
08:23:37.138 [ERROR] [odbus.handler.ModbusWriteThingHandler] - Unsuccessful write: net.wimpi.modbus.ModbusSlaveException Error Code = 1
08:23:37.138 [TRACE] [ort.modbus.internal.ModbusManagerImpl] - Response for write (FC=134) 43 7f 00 00 00 03 1e 86 01 
08:23:37.139 [INFO ] [ome.event.ThingStatusInfoChangedEvent] - 'modbus:write:endpointNilan:Nilan_Holding_Control:Nilan_Control_VentSet:NilanH1003' changed from ONLINE to OFFLINE (COMMUNICATION_ERROR): Error with writing request org.openhab.io.transport.modbus.ModbusWriteRegisterRequestBlueprintImpl@6371bc74: net.wimpi.modbus.ModbusSlaveException: Error Code = 1
08:23:37.139 [TRACE] [ort.modbus.internal.ModbusManagerImpl] - returned connection for endpoint ModbusTCPSlaveEndpoint@4ad7be81[address=192.168.100.30,port=502]
08:23:37.139 [INFO ] [ome.event.ThingStatusInfoChangedEvent] - 'modbus:readwrite:endpointNilan:Nilan_Holding_Control:Nilan_Control_VentSet' changed from ONLINE to OFFLINE (COMMUNICATION_ERROR): Error with writing request org.openhab.io.transport.modbus.ModbusWriteRegisterRequestBlueprintImpl@6371bc74: net.wimpi.modbus.ModbusSlaveException: Error Code = 1
08:23:37.140 [INFO ] [ome.event.ThingStatusInfoChangedEvent] - 'modbus:write:endpointNilan:Nilan_Holding_Control:Nilan_Control_VentSet:NilanH1003' changed from OFFLINE (COMMUNICATION_ERROR): Error with writing request org.openhab.io.transport.modbus.ModbusWriteRegisterRequestBlueprintImpl@6371bc74: net.wimpi.modbus.ModbusSlaveException: Error Code = 1 to OFFLINE (BRIDGE_OFFLINE)
08:23:37.140 [INFO ] [ome.event.ThingStatusInfoChangedEvent] - 'modbus:write:endpointNilan:Nilan_Holding_Control:Nilan_Control_VentSet:NilanH1003' changed from UNKNOWN to ONLINE
08:23:37.140 [INFO ] [ome.event.ThingStatusInfoChangedEvent] - 'modbus:write:endpointNilan:Nilan_Holding_Control:Nilan_Control_VentSet:NilanH1003' changed from OFFLINE (BRIDGE_OFFLINE) to UNKNOWN
08:23:37.141 [INFO ] [ome.event.ThingStatusInfoChangedEvent] - 'modbus:readwrite:endpointNilan:Nilan_Holding_Control:Nilan_Control_VentSet' changed from OFFLINE (COMMUNICATION_ERROR): Error with writing request org.openhab.io.transport.modbus.ModbusWriteRegisterRequestBlueprintImpl@6371bc74: net.wimpi.modbus.ModbusSlaveException: Error Code = 1 to ONLINE
08:23:37.141 [INFO ] [ome.event.ThingStatusInfoChangedEvent] - 'modbus:write:endpointNilan:Nilan_Holding_Control:Nilan_Control_VentSet:NilanH1003' changed from ONLINE to OFFLINE (BRIDGE_OFFLINE): Read-write bridge Modbus read-write definition is offline
08:23:37.141 [INFO ] [ome.event.ThingStatusInfoChangedEvent] - 'modbus:read:endpointNilan:Nilan_Holding_Control:Nilan_Control_VentSet:NilanH1003' changed from OFFLINE (BRIDGE_OFFLINE): Read-write bridge Modbus read-write definition is offline to ONLINE
08:23:37.141 [INFO ] [ome.event.ThingStatusInfoChangedEvent] - 'modbus:read:endpointNilan:Nilan_Holding_Control:Nilan_Control_VentSet:NilanH1003' changed from ONLINE to OFFLINE (BRIDGE_OFFLINE)
08:23:37.142 [INFO ] [ome.event.ThingStatusInfoChangedEvent] - 'modbus:write:endpointNilan:Nilan_Holding_Control:Nilan_Control_VentSet:NilanH1003' changed from OFFLINE (BRIDGE_OFFLINE): Read-write bridge Modbus read-write definition is offline to ONLINE
08:23:37.142 [INFO ] [ome.event.ThingStatusInfoChangedEvent] - 'modbus:read:endpointNilan:Nilan_Holding_Control:Nilan_Control_VentSet:NilanH1003' changed from OFFLINE (BRIDGE_OFFLINE) to OFFLINE (BRIDGE_OFFLINE): Read-write bridge Modbus read-write definition is offline
08:23:37.143 [INFO ] [ome.event.ThingStatusInfoChangedEvent] - 'modbus:write:endpointNilan:Nilan_Holding_Control:Nilan_Control_VentSet:NilanH1003' changed from ONLINE to UNKNOWN
08:23:37.144 [INFO ] [ome.event.ThingStatusInfoChangedEvent] - 'modbus:write:endpointNilan:Nilan_Holding_Control:Nilan_Control_VentSet:NilanH1003' changed from UNKNOWN to ONLINE

Hi @ssalonen,

Is there anything I can test according to the connection handling?

Greetings,
Frederic

@FredericMa, please try the latest version from today. It should include the fix I described some time ago. Sorry for the delay, been quite busy with non-openHAB stuff :slight_smile:

@Nanna_Agesen, I notice that in the old binding you do not have writemultipleregisters enabled, but with the new binding you do have writeMultipleEvenWithSingleRegister=true. Perhaps try removing the writeMultipleEvenWithSingleRegister or set it false (the default)? Perhaps your slave does not accept the function code ā€œwrite multipleā€ (as indicated by the error code!).

@all :

I have put some effort to documentation, you can read it here: https://github.com/ssalonen/openhab2-addons/blob/modbus-openhab2-native-binding/addons/binding/org.openhab.binding.modbus/README.md

As you can see, the new binding docs are in the beginning, and old binding docs are now just appended in the end. Naturally this is just WIP, and eventually you would have nice single doc.

Also note that now there is new thing type data to replace read, write and readwrite things. The old things are still there so you can compare the two, hopefully still working as before. Please note that the read/write addresses with data are ā€œabsoluteā€, not relative to poll start as with read and write. Check docs for more explanation on the parameters.

The original concept behind data is described here: Modbus openHAB2 binding available for alpha testing . I have also implemented support for the JSON transformation output as described in the post to cover the more complex use cases.

Please, try it out and check if it feels more natural/simple now? I think I like the new structure better at least :slight_smile:

The old binding have writemultiableregisters enabled, it was in the top of my config, and I did not list it in my post.

I did a check with modbus poll, and it respond OK when I use fc-16 and gave me an error using fc-06.