Giant ShiftBrite Election Meter

Election Meter

I built a giant red/blue bar graph to display the electoral vote at my house tonight. It uses 32 ShiftBrite RGB LED modules, two CSG-4M LED numerical displays, a Cubloc CB405 with Quick Start 1000 board, and an ACODE-300B Bluetooth module. I used Eric's code from Hackaday last night to scrape CNN's election results. The code runs on a small 400MHz Linux server I always have running for file storage and random scripting.

Here's how I did it:

Election Meter

I started with the above parts already listed. In addition, there's a carrier board for setting up the ACODE Bluetooth module, an LM1086 3.3 volt regulator for powering the ACODE module later, and a cheap (~$5) Bluetooth USB dongle from DealExtreme.

First, I wanted to make sure the Bluetooth dongle would work from Linux. I've had really good results with these before, Linux seems to pick up all the common chipsets immediately. I plugged it into the old Linux server running in the lab at my house, and checked the results with dmesg:

Election Meter

Lookin' good! Next, let's try to get the Linux computer talking to the ACODE module over Bluetooth. First, I plugged the ACODE module into a USB-RS232 converter and power.

Election Meter

Next, I connected to the USB-RS232 converter at 9600bps on COM4 using PuTTY:

Election Meter

And held the reset button on the ACODE carrier board until the serial configuration terminal appeared:

Election Meter

You can select menu items by typing the letter and pressing Enter. I changed the name to "Election", left authentication off, changed the connection mode to "MODE2" which automatically reconnects to the last connected device. I also disabled the status message since I didn't want to have non-data text coming into the Cubloc serial port. I made sure the role was "SLAVE" since I planned to use the Linux server as the master device. I turned the power to the ACODE on and off, and it's ready to go!

Back in my SSH session to the Linux server, I scanned for the ACODE module with "hcitool scan":

Election Meter

There it is! I also copied the device address since it's required later.

Next, I made sure the Bluetooth serial port service was available with "sdptool search SP":

Election Meter

And everything still looks good. I noted that my RFCOMM service was on Channel 1, this is generally true for a single function device like the ACODE-300, but it may be different on other Bluetooth devices.

To map the remote Bluetooth serial port to a local serial port, I used "rfcomm bind 0 00:06:6E:11:B7:36":

Election Meter

I tested the connection by echoing some text to /dev/rfcomm0, and it appeared in my local serial connection to COM4, from the ACODE-300 Bluetooth serial port.

So I wouldn't have to issue the rfcomm command manually again, I added the following configuration in /etc/bluetooth/rfcomm.conf:

Election Meter

So I've definitely got a wireless link going! I can treate /dev/rfcomm0 as a normal serial port. This will make it easy to communicate from Python later.

First, I've got to get some hardware together. I used the CB405 and Quick Start 1000 board, and added the ACODE-300 module to the breadboard area. The ACODE module needs 3.3 volts, so I used an LM1086 regulator. It's not picky about logic levels, so I was able to run those directly into the TTL serial ports for Channel 1 on the CB405. I also added a 10K pullup resistor on the ACODE Reset line, and a 100 ohm resistor and LED for the status indicator. This will blink at first, but will stay on when a connection is active.

Election Meter

Next, I added connections for a ShiftBrite chain, hooked up the CSG-4M displays, and used some old code to test the ShiftBrites and displays. I lined up 32 ShiftBrites on a piece of 3/4x3/4 hardwood, fastened with zip ties, and chained with the 3.5" cables from my store.

Election Meter

Election Meter

Election Meter

Before writing the Cubloc code, I wanted to get Eric's CNN scraper sending data to the serial port. Here's what I ended up using:

import urllib2
import re
import serial

class ElectionWon(Exception):

