Zigbee2mqtt and Zigbee bulbs small tutorial

Zigbee2mqtt is an opensource zigbee-mqtt-bridge solution which utilizes cheap hardware in order to bypass commercial gateways to communicate using the Zigbee protocol. It operates using mqtt (a message broker) making it suitable for IOT platforms.

I have recently bought some cheap and simple IKEA Trådfri bulbs as well as some Philips Hue white bulbs and I have not seen any complete solutions for the new Openhab2 mqtt binding. I’ll share some info about it here. Mostly I have take bits and pieces from other topics.


  • zigbee2mqtt up and running with working Zigbee sniffer (ie CC2531 or similar)
  • Trådfri bulbs which are included in the zigbee network (they can be a pain to include, for me 6 very short ons and longer offs made it possible to reset them)
  • Philips HUE white bulbs (I’ve used the regular cheap HUE White which you should be able to get for 6-7$ a piece.)
    To set zigbee2mqtt up see: https://www.zigbee2mqtt.io/

For Openhab you will need to have the following addons installed:
action: mqtt-action
bindings: mqtt (the version 2), expire (optional)
transformation: jsonpath, javascript

I’m running on Openhab 2.5.0-M1, the 2.4 version has some bugs when it comes to MQTT, so I recommend the 2.5.0-M1.

You need to create an mqtt broker using Paper UI. You can run the mqtt “server” on either your openhab instance or as in my case I run it on a different server.

Add a file called zigbee2mqtt.things

