LED Lighting

Photo by Suzy Hazelwood from StockSnap

Disclosure: I have included some affiliate / referral links in this post. There’s no cost to you for accessing these links but I do indeed receive some incentive for it if you buy through them.

It’s time to get back to some lighting as I spent a little time enhancing my setup that I left off configuring in Making the Lights Dance. In my Building the RaspberryPi Christmas Light Box post, I blamed a friend for starting me down this path. Once again, I’m blaming a different friend for causing me to wander down the LED lighting road. This friend saw some of my posts regarding the simplistic lighting box I created, and they suggested that I tinker with WS2811 lights. Let the tinkering begin!

Hardware List

It’s always good to talk through the hardware that we’ll be using for this. To start, I extended my previous Building the RaspberryPi Christmas Light Box system to be able to do some LED lighting. Here are the items that I purchased from Amazon:

By the way, your hardware may vary slightly but I bought the 5v lights just because. There are LED tape strips and these 12mm bullets. There’s indoor only and IP68 rated. There are 12v lights and many other options to choose from. I just happened to pick these because they were the cheapest at the time.

Tiny Electrical Lesson on the Hardware

I’m not an electrician by any stretch of the imagination but I know a guy that helped me get through it a little. He’s more AC than DC but we had a good chat about it all (ok enough babbling on that).

There are some very important concepts to keep in mind on the power requirements. These important items were things that I had to dig up and learn from my electrician. I figured I’d drop them here to help anyone else going down the LED lighting route as blindly as I did. You need to make sure the output voltage on the power supply matches the input requirements on the lights. Aside from voltage drops (I’ll cover that in a later article when I go bigger on the system), the voltage will remain constant. I am using 5V lights so an adapter capable of outputting 5V was required.

Wattage is cumulative! This is a very important point to remember in all of this. The example lights used have a spec of roughly 0.3W per LED bulb. Each strand has 50 bulbs. If you take 0.3W * 50 bulbs, you get 15W. This means that a single strand of lights requires 15W of power. If you wanted to use two strands, you’d do 0.3W * 100bulbs for 30W of power required. This means that when you purchase your power supply, it will need to support 5V and 15W * <The number of strands>. Given the power supply listed above in the hardware list, I can only run a single strand of lights :facepalm: here. For those wanting to do more than one strand, I would suggest possibly getting the SHNITPWR 4V – 12V Power Supply 10A 120W AC to DC Adapter. This was used when I went bigger with the LED lighting.

The only other thing to keep in mind would be the data channel on the lights. The lights have 3 wires (5 if you count the separate power leads at each end of the strand but who’s really counting?) that supply power and data. The power has your standard +/- and the third middle wire is data. The nice thing is that data does not suffer from voltage drop like the power. Data is repeated at each bulb so it doesn’t lose signal (as long as you get good power to the first bulb. A warning I didn’t fully head until I built the bigger system. Again, more details later).

Connecting Everything

The awesome folks over at Adafruit have put together some really nice articles to also help out. In order to get everything up and running, it was pretty simple to follow their NeoPixels on Raspberry Pi Wiring guide (FYI, this guide contained the warning that I ignored regarding the data power requirements. They refer to it as level shifting. In my testing of a single strand and later connecting 8 strands, I had zero issues without doing the level shifting. The moment I wired everything up outside for the bigger system, I did end up needing to level shift 🙂 ). Ok so I ignored all warnings and went straight for wiring the light strand directly to my Raspberry Pi 4 along with adding the power supply.

I started with my mess of goodies

hardware pieces to be assembled

Something very important to know about the LED lights is that the data is a one way street. When you connect your data wire to the Raspberry Pi, you need to make sure the Pi is feeding “in” to the strand. These strands come with a little arrow to explain how the data is expected to flow (sorry the arrow is a little blurry).

Picture of data directional arrow on 12mm bulb

This isn’t too terribly difficult to get wrong or right to be honest. The example I have above shows the arrow pointing up from the wire. This means that the data will come “in” from that wire to the bulb. This will be the end that you connect your power supply and Raspberry Pi onto. Speaking of that!

Power supply connections and pigtail