class CNN(object):
  def __init__(self):
    self.url = ""

  def get(self):
    """return the electoral balance
        (dpopular, delectoral), (rpopular, relectoral)
    u = urllib2.urlopen(self.url)
    for line in u.readlines():
      res ='var CNN_NData=(.*?);', line)
      if res is not None:
        data =
        data = data.replace("true", "True")
        data = data.replace("false", "False")
        data = eval(data)

        demp = None
    deme = None
    repp = None
    repe = None
    w = "N"
        for candidate in data['P']['candidates']:
          if candidate['party'] == 'D':
            demp = candidate['votes']
        deme = candidate['evotes']
            if candidate['winner']:
              w = 'D'
          elif candidate['party'] == 'R':
            repp = candidate['votes']
        repe = candidate['evotes']
            if candidate['winner']:
              w = 'R'

    return demp,deme,repp,repe,w

if __name__=='__main__':
  cnn = CNN()
  s=str(cnn.get()) + "\n"
  ser = serial.Serial('/dev/rfcomm0', 9600, timeout=1)

Next, I needed to process the data coming from the Bluetooth connection. I used the Cubloc's serial routines to iterate through the received string and extract the numbers and winner data. Then, I calculated the position of the bar graph and sent the color commands out to the ShiftBrite array.

Const Device = CB405

Opencom 1,9600,3,32,32
On Recv1 Gosub GetSerial

Set Until 1,32,10

Set I2c 45,44

#define CI 2
#define EI 3
#define LI 4
#define DI 5

Low CI
Low LI
Low DI
Low EI

#define Num_ShiftBrites 32
Dim CurrentRGB(Num_ShiftBrites,3) As Integer

Dim RecvString As String * 64
Dim Results(4) As Integer
Dim Winner As String * 1

Dim ElectoralPercentage As Long

Dim i As Byte
Dim j As Byte
Dim k As Integer
Dim n As Integer
Dim tempStr As String * 12
Dim BlinkVal As Integer



Delay 250

If Winner = "D" Then
    For n = 0 To Num_ShiftBrites
        CurrentRGB(n,2) = BlinkVal
Elseif Winner = "R" Then
    For n = 0 To Num_ShiftBrites
        CurrentRGB(n,0) = BlinkVal

BlinkVal = 1023 * (BlinkVal = 0)

Csgdec 0,Results(3)
Csgdec 1,Results(1)



    RecvString =  Getstr2(1,32,10)
    Bclr 1,2

    i = 1

    For j = 0 To 3   

        tempStr = ""
        Do While RecvString_A(i) <> 44
        tempStr = tempStr + Chr(RecvString_A(i))
        Incr i
        Results(j) = Val(tempStr)

        Incr i
        Incr i
    Incr i
    Winner = Chr(RecvString_A(i))


Sub DrawShiftBrites()

        For k = 1 To Num_ShiftBrites
            Shiftout CI,DI,1,0b010001101111,12
            Shiftout CI,DI,1,0b0001111111,10
            Shiftout CI,DI,1,0b0001111111,10


        High LI
        Low LI

    For k = Num_ShiftBrites To 1 Step -1
        Shiftout CI,DI,1,CurrentRGB(k-1,2),12
        Shiftout CI,DI,1,CurrentRGB(k-1,0),10
        Shiftout CI,DI,1,CurrentRGB(k-1,1),10
    High LI
    Low LI
End Sub

Sub CalcBarGraph()

ElectoralPercentage = (1024*Results(1)/(Results(1)+Results(3)))*Num_ShiftBrites

If Results(1) = 0 And Results(3) = 0 Then ElectoralPercentage = 1024*32/2
For n = 0 To Num_ShiftBrites

    If (ElectoralPercentage >= (n*1024) And ElectoralPercentage < (n*1024+1023)) Then
        CurrentRGB(n,2) = ElectoralPercentage - (n*1024)
    Elseif ElectoralPercentage > (n*1024) Then
        CurrentRGB(n,2) = 1023
        CurrentRGB(n,2) = 0

    CurrentRGB(n,0) = 1023 - CurrentRGB(n,2)


End Sub

Finally, I fastened everything to a board. Looks pretty good!

Election Meter

Election Meter

Election Meter

Submitted by Garrett on Tue, 11/04/2008 - 14:06.

Too bad the election didn't

Too bad the election didn't turn out as great as your project.

Wow, this is a neat idea. It

Wow, this is a neat idea. It looks like a nice build. I am amazed at how clean your work area is too, way better than mine. =)

Post new comment

The content of this field is kept private and will not be shown publicly.
Please prove you are sentient by typing the correct phrase below (capital letters only):
  ___   ___  __  __  _  __  ___    ___   __  __   ___ 
| __| | __| \ \/ / | |/ / / __| / _ \ \ \/ / / __|
| _| | _| > < | ' < \__ \ | (_) | > < | (_ |
|_| |___| /_/\_\ |_|\_\ |___/ \__\_\ /_/\_\ \___|
Enter the code depicted in ASCII art style.