Controlling WiFi Lightbulbs (aka MiLight/AppLamp/LimitlessLED/Easybulb etc...) via UDP Packets?

2,633 views
Skip to first unread message

Andrew Jawitz

unread,
Dec 3, 2014, 11:50:39 AM12/3/14
to node...@googlegroups.com
  While I've already posted on this question in the thread on "Creating a universal WiFi LED Bulb Flow?" , I figure that thread will best be left for examining different ways to integrate the growing variety of "smart lighting" protocols becoming commercially available.
   I've created this thread in the hopes of getting advice about how to use NodeRED to control a wireless lighting system based on the WiFi370 platform (aka- LimitlessLED, MiLight, AppLamp, EasyBulb etc....)  
   
    The Wifi Hub controls the lights using UDP commands with each color state specified in a hex code.  This makes it somewhat more complicated to do anything more than turn lights on/off or specify a single color.  Node-RED could come in handy in this regard by automating the specific UDP commands as an output that can be triggered by anything in the Node-RED universe. But as often occurs when i try to use the NodeRED platform, I'm having trouble figuring out the best way to set this up.
  
  For example,according to the LimitlessLED/dev/api page the following command can be triggered, 

 to turn all RGBW COLOR LimitlessLED Smart lights to ON then send the TCP/IP UDP packet of:  0x42 0x00 0x55
 
Thus far I've seen nothing I can use as a template from the NR library, so can anybody recommend how would I set this up in an NR Flow?  Would I enter the commands into a function node or as a UDP input?

 There are multiple other resources and code libraries available, which I've listed below (and in the "Universal Wifi" thread,)



 .  In the information below, you'll see there are multiple repositories on NPM as well as some control scripts written for Node.js.

Node.js Drivers/scripts-
 
  Is there a template/tutorial available (beyond what is written under http://nodered.org/docs/writing-functions.html) that would help me use for example, the node-rgb available on NPM, to build a custom Node? 


   There are probably other ways of automating these smart lighting systems, but it just seems like the perfect candidate for NodeRED!

                                                                                                                       Thank You Very Much
  

 

Andrea Ghensi

unread,
Jan 18, 2015, 5:50:00 AM1/18/15
to node...@googlegroups.com
Hi Andrew, we had a chat some time ago at sleep as android support group. You talked about MQTT and node-RED so here I am, spending my free time in this project!
I don't know if you've managed to solve your problems, but yesterday I spent 6 hours learning how to write node-RED functions and creating this simple flow that can address what you're trying to do:
http://flows.nodered.org/flow/b2cb3bdc5a81ac881d4b

Now I can control lights with tasker via MQTT sender plugin (https://play.google.com/store/apps/details?id=com.toucware.mqttsender), and there's also another plugin that is open source: https://github.com/bodiroga/mqtter/tree/master/Mqtter.

Maybe I should remove the "whiteMode" and instead check for a "white" message with the "hue" subtopic, so I can use MQTT to fake a "current status". same applies to disco mode. The advantage of this approach is that you can modify the MQTT parsing function without touching the translation of the simple commands to Milight codes.

Also, using the UDP out code instead of implementing it in a single node will allow me to easily change it with a serial out node as soon as I find the time (and courage) to hack te wifibox and hardwire it to my olinuxino (something like a RasPi) as someone else did with an Arduino (http://www.geekzone.co.nz/forums.asp?forumid=73&topicid=113569&page_no=29#1098309).

The next step is to create another flow that listens for an "alarm start" and "alarm stop" and takes care of sending the right sequence of MQTT messages to recreate what I did in tasker for the sunrise alarm, so I need only 2 messages from my smartphone to my server, and the rest is managed by node-red.

Then, I'll investigate homA (https://github.com/binarybucks/homA) to move the entire alarm clock logic to the server (I don't use the sleep tracking thing anymore, so just starting the alarm 30min before my wakeup time is fine for me) and use the homA android app to set the alarm.

Hope you find this useful,
happy hacking!

Andrea Ghensi

unread,
Jan 18, 2015, 11:01:50 AM1/18/15
to node...@googlegroups.com
Hi Andrew,
I've managed to create a really simple sunrise alarm! This time I used a linear curve for the brightness, but it can be modified with little code.
now I can send only the MQTT message "start" to the "alarmclock" topic of my mqtt broker. stopping the alarm is also as simple as sending the "stop" message to the same topic. To avoid flashes in the morning, the "setup" message takes care of setting the light in white mode at minimum brigthness, then turns all the lights off (and stops the music, see below).
Obviously you need the flow I posted before; I hardwired the controlled light group in the code, change the lightsMsg assignments in the function to change it.
The function also sends messages to my mopidy music daemon, if you don't need it just remove the nodes attached to the third output and don't bother editing the code :) or simply remove any line that contain audioMsg, remove it from the last line and change the outputs number to 2.

Now I got why everyone uses JS :)
Happy hacking!

[{"id":"a1e6a9c6.5e1958","type":"mqtt-broker","broker":"localhost","port":"1883","clientid":""},{"id":"33d9dd31.cc2622","type":"mqtt in","name":"Alarm Clock MQTT","topic":"alarmclock","broker":"a1e6a9c6.5e1958","x":120,"y":218.75000286102295,"z":"77df6b64.882094","wires":[["f7bcc557.084338"]]},{"id":"f68d624d.0972a","type":"mqtt out","name":"Lights MQTT","topic":"","qos":"","retain":"","broker":"a1e6a9c6.5e1958","x":615.0000076293945,"y":205.0000033378601,"z":"77df6b64.882094","wires":[]},{"id":"94e11e5b.6b1ee","type":"http request","name":"Mopidy JsonRPC","method":"POST","url":"http://localhost:6680/mopidy/rpc","x":753.7500076293945,"y":247.50000381469727,"z":"77df6b64.882094","wires":[[]]},{"id":"f7bcc557.084338","type":"function","name":"Sunrise Alarm Control","func":"var lightMsg = null;\nvar audioMsg = null;\nswitch (msg.payload) {\n\tcase \"setup\":\n\t\tcontext.stopped = 1;\n\t\tmsg = null;\n\t\tlightMsg = [{topic:\"lights/1/whitemode\", payload:\"yes\"},{topic:\"lights/1/brightness\", payload:1},{topic:\"lights/0/power\", payload:\"off\"}];\n\t\taudioMsg = {payload:{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"core.playback.stop\"}};\t\n\tcase \"start\":\n\t\t//initialize loop, switch on the lights at minimum brightness and start classical music from spotify, but muted\n\t\tcontext.stopped = 0;\n\t\tmsg.payload = 1;\n\t\tlightMsg = [{topic:\"lights/1/whitemode\", payload:\"yes\"},{topic:\"lights/1/brightness\", payload:1}];\n\t\taudioMsg = [{payload:{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"core.tracklist.clear\"}},\n\t\t\t\t\t{payload:{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"core.tracklist.add\",\"params\":{\"uri\":\"spotify:user:spotify:playlist:63dDpdoVHvx5RkK87g4LKk\"}}},\n\t\t\t\t\t{payload:{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"core.tracklist.shuffle\"}},\n\t\t\t\t\t{payload:{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"core.playback.set_volume\",\"params\":[0]}},\n\t\t\t\t\t{payload:{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"core.playback.play\"}}];\n\t\tbreak;\n\tcase \"stop\":\n\t\t//switch off the light and stops the music\n\t\tcontext.stopped = 1;\n\t\tmsg = null;\n\t\tlightMsg = {topic:\"lights/1/power\", payload:\"off\"};\n\t\taudioMsg = {payload:{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"core.playback.stop\"}};\n\t\tbreak;\n\tcase 101:\n\t\t//natural end of the loop\n\t\tmsg = null;\n\t\tbreak;\n\tdefault:\n\t\tif (context.stopped == 0) {\n\t\t\t//set the right brightness and volume based on the payload value and increments it\n\t\t\tlightMsg = {topic:\"lights/1/brightness\", payload:msg.payload};\n\t\t\taudioMsg = {payload:{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"core.playback.set_volume\",\"params\":[Math.ceil(1+(msg.payload-1)*72/99)]}};\n\t\t\tmsg.payload ++;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tmsg = null;\n\t\t}\n\t\tbreak;\n}\nreturn [ msg , lightMsg, audioMsg ];","outputs":"3","x":358.75000762939453,"y":218.75000381469727,"z":"77df6b64.882094","wires":[["18ea3251.e715ce"],["f68d624d.0972a"],["57f68bf0.a80974"]]},{"id":"18ea3251.e715ce","type":"delay","name":"","pauseType":"delay","timeout":"12","timeoutUnits":"seconds","rate":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":363.75000762939453,"y":133.75000190734863,"z":"77df6b64.882094","wires":[["f7bcc557.084338"]]},{"id":"57f68bf0.a80974","type":"delay","name":"","pauseType":"rate","timeout":"3","timeoutUnits":"seconds","rate":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":577.5000076293945,"y":247.50000381469727,"z":"77df6b64.882094","wires":[["94e11e5b.6b1ee"]]}]

Andrew Jawitz

unread,
Jan 19, 2015, 12:10:01 PM1/19/15
to node...@googlegroups.com
OMFG!  You are my HERO!!!  I was only able to get so far with the existing flows I could find... 
  This will help me majorly since my morning routines actually involve more interactions then the MiLight bulbs alone.  Basically,  I have to wake up twice every morning... I have to take a certain medication exactly one hour before I really wake up so I actually need to alarms. Unless I could remember to set out the correct medication next to a cup of water, i always found myself making a mess of everything in my half-awakened state.  
   So my solution involves three major functions.  The first one is the sleep cycle tracker/alarm on my Pebble Watch, the next next is the smart lighting system and the third is a smart medication dispensing cup.
    The following images can explain-

            The med dispenser is actually a 3D Printed Mason Jar lid, with a screened spout where I put the pill in the night before.  I then snap the cover shut in case it gets knocked over in the evening.

I then attached a Neopixel RGB-LED Ring to an Arduino Yun that can be wirelessly triggered via MQTT-

The ring is embedded in a 3D printed cup holder



Ideally, the LED will be triggered to blink red and white when my first alarm goes off while my MiLight will still be in Night mode-

When I take my medication I can then scan the NFC tag next to the cup which will turn off the alarm sequence and begin the sequence for the daylight alarm on the MiLight bulbs...

  I had been using code from this sketch (https://github.com/sourceperl/arduino.yun.ikea-fado) to trigger the Neopixel Ring on the Yun, but it is only good for changing into solid colors.  I would like to do much much more, but the code for Adafruit's Neopixel's is much more complex than regular RGB LEDs unfortunately...

  In any case, thanks to you, I can now do almost everything I need from NodeRED!

  P.S-  Have you tried any of the input nodes like Sunrise or OpenWeatherMap? One of my original ideas was to use them to dynamically control when the lights go on based on the time of the day or weather.  I'll play around with the flow you created and see if I can set something up.



First, 

Andrea Ghensi

unread,
Jan 19, 2015, 2:35:13 PM1/19/15
to node...@googlegroups.com
Il giorno lunedì 19 gennaio 2015 18:10:01 UTC+1, Andrew Jawitz ha scritto:
OMFG!  You are my HERO!!!  I was only able to get so far with the existing flows I could find... 

I'm glad to help you, since it was you who pointed me in the "right" (mqtt+nodered) direction! Now an entire new world opens...
By the way, I forgot to test the "setup" function and it obviously don't work because I forgot a "break;" at the end of the case. Just add it after line 8 and you're good to go.
This morning the alarm didn't trigger, but It was the tasker profile that had something wrong. Testing it this evening worked like a charm. Let's hope for tomorrow (in the meantime, a classic alarm on my phone is still enabled :P )

Unless I could remember to set out the correct medication next to a cup of water, i always found myself making a mess of everything in my half-awakened state.

I have some similar problems, even though not health related: I'm trying to build an evening routine (and a morning one), and to get into the habit I'm using some tasker profiles that remind me to do things or open some other app. I would like to be able to track everything down (ie if and when I took some food supplement or did some pushup), but I think it will be a major project upgrade. It could involve MQTT and the integration of Day One (a mac journal app that uses XML entries) with it.
 
  P.S-  Have you tried any of the input nodes like Sunrise or OpenWeatherMap? One of my original ideas was to use them to dynamically control when the lights go on based on the time of the day or weather.  I'll play around with the flow you created and see if I can set something up.

Still have to try the other nodes, but I will surely use one of them to accomplish that. It could be integrated with Owntracks to detect if you're home, but for single room occupancy I think I'll need some sensors...

Right now I'm focused in making a DHT22 (temperature and humidity) sensor work with my olinuxino, and using mosquitto library to publish my room temp/humidity (I bought it a long time ago to keep track of night temperature, but I can also think about pushing a notification to open the window when the humidity is too high, or even start the ceiling fan.... to many ideas!).

Happy hacking!

Andrew Jawitz

unread,
Jan 23, 2015, 12:17:15 PM1/23/15
to node...@googlegroups.com
By the way, I forgot to test the "setup" function and it obviously don't work because I forgot a "break;" at the end of the case. Just add it after line 8 and you're good to go.

Do you mean to edit the function node titled "parse light commands" or to add a new function node for setup?

Andrea Ghensi

unread,
Jan 25, 2015, 5:15:06 AM1/25/15
to node...@googlegroups.com
Il giorno venerdì 23 gennaio 2015 18:17:15 UTC+1, Andrew Jawitz ha scritto:
By the way, I forgot to test the "setup" function and it obviously don't work because I forgot a "break;" at the end of the case. Just add it after line 8 and you're good to go.

Do you mean to edit the function node titled "parse light commands" or to add a new function node for setup?

I meant to edit the "Sunrise alarm" function in the flow I posted on my second message. Anyway, I changed the code to have a gentler sunrise, starting from a red with minimum brightness to a yellow with full brightness, then switch to white at about 30% of brightness (maybe it could be changed with 25% or something like that to have a smoother transition) and go all the way up to white 100% (note I have warm white RGBW led lamp).
Just copy the code below and import it.
I'm also trying to get the suncalc + presence (with owntracks android app) thing working, but I have some problems. For testing purposes (and maybe some other nice things) I've installed the pushbullet node (and the android app) to have notifications for when I leave home (and be sure the lights are switched off). For now I only implemented a "turn on the light when I'm at home, in the evening and awake" because suncalc node only tells you about the beginning of day and night, but not how much light there could be outside. Maybe using multiple suncalc nodes and setting them with diferent types of ends (sunset, civil twilight, golden hour, dusk, etc) we can build the logic to set the brightness and color of the lights... just a thought.
 
[{"id":"a1e6a9c6.5e1958","type":"mqtt-broker","broker":"localhost","port":"1883","clientid":""},{"id":"33d9dd31.cc2622","type":"mqtt in","name":"Alarm Clock MQTT","topic":"alarmclock","broker":"a1e6a9c6.5e1958","x":115.99999237060547,"y":225.75,"z":"77df6b64.882094","wires":[["f7bcc557.084338","3e04700a.c1fb9"]]},{"id":"f68d624d.0972a","type":"mqtt out","name":"Lights MQTT","topic":"","qos":"","retain":"","broker":"a1e6a9c6.5e1958","x":697,"y":222,"z":"77df6b64.882094","wires":[]},{"id":"94e11e5b.6b1ee","type":"http request","name":"Mopidy JsonRPC","method":"POST","url":"http://localhost:6680/mopidy/rpc","x":756.75,"y":342.50000190734863,"z":"77df6b64.882094","wires":[[]]},{"id":"f7bcc557.084338","type":"function","name":"Sunrise Alarm Control","func":"var lightMsg = [];\nvar audioMsg = [];\nswitch (msg.payload) {\n\tcase \"setup\":\n\t\tcontext.stopped = 1;\n\t\tlightMsg = [{topic:\"lights/1/whitemode\", payload:\"yes\"},{topic:\"lights/1/brightness\", payload:30},{topic:\"lights/1/hue\", payload:174},{topic:\"lights/1/brightness\", payload:1},{topic:\"lights/0/power\", payload:\"off\"}];\n\t\taudioMsg = {payload:{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"core.playback.stop\"}};\t\n\t\tmsg = null;\n\t\tbreak;\n\tcase \"start\":\n\t\t//initialize loop, switch on the lights at minimum brightness and start classical music from spotify, but muted\n\t\tcontext.stopped = 0;\n\t\tmsg.payload = 1;\n\t\tlightMsg = [{topic:\"lights/1/hue\", payload:174},{topic:\"lights/1/brightness\", payload:1}];\n\t\taudioMsg = [{payload:{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"core.tracklist.clear\"}},\n\t\t\t\t\t{payload:{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"core.tracklist.add\",\"params\":{\"uri\":\"spotify:user:spotify:playlist:63dDpdoVHvx5RkK87g4LKk\"}}},\n\t\t\t\t\t{payload:{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"core.tracklist.shuffle\"}},\n\t\t\t\t\t{payload:{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"core.playback.set_volume\",\"params\":[0]}},\n\t\t\t\t\t{payload:{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"core.playback.play\"}}];\n\t\tbreak;\n\tcase \"stop\":\n\t\t//switch off the light and stops the music\n\t\tcontext.stopped = 1;\n\t\tmsg = null;\n\t\tlightMsg = {topic:\"lights/1/power\", payload:\"off\"};\n\t\taudioMsg = {payload:{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"core.playback.stop\"}};\n\t\tbreak;\n\t//case 101:\n\tcase 80:\n\t\t//natural end of the loop\n\t\tmsg = null;\n\t\tbreak;\n\tdefault:\n\t\tif (context.stopped == 0) {\n\t\t\tif (msg.payload < 48) {\n\t\t\t\t//from dim red to bright yellow\n\t\t\t\tlightMsg = [{topic:\"lights/1/hue\", payload:(175-msg.payload)},{topic:\"lights/1/brightness\", payload:(Math.ceil(1+(msg.payload-1)*99/46))}];\n\t\t\t} else if (msg.payload == 48) {\n\t\t\t\t//switch to white, 30% of brightness\n\t\t\t\tlightMsg = [{topic:\"lights/1/whitemode\", payload:\"yes\"},{topic:\"lights/1/brightness\", payload:30}];\n\t\t\t} else {\n\t\t\t\t//increase white brightness\n\t\t\t\tlightMsg = [{topic:\"lights/1/brightness\", payload:(Math.ceil(30+(msg.payload-48)*70/31))}];\n\t\t\t}\n\t\t\taudioMsg = {payload:{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"core.playback.set_volume\",\"params\":[Math.ceil(1+(msg.payload-1)*72/76)]}};\n\t\t\tmsg.payload ++;\n\t\t\t//set the right brightness and volume based on the payload value and increments it\n\t\t\t//lightMsg = {topic:\"lights/1/brightness\", payload:msg.payload};\n\t\t\t//audioMsg = {payload:{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"core.playback.set_volume\",\"params\":[Math.ceil(1+(msg.payload-1)*72/99)]}};\n\t\t\t//msg.payload ++;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tmsg = null;\n\t\t}\n\t\tbreak;\n}\nreturn [ msg , lightMsg, audioMsg ];","outputs":"3","x":361.75,"y":313.75000190734863,"z":"77df6b64.882094","wires":[["18ea3251.e715ce"],["f68d624d.0972a"],["57f68bf0.a80974"]]},{"id":"18ea3251.e715ce","type":"delay","name":"","pauseType":"delay","timeout":"15","timeoutUnits":"seconds","rate":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":355.75,"y":257.75,"z":"77df6b64.882094","wires":[["f7bcc557.084338"]]},{"id":"57f68bf0.a80974","type":"delay","name":"","pauseType":"rate","timeout":"3","timeoutUnits":"seconds","rate":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":580.5,"y":342.50000190734863,"z":"77df6b64.882094","wires":[["94e11e5b.6b1ee"]]}] 
Reply all
Reply to author
Forward
0 new messages