I’ve been wanting to start a project using a Raspberry Pi for a while, I just needed to come up with a practical idea. A few months ago, I was in the process of automating my company’s deployment process using Capistrano — this seemed as good a time as any. I decided on picking up a real traffic light and using the Pi’s GPIO pins to control the individual lights through relays, using the Pi to trigger light sequences programmatically. I eventually hooked it into our Capistrano recipe, using light sequences to show the progress of our staging/production deployments.
I picked up a traffic light on Craigslist for around $50 and a Raspberry Pi B, as well as an 8 Channel 5V Relay Shield Module. Though the Pi’s GPIO outputs are only 3.3v, the relays are active on low inputs. This means as long as we give the relays an output marginally above 0v, they’ll be deactivated. Here is the Pi wired up to the relay board:
Installing the wiringPi library and issuing the commands to send low signals to the relays made them click as expected. The next step was to wire the relay outputs to the traffic light. Here, I wrote a quick script to sequence through all three lights:
Time to get this hooked up to Capistrano so it can show the status of our deployment process. The first step was to install Apache/PHP and write a very simple script to illuminate the individual lights. I decided to use PHP to directly interact with the CLI wiringPi library. This definitely isn’t the most elegant solution, but remains simpler than some of the other API interactions I’d come across. The below script allows web requests to trigger specific lights to illuminate when requested with their corresponding GET parameter:
function clear_all()
{
$pins = array(3,4,5);
foreach($pins as $pin)
{
$cmd = "gpio write $pin 1";
shell_exec($cmd);
}
}
if(!empty($_GET['color']))
{
clear_all();
switch($_GET['color'])
{
case 'yellow-blink-start':
shell_exec("/etc/init.d/yellow-blinking start > /dev/null 2>&1 &");
break;
case 'yellow-blink-stop':
shell_exec("/etc/init.d/yellow-blinking stop > /dev/null 2>&1 &");
break;
case 'red':
$pin = 3;
$inner_cmd .= "gpio write $pin 0 && sleep 5m && gpio write $pin 1";
$cmd = "($inner_cmd) > /dev/null 2>&1 &";
shell_exec($cmd);
break;
case 'green':
$pin = 5;
$inner_cmd .= "gpio write $pin 0 && sleep 1m && gpio write $pin 1";
$cmd = "($inner_cmd) > /dev/null 2>&1 &";
shell_exec($cmd);
break;
}
}
Pretty straightforward. Basically, the script constructs a shell command and sends it to the background. This way, the web request isn’t waiting for the command to complete and we still timeout the lights after certain intervals. For instance, after green is show, it shuts off automatically after one minute. This is built directly into the shell command when it’s issued.
With the yellow light however, I needed to come up with a different solution. The plan for the yellow light was for it to blink continuously on and off during the deployment process, but since that process can vary in length, we need to be able to tell it to start blinking and stop blinking, without requiring the web request to be held for that entire duration. To handle the yellow light blinking process, I created a simple daemon:
#!/bin/bash
do_start()
{
touch /tmp/testfile
while true;
do
if [ ! -f /tmp/testfile ]; then
break
fi
gpio write 4 0
sleep 1
gpio write 4 1
sleep 1
done
}
do_stop()
{
echo "stopping!"
rm -rf /tmp/testfile
}
case "$1" in
start)
do_start &
;;
stop)
do_stop
;;
esac
Essentially, this service begins by creating a tmp file, followed by looping through a blinking sequence (one second delay between on/off). The loop lasts until the tmp file no longer exists. Stopping the service of course removes this temp file, and the loop terminates.
Great! At this point, I’m able to manually toggle the lights by visiting the corresponding URLs on my Pi. All that’s left is to create a Capistrano recipe. I don’t write a lot of Ruby, so I’m sure this can be done more efficiently.
require 'open-uri'
set :trafficlight_host, "http://10.0.0.214"
namespace :deploy do
task :show_red do
trafficlight_host = fetch(:trafficlight_host)
begin
open("#{trafficlight_host}/cap.php?color=red")
rescue OpenURI::HTTPError => ex
puts "traffic light 404 Error"
end
end
task :start_blinking do
trafficlight_host = fetch(:trafficlight_host)
begin
open("#{trafficlight_host}/cap.php?color=yellow-blink-start")
rescue OpenURI::HTTPError => ex
puts "traffic light 404 Error"
end
end
task :stop_blinking do
trafficlight_host = fetch(:trafficlight_host)
begin
open("#{trafficlight_host}/cap.php?color=yellow-blink-stop")
rescue OpenURI::HTTPError => ex
puts "traffic light 404 Error"
end
end
task :show_green do
trafficlight_host = fetch(:trafficlight_host)
begin
open("#{trafficlight_host}/cap.php?color=green")
rescue OpenURI::HTTPError => ex
puts "traffic light 404 Error"
end
end
before :starting, :show_red
before :started, :start_blinking
after :finished, :stop_blinking
after :finished, :show_green
after :failed, :stop_blinking
end
The deployment went off as expected! As you can see, I initially show a red signal while picking branches and beginning the preparation to deploy. It then begins the blinking process until finishing with the “finished” hook. It’s now hung in the corner of my office and keeps me informed of deployments to our different server environments throughout the day!
Share this:

