Mqtt Binding: step property nor working properly for transformations

I have the following Thing configuration:

Thing topic zigbeeOsram {
    Channels:
        Type dimmer : brightness [
            stateTopic="zigbee2mqtt/0x84182600000f7da8",
            transformationPattern="JSONPATH:$.brightness",
            commandTopic="zigbee2mqtt/0x84182600000f7da8/set",
            formatBeforePublish="{\"brightness\": %s}",
            min=1,
            max=254,
            step=1
       ]
}

I then created a new Item and bound it to that Channel using PaperUI. When using it in Control (for easy testing), I encountered two problems:

  1. The step is completely ignored. The Bindings sends messages like
    { "brightness" : 107.68 } to the Broker while it should be only integers when step=1 is used, right? (at least the formatBeforePublish seems to work as it should).
  2. Incoming messages like {"brightness": 54} result in screwed up floating point percentages like

Do you have any idea what the problem might be? Maybe a mistake in my Thing definition?

Have you tried changing the formatBeforePublish from a string (%s) to a number (%d)?

Examle:

formatBeforePublish="{\"brightness\": %d}"

Have you tried changing the formatBeforePublish from a string (%s) to a number (%d)?

yes, unfortunately the result stays the same

How do you have the dimmer setup in your sitemap?

This is what I use and no floating point issues.

Slider item=My_Light_Level label="My Light Level [%d]"

You might want to try adding the Max, Min, and Steps to the sitemap and not in the Things file.

I tried your configuration, but the result stayed the same. But even if it worked in the Sitemap, I would still have the problem with incoming values not being properly transformed.

Nevertheless, I tried setting min and max in the Sitemap like

Slider item=MyLightBrightness minValue=0 maxValue=254 step=1

but it didnā€™t went well with the Dimmer seeming to expect percentages [0, 100] only. The steps, both in the Sitemap and PaperUI Control, are ā€œ1ā€, though (I can choose every integer between 0 and 100).

Okay, thatā€™s odd. I narrowed the problem down to the Binding type dimmer. If I switch from Type dimmer to Type number the step parameter works as expected. Might be a bug, what would you say?

1 Like

Not sure if itā€™s a bug,:thinking: as dimming is normally defined from 0 to 100 %. The good thing about OH is the flexibility that allows you to change the item to a Number and make it work.:+1:

The problem comes from the fact that a dimmer works in 0-100% so if you set it to 50 it sends a value equal to half your max settingā€¦so 129 in the case of a 254 max.

Iā€™m also using Zigbee2MQTT and had it setup the exact same way you did.

In the end I installed the legacy MQTT V1 binding so I could use some more complex Javascript transformations that could convert the 0-100 slider to 0-255 rounding all the numbers to remove the decimal point. Another feature of the Javascript transformation was I could configure it to also except ā€œONā€ and ā€œOFFā€ commands that way I can have a slider or a switch tied to the same item in OpenHAB. This also allows me to share that single item with Alexa. If I tell Alexa to set lights to 50 they dim to half, if I say off they turn off and if I say on they come back at there previous brightness.

1 Like

Good to know Iā€™m neither alone nor just too stupid to set this up :wink:

Iā€™m not too deep into this yet. So can you please tell me what the MQTT v1 Binding allows in terms of transformation that canā€™t be realized with transformationPatternOut and transformationPatternOut?

Iā€™m no expert but this is what I have gathered.

the V2 binding allows you to use the JSON transformation on the incoming data to pick out the info you want like the brightness value. You can then use the FormatBeforePublish to convert a value you are sending into a JSON format that Zigbee2MQTT can use.

The V1 binding allows you to use a Javascript script to transform the data however you want. Iā€™ve yet to personally see any drawbacks of doing the transformation via a Javascript script.

You can use the V1 binding as well as the V2. I have both installed and used the V2 for most things until I worked out how powerful the Javascrtipt transformation could be.

Hereā€™s what I have setup

There is no ā€˜Thingā€™ for V1, once installed you configure the binding to connect to your broker though the mqtt.cfg file you can find details here https://www.openhab.org/addons/bindings/mqtt1/

Item

Dimmer His_Lamp "His Lamp" (gLamps) [ "Lighting" ] {mqtt=">[broker:zigbee2mqtt/His_Lamp/set:command:*:JS(setZigbeeBrightness.js)],<[broker:zigbee2mqtt/His_Lamp:state:JS(getZigbeeBrightness.js)]"}

