""" Tracker-Daten Mögliche Typen: HERO - Regatta Hero SDCARD SERVER NONE - kein Tracking Wenn die Verbindung zum Server im Internet nicht funktioniert, werden die Positionen in eine Warteschlange gesichert und nach Wiederherstellung der Verbindung übertragen. """ import os import time import paho.mqtt.client as mqtt import json class Tracker(): 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.trace = False # Debugging self.trace_fh = None # File Handle der Tracedatei 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 self.trace: self.trace_fh.write(msg.topic) self.trace_fh.write("\n") self.trace_fh.write(msg.payload.decode()) self.trace_fh.write("\n\n") self.trace_fh.flush() 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") self.trace = cfg['trace'] 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 if cfg['trace']: # TODO Log Hinweis tracefile = os.path.join(os.path.expanduser(cfg['logdir']), 'tracker.log') self.trace_fh = open(tracefile, 'w+') 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) client.loop_stop() client.disconnect() if cfg['trace']: self.trace_fh.close()