Ankerseite und mehr NMEA0183 code

This commit is contained in:
Thomas Hooge 2025-07-20 21:29:22 +02:00
parent 5d8b33b086
commit 664d6c7d49
3 changed files with 102 additions and 30 deletions

5
README
View File

@ -31,9 +31,12 @@ Abhängigkeiten
- python3-heapdict - python3-heapdict
- python3-setproctitle - python3-setproctitle
Für GPS Für GPS und/oder NMEA0183
- python3-serial - python3-serial
- python3-nmea2 - python3-nmea2
Achtung: in Debian ist Version 1.15, die aktuelle Version 1.19 hat
weitere Satzarten implementiert. Allerdings ist dort auch kein AIS
vorhanden.
Für BME280 Für BME280
- python3-smbus2 - python3-smbus2

View File

@ -13,6 +13,13 @@ def DBT(boatdata, msg):
pass pass
#boatdata.setValue("DBT", msg.depth) #boatdata.setValue("DBT", msg.depth)
def DPT(boatdata, msg):
# Depth
print("-> DPT")
print(msg.fields)
print(msg.data)
#boatdata.setValue("DBT", msg.depth)
def GBS(boatdata, msg): def GBS(boatdata, msg):
# GNSS satellite fault detection # GNSS satellite fault detection
""" """
@ -42,9 +49,20 @@ def GGA(boatdata, msg):
boatdata.setValue("HDOP", msg.horizontal_dil) boatdata.setValue("HDOP", msg.horizontal_dil)
def GLL(boatdata, msg): def GLL(boatdata, msg):
print("-> GLL") # Position data: position fix, time of position fix, and status
boatdata.setValue("LAT", msg.latitude) # UTC of position ignored
boatdata.setValue("LON", msg.longitude) print(msg.data)
if not msg.status == 'A':
return
lat_fac = 1 if msg.lat_dir == 'N' else -1
lat_deg = int(msg.lat[0:2])
lat_min = float(msg.lat[2:])
print(lat_deg, lat_min)
boatdata.setValue("LAT", lat_fac * lat_deg + lat_min / 60)
lon_fac = 1 if msg.lon_dir == 'E' else -1
lon_deg = int(msg.lon[0:3])
lon_min = float(msg.lon[3:])
boatdata.setValue("LON", lon_fac * lon_deg + lon_min / 60)
def GSA(boatdata, msg): def GSA(boatdata, msg):
# Satellites # Satellites
@ -113,8 +131,10 @@ def HDM(boatdata, msg):
def HDT(boatdata, msg): def HDT(boatdata, msg):
# Heading True # Heading True
print("-> HDT") if msg.hdg_true == 'T':
print(msg.fields) boatdata.setValue("HDT", msg.heading)
else:
print("HDT: T not set!")
def HTD(boatdata, msg): def HTD(boatdata, msg):
# Heading/Track control data # Heading/Track control data
@ -141,20 +161,25 @@ def RMB(boatdata, msg):
def RMC(boatdata, msg): def RMC(boatdata, msg):
# Recommended Minimum Navigation Information # Recommended Minimum Navigation Information
# print("-> RMC") #print("-> RMC")
# print(msg.timestamp, msg.datestamp) # print(msg.timestamp, msg.datestamp)
# print(msg.status) # V=Warning, P=Precise, A=? # print(msg.status) # V=Warning, P=Precise, A=OK
# mag_variation, mag_var_dir E/W # mag_variation, mag_var_dir E/W
# true_course # TODO nav_status welche Bedeutung?
if msg.lat_dir == 'N': if not msg.status == 'A':
boatdata.setValue("LAT", msg.lat) return
else: lat_fac = 1 if msg.lat_dir == 'N' else -1
boatdata.setValue("LAT", msg.lat) * -1 lat_deg = int(msg.lat[0:2])
if msg.lon_dir == 'E': lat_min = float(msg.lat[2:])
boatdata.setValue("LON", msg.lon) boatdata.setValue("LAT", lat_fac * lat_deg + lat_min / 60)
else: lon_fac = 1 if msg.lon_dir == 'E' else -1
boatdata.setValue("LON", msg.lon) * -1 lon_deg = int(msg.lon[0:3])
boatdata.setValue("SOG", msg.spd_over_grnd) lon_min = float(msg.lon[3:])
boatdata.setValue("LON", lon_fac * lon_deg + lon_min / 60)
if msg.spd_over_grnd:
boatdata.setValue("SOG", float(msg.spd_over_grnd))
if msg.true_course:
boatdata.setValue("COG", float(msg.true_course))
def ROT(boatdata, msg): def ROT(boatdata, msg):
# Rate Of Turn # Rate Of Turn
@ -242,7 +267,13 @@ def XDR(boatdata, msg):
# units: D # units: D
# id: Yaw # id: Yaw
if msg.id.lower() == 'yaw': if msg.id.lower() == 'yaw':
boatdata.setValue("YAW", msg.value) boatdata.setValue("YAW", float(msg.value))
elif msg.id.lower() == 'ptch':
boatdata.setValue("PTCH", float(msg.value))
elif msg.id.lower() == 'roll':
boatdata.setValue("ROLL", float(msg.value))
elif msg.id.lower() == 'barometer':
boatdata.setValue("xdrPress", float(msg.value))
else: else:
print(f"-> XDR: {msg.type}, {msg.value}, {msg.units}, {msg.id}") print(f"-> XDR: {msg.type}, {msg.value}, {msg.units}, {msg.id}")
@ -275,6 +306,7 @@ def VDO(boatdata, msg):
decoder = { decoder = {
"DBS": DBS, "DBS": DBS,
"DBT": DBT, "DBT": DBT,
"DPT": DPT,
"GBS": GBS, "GBS": GBS,
"GGA": GGA, "GGA": GGA,
"GLL": GLL, "GLL": GLL,
@ -282,6 +314,7 @@ decoder = {
"GSV": GSV, "GSV": GSV,
"HDG": HDG, "HDG": HDG,
"HDM": HDM, "HDM": HDM,
"HDT": HDT,
"HTD": HTD, "HTD": HTD,
"MWV": MWV, "MWV": MWV,
"MTW": MTW, "MTW": MTW,

View File

@ -14,6 +14,7 @@ Daten
- Alarm aktiv J/N - Alarm aktiv J/N
- Alarmradius - Alarmradius
- GPS Abweichung/ Fehler in der Horizontalen - GPS Abweichung/ Fehler in der Horizontalen
- Zeitpunkt des Ankeraus
Darstellung: Darstellung:
- Modi: - Modi:
@ -29,6 +30,7 @@ Es gibt verschiedene Unterseiten
import os import os
import cairo import cairo
import math import math
import time
from .page import Page from .page import Page
class Anchor(Page): class Anchor(Page):
@ -41,6 +43,7 @@ class Anchor(Page):
self.buttonlabel[5] = '' # ALARM erst möglich wenn der Anker unten ist self.buttonlabel[5] = '' # ALARM erst möglich wenn der Anker unten ist
self.mode = 'N' # (N)ormal, (C)onfiguration self.mode = 'N' # (N)ormal, (C)onfiguration
self.scale = 50 # Radius of display circle in meter
self._bd = boatdata self._bd = boatdata
@ -54,6 +57,7 @@ class Anchor(Page):
self.anchor_lat = 0 self.anchor_lat = 0
self.anchor_lon = 0 self.anchor_lon = 0
self.anchor_depth = -1 self.anchor_depth = -1
self.anchor_ts = None # Timestamp of dropped anchor
self.lat = 0 self.lat = 0
self.lon = 0 self.lon = 0
self.heading = -1 self.heading = -1
@ -75,13 +79,15 @@ class Anchor(Page):
self.anchor_lat = self._bd.lat self.anchor_lat = self._bd.lat
self.anchor_lon = self._bd.lon self.anchor_lon = self._bd.lon
self.anchor_set = True self.anchor_set = True
self.anchor_ts = time.time()
self.buttonlabel[2] = 'RISE' self.buttonlabel[2] = 'RISE'
self.buttonlabel[5] = 'ALARM' self.buttonlabel[5] = 'ALARM'
else: else:
self.anchor_set = False self.anchor_set = False
self.alarm = False self.alarm = False
self.alarm_enabled = False self.alarm_enabled = False
self.buttonlabel[2] = 'SET' self.anchor_ts = None
self.buttonlabel[2] = 'DROP'
self.buttonlabel[5] = '' self.buttonlabel[5] = ''
if buttonid == 5: if buttonid == 5:
# Bei aktivem Alarm kann mit dieser Taste der Alarm zurückgesetzt # Bei aktivem Alarm kann mit dieser Taste der Alarm zurückgesetzt
@ -142,27 +148,57 @@ class Anchor(Page):
cy = 150 cy = 150
r = 125 r = 125
ctx.set_line_width(1.5) # Skala
ctx.set_line_width(1)
ctx.arc(cx, cy, r, 0, 2*math.pi) ctx.arc(cx, cy, r, 0, 2*math.pi)
ctx.move_to(cx + 10, cy + 0.5)
ctx.line_to(cx + r - 4, cy + 0.5)
ctx.move_to(cx + r / 2, cy + 20)
# Pfeil links
ctx.move_to(cx + 10, cy + 0.5)
ctx.line_to(cx + 16, cy - 4 + 0.5)
ctx.move_to(cx + 10, cy + 0.5)
ctx.line_to(cx + 16, cy + 4 + 0.5)
# Pfeil rechts
ctx.move_to(cx + r - 4, cy + 0.5)
ctx.line_to(cx + r - 10, cy - 4 + 0.5)
ctx.move_to(cx + r - 4, cy + 0.5)
ctx.line_to(cx + r - 10, cy + 4 + 0.5)
ctx.set_font_size(16)
self.draw_text_center(ctx, cx + r / 2, cy + 8, str(self.scale) + " m")
ctx.stroke() ctx.stroke()
# Ankersymbol falls Anker fallen gelassen wurde, ansonsten nur Kreis- ctx.set_line_width(1.5)
# mittelpunkt kennzeichnen # Ankersymbol falls Anker fallen gelassen wurde
# Ansonsten ist das Boot-Symbol im Mittelpunkt
if self.anchor_set: if self.anchor_set:
ctx.save() ctx.save()
ctx.set_source_surface(self.sym_anchor, cx-8, cy-8) ctx.set_source_surface(self.sym_anchor, cx-8, cy-8)
ctx.paint() ctx.paint()
ctx.restore() ctx.restore()
else:
ctx.move_to(cx-6, cy-6)
ctx.line_to(cx+6, cy+6)
ctx.move_to(cx+6, cy-6)
ctx.line_to(cx-6, cy+6)
ctx.stroke()
# Boot zeichnen # Boot zeichnen
# Heading beachten # Heading beachten
# Wir arbeiten mit einer Kopie, weil bx/by im Laufe der Zeit von
# cx/cy abweichen werden
if self.anchor_set:
bx = cx
by = cy + 30
else:
bx = cx
by = cy + 8
p = ((bx - 5, by), (bx - 5, by - 10), (bx, by - 16), (bx + 5, by - 10), (bx + 5, by), (bx - 6, by))
if self._bd.hdt.value:
# Rotiere Boot-Symbol um eigenes Zentrum
boat = self.rotate((bx, by - 8), p, self._bd.hdt.value)
else:
# Kein Heading, Boot immer zeichnen
boat = p
ctx.move_to(*boat[0])
for point in boat[1:]:
ctx.line_to(*point)
ctx.stroke()
# Windpfeil zeichnen # Windpfeil zeichnen
if self._bd.awa.value: if self._bd.awa.value: