Skip to main content

Turning GE Color Effects G-35 Christmas Lights into a 7x7 display with Arduino

Some time ago I saw some GE Color Effects G-35 Christmas lights and was fascinated by the combination of color patterns that they were capable of and the fact that they only had three wires. That meant that something digital was going on.

Happily, a chap called Robert Quattlebaum did the hard work last year of hacking these lights to reveal that they are linked by a simple self-clocked serial protocol that can easily be driven by a microcontroller. That blog post gives the full details of the protocol.

Each lamp can be set to a specific brightness and an RGB color (4 bits per color). And the protocol is clocked at 30µs per bit so it's possible to refresh the entire 50 LED string at a rate of 24Hz. Perfect for hacking fun.

So I got a set and plugged them in just once (still in their packaging) to check that they worked. Here's a video of the lights getting their one real work out before the soldering iron got to them.



The first thing I did was remove the lovely plastic blub covers (these are being saved to brighten up a simple set of Christmas lights) to reveal the LED inside. This picture shows all three states: one has the original plastic cover on, the one in my hand has it removed but the plastic base intact, the bottom one is the naked LED and controller.

Once you've ripped off the protective plastic you are down to a simple LED with three wires going in (+5V, Data and GND) and three coming out. With 50 of these on a string I decided to make a 7x7 display (with one LED 'spare' should I break one).

Here's the finished display. The entire chain of lights has been cut up, mounted, resoldered and is now controlled by an Arduino Pro. All that's needed is a 5V power supply to plug into the power socket.

It's controlled by a small piece of Arduino software that contains a simple frame buffer implementation, code to implement the LED protocol via bit banging, code for scrolling text and for making faces. You can get the source code here. The key file is protocol.cpp which initializes the display and allows simple setting of the color and brightness of each LED. The most interesting part of that code (at least to me) is the initialization of the LED addresses. On power up the LEDs wait to learn their 6 bit address. They wait in turn and have to be programmed for use. I exploit this to make addressing them easy:

To build this I first cut up the entire string of lights to get just the LEDs with a small amount of cable attached to each. Then I prepared a piece of plywood, marked it up, drilled guide holes and then drilled the 49 mounting holes for the lights.

Then I glued in place each of the lights taking care to orient them for easy soldering into the chain. Then just 144 solder joints and little bits of heat shrink later I had the chain reattached and capable of being driven by the GE supplied controller.

The next step was some sort of opaque diffuser to put in front of the display. For this I used a cutting board that I cut to the right size. With the board in various positions it's possible to get different diffusion effects.

The final step in the hardware was to get a picture frame made to measure (I got a cheap, but deep, one in simple white wood from these folks) and then stuck the cutting board inside, used some old nylon nuts as spacers, mounted the LED board and finally used a piece of MDF that was supplied with the frame as a backing. The back is fixed on using some parts from an old servo.

Electronically this modification to the original lights was pretty simple. Having eliminated the original power supply and controller all that was needed was a new controller in the form of an Arduino Pro and a 5V power supply. The supply provided with the lights gave 5V at 3A (which seemed at lot). I measured the actual power usage and the highest current seen was 1.68A with all LEDs on white at maximum brightness. Thus I used an off-the-shelf power supply for the lights (plus Arduino Pro) capable of providing 2.25A.

The Arduino Pro is screwed to the back of the picture frame and there's only one component added: a 10K pull down resistor between GND and pin 7. Pin 7 is driving the serial data through the LEDs and it is low when not being driven with data. You can see that here:

If you're eagle-eyed you might have spotted a capacitor as well. I got this Arduino Pro free because it had a manufacturing fault and I repaired it using an old capacitor that I'd desoldered from the control board of a dead toaster. In that photo the Arduino Pro is connected via an FTDI cable for programming.

The other slightly tricky thing with this project was getting the timing of the serial protocol right. The simple serial protocol uses alternating high/low pulses of 20µs and 10µs (or low/high). In protocol.cpp I've made use of C #define statements to inline code for speed and also third-party code for fast changes to the I/O ports and accurate delays.

When working on this I used the Salae Logic analyzer to view the actual serial protocol in action. Here are two screen shots. The upper one shows the standard GE controller sending the initialization packets to the each of the LEDs in turn (with a gap of 40ms between them), the lower one shows a zoom into a specific packet being sent.

Finally, here's a video of the complete unit running through a simple "Hello World", followed by a few facial expressions and finishing with a "Thanks GE" for such a nice hackable string of Christmas lights.



PS If anyone from GE is reading this... how about making a 220V version of these? All you need to change is the wall wart to one that does 110-220V and you'd have all us Europeans interested in these lights.

PPS Other Arduino-based projects you might enjoy: GAGA-1: High Altitude Balloon Project and Cansole: Video games console in a can. Other non-Arduino projects: Revealing the secrets of the Ikea Lillabo wooden train set and Building a 'Ponyo' boat.

Comments

