Tracker in eigene Klasse und AppData eingeführt
This commit is contained in:
160
tracker.py
160
tracker.py
@@ -13,12 +13,170 @@ Wiederherstellung der Verbindung übertragen.
|
||||
|
||||
"""
|
||||
|
||||
import os
|
||||
import time
|
||||
import paho.mqtt.client as mqtt
|
||||
import json
|
||||
|
||||
class Tracker():
|
||||
|
||||
def __init__(self, trackertype):
|
||||
def __init__(self, trackertype='NONE'):
|
||||
validtypes = ('HERO', 'SDCARD', 'SERVER', 'NONE')
|
||||
trackertype = trackertype.upper()
|
||||
if trackertype not in validtypes:
|
||||
raise TypeError(f"Invalid tracker type: '{valtype}'. Only supported: {validtypes}")
|
||||
self.ttype = trackertype
|
||||
self.activated = False
|
||||
self.races = set() # Liste der Regatten, eindeutige Namen
|
||||
self.courses = set() # Liste der Bahnen, eindeutige Namen
|
||||
|
||||
self.lat = None # last latitude
|
||||
self.lon = None # last longitude
|
||||
self.tspos = None # timestamp (hh:ss:mm) as datetime.time
|
||||
self.sog = None
|
||||
|
||||
|
||||
def is_active(self):
|
||||
return self.activated
|
||||
|
||||
def set_active(self, newval):
|
||||
self.activated = newval
|
||||
|
||||
def get_position(self):
|
||||
# Positionsabfrage für die Payload
|
||||
# LAT, LON, TSPOS, SOG
|
||||
return (self.lat, self.lon, self.tspos, self.sog)
|
||||
|
||||
def hero_add_race(self, raceid):
|
||||
self.races.add(raceid)
|
||||
|
||||
def hero_set_races(self, newraces):
|
||||
self.races = set(newraces)
|
||||
|
||||
def mqtt_on_connect(self, client, userdata, flags, rc):
|
||||
print(f"MQTT connected with result code {rc}")
|
||||
#userdata['connect_rc'] = rc
|
||||
if rc != 0:
|
||||
# Result codes:
|
||||
# 1: Connection Refused, unacceptable protocol version
|
||||
# 2: Connection Refused, identifier rejected
|
||||
# 3: Connection Refused, Server unavailable
|
||||
# 4: Connection Refused, bad user name or password
|
||||
# 5: Connection Refused, not authorized
|
||||
#userdata['connect_ok'] = True
|
||||
pass
|
||||
else:
|
||||
client.subscribe("regattahero/orgstatus/thomas")
|
||||
client.subscribe("regattahero/racestatus/thomas/#")
|
||||
#userdata['connect_ok'] = False
|
||||
|
||||
def mqtt_on_message(self, client, userdata, msg):
|
||||
"""
|
||||
TODO raceid über userdata? dann topic prüfen?
|
||||
"""
|
||||
if msg.topic == "regattahero/orgstatus/thomas":
|
||||
# kommt alle 10s
|
||||
orgstatus = json.loads(msg.payload)
|
||||
if orgstatus['allLogout']:
|
||||
print("All logout received!")
|
||||
client.disconnect()
|
||||
sys.exit(0) # TODO nur die MQTT-Task beenden
|
||||
if orgstatus['message']:
|
||||
# TODO Alarm-Funktion nutzen?
|
||||
print("Nachricht der Wettfahrtkeitung:")
|
||||
print(orgstatus['message'])
|
||||
print(orgstatus['races'])
|
||||
#for r in orgstatus['races']:
|
||||
# print(f"Race: {r}")
|
||||
elif msg.topic.startswith("regattahero/racestatus/thomas"):
|
||||
# kommt alle 1s
|
||||
# dem Topic angehängt ist noch die raceid
|
||||
payload = json.loads(msg.payload)
|
||||
racestatus = payload['racestatus']
|
||||
"""
|
||||
time: negativ: Zeit vor dem Start, positiv: Zeit nach dem Start
|
||||
in Sekunden
|
||||
|
||||
Signale der Wettfahrtleitung hier anzeigen
|
||||
Regattaabbruch
|
||||
Bahnverkürzung
|
||||
Rückrufe
|
||||
|
||||
"""
|
||||
else:
|
||||
print(f"UNKNOWN TOPIC: {msg.topic}")
|
||||
print(msg.payload)
|
||||
|
||||
def mqtt_publish(self, client, topic, payload, bv_lat, bv_lon, bv_sog):
|
||||
"""
|
||||
Payload vorbelegt als Template, so daß nur noch die veränderlichen
|
||||
GPS-Daten eingefügt werden müssen: LAT LON SOG TIMESTAMP
|
||||
"""
|
||||
lat = bv_lat.getValueRaw()
|
||||
lon = bv_lon.getValueRaw()
|
||||
sog = bv_sog.getValueRaw()
|
||||
if lat and lon and sog:
|
||||
payload['gps']['lat'] = round(lat, 5)
|
||||
payload['gps']['lon'] = round(lon, 5)
|
||||
payload['gps']['speed'] = sog
|
||||
payload['gps']['timestamp'] = time.strftime("%Y-%m-%dT%H:%M:%S.000Z", time.gmtime())
|
||||
|
||||
client.publish(topic, json.dumps(payload))
|
||||
else:
|
||||
print("No GPS data available. Nothing published!")
|
||||
|
||||
def mqtt_tracker(self, cfg, boat, appdata, boatdata):
|
||||
print("MQTT tracker enabled")
|
||||
client = mqtt.Client()
|
||||
client.on_connect = self.mqtt_on_connect
|
||||
client.on_message = self.mqtt_on_message
|
||||
client.username_pw_set(username=cfg['mqtt_user'], password=cfg['mqtt_pass'])
|
||||
try:
|
||||
client.connect(cfg['host'], cfg['port'], 60)
|
||||
except ConnectionRefusedError:
|
||||
print("MQTT connection refused. Check username and password.")
|
||||
return
|
||||
|
||||
tracefile = os.path.join(os.path.expanduser(cfg['logdir']), 'tracker.log')
|
||||
trace_fh = open(tracefile, 'w+')
|
||||
client.user_data_set({'trace': trace_fh})
|
||||
|
||||
topic = "regattahero/tracker/" + cfg['orgname']
|
||||
payload = {
|
||||
"passcode": cfg['passcode'],
|
||||
"orgid": cfg['orgname'],
|
||||
"raceid": "Demo Regatta", # TODO aus Selektion einstellen
|
||||
"gps": {
|
||||
"lat": 0.0,
|
||||
"lon": 0.0,
|
||||
"speed": 0.0,
|
||||
"age": 1000,
|
||||
"odo": 1000,
|
||||
"bat": 1.0,
|
||||
"timestamp": "" # ISO8601 Format mit Millisekunden in UTC
|
||||
},
|
||||
"boat": {
|
||||
"boatid": cfg['uuid'],
|
||||
"sailno": boat['sailno'],
|
||||
"team": boat['team'],
|
||||
"boatclass": boat['class'],
|
||||
"handicap": boat['handicap'],
|
||||
"club": boat['club'],
|
||||
"boatname": boat['name']
|
||||
}
|
||||
}
|
||||
|
||||
# Zugriff auf Boatdata: Referenzen für leichten schnellen Zugriff
|
||||
bv_lat = boatdata.getRef("LAT")
|
||||
bv_lon = boatdata.getRef("LON")
|
||||
bv_sog = boatdata.getRef("SOG")
|
||||
|
||||
client.loop_start()
|
||||
while not appdata.shutdown:
|
||||
time.sleep(1)
|
||||
if appdata.track.is_active():
|
||||
self.mqtt_publish(client, topic, payload, bv_lat, bv_lon, bv_sog)
|
||||
print("MQTT tracker shutdown")
|
||||
client.loop_stop()
|
||||
client.disconnect()
|
||||
trace_fh.close()
|
||||
|
||||
Reference in New Issue
Block a user