Bridge mqtt:broker:mymqttbroker [ host="mymqttbrokeripaddr", secure=false ]
    Thing topic zigbeebridge "Zigbee2mqtt Bridge" {
        Type switch : permitJoin         [ commandTopic="zigbee2mqtt/bridge/config/permit_join", on="true", off="false" ]
        Type string : state              [ stateTopic="zigbee2mqtt/bridge/state" ]
        Type string : logType            [ stateTopic="zigbee2mqtt/bridge/log",  transformationPattern="JSONPATH:$.type" ]
        Type string : logMessage         [ stateTopic="zigbee2mqtt/bridge/log",  transformationPattern="JSONPATH:$.message" ]

    Thing topic ikeabulb01 "IKEA Bulb 01" {
        Type switch : switch "Ikea Bulb 01 Switch" [ stateTopic="zigbee2mqtt/ikeabulb01", commandTopic="zigbee2mqtt/ikeabulb01/set", transformationPattern="JSONPATH:$.state", transformationPatternOut="JS:switch2Zigbee2mqtt.js"]
        Type dimmer : dimmer "Ikea Bulb 01 Dimmer" [ stateTopic="zigbee2mqtt/ikeabulb01", commandTopic="zigbee2mqtt/ikeabulb01/set", min=0, max=100, step=1, transformationPatternOut="JS:openhabdimmer2zigbeebridge.js", transformationPattern="JS:tradfri2openhab.js" ]
        Type number : linkquality "Ikea Bulb 01 LinkQuality" [ stateTopic="zigbee2mqtt/ikeabulb01",  transformationPattern="JSONPATH:$.linkquality" ]

    Thing topic huewhite02 "Philips HUE White 02" {
        Type switch : switch "Hue White 02 Switch" [ stateTopic="zigbee2mqtt/huewhite02", commandTopic="zigbee2mqtt/huewhite02/set", transformationPattern="JSONPATH:$.state", transformationPatternOut="JS:switch2Zigbee2mqtt.js"]
        Type dimmer : dimmer "Hue White 02 Dimmer" [ stateTopic="zigbee2mqtt/huewhite02", commandTopic="zigbee2mqtt/huewhite02/set", min=0, max=100, step=1, transformationPatternOut="JS:openhabdimmer2zigbeebridge.js", transformationPattern="JS:huewhite2openhab.js" ]
        Type number : linkquality "Hue White 02 LinkQuality" [ stateTopic="zigbee2mqtt/huewhite02",  transformationPattern="JSONPATH:$.linkquality" ]

Under transformation add a file called switch2zigbee2mqtt

(function(x) {
    var result = "";
    if (x == '1' || x == 'ON') {
        result="{ \"state\": \"ON\" }";
    } else {
        result="{ \"state\": \"OFF\" }";
    return result;

A file called: huewhite2openhab.js

(function(x) {
    var result;
    var json = JSON.parse(x);
    if (json.state == 'OFF') {
        return 0;
    if (json.brightness >= 254) {
        return 100;
    // If brightnes is 0 or 1 it is off from my experiments
    if (json.brightness <= 1) {
        return 0;
    result = Math.round(((json.brightness / 255) * 100));
    return result;

A file called: tradfri2openhab.js

(function(x) {
    var result;
    var json = JSON.parse(x);
    if (json.state == 'OFF') {
        return 0;
    if (json.brightness == 254) {
        return 100;
    result = Math.round(((json.brightness / 255) * 100));
    return result;

A file called: openhabdimmer2zigbeebridge.js

(function(i) {
    return input  == 0 
                 ? "{ \"state\":\"OFF\"  }" 
                 : "{ \"state\":\"ON\" ,  \"brightness_percent\": " + input + " }";

An items file called zigbee2mqtt.items (this is just an example)

Group  Zigbee

Group  ZigbeeBridge                   "Zigbee2mqtt Bridge"                                     (Zigbee)
String ZigbeeBridgeState              "Zigbee2mqtt Bridge State"                               (ZigbeeBridge) { channel="mqtt:topic:mymqttbroker:zigbeebridge:state" }
Switch ZigbeeBridgePermitJoin         "Zigbee2mqtt Bridge Permit join"                         (ZigbeeBridge) { channel="mqtt:topic:mymqttbroker:zigbeebridge:permitJoin" , expire="10m,command=OFF" }
String ZigbeeBridgeLogType            "Zigbee2mqtt Bridge LogType"                             (ZigbeeBridge) { channel="mqtt:topic:mymqttbroker:zigbeebridge:logType" }
String ZigbeeBridgeLogMessage         "Zigbee2mqtt Bridge LogMessage"                          (ZigbeeBridge) { channel="mqtt:topic:mymqttbroker:zigbeebridge:logMessage" }

Group  ZigbeeKitchenBulb                                                                  (Zigbee)
Switch ZigbeeKitchenBulbSwitch   "Kitchen [%s]"                                 (ZigbeeKitchenBulb) { channel="mqtt:topic:mymqttbrokername:ikeabulb01:switch" }
Dimmer ZigbeeKitchenBulbDim      "Kitchen [%s]"                                 (ZigbeeKitchenBulb)            { channel="mqtt:topic:mymqttbrokername:ikeabulb01:dimmer" }
Number ZigbeeKitchenBulbQuality  "Kitchen LinkQuality [%d]" <qualityofservice>  (ZigbeeKitchenBulb)            { channel="mqtt:topic:mymqttbrokername:ikeabulb01:linkquality" }

The name ikeabulb01 has to be set as a friendly name inside the configuration on zigbee2mqtt (configuration.yaml)

Notice that I’m using the expire binding to set the permit join off after 10 mins.
Using this example you will need to enable permit join in openhab before you can add zigbee components.

You can test by adding the Zigbee group item to your sitemap, to enable access to all members of the Zigbee group:

sitemap mysitemap label="My Cool Sitemap with Zigbee" {
    Frame {
        Group item=Zigbee

The reason why I use these transformations is because when dimmer get a 0 value, we want to turn off.
The valid value range for the bulbs are 1-254 which are passed onto openhab, hence 0 equals off and max is 254.
Also for HUE White the value 1 is also off (at least from my experiment, thus if we get 1 we should display that as 0 in openhab)

See comments in scripts.
Some random things to note:

  • We need to send both state and brightness_percent in order to change the dimvalue
  • It’s a good idea to run mosquitto_sub to see all topics for zigbee2mqtt when debuggig, i do this by running:
mosquitto_sub -h brokerIpaddress -v -t 'zigbee2mqtt/#'
  • LinkQuality is a value for how good connection it is. The higher value the better, value can range from 0 to 255

  • It can also be helpful to manually send mqtt messages, i.e

mosquitto_pub -h brokeripaddress -t 'zigbee2mqtt/ikeabulb01/set' -m '{"state":"ON","brightness":254}'

In zigbee2mqtt configuration (configuration.yaml) you should set the parameter persistent to true.
When doing so the status of the bulbs will be updated /refreshed when you restart openhab.

Mine looks something like this:

homeassistant: false
permit_join: true
  base_topic: zigbee2mqtt
  server: 'mqtt://ipnumber'
  port: /dev/ttyACM0
    friendly_name: ikeabulb01
    retain: true

Thansk to @AndreasBrett for input and suggestions

Regards, S


Zigbee2MQTT supports setting brightness using percentage values. Not sure when they added that but it’s in the current master tree over on GitHub. If you send { "brightness_percent": 50} it will set brightness to 50%. No need for conversions as Zigbee2MQTT will do the math.

I don’t get your logic regarding “If the bulb is off, we should display that as 0 for the dimmer”. To me a light bulb can be off but set to a specific brightness. If for example my light bulb is set to 23% and I turn it off via state=OFF it will still shine at 23% brightness if I simply turn it back on again through a state=ON.

There’s also no need to use JS transformation for setting the state. If you send Non-JSON values like OFF and ON Zigbee2MQTT maps these automatically to the state attribute. Try running:

mosquitto_pub -h brokeripaddress -t 'zigbee2mqtt/ikeabulb01/set' -m 'ON'

Cool I’ll try it out. WIll still need to handle incoming values in the range 1-254 then. Unless there is a setting in zigbee2mqtt that will force send brightness_percent.

Don’t agree. If I see the dimmer slider at a certain percent I would expect it to be on. This is exactly how the Zwave dimmers are working. You might map only the dimmer slider and not the ON/OFF button on your sitemap, if that is the case it will be veryconfusing if it’s not on when the slider indicates so.

I got errors from Zigbee2mqtt when doing this. From openhab you will send ‘1’ and not ON. I guess you can do a map transformation to send on. sending 1 though caused an error.
I’ll check it out though.

Regards, S

Not sure where you see hexadecimal values.

You are correct. Should have written 10-base representation of a byte. :slight_smile:
What I mean is that OpenHab still needs to handle the case when incoming values are in the range of 1-254 in decimal format (10 base), unless you can force zigbee2mqtt to output brightness_percent.

Updated the reply by removing hexadecimal values.

1 Like

Ah now I see. I did that by configuring the thing channel with min and max values of 0 and 255 instead of 0 and 100.

Hello guys.
It does not work for me what I do wrong:
Add a file called zigbee2mqtt.things (this same but my Bridke is mqtt:broker:Mosguitto)
Add a file called zigbee2mqtt.things.js (this same)
A file called: convert2hexdecvalue.js
A file called: convert2percentage.js
An items file called zigbee2mqtt.items (this same)

work for me : mosquitto_pub -h brokeripaddress -t ‘zigbee2mqtt/ikeabulb01/set’ -m ‘{“state”:“ON”,“brightness”:254}’

but in my “sitemap”
Switch Kitchen “-” colour gray and can not be turned on
when I do Switch ZigbeeKitchenBulbSwitch in my log :
Item ‘ZigbeeKitchenBulbSwitch’ received command ON
[nt.ItemStatePredictedEvent] - ZigbeeKitchenBulbSwitch predicted to become NULL

If you do

mosquitto_sub -h brokerIpaddress -v -t ‘zigbee2mqtt/#’

You should see all messages that goes to and from zigbee2mqtt. Do you get anything when you press your press your switch? Also take a look at the zigbee2mqtt log to see what happens there.
What version of openhab are you running on? This is done using 2.5.0 m1 release.

Updated with some of the suggestions, hopefully making it a bit more understandable.

Where do I have to put the scripts?
In the transform directory I get the error:

2019-04-18 13:43:01.755 [WARN ] [l.generic.ChannelStateTransformation] - Transformation service JS for pattern tradfri2openhab.js not found!


Yes in the transform directory. Double check names and that you have the JavaScript transformation addon installed.
Could also be a permission thing, check that the script is accessible for the openhab user.

Regards s

The JavaScript Transformation was missing

1 Like

Hi everyone,

i have some similar problems with my brightness channel of my innr RB 285 C RGBW bulb.
MQTT is running fine with other devices and iam on OH2 2.4 stable.
My problem is, that the parameter transformationPatternOut, which points to my JS transformation script, has no effect. Even when i change the script to return fixed value, mqtt recieves the plain, unchanged dimmer value from the item. The JS tranformation of transformationPattern is working instead. If i use formatBeforePublish="{“brightness_percent”:%s}" instead of transformationPatternOut, it works. I tried to get it working several hours and triple chcked filenames. It looks like the outgoing transformation statement is ignored by the MQTT binding. Can anyone confirm this? I also tried transformationPatternOut=“JSONPATH:$.brightness”, whis also doesnt work.
So finally either iam totally stupid or it is really a bug with the MQTT binding?
The OP used OH2 2.5.0-M1, would this solve my issue? If yes, how can i savely upgrade or is there a nice smooth workaround?

My Config is as follows:


Thing topic LivingRoomFloorLight4 "Wohnzimmer Bodenlampe"  @ "Wohnzimmer"{
            Type switch : status "Status" 
            [ stateTopic="zigbee2mqtt/RgbwLampWZFloor", commandTopic="zigbee2mqtt/RgbwLampWZFloor/set", transformationPattern="JSONPATH:$.state", on="ON", off="OFF" ]
            Type dimmer : brightness "Helligkeit" 
            [ min=0, max=100, step=1, stateTopic="zigbee2mqtt/RgbwLampWZFloor", transformationPattern="JS:innr2openhab.js", commandTopic="zigbee2mqtt/RgbwLampWZFloor/set", transformationPatternOut="JS:openhab2innr.js"] //formatBeforePublish="{\"brightness_percent\":%s}"]
            Type number : linkquality "RSSI"
            [ stateTopic="zigbee2mqtt/RgbwLampWZFloor", transformationPattern="JSONPATH:$.linkquality" ]


(function(x) {
    var result;
    var json = JSON.parse(x);
    result = Math.round(((json.brightness / 255) * 100));
    return result;


	var result = new Object();
	result.brightness = Math.round(x*255/100);
	return JSON.stringify(result);

Is there a way to see the logs generated by zigbee2mqtt realtime? I cannot figure out how to pair a zigbee device (in my case a relay) , like how I usually do with a z wave device without looking at the logs.
Can I put it on the OH dashboard?

I don’t know how to display them in the log viewer of openhab, but Zigbee2mqtt is generating its own log in real-time. You can access it via the console

Sorry, but how do I access via the “console”?
do you mean the karaf console?

zigbee2mqtt has a pretty good documentation. Just type sudo journalctl -u zigbee2mqtt.service -f and you’ll see the log

1 Like

How to convert mqtt output "zigbee2mqtt/Zigbee_Ikea_Dnevna/set 1 ? I use above tutorial with switch2zigbee2mqtt.js. I try with “formatBeforePublish” and “MAP” but without success. If I run mqtt messages
mosquitto_pub -h localhost -t ‘zigbee2mqtt/Zigbee_Ikea_Dnevna/set’ -m ‘{“state”:“1”}’ or
mosquitto_pub -h localhost -t ‘zigbee2mqtt/Zigbee_Ikea_Dnevna/set’ -m ‘{“state”:“ON”}’
I can turn ON the Ikea bulb.

I managed to get everything running with this thread.

The tradfri bulbs offer two additional values: color_temp and color_mode
I cannot change color_mode with a mqtt client, but color_temp is possible
How do I know the possible range? Is there a possibility to find that out?
I looked at the zigbee2mqtt documentation and it seems it just offers the option to GET the current values.

Thank you


I didn’t find out in the meantime how to get the range from the device, but I want to share you my solution for setting the color temp without js conversion (in my opinion we can use the “real” temperature values here, no need for a mapping)

mqtt.things channel definition
I use the device/set/{property} topic, which works without json conversion but by direct numerical values

Type number : ikea1colortemp "Ikea Bulb 01 Color Temp" [ stateTopic="zigbee2mqtt/bulb1",  transformationPattern="JSONPATH:$.color_temp", commandTopic="zigbee2mqtt/bulb1/set/color_temp"]


Number Ikea1Colortemp "Ikea bulb 01 color temp" {channel="mqtt:topic:zigbee2mqtt:ikea1colortemp"}


Setpoint item=Ikea1Colortemp label="Ikea Wohnzimmer rechts Farbtemperatur" step=25 minValue=250 maxValue=454

I just used a setpoint here to set the values I found out are possible: 250 to 454

But this is only for fine tuning. I set up different scenes by using rules

e.g. normal lightning

rule "Normales Licht"
Item IkeaScene2 received command ON
sendCommand(gL, ON)
sendCommand(Ikea1Brightness, 80)
sendCommand(Ikea2Brightness, 80)
sendCommand(Ikea3Brightness, 80)
sendCommand(Ikea1Colortemp, 350)
sendCommand(Ikea2Colortemp, 350)
sendCommand(Ikea3Colortemp, 350)
1 Like