Zentyal‎ > ‎UniFi‎ > ‎

Controlling color-changing lights from a computer for <$100

Start with a quick demonstration, artfully compiled by google auto-awesome.
What this project covers is how to control RGB (red green blue) LED lights from a PC through your existing WiFi network.  To do this, you need a few items; you can get started with controlling RGB LEDs for less than $100.

Parts

  • A power supply.  Start with a 12V 2A DC transformer of some sort.  I've used old laptop and router power supplies.  I'm still learning about the engineering here, but my understanding is more amps means you can power more lights.  But there's a limit; there is a voltage drop over the length of the light strip and at some point the power will need to be refreshed if you're going to power a lot of lights.  And I'm not sure about the load capacity of the LED controllers.

  • RGB LED lights.  I like LED tape due to its versatility.  It has a sticky backing that'll adhere to most surfaces.  You can get it with varying degrees of weather ratings.

  • And finally, you need a controller.  I've used two types.
    • This one needs more parts and is not as great:

       don't get this one; the rest of this guide will only cover the next one.






    • This one is a better product both in terms of construction and firmware:

      yup.  much better.  get that one.



Setup

Wring:
If you got the power supply we recommended above, you need to know a little bit about electrical wiring to hook it up.  What I did was cut the end off a PC power cable to expose the raw wires, which will need to be connected to the screw terminals.  Black is line (L - screw 9), white is neutral (N - screw 8), and green is ground (screw 7).  Screws 1, 2, and 3 are V+.  Screws 4, 5, and 6 are V-.  You need to connect one V+ and one V- to your WiFi LED controller.

Setup the WiFi controller:
When you first turn on your WiFi LED controller, it'll be broadcasting a WiFi network called "LEDnetXXXXXXXXXXXX" where the Xs are the BSSID.  You need to hop onto the network (WPA key is "88888888") and browse to the WiFi controller (http://192.168.10.1/) so you can reconfigure a couple things.  The username is: admin with password: nimda


  1. Setup the STA parameters according to your existing WiFi LAN.  Setting these parameters will make the LED WiFi controller available on your network.  I broadcast a special SSID called LEDnet just for these adapters; my WiFi infrastructure (UniFi), enables multiple SSIDs with client access rights.  It's off-topic, but I highly recommend UniFi.




  2. Hide the SSID in the AP settings section.  I would disable it altogether if it provided the option.  When it's on your network, there's no reason to let it continue broadcasting a rogue signal.  At least by hiding the SSID it won't be visible.





  3. Set the mode to STA.  I would've expected this to disable the AP interface, but it doesn't.  I suppose it's a bug in the firmware.





All done!  Now you're all set to control your LEDs from a PC.  I wrote the API in javascript so that you can run it with node.js.  I haven't updated it in npm for the new WiFi module yet, however.  Currently the API only covers the first WiFi module, which is not the recommended module.  So until I publish the new API, let me explain the protocol of the adapter by providing a working source code example.

This code was written for Node.JS:

var net = require('net')
var Office = '10.1.1.65' //IP of the LED controller.
var Living = '10.1.1.66' //IP of another LED controller.
var PORT = '5577' //the default port can be changed in the STA settings of the LED controller

//This message gets sent to the controller when the socket connection is established.
//The controller won't accept any other messages until you send this once.
connect = new Buffer([0, 1, 1, 3, 3, 7])

//Here we create an object for one set of lights.
var office = {
  socket: new net.Socket(),
  state : "init",
  connect: function(){ office.socket.connect(PORT, Office) }
}
office.socket.on("error", function(){ office.state = "error" })
office.socket.on("close", function(){ office.state = "close" })
office.socket.on("connect", function(){ 
  office.state = "ready" 
  office.socket.write(connect)
  console.log("office is connected")
})

