From 5b000f4f1f1952d6a73c8bfdf345fb2bb3852612 Mon Sep 17 00:00:00 2001 From: Thomas Hooge Date: Sat, 13 Sep 2025 07:55:56 +0200 Subject: [PATCH] NMEA0183 Empfangscode in entsprechendes Modul verlagert --- TODO | 8 +++++--- nmea0183.py | 44 ++++++++++++++++++++++++++++++++++++++++++ obp60v.py | 45 +++---------------------------------------- pages/tracker.py | 50 +++++++++++++++++++++++++++++++++++++++++------- tracker.py | 12 +++++++++++- 5 files changed, 106 insertions(+), 53 deletions(-) diff --git a/TODO b/TODO index 6de56cc..3b5c2d4 100644 --- a/TODO +++ b/TODO @@ -1,9 +1,11 @@ Aufgaben, Planungs- und Ideenliste - Tracker - Regatta Hero - python3-paho-mqtt benötigt - + a) Regatta Hero + python3-paho-mqtt benötigt + b) lokal + c) Server + - Satelliten: SatelliteList verwenden und dieses auch in nmea2000 implementieren - Satellitenübersicht / SkyView diff --git a/nmea0183.py b/nmea0183.py index 42d2168..4914847 100644 --- a/nmea0183.py +++ b/nmea0183.py @@ -7,6 +7,50 @@ TODO Multi-Sentence verarbeiten AIS-Sentences mit Binärdaten """ +import serial +from setproctitle import setthreadtitle + +# Empfangsthread +def rxd_0183(appdata, devname): + # Prüfe ob NMEA0183-Port vorhanden ist und sich öffnen läßt + try: + ser = serial.Serial(devname, 115200, timeout=3) + except serial.SerialException as e: + print("NMEA0183 serial port not available") + return + setthreadtitle("0183listener") + while not appdata.shutdown: + raw = ser.readline().decode('ascii') + if len(raw.strip()) == 0: + continue + try: + msg = pynmea2.parse(raw) + except pynmea2.nmea.ParseError: + print(f"NMEA0183: Parse-Error: {raw}", end='') + continue + # sentence_type kann fehlen + try: + stype = msg.sentence_type + except: + print(f"NMEA0183: Sentence type missing: {raw}") + continue + # WIP Neuer Code aus Modul + # TODO Filter mit gewünschen Satztypen + # if stype in stypefilter: + # continue + if stype in decoder: + decoder[stype](boatdata, msg) + else: + # Hier unbekannter Satztyp: protokollieren und ignorieren + """ + ['checksum', 'data', 'fields', 'identifier', 'name_to_idx', 'parse', + 'proprietary_re', 'query_re', 'render', 'sentence_re', + 'sentence_type', 'sentence_types', 'talker', 'talker_re'] + """ + print(f"Nicht implementiert: '{stype}' from {msg.talker}") + + ser.close() + def DBS(boatdata, msg): # Wassertiefe unter der Oberfläche pass diff --git a/obp60v.py b/obp60v.py index 5af1357..e627dfd 100755 --- a/obp60v.py +++ b/obp60v.py @@ -108,8 +108,8 @@ import struct import uuid import json -import nmea0183 from appdata import AppData +import nmea0183 import pages __author__ = "Thomas Hooge" @@ -118,6 +118,7 @@ __version__ = "0.2" __email__ = "thomas@hoogi.de" __status__ = "Development" +# Standardkonfiguration, kann durch Konfigdatei überschrieben werden cfg = { 'cfgfile': 'obp60v.conf', 'logdir': '~/.local/share/obp60v', @@ -205,46 +206,6 @@ def rxd_n2k(device): pass bus.shutdown() -def rxd_0183(devname): - # Prüfe ob NMEA0183-Port vorhanden ist und sich öffnen läßt - try: - ser = serial.Serial(devname, 115200, timeout=3) - except serial.SerialException as e: - print("NMEA0183 serial port not available") - return - setthreadtitle("0183listener") - while not appdata.shutdown: - raw = ser.readline().decode('ascii') - if len(raw.strip()) == 0: - continue - try: - msg = pynmea2.parse(raw) - except pynmea2.nmea.ParseError: - print(f"NMEA0183: Parse-Error: {raw}", end='') - continue - # sentence_type kann fehlen - try: - stype = msg.sentence_type - except: - print(f"NMEA0183: Sentence type missing: {raw}") - continue - # WIP Neuer Code aus Modul - # TODO Filter mit gewünschen Satztypen - # if stype in stypefilter: - # continue - if stype in nmea0183.decoder: - nmea0183.decoder[stype](boatdata, msg) - else: - # Hier unbekannter Satztyp: protokollieren und ignorieren - """ - ['checksum', 'data', 'fields', 'identifier', 'name_to_idx', 'parse', - 'proprietary_re', 'query_re', 'render', 'sentence_re', - 'sentence_type', 'sentence_types', 'talker', 'talker_re'] - """ - print(f"Nicht implementiert: '{stype}' from {msg.talker}") - - ser.close() - def rxd_gps(devname, devspeed): # Prüfe ob GPS-Port vorhanden ist und sich öffnen läßt try: @@ -789,7 +750,7 @@ if __name__ == "__main__": t_rxd_n2k.start() if cfg['nmea0183']: print("NMEA0183 enabled, library version {}".format(pynmea2.version)) - t_rxd_0183 = threading.Thread(target=rxd_0183, args=(cfg['0183_port'],)) + t_rxd_0183 = threading.Thread(target=nmea0183.rxd_0183, args=(appdata,cfg['0183_port'],)) t_rxd_0183.start() if cfg['gps']: print("GPS enabled (local)") diff --git a/pages/tracker.py b/pages/tracker.py index 8ee718d..96b5953 100644 --- a/pages/tracker.py +++ b/pages/tracker.py @@ -23,11 +23,15 @@ class Tracker(Page): self.bv_sog = boatdata.getRef("SOG") self.buttonlabel[1] = 'MODE' self.buttonlabel[2] = 'ON' + self.mode = 'N' # (N)ormal, (C)onfiguration def handle_key(self, buttonid): if buttonid == 1: - - pass + # Modus umschalten + if self.mode == 'N': + self.mode = 'C' + else: + self.mode = 'N' elif buttonid == 2: # Tracking ein/-ausschalten if self._appdata.track.is_active(): @@ -37,7 +41,7 @@ class Tracker(Page): self._appdata.track.set_active(True) self.buttonlabel[2] = 'OFF' - def draw(self, ctx): + def draw_normal(self, ctx): # Name ctx.select_font_face("Ubuntu", cairo.FontSlant.NORMAL, cairo.FontWeight.BOLD) ctx.set_font_size(32) @@ -66,11 +70,32 @@ class Tracker(Page): ctx.show_text("Sog=") ctx.show_text(self.bv_sog.format()) - # Mögliche Regatten + # Ausgewählte Regatta (raceid) x = 250 - y = 160 + y = 100 ctx.move_to(x, y - 24) - ctx.show_text("Regatten") + ctx.show_text("Regatta: ") + # if ... + # else + # "not selected" + + def draw_config(self, ctx): + ctx.select_font_face("Ubuntu", cairo.FontSlant.NORMAL, cairo.FontWeight.BOLD) + ctx.set_font_size(32) + ctx.move_to(20, 80) + ctx.show_text("Tracker config") + # Daten aus Konfiguration anzeigen + # - boot + # - tracker + + ctx.set_font_size(16) + + # Mögliche Regatten + # -> auf Konfigurationsmodus verschieben + x = 250 + y = 100 + ctx.move_to(x, y - 24) + ctx.show_text("Regattas") for r in self._appdata.track.hero_get_races(): ctx.move_to(x, y) ctx.show_text(r) @@ -78,4 +103,15 @@ class Tracker(Page): if y == 160: ctx.move_to(x, y) ctx.show_text("keine") - + + + + ctx.move_to(20, 120) + ctx.show_text("Type: ") + ctx.show_text(self._appdata.track.ttype) + + def draw(self, ctx): + if self.mode == 'N': + self.draw_normal(ctx) + else: + self.draw_config(ctx) diff --git a/tracker.py b/tracker.py index 8c55a5e..d594d89 100644 --- a/tracker.py +++ b/tracker.py @@ -4,7 +4,8 @@ Tracker-Daten Mögliche Typen: HERO - Regatta Hero SDCARD - SERVER + LOCAL + SERVER - spezielle Software benötigt, kann auch ein Raspi an Bord sein NONE - kein Tracking Wenn die Verbindung zum Server im Internet nicht funktioniert, werden @@ -45,6 +46,15 @@ class Tracker(): self.hero_orgstatus = None self.hero_racestatus = None # Akluelle Regatta + # TODO Wirklich alles im Tracker oder ist einiges generisch? + self.boatid = None + self.sailno = None + self.boatname = None + self.boatclass = None + self.handicap = None + self.club = None + self.team = None + def is_server_active(self, hostname, port): """ ohne Netzwerkverbindung wirft socket.gethostbyname eine Exception,