ColorNode
ColorNode is a wireless Arduino-compatible microcontroller board designed to replace the stock controller board on GE Color Effects light strings.
Background
ColorNode was inspired by the original controller protocol reverse-engineering effort featured here: Hacking Christmas Lights. That work enabled simple control of each individual bulb of these light strings using just one pin on a microcontroller. The stock controller works nice and the patterns are good, however being able to have full control of the color and brightness of each bulb unlocks the potential for awesome holiday light displays. Hacking these lights is also relatively inexpensive, compared to using other addressable strings or light sequencers on the market.
Design Process
As I mentioned on my posting for the GE Color Effects Arduino Library, I have been working towards using these programmable strings for my holiday decorations. One issue I had when I was planning out how to install these lights was being able to control and synchronize multiple strings. Each string only needed to be driven with one pin on a microcontroller so technically I could run all of my strings off one board. However, I didn’t like the idea of running a bunch of extra wires to each string from a controller. One nice thing about the stock GE controller is that it has a wireless receiver that works with the supplied remote to cycle the lights between the pre-programmed patterns. Since I would be replacing that controller and supplying my own control signals, I would be loosing the wireless aspect. That’s when it came to me: create a cheap wireless microcontroller board to replace the stock controller and make it fit in the existing little electronics box.
Unfortunately, that last sentence imposes a lot of design challenges, because there are usually trade-offs between cheap and wireless and microcontroller and small. As I was looking for solutions to this design, I knew that the wireless part would be the most expensive part. I didn’t want to re-use the existing module because there wasn’t much documentation about it and I wanted better control over the wireless link. I looked at XBee and Nordic transmitters and others that can be found at SparkFun. Most were either too big or too expensive. There is one, however, that fits both criteria: the RFM12B module from HopeRF. Not only was this wireless module small (16mm x 16mm) and inexpensive (~$6 from SparkFun or ~$3 if you order straight from the OEM), but it is also easy to solder. It gets even better – the stock controller uses a simple receiver paired with a transmitter in the remote. The RFM12B radio is a transceiver, so data can be received and sent from the controller board. Sweet!
Having found a great solution for the wireless radio, the next step was to figure out how to use it. XBee radios are nice because they can just look like a wireless serial port link and there is very little setup necessary. The RFM12B, however, requires more low-level control and configuration to get up and running. It uses a SPI interface for communication along with an interrupt pin to signal receipt of new wireless packets. Being more of a systems guy and less of a software guy, I looked around for existing implementations of this radio.
Eventually I stumbled upon the work of Jean-Claude Wippler who has an awesome design blog and store over at JeeLabs.org and JeeLabs.com. His main electronics design project is called the JeeNode. It is a low-cost, low-power Arduino-compatible board with an RFM12B wireless module interface. He has also developed many smaller sensor and I/O boards that interface directly with the ports on the JeeNode. The greatest thing, from my perspective, is the RF12 software library created for the JeeNode. This wealth of code removes all the complexity from using the RFM12B in the Arduino environment.
It made no sense to reinvent the wheel, so I set out to use the RFM12B radio with the RF12 JeeLabs code in hand. Next step: PCB. I admit I blatantly copied and modified the JeeNode PCB design in Eagle. That’s the whole point of Open Source Hardware anyway, right?
I wanted to use all through-hole components (besides the radio) so that it could be easily built by anyone or supplied as a kit. Unfortunately the ATmega328 in a 28-pin DIP package is pretty large (I had originally though about using a lower pin-count ATtiny85, but ultimately stayed with the ATmega so I could stay with the supplied libraries and Arduino IDE). I removed all the interface headers and moved components around and managed to fit everything on a board sized for the little plastic enclosure on the light strings. I liked that box because it was nice and small and already had environmental seals to keep out moisture. I run the antenna wire in a small loop around the box instead of coming out to avoid having additional areas I needed to seal.
As you can see from the PCB image and pictures below, the board shape replicates that of the stock controller, down to the holes for the plastic standoffs in the enclosure. You simply tear out (there is some extra epoxy in there for water sealing which makes it slightly more difficult to remove) the stock controller, cut off and strip back the wires going to the lights and the power brick, and solder them in the same positions on the PCB. Both the light strings (50, 36 count) and the yard sculptures (santa, tree, snowflake, etc.) share the same circuitry and electronics box, so it should work in most (if not all) of the Color Effects products. For the PCB manufacturing, I used the DorkbotPDX board service as I have for several other boards now (previously reviewed here) with good success.
Name
This brings me to the name: ColorNode. Since this project is based so heavily on the JeeNode design and RF12 libraries, I decided to call it (with JCW’s permission) ColorNode. Leveraging the JeeLabs hardware and software designs enabled me to quickly design and prototype this project. It is really just a stripped-down clone of the JeeNode with the sole purpose of functioning as drop-in replacement for the stock Color Effects controller. As I said earlier, I wanted to take advantage of the existing enclosure and I didn’t want to run extra wires all over the place. Now I can just run my light strings as normal and not have to worry about any other connections.
Design Details
Like the JeeNode, the ColorNode is based around the Arduino design but runs at 3.3V instead of 5V. The RFM12B module is only 3.3V tolerant so this was a necessary change. The ColorNode is programmed like the JeeNode or Arduino Pro-type boards where the USB-to-Serial converter is separate from the PCB and connects to a six-pin programming header. I use the USB BUB II from Modern Device (also a US distributor for the JeeNode) as my programming interface. This is similar to other FTDI-based USB-to-TTL adapters, except I like the way I can switch the supply and logic voltages with jumpers. I need to power and program the ColorNode at 3.3V instead of 5V to avoid damage to the RFM12B radio which shares the same power connections. I program the Atmel chips with the standard Arduino bootloader and download code to it using the Arduino IDE set to Pro or Duemilanove w/ATmega328. There are very few parts because I wanted the assembly cost to be as low as possible (~$10 in larger quantities). You can find the bill-of-materials here: BOM and the Eagle PCB design files here: ColorNodeV1. If you want to have the PCB manufactured, here are the Gerber files: ColorNodeV1.0 Gerbers. It is a two-layer board and the size is 1.82″ x 1.42″.
Software
With the hardware designed and tested, I’ve moved on to the software. I have created two pieces of software for this project – code for the node itself and code for a controller board. I am using a JeeNode for a controller, which sends wireless commands to the string nodes to set patterns, colors, sequences, etc. I use my GE Color Effects Arduino library for the basic string control. The nodes each have a Node ID established so that the controller can either address an individual node or all at once using a broadcast message. Since the RFM12B radios are transceivers, I use ACK messages to signal back to the controller that a command has been successfully received. The controller will re-send several times if it does not receive an ACK. This method results in very reliable communications, more so than with just a simple transmitter/receiver pair. The code is still a work-in-progress, but I have the basic wireless communication done and mostly debugged. I just need to add some more light patterns to the node software and define light show sequences in the controller. Once I get the software to a stable state I will post it here.
Pictures
Update: 26 November 2011
Here is the current code I am working with: ColorNode Code. I used the G35Arduino library which was created off of my GEColorEffects Arduino Library. It has some nice programs in the examples which mimic the stock controller. In order to not have to mess around with the timing of the delays, I modified the G35 library to use the DigitalWriteFast library. By hard-coding in the pin number for the LED string output, I was able to achieve the 2-cycle latency I wanted and then I could simply use the correct 10, 20, and 30 μs delays necessary. I am able to get reliable flicker/error free string lighting with this code. I think it has been updated since I grabbed it (November 20th) so it may have more/better features.
I also made a modification to the RF12 library to have the rf12_easySend function retry much faster (10ms versus 1s) and increased the retries up to 10. I found that, as long as the controller and nodes are within range (~50-100′ as implemented) the command will be received reliably using this method. Also, with the retries happening so fast, if one or more nodes doesn’t properly receive the command on the first try, it will on one of the subsequent retries and it will appear nearly simultaneous. It’s at least good enough for synchronizing multiple strings.
I don’t have a good interface yet for controlling the light programs/colors/etc. but it is all based on serial commands to the controller or the node PCB itself. It’s all spelled out in the Arduino code and a list of options/commands is displayed in the terminal window when connected. I’d like to connect the JeeNode I’m using right now to my home network (maybe with this?) and run a web server on it so I can control the lights from a web browser. That’s next on the To Do list…
The code is not perfect, but I had to baseline it so I could program the nodes and hang up my lights. I’ll be watching the development of that G35 library and I hope more people get involved and add features, like new cool light programs. After this season, I’ll re-visit the code and make any upgrades so the show is even better for next year.







So, ive been trying for the better part of the day to get this to compile in the Arduino IDE. I have tried both 1.0 and 0023.
Trying 0023, with the current zips from github for both G35 and RF12 with the appropriate .cpp’s and .h’s from the code above, I get the following error:
In file included from \Desktop\arduino-0023\libraries\G35/Cylon.h:14,
from \Desktop\arduino-0023\libraries\G35\Cylon.cpp:11:
\Desktop\arduino-0023\libraries\G35/LightProgram.h: In constructor ‘LightProgram::LightProgram(G35&)’:
\Desktop\arduino-0023\libraries\G35/LightProgram.h:23: error: ‘class G35′ has no member named ‘get_light_count’
\Desktop\arduino-0023\libraries\G35/LightProgram.h:24: error: ‘class G35′ has no member named ‘get_bulb_frame’
Hi, Michael.
I considered using XLR style connectors as Rob K suggests, but the store I was in didn’t have both male and female inline XLR connectors in stock, so I decided to go with 1/4″ audio connectors instead, which seemed to work fine, and were considerably cheaper (if not as elegant or as durable).
Here’s what I used:
http://www.radioshack.com/product/index.jsp?productId=2103446
http://www.radioshack.com/product/index.jsp?productId=2103445
One caveat: Make sure you cut the wire far enough away from the box to allow the entire connector to be installed. You need enough wire to allow the plastic housing on the connector to be unscrewed from the metal parts of the connector and slid up the wire towards the box while still leaving enough space for you to solder to the metal parts. This means the wire running from the box to the cut must be at least 3-4 inches. On my first attempt at this, I cut things too close and was barely able to slide the plastic housing far enough down the wire to allow me to solder the necessary parts. I suggest doing a “dry run” ahead of time and acting out the procedure with the actual connector parts to see how much space you will need before you actually cut the wire.
Rob K:
It looks like the code you are using is probably later/more sophisticated than the code I used. My G35 class has neither a ‘get_light_count’ member nor a ‘get_bulb_frame’ member. (In my version, the number of lights is set by a #define, not a method call.) Also, the entirety of the LightProgram class declaration I am using is:
class LightProgram {
public:
virtual void Init() {}
virtual void Do() = 0;
};
which as you can see has no constructor that takes a G35 reference.
One thing that I did do was go to github to get the latest versions of the ‘JeeLib’ library and used it to replace the RF12 software library, as well as ports.h, that Paul included above, making minor changes as he described in his source code documentation to add the changes he had made to the ones he was using into the ones I downloaded. However, that doesn’t explain the problems that you are having.
It seems as though you have a mismatch with your LightProgram class and your G35 class. Are you getting them from the same source repository? (You probably should, I would think.)
Yes, they are the last zip snapshots from yesterday. I guess I can try to look back and find an older rev of the code.. I will have to give it another shot in a few days when I get a chance to play with it again.
As for using 1/4″ TRS connectors, I would be concerned about possibly shorting something during insertion or removal. I like XLRs as they are parallel conductors.
Can anyone tell me what gauge the wires are (both the power supply and the 3-strand green wire)? This will be handy for stripping them and buying extension wire.
I’ve assembled my ColorNode, soldered it to the wires of the GE LED lights, and am now ready for the Arduino programming. I’m not understanding how to install both the code for the nodes and the code for the controller simultaneously. As I understand, I can only upload (via the Arduino IDE) one code program to the ColorNode board at a time (which is conneted to my computer via an FTDI USB converter). How does the node code get installed on the nodes (and by nodes, I assume we are talking about the indivual lights on the GE LED string)? If I upload the controller code first and then upload the node code, won’t the controller code be overwritten?
Okay, now I’m thinking … that since the two code files are named differently, they should both upload.
New question: I’m getting this error when trying to upload code:
ColorNode_Node.cpp:8:19: error: Ports.h: No such file or directory
In file included from ColorNode_Node.cpp:10:
/Users/mac/Documents/Arduino/libraries/G35/G35.h:13:22: error: WProgram.h: No such file or directory
Do the libraires stay in the project folder, or get put in the user/Arduino/libraries folder (I’ve found differing options posted on-line)? I’m assuming they go in the user docs library folder (I get far less errors, as posted above). When I leave the libraries only in the project folder, I get a whole list of errors:
ColorNode_Controller.cpp:8:19: error: Ports.h: No such file or directory
ColorNode_Controller.cpp:9:18: error: RF12.h: No such file or directory
ColorNode_Controller.cpp:14:17: error: G35.h: No such file or directory
ColorNode_Controller.pde:-1: error: ‘G35′ does not name a type
ColorNode_Controller.pde:-1: error: ‘RF12_EEPROM_SIZE’ was not declared in this scope
ColorNode_Controller.pde:-1: error: ‘color_t’ does not name a type
ColorNode_Controller.pde:-1: error: ‘RF12_MAXDATA’ was not declared in this scope
ColorNode_Controller.pde:-1: error: ‘RF12_MAXDATA’ was not declared in this scope
ColorNode_Controller.cpp: In function ‘void saveConfig()’:
ColorNode_Controller.pde:-1: error: ‘struct RF12Config’ has no member named ‘msg’
ColorNode_Controller.pde:-1: error: ‘struct RF12Config’ has no member named ‘msg’
ColorNode_Controller.pde:-1: error: ‘struct RF12Config’ has no member named ‘msg’
ColorNode_Controller.pde:-1: error: ‘struct RF12Config’ has no member named ‘msg’
ColorNode_Controller.pde:-1: error: ‘struct RF12Config’ has no member named ‘msg’
ColorNode_Controller.pde:-1: error: ‘struct RF12Config’ has no member named ‘msg’
ColorNode_Controller.pde:-1: error: ‘struct RF12Config’ has no member named ‘msg’
ColorNode_Controller.pde:-1: error: ‘struct RF12Config’ has no member named ‘msg’
ColorNode_Controller.pde:-1: error: ‘struct RF12Config’ has no member named ‘msg’
ColorNode_Controller.pde:-1: error: ‘struct RF12Config’ has no member named ‘msg’
ColorNode_Controller.pde:-1: error: ‘struct RF12Config’ has no member named ‘msg’
ColorNode_Controller.pde:-1: error: ‘RF12_EEPROM_ADDR’ was not declared in this scope
ColorNode_Controller.pde:-1: error: ‘rf12_config’ was not declared in this scope
ColorNode_Controller.cpp: In function ‘void showHelp()’:
ColorNode_Controller.pde:-1: error: ‘RF12_915MHZ’ was not declared in this scope
ColorNode_Controller.cpp: In function ‘void handleInput(char)’:
ColorNode_Controller.pde:-1: error: ‘stack’ was not declared in this scope
ColorNode_Controller.pde:-1: error: ‘RF12_868MHZ’ was not declared in this scope
ColorNode_Controller.pde:-1: error: ‘RF12_915MHZ’ was not declared in this scope
ColorNode_Controller.pde:-1: error: ‘RF12_433MHZ’ was not declared in this scope
ColorNode_Controller.pde:-1: error: ‘stack’ was not declared in this scope
ColorNode_Controller.pde:-1: error: ‘struct payload’ has no member named ‘bulb_color’
ColorNode_Controller.pde:-1: error: ‘lights’ was not declared in this scope
ColorNode_Controller.pde:-1: error: ‘stack’ was not declared in this scope
ColorNode_Controller.cpp: In function ‘void setup()’:
ColorNode_Controller.pde:-1: error: ‘RF12_915MHZ’ was not declared in this scope
ColorNode_Controller.pde:-1: error: ‘rf12_initialize’ was not declared in this scope
ColorNode_Controller.pde:-1: error: ‘rf12_control’ was not declared in this scope
ColorNode_Controller.pde:-1: error: ‘rf12_easyInit’ was not declared in this scope
ColorNode_Controller.cpp: In function ‘void loop()’:
ColorNode_Controller.pde:-1: error: ‘rf12_easyPoll’ was not declared in this scope
ColorNode_Controller.pde:-1: error: ‘rf12_easySend’ was not declared in this scope
ColorNode_Controller.pde:-1: error: ‘rf12_hdr’ was not declared in this scope
ColorNode_Controller.pde:-1: error: ‘RF12_HDR_CTL’ was not declared in this scope
ColorNode_Controller.pde:-1: error: ‘RF12_HDR_DST’ was not declared in this scope
ColorNode_Controller.pde:-1: error: ‘RF12_HDR_ACK’ was not declared in this scope
ColorNode_Controller.pde:-1: error: ‘RF12_HDR_MASK’ was not declared in this scope
And what is Ports.h?
Michael-
The library files need to go in the libraries folder in the Adruino directory. The ColorNode code relies on the RF12 library from JeeLabs (http://jeelabs.net/projects/cafe/wiki/Libraries) which in turn also requires the Ports library. Download and extract both libraries into your Arduino program folder, not your project folder.
The difference between the Node program and the Controller program is that the Node program gets installed on the ColorNode board attached to the string of lights while the controller program is programmed onto your central controller. The central controller can either be another ColorNode board, a JeeNode board, or some other Arduino-compatible board with an RFM12B radio attached. The Node program is designed to accept commands from the controller program, which is designed to wirelessly control multiple ColorNodes, each running the same or similar (as long as the payload and commands are common) Node program. You don’t program one board with both – you need two boards to accomplish the wireless control. Now, you can just use one board and program it with the Node software and modify it to run different light programs independently of any wireless control. You can also send the software commands serially (using the Adruino serial console, for example) via a connected FTDI cable. That is a good way to test out your light sequences before jumping into the wireless control.
For the ColorNode, which board do I choose from the list in Arduino –> Tool –> Board ?
Thanks for the quick reply Paul.
I’ve had success (!) with getting the ColorNode to light up my GE 16s … tho, I’m still not clear on a few things:
1) After fiddling around with a bunch of unknowns to get the code to compile … I came to realize that ColorNode is perhaps only applicable with the Arduino IDE 0022 version, correct? On the JeeLabs page (http://jeelabs.net/projects/cafe/wiki/RF12), it’s not clear which package I should download based on the version of which Arduino IDE I have. My preferred IDE version says “1.0″ (the most recent version). So, if using the most recent version of Arduino (“1.0″), what is the appropriate code package to use? Or is 0022 necessary? I just got the code and libraries to work with 0022, so I assume that it is necessary (but will the “jeelib” library from GIThub somehow work with IDE 1.0? I was not able to get it to work, as it appears I was missing “WProgram.h”.)
2) Anyway, with 0022, the code compiles. And then I had to change the IDE serial port output to “dev/tty”, and choose board “Arduino Uno” to get the code to upload, and then see some lights! With the initial install of Node code, I get a few variable colors, tho not all of the 16 lights are lit up (does this sound right?). So now, I’ll be looking into understanding and adapting the code.
Questions:
- Mr RGB mentions above, Paul’s “source code documentation”. Is there documentation aside from the code comments?
- In the Node code, to adapt for a string of GE 16s, is there generally anything else I would need to change besides “#define LIGHT_COUNT 16″?
- Can anyone offer an example of how to make calls via serial? I still have only barely a concept of what the general protocal is for calling the functions in the Node program. My needs are pretty straight forward. I just need to be able to have 12 of my 16 lights be a unique color, and then control the brightness of each light dynamically. How would I, for example, have light # 7 fade gradually from black (off) to very bright red?
- Or one of the included Light Programs?
I too was able to compile the code finally with 0022, and had no success with anything newer than that.
I now have a functioning 50 bulb string, and I can get to the serial console using the UART Pass mode on my Bus Pirate. Now, I am a little confused about how to actually use the console. I can only seem to change the brightness of a cyan color on bulb 1, as any other input seems to bring up the “help” menu over and over again.
Is there a more detailed breakdown of the control protocol for this?
Now, on to another question. I have been controlling it thusfar with the console header on the node itself. I have not yet built a “controller” node. I understand that Paul uses a Jeenode to do the control, and I was wondering if that code would work natively on the JeeLink, which seems to be basically a Jeenode with built in USB and 1mbit of flash.
So, I have been able to get a chance pattern to work on this via the console using the arduino serial monitor. But, I would like to use the patterns. no matter what I have tried for color commands, I cant get a built in pattern to kick over. I am sure I am looking over something completely obvious, but I cant seem to find it!
Any assistance would be greatly appreciated.
Sorry, by “Pattern” I mean “Program”, from command 1.
Nevermind. After a weekend of toying around with it, I figured it out. The only thing I am trying to figure out now is the RGB codes that do not seem to match up with my understanding.
Rob-
What did you have to do to get it working? Do you know what was going wrong? As far as the RGB is concerned, the lights are only 12-bit RGB, so 4-bits (0 through F, in HEX, or 0 through 15 in decimal) per color. We are used to 24-bit RGB with one byte per color, so with 12-bits you have a smaller range of colors (4096 versus 16+ million). White in 24-bit RGB is FFFFFF while in 12-bit it is FFF or, for the ColorNode code, 15,15,15. Here is a site that shows the whole 12-bit color space: http://rangevoting.org/ColorCode.html I couldn’t get the hover to work like it says, but it gives you an idea of what’s possible with 12-bits, even though the LEDs may not be able to accurately reproduce all those colors. Also, as the bulb intensity is altered, the colors may look slightly different than when the intensity is at max.
I don’t see why the code wouldn’t work on a JeeLink. I actually was looking to get one of those next time since it is so compact and more convenient to use with a laptop than a board + USB converter + cable.
It basically boiled down to my misunderstanding the command syntax. Now as for the color codes that makes more sense, I was trying to pass 254,0,0 thinking I would get Red, but instead I was getting Cyan.
I just received my JeeLink this afternoon, so I am about to compile the code and upload, I will reply with my results.
Okay, so it works just fine on the JeeLink, now that I set the frequency properly anyways.. I would highly recommend it for this setup!
I’ve ordered and put together a colornode for myself. While I don’t need RF, it’s a nice feature to be able to add.
I was able to compile and run the ColorNode_Node.pde file with Arduino 0023. However, I’m unable to get the G35Arduino examples to run on the colornode hardware. The code requires Arduino 1.0 and other than the changing the data pin from 13 to 19, I’m not sure what I’m doing wrong. I can upload the BasicExample.ino file successfully but the lights stay off. I’m using the latest jeelib library. Any pointers would be great.