In the last after Christmas sales I spotted some wooden Christmas trees for £1.50 each. Realising that I hadn’t even put up a Christmas tree that year I decided to take these to use next time around. However, they seemed a bit dull, so I figured that over the next 12 months or so I would figure out a way to make them a bit more lively with some LEDs. To be honest I actually had a lot of the parts needed for this project lying around and I was looking for an excuse to do something with them. These were a set of WS2811 LEDs and a 2.8” Nextion touchscreen made by Itead. I’ll go over both of these here now.
The WS2811 LEDs fully addressable RGB LEDs. Internally they are actually a combination of an LED and a small microchip and typically come as a strings of LEDs and they each have three wires, two for power and one for the data. They way they work is like this: say you have a string of 8 LEDs you want to control connected to an Arduino. From the Arduino you will send the values of all 8 LEDs to the first LED in the string. It the chip inside will take the first of those 8 colours, set itself to that colour, and then send the 7 remaining colours to the next LED. This continues up the string until there are no more colours left or no more LEDs to send them to. Obviously this is incredibly useful because it allows you to control a large number of LEDS with only one pin on a microcontroller.
The Nextion screen is something that I had been wanting to play with for a long time. The way this works is that instead of everything for the screen being stored on whatever is controlling it, the screen runs its own small program and communication with the microcontroller is done via a serial connection. The advantage of this over a more traditional TFT is that there is a lot less burden on the microcontroller, allowing for a much smaller microcontroller to be used. This means that if you want a touchscreen in your project but what your touchscreen is controlling is actually quite simple you can get away with something like an Arduino micro or even an ATTiny84, rather than having to use something bigger.
The only other major part used was an Arduino micro to control the based on what was on the screen. As I said I wanted to use an Attiny84, but ended up using an Arduino micro because the ATTiny84 seemed to not be able to handle Software Serial, and hence could not drive the Nextion screen.
Programming the lights
Typically addressable LEDs like the WS2811s are not controlled directly in Arduino sketches but through a library that abstracts away most of the details. I initially used the FastLED library, but found this to be a bit large and I was trying to keep the resulting sketch small as I would only have limited space on the Arduino micro. So I instead went for the Adafruit_NeoPixel library as the binary it produced took up a lot less space.
There are 3 different patterns for the lights, and one off mode, making for a total of 4 different modes. Each pattern is controlled by an individual function which is called from inside the Arduino loop() function. Each of these functions takes in a “position” variable, which tells it where in the pattern it is, and will return the position that needs to be used next. In hindsight I could have done this as a global variable but it didn’t make too much of a difference. The key thing was that each of the mode functions was in charge of changing the position in the pattern. Simply having the count be incremented inside loop() would not do because eventually the code would reach a number too big for the integer and it would end up in an integer overflow state which could result in unpredictable behaviour. This is why all of the pattern functions except for “off” checks to see that the position has not reached the start of a new cycle. If it has it will return 0 instead of the next number because it should result in the same light pattern, and will also prevent the sketch trying to count to infinity and hence causing overflow issues.
It might seem like a simpler way to control the speed would be to change the delay in the loop function, but the problem with doing that is that the interaction with the LCD screen is also controlled by this loop. Changing the delay in the loop would change the responsiveness of the UI. I didn’t want the responsiveness of the UI to be affected by the speed of the loop as from the user’s perspective it shouldn’t make a difference, and seemed like just plain bad design. In hindsight, looking at what the delays are in practice, it probably would not have been noticeable, but at the time I didn’t know how long I wanted the delays in each iteration of the loop to be.
Another thing in the code that might seem unusual to people who are only familiar with the C programming language though programming in the Arduino IDE but not otherwise is the use of function pointers. Instead of having a switch statement in the middle of the loop function and selecting which function for which light pattern to call that way, there is an array called modeFns that contains pointers to the pattern functions. Instead of the switch statement I just select the appropriate function from modeFns using the mode number. In reality this is just a matter of taste, and I could have used a switch statement, but it can be useful to know about.
Programming and talking to the screen
Before doing any programming on the Arduino side I had to program the UI components into the screen. This was done through a program called Nextion editor, provided by Nextion. This is a very simple point-and-click program where, after selecting what screen you want to program, you simply drag and drop the various widgets (sliders, buttons, text fields) to the location you want them in, and update their properties as needed. To get the program onto the Nextion screen you compile inside the editor and then copy it and SD card which you then put into a slot on the back of the screen. Power cycling the screen will then cause it to recognise the program on the SD card and flash it to its internal storage. Once done you just remove the SD card and power cycle again. This was a very good method for getting the program onto the screen for me as I was running the Editor under WINE on Linux and this seemed like far less trouble than trying to establish a serial connection from inside WINE to flash the screen.
As for the Arduino side, much like with the LEDs there are a few different libraries out there for controlling the Nextion screens. I wanted to use software serial to talk to the screen, so I was originally going to use
Actually responding to the button presses on the screen is simply done by specifying some callbacks and changing text and numerical values on the text and number fields is done by calling setText and setValue respectively. nextLoop() is called at the top of loop, and although I have not looked into the code I assume this calls the callbacks based on what events it gets from the screen and will also post the updates from setText and setValue back to the screen.
Putting all of this was rather straightforward. I decided to make it modular, with a control box that would house the Arduino and touchscreen and a connector for the tree, and then have the tree itself separate. This was for a couple of reasons, one so that I could possibly plug some other decoration into the controller box later and partly because I had some ideas for another control box which I may be able to get done in time for this Christmas.
For the control box I just soldered the Arduino onto some veroboard, and then solder on a USB cable so for power, some pins for the screen and a connector for the tree to plug into (more on that in a minute). I had a nice cardboard box from a gift from last Christmas that I used. The only slightly tricky bit as that I needed to put the USB cable into the box first and then solder it to the veroboard, otherwise I would have needed to make a much bigger hole for the cable so I could get the USB plug through it. The connector for the tree was simply hot glued in, and the screen was mounted in a 3D printed bezel that came from an STL provided by Nextion. I was a bit lazy on this bit and got it printed by 3D Hubs rather than printing it myself. I was very happy with the results from them and will probably use them again in the future.
For the tree it was a simple matter of cutting off 8 of the LEDS from the string of 24 I had, soldering some wire with a connector on the end to them and then drilling holes in the tree for the LEDS and gluing them in. For the ones I bought I had to drill through holes 8mm in diameter, and the counterbore 12mm holes so that that would come out the front of the tree slightly as there was a bigger section behind the LEDs that housed the chip. As for the connector on the end of that wire, I used a simple headphone plug (and socket on the control box side) which worked well as the LEDs only needs three wires.
There was another idea for this was to be a lot simpler and use an RF remote control and an OLED screen. This didn’t end up happening because I couldn’t find an RF remote that worked well enough. This may still happen this Christmas, as I have a new remote to try, and if it does I’ll do a small update here on the blog.
The thing I would like to do with this next time around is to make a WiFi version. I bought a CHIP when they had their kickstarter and I have never really found a use for it, but I think it would be up to the task of running a little bit of node JS code that can control the LEDs on the tree. Also the CHIP has a much more powerful processor, so I might be able to plug a couple of trees into and make a small version of the full-house displays that get posted on youtube around this time of year, possibly with more than one tree plugged into it and a musical element.
But for now I’m just left just got to decide where to put my new tree. Out the window for the world to see, or in the house? I might have to make another one.