NMEA0183 in eigenes Modul ausgelagert

This commit is contained in:
Thomas Hooge 2025-07-12 07:26:32 +02:00
parent b1fdb592b0
commit df04c9ad8e
4 changed files with 102 additions and 27 deletions

3
TODO
View File

@ -1,5 +1,8 @@
Aufgaben- und Planungs- und Ideenliste Aufgaben- und Planungs- und Ideenliste
- datareader für mehrere I²C-Sensoren. History muß entsprechend
eine Liste sein.
- Barograph - Barograph
- Ankeralarm - Ankeralarm

69
nmea0183.py Normal file
View File

@ -0,0 +1,69 @@
"""
NMEA0183 verarbeiten
"""
def DBS(boatdata, msg):
# Wassertiefe unter der Oberfläche
pass
def DBT(boatdata, msg):
# Wassertiefe unter Geber
pass
def GLL(boatdata, msg):
print("-> GLL")
boatdata.setValue("LAT", msg.latitude)
boatdata.setValue("LON", msg.longitude)
def HDT(boatdata, msg):
# Heading True
print("-> HDT")
print(msg.fields)
def MWV(boatdata, msg):
# Windgeschwindigkeit und -winkel
print(f"Wind: {msg.wind_angle}° {msg.wind_speed}kt")
boatdata.setValue("AWA", msg.wind_angle)
boatdata.setValue("AWS", msg.wind_speed)
def RSA(boatdata, msg):
# Rudder Sensor Angle
# negative Werte bedeuten Backbord
# Boatdata: RPOS primär, PRPOS sekundär
print("-> RSA")
print(msg.fields)
def RTE(boatdata, msg):
# Route
print("-> RTE")
print(msg.fields)
def VHW(boatdata, msg):
boatdata.setValue("STW", float(msg.water_speed_knots))
def VTG(boatdata, msg):
boatdata.setValue("COG", int(msg.true_track))
#TODO klären was für Typen hier ankommen können
# bytearray, str, decimal.Decimal?
sog = float(msg.spd_over_grnd_kts)
#str von OpenCPN: sog = float(msg.spd_over_grnd_kts[:-1])
boatdata.setValue("SOG", sog)
def WPL(boatdata, msg):
print("-> WPL")
print(msg.fields)
# Aus Performancegründen eine direkte Sprungtabelle, ggf. können
# zukünftig außer der Funktion noch weitere Daten gespeichert werdeb
decoder = {
"DBS": DBS,
"DBT": DBT,
"GLL": GLL,
"MWV": MWV,
"RSA": RSA,
"RTE": RTE,
"VHW": VHW,
"VTG": VTG,
"WPL": WPL
}

View File

