From e738438a948c81d8aebbb89da60d162323ed462a Mon Sep 17 00:00:00 2001 From: Thomas Hooge Date: Wed, 10 Sep 2025 20:04:31 +0200 Subject: [PATCH] Tracker und MQTT code --- obp60v.conf-sample | 9 ++++++ obp60v.py | 80 ++++++++++++++++++++++++++++++++++++++++++++-- pages/tracker.py | 15 +++++++++ 3 files changed, 102 insertions(+), 2 deletions(-) create mode 100644 pages/tracker.py diff --git a/obp60v.conf-sample b/obp60v.conf-sample index 3d22ede..aa97eb7 100644 --- a/obp60v.conf-sample +++ b/obp60v.conf-sample @@ -37,6 +37,15 @@ port = /dev/ttyACM0 navobj = ~/.opencpn/navobj.xml config = ~/.opencpn/opencpn.conf +[tracker] +type = NONE +host = 127.0.0.1 +port = 1883 +mqtt_user = demo +mqtt_pass = 123456 +orgname = demo +passcode = 123456 + [settings] timezone = 1 boat_draft = 1.3 diff --git a/obp60v.py b/obp60v.py index 515b9cc..d5a033a 100755 --- a/obp60v.py +++ b/obp60v.py @@ -107,6 +107,8 @@ from nmea2000 import parser import nmea0183 import pages import struct +import uuid +import json __author__ = "Thomas Hooge" __copyright__ = "Copyleft 2024-2025, all rights reversed" @@ -123,9 +125,58 @@ cfg = { 'devclass': 120, # Display 'industrygroup': 4, # Marine 'gps': False, - 'bme280': False + 'bme280': False, + 'tracker': { 'type': 'NONE' } } +def mqtt_on_connect(client, userdata, flags, rc): + print(f"MQTT connected with result code {rc}") + client.subscribe("regattahero/orgstatus/thomas") + #client.subscribe(topic_racestatus) + +def mqtt_on_message(client, userdata, msg): + """ + TODO raceid über userdata? dann topic prüfen? + """ + if msg.topic == "regattahero/orgstatus/thomas": + orgstatus = json.loads(msg.payload) + if orgstatus['allLogout']: + print("All logout received!") + client.disconnect() + sys.exit(0) + if orgstatus['message']: + # TODO Alarm-Funktion nutzen? + print("Nachricht der Wettfahrtkeitung:") + print(orgstatus['message']) + #for r in orgstatus['races']: + # print(f"Race: {r}") + elif msg.topic.startswith("regattahero/racestatus/thomas"): + racestatus = json.loads(msg.payload) + print(racestatus) + else: + print(f"UNKNOWN TOPIC: {msg.topic}") + print(msg.payload) + +def mqtt_tracker(cfg): + import paho.mqtt.client as mqtt + print("MQTT tracker enabled") + print(cfg) + client = mqtt.Client() + client.on_connect = mqtt_on_connect + client.on_message = 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 + client.loop_start() + while not shutdown: + time.sleep(1) + #TODO publish here + client.loop_stop() + client.disconnect() + def rxd_n2k(device): setthreadtitle("N2Klistener") bus = can.Bus(interface='socketcan', channel=device, bitrate=250000); @@ -685,7 +736,8 @@ if __name__ == "__main__": # Basiskonfiguration aus Datei lesen config = configparser.ConfigParser() - ret = config.read(os.path.join(sys.path[0], cfg['cfgfile'])) + config_path = os.path.join(sys.path[0], cfg['cfgfile']) + ret = config.read(config_path) if len(ret) == 0: print("Konfigurationsdatei '{}' konnte nicht gelesen werden!".format(cfg['cfgfile'])) sys.exit(1) @@ -730,6 +782,27 @@ if __name__ == "__main__": history = History("press", 75) boatdata.addHistory(history, "press") + # Tracker data + cfg['tracker']['type'] = config.get('tracker', 'type') + cfg['tracker']['host'] = config.get('tracker', 'host') + cfg['tracker']['port'] = config.getint('tracker', 'port') + cfg['tracker']['mqtt_user'] = config.get('tracker', 'mqtt_user') + cfg['tracker']['mqtt_pass'] = config.get('tracker', 'mqtt_pass') + cfg['tracker']['orgname'] = config.get('tracker', 'orgname') + cfg['tracker']['passcode'] = config.get('tracker', 'passcode') + + # Client UUID. Automatisch erzeugen wenn noch nicht vorhanden + create_uuid = False + try: + cfg['tracker']['uuid'] = config.get('tracker', 'uuid') + except configparser.NoOptionError: + create_uuid = True + if create_uuid or (len(cfg['tracker']['uuid']) != 36): + cfg['tracker']['uuid'] = str(uuid.uuid4()) + config.set('tracker', 'uuid', cfg['tracker']['uuid']) + with open(config_path, 'w') as fh: + config.write(fh) + if cfg['simulation']: boatdata.enableSimulation() @@ -757,6 +830,9 @@ if __name__ == "__main__": print("Networking enabled") t_rxd_net = threading.Thread(target=rxd_network, args=(cfg['net_port'],cfg['net_addr'])) t_rxd_net.start() + if cfg['tracker']['type'] != 'NONE': + t_tracker = threading.Thread(target=mqtt_tracker, args=(cfg['tracker'],)) + t_tracker.start() if not cfg['simulation']: if cfg['bme280']: t_data = threading.Thread(target=datareader, args=(cfg, history)) diff --git a/pages/tracker.py b/pages/tracker.py new file mode 100644 index 0000000..b9c3e9a --- /dev/null +++ b/pages/tracker.py @@ -0,0 +1,15 @@ +import cairo +from .page import Page + +class Tracker(Page): + + def __init__(self, pageno, cfg, boatdata): + super().__init__(pageno, cfg, boatdata) + + def draw(self, ctx): + # Name + ctx.select_font_face("Ubuntu", cairo.FontSlant.NORMAL, cairo.FontWeight.BOLD) + ctx.set_font_size(60) + ctx.move_to(20, 100) + ctx.show_text("Tracker") +