The above item is using two Javascript fils to transform the message being sent and recieved. setZigbeeBrightness.js and getZigbeeBrightness.js.

You need to install the Javascript Transformation service in PaperUI and place these files within the Transform folder.

setZigbeeBrightness.js - Iā€™ve added some comments to show what the script does.

(function(x){   //Read incomming message into x

  var result = new Object();    //Make JSON object ready to send out

  if (x == "ON") {            //If incomming command is ON set "state" = ON in JSON message
    var state = "ON"
    result.state = state;
  } else if (x == "OFF") {    //If incomming command is OFF set "state" = OFF in JSON message
    var state = "OFF"
    result.state = state;
  }else if (x < 1) {          //If incomming command is 0 (i.e Slider set to off) set "state" = OFF in JSON message
    var state = "OFF"
    result.state = state;
  } else{                     //Otherwise command must be brightness value between 1-100
    var brightness = x*255/100;   //Change 0-100 range to 0-255 range
    result.brightness = brightness.toFixed();   //set "brightness" = <VALUE> in JSON message without any decimals
  }

  return JSON.stringify(result);    //Return finished JSON objest to be sent to MQTT broker
  
})(input)

getZigbeeBrightness.js

(function(x){               //Read incomming message into x

    var brightness;         //Define var's to be used in script
    var state;
    var result;

    var json = JSON.parse(x);       //Parse x into json var
    brightness = json.brightness * 100 / 255;           //Read brightness value into var and convert 0-255 range into 0-100 range
    state = json.state;                                 //Read state value into var

    if (brightness < 1 || state == "OFF") {             //If brightness = 0 or state = OFF set result to 0
        result = 0;
    } else {
        result = brightness.toFixed();                  //else set result to brightness value without decimals
    }


    return result;                                      //Send result into OpenHAB MQTT state.
    
})(input)

Please donā€™t make your sentences sound like facts if you are not sure yourself. Mqtt2 allows to use all as in ALL transformation exactly like mqtt1 and there is not a single documentation line that supports your guess.

The background is that Mqtt1 will not live forever and if you make people migrate back to v1 weā€™ll have more unhappy users in the end when mqtt1 dies.

Avoid JavaScript transformations

If possible try to use mapping and jaonpath transformations and if necessary output formatter. JavaScript transformations are very expensive for the core to perform.

step

The step is actually working correctly. It has a different semantic than you thought it has. It is meant to be used for UIs so that they offer a stepped slider widget. The step value is not for converting a floating point number to an integer value.

Thanks, David

1 Like

Thanks for your answer! As for the definition in the documentation

  • step : For decrease, increase commands the step needs to be known

one might find a wording more comprehensible by beginners then :thinking:

The documentation only mentiones the FormatBefoerPublish which would allow me to format the outgoing message to JSON but wouldnā€™t allow me to change the message the same way the script can.

Could you point me in the right direction how to have the funcionality from the script in MQTT V2?

Looks like a normal MQTT Generic dimmer channel with min=0, max=100. ON/OFF are automatically interpreted.

The value form the dimmer needs to be converted into a JSON message like the following.

{"state":"ON","brightness":255}

Using the Min, Max and FormatBeforePublish I was able to send brightness levels but I need to be able to send a state of OFF if dimmer is set to 0 as not all bulbs respond correctly to setting a brightness of 0 hence why I followed examples elsewhere to use the Javascript transformation.

Iā€™ve been having a play and Iā€™ve got a partially working system by using a rule to format a JSON message based on a dimmer value and pass that to the MQTT item that I have set as a string.

Is this how I should be doing it or is there a better way to create the JSON message?

Thanks.

1 Like

Well it might be over complicated but I have got this working.

Basically Iā€™ve changed the MQTT item into a string and I have a separate dimmer item that isnā€™t directly connected to the MQTT item and I have replicated the functionality of the Javascript file within a rule.

So if a number is set on the dimmer unit it converts the 0-100 to 0-255 and sends the value as the brightness key in the JSON message. If the dimmer is set to 0 it sends a State = OFF in the JSON message.