The nice thing about these lights is that there was a pigtail included that connected to the existing connectors. Also, the ground aka “-” has a dotted line on the wire while the positive does not. The above picture shows you the 5 wires I talked about. I have the power connected directly to the “-” and “+” light strand’s separate power wires. Those are connected to the proper terminals on the power plug connector. On the pigtail, the color scheme is like this:

  • Green == Data Wire
  • Red == +
  • White == –

With the power connected to the power plug adapter and the pigtail connected to the lights, I needed to connect everything to the Raspberry Pi. This is where the breadboard comes in:

Connections into the breadboard

On the left side of the image, you can see that I have my pigtail wired onto the breadboard. On the right side, the wires are destined for the Pi. The below table explains how I have the wires connected

Red Wire From Light Strand pigtailConnected to the “+” rail on breadboardThis serves no purpose whatsoever. I just didn’t want a lose wire roaming around
Green Wire From Light Strand pigtailConnected to row “44” on breadboardThis is the data wire to the light strand and we’ll need to connect this to GPIO18 on the Raspberry Pi via the breadboard
White Wire From Light Strand pigtailConnected to the “-” rail on the breadboardThis is connecting the ground wire from the light strand to the Raspberry Pi via the breadboard
Red Wire from Raspberry Pi Pin 6 (GND)Connected to the “-” tail on the breadboardThis is connecting the ground from the Raspberry Pi to the ground on the light strand via the breadboard
Tan Wire from Raspberry Pi Pin 12 (GPIO18)Connected to row “44” on breadboardThis is connecting GPIO18 to the light strand via the breadboard.

GPIO18 is very important to use as our data connection to the light strand. Below is a full picture of the wiring.

full wiring diagram of breadboard and pi

Getting the Software

With all of the hardware in place, it is now time to fire everything up and get the software we need to run this light show! I’m assuming you can login to your Pi and create a directory called LEDs. We’ll use this directory to house our testing code. I’m also going to assume that you are ok with using NodeJS (sorry I’ve been on a Javascript kick lately. There’s also Python code available to do this as well). Let’s get into that directory and install the rpi-ws281x-native library we’ll need to get the lights running:

 $ cd LEDs/
 pi@raspberrypi:~/LEDs $ npm install rpi-ws281x-native
 npm WARN npm npm does not support Node.js v10.21.0
 npm WARN npm You should probably upgrade to a newer version of node as we
 npm WARN npm can't make any promises that npm will work with this version.
 npm WARN npm Supported releases of Node.js are the latest release of 4, 6, 7, 8, 9.
 npm WARN npm You can find the latest version at https://nodejs.org/
 
 > rpi-ws281x-native@0.10.1 install /home/pi/LEDs/node_modules/rpi-ws281x-native
 > node-gyp rebuild
 
 make: Entering directory '/home/pi/LEDs/node_modules/rpi-ws281x-native/build'
   CC(target) Release/obj.target/rpi_libws2811/src/rpi_ws281x/ws2811.o
   CC(target) Release/obj.target/rpi_libws2811/src/rpi_ws281x/pwm.o
   CC(target) Release/obj.target/rpi_libws2811/src/rpi_ws281x/dma.o
   CC(target) Release/obj.target/rpi_libws2811/src/rpi_ws281x/pcm.o
   CC(target) Release/obj.target/rpi_libws2811/src/rpi_ws281x/mailbox.o
   CC(target) Release/obj.target/rpi_libws2811/src/rpi_ws281x/rpihw.o
   AR(target) Release/obj.target/rpi_libws2811.a
   COPY Release/rpi_libws2811.a
   CXX(target) Release/obj.target/rpi_ws281x/src/rpi-ws281x.o
   SOLINK_MODULE(target) Release/obj.target/rpi_ws281x.node
   COPY Release/rpi_ws281x.node
   COPY ../lib/binding/rpi_ws281x.node
   TOUCH Release/obj.target/action_after_build.stamp
 make: Leaving directory '/home/pi/LEDs/node_modules/rpi-ws281x-native/build'
 npm WARN saveError ENOENT: no such file or directory, open '/home/pi/LEDs/package.json'
 npm WARN enoent ENOENT: no such file or directory, open '/home/pi/LEDs/package.json'
 npm WARN LEDs No description
 npm WARN LEDs No repository field.
 npm WARN LEDs No README data
 npm WARN LEDs No license field.
 
 + rpi-ws281x-native@0.10.1
 updated 1 package in 13.568s
 pi@raspberrypi:~/LEDs $  

With that all set and ready to go, I suggest grabbing the example libraries hosted in the rpi-ws281x-native GitHub repo. Note that you will need to modify the require lines in those scripts from:

var ws281x = require('../lib/ws281x-native');

to something like this:

var ws281x = require('rpi-ws281x-native');

From there, you can try and test out the one of the scripts. Remember, you must specify the total pixels that are in the strand to be tested. By default, the code will only light up 10 bulbs. The example below shows how you would run the command for all 50 bulbs in our example strand:

 $ sudo node rainbow.js 50
 Press <ctrl>+C to exit.
 pi@raspberrypi:~/LEDs $  

Very important to run them using “sudo” because the code requires root access in order to be able to properly signal the strand.

Video: The Example Scripts in Action

Here is an example of me running those scripts and the lights in action

Making the Lights Dance

My previous post, Making the Little Lights Twinkle, covered my coding of the NodeJS server that could take simply relay numbers and command (on|off) and put them to use. Now that I have a server/service up and running, it was time for me to be able to control the lights. I removed my Orchestra of Lights and put my new Raspberry Pi hardware device in its place. The only downside is that my setup has 8 outlets and the Orchestra of Lights only had 6. As I built out some of my light sequences, I noticed there’s a delay due to relays 7 and 8 being triggered but nothing being connected to them. Maybe that’s something I can do for next year. I’ll plan for 8 lighting areas instead of just 6.

In addition to needing to be able to plan for two more strands of lights, I still hadn’t figured out my audio configuration yet. I’ve only had the time to focus on the lights themselves. For the time being, I’ve got a weatherproof bluetooth speaker outside that I sync my iPad to for music. I just tell my iPad to loop through a playlist that my wonderful wife has put together. Thank you deer!

The Initial Script

While I still struggled to find some time to continue to research making the lights dance to music, I figured it was a really good idea to get something up and running. I thought randomness was key. I wanted it to be random because I was sick of the Orchestra of lights running through the same/similar light pattern over and over and over and over…..and over. With that, I built the initial script control my lights:

#!/bin/bash

COMMANDS=("off" "on")
i=0

trap exitout SIGINT

exitout() {
  echo "We Are Done Here!"
  exit
}

while :
do
  CMD=$(( ${RANDOM} % 2 ))
  RELAY=$(( ${RANDOM} % 8 + 1 ))
  curl 127.0.0.1:8080/light/$RELAY/${COMMANDS[$CMD]}
  echo $RELAY ${COMMANDS[$CMD]}
  sleep 0.2
done

Obviously, this is a really quick hack of a script but it works. It’s also obvious that it is a simple shell script. I created the array “COMMANDS” with two elements “off” and “on”. I ended up not using “i” but oh well it’s still here. I have the script setup to exit “cleanly” by calling exitout whenever someone presses CTRL+C on the keyboard. You need this because as you can tell the script is created with a while loop that never exits.

Let’s talk about what is going on inside that while loop. With each iteration, I’m setting CMD to a random number modulo 2 which gives us either 0 or 1. I’m also setting RELAY to a random number modulo 8 which gives us something 0 – 7 on each iteration. You’ll notice I add +1 so that I actually make RELAY be 1 – 8. Next, I run a curl command with my relay number and the element 0 or 1 aka off on from the COMMANDS array. From there, I just echo out what I sent to the server and then sleep for 0.2 seconds. This loop runs forever until something crashes or the user does CTRL+C.

Oh My Goodness This is Ok

The above simple script did the trick. This made my lights randomly turn on and off. I was quite happy with the results we got with this. I had light strands turning on and off. Sometimes, the lights were doing something that appeared like it was in tune with the music. There was one little flaw in this. The flaw was that because it was random, you could have the same relay being given the same command or the randomness would focus on a single light strand turning on and off.

Ultimately, my major concern was that we had too many lights out at the same time. So, this was a really good initial step and worked well for my immediate wants and needs. I wanted more. I got bored with random and put a little time into something a little more.

Building the More Interesting Client

Ok like I said before, I was getting bored with the original client script. I wanted to be able to do just a little bit more. I built a script that does a few sequences as you can see below.

#!/bin/bash

COMMANDS=("blinkUp" "blinkDown" "danceUp" "danceDown" "blinkAll" "crazyRun")
i=0

trap exitout SIGINT

exitout() {
  echo "We Are Done Here!"
  exit
}

allLights() {
  a=1
  while [ $a -le 8 ]
  do
    curl 127.0.0.1:8080/light/$a/$1
    echo ""
    a=$(( a + 1 ))
  done 
}

blinkUp() {
  echo "Blinking Up"
  allLights on
  a=1
  while [ $a -le 8 ]
  do
    curl 127.0.0.1:8080/lights/$a/off
    echo ""
    sleep 0.5
    curl 127.0.0.1:8080/lights/$a/on
    echo ""
    sleep 1
    a=$(( a + 1 ))
  done
}

blinkDown() {
  echo "Blinking Down"
  allLights on
  a=8
  while [ $a -ge 1 ]
  do
    curl 127.0.0.1:8080/lights/$a/off
    echo ""
    sleep 0.5
    curl 127.0.0.1:8080/lights/$a/on
    echo ""
    sleep 1
    a=$(( a - 1 ))
  done
}

danceUp() {
  echo "Dancing Up"
  allLights off
  a=1
  while [ $a -le 8 ]
  do
    curl 127.0.0.1:8080/lights/$a/on
    echo ""
    sleep 0.5
    curl 127.0.0.1:8080/lights/$a/off
    echo ""
    a=$(( a + 1 ))
  done
}

danceDown() {
  echo "Dancing Down"
  allLights off
  a=8
  while [ $a -ge 1 ]
  do
    curl 127.0.0.1:8080/lights/$a/on
    echo ""
    sleep 0.5
    curl 127.0.0.1:8080/lights/$a/off
    echo ""
    a=$(( a - 1 ))
  done
}

blinkAll() {
  echo "Blinking All"
  allLights on
  allLights off
  allLights on
  allLights off
  allLights on
  allLights off
}

crazyRun() {
  echo "Doing Crazy Shit"
  danceUp
  danceDown
  allLights off
  sleep 0.5
  allLights on
  sleep 0.5
  danceDown
  danceUp
  blinkAll
  danceUp
  danceDown
  danceUp
  danceDown
}

while :
do
  CMD=$(( ${RANDOM} % 6 ))
  ${COMMANDS[$CMD]}
  sleep 0.2
done

I’ve added a bunch of different functions to this new script:

allLightsThis function takes an argument of “on” or “off”. When called, it will either turn on or off all of the lights by issuing curl commands for all relays and either on or off.
blinkUpThis function starts by turning on all of the lights and then every 0.5 seconds it turns off and then on a light staying at 1 and continuing through 8.
blinkDownThis function is similar to blinkUp but it just works backwards from 8 through 1.
danceUpThis function starts by turning all of the lights off and then works its way up from 1 through to 8. It works up by turning each light on and then off.
danceDownThis function is similar to danceUp but it just works backwards starting at 8 and continuing through to 1.
blinkAllThis function just flashes all of the lights on and off.
crazyRunThis function just takes each of the above options and runs them all as a sequence that I’ve picked out.

Finally, the while statement in this script is now being used to randomly select one of the predefined sequences. So now I’ve got something a little more sophisticated to run my light show. I still want to up the game on this to sequence on its own to music and add more lights. Here’s an example below.

This got us through this Christmas season so more upgrades for next year and I can’t wait!

Making the Little Lights Twinkle

My previous post, Building the RaspberryPi Christmas Light Box, explained at a hight level building out the hardware. That step was a little scary than I think it should be but it all worked out just fine in the end. Now that I had everything put together and powered on, I was stuck here:

pi@raspberrypi:~ $ 

What are the next steps? I’ve got this box all wired up and ready to go but now I’m just sitting at a prompt waiting. As I mentioned before, I broke this down into a few parts to make my life easier and not get overwhelmed. After doing some more and more reading, I figured I had two options. I could program everything in Python or I could program everything in NodeJS.

I’m comfortable either language and no matter how hard I tried I kept going in circles. Something told me that I should write it in NodeJS because I felt that I should consider a client-server model. There were TONS of examples of people that had written all kinds of programs and libraries for handling sound and music and lights and GPIOs. I ended up throwing myself a curve ball. I decided that the client-server model was indeed what I should consider for future expansion of my new found hobby of Christmas tree lighting so I decided on NodeJS.

Well Folks, Here’s the Start of the Code

It all started pretty easy. I wanted to first make sure I had all of my GPIOs hooked up correctly. I wanted to make sure things blinked on and off like I expect. It seems that the only thing I needed to make NodeJS work was the onoff package. I popped into a directory on my Pi and installed it:

npm install onoff --save

Great! I guess the next step was to steal one of the sample JS scripts that gives you an example of how to make a relay turn on and off (my blink.js is born):

var Gpio = require('onoff').Gpio; //include onoff to interact with the GPIO
var LED = new Gpio(23, 'out'); //use GPIO pin 23, and specify that it is output
var blinkInterval = setInterval(blinkLED, 250); //run the blinkLED function every 250ms

function blinkLED() { //function to start blinking
  if (LED.readSync() === 0) { //check the pin state, if the state is 0 (or off)
    LED.writeSync(1); //set pin state to 1 (turn LED on)
  } else {
    LED.writeSync(0); //set pin state to 0 (turn LED off)
  }
}

function endBlink() { //function to stop blinking
  clearInterval(blinkInterval); // Stop blink intervals
  LED.writeSync(0); // Turn LED off
  LED.unexport(); // Unexport GPIO to free resources
}

setTimeout(endBlink, 5000); //stop blinking after 5 seconds

That seemed to work just wonderfully so I wanted to make sure that I could get all of the relays to go click click for me so enter the flowled.js (This is a great way to annoy ANYONE within ear shot. Remember from my previous post that I have the analog relays so they go *click click* when they turn on and off). While my wife was excited at the thoughts of our new Christmas lighting show, she was getting annoyed of the various clicking combinations that I came up. Thank you for your patience and appearing to be just as excited as I was deer!:

var Gpio = require('onoff').Gpio; //include onoff to interact with the GPIO
var RELAY01 = new Gpio(24, 'out'), //use declare variables for all the GPIO output pins
  RELAY02 = new Gpio(25, 'out'),
  RELAY03 = new Gpio(23, 'out'),
  RELAY04 = new Gpio(22, 'out'),
  RELAY05 = new Gpio(12, 'out'),
  RELAY06 = new Gpio(13, 'out'),
  RELAY07 = new Gpio(16, 'out'),
  RELAY08 = new Gpio(26, 'out');

//Put all the RELAY variables in an array
var leds = [RELAY01, RELAY02, RELAY03, RELAY04, RELAY05, RELAY06, RELAY07, RELAY08];
var indexCount = 0; //a counter
dir = "up"; //variable for flowing direction

var flowInterval = setInterval(flowingLeds, 100); //run the flowingLeds function every 100ms

function flowingLeds() { //function for flowing Leds
  leds.forEach(function(currentValue) { //for each item in array
    currentValue.writeSync(0); //turn off RELAY
  });
  if (indexCount == 0) dir = "up"; //set flow direction to "up" if the count reaches zero
  if (indexCount >= leds.length) dir = "down"; //set flow direction to "down" if the count reaches 7
  if (dir == "down") indexCount--; //count downwards if direction is down
  leds[indexCount].writeSync(1); //turn on RELAY that where array index matches count
  if (dir == "up") indexCount++ //count upwards if direction is up
};

function unexportOnClose() { //function to run when exiting program
  clearInterval(flowInterval); //stop flow interwal
  leds.forEach(function(currentValue) { //for each RELAY
    currentValue.writeSync(0); //turn off RELAY
    currentValue.unexport(); //unexport GPIO
  });
};

process.on('SIGINT', unexportOnClose); //function to run when user closes using ctrl+c

Time to Build the REST API!

Now that I had sufficiently annoyed everyone in the house by showing them the little LED on the relays blink and click, I think it was time to actually put this to work for me. All good client server models work via APIs, right? I had dreams of multiple Pis being setup around the yard and house being controlled by a central Pi that played the music and made all of the magical lighting happen. This will indeed be the case in a few years I’m sure. But we’re crawling before we can dead sprint. With that, I added http to my project with a little:

npm install http --save

So now I had onoff and http installed and saved to my package.json. With onoff and http ready to go, it was time for me to create the REST API server. I started with a few constants:

var Gpio = require('onoff').Gpio; //include onoff to interact with the GPIO
var RELAY1 = new Gpio(24, 'out'), //use declare variables for all the GPIO output pins
  RELAY2 = new Gpio(25, 'out'),
  RELAY3 = new Gpio(23, 'out'),
  RELAY4 = new Gpio(22, 'out'),
  RELAY5 = new Gpio(12, 'out'),
  RELAY6 = new Gpio(13, 'out'),
  RELAY7 = new Gpio(16, 'out'),
  RELAY8 = new Gpio(26, 'out');

const NUM_RELAYS = 8;
const RELAYS = [RELAY1, RELAY2, RELAY3, RELAY4, RELAY5, RELAY6, RELAY7, RELAY8];

const COMMANDS = [ 'on', 'off' ];

const PORT = process.env.PORT || 8080

Of course, the first var is to bring in the GPIO control and then I mapped the various RELAY vars to the appropriate gpios that I was using on my Pi. I have a total of 8 relays to choose from and then I also created two arrays, RELAYS and COMMANDS. These will make more sense later. Finally, I’m defining a default port for my API server to run on:

var http = require('http').createServer(handler); //require http server, and create server with function handler()

console.log(`Server Running on ${PORT}`);
http.listen(PORT);

Then we fire up the http server with my “handler” middleware. The handler function is below:

function handler (req, res) { //create server
  if (req.url.startsWith('/light') && req.method == 'GET') {
    getCommands(req.url, (err, commands) => {
      if(err) {
        var message = `{"test": "Failed","message": "${err}"}`;
      } else {
        var message = doCommand(commands.relay, commands.command);
      }
      res.statusCode = 200;
      res.setHeader('Content-Type', 'application/json');
      res.end(message);
    })
  } else if ( req.url == '/status' && req.method == 'GET' ) {
    res.statusCode = 200;
    res.setHeader('Content-Type', 'application/json');
    res.end('{"status": 200, "message": "test ok"}');
  } else {
    //Set the response HTTP header with HTTP status and Content type
    res.statusCode = 200;
    res.setHeader('Content-Type', 'application/json');
    res.end('{"status": 200, "message": "ok"}');
  }
}

I setup handler to push two routes that will accept GET requests, /light and /status. The /light route is where everything happens and /status was future proofing to make sure that we could possibly check the status of the server when we build the monolithic light show like Clark W! Of course, the final “else” is my garbage eat all where I just return “ok” to any request.

For those that don’t know, I’m a security geek so I built my getCommands function into the /light route:

function getCommands(string, cb) {

  var data = string.split('/');

  if(data.length != 4) {
    return cb('Wrong Number of Arguments Provided');
  }

  if(!COMMANDS.includes(data[3])) {
    return cb('Unsupported Command');
  }

  if(data[2] > NUM_RELAYS || data[2] < 1) {
    return cb('Sorry We Cannot Control That One');
  }

  result = {
    "relay" : data[2],
    "command" : data[3]
  }

  return cb(null, result);
}

