Modbus openHAB2 binding available for alpha testing

Have a look in events log for the “mystery” Item value change, then you’ll know where to look in the debug log. There should be many successful read polls before that?

1 Like

I think I made a working solution, but it really gives no sense ?

I’m reading values between 0-100, i’m also seeing that value in my modbus tool.

If I use readtransform and divide the result by 1 it works :roll_eyes:

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

Brilliant fix! So, you’ve now got a working Dimmer Item with two different Modbus channels? Ah no, wait, this is just one holding register pair now isn’t it?

The transform may be circumventing some issue with number/string formatting or parsing into percentage. Might tie in with reported different Number/Dimmer behaviour?

Yes it is working 100% :slight_smile:

// #Smartlight Function
			    
Bridge poller Smartlight [ start=4700, length=42, refresh=1000, type="input" ] {
	    
	         Thing data Smartlight [ readStart="4702", readValueType="uint16", readTransform="JS(divide1.js)", writeStart="4738", writeValueType="uint32_swap", writeType="holding" ]

}

Combined Input and Holding register

Would you mind sharing the item definition still? Is it DimmerItem bound to channel named dimmer?

Do you mind sharing the logs without the transformation in place? I am curious to find out if there is a bug that would need fixing…

Hi (@ssalonen)

Thanks a lot for the Modbus binding.

I was able to connect our Ökofen heater to OH with the binding.

Best regards

Raphael

1 Like

Hi… I shared the log approx 1-2 days ago, it the log sufficient ?

My Item definition is:

Dimmer Light_GF_Sove_Seng	 	"LED Seng [%d %%]"	 	                 (GF_Sove, Lights)                 { channel="modbus:data:endpointSmarthouse:Smartlight:Smartlight:dimmer" }
1 Like

The two lines of log? No… I would need more to really dig into this. Ideally would be the whole sequence of events, starting from command from openHAB, value changing, and then value reverting back start (e.g. your case mentioned here).

Really would appreciate all the help!

Best,
Sami

EDIT:

I think I know what might be the reason, with a similar setup (reading & writing to holding register, using dimmer, no transformation), I have the following in the verbose logs

xxxx will be updated to 'ON' (type OnOffType). Input data: number value 60 (value type 'uint16' taken into account) and bool value t

So numeric value of 60 is converted to ON. Logic is explained more thoroughly here: Modbus - Bindings | openHAB (Transform On Read section)

The default is to convert non-zero numbers to ON / OPEN , and zero numbers to OFF / CLOSED , respectively. If the item linked to the data channel does not accept these states, the number is converted to best-effort-basis to the states accepted by the item. For example, the extracted number is passed as-is for Number items, while ON / OFF would be used with DimmerItem.

The behaviour is meant to be smart with Switch etc items (converting numeric values to “boolean” values) but obviously a bit unexpected with DimmerItem. Since Dimmer items accept ON/OFF, the same piece of logic applies to it as well (a bit unexpectedly, I admit).

Best,
Sami

1 Like

Humm, bit debatable whether automatically converting a number read from a Modbus register to a Dimmer Item would be a good idea.
Given the variety of manufacturers devices (although dimmers are rare!) I would not think that numeric100 representing 100% is guaranteed. 255 seems just as likely.
Not to consider we’re (usually) dealing with 16-bit values … or as in this case, 32-bit.
We’ve already had this conversation, I bet?

Requiring a transform to scale a register to a Dimmer Item doesn’t seem unreasonable. Even for the odd time it is effectively a no-op transform.

It would be a good idea to make this clear in the docs, an example would be helpful.

Out of interest, is it just chance that the write side works here? I imagine that would often need scaling/transform as well.

1 Like

Heh, indeed it is a bit deja vu. I think we have had this discussion before.

Good question regarding write… On write, the binding accepts DecimalType, OPEN/CLOSED and ON/OFF.

Since PercentType used by dimmer items is inherited from DecimalType, it should work with writes when the command is a number.

But, when command is ON/OFF, it would be converted to 1 and 0 when writing, probably not something you would want… Cc @Nanna_Agesen

Definitely needs a proper example in docs.

We try to convert transformation output to number ( DecimalType ), OPEN / CLOSED ( OpenClosedType ), and ON / OFF ( OnOffType ); in this order.