The reason for using the state is some of my bulbs didnā€™t consistently turn off when sent a brightness = 0 and they always reported back a state = ON and brightness = 1 even if they did actually go off. If I send a state = OFF they always go off and report back that the state = off.

If the dimmer receives a ON or OFF command it also just send the state value. This means that if I toggle the light it comes back on at itā€™s previous brightness and not full.

There might be an easier way of doing it but I didnā€™t find it and this is working.

please see this issue, you should not need this any longer in the current dev version.

I hadnā€™t checked the issues for a few days.

That does mean that if you didnā€™t care about the bulb remembering the previous brightness level when turning off and on you could do it with a single MQTT dimmer item with a min of 0 and max of 255.

Could you please post your config? I have exactly the same problem with a Hue Bulb. Linkquality and On/Off works fine, unfortunately it doesnā€™t dim. Thatā€™s how it looks with me at the moment:

Things file:

//Hue Lampe Esszimmer1 0x001788010248565d   
   Thing mqtt:topic:0x001788010248565d  "Hue Lampe Esszimmer1" @ "MQTT"{
    Channels:
	    Type switch : huelamp "Hue Lampe Esszimmer1" [
		    stateTopic="zigbee2mqtt/0x001788010248565d",
		    transformationPattern="JSONPATH:$.state",
		    commandTopic="zigbee2mqtt/0x001788010248565d/set",
		    on="ON", off="OFF" ]
    	Type number : link "Verbindung" [         
            stateTopic="zigbee2mqtt/0x001788010248565d",    
            transformationPattern="JSONPATH:$.linkquality"    
          ]
      Type dimmer : dimmer "Dimmer" [ 
        stateTopic="zigbee/0x001788010248565d",
        commandTopic="zigbee/0x001788010248565d/set", 
        transformationPattern="JSONPATH:$.brightness", 
        formatBeforePublish="{\"brightness\":%s}",
        min=1,
        max=254,
        step=1 ]      
    }

Items File:

Switch hueesszimmer1 "Esszimmer Lampe1" <light> { channel="mqtt:topic:0x001788010248565d:huelamp"}
Number linkhuelamp1 "Esszimmer Lampe1 Linkquali [%d %%]" <qualityofservice>  { channel="mqtt:topic:0x001788010248565d:link", expire="5h,0" }
Dimmer EsszimmerLinkeLampe_Helligkeit "Esszimmer linke Lampe [%.0f %%]"    <light> ["Lighting"]  { channel="mqtt:topic:0x001788010248565d:dimmer" }

Would be great if somebody could help me out.

Using zigbee2mqtt this is what works running OH 2.4

Thing:

Thing topic zigbee2mqtt "Bedroom Light" @ "Bedroom" {
    Channels:
        Type switch : power  "Power"               [ stateTopic="zigbee/0xb0ce1814030ac279", transformationPattern="JSONPATH:$.state",
                                                    commandTopic="zigbee/0xb0ce1814030ac279/set", on="ON", off="OFF" ]
        Type dimmer : dimmer "Dimmer"              [ stateTopic="zigbee/0xb0ce1814030ac279",
                                                    commandTopic="zigbee/0xb0ce1814030ac279/set", transformationPattern="JSONPATH:$.brightness", formatBeforePublish="{\"brightness\":%s}" ]
    }

Item:

Switch BedroomLight "Bedroom Light"    <light> ["Lighting"]  { channel="mqtt:topic:pibroker:zigbee2mqtt:power", expire="120m,command=OFF" }
Dimmer BedroomLight_Level "Bedroom Light Level [%.0f %%]"    <light> ["Lighting"]  { channel="mqtt:topic:pibroker:zigbee2mqtt:dimmer" }

Then I use these three transformation files, placed in ā€˜/etc/openhab2/transformā€™, also make sure you have js transformation service installed via PaperUI.

getZigbeeBrightness.js for getting the brightness:

(function(x){

    var result;
 
    var json = JSON.parse(x);  
    result = json.brightness * 100 / 255;

    return result;
    
})(input)

setZigbeeBrightness.js for setting the brightness level:

(function(x){

    var brightness = x * 255/100;

    var result = new Object();
    result.brightness = brightness;
 
    return JSON.stringify(result);
    
})(input)

setZigbeeState.js for setting the state:

```csv
(function(x){

    var result = new Object();
    result.state = x;
 
    return JSON.stringify(result);
    
})(input)