NMEA0183 Empfangscode in entsprechendes Modul verlagert

This commit is contained in:
Thomas Hooge 2025-09-13 07:55:56 +02:00
parent 612783454e
commit 5b000f4f1f
5 changed files with 106 additions and 53 deletions

8
TODO
View File

@ -1,9 +1,11 @@
Aufgaben, Planungs- und Ideenliste Aufgaben, Planungs- und Ideenliste
- Tracker - Tracker
Regatta Hero a) Regatta Hero
python3-paho-mqtt benötigt python3-paho-mqtt benötigt
b) lokal
c) Server
- Satelliten: SatelliteList verwenden und dieses auch in - Satelliten: SatelliteList verwenden und dieses auch in
nmea2000 implementieren nmea2000 implementieren
- Satellitenübersicht / SkyView - Satellitenübersicht / SkyView

View File

@ -7,6 +7,50 @@ TODO Multi-Sentence verarbeiten
AIS-Sentences mit Binärdaten 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): def DBS(boatdata, msg):
# Wassertiefe unter der Oberfläche # Wassertiefe unter der Oberfläche
pass pass

View File

@ -108,8 +108,8 @@ import struct
import uuid import uuid
import json import json
import nmea0183
from appdata import AppData from appdata import AppData
import nmea0183
import pages import pages
__author__ = "Thomas Hooge" __author__ = "Thomas Hooge"
@ -118,6 +118,7 @@ __version__ = "0.2"
__email__ = "thomas@hoogi.de" __email__ = "thomas@hoogi.de"
__status__ = "Development" __status__ = "Development"
# Standardkonfiguration, kann durch Konfigdatei überschrieben werden
cfg = { cfg = {
'cfgfile': 'obp60v.conf', 'cfgfile': 'obp60v.conf',
'logdir': '~/.local/share/obp60v', 'logdir': '~/.local/share/obp60v',
@ -205,46 +206,6 @@ def rxd_n2k(device):
pass pass
bus.shutdown() 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): def rxd_gps(devname, devspeed):
# Prüfe ob GPS-Port vorhanden ist und sich öffnen läßt # Prüfe ob GPS-Port vorhanden ist und sich öffnen läßt
try: try:
@ -789,7 +750,7 @@ if __name__ == "__main__":
t_rxd_n2k.start() t_rxd_n2k.start()
if cfg['nmea0183']: if cfg['nmea0183']:
print("NMEA0183 enabled, library version {}".format(pynmea2.version)) 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() t_rxd_0183.start()
if cfg['gps']: if cfg['gps']:
print("GPS enabled (local)") print("GPS enabled (local)")

View File

@ -23,11 +23,15 @@ class Tracker(Page):
self.bv_sog = boatdata.getRef("SOG") self.bv_sog = boatdata.getRef("SOG")
self.buttonlabel[1] = 'MODE' self.buttonlabel[1] = 'MODE'
self.buttonlabel[2] = 'ON' self.buttonlabel[2] = 'ON'
self.mode = 'N' # (N)ormal, (C)onfiguration
def handle_key(self, buttonid): def handle_key(self, buttonid):
if buttonid == 1: if buttonid == 1:
# Modus umschalten
pass if self.mode == 'N':
self.mode = 'C'
else:
self.mode = 'N'
elif buttonid == 2: elif buttonid == 2:
# Tracking ein/-ausschalten # Tracking ein/-ausschalten
if self._appdata.track.is_active(): if self._appdata.track.is_active():
@ -37,7 +41,7 @@ class Tracker(Page):
self._appdata.track.set_active(True) self._appdata.track.set_active(True)
self.buttonlabel[2] = 'OFF' self.buttonlabel[2] = 'OFF'
def draw(self, ctx): def draw_normal(self, ctx):
# Name # Name
ctx.select_font_face("Ubuntu", cairo.FontSlant.NORMAL, cairo.FontWeight.BOLD) ctx.select_font_face("Ubuntu", cairo.FontSlant.NORMAL, cairo.FontWeight.BOLD)
ctx.set_font_size(32) ctx.set_font_size(32)
@ -66,11 +70,32 @@ class Tracker(Page):
ctx.show_text("Sog=") ctx.show_text("Sog=")
ctx.show_text(self.bv_sog.format()) ctx.show_text(self.bv_sog.format())
# Mögliche Regatten # Ausgewählte Regatta (raceid)
x = 250 x = 250
y = 160 y = 100
ctx.move_to(x, y - 24) 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(): for r in self._appdata.track.hero_get_races():
ctx.move_to(x, y) ctx.move_to(x, y)
ctx.show_text(r) ctx.show_text(r)
@ -78,4 +103,15 @@ class Tracker(Page):
if y == 160: if y == 160:
ctx.move_to(x, y) ctx.move_to(x, y)
ctx.show_text("keine") 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)

View File

@ -4,7 +4,8 @@ Tracker-Daten
Mögliche Typen: Mögliche Typen:
HERO - Regatta Hero HERO - Regatta Hero
SDCARD SDCARD
SERVER LOCAL
SERVER - spezielle Software benötigt, kann auch ein Raspi an Bord sein
NONE - kein Tracking NONE - kein Tracking
Wenn die Verbindung zum Server im Internet nicht funktioniert, werden Wenn die Verbindung zum Server im Internet nicht funktioniert, werden
@ -45,6 +46,15 @@ class Tracker():
self.hero_orgstatus = None self.hero_orgstatus = None
self.hero_racestatus = None # Akluelle Regatta 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): def is_server_active(self, hostname, port):
""" """
ohne Netzwerkverbindung wirft socket.gethostbyname eine Exception, ohne Netzwerkverbindung wirft socket.gethostbyname eine Exception,