The purpose of this function is to make sure we’re not fed garbage by anyone. I’m checking to make sure we get the right number of items in the request path (aka /light/<RELAY #>/<COMMAND>). If these fail, then I fail the request and do nothing. Assuming we pass validation, we get to the work horse, doCommand:

function doCommand(relay, command) {
  var myIndex = relay - 1;
  try {
    RELAYS[myIndex].writeSync(COMMANDS.indexOf(command));
    var message = 'OMG This is Great!';
  } catch (e) {
    var message = e;
  }
  var resp = `{"status": "Ok", "message": "${message}"}`

  return resp;
}

This function just takes the received command (on or off) and runs it against the specified relay (1 – 8). In curl the command would look a little something like this to turn on relay 4:

$ curl localhost:8080/light/4/on
{"status": "Ok", "message": "OMG This is Great!"}

To turn off the same relay, we would issue:

$ curl localhost:8080/light/4/off
{"status": "Ok", "message": "OMG This is Great!"}

Now I have a NodeJS server that can handle REST API calls to be able to turn on and off certain relays. What an accomplishment! Next post will cover how I put this all together to at least do some crappy light shows.

Building the RaspberryPi Christmas Light Box

Disclosure: I have included some affiliate / referral links in this post. There’s no cost to you for accessing these links but I do indeed receive some incentive for it if you buy through them.

Let’s Cover Some Background Here

I have always enjoyed Christmas lights. For quite some time, I was very intrigued at the notion of putting the lights to music or at least making them dance in motion. About 3 years ago, my wife and I bought a string of lights that had a mind of their own. It was neat to watch it random go through the different patterns of blinking, dancing, and chasing. Last year was the year that we got the really neat ones. They were icicles that changed colors AND danced and chased and more.

All of this was great but I wanted more this year. I wanted to be able to set the lights to music just like the fancy light shows you go to see. I figured the easiest way to do this was to just simply buy something at the store, right? So that’s what we did. We ended up buying an Orchestra of Lights (sure a plug for them yaay). The concept is really cool. We bought the speak box that comes with 6 outlets that are all controlled by the wifi hub. We’ll just say that if you’d like to buy one of these, ask me about purchasing a barely used one for a deep discount.

As part of a little additional background, I’ve always wanted to get my hands on a Pi or Arduino but I could never justify buying one. I could never figure out what legitimate project to apply such an amazing device. Enter the friend….

The Friend Made Me Do It

This is what friends are for right? As we were stringing up all of the lights outside, a friend of ours stopped by who is also a geek. I explained what we were doing and he very promptly asked if I was using a Raspberry Pi to do all of it. As the gears began to turn in my head, I know my face gave it all away. We weren’t doing it at the time, but we would be in just about a week!

The Planning Phase

I’m an over planning and over thinker so I was looking everywhere for what I needed how I needed to do it and what I should do next. My end goal was to be able build a device I could put outside that would play music and control the lights automatically to whatever little tune was playing at the time. This turned out to be a little more difficult than I bargained for but not a big deal. I looked at a bunch of sites and decided that I should probably break this project down into parts.

  1. Build out the hardware
  2. Make it do “something”
  3. Look at how I could possibly get the music to control the action

During this planning phase, I happened upon a really great article that gave amazing details on hooking up the hardware (https://system76.com/weekend-project/holiday-light-show). I mostly ignored everything but the pretty pictures. This site along with a bunch of other sites helped me put together my shopping list.

The Shopping List

Now remember that I said I had already ordered the Pi but let’s still list it here so that you know what I had coming:

This would be the very the basic shopping list. I also bought some little connectors and such so that I could conduit all of the metal pieces together. I also bought some tiny screws and bushings so that I could install the Pi and relay into the breaker box.

Putting it all Together

I lined up the Pi and Relay and marked my holes. I drilled them out. I added my bushings. I mounted everything and was quite proud of it all. Next steps were to wire everything up. Ok why reinvent the wheel here. As I noted before, I basically did exactly what was done in Steps C – K in here. This was a really great write up on how to wire everything.

After everything was done I had me a nice little system. This would be a GREAT spot to add a picture but I already have it hooked up on the porch, plugged in, and nicely hidden away so the neighbors can’t see it. I’ll remember to take some pictures next time.

Next, I’ll go through the code that I put together to get the thing clicking like crazy!