Use ESP8266 to control unlimited groups of milight or limitless LED bulbs in Openhab2

I have been waiting for Milight (also sold as Limitless LED and Easybulb) to release a bridge with support for >4 groups for a while, so I was very happy when recently I came across the ability to make your own Milight bridge with an ESP8266 and nrf radio. It’s working so well for me I thought I would share how to get it running to save others any issues I came across. You do not need to solder and it costs around $10!

UPDATE: I have now created a binding for this hub so you do not need to create rules anymore unless you prefer to do things the hard way :slight_smile: The binding is found in this following thread:

Advantages of using this hub over using the OEM milight hubs are:

  1. Supports more than 4 groups from a single hub so all your globes have individual control.
  2. Updates openhab when the milight remotes are pressed.
  3. Uses MQTT which is lower latency, less delay for things to happen.
  4. If you prefer to use the milight binding via UDP instead of MQTT this bridge supports that by using emulation.
  5. If openhab is re-started the MQTT broker updates the controls in openhab when it re-connects, so the globes match the controls.
  6. Active opensource project that if new globes are released you only need a new firmware.

In depth details on how to build and what the bridge is can be found here:
http://blog.christophermullins.com/2017/02/11/milight-wifi-gateway-emulator-on-an-esp8266/

A quick overview of the steps to get the hardware going are:

  1. Connect a nodemcu/esp8266 to your computer via USB
  2. Download the latest BIN file from here https://github.com/sidoh/esp8266_milight_hub/releases
  3. Download esp8266flasher if you are on windows https://github.com/nodemcu/nodemcu-flasher
    Check the blog above on more info on how to do it from mac or linux.
  4. Open the flasher tool and make sure the flash size is 4mb or whatever your esp8266 board has.
  5. Flash the bin and then press the reset button on the nodemcu board when complete.
  6. Connect to the wifi access point of the esp directly and setup to connect to your network. Blog has more info.
  7. Login by using the IP address of the esp8266 in a web browser and the control panel will show up.
  8. Connect 7 wires between the two ready made PCBs as shown in the above blog.

You then need to get MQTT running as this method uses the faster and lightweight MQTT protcol and not UDP. If you wish to use the milight binding with this ESP hub you can use the UDP method and details on how to do this are found here.

To get MQTT running google mosquitto and how to install a broker. If using openhabian you can use the linux command ‘sudo openhabian-config’ and select the menu option to install and setup mosquitto for you. Once setup you can use this linux command to watch all milight topics which is handy for fault finding…

mosquitto_sub -u usernamehere -P passwordhere -p 1883 -v -t 'milight/#'

change the -p to your port if not using the default 1883 port.

Next step is to use paperUI to install the MQTT Binding, if this is successful it will auto create a file you need to edit, if the file is missing then the binding is not installed by paperUI.
\OPENHABIANPI\openHAB-conf\services\mqtt.cfg

Put these lines in the file:

mqtt:mosquitto.url=tcp://192.168.1.100:1883
mosquitto.clientId=openHab
mosquitto.user=UserNameForMqttHere
mosquitto.pwd=PasswordHere
mosquitto.qos=0
mosquitto.retain=false
mosquitto.async=true

If you called your broker something other than mosquitto you will need to change the above to match the brokers name. Also change the IP address and port to match the brokers location. You can use localhost instead of an IP.

Reboot your openhab server after saving and it should be setup.

Enter the control panel for the ESP8266 by using any browser and entering the IP address.
Setup the following:

mqtt_topic_pattern

milight/commands/:device_id/:device_type/:group_id

mqtt_state_topic_pattern

milight/states/:device_id/:device_type/:group_id

In the box called “group_state_fields” you need to untick brightness and Color, then you need to tick level, hue and saturation instead. Leave the rest on defaults.

Fill in the other fields for your MQTT broker.
Click save down the bottom and now when you use a milight remote control you will see MQTT topics being created.

Once again you can use this linux command to watch all topics from milight:

mosquitto_sub -u usernamehere -P passwordhere -p 1883 -v -t 'milight/#'

You can also use the mosquitto_pub command to send your own commands and watch the bulbs respond to test before getting into setting up openhabs items.

Now for the changes to OpenHab2 files…

Sitemap:

Text label="Milight hallway globe" icon="light" 
{
Switch 		item=Milight_ID1_G1_State
Slider 		item=Milight_ID1_G1_Brightness
Slider 		item=Milight_ID1_G1_CTemp
Colorpicker 	item=Milight_ID1_G1_Hue
}

Items:

String Milight_ID1_G1_Light {mqtt=">[mosquitto:milight/commands/0x1/rgb_cct/1:command:*:default]"}
String Milight_ID1_G1_EspMilightHub {mqtt="<[mosquitto:milight/states/0x1/rgb_cct/1:state:default]"}
Switch Milight_ID1_G1_State "Light On/Off"
Dimmer Milight_ID1_G1_Brightness "Brightness"   
Dimmer Milight_ID1_G1_CTemp "White Color Temp"   
Color  Milight_ID1_G1_Hue "Color Hue"   

These rules MUST be used with firmware 1.6.0 RC3 or higher loaded into the esp8266 otherwise the remote will not control Openhab.
Create a file called ‘milight.rules’ and place it into the “openhab2-conf\rules” folder.

Rules:

rule "Milight_ID1_G1_ONOFF"
  when
	Item Milight_ID1_G1_State received command
  then
	Milight_ID1_G1_Light.sendCommand('{"state":"'+receivedCommand+'"}')
end


rule "Milight_ID1_G1_BRIGHT"
  when
	Item Milight_ID1_G1_Brightness received command
  then
	var iLEVEL = (receivedCommand as PercentType).intValue
	
	if(Milight_ID1_G1_State.state==OFF) // Needed to keep openhab up to date if incoming MQTT is disabled.
	Milight_ID1_G1_State.postUpdate(ON)

	Milight_ID1_G1_Light.sendCommand('{"state":"ON","level":'+iLEVEL+'}') // Using level means values from 0 to 100 and not 0-255
end


rule "Milight_ID1_G1_CT"
  when
	Item Milight_ID1_G1_CTemp received command
  then
	var iVAL = (receivedCommand as DecimalType).intValue
	var iCTEMP = (370-(2.17*iVAL)).intValue // Scale values to range from 370 to 153
	
	if(Milight_ID1_G1_State.state==OFF) // Needed to keep openhab up to date if incoming MQTT is disabled.
	Milight_ID1_G1_State.postUpdate(ON)

    Milight_ID1_G1_Light.sendCommand('{"state":"ON","color_temp":'+iCTEMP+'}')
end


rule "Milight_ID1_G1_HUE"
  when
	Item Milight_ID1_G1_Hue received command
  then
	var iHUE 	= Math::round((receivedCommand as HSBType).getHue.intValue)
	var iSAT 	= Math::round((receivedCommand as HSBType).getSaturation.intValue)
	var iLEVEL 	= Math::round((receivedCommand as HSBType).getBrightness.intValue)
	Milight_ID1_G1_Light.sendCommand('{"state":"ON","level":'+iLEVEL+',"hue":'+iHUE+',"saturation":'+iSAT+'}')
end

// Rule for updating controls in Openhab when a milight remote is used //
// Only use postUpdate in here to prevent Openhab sending a command in response and causing pot. feedback//
rule "Milight_ID1_G1_HubStates"
  when
	Item Milight_ID1_G1_EspMilightHub changed
  then
	var sJSONBLOB = Milight_ID1_G1_EspMilightHub.state.toString
	var sMODE =	transform("JSONPATH","$.bulb_mode", sJSONBLOB)
	var sSTATE=	transform("JSONPATH","$.state", sJSONBLOB)
	var sLEVEL=	transform("JSONPATH","$.level", sJSONBLOB)
	var Number iLEVEL= Integer::parseInt(sLEVEL).intValue //convert the string to an int.
	
	if(Milight_ID1_G1_State.state!=sSTATE)
	Milight_ID1_G1_State.postUpdate(sSTATE)
	
	if(sMODE=="white") // Code to handle a white JSON blob
	{
		var sCTEMP=transform("JSONPATH","$.color_temp", sJSONBLOB)
		var iTempScaled=(((Integer::parseInt(sCTEMP)/2.17)-171)*-1).intValue //Dirty but seems to work. Converts string to int and scale range.
		Milight_ID1_G1_CTemp.postUpdate(iTempScaled) //send CT to globe
		Milight_ID1_G1_Brightness.postUpdate(iLEVEL) //send new brightness to globe
	}
	
	else if(sMODE=="color") // Code to handle a colour JSON blob
	{		
		var String sHUE			= transform("JSONPATH","$.hue", sJSONBLOB)
		var String sSATURATION	= transform("JSONPATH","$.saturation", sJSONBLOB)
		Milight_ID1_G1_Brightness.postUpdate(iLEVEL) 	//update main dimmer item
		Milight_ID1_G1_Hue.postUpdate(sHUE+","+sSATURATION+","+sLEVEL)		//update color item      
	}
end

Note: The above is for one of the RGB+WW+CW also called rgb+cct globes which is setup/paired to a remotes device ID of 1 and a group of 1. Each milight remote has a hard coded device ID and for each of these you can have four groups. Bulbs do not have an ID and you pair/sync them to a device ID for a remote. You can have multiple remotes paired to a single globe at the same time. For example I have 1 remote that is paired to every globe in the house for testing, plus I have openhab paired and controlling every globe individually.

These are the better Milight globes to use that have saturation controls that older and cheaper globes do not:
http://www.limitlessled.com/shop/rgbw-ww-cw-light-bulb/

11 Likes

Thanks for the links. Looked at this along time ago, someone using an arduino with ethernet shield and rf transciever. Esp all the way…

Yes the ESP8266 is a great value and powerful little setup, in case you had not found them there are currently three different projects for making your own milight bridge, they are:

http://www.rflink.nl/blog2/devlist

I have not tried the other two as Chris Mullins has done an excellent job documenting everything and is making releases every few days so it is very active.

2 Likes

Hey Matt,

This is a really great writeup. Would love to incorporate this into the project documentation if that’s okay with you. I’m happy to paste/adapt your post, or you can let me know what you want it to look like if you prefer.

Hi Chris,

Yes your welcome to use it as you wish. I do feel the openhab code is better linked to here so I can update it as I improve the openhab side of things, or if you change the MQTT implementation and a newer firmware needs openhab changes. Also that would mean I get people asking for help here instead of you getting hammered with questions from noobs freeing you up to do more coding :wink:

At the moment I’m looking at learning how to write openhab2 bindings so I can make this easier for others then what is posted above. It may/will end up easier for me to create the binding compared to using rules to parse the MQTT updates for when a physical milight remote is pressed. It would then also be possible to add a feature that would auto find and add all globes automatically for end users. The OEM official bridges and milight bindings do not have that ability so it would really make sense to throw away any official bridge/s if you owned one and move to a setup with esp8266 and gain full individual control over many globes.

Thanks for your hard work on this and I look forward to the next release that can handle high rates of commands being sent and the fixes for windows compiling.

Thanks Matt, makes sense to link back here. Added a link on the wiki:

Thanks again for writing this up!

Just a note that I updated the first post with new updated rules that work better for changing colours as previously 1 out of 5 changes were missed. Changing colours now works perfectly unless you hold and swipe around the colour wheel which overloads the current firmware of the esp8266. Just do a single tap for the colour you want and it works great.

is there instruction how to use milight remote with openhab (to keep a state in sync with openhab)?

This setting found in the espMH control panel allows any changes by the milight remotes to send MQTT updates to Openhab and I can confirm it is already sending the MQTT updates.

mqtt_update_topic_pattern
milight/updates/:device_id/:device_type/:group_id

What still needs to be done is to either write openhab rules to parse the incoming MQTT, OR a new binding can be written which will give more benefits. In my free time I am learning at how bindings are created, probably Christmas time I may actually have enough spare time. I will look at doing a rule for on and off only and post it here so you can see how it is done. Then you can try the remote out.

I think I’m in the same boat here.

I’ve purchased a Milight 8 zone RGB+CCT remote and 1 RGB+CCT bulb.

I can control the bulb with the remote and with the ESP8266 using Version 1.6.0_dev9. But I can not seem to control the bulb via OH2.

I do see the MQTT being published when I use 1) the remote control, 2) logged into the ESP8266, and 3) MQTT updates from an OH2 sitemap for ON|OFF, Brightness, and Temp. But I do not see any MQTT updates from OH2 for the color wheel.

But I can not seem to get the Bulb itself to react to OH2 commands including ON and OFF. I see the update in MQTT, but guessing the rule is not parsing correctly. I’m not sure how to exactly confirm my device ID and other info to ensure my Item file information is correct. I did install the Milight binding as well, and that finds the ESP8266 and reports the Bridge being Online with I think I ID of all zeros, ie, Bridge 000000000000

I’m hoping long term here to be able to with the remote to being able to also update/change the color of my philips and lightify bulbs.

What is your remote I’d and the group number of the globe? If the remote is paired with the globe move the remote and watch mqtt. Post what is published as that will tell u the remote Id and the group of the globe. Enter those into the Control panel of the esp8266 up the very top and see
If u can control the globe? If so then u know the hardware is working, the. We just need to edit the openhab rules to match your remote and globe I’d and group.

One thing to be aware of is the mqtt remote Id needs to be in decimal and in the esp2866 control panel it needs to be in hex! Huge pain they r not consistent. The 8266 control panel has the sniff feature and it will report the id in hex whilst mqtt updates will be
In decimal. Sniff works by capturing any remote movements and displaying a log output. Post some more info of what u see being published and check the openhab logs and post their contents when u move a control. Lastly I will need to see how I have edited the code to match your remote I’d and group number.

In the 8266 Control Panel, I can control the bulb as follows. Think this may mean ID 0?

And when I use the slider on either remote or in the 8266 control panel, I see this information in MQTT

 mosquitto_sub -u openhab -P XXXXX -p 1883 -t '#'
{"hue":126}
{"hue":25}
{"saturation":20}
{"color_temp":183}
{"color_temp":270}
{"hue":1}
{"hue":356}
{"hue":349}
{"hue":343}
{"hue":339}
{"hue":335}
{"hue":332}
{"hue":330}
{"hue":328}
{"hue":337}
{"hue":349}
{"hue":352}
{"brightness":232}
{"brightness":219}
{"brightness":196}

What I think was strange was that when I first had the 1.5 firmware on there, MQTT reported more info including group info. But the current 1.6.0_dev9 shows only the above.

26804 is your remote Id in decimal. The photo of the esp8266 gave me the hex of 68B4 and I used an online calc here to convert.
http://www.rapidtables.com/convert/number/hex-to-decimal.htm
Your using group 1 so the code for openhab needs to be edited with those details to work, or you can pair two remotes to the globe to test my code unchanged.

0x68b4 the 0x means this is hex aka base 16 number. Drop the 0x as it is not part of the number it is just to indicate it is hex and you have the remotes code.

1.5 of the esp8266 published to mqtt differently make sure u use the same version I posted my rules have been tested to work with in my first post.

I think I only need to change that in first spot for the remote ID, and not the group ID and it appears to be working.

So this:

becomes this

And I also found you can use the Hex value as well. This appears to be working as well

Next is to learn how to using the remote control to update other Philips bulb with a Rule.

Yes u only needed to edit that one line if u only own one globe. The other lines need to be unique if u want to get more globes going with separate controls for each but it sounds like u have the hang of it now.

In attempting to learn here this morning more about OH2 and using Mosquitto, have anyone had any luck at getting the Milight remote control to pass its input into OH2? I see Mosquitto is logging the info when the remote is used, I just haven’t figure out yet how to perhaps configure an item file for an Inbound message from the remote in Mosquitto, and then pass that information over to a rule yet.

After searching and reading, I was trying first with just something like to perhaps get a test switch to turn on and off when using the Milight remote, but no luck so far. I’m really not even sure if the Item should be a Switch or a String.

Item

Switch TestMQTT "Testing" {mqtt=">[mosquitto:milight/commands/0x68B4/rgb_cct/1:command:ON:1],>[mosquitto:milight/commands/0x68B4/rgb_cct/1:command:OFF:0],<[mosquitto:milight/commands/0x68B4/rgb_cct/1:command:MAP(en.map)]"}

and the rule

rule "Test MQTT Received"
	when
		Item TestMQTT received command
	then
		sendCommand(TestSwitch, ON)
end

I won’t have time until Sunday to have a play. You should only have to modify that same string line and then use a rule to parse all the incoming mqtt messages from the one mqtt topic for that globe. The one rule will need to handle state, brightness, hue etc. the colour will be complex which is why I prefer to spend the time creating a binding.

The MQTT topics should always substitute the hexadecimal value for the device ID. I think v1.5 and earlier sent the decimal value of the remote ID in the JSON blob simply because it felt weird to send a string for something that is an integer. But v1.6 and later don’t send the device ID in the JSON blob, so hopefully that makes things less confusing.

However, the formatting of the device ID in the MQTT topics should be more explicit. Created this issue: https://github.com/sidoh/esp8266_milight_hub/issues/143.