-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathstationservice.py
executable file
·129 lines (110 loc) · 3.82 KB
/
stationservice.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#! /usr/bin/python
import aprslib
import json
import logging
import re
import sys
from threading import Thread
import time
import yaml
from flask import Flask
from flask_cors import CORS
from flask_restful import Api, Resource, reqparse
_stationList = {}
class Station(Resource):
def get(self, callsign):
global _stationList
print('GET ' + callsign)
if callsign in _stationList:
return _stationList[callsign], 200
else:
return 'callsign not cached', 404
def post(self, name):
return 'operation not supported', 403
def put(self, name):
return 'operation not supported', 403
def delete(self, name):
return 'operation not supported', 403
_startTime = time.clock()
_bytesRead = 0
_highwaterDelta = 1000000
_highwater = _highwaterDelta
def handlePacket(raw):
global _stationList
global _startTime
global _bytesRead
global _highwater
global _highwaterDelta
if raw is None: return
packet = aprslib.parse(raw)
if packet is None: return
m = re.match(stationsToMatch, packet['from'])
if m != None:
packet['timestamp'] = time.time()
packet['result'] = 'OK'
if packet['from'] in _stationList:
_stationList[packet['from']].update(packet)
if 'message_text' not in packet and 'message_text' in _stationList[packet['from']]:
del _stationList[packet['from']]['message_text']
else:
_stationList[packet['from']] = packet
# print('- heard ' + packet['from'])
# Record how many bytes we've read...
_bytesRead = _bytesRead + len(raw)
# And checkpoint it to the log occasionally.
if _bytesRead > _highwater:
_highwater = _bytesRead + _highwaterDelta
elapsed = time.clock() - _startTime;
hours, rem = divmod(elapsed, 3600)
minutes, seconds = divmod(rem, 60)
print("- elapsed {:0>2}:{:0>2}:{:05.2f} read {}".format(int(hours),int(minutes),seconds,_bytesRead))
# If we're going to overflow, reset the counter and elapsed timer.
if sys.maxsize - _bytesRead < _highwaterDelta:
_bytesRead = 0
_highwater = highwater_delta
_startTime = time.clock()
def runAprsMonitor():
while True:
try:
if password is not None:
AIS = aprslib.IS(login, passwd = password)
else:
AIS = aprslib.IS(login)
print('- Connecting to APRS-IS...')
AIS.connect()
print('- Connected! Handling incoming packets.')
AIS.consumer(handlePacket, raw=True)
except Exception as e:
print(e);
print('- APRS server socket failure... reconnecting in 2 seconds')
time.sleep(2)
# Read configuration
configFile = open("config.yaml")
config = yaml.load(configFile, Loader=yaml.FullLoader)
if not 'stations' in config or len(config['stations']) == 0:
sys.exit("pyaprs-stationservice: must specify at least one callsign in configuration.");
if 'login' in config:
login = config['login']
else:
login = 'N0CALL'
if 'password' in config:
password = config['password']
else:
password = None
# Convert station list to regular expression and compile.
stationExpression = ''
for station in config['stations']:
stationExpression = stationExpression + station + '|'
stationExpression = stationExpression[:-1]
stationsToMatch = re.compile(stationExpression, re.I)
# logging.basicConfig(level=logging.DEBUG)
# Start the server to monitor the APRS feed.
serverMonitorThread = Thread(target=runAprsMonitor)
serverMonitorThread.start()
# Start the REST server
app = Flask(__name__)
CORS(app)
api = Api(app)
api.add_resource(Station, '/callsign/<string:callsign>')
if __name__ == '__main__':
app.run()