Created
April 4, 2013 01:16
-
-
Save compbrain/5306918 to your computer and use it in GitHub Desktop.
alphasign
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from metar.Datatypes import direction | |
import alphasign | |
import socket | |
import threading | |
import time | |
import collections | |
_PR = collections.namedtuple('_PR', | |
['mt', 'tn', 'a', 'b', 'icao', 'c', 'd', 'e', 'f', | |
'g', 'flight', 'altitude', 'speed', 'track', | |
'latitude', 'longitude', 'n', 'o', 'p', | |
'q', 'r', 's']) | |
class Record(object): | |
def __init__(self): | |
self._r = None | |
self._last_update = None | |
self._lock = threading.Lock() | |
@property | |
def r(self): | |
with self._lock: | |
return self._r | |
def Format(self): | |
def red(s): | |
return '%s%s' % (alphasign.colors.RED,s) | |
def green(s): | |
return '%s%s' % (alphasign.colors.GREEN,s) | |
r = self.r | |
if not (r.flight and r.altitude and int(r.altitude)): | |
return | |
msg = (red('Flt ') + green(r.flight.strip()) + red(' at ') + | |
green(r.altitude.strip()) + red('ft')) | |
if r.speed and int(r.speed): | |
msg = '%s [%s' % (msg, green(r.speed.strip())) | |
msg += red(' MPH]') | |
if r.track and int(r.track): | |
msg = '%s heading %s' % (msg, green(direction(int(r.track)).compass())) | |
return msg | |
def __repr__(self): | |
with self._lock: | |
if self._r is None: | |
return object.__repr__(self) | |
else: | |
return 'Record(%s)' % self._r.icao | |
def _DoUpdate(self, new_record): | |
now = time.time() | |
if self._r is None: | |
self._r = new_record | |
else: | |
d = new_record._asdict() | |
for k, v in d.iteritems(): | |
if not v: | |
del d[k] | |
self._r = self._r._replace(**d) | |
def Update(self, new_data): | |
with self._lock: | |
new_record = self.Parse(new_data) | |
self._DoUpdate(new_record) | |
self._last_update = time.time() | |
@property | |
def last_update(self): | |
return int(self._last_update) | |
@property | |
def is_old(self): | |
with self._lock: | |
return (time.time() - self._last_update) > 30 | |
@staticmethod | |
def Parse(new_data): | |
raw = new_data.split(',') | |
if len(raw) != 22: | |
return | |
return _PR(*raw) | |
class Spotter(object): | |
def __init__(self): | |
self._records = collections.defaultdict(Record) | |
self._lock = threading.Lock() | |
def Dump(self): | |
ps = [] | |
with self._lock: | |
ps.extend(self._records.values()) | |
for rec in ps: | |
f = rec.Format() | |
if f: | |
print f | |
def Dumper(self): | |
while True: | |
time.sleep(13) | |
self.Dump() | |
def GetSignUpdate(self, message): | |
ps = [] | |
with self._lock: | |
ps.extend(self._records.values()) | |
ps = reversed(sorted(ps, key=lambda x: x.last_update)) | |
for rec in ps: | |
f = rec.Format() | |
if f: | |
message.data = f | |
return True | |
def SignUpdater(self, sign): | |
last_update = 0 | |
cleared = True | |
message = alphasign.Text('Gooooogle', label='A', mode=alphasign.modes.ROTATE) | |
sign.allocate((message,)) | |
sign.set_run_sequence((message,)) | |
sign.write(message) | |
lastdata = message.data | |
while True: | |
if ((time.time() - last_update) > 10) and self.GetSignUpdate(message): | |
last_update = time.time() | |
if message.data != lastdata: | |
cleared = False | |
sign.write(message) | |
lastdata = message.data | |
elif (time.time() - last_update) > 90 and not cleared: | |
print 'Clearing stale sign' | |
cleared = True | |
message.data = '' | |
sign.write(message) | |
time.sleep(5) | |
def Vacuum(self): | |
with self._lock: | |
d_count = 0 | |
to_remove = [] | |
for k, v in self._records.iteritems(): | |
if v.is_old: | |
to_remove.append(k) | |
for k in to_remove: | |
d_count += 1 | |
del self._records[k] | |
print 'Removed %d records' % d_count | |
def Vacuumer(self): | |
while True: | |
time.sleep(60) | |
self.Vacuum() | |
def __len__(self): | |
with self._lock: | |
return len(self._records) | |
def Update(self, r): | |
pr = Record.Parse(r) | |
if pr: | |
record = self._records[pr.icao] | |
record.Update(r) | |
return record | |
def client(spotter): | |
HOST, PORT = 'localhost', 30003 | |
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
sock.connect((HOST, PORT)) | |
buf = '' | |
while True: | |
r = sock.recv(1024) | |
buf += r | |
if '\n' in buf: | |
msg, buf = buf.split('\n', 1) | |
record = spotter.Update(r) | |
def main(): | |
s = Spotter() | |
sign = alphasign.Serial() | |
sign.connect() | |
sign.clear_memory() | |
t = threading.Thread(group=None, target=client, args=(s,)) | |
v = threading.Thread(group=None, target=s.Vacuumer) | |
d = threading.Thread(group=None, target=s.Dumper) | |
su = threading.Thread(group=None, target=s.SignUpdater, args=(sign,)) | |
t.start() | |
v.start() | |
#d.start() | |
su.start() | |
while True: | |
time.sleep(1) | |
print 'Have %d records' % len(s) | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment