Traffic Light shows Air Quality Index

I recently saw this project: Traffic Light Shows Internet Status at the “WTH” (whiskey tango hotel) website and decided it would be fun to build. So here we go.

I found the same traffic light available on Amazon: http://smile.amazon.com/gp/product/B00IX73BGW

I decided (of course) to make a few changes to the project:

  • I used a BeagleBone Black (BBB), simply because it was something I had sitting in the “random leftover stuff” bin. It’s the same idea as a Raspberry Pi – it’s a small inexpensive box running Linux.
  • I completely redid the internal wiring of my toy traffic light to separate out each LED connection individually (six wires total) whereas WTH implemented his project leaving the original common anode wiring intact (4 wires total coming out of the traffic light). I’d like to say I rewired for a particularly good reason but I didn’t really; I just did it during debugging because I was confused. But, as a result, I am presenting an alternate implementation of the circuitry.
  • I hooked my traffic light up to Numerous (of course) and it is currently displaying my Austin Air Quality Index metric. It displays the red light for bad air quality, yellow for moderate, and green for good.

Modifying the Traffic Light

As WTH did, I opened the base of the light (four screws) and removed the small circuit board inside by cutting its connections.

I then opened the back of the traffic light itself (another four screws). The original connections look like this:

2015-10-21 19.24.29

 

Schematically, the light is wired like this:

 

original-led copy

Notice how they oriented the LEDs to make the common-anode setup easier to wire.

I cut all these connections, took a cat5 cable, separated out three pairs (6 wires) and brought the individual anode/cathode connections from each LED out of the traffic light. Beware software engineers with soldering irons! But it seemed to work out ok.

To help me keep track of what was going on, I was careful to set up this color code:

  • Brown – anode (positive) side of the red LED
  • Brown/white – cathode (negative) side of the red LED
  • Orange – yellow LED anode
  • Orange/white – yellow LED cathode
  • Green – green LED anode
  • Green/white – green LED cathode

Obviously the color choices don’t matter – but if you do rewire your entire light make sure you keep track of which ones are the anodes and cathodes in some methodical manner.

The LEDs need to be wired in series with a resistor (for current-limiting) and connected to the BBB. On the BBB I used GPIO outputs 1-16, 1-17, and 1-18, which are also known in the /sys/class/gpio filesystem as gpio48, gpio49, and gpio50. The BBB has three GPIO chips; chip 0 occupies gpio0..gpio31, so each input/output on GPIO chip 1 is numbered as “n + 32”. Thus GPIO 1-16 is known as “gpio48” in the /sys/class/gpio filesystem.

The pins for gpio48, 49, and 50 are on connector P9 as shown here:

p89

You’ll also need to make a GND connection, which can be common across all three LEDs. I connected it all up according to this schematic:

gpio-led

The BBB GPIO outputs only supply 3.3V whereas the design used by WTH supplies 5V. 3.3V is still enough to light the LEDs but the calculation for the total amount of current (which determines brightness) will be different. The fixed voltage drop across an LED varies by color, but using 1.9V as an approximate average value the amperage calculation for 470Ω looks like this:

(3.3V – 1.9V) / 470Ω = approximately 3ma

This is within the current that the BBB can supply on these particular output pins. The corresponding current flow from the Pi at 5V is:

(5V – 1.9V) / 470Ω = 6.6ma

I decided to try 470Ω and see if it was bright enough for my purposes; it was. If you want to try experimenting you could reduce the 470Ω resistor. Be careful not to overdrive the LED nor overdraw the GPIO outputs.

I stuck with 470Ω as I already mentioned; this has the added advantage of my trivial little circuit board still being ok if I move it to a Pi at 5V.

Controlling the lights

Now to write some software. While I was changing everything else about the WTH approach, I decided to also just use the /sys/class/gpio “special text files” to control the outputs. To do this first you have to “export” the pins you want to control this way. At the shell you do this:

    root# echo 48 > /sys/class/gpio/export
    root# echo 49 > /sys/class/gpio/export
    root# echo 50 > /sys/class/gpio/export

which tells the kernel you’ll be using the filesystem interface for pins 48, 49, and 50. You only have to do this once per boot (assuming no one ever unexports them after you export them).

Then you have to set their direction. You can also give an initial setting (high or low) at the same time:

    root# GP=/sys/class/gpio
    root# echo high > $GP/gpio48/direction
    root# echo high > $GP/gpio49/direction
    root# echo high > $GP/gpio50/direction

At this point you turn an individual GPIO on or off like this:

    root# GP=/sys/class/gpio
    root# echo 1 > $GP/gpio48/value

Writing 1 turns it on; writing 0 turns it off.

