Introduction: Raspberry Pi Musical Christmas Lights
Instructions for a set of stars that will light up according to a musical tune. The concept is that each star represents one note and as the song progresses the star associated with the current note will light up. The setup uses strands of off-the-shelf Christmas lights along with a Raspberry Pi and 8-channel relay module to control the illumination. The software is written in Python and is designed to be generic so that any song can be coded and added to a playlist. The notes for the songs were manually coded based on sheet music.
The above video shows the final product playing Deck The Halls.
Step 1: Parts List
- Raspberry Pi Module: https://www.raspberrypi.org/products/ (I used a model B version 2)
- JBtek® DC 5V 8 Channel Relay Module
- DROK® LM2596 Analog Control Buck Converter DC-DC Step-down Transformer
- Battery for Relay Module (I used a 12V rechargeable lead-acid battery)
- Wire (I used 18/2 gauge)
- Wire connectors
- 7 sets of 50 ct mini Christmas lights
- Homemade wooden stars to mount the lights
Step 2: Build the Stars
The stars were patterned after the plans described on the Rogue Engineer website: DIY Wooden Star. The difference is that I simply used slats of 1/2 inch plywood to keep them light. I also scaled the design up in order to make the stars about 22 inches across. I used carpenters glue and a small brace on the backside of each of the 10 joints to hold them in place.
The lights are 50 count, clear mini lights. Any lights could be used, but these were an inexpensive option since I was buying 7 strands. The strands were ~12 ft long so I doubled them up around the star. As you can see in the picture I sort of let the bulbs fall where they wanted. Because of this, some of the stars had an ill-defined outline when lit. Before I put them up again, I need to take the lights off and reattach them while making sure they all point the same direction and adhere more strictly to the star outline.
The end plugs were removed from the light strands and 18 gauge wire was attached in order to route it to the relay module. You could you extension cords but you would need a separate cord to run each star back to the common source. Also, you will still need to use connector wires to attach each star to the relay module so it just made more sense to run my own wires all the way to the lights.
Of course you don't need to use stars at all. The controller/relay setup can be used with any sort of light arrangement.
I was able to route the wires from the stars into the house through a convenient vent. This made things much easier since all the electronics could be protected from the weather. Originally my plan was to use a waterproof box and leave everything outside, but fortunately I did not have to use this method.
Step 3: Wire the Relays
The 8 channel relay module is used to provide power to each of the 7 strands of lights. The lights utilize 110 V AC power so it is important to use an isolated relay to protect the Raspberry Pi from the high voltage circuit. The board I used had opto-isolators built in for each relay on the board. The 3.3 V output from the Raspberry Pi is only capable of powering a few of the relays at a time. If you tried to activate all 8 simultaneously, nothing would happen. To solve this, power is provided to the relay module by a separate 12V battery. Since the relay module is 5V, a DC step down converter was used to convert the 12V signal to 5V. The + and - outputs from the converter are connected to the JD-VCC and Ground pins on the relay board in the lower right hand corner. A good resource on the operation of the relay board can be found at: Arduino Power Tutorial.
The full circuit diagram is shown in the attached sketch. One wire (+) of each of the 7 light strands is connected directly to the COM (Common) terminal of each relay. The NO (Nominally Open) terminal of each relay was connected to 110V AC power from a terminal block. The other wire (-) of each of the 7 light strands is connected to ground. A 110V AC extension cord was plugged into the wall outlet and the other end of the extension cord was cut and attached to a positive and negative terminal block. The use of the terminal blocks made it a little easier to organize the sets of 7 wires and provide a common +110V AC and Ground.
I ended up using a 12V lead acid rechargeable battery to power the relay board. I tried both a 9V alkaline battery and a 6V 7amp-hr lead acid battery and had trouble with them running out of power. I re-charged the 12V battery with a solar charger every 4-5 days and had no further power problems.
Finally, the 8 input pins and the VCC pin (not to be confused with the JD-VCC pin) are connected to the Raspberry Pi. Simply choose a set of 7 of the Pi's GPIO pins and make sure the software is coded with the same pin numbers that you connected (see next step).
Step 4: Program the Controller
The control for the light show was done using Python and executed on a Raspberry Pi model B. I included a couple of the files here, but the full set of source code can be found on github. The main file is lightshow.py. This is where you set up the pins you are using on the Raspberry Pi, you'll need to be sure and connect the same pins as I did or update this part of the code. Lightshow.py is also where you set the playlist that will be executed. I have it set up to run a simple chase sequence twice at the beginning. This is useful to make sure everything is hooked up and working correctly. Then it will run each song in the playlist. Before each song it will give an indicator of which numbered item in the playlist (starting with 0) that it is about to run by lighting up that number of starts. If the playlist contains more songs than stars the indicator will wrap around from the other side and start with 1 star illuminated. Once each song is finished, it runs a finale program where it twinkles all stars for 5 seconds and then leaves them all illuminated. It then goes on to the next song.
The songs are programmed using a Song class that is defined in the lightshow_classes.py file. The Song class defines each of the notes e-f-g-a-b-c-d in my case along with the duration of the notes. 1 beat for a quarter note, 1/2 beat for an eighth note, etc. If you want to use more than 7 stars, you would need to modify this section to map the additional notes.
Each song has its own file. Use Deck_The_Halls.py as an example. These files were created by looking at a set of sheet music and adding each note and its duration to the Song.notes list. An important part of this file is the tempo play it at. This is an argument to the Song class constructor (in the example it is 140 beats/minute). These were set by trial and error and using what seemed to look best. In theory, any song can be coded in this manner and added to the playlist, though it is limited to only illuminating one light at a time.
There is also a Show class that can be used to perform commands like turning one light on/off, all lights on/off, play a song. Combining these methods is how the chase.py function was created.
Once loaded on the Raspberry Pi, the program can be run by the command: sudo python lightshow.py
The relays make an audible 'click' when they switch so you'll get an indication that the song is playing even if you can't see the lights themselves.
Step 5: Future Variations
- Need to add more stars. Only having 7 unique notes means that on many songs you will be re-using stars. When a song had a range greater than 7 notes, I simply set the "low" and "high" version of the note to the same star (e.g. a low C and a high C were treated the same). This can look weird when you're expecting to see a note illuminate in one place, but it actually illuminates on the opposite side.
- If moe than 8 stars are used, another relay module will be required and eventually you'll run out of GPIO pins on the Raspberry Pi.
- Add more verses to the songs. In their current versions, most are way too short.
- Add a sound output. This will require making sure the tempo setting in the song definition exactly matches the audio being played. The existing songs were created using very basic sheet music versions so these will have to be matched to an audio version of the song.
- Would like to have an automated method to create the song files. A brief attempt was made using Audacity, but it never really produced good results.