#!/usr/bin/python # Quick and dirty AmbientOrb code to scrape and report election results # most of this code came from: # http://www.exothermia.net/monkeys_and_robots/2008/11/03/code-to-scape-cnncom-election-results/#more-34 import serial import urllib2 import re import time from optparse import OptionParser SERIAL_PORT = "/dev/ttyUSB0" BAUD = 9600 UPDATE = 600 class ElectionWon(Exception): pass class CNN(object): def __init__(self): self.url = "http://www.cnn.com/ELECTION/2008/results/president/" def get(self): """return the electoral balance (dpopular, delectoral), (rpopular, relectoral) """ u = urllib2.urlopen(self.url) for line in u.readlines(): res = re.search(r'var CNN_NData=(.*?);', line) if res is not None: data = res.group(1) data = data.replace("true", "True") data = data.replace("false", "False") data = eval(data) d,r = None, None for candidate in data['P']['candidates']: if candidate['party'] == 'D': d = candidate['votes'], candidate['evotes'] if candidate['winner']: raise ElectionWon("D") elif candidate['party'] == 'R': r = candidate['votes'], candidate['evotes'] if candidate['winner']: raise ElectionWon("R") return d,r def normalize(d,r, interval=0.5): """normalize to -1 => democrat winning +1 => republican winning abs(1.0) is having "2*interval" higher percent than the other guy """ if d+r == 0: return 0.0 rnorm = 2.0*(1.0*r/(d+r) - 0.5) / (2*interval) if rnorm > 1.0: rnorm = 1.0 if rnorm < -1.0: rnorm = -1.0 return rnorm def calc_color(value): """ Assumes a normaized -1:1 range and returns 0000FF through FF0000 Only manipulates the Red and Blue values -1 ==> 0000FF 0 ==> 000000 1 ==> FF0000 """ red = 0 blue = 0 if(value < 0): blue = (value * -128) + 127 if(value > 0): red = (value * 128) + 127 return('%02x00%02x' % (red, blue)) if __name__=='__main__': POP_VOTE = 0 ELECTORAL_VOTE = 1 parser = OptionParser() parser.add_option("-e", "--electoral", dest="vote_sel", action="store_const", const=ELECTORAL_VOTE, help="Report based on electoral vote (default)") parser.add_option("-p", "--popular", dest="vote_sel", action="store_const", const=POP_VOTE, help="Report based on popular vote") (options, args) = parser.parse_args() vote_sel = options.vote_sel if(vote_sel is None): vote_sel = ELECTORAL_VOTE cnn = CNN() ser = serial.Serial(SERIAL_PORT, BAUD, timeout=1) time.sleep(10) try: while True: (d,r) = cnn.get() ser.write("#" + calc_color(normalize(d[vote_sel], r[vote_sel]))) time.sleep(UPDATE) except ElectionWon, elewon: if(elewon.message == 'D'): ser.write("%0000FF") elif(elewon.message == 'R'): ser.write("%FF0000") while True: time.sleep(UPDATE)