I wrote python code to do exactly this. Note that you have to be prepared for the export requests to fail if the pins have already been exported by a previous run. My code for setting up the pins looks like this:

gp = '/sys/class/gpio'
gpdir = gp + '/gpio{}/direction'

pins = {'red':'48', 'yellow':'49', 'green':'50' }

for color in pins:
  try:
    with open(gp + '/export', 'w') as f:
      f.write(pins[color] + '\n')
    with open(gpdir.format(pins[color]), 'w') as dirf:
      dirf.write('high\n')
  except OSError:
    pass

If you want, you could check the OSError and make sure that if something fails it was because the export was already done a previous time. But pragmatically this suffices.

I wrote a python function to turn an individual light on or off:

gpio_v = gp + '/gpio{}/value'

# call with, for example:
#    color == 'red' 
#    onoff == 1
# to turn on the red LED
def light_onoff(color, onoff):
  with open(gpio_v.format(pins[color]), 'w') as f:
    f.write('{}\n'.format(onoff))

# convenience function:
def alllightsoff():
  light_onoff('red', 0)
  light_onoff('yellow', 0)
  light_onoff('green', 0)

Now that we have the basic tools for manipulating the lights, we’re ready for the final code.

Connecting to Numerous

I used my Numerous class library (https://github.com/outofmbufs/Nappy and/or “pip install numerous”) to get the value of a metric I wanted to display; in this case I am reading my Austin Air Quality Index . This is a public metric, anyone who wants to read it is permitted to do so.

The government defines an AQI value of 50 or less as “Good”, a value of 51 to 100 as “moderate”, and values above 100 as various increasing levels of “bad”. I’m displaying those on my light with the obvious mapping to red/yellow/green. The code for doing this looks approximately like this (simplified for presentation here):

import numerous
m = numerous.NumerousMetric('7896524241619416448')

try:
  q = m.read()
except numerous.NumerousError:
  q = -1

alllightsoff()
if q == -1:
  light_onoff('red', 1)
  light_onoff('yellow', 1)
elif q < 51:
  light_onoff('green', 1)
elif q < 101:
  light_onoff('yellow', 1)
else:
  light_onoff('red', 1)

Notice that if there was an error talking to the Numerous server I display both a red and yellow light simultaneously.

The actual code loops around this, reading from Numerous once every three minutes to get any new values.

Bells and Whistles

Right after I get a (possibly) new value from Numerous I run a loop that “rolls” the traffic lights, rapidly looping green, yellow, red, green, yellow, red, etc. This lets you know that the system is working and also turned out to be a cool looking effect. The code for doing this looks like this:

alllightsoff()
dt = 0.03
for i in range(30):
  light_onoff('green', 1)
  time.sleep(dt)
  light_onoff('green', 0)
  time.sleep(dt)
  light_onoff('yellow', 1)
  time.sleep(dt)
  light_onoff('yellow', 0)
  time.sleep(dt)
  light_onoff('red', 1)
  time.sleep(dt)
  light_onoff('red', 0)
  time.sleep(dt)

# ... now update the light based on Numerous

It almost looks visually as if the lights are “spinning” and finally settling on whatever the new value dictates.

In addition to rolling the lights when updating from Numerous, every thirty seconds I blink whichever light happens to be turned on as another way for you to know that the system is still alive and well.

The Actual Code

For presentation purposes here I’ve simplified the code snippets shown in the discussion and edited them to make it fit the screen better. The full source code I am running for my traffic light is here.

Buttoning it all back up

The cat5 wire I used fits very well into the tube/base of the toy traffic light. I did drill a hole in the side of the plastic base so that the light could stand up and the wire could come out through the side of the base. I did this by hand using a pin vise starting with a small bit and basically reaming the hole gradually larger with increasing bit sizes. I’m not 100% sure if that amount of care was necessary, but it worked.

I also wedged some hex nuts into the (now unused/disconnected) battery compartment in the base to weight the traffic light better. I really want to go get some better lead weights for this but for now the hex nuts seem to work reasonably well at keeping the light upright despite the new leverage point from the cable sticking out of the base.

My “circuit” which consists of a whopping three resistors is sitting on a tiny project breadboard that I just double-sticky-taped to the top of the BBB case. The whole thing *almost* fit inside the case; I’m tempted to just hand-solder and hand-construct a small assembly that can in fact be jammed into the case leaving nothing but the cat5 wire coming out of the case and running to the traffic light.

Here’s the result – before I was able to add some cable dressing/management:

done

Air quality was good ( < 50) at the time this picture was taken.

4 thoughts on “Traffic Light shows Air Quality Index”

Leave a Reply

Your email address will not be published. Required fields are marked *