@ -102,6 +102,7 @@ import time
from datetime import datetime from datetime import datetime
from nmea2000 import Device, BoatData, History, HistoryBuffer from nmea2000 import Device, BoatData, History, HistoryBuffer
from nmea2000 import parser from nmea2000 import parser
import nmea0183
import pages import pages
import struct import struct
@ -203,37 +204,29 @@ def rxd_0183(devname):
return return
setthreadtitle("0183listener") setthreadtitle("0183listener")
while not shutdown: while not shutdown:
raw = ser.readline().decode('ascii')
if len(raw) == 0:
continue
try: try:
raw = ser.readline().decode('ascii')
msg = pynmea2.parse(raw) msg = pynmea2.parse(raw)
except pynmea2.nmea.ParseError: except pynmea2.nmea.ParseError:
print(f"NMEA0183: Parse-Error: {raw}") print(f"NMEA0183: Parse-Error: {raw}")
continue continue
# sentence_type kann fehlen # sentence_type kann fehlen
try: try:
stype = msg.sentence_type stype = msg.sentence_type
except: except:
print(f"NMEA0183: Sentence type missing: {raw}") print(f"NMEA0183: Sentence type missing: {raw}")
continue continue
if stype == 'GLL': # WIP Neuer Code aus Modul
boatdata.setValue("LAT", msg.latitude) # TODO Filter mit gewünschen Satztypen
boatdata.setValue("LON", msg.longitude) # if stype in stypefilter:
elif stype == 'VTG': # continue
boatdata.setValue("COG", int(msg.true_track)) if stype in nmea0183.decoder:
#TODO klären was für Typen hier ankommen können nmea0183.decoder[stype(boatdata, msg)]
# bytearray, str, decimal.Decimal?
sog = float(msg.spd_over_grnd_kts)
#str von OpenCPN: sog = float(msg.spd_over_grnd_kts[:-1])
boatdata.setValue("SOG", sog)
elif stype == 'VHW':
boatdata.setValue("STW", float(msg.water_speed_knots))
elif stype == 'WPL':
# Wegepunkt
print(msg.fields)
elif stype == 'RTE':
# Route
print(msg.fields)
else: else:
# Hier unbekannter Satztyp: protokollieren und ignorieren
print("Nicht implementiert")
print(msg) print(msg)
ser.close() ser.close()
@ -258,7 +251,7 @@ def rxd_gps(devname, devspeed):
print(msg.fields) print(msg.fields)
ser.close() ser.close()
def datareader(histpath, history): def datareader(cfg, history):
""" """
Daten zu fest definierten Zeitpunkten lesen Daten zu fest definierten Zeitpunkten lesen
@ -272,9 +265,9 @@ def datareader(histpath, history):
setthreadtitle("datareader") setthreadtitle("datareader")
# Speicherpfad für Meßwertdaten # Speicherpfad für Meßwertdaten
if not os.path.exists(histpath): if not os.path.exists(cfg['histpath']):
os.makedirs(histpath) os.makedirs(cfg['histpath'])
history.basepath = histpath history.basepath = cfg['histpath']
# Serien initialisieren # Serien initialisieren
history.addSeries("BMP280-75", 336 ,75) history.addSeries("BMP280-75", 336 ,75)
history.addSeries("BMP280-150", 336 , 150) history.addSeries("BMP280-150", 336 , 150)
@ -687,17 +680,23 @@ if __name__ == "__main__":
# Schnittstellen aktivieren # Schnittstellen aktivieren
if cfg['can']: if cfg['can']:
print("CAN enabled")
t_rxd_n2k = threading.Thread(target=rxd_n2k, args=(cfg['can_intf'],)) t_rxd_n2k = threading.Thread(target=rxd_n2k, args=(cfg['can_intf'],))
t_rxd_n2k.start() t_rxd_n2k.start()
if cfg['nmea0183']: if cfg['nmea0183']:
print("NMEA0183 enabled")
t_rxd_0183 = threading.Thread(target=rxd_0183, args=(cfg['0183_port'],)) t_rxd_0183 = threading.Thread(target=rxd_0183, args=(cfg['0183_port'],))
t_rxd_0183.start() t_rxd_0183.start()
if cfg['gps']: if cfg['gps']:
print("GPS enabled (local)")
t_rxd_gps = threading.Thread(target=rxd_gps, args=(cfg['gps_port'],)) t_rxd_gps = threading.Thread(target=rxd_gps, args=(cfg['gps_port'],))
t_rxd_gps.start() t_rxd_gps.start()
if not cfg['simulation']: if not cfg['simulation']:
t_data = threading.Thread(target=datareader, args=(cfg['histpath'], history)) if cfg['bme280']:
t_data.start() t_data = threading.Thread(target=datareader, args=(cfg, history))
t_data.start()
else:
print("Simulation mode enabled")
app = Frontend(cfg, owndevice, boatdata, profile) app = Frontend(cfg, owndevice, boatdata, profile)
app.run() app.run()
@ -708,6 +707,6 @@ if __name__ == "__main__":
t_rxd_0183.join() t_rxd_0183.join()
if cfg['gps']: if cfg['gps']:
t_rxd_gps.join() t_rxd_gps.join()
if not cfg['simulation']: if not cfg['simulation'] and cfg['bme280']:
t_data.join() t_data.join()
print("Another fine product of the Sirius Cybernetics Corporation.") print("Another fine product of the Sirius Cybernetics Corporation.")

View File

@ -28,6 +28,10 @@ Damit eine saubere Skala auf der Y-Achse erreicht wird, gibt einige
feste Skalierungen. feste Skalierungen.
Standard: 20hPa von unten nach oben, z.B. 1015, 1020, 1025, 1030, 1035 Standard: 20hPa von unten nach oben, z.B. 1015, 1020, 1025, 1030, 1035
TODO
- wenn keine Luftdruckdaten vorliegen, dann eine entsprechende
Meldung anzeigen
""" """
import time import time