Skip to content

Commit c2e16d6

Browse files
author
Aaron Artessa
committed
2 parents 4b7d4be + 28bd45d commit c2e16d6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+1363
-1404
lines changed

.behaverc

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[behave]
2+
show_source=yes
3+
stop=yes
4+
strict=yes

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
.DS_Store
22
*.sublime-*
3-
node_modules
3+
*.pyc
4+
massroute.log

Gruntfile.js

-70
This file was deleted.

LICENSE

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
The MIT License
2+
3+
Copyright (C) 2013 Infrared5 Inc. and contributors.
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy of
6+
this software and associated documentation files (the "Software"), to deal in
7+
the Software without restriction, including without limitation the rights to
8+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9+
of the Software, and to permit persons to whom the Software is furnished to do
10+
so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

README.md

+15-3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
1-
massroute-pi
2-
===
3-
> real-time bus route aggregation and display using a [raspberry pi](http://www.raspberrypi.org)
1+
Introduction
2+
---
3+
> An exploration of real-time bus data aggregation and display using Raspberry Pi
4+
5+
###Schematic
6+
7+
<img src="https://raw.github.com/infrared5/massroute-pi/master/notes/massroutepy_schematic.png" style="width:310px" alt="MassROUTE-Pi schematic">
8+
9+
10+
###Development
11+
12+
```
13+
$> mkvirtualenv massroute
14+
$> pip install -r requirements.txt
15+
```

app/__init__.py

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
def enum(**enums):
2+
return type('Enum', (), enums)

app/board.py

+99
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import random
2+
import logging
3+
import RPi.GPIO as GPIO
4+
5+
from . import enum
6+
from settings import *
7+
from time import sleep
8+
from threading import Timer
9+
10+
from component.shifter import Shifter
11+
from component.modifier.blinker import Blinker
12+
13+
logger = logging.getLogger(__name__)
14+
States = enum(IDLE=0, LIVE=1, ERROR=2)
15+
16+
class Board:
17+
""" Raspberry Pi interface """
18+
shifter = None
19+
error_timer = None
20+
state = States.IDLE
21+
22+
def __init__(self):
23+
GPIO.setmode(GPIO.BCM)
24+
self.shifter = Shifter(DATA_PIN, LATCH_PIN, CLOCK_PIN)
25+
self.shifter.set_shift_register_count(NUM_REGISTERS)
26+
27+
def reset(self):
28+
self.shifter.clear()
29+
self.state = States.IDLE
30+
if not self.error_timer == None:
31+
self.error_timer.cancel()
32+
33+
def run_startup_seq(self):
34+
logger.info('Running startup sequence...')
35+
self.reset()
36+
count = 0
37+
while count < 3:
38+
for index in range(0, NUM_REGISTERS*8):
39+
self.shifter.set_pin(index, 1)
40+
sleep(0.02)
41+
self.shifter.write()
42+
sleep(2)
43+
for index in range(0, NUM_REGISTERS*8):
44+
self.shifter.set_pin(index, 0)
45+
sleep(0.02)
46+
self.shifter.write()
47+
sleep(2)
48+
count = count + 1
49+
logger.info('Done running startup sequence.')
50+
51+
def run_shutdown_seq(self):
52+
logger.info('Running shutdown sequence...')
53+
self.reset()
54+
count = 0
55+
for index in range(0, NUM_REGISTERS*8):
56+
self.shifter.set_pin(index, 1)
57+
sleep(0.02)
58+
self.shifter.write()
59+
while count < 3:
60+
for index in range(0, NUM_REGISTERS*8):
61+
self.shifter.set_pin(index, 0)
62+
self.shifter.write()
63+
sleep(0.1)
64+
for index in range(0, NUM_REGISTERS*8):
65+
self.shifter.set_pin(index, 1)
66+
self.shifter.write()
67+
sleep(0.1)
68+
count = count + 1
69+
sleep(0.5)
70+
self.shifter.clear()
71+
logger.info('Done running shutdown sequence.')
72+
73+
def run_resource_error(self):
74+
logger.info('Running error sequence...')
75+
if not self.is_in_error_state():
76+
pins = range(NUM_REGISTERS*8)
77+
self.reset()
78+
self.state = States.ERROR
79+
self.show_error_sequence(pins)
80+
81+
def show_error_sequence(self, pins):
82+
if self.is_in_error_state():
83+
for pin in pins:
84+
self.shifter.set_pin(pin, 1)
85+
sleep(0.05)
86+
self.shifter.write()
87+
self.shifter.set_pin(pin, 0)
88+
sleep(0.05)
89+
self.shifter.clear()
90+
self.error_timer = Timer(0.5, self.show_error_sequence, [pins])
91+
self.error_timer.start()
92+
93+
def is_in_error_state(self):
94+
return self.state == States.ERROR
95+
96+
def blinker_test(self):
97+
blinker = Blinker(self.shifter, 0.5)
98+
blinker.set_pins([10,11,12,13])
99+
blinker.start()

app/component/__init__.py

Whitespace-only changes.

app/component/led.py

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import json
2+
import logging
3+
4+
from ..util.json_util import convert
5+
6+
logger = logging.getLogger(__name__)
7+
8+
class LED:
9+
10+
stop_id = 0
11+
resolver = None
12+
13+
def __init__(self, stop_id, resolver):
14+
self.stop_id = stop_id
15+
self.resolver = resolver
16+
17+
def data(self, result):
18+
data = convert(json.loads(result))
19+
logger.info("LED:data(result) for stop %r" % self.stop_id)
20+
if 'predictions' in data:
21+
self.resolver.resolve(data['predictions'])
22+
elif 'error' in data:
23+
self.error("Error in getting predictions for %r: %r" % (self.stop_id, data['error']))
24+
else:
25+
self.error('Unkown error occurred.')
26+
27+
def error(self, error):
28+
logger.error("Error for LED %r: %r" % (self.stop_id, error))
29+
self.resolver.error()

app/component/modifier/__init__.py

Whitespace-only changes.

app/component/modifier/blinker.py

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
from threading import Timer
2+
3+
class Blinker:
4+
5+
flag = 0
6+
pins = []
7+
shifter = None
8+
timer = None
9+
active = False
10+
delay = 0.5 # seconds
11+
12+
def __init__(self, shifter, delay=0.5):
13+
self.flag = 0
14+
self.shifter = shifter
15+
self.delay = delay
16+
17+
def set_pins(self, pins):
18+
self.pins = pins
19+
20+
def blink(self):
21+
if self.flag % 2 == 0:
22+
self.shifter.set_pins(self.pins, 1)
23+
else:
24+
self.shifter.set_pins(self.pins, 0)
25+
26+
self.shifter.write()
27+
self.timer = Timer(self.delay, self.blink)
28+
self.timer.start()
29+
self.flag = 0 if self.flag == 1 else 1
30+
31+
def start(self):
32+
if self.active == False:
33+
self.active = True
34+
self.flag = 0
35+
self.blink()
36+
37+
def stop(self):
38+
self.active = False
39+
if not self.timer == None:
40+
self.timer.cancel()
41+
self.shifter.set_pins(self.pins, 0)
42+
self.shifter.write()
43+
44+
class BlinkerPool:
45+
46+
pool = []
47+
48+
def __init__(self):
49+
self.pool = []
50+
51+
def get(self, shifter, delay=0.5):
52+
blinker = Blinker(shifter, delay)
53+
self.pool.append(blinker)
54+
return blinker
55+
56+
def stop_all(self):
57+
for blinker in self.pool:
58+
blinker.stop()
59+
60+
def drain(self):
61+
self.stop_all()
62+
del self.pool[:]
63+
64+
blinker_pool = BlinkerPool()

app/component/resolver/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)