Ages ago, dismayed by the price of Hue bulbs, I started looking into DIY smart lighting solutions (don't go read the post, please, I hooked a single RGB LED up to a computer and gave it a useless web interface). I put the idea and the project into deep storage (by which I mean I probably wiped it by accident somewhere along the line) and left it alone for a while. Recently, however, I started looking into analog RGB LED strips (where the entire strip is a uniform color, unlike digital or addressable LED strips). A lot of them come packaged with dedicated controllers that you can use with an IR remote, giving a very small subset of possible colors and brightness levels. After unexpectedly receiving one of these kits as a gift, I decided to immediately tear it apart and try to make my own network-enabled smart lighting system.
In accordance with the engineering credo:
Step 1: Make it Work
I ditched the controller assembly that came with the kit and did some research on how to control the strip more precisely. A few options presented themselves:
- A PWM board, like this one from Adafruit. This didn't seem like a bad solution at all, but I realized if I wanted to run more than a couple strips off it I would need quite a bit of current running through this one board. Plus, requires separate transistors.
- Building my own board, mostly just using transistors or MOSFETS. Cheaper and a more lean solution, but requiring three PWM outputs for each strip. Also, I'm lazy.
- This board (also available cheaper here)! It's inexpensive, it is specifically designed for the task at hand, and you can chain it to multiple boards without using more data output pins.
I went with option three, and upon receiving the necessary parts (the controller board and a bunch of DC barrel jack adapters), I cannibalized one of the cables that came with the light strip kit so I could connect it to the board, and started wiring things together.
The cable's wires were red, blue, green, and black, so the ground wire at least was clear. The RGB wires and the RGB terminal labeling on the board? Not so much. After experimentation, I ended up with the green wire in the appropriate terminal and the red and blue wires switched--your mileage may vary. The power terminals are labelled properly, and those went to the barrel jack adapter so that I could use the wall wart that came with the kit (a 12V 6A adapter).
With the strip connected to the control board, I now had to connect an Arduino Uno to the control board. This was relatively simple, with only four wires needed: 5V and GND from the Arduino, one data pin, and one clock pin. The final step was the simplest. Instead of using more pins on my RasPi and Arduino, I opted to use serial communication through USB--as I'd later find, this made reprogramming the Arduino much easier during software development.
Working on software followed roughly the same progression as hardware. The first step was getting the Arduino to properly interact with the driver board. Though I could find literally no documentation on it, an Arduino library does exist for the board, and the included examples are straightforward enough to make writing code reasonably easy. (Quick tip for anyone doing work with the library: any SetColor() calls made between Driver.begin() and Driver.end() set the color for successive boards that are chained together. i.e. the first call sets the first board's color, second call sets the second board's color, etc.) This made it really easy to control the LED strip from the Arduino.
Facilitating communication between the RasPi and the Arduino turned out to be much harder than I'd expected, mostly because of the quirks of serial connections. In order to make the LED strip network-accessible I chose Node to write server code in, which has (surprise, surprise) a module designed for serial communication. The most difficult part of getting the two devices to talk correctly was all of the time before I realized that when an Arduino receives an incoming serial connection it actually resets--in other words, you need to connect to the Arduino and then wait for it to be ready, which I managed by having the board send a simple "ok". I decided on a simple protocol for sending colors to the board, involving '#' as a color delimiter (because try as I might I couldn't get the board to pull a single color value from a char sent over serial) and a single character before the first color representing whether to jump or fade to the next color. A color command would look something like
j tells the server to jump instantly to the next color
With that working, the last software step was to cobble together a webserver to control the whole system--again, thankfully, something easy to do in Node. Red, green, and blue color values could be sent through a POST request, and I hacked together a quick Tasker task and scene to send them from my phone.
And it worked!
Step 2: Make it Better
I picked up a 4-pin extension cable from Amazon so that the strip could be somewhere that wasn't my desk. Even when fully unrolled, the strip was only moderately bright when using an incandescent-ish preset I came up with; I'm pretty sure this was just due to the luminosity difference between blue/green and red, and the strip is much brighter on colors that have higher blue/green components. It does make fantastic "runner lighting", perfect for after your Netflix session is over but you don't want to get up to turn on the lights again. Tested and verified with Daredevil season 02.
My first goal was to build a proper REST API to interact with the control unit. The proper documentation of it is here, on the repo's wiki, but as a quick summary, you can GET
/status/ to obtain info about the server such as its display name, API version, and a list of presets stored on the server. POST-ing
/v1/update/ with some specific parameters actually changes the light color.
I'm working on an Android client to control the lightstrip. I plan on publishing it once I have a proper settings page working. I also made a Pebble watchapp to control the lights, because, screw it, why the hell not. It uses Pebble.js because that was the easiest with which to make HTTP requests (see future plans below). Again, once I can settings working properly, I'll publish it.
Finally, I implemented a few miscellaneous features, namely fading lights from one color to another (which is now handled on the server end rather than the Arduino end--I might flip-flop this around again in the future), a configuration section in the server JS, presets stored in the server and usable by clients, and optional HTTP authentication. I had to motivate myself for that last one, so I gave a copy of the beta Android app--with my server's IP address hardcoded in--to my friend Alan.
Alan enjoyed this.
Step 3: Make it Better-er
Considering my original motivation was being ticked at the price of Hue equipment, I tried to figure out what the general cost of this sort of system would be to a new adopter, but it's not as straightforward as I thought it would be (I'm assuming my future hypothetical version that can handle multiple light strips). First of all, for controlling computer: you can use any Linux computer that you want to use as a server. I figured a RasPi was a logical choice, but you only need one no matter how many LED strips you're using. Same with the Arduino--only one necessary. I used an Uno because it can output 5V (for powering the control board), but I'm sure it's possible to make it work with cheaper boards. For each light strip you want to use, you'll need the strip itself, a power adapter and DC jack, a control board, and some cables. I'm excluding the cost of wire here because, you know, it's wire. For reference: the Hue starter pack, with three bulbs and the hub, costs $200.
I did a little napkin math, and to be honest, I'm not entirely sure it's cheaper than a Hue setup--it might be around the same. Metrics are hard here because the strip isn't quite as bright as a couple actual light-fixture bulbs. So why would I bother to pursue this? Because I want to improve it. One of my stretch (and I do mean stretch here) goals is to work on developing dedicated hardware here, something that lets a microcontroller and a few transistors replace the Arduino, controller board, and ideally, perhaps the computer.
Is this reinventing the wheel? Maybe. Are there already smart lighting solutions out there that do exactly this? Yes. Are they too expensive in my mind? Yes. Is the market too saturated? Maybe, I don't know. But I'm having fun, building something that (I think) is cool, and I'm learning in the process. So screw it.
I'm incredibly happy with what I managed to hack together, but I have plans to improve it--ideally in future API versions. Some of the improvements I have in mind:
- Support for multiple driver boards and grouping of driver boards into "rooms", taking advantage of the ability to chain the drivers together
Light presets stored on the server, retrievable through API by clientsALREADY DID IT TADA Authentication (yeah, this one's important, I know)Sorry Alan, no one man should have that much power
- Rewriting the driver board's Arduino library in C/C++ or Node so that the boards can be controlled from the RasPi itself with no Arduino middleman. Theoretically there's no reason this should be that difficult, because the library itself isn't too complex, but by that logic I should theoretically be a multi-millionaire living in my own mansion by this point in my life, so maybe we'll just see how the rewriting goes.
- More modes for lighting, including disco, blink, seizure-inducing, etc.
In the meantime, check out the project here! Documentation's in the wiki and I want to know what people would do with this.