Mike P. said…
Incredibly frustrating that it's so hard to get these lights in Canada.
Ron Proctor said…
Congratulations on a fun build! Now all you have to do is make 42,624 more and link 'em together for a giant HDTV! :)
kamakazi said…
Wonderful idea. I love it. Incredibly frustrated though. I can't get your code to compile. I have a fresh install of the 1.0 environment and the MEGA ADK. Your code uses includes for WProgram.h and unfortunately I don't have what it is looking for. I believe as a result of the missing file, I'm getting compile errors stating that 'byte' has not been declared in face.h; 'byte' was not declared in this scope in protocol.h; 'byte' does not name a type in frame.h. I would love to make your code work on this controller so I can pass it off to my colleague. Any thoughts to what I am missing?
kamakazi said…
Wonderful idea. I love it. Incredibly frustrated though. I can't get your code to compile. I have a fresh install of the 1.0 environment and the MEGA ADK. Your code uses includes for WProgram.h and unfortunately I don't have what it is looking for. I believe as a result of the missing file, I'm getting compile errors stating that 'byte' has not been declared in face.h; 'byte' was not declared in this scope in protocol.h; 'byte' does not name a type in frame.h. I would love to make your code work on this controller so I can pass it off to my colleague. Any thoughts to what I am missing?
kamakazi said…
Wonderful idea. I love it. Incredibly frustrated though. I can't get your code to compile. I have a fresh install of the 1.0 environment and the MEGA ADK. Your code uses includes for WProgram.h and unfortunately I don't have what it is looking for. I believe as a result of the missing file, I'm getting compile errors stating that 'byte' has not been declared in face.h; 'byte' was not declared in this scope in protocol.h; 'byte' does not name a type in frame.h. I would love to make your code work on this controller so I can pass it off to my colleague. Any thoughts to what I am missing?
WProgram.h is part of the standard Arduino environment. I am using version 0022.

http://www.arduino.cc/playground/Code/Library#WProgram
kamakazi said…
JGC, thanks for the version tip... Version 1.0 has library compat issues. WProgram.h is now Arduino.h and the library has undergone many changes. I'm using 022 now and now I'm having different compile errors about multiple definitions across files. I'm googling to find the solution, but if you have any thoughts I'd love to hear them.
Anonymous said…
Fuck kamakzi, patients is a virtue!
Matt Smith said…
Trying to recreate this, but unknowingly put my 50th LED at the front of the bus instead of the end. I'm no programming expert, but am having a hard time trying to find out how to make fix the code to support it. I also wired them in rows vs diagonals, but I got them to initialize properly (aside from the one extra at the wrong end). Any ideas?
@Matt Smith: The order in which the lights are strung together doesn't matter because they are assigned their addresses when the power is turned on. In fact when I made mine I cut them all up and had a bag of them and took them out in some random order. All that really matters is that you get the electrical connection correct: i.e. +ve, GND and the data line.
Vinnie Vu said…
Since the Arduino Software has been updated to version 1.0, there has been a lot of compatibility issues with a lot of codes written in 022 or 023 simply because of library name changes and other changes.

If you would simply change your #include "WProgram.h" to:
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

It'll automatically detect the version and compile with the correct library.

Thanks for the inspiration!! I picked up twenty one boxes of lights!! You should see some ridiculous display up soon.
We referenced your code and added MSQEG7 to add audio and 7 segment equalizer.

Also, if ou use a cardboard and cut into a grid, you can get the lights to display more evenly.

Popular posts from this blog

Your last name contains invalid characters

My last name is "Graham-Cumming". But here's a typical form response when I enter it:


Does the web site have any idea how rude it is to claim that my last name contains invalid characters? Clearly not. What they actually meant is: our web site will not accept that hyphen in your last name. But do they say that? No, of course not. They decide to shove in my face the claim that there's something wrong with my name.

There's nothing wrong with my name, just as there's nothing wrong with someone whose first name is Jean-Marie, or someone whose last name is O'Reilly.

What is wrong is that way this is being handled. If the system can't cope with non-letters and spaces it needs to say that. How about the following error message:

Our system is unable to process last names that contain non-letters, please replace them with spaces.

Don't blame me for having a last name that your system doesn't like, whose fault is that? Saying "Your last name …

All the symmetrical watch faces (and code to generate them)

If you ever look at pictures of clocks and watches in advertising they are set to roughly 10:10 which is meant to be the most attractive (smiling!) position for the hands. They are actually set to 10:09.14 if the hands are truly symmetrical. CC BY 2.0image by Shinji
I wanted to know what all the possible symmetrical watch faces are and so I wrote some code using Processing. Here's the output (there's one watch face missing, 00:00 or 12:00, because it's very boring):



The key to writing this is to figure out the relationship between the hour and minute hands when the watch face is symmetrical. In an hour the minute hand moves through 360° and the hour hand moves through 30° (12 hours are shown on the watch face and 360/12 = 30).
The core loop inside the program is this:   for (int h = 0; h <= 12; h++) {
    float m = (360-30*float(h))*2/13;
    int s = round(60*(m-floor(m)));
    int col = h%6;
    int row = floor(h/6);
    draw_clock((r+f)*(2*col+1), (r+f)*(row*2+1), r, h, floor(m…

The Elevator Button Problem

User interface design is hard. It's hard because people perceive apparently simple things very differently. For example, take a look at this interface to an elevator:


From flickr

Now imagine the following situation. You are on the third floor of this building and you wish to go to the tenth. The elevator is on the fifth floor and there's an indicator that tells you where it is. Which button do you press?

Most people probably say: "press up" since they want to go up. Not long ago I watched someone do the opposite and questioned them about their behavior. They said: "well the elevator is on the fifth floor and I am on the third, so I want it to come down to me".

Much can be learnt about the design of user interfaces by considering this, apparently, simple interface. If you think about the elevator button problem you'll find that something so simple has hidden depths. How do people learn about elevator calling? What's the right amount of informati…