Skip to content

Instantly share code, notes, and snippets.

@compbrain
Created April 4, 2013 01:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save compbrain/5306918 to your computer and use it in GitHub Desktop.
Save compbrain/5306918 to your computer and use it in GitHub Desktop.
alphasign
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