Zigbee2mqtt and Zigbee bulbs small tutorial

Hi @R-Rosenow, welcome to the openHAB community!

JS transformation only transforms information provided by openHAB color item to json format expected by Z2M. 10%, at least in Ikea bulb case, is minimum brightness value bulb can ‘produce’. So I suspect, when bulb receives command ON without color/brightness information then switches to minimum brightness. You can extend json string for command ON adding key brightness and desired value (or color key too). This is workaround, not real solution, but at least you will have control over initial brightness (or color).

That don’t work. I have tested this:

return ‘{“state”:“ON”, “brightness”:215}’

With MQTT.fx this message work, but not at the JS at Openhab.

In the Openhab Documentation you can read this, that could be the problem, but there is no explain how to do it.

" Channel Type “colorRGB”, “colorHSB”

  • on : An optional string (like “BRIGHT”) that is recognized as on state. (ON will always be recognized.)
  • off : An optional string (like “DARK”) that is recognized as off state. (OFF will always be recognized.)
    *** onBrightness : If you connect this channel to a Switch item and turn it on,**

color and saturation are preserved from the last state, but the brightness will be set to this configured initial brightness (default: 10%).

You can connect this channel to a Color, Dimmer and Switch item.

This channel will publish the color as comma separated list to the MQTT broker, e.g. “112,54,123” for an RGB channel (0-255 per component) and “360,100,100” for a HSB channel (0-359 for hue and 0-100 for saturation and brightness).

The channel expects values on the corresponding MQTT topic to be in this format as well.

Do you have an Idea?

Thank you.

I’ve just checked JS modification as below with IKEA color bulb and it works as expected

    if (x=="ON" || x=="INCREASE") {
        return '{"state":"ON","brightness":250}'

Message from Z2M zigbee2mqtt/ikea_led_color_1

{"state":"ON","linkquality":60,"last_seen":"2020-01-12T13:13:39+01:00","brightness":250,"color_mode":2,"color":{"x":0.5346,"y":0.3124}}

Please pay attention to quotation marks " is not the same as - see https://www.w3schools.com/html/html_charset.asp

PS. To preserve code formatting use code fences ``` around code
(or marked button in editor
image
)

Good luck!

It dont work for me.

Can you show your Item & Thing for example?

Thing:

Thing topic philips_hue_fensterlampe “Fensterlampe” @ “MQTT” {
Channels:
Type colorHSB:color “Farbe” [ stateTopic = “zigbee2mqtt/philips_hue_fensterlampe/state”,
commandTopic = “zigbee2mqtt/philips_hue_fensterlampe/set”, transformationPatternOut=“JS:HSBtoRGB.js” ]
Type number : linkquality “Verbindung” [ stateTopic = “zigbee2mqtt/philips_hue_fensterlampe/linkquality” ]
}

Item:

Switch wohnzimmer_fensterlampe “Fensterlampe” (glichter_gesamt,glichter_wohnzimmer) { channel=“mqtt:topic:Mosquitto:philips_hue_fensterlampe:color” }

Color wohnzimmer_color_fensterlampe “Fensterlampe” [“Lighting”] { channel=“mqtt:topic:Mosquitto:philips_hue_fensterlampe:color” }

Dimmer wohnzimmer_fensterlampe_dimmer “Fensterlampe” { channel=“mqtt:topic:Mosquitto:philips_hue_fensterlampe:color” }

Number wohnzimmer_fensterlampe_verbindung “Fensterlampe [%.1f %%]” { channel=“mqtt:topic:Mosquitto:philips_hue_fensterlampe:linkquality” }

Thats the output of Zigbee2Mqtt:

Jan 12 13:54:02 openHABianPi npm[2760]: zigbee2mqtt:info 2020-01-12 13:54:02: MQTT publish: topic ‘zigbee2mqtt/philips_hue_fensterlampe/state’, payload ‘ON’
Jan 12 13:54:02 openHABianPi npm[2760]: zigbee2mqtt:info 2020-01-12 13:54:02: MQTT publish: topic ‘zigbee2mqtt/philips_hue_fensterlampe/linkquality’, payload ‘55’
Jan 12 13:54:02 openHABianPi npm[2760]: zigbee2mqtt:info 2020-01-12 13:54:02: MQTT publish: topic ‘zigbee2mqtt/philips_hue_fensterlampe/brightness’, payload ‘26’
Jan 12 13:54:02 openHABianPi npm[2760]: zigbee2mqtt:info 2020-01-12 13:54:02: MQTT publish: topic ‘zigbee2mqtt/philips_hue_fensterlampe/color-x’, payload ‘0.4062’
Jan 12 13:54:02 openHABianPi npm[2760]: zigbee2mqtt:info 2020-01-12 13:54:02: MQTT publish: topic ‘zigbee2mqtt/philips_hue_fensterlampe/color-y’, payload ‘0.3669’
Jan 12 13:54:02 openHABianPi npm[2760]: zigbee2mqtt:info 2020-01-12 13:54:02: MQTT publish: topic ‘zigbee2mqtt/philips_hue_fensterlampe/color-saturation’, payload ‘55.1’
Jan 12 13:54:02 openHABianPi npm[2760]: zigbee2mqtt:info 2020-01-12 13:54:02: MQTT publish: topic ‘zigbee2mqtt/philips_hue_fensterlampe/color-hue’, payload ‘46.2’

For things/items definition please see post#34

I see there no difference.

OK, so it looks like binding mqtt1.x and mqtt2.x behaves differently. I did my tests with modified JS file return '{"state":"ON","brightness":250}' on mqtt1.x

When I switched to mqtt2.x it started behaving like you described. To fix it please update channel definition as follow:

    Type colorHSB   : color         "Ikea Color 1"              [ stateTopic="zigbee2mqtt/ikea_led_color_1/dumb", commandTopic="zigbee2mqtt/ikea_led_color_1/set", transformationPatternOut="JS:HSBtoRGB.js", onBrightness=70 ]

adding onBrightness=70, where 70 is desired brightness when switching on.

Hope this helps also in your case.
Cheers!

1 Like

Thats the solution that I was search for.

It works great! Thanks.

Add into configuration.yaml

experimental:
    output: attribute

and stop to use transformationPatternOut

That don‘t work for me.

Can you post your things and item?

mqtt.things

Bridge mqtt:broker:MQTTBroker [ host="127.0.0.1", secure=false, username="myuser", password="mypasswd" , clientID="openhab2", reconnectTime=5 ] {
    Thing topic xiaomi-contact"xiaomi-contact" {
    Channels:
        Type number : battery       "battery"           [ stateTopic="zigbee2mqtt/0x00158d0001c2d860/battery" ]     
        Type number : voltage       "voltage"           [ stateTopic="zigbee2mqtt/0x00158d0001c2d860/voltage" ]     
        Type switch : contact       "contact"           [ stateTopic="zigbee2mqtt/0x00158d0001c2d860/contact", on="true", off="false" ]     
        Type number : linkquality   "linkquality"       [ stateTopic="zigbee2mqtt/0x00158d0001c2d860/linkquality" ]     
    }        
}

xiaomi.items

String    Switch_Click    { channel="mqtt:topic:MQTTBroker:xiaomi-contact:click" }

configuration.yaml

homeassistant: false
permit_join: false
mqtt:
  base_topic: zigbee2mqtt
  server: 'mqtt://localhost'
  user: myuser
  password: mypassword
serial:
  port: /dev/ttyACM1
experimental:
  output: attribute
devices:
  '0x00158d0001c2d860':
    friendly_name: '0x00158d0001c2d860'
1 Like

I see your transformationPatternOut and I raise you a transformationPattern (in).

I loved that with your transformation I could use a single Color item and link it to OpenHAB Switch, Dimmer, and Color objects to control them with one bit of code, but it bugged me that updating the color of the device didn’t update the OpenHAB object. The next time I would pull up the ColorPicker, it would default back to white, not the current color.

So I decided to see if I could cobble up an incoming transformationPatter script.

My Thing definition (the important part is the colorHSB definition):

  Thing topic testlightstrip {
      Type switch : toggleonoff [ stateTopic="zigbee2mqtt/test_osram_flexstrip/state", commandTopic="zigbee2mqtt/test_osram_flexstrip/set/state", on="ON", off="OFF", transformationPatternOut="JS:HSBtoRGB.js"]
      Type dimmer : dim [ stateTopic="zigbee2mqtt/test_osram_flexstrip/brightness", commandTopic="zigbee2mqtt/test_osram_flexstrip/set/brightness_percent", transformationPattern="JS:byte2percent.js" ] //, transformationPatternOut="JS:percent2byte.js"]
      //Note: Color is still SET-only:
      Type colorHSB : colorHSB [ 
        commandTopic="zigbee2mqtt/test_osram_flexstrip/set", transformationPatternOut="JS:HSBtoRGB.js", onBrightness=100, 
        stateTopic="zigbee2mqtt/test_osram_flexstrip", transformationPattern="JS:xyz2hsb.js" 
      ]
  }

My Items:

Switch testlightstrip_sw "Test Lightstrip sw" (gTest) {channel="mqtt:topic:Mosq:testlightstrip:colorHSB"}
Dimmer testlightstrip_dim "Test Lightstrip dim" (gTest) {channel="mqtt:topic:Mosq:testlightstrip:colorHSB"}
Color  testlightstrip_color "Test Lightstrip clr" (gTest) {channel="mqtt:topic:Mosq:testlightstrip:colorHSB"}

The xyz2hsb.js transformation script:

//Convert Zigbee2MQTT's xyZ format to OpenHAB's HSB/HSV format
(function(xyz) {

    var debug=true;

    if (debug) {
        var logger = Java.type("org.slf4j.LoggerFactory").getLogger("xyz2hsb.js");
        logger.warn("Input: "+xyz);
    }

    var json = JSON.parse(xyz);
    var x = json.color.x;
    var y = json.color.y;
    var brightness = json.brightness;

    if (debug) logger.warn("X:" + x + " Y:" + y + " B:"+ brightness);

    //The following is based on https://github.com/Koenkk/zigbee2mqtt/issues/3497
	if (brightness === undefined) brightness = 254; //Do I need this in this context??

	var z = 1.0 - x - y;
	var Y = (brightness / 254).toFixed(2);
	var X = (Y / y) * x;
	var Z = (Y / y) * z;

	//Convert to RGB using Wide RGB D65 conversion
	var r 	=  X * 1.656492 - Y * 0.354851 - Z * 0.255038;
	var g 	= -X * 0.707196 + Y * 1.655397 + Z * 0.036152;
	var b 	=  X * 0.051713 - Y * 0.121364 + Z * 1.011530;

	//If red, green or blue is larger than 1.0 set it back to the maximum of 1.0
	if (r > b && r > g && r > 1.0) {
		g = g / r;
		b = b / r;
		r = 1.0;
	} else if (g > b && g > r && g > 1.0) {
		r = r / g;
		b = b / g;
		g = 1.0;
	} else if (b > r && b > g && b > 1.0) {
		r = r / b;
		g = g / b;
		b = 1.0;
	}

	//Reverse gamma correction
	r 	= r <= 0.0031308 ? 12.92 * r : (1.0 + 0.055) * Math.pow(r, (1.0 / 2.4)) - 0.055;
	g 	= g <= 0.0031308 ? 12.92 * g : (1.0 + 0.055) * Math.pow(g, (1.0 / 2.4)) - 0.055;
	b 	= b <= 0.0031308 ? 12.92 * b : (1.0 + 0.055) * Math.pow(b, (1.0 / 2.4)) - 0.055;

	//Convert normalized decimal to decimal
	r 	= Math.round(r * 255);
	g 	= Math.round(g * 255);
	b 	= Math.round(b * 255);

	if (isNaN(r)) r = 0;
	if (isNaN(g)) g = 0;
	if (isNaN(b)) b = 0;

    if (debug) logger.warn("RGB: "+r+","+g+","+b);

    // We now have RGB!!! Now convert THAT to HSB for OpenHAB's pleasure:

    //The following based on https://stackoverflow.com/questions/8022885/rgb-to-hsv-color-in-javascript
    var rabs, gabs, babs, rr, gg, bb, h, s, v, diff;
    rabs = r / 255;
    gabs = g / 255;
    babs = b / 255;
    v = Math.max(rabs, gabs, babs),
    diff = v - Math.min(rabs, gabs, babs);

    if (diff == 0) {
        h = s = 0;
    } else {
        s = diff / v;
        rr = (v - rabs) / 6 / diff + 1 / 2;
        gg = (v - gabs) / 6 / diff + 1 / 2;
        bb = (v - babs) / 6 / diff + 1 / 2;

        if (rabs === v) {
            h = bb - gg;
        } else if (gabs === v) {
            h = (1 / 3) + rr - bb;
        } else if (babs === v) {
            h = (2 / 3) + gg - rr;
        }
        if (h < 0) {
            h += 1;
        }else if (h > 1) {
            h -= 1;
        }
    }

    // var hsb = Math.round(h*360) + "," + Math.round(s * 100) + "," + Math.round(v * 100);
    var hsb = h*360.0 + "," + s * 100.0 + "," + v * 100.0;

    if (debug) logger.warn("Returning HSB: "+hsb);

    return(hsb);

})(input)

Debug output shows that the xyz2hsb.js properly converts the Zigbee2MQTT’s xyz color codes back to OpenHAB’s HSB format and when you open the ColorPicker again, it shows you the current value.

I hope that this provides some value to others who want to be able to use a Color object in both directions.

Great job, but to be honest you do not need to the whole transformation on your our. First i didi it the same way.

If you define the mqtt channel as xyY color channel you could simply use the following transformations.

Reading a color value from Zigbee2mqtt (Incoming transformation

(function(i) {

    /* Aufbereitung Z2M JSON -> xyY
    /
    /  Grundsätzlicher Ablauf
    /     1. Parsen der Eingangswerte
    /     2. Umrechnungen 
    /     3. Aufbereitung der Ausgabewerte als JSON
    /
    */
    
    // Schritt 1: Parsen
    // // Input: i = String = {"brightness":Y_value,"color":{"x":x_value,"y":y_value}}; Input: xy in [0,1], brightness in [0, 254]
    var data = JSON.parse(i);
    x = data.color.x;
    y = data.color.y;
    Y = data.brightness;

    // Schritt 2: Umrechungen
    // Input: xy in [0,1], Y in [0, 254]; Output: xy in [0, 1], Y in [0, 100]
    Y = Math.round(Y / 2.54);

    // Schritt 3: Aufbereitung der Ausgabewerte als JSON
    return x + ',' + y + ',' + Y;

}) (input)

and to send a color use this ourgoing transformation

(function(i) {

    /* Aufbereitung xyY -> Z2M JSON
    /
    /  Grundsätzlicher Ablauf
    /     1. Parsen der Eingangswerte
    /     2. Umrechnungen 
    /     3. Aufbereitung der Ausgabewerte als JSON
    /
    */
    
    // Schritt 1: Parsen
    // Input: i = String = "x,y,Y"; Input: xy in [0,1], Y in [0, 100]
    var data = i.split(',');
    x = parseFloat(data[0]);
    y = parseFloat(data[1]);
    Y = parseFloat(data[2]);

    // Schritt 2: Umrechungen
    // Input: xy in [0,1], Y in [0, 100]; Output: xy in [0,1], Y in [0, 254]
    Y = Math.round(Y * 2.54);

    // Schritt 3: Aufbereitung der Ausgabewerte als JSON
    return '{"brightness":' + Y + ',"color":{"x":' + x + ', "y":' + y + '}}';

}) (input)

Here is the channel definition


I really like your debug idea and will definitely copy it.

Thomas

2 Likes

LOL, of course.

I spent hours searching for an easier way, finally gave up and cobbled together code, only then to have someone say “you could have just…”. :rofl: :rofl: :rofl: :joy:

I had no idea you could simply specify the Thing’s color model. Well, at least I got to brush up on my rusty JS skills just a bit.

Now… how do I specify this in .things file format?

This does NOT work right, and I’ve searched through the OH source code for an hour now and tried many different variants:

      Type colorHSB : colorHSB [ onBrightness=100, colorMode="xy",
        commandTopic="zigbee2mqtt/test_osram_flexstrip/set", transformationPatternOut="JS:z2m_xyY2JSON.js",
        stateTopic="zigbee2mqtt/test_osram_flexstrip", transformationPattern="JS:z2m_JSON2xyY.js"
      ]

Because I then get the following error from Zigbee2MQTT:

Mar 31 10:52:25 openhab npm[9833]: Zigbee2MQTT:info  2021-03-31 10:52:25: MQTT publish: topic 'zigbee2mqtt/bridge/log', payload '{"message":"Publish 'set' 'color' to 'test_osram_f
lexstrip' failed: 'RangeError [ERR_OUT_OF_RANGE]: Command 0x7cb03eaa00a4c418/3 lightingColorCtrl.moveToColor({\"transtime\":0,\"colorx\":7536525,\"colory\":5898150}, {\"timeout\":
10000,\"disableResponse\":false,\"disableRecovery\":false,\"disableDefaultResponse\":false,\"direction\":0,\"srcEndpoint\":null,\"reservedBits\":0,\"manufacturerCode\":null,\"tran
sactionSequenceNumber\":null,\"writeUndiv\":false}) failed (The value of \"value\" is out of range. It must be >= 0 and <= 65535. Received 7536525)'","meta":{"friendly_name":"test
_osram_flexstrip"},"type":"zigbee_publish_error"}'

Got any other Zigbee2MQTT hints to make my transition easier?

I always create thing using the UI. But what i know is that once choosen the color format ist is not possible to change it even if it looks possoble in the UI.

This is the code view of the UI maybe it helps.

UID: mqtt:topic:61e5bd7fc8:bec4de4ee6
label: RH_GF_BR_MoodLight01 - Generic MQTT Thing
thingTypeUID: mqtt:topic
configuration:
  payloadNotAvailable: offline
  availabilityTopic: zigbee2mqtt/RH_GF_BR_MoodLight01/availability
  payloadAvailable: online
bridgeUID: mqtt:broker:61e5bd7fc8
channels:
  - id: state
    channelTypeUID: mqtt:switch
    label: State
    description: ""
    configuration:
      commandTopic: zigbee2mqtt/RH_GF_BR_MoodLight01/set
      transformationPatternOut: JS:z2m_onoff_2_JSON.js
      stateTopic: zigbee2mqtt/RH_GF_BR_MoodLight01
      transformationPattern: JS:z2m_JSON_2_onoff.js
  - id: color
    channelTypeUID: mqtt:color
    label: Color
    description: ""
    configuration:
      commandTopic: zigbee2mqtt/RH_GF_BR_MoodLight01/set
      colorMode: XYY
      transformationPatternOut: JS:z2m_xyY_2_JSON.js
      stateTopic: zigbee2mqtt/RH_GF_BR_MoodLight01/
      transformationPattern: JS:z2m_JSON_2_xyY.js

That “feature” of not being able to change a Thing definition without destroying and recreating it exists in using the files interface as well, but here I just need to force a syntax error, save it, fix it, and save it again and it will destroy and recreate it.

I have tried every way of setting the colorMode in a .things file I can think of. Thanks for posting yours, but even colorMode=“XYY” doesn’t seem to work.

For now, I’m going to just use my code and the standard HSB color mode, since that does work even when using .things files to create my Things.

If anyone else comes up with changing the colorMode of a Thing using .things file, I’ll revisit.

1 Like

Hi I’m using openhabian with OH3.0.2-1 on a Raspi 4.
I’ve connected a Aldi LIGHTWAY smart home LED-lamp via zigbee2mqtt. The “brightness” channel is not working.

This is my setting in the configuration.yaml:

using the state channel works absoutely fine. This is the state channel config:

But I get a warning in the OH logs:

2021-04-26 22:39:09.172 [WARN ] [ab.binding.mqtt.generic.ChannelState] - Incoming payload 'OFF' not supported by type 'NumberValue'

The brightness channel is not working. Although I’ve activated the zigbee2mqtt experimental attribute I can’t control the brightness. Hence I’ve decided to try with a transformation. Also no success.

z2m_brightess.js

(function(i) {
    //console.log(i);
    var logger = Java.type("org.slf4j.LoggerFactory").getLogger("myScript");
     logger.warn("test: " + i);
    //log("Test " + i);
    var array = i.split(" ");
    var value = parseFloat(array[0]*100);
    logger.warn("value: " + value);
    return '{"brightness" :' + value + '}';
})(input)

When I try to control via the bar nothing happens. Not even an entry in the OH logs

Does anybody has an idea?

Regards
becksen.

Hi I’ve answered it myself.

The abolute maximum in the channel was set to 100 and in the script I’ve multiplied with 2.54 to get the max value of the property 254.

(function(i) {
    //console.log(i);
    var logger = Java.type("org.slf4j.LoggerFactory").getLogger("myScript");
     logger.warn("test: " + i);
    //log("Test " + i);
    var array = i.split(" ");
    var value = parseFloat(array[0]*100*2.54);
    logger.warn("value: " + value);
    return '{"brightness" :' + value + '}';
})(input)

HI, i had the same problem with colorMode=“XYY”, i found the cause was actually that i used the deprecated Type colorRGB for another thing.
I also had an wrongly configured thing Type color where i for got the colorMode selection.
These things was working before trying to use “XYY”, but not together.

Edit i see you use colorHSB this is also deprecated

Regards Mads