Draft example (fictional simple device) - please review @ssalonen @Nanna_Agesen
Completely untested !

OpenHAB Dimmer type Items are not a straightforward match to Modbus registers, as they feature a numeric value which is limited to 0-100 Percent, as well as handling ON/OFF commands.
Transforms can be used to match and scale both reading and writing.

Example for a dimmer device where 255 register value = 100% for fully ON :
Thing definition

Bridge modbus:tcp:remoteTCP [ host="192.168.0.10", port=502 ]  {
   Bridge poller MBDimmer [ start=4700, length=2, refresh=1000, type="holding" ]  {
	         Thing data DimmerReg [ readStart="4700", readValueType="uint16", readTransform="JS(dimread255.js)", writeStart="4700", writeValueType="uint16", writeType="holding", writeTransform="JS(dimwrite255.js)" ]

Dimmer transforms
dimread255.js

// Wrap everything in a function (no global variable pollution)
// variable "input" contains data string passed by binding
(function(inputData) {
    // here set the 100% equivalent register value
    var MAX_SCALE = 255;
    // convert to percent
    return Math.round( parseFloat(inputData) * 100 / MAX_SCALE );
})(input)

dimwrite255.js

// variable "input" contains command string passed by openhab
(function(inputData) {
    // here set the 100% equivalent register value
    var MAX_SCALE = 255;
    var out = 0
    if (inputData == 'ON') {
          // set max
         out = MAX_SCALE
    } else if (inputData == 'OFF') {
         out = 0
    } else {
         // scale from percent
         out = Math.round( parseFloat(inputData) * MAX_SCALE / 100 )
    }
    return out
})(input)

Item

Dimmer myLight "My Dimmer"   { channel="modbus:data:remoteTCP:MBDimmer:DimmerReg:dimmer" }

This is excellent!

The example looks good! I just noticed one small thing, the writeValueType should be int16, there’s no such thing as uint16 when writing. Second thing was missing braces (}) in the things snippet.

Would @Nanna_Agesen like to try this out?

Woah, is that so? Seems a little asymmetric. I haven’t tried it, does it fail ? Or are we just talking about the logic - because an OH Number covers the range of both uint16 and int16 without worry.

Is there an implication that to write hex FFEE to a register, you’d need an OH Number of -18 for int16, rather than 65518 for uint16? Or do both varieties just give the same result automagically? (65518 technically “won’t fit” into int16 but I’m sure the binding can just do it anyway on a write) Just a bit worried about truncation of numbers over 32767, the theoretical max for int16.

I take it for granted int32 works similar !

@ssalonen @rossko57

Interesting example, Ill give it a test this weekend :slight_smile:

You’ll have to tweak the simplified example a little to fit your case.

I’m really curious how your Dimmer works with an ON command, with and without the write transform? If you get the opportunity to try.

@rossko57

I have tested the example and it works really excellent - I don’t see the issue were the slider either max out to 100% or 0%.

In my case that problem is only related to the read transform.

When i’m using the dim transform combined with On/Off command the difference is that the light (With the write transform) turns on with Max (100%) and Off (0%).

Without the dim transform light is turned on with the previous state of the dimmer.

You are on the right path @rossko57.

The binding actually truncates the incoming number to 16 bits (DecimalType.shortValue()) command and then writes this to the device. Exact steps of this truncation are explained in the java narrowing conversion rules. With integer commands, we simply pick out the lowest 16 bits and write that. Values within the range of 16 bit unsigned and signed integers should be written without any loss of precision.

So if the low bits are 0xFFEE, then it writes that. We can call it -18 (signed) or 65518 (unsigned), it’s all the same bits anyway.

32bit is treated similarly.

So in a way the write is asymmetric to read since there is no interpretation of signed / unsigned. On the other hand calling the write path as “int16” is obviously misleading (and causing confusion I can see) as the process is more like “pick-low-16bits-from-integer-part”.

The behavior with 16 bit numbers is the same as with the old binding.

Best
Sami

I am not sure I understand. If you do not have the write transform (but do have the read transform) I would expect OFF command to write 0 (into two registers as 32 bit integer in your case) and ON command to write 1.

Is this what you are seeing?

@ssalonen

Yes the OFF command write 0, but without writetransform the last state of the dimmer is used when ON command is recieved.

all right. Could you please share verbose logs?

It is quite unexpected behavior