Milight control via MQTT

Simple flow that controls MiLight/limitlessLED/AppLamp wireless RGBW lights via MQTT.

  • MQTT in node listens for topic "lights/+/+", where the first subtopic is the light group number and the second is a command that goes along some possible message values:
    • power, "on"/"off"
    • whitemode, "yes"
    • hue, "0-255"
    • brightness, "1-100"
    • disco, "yes"
    • disco, "up"
    • disco, "down"
  • The first function translates MQTT subtopics and messages into a simple command or an array of simple commands, since most controls need the power on/enable group command to be effective
  • The second function takes the simple command and translate it into MiLight 2-bytes code (or 3 bytes code if you uncomment the last line)
  • The delay node ensures that there's at most 1 packet every 100ms, as per MiLight specifications
  • The UDP out node finally send the 2/3-byte code to the MiLight wifi box.
[{"type":"tab","id":"77df6b64.882094","label":"Sheet 1"},{"id":"a1e6a9c6.5e1958","type":"mqtt-broker","broker":"localhost","port":"1883","clientid":""},{"id":"526daa8a.ad9254","type":"udp out","name":"MiLight UDP send","addr":"255.255.255.255","iface":"","port":"8899","outport":"","base64":false,"multicast":"false","x":859.6111450195312,"y":273.2778015136719,"z":"77df6b64.882094","wires":[]},{"id":"91cbca9b.6e3438","type":"mqtt in","name":"Lights MQTT","topic":"lights/+/+","broker":"a1e6a9c6.5e1958","x":127.75,"y":274,"z":"77df6b64.882094","wires":[["4acc7480.b5338c"]]},{"id":"4acc7480.b5338c","type":"function","name":"parse light commands","func":"var newMsg = [];\nvar topics = msg.topic.split(\"/\");\nvar group = parseInt(topics[1]);\nvar command = topics[2];\nswitch (command) {\n\tcase \"power\":\n\t\t//\"on\" or \"off\"\n\t\tnewMsg={payload:{command:msg.payload,value:group}};\n\t\tbreak;\n\tcase \"whitemode\":\n\t\t//should be \"yes\"\n\t\tif ( msg.payload == \"yes\" ) {\n\t\t\tnewMsg=[{payload:{command:\"on\",value:group}},{payload:{command:\"whiteMode\",value:group}}];\n\t\t}\n\t\tbreak;\n\tcase \"hue\":\n\t\t//should be 0-255, not checking it\n\t\tnewMsg=[{payload:{command:\"on\",value:group}},{payload:{command:\"hue\",value:parseInt(msg.payload)}}];\n\t\tbreak;\n\tcase \"brightness\":\n\t\t//should be 1-100, not checking it\n\t\tnewMsg=[{payload:{command:\"on\",value:group}},{payload:{command:\"brightness\",value:parseInt(msg.payload)}}];\n\t\tbreak;\n\tcase \"disco\":\n\t\tswitch (msg.payload) {\n\t\t\t//check if I have to turn them on first\n\t\t\tcase \"yes\":\n\t\t\t\tnewMsg=[{payload:{command:\"on\",value:group}},{payload:{command:\"discoMode\",value:\"\"}}];\n\t\t\t\tbreak;\n\t\t\tcase \"up\":\n\t\t\t\tnewMsg=[{payload:{command:\"on\",value:group}},{payload:{command:\"discoMode\",value:\"\"}},{payload:{command:\"discoSpeedUp\",value:\"\"}}];\n\t\t\t\tbreak;\n\t\t\tcase \"down\":\n\t\t\t\tnewMsg=[{payload:{command:\"on\",value:group}},{payload:{command:\"discoMode\",value:\"\"}},{payload:{command:\"discoSpeedDown\",value:\"\"}}];\n\t\t\t\tbreak;\n\t\t}\n\t\tbreak;\n}\nreturn [newMsg]; ","outputs":1,"x":312.99999618530273,"y":273.88889598846436,"z":"77df6b64.882094","wires":[["f73b6ec4.08c49"]]},{"id":"18702845.e78fd8","type":"delay","name":"","pauseType":"rate","timeout":"100","timeoutUnits":"milliseconds","rate":"10","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":686.5277709960938,"y":274.0278015136719,"z":"77df6b64.882094","wires":[["526daa8a.ad9254"]]},{"id":"f73b6ec4.08c49","type":"function","name":"Translate to Miligt","func":"//wifibox 4 should handle 2 byte data (on limitlessled they mentrion only wifi box 3)\nvar commandCode = [];\nswitch ( msg.payload.command ) {\n\tcase \"on\":\n\t\tcommandCode = [[0x42,0x45,0x47,0x49,0x4B][msg.payload.value],0x00]; \n\t\tbreak;\n\tcase \"off\":\n\t\tcommandCode = [[0x41,0x46,0x48,0x4A,0x4C][msg.payload.value],0x00];\n\t\tbreak;\n\tcase \"hue\": //0-255\n\t\tvar hex = msg.payload.value.toString(16);\n\t\thex = (hex.length < 2) ? '0x0'+hex : '0x'+hex;\n\t\tcommandCode = [0x40,hex];\n\t\tbreak;\n\tcase \"whiteMode\":\n\t\tcommandCode = [[0xC2,0xC5,0xC7,0xC9,0xCB][msg.payload.value],0x00];\n\t\tbreak;\n\tcase \"brightness\": //1-100 => 2 to 27\n\t\tvar hex = Math.max(2,(Math.ceil((msg.payload.value-1)/99*25))+2).toString(16);\n\t\thex = (hex.length < 2) ? '0x0'+hex : '0x'+hex;\n\t\tcommandCode= [0x4E,hex];\n\t\tbreak;\n\tcase \"discoMode\":\n\t\tcommandCode = [0x4D,0x00];\n\t\tbreak;\n\tcase \"discoSpeedUp\":\n\t\tcommandCode = [0x44,0x00];\n\t\tbreak;\n\tcase \"discoSpeedDown\":\n\t\tcommandCode = [0x43,0x00];\n\t\tbreak;\n};\n//commandCode[2]=0x55;\nmsg.payload = new Buffer(commandCode);\nreturn msg;;","outputs":1,"x":512.8611145019531,"y":274.1111145019531,"z":"77df6b64.882094","wires":[["18702845.e78fd8"]]}]
sanzoghenzo

Flow Info

created 2 years, 9 months ago

Node Types

Core
  • delay (x1)
  • function (x2)
  • mqtt in (x1)
  • mqtt-broker (x1)
  • udp out (x1)
Other
  • tab (x1)

Tags

  • millight
  • mqtt
  • udp
  • limitlessled
  • applamp
  • wifi-light
  • light
Copy this flow JSON to your clipboard and then import into Node-RED using the Import From > Clipboard (Ctrl-I) menu option