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 b) lokal
c) Server c) Server
- Internationalisierung
1. EN (Standardsprache)
2. DE
3. FR
4. ES
5. IT
- 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

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

View File

@ -45,7 +45,10 @@ class Barograph(Page):
# Meßwert alle 15 Minuten: # Meßwert alle 15 Minuten:
# 84 Stunden * 4 Werte je Stunde = 336 Meßwerte # 84 Stunden * 4 Werte je Stunde = 336 Meßwerte
self.bd = boatdata 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.zoom = (1, 2, 3, 6, 12)
self.zoomindex = 4 self.zoomindex = 4
self.series = (75, 150, 300, 600, 900) self.series = (75, 150, 300, 600, 900)
@ -65,6 +68,7 @@ class Barograph(Page):
self.buttonlabel[2] = '-' self.buttonlabel[2] = '-'
self.buttonlabel[5] = 'SRC' self.buttonlabel[5] = 'SRC'
self.data = None
self.refresh = time.time() - 30 self.refresh = time.time() - 30
def handle_key(self, buttonid): def handle_key(self, buttonid):
@ -113,6 +117,9 @@ class Barograph(Page):
Transfer data from history to page buffer Transfer data from history to page buffer
set y-axis according to data set y-axis according to data
""" """
if self.source == None:
# TODO hier muß noch Arbeit reingesteckt werden!
return False
self.data = [] self.data = []
self.vmin = 9999 self.vmin = 9999
self.vmax = 0 self.vmax = 0
@ -363,8 +370,13 @@ class Barograph(Page):
ctx.stroke() ctx.stroke()
# Meßdaten # Meßdaten
if self.data:
for v in self.data: for v in self.data:
x0 -= 1 x0 -= 1
if v > 0: if v > 0:
ctx.rectangle(x0, y0 - (v - ysmin) * dy, 1.5, 1.5) ctx.rectangle(x0, y0 - (v - ysmin) * dy, 1.5, 1.5)
ctx.fill() 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_lat = boatdata.getRef("LAT")
self.bv_lon = boatdata.getRef("LON") self.bv_lon = boatdata.getRef("LON")
self.bv_sog = boatdata.getRef("SOG") self.bv_sog = boatdata.getRef("SOG")
self.bv_hdop = boatdata.getRef("HDOP")
self.races = None self.races = None
self.raceid = None
if self.ttype == 'HERO': if self.ttype == 'HERO':
self.raceid = self.app.track.hero_raceid # Ausgewählte Regatta self.raceid = self.app.track.hero_raceid # Ausgewählte Regatta
self.buttonlabel[1] = 'MODE' self.buttonlabel[1] = 'MODE'
self.buttonlabel[2] = 'INFO' self.buttonlabel[2] = 'INFO'
self.buttonlabel[5] = 'ABORT' self.buttonlabel[5] = 'ABORT'
else: elif self.ttype in ('LOCAL','SDCARD'):
self.raceid = None self.buttonlabel[5] = 'ON'
self.menupos = 0 self.menupos = 0
self.mode = 'N' # (N)ormal, (C)onfiguration, (M)itteilung self.mode = 'N' # (N)ormal, (C)onfiguration, (M)itteilung
self.query_active = False self.query_active = False
@ -92,6 +94,8 @@ class RaceTracker(Page):
self.buttonlabel = self.savebuttons.copy() self.buttonlabel = self.savebuttons.copy()
return True return True
if buttonid == 1: if buttonid == 1:
if not self.ttype == 'HERO':
return False
# Modus umschalten # Modus umschalten
if self.mode == 'N': if self.mode == 'N':
self.mode = 'C' self.mode = 'C'
@ -110,6 +114,8 @@ class RaceTracker(Page):
self.buttonlabel[5] = 'ABORT' self.buttonlabel[5] = 'ABORT'
return True return True
elif buttonid == 2: elif buttonid == 2:
if not self.ttype == 'HERO':
return False
if self.mode == 'N': if self.mode == 'N':
self.mode = 'M' # Nachrichten der Wettfahrtleitung self.mode = 'M' # Nachrichten der Wettfahrtleitung
self.buttonlabel[2] = '' self.buttonlabel[2] = ''
@ -140,6 +146,17 @@ class RaceTracker(Page):
return True return True
elif buttonid == 5: elif buttonid == 5:
if self.mode == 'N': if self.mode == 'N':
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.query_active = True;
self.savebuttons = self.buttonlabel.copy() self.savebuttons = self.buttonlabel.copy()
self.buttonlabel[1] = "" self.buttonlabel[1] = ""
@ -180,16 +197,22 @@ class RaceTracker(Page):
ctx.set_font_size(16) ctx.set_font_size(16)
ctx.move_to(x, y) ctx.move_to(x, y)
ctx.show_text("Disabled by 'NONE in configuration'.") ctx.show_text("Disabled by 'NONE in configuration'.")
y += 40 y += 30
ctx.move_to(x, y) 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 y += 20
ctx.move_to(x, y) 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 y += 20
ctx.move_to(x, y) ctx.move_to(x, y)
ctx.show_text("Hero web page for detailed description.") ctx.show_text("web page for detailed description.")
y += 40 y += 20
ctx.move_to(x, y) ctx.move_to(x, y)
ctx.show_text("Additionally you should contact your local") ctx.show_text("Additionally you should contact your local")
y += 20 y += 20
@ -198,19 +221,61 @@ class RaceTracker(Page):
def draw_local(self, ctx): def draw_local(self, ctx):
x = 8 x = 8
x1 = 130
y = 50 y = 50
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(24) ctx.set_font_size(24)
ctx.move_to(x, y) ctx.move_to(x, y)
ctx.show_text("Local Tracking") 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 # Anzeige
# - LAT, LON # - LAT, LON
# - bisher gespeicherte Anzahl Positionen # - bisher gespeicherte Anzahl Positionen
# - Zeitabstand zwischen den einzelnen Messungen # - Zeitabstand zwischen den einzelnen Messungen
# - Hinweis wo gespeichert wird # - 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.select_font_face("DSEG7 Classic")
ctx.set_font_size(80) ctx.set_font_size(80)
@ -448,10 +513,12 @@ class RaceTracker(Page):
def draw(self, ctx): def draw(self, ctx):
if self.mode == 'N': if self.mode == 'N':
if self.ttype == 'NONE': if self.ttype in ('LOCAL', 'SDCARD'):
self.draw_none(ctx) self.draw_local(ctx)
elif self.ttype == 'HERO':
self.draw_hero(ctx)
else: else:
self.draw_normal(ctx) self.draw_none(ctx)
elif self.mode == 'C': elif self.mode == 'C':
self.draw_config(ctx) self.draw_config(ctx)
else: else:

View File

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

View File

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