Lokaler Tracker funktionsfähig. Bugfixes.

This commit is contained in:
Thomas Hooge 2025-09-22 14:27:05 +02:00
parent f0ebdd0201
commit e7a96390f2
6 changed files with 150 additions and 44 deletions

7
TODO
View File

@ -6,6 +6,13 @@ Aufgaben, Planungs- und Ideenliste
b) lokal
c) Server
- Internationalisierung
1. EN (Standardsprache)
2. DE
3. FR
4. ES
5. IT
- Satelliten: SatelliteList verwenden und dieses auch in
nmea2000 implementieren
- Satellitenübersicht / SkyView

View File

@ -115,7 +115,7 @@ import pages
__author__ = "Thomas Hooge"
__copyright__ = "Copyleft 2024-2025, all rights reversed"
__version__ = "0.2"
__version__ = "0.3"
__email__ = "thomas@hoogi.de"
__status__ = "Development"
@ -128,7 +128,7 @@ cfg = {
'loglevel': 3,
'imgpath': os.path.join(sys.path[0], 'images'),
'audiopath': os.path.join(sys.path[0], 'audio'),
'histpath' = '~/.local/lib/obp60v',
'histpath': '~/.local/lib/obp60v',
'deviceid': 100,
'manufcode': 2046, # Open Boat Projects (OBP)
'devfunc': 120, # Display
@ -749,6 +749,7 @@ if __name__ == "__main__":
cfg['tracker']['mqtt_pass'] = config.get('tracker', 'mqtt_pass')
cfg['tracker']['logdir'] = cfg['logdir']
cfg['tracker']['trace'] = config.getboolean('tracker', 'trace')
cfg['tracker']['interval'] = config.getint('tracker', 'interval')
# Boat data
cfg['boat']['name'] = config.get('boat', 'name')
@ -806,14 +807,15 @@ if __name__ == "__main__":
log.info("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':
if cfg['tracker']['type'] != 'NONE':
log.info(f"Tracking enabled, mode {cfg['tracker']['type']}")
#appdata.track.set_type( cfg['tracker']['type'])
if cfg['tracker']['type'] == 'HERO':
t_tracker = threading.Thread(target=appdata.track.mqtt_tracker, args=(cfg['tracker'],cfg['boat'],appdata,boatdata))
elif cfg['tracker']['type'] IN ['LOCAL', 'SDCARD']:
t_tracker = threading.Thread(target=appdata.track.local_tracker, args=(cfg['tracker'],cfg['boat'],appdata,boatdata))
t_tracker.start()
t_tracker.start()
elif cfg['tracker']['type'] in ['LOCAL', 'SDCARD']:
t_tracker = threading.Thread(target=appdata.track.local_tracker, args=(cfg,appdata,boatdata))
t_tracker.start()
if not cfg['simulation']:
if cfg['bme280']:
log.info("Environment sensor enabled")

View File

@ -45,7 +45,10 @@ class Barograph(Page):
# Meßwert alle 15 Minuten:
# 84 Stunden * 4 Werte je Stunde = 336 Meßwerte
self.bd = boatdata
self.source = 'I' # (I)ntern, e(X)tern
if not cfg['bme280']:
self.source = None # keine Datenquelle!
else:
self.source = 'I' # (I)ntern, e(X)tern, None=Disabled
self.zoom = (1, 2, 3, 6, 12)
self.zoomindex = 4
self.series = (75, 150, 300, 600, 900)
@ -65,6 +68,7 @@ class Barograph(Page):
self.buttonlabel[2] = '-'
self.buttonlabel[5] = 'SRC'
self.data = None
self.refresh = time.time() - 30
def handle_key(self, buttonid):
@ -113,6 +117,9 @@ class Barograph(Page):
Transfer data from history to page buffer
set y-axis according to data
"""
if self.source == None:
# TODO hier muß noch Arbeit reingesteckt werden!
return False
self.data = []
self.vmin = 9999
self.vmax = 0
@ -363,8 +370,13 @@ class Barograph(Page):
ctx.stroke()
# Meßdaten
for v in self.data:
x0 -= 1
if v > 0:
ctx.rectangle(x0, y0 - (v - ysmin) * dy, 1.5, 1.5)
ctx.fill()
if self.data:
for v in self.data:
x0 -= 1
if v > 0:
ctx.rectangle(x0, y0 - (v - ysmin) * dy, 1.5, 1.5)
ctx.fill()
else:
# Keine Daten vorhanden!
# TODO iregndwas nettes anzeigen
pass

View File

@ -33,14 +33,16 @@ class RaceTracker(Page):
self.bv_lat = boatdata.getRef("LAT")
self.bv_lon = boatdata.getRef("LON")
self.bv_sog = boatdata.getRef("SOG")
self.bv_hdop = boatdata.getRef("HDOP")
self.races = None
self.raceid = None
if self.ttype == 'HERO':
self.raceid = self.app.track.hero_raceid # Ausgewählte Regatta
self.buttonlabel[1] = 'MODE'
self.buttonlabel[2] = 'INFO'
self.buttonlabel[5] = 'ABORT'
else:
self.raceid = None
elif self.ttype in ('LOCAL','SDCARD'):
self.buttonlabel[5] = 'ON'
self.menupos = 0
self.mode = 'N' # (N)ormal, (C)onfiguration, (M)itteilung
self.query_active = False
@ -92,6 +94,8 @@ class RaceTracker(Page):
self.buttonlabel = self.savebuttons.copy()
return True
if buttonid == 1:
if not self.ttype == 'HERO':
return False
# Modus umschalten
if self.mode == 'N':
self.mode = 'C'
@ -110,6 +114,8 @@ class RaceTracker(Page):
self.buttonlabel[5] = 'ABORT'
return True
elif buttonid == 2:
if not self.ttype == 'HERO':
return False
if self.mode == 'N':
self.mode = 'M' # Nachrichten der Wettfahrtleitung
self.buttonlabel[2] = ''
@ -140,15 +146,26 @@ class RaceTracker(Page):
return True
elif buttonid == 5:
if self.mode == 'N':
self.query_active = True;
self.savebuttons = self.buttonlabel.copy()
self.buttonlabel[1] = ""
self.buttonlabel[2] = "YES"
self.buttonlabel[3] = ""
self.buttonlabel[4] = ""
self.buttonlabel[5] = "NO"
self.buttonlabel[6] = ""
# Taste 2 = JA, Taste 5 = NEIN
if self.ttype in ('LOCAL','SDCARD'):
# Tracking ein/-ausschalten
if self.app.track.is_active():
self.app.track.set_active(False)
self.buttonlabel[5] = 'ON'
else:
self.app.track.set_active(True)
self.buttonlabel[5] = 'OFF'
else:
if self.ttype == ('HERO'):
# Rennabbruch verarbeiten
self.query_active = True;
self.savebuttons = self.buttonlabel.copy()
self.buttonlabel[1] = ""
self.buttonlabel[2] = "YES"
self.buttonlabel[3] = ""
self.buttonlabel[4] = ""
self.buttonlabel[5] = "NO"
self.buttonlabel[6] = ""
# Taste 2 = JA, Taste 5 = NEIN
elif self.mode == 'C':
# Tracking ein/-ausschalten
if self.app.track.is_active():
@ -180,16 +197,22 @@ class RaceTracker(Page):
ctx.set_font_size(16)
ctx.move_to(x, y)
ctx.show_text("Disabled by 'NONE in configuration'.")
y += 40
y += 30
ctx.move_to(x, y)
ctx.show_text("Currently only tracker type 'HERO' is")
ctx.show_text("Currently only tracker types 'HERO' and 'LOCAL'")
y += 20
ctx.move_to(x, y)
ctx.show_text("implemented. Please visit the Regatta")
ctx.show_text("are implemented.")
y += 30
ctx.move_to(x, y)
ctx.show_text("'LOCAL' tracks positions in file system.")
y += 30
ctx.move_to(x, y)
ctx.show_text("For 'HERO' pleast visit the Regatta Hero")
y += 20
ctx.move_to(x, y)
ctx.show_text("Hero web page for detailed description.")
y += 40
ctx.show_text("web page for detailed description.")
y += 20
ctx.move_to(x, y)
ctx.show_text("Additionally you should contact your local")
y += 20
@ -198,19 +221,61 @@ class RaceTracker(Page):
def draw_local(self, ctx):
x = 8
x1 = 130
y = 50
ctx.select_font_face("Ubuntu", cairo.FontSlant.NORMAL, cairo.FontWeight.BOLD)
ctx.set_font_size(24)
ctx.move_to(x, y)
ctx.show_text("Local Tracking")
ctx.select_font_face("Ubuntu", cairo.FontSlant.NORMAL, cairo.FontWeight.BOLD)
ctx.set_font_size(16)
y += 30
ctx.move_to(x, y)
ctx.show_text("Activated: ")
ctx.show_text("Yes" if self.app.track.is_active() else "No")
y += 20
ctx.move_to(x, y)
ctx.show_text(f"Log interval: {self.app.track.local_dt} seconds")
#ctx.show_text(str(self.app.track.local_dt))
y += 20
ctx.move_to(x, y)
ctx.show_text("Log entries written: ")
ctx.show_text(str(self.app.track.local_lfdno))
# Anzeige
# - LAT, LON
# - bisher gespeicherte Anzahl Positionen
# - Zeitabstand zwischen den einzelnen Messungen
# - Hinweis wo gespeichert wird
y += 30
ctx.move_to(x, y)
ctx.show_text("Latitude: ")
ctx.move_to(x1, y)
ctx.show_text(self.bv_lat.format())
y += 20
ctx.move_to(x, y)
ctx.show_text("Longitude: ")
ctx.move_to(x1, y)
ctx.show_text(self.bv_lon.format())
y += 20
ctx.move_to(x, y)
ctx.show_text("HDOP: ")
ctx.move_to(x1, y)
ctx.show_text(self.bv_hdop.format() or '---')
y += 20
ctx.move_to(x, y)
ctx.show_text("Speed: ")
ctx.move_to(x1, y)
ctx.show_text(self.bv_sog.format())
def draw_normal(self, ctx):
def draw_hero(self, ctx):
"""
Regatta Hero Normalansicht
TODO
racephase anzeige zu Debuggingzwecken
"""
ctx.select_font_face("DSEG7 Classic")
ctx.set_font_size(80)
@ -448,10 +513,12 @@ class RaceTracker(Page):
def draw(self, ctx):
if self.mode == 'N':
if self.ttype == 'NONE':
self.draw_none(ctx)
if self.ttype in ('LOCAL', 'SDCARD'):
self.draw_local(ctx)
elif self.ttype == 'HERO':
self.draw_hero(ctx)
else:
self.draw_normal(ctx)
self.draw_none(ctx)
elif self.mode == 'C':
self.draw_config(ctx)
else:

View File

@ -1,3 +1,11 @@
"""
Wind / Windlupe
TODO
- Windlupe:
Wenn der Wind achterlich kommt, dann andere Ansicht / Skala verwenden
"""
import os
import cairo
import math

View File

@ -48,6 +48,9 @@ class Tracker():
raise TypeError("Invalid tracker type: '{}'. Only supported: {}".format(cfg['tracker']['type'], ','.join(validtypes)))
self.ttype = cfg['tracker']['type']
self.local_lfdno = 0
self.local_dt = cfg['tracker']['interval'] # Eintrag alle <n> Sekunden schreiben
self.trace = cfg['tracker']['trace'] # Debugging
self.trace_fh = None # File Handle der Tracedatei
@ -127,9 +130,11 @@ class Tracker():
def set_active(self, newval):
self.activated = newval
def local_tracker(self, cfg, boat, appdata, boatdata):
# TODO / WIP
def local_tracker(self, cfg, appdata, boatdata):
self.log.info("Local tracker enabled")
if not os.path.exists(cfg['histpath']):
os.makedirs(cfg['histpath'])
self.log.info(f"History path created: '{cfg['histpath']}'")
# Zugriff auf Boatdata: Referenzen für leichten schnellen Zugriff
bv_lat = boatdata.getRef("LAT")
@ -137,20 +142,25 @@ class Tracker():
bv_hdop = boatdata.getRef("HDOP")
bv_tspos = boatdata.getRef("TSPOS")
self.local_dt = 15
self.local_lfdno = 0
trackerfile = "/tmp/test.log" # TODO Konfiguration lesen
trackerfile = os.path.join(cfg['histpath'], "localtrack.log")
fh = open(trackerfile, 'a+')
n = 0
while not appdata.shutdown:
time.sleep(self.local_dt)
time.sleep(1)
if not self.activated:
continue
n += 1
if n % self.local_dt != 0:
continue
self.local_lfdno += 1
data = f"{},{},{},{}\n".format(
data = "{},{}Z,{},{},{}\n".format(
self.local_lfdno,
bv_tspos.getValueRaw(),
bv_lat.getValueRaw(),
bv_lon.getValueRaw(),
bv_hdop.getValueRaw())
bv_tspos.getValue(),
bv_lat.getValue(),
bv_lon.getValue(),
bv_hdop.getValue())
fh.write(data)
fh.flush()
fh.close()
def set_hero_raceid(self, newraceid):