//And here we create the same object for another set of lights.
var living = {
  socket: new net.Socket(),
  state : "init",
  connect: function(){ living.socket.connect(PORT, Living) }
}
living.socket.on("error", function(){ living.state = "error" })
living.socket.on("close", function(){ living.state = "close" })
living.socket.on("connect", function(){
  living.state = "ready"
  living.socket.write(connect)
  console.log("living room is connected")
})

/**************************************
* In this block, we create an array that we'll use to 
* continually fade the lights through a color wheel.
* See the writeToLight function to understand the
* values of the colors array.
*******************************************/
var step = 1
var colors = []
//Fade red to green
for(var i=0; i<256; i+= step){
  colors.push({r: 255-i, g: i, b: 0})
}
//Fade green to blue
for(var i=0; i<256; i+= step){
  colors.push({r: 0, g: 255-i, b: i})
}
//Fade blue to red
for(var i=0; i<256; i+= step){
  colors.push({r: i, g: 0, b: 255-i})
}


var color = 0 //global variable marking our position within the colors array.
var brightness = 100 //global variable indicating the dim level as a percentage.

function cycle(forward){
  //This function gets called continuously on an interval.  This is what 
  //keeps cycling our lights.  See the key bindings to understand 'forward'
  if(forward){
  color++
  if(color >= colors.length) color = 0
  }else{
color--
  if(color < 0) color = colors.length-1
  }
  writeToLight() //DRY communicate with the lights.
}
function writeToLight()
  /**********************************************************
  * This is the core of the protocol we discovered.  Commands
  * look like this:
  *     [STX], [RED], [GREEN], [BLUE], [ETX]
  * Each field is a hex byte with possible values 00-FF, which
  * are expressed in decimal as 0-255.
  *
  * Each command starts (the STX value) with a value of 86.
  * Each command ends (the ETX value) with a value of 170.
  *
  * The red, green, blue values combine to determine the color
  * and brightness level.  For example:
  *
  *     Bright red would be: 255,0,0
  *     reduce the value to dim; a dim red could be: 40,0,0
  *     Bright green would be: 0,255,0
  *     Bright purple would be: 255,0,255
  *     a dim purple could be 40,0,40
  *     a less dim purple could be 160,0,160
  *
  *     White is: 255,255,255
  *     Off is: 0,0,0
  ************************************************************/
  var red   = Math.round(colors[color].r * brightness / 100)
  var green = Math.round(colors[color].g * brightness / 100)
  var blue  = Math.round(colors[color].b * brightness / 100)
 
    if(office.state == "ready"){
        office.socket.write( new Buffer([86, red, green, blue, 170]) )
    }else{
        //If the state isn't ready, we lost our socket. Try to reconnect.
        office.connect()
  }

  if(living.state == "ready"){
  living.socket.write( new Buffer([86, red, green, blue, 170]) )
  }else{
  //If the state isn't ready, we lost our socket.  Try to reconnect.
  living.connect()
  }
}

var stdin = process.stdin
stdin.setRawMode( true )
stdin.resume()


stdin.on( 'data', function( key ){
  if(key == '\x03'){
        //ctrl+c was pressed.
  process.exit()
  }else if(key == "\x1B\x5BC"){
  //Right arrow key was pressed; cycle forwards through the colors.
  cycle(true)
  }else if(key == "\x1B\x5BD"){
  //Left arrow key.  cycle backwards through the colors.
  cycle()
  }else if(key == "\x1B\x5BA"){
  //up arrow key.  increase the brightness level.
  if(brightness < 100) brightness += 1
  writeToLight()
  }else if(key == "\x1B\x5BB"){
  //down arrow key.  decrease the brightness level.
  if(brightness > 0) brightness -= 1
  writeToLight()
  }else{
  //we don't know what key was pressed.
  //uncomment the following to log the keypress so it can be implemented.
  //process.stdout.write( escape(key) )
  }
})

//This is the continuous interval that constantly changes the lights.
setInterval(function(){ cycle(true) }, 12000)


Comments