aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias P. Braendli <matthias.braendli@mpb.li>2020-04-28 22:06:51 +0200
committerMatthias P. Braendli <matthias.braendli@mpb.li>2020-04-28 22:06:51 +0200
commit5008d0e9398edf4311d826d41e28e96cdb992cee (patch)
tree666ca665838eec38aacf4aca001d2bbd78a31ee3
parent8df2849a482ef356584bcddf34e8e78fbe040ea1 (diff)
downloadglutte-serial-web-5008d0e9398edf4311d826d41e28e96cdb992cee.tar.gz
glutte-serial-web-5008d0e9398edf4311d826d41e28e96cdb992cee.tar.bz2
glutte-serial-web-5008d0e9398edf4311d826d41e28e96cdb992cee.zip
Add message parser and /stats endpoint
-rwxr-xr-xglutte_serial_web.py23
-rw-r--r--serialrx.py99
2 files changed, 112 insertions, 10 deletions
diff --git a/glutte_serial_web.py b/glutte_serial_web.py
index 4390f76..b5552dc 100755
--- a/glutte_serial_web.py
+++ b/glutte_serial_web.py
@@ -2,7 +2,7 @@
#
# The MIT License (MIT)
#
-# Copyright (c) 2016 Matthias P. Braendli, Maximilien Cuony
+# Copyright (c) 2020 Matthias P. Braendli, Maximilien Cuony
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -22,10 +22,11 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
+import time
from geventwebsocket.handler import WebSocketHandler
from gevent import pywsgi, Timeout
from time import sleep
-from flask import Flask, render_template
+from flask import Flask, render_template, jsonify
from flask_sockets import Sockets
import serialrx
import adsl
@@ -36,17 +37,29 @@ sockets = Sockets(app)
ser = serialrx.SerialRX()
adsl = adsl.ADSL(ser)
-
@app.route('/')
def index():
return render_template('index.html', last_lines=ser.get_last_lines())
+@sockets.route('/stats')
+def stats():
+ t_now = time.time()
+ values = ser.get_parsed_values()
+
+ out_json = {}
+
+ for k in values:
+ value, ts = values[k]
+ if ts + 60 < t_now:
+ out_json[k] = None
+ else:
+ out_json[k] = value
+
+ return jsonify(out_json)
@sockets.route('/stream')
def stream(socket):
-
try:
-
queue = ser.register_client()
error = False
diff --git a/serialrx.py b/serialrx.py
index 19a123c..4c3eac5 100644
--- a/serialrx.py
+++ b/serialrx.py
@@ -25,15 +25,65 @@
import serial
import threading
import collections
+import re
+import time
import config
+flags = re.ASCII
+re_cc_capa = re.compile(r"\[\d+\] CC: CAPA,\d+,(\d+)", flags)
+re_cc_vbat_plus = re.compile(r"\[\d+\] CC: VBAT\+,\d+,(\d+)", flags)
+re_num_sv = re.compile(r"\[\d+\] T_GPS.+ (\d+) SV tracked", flags)
+re_alim = re.compile(r"\[\d+\] ALIM (\d+) mV", flags)
-class SerialRX(threading.Thread):
+class MessageParser:
+ def __init__(self):
+ self._lock = threading.Lock()
+
+ self._last_cc_capa = 0
+ self._last_cc_capa_time = 0
+ self._last_vbat_plus = 0
+ self._last_vbat_plus_time = 0
+ self._last_num_sv = 0
+ self._last_num_sv_time = 0
+ self._last_alim = 0
+ self._last_alim_time = 0
+
+ def parse_message(self, message):
+ with self._lock:
+ match = re_cc_capa.search(message)
+ if match:
+ self._last_cc_capa = int(match.group(1))
+ self._last_cc_capa_time = time.time()
+
+ match = re_cc_vbat_plus.search(message)
+ if match:
+ self._last_vbat_plus = int(match.group(1))
+ self._last_vbat_plus_time = time.time()
+
+ match = re_num_sv.search(message)
+ if match:
+ self._last_num_sv = int(match.group(1))
+ self._last_num_sv_time = time.time()
+
+ match = re_alim.search(message)
+ if match:
+ self._last_alim = int(match.group(1))
+ self._last_alim_time = time.time()
+
+ def get_last_data(self):
+ with self._lock:
+ return {"capa": (self._last_cc_capa, self._last_cc_capa_time),
+ "vbat_plus": (self._last_vbat_plus, self._last_vbat_plus_time),
+ "alim": (self._last_alim, self._last_alim_time),
+ "num_sv": (self._last_num_sv, self._last_num_sv_time) }
+class SerialRX(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
+ self._parser = MessageParser()
+
print("Open Serial on {} at {}".format(config.SERIALPORT, config.BAUDRATE))
self.ser = serial.Serial(config.SERIALPORT, baudrate=config.BAUDRATE)
@@ -47,6 +97,9 @@ class SerialRX(threading.Thread):
print("Serial port ready")
+ def get_parsed_values(self):
+ return self._parser.get_last_data()
+
def run(self):
print("Serial port starting reception")
while not self.event_stop.is_set():
@@ -54,20 +107,20 @@ class SerialRX(threading.Thread):
self.line_accumulator.append(databyte)
if databyte == "\n":
+ line = "".join(self.line_accumulator)
+ self._parser.parse_message(line)
self.data_lock.acquire()
try:
-
for queue in self.clients:
- queue.append("".join(self.line_accumulator))
+ queue.append(line)
if len(queue) > config.LINES_TO_KEEP:
queue.popleft()
- self.last_lines.append("".join(self.line_accumulator))
+ self.last_lines.append(line)
if len(self.last_lines) > config.LAST_LINE_TO_KEEP:
self.last_lines.pop(0)
-
except:
raise
finally:
@@ -101,3 +154,39 @@ class SerialRX(threading.Thread):
raise
finally:
self.data_lock.release()
+
+if __name__ == "__main__":
+ test_set = """[193583144] CW: K
+ [193583168] In cw_done change 0 0
+ [193584056] FSM: FSM_ECOUTE
+ [193585992] In SQ 1
+ [193586008] FSM: FSM_QSO
+ [193592816] CC: CAPA,148111,1632707
+ [193605944] CC: CAPA,148121,1632682
+ [193605944] CC: VBAT+,148121,12340
+ [193605944] CC: VBAT-,148121,0
+ [193612144] ALIM 11811 mV
+ [193672600] T_GPS 2020-04-28 19:07:30 12 SV tracked
+ [193672656] TIME 2020-04-28 21:07:30 [GPS]
+ [193692528] TEMP invalid
+ """
+ test_should = { "capa": 1632682, "vbat_plus": 12340, "alim": 11811, "num_sv": 12 }
+
+ mp = MessageParser()
+
+ print("Testing parser")
+ for message in test_set.split("\n"):
+ print(f"Parse {message}")
+ mp.parse_message(message)
+
+ test_measured = mp.get_last_data()
+
+ for k in test_measured:
+ if test_measured[k][1] == 0:
+ print(f"Value {k} has time 0")
+
+ values = {k: test_measured[k][0] for k in test_measured}
+ if values != test_should:
+ print("invalid values {}".format(values))
+
+ print("Test end")