Tide: Anzeige erster Testdaten

This commit is contained in:
Thomas Hooge 2025-10-05 12:04:19 +02:00
parent e9d473fd10
commit e7a2f4bb54
6 changed files with 91 additions and 24 deletions

View File

@ -4,6 +4,7 @@ Generische Applikationsdaten
""" """
import os import os
from web import WebInterface
from tracker import Tracker from tracker import Tracker
from navtex import NAVTEX from navtex import NAVTEX
@ -14,6 +15,13 @@ class AppData():
self.log = logger self.log = logger
if cfg['navtex']: if cfg['navtex']:
self.navtex = NAVTEX(logger, cfg) self.navtex = NAVTEX(logger, cfg)
else:
self.navtex = None
if cfg['tide']:
self.web = WebInterface(logger, cfg)
self.web.refresh()
else:
self.web = None
self.track = Tracker(logger, cfg) self.track = Tracker(logger, cfg)
self.frontend = None self.frontend = None
self.bv_lat = None self.bv_lat = None

View File

@ -26,6 +26,9 @@ B2: Subject indicator character
Y Special services allocation by IMO NAVTEX Panel Y Special services allocation by IMO NAVTEX Panel
Z No message on hand Z No message on hand
Für Konfiguration: subjects = ABCDEFGHIJKLTVWXYZ
B3, B4: Serial number 01-99, 00: immediate printout B3, B4: Serial number 01-99, 00: immediate printout
Timecode: DDHHmm UTC MMM YY Timecode: DDHHmm UTC MMM YY
@ -38,6 +41,7 @@ Sqlite database schema
content TEXT content TEXT
received TEXT received TEXT
siehe auch: https://www.icselectronics.co.uk/support/info/navtexdb
""" """
import os import os
import http.client import http.client

View File

@ -36,6 +36,8 @@ port = /dev/ttyACM0
[navtex] [navtex]
enabled = false enabled = false
source = net source = net
navarea = I
subjects = ABDEFKLXYZ
housekeeping = 72 housekeeping = 72
refresh = 30 refresh = 30

View File

@ -6,7 +6,7 @@ Virtuelles Multifunktionsgerät OBP60v
Zwei Displayvarianten Zwei Displayvarianten
1. Fliegendes OBP60 auf großem Bildschirm. 400x300 Display 1. Fliegendes OBP60 auf großem Bildschirm. 400x300 Display
2. Fullscreen Display skaliert mit 1,6 ergibt 640x480 2. Fullscreen Display skaliert mit 1,6 ergibt 640x480
mit Platz für große Touch-Flächen am rechten Rand mit Platz für große Touch-Flächen (160px) am rechten Rand
Das Gerät kann Daten von NMEA2000 und NMEA0183 empfangen, sowie von Das Gerät kann Daten von NMEA2000 und NMEA0183 empfangen, sowie von
einem lokal angeschlossenen GPS-Empfänger. einem lokal angeschlossenen GPS-Empfänger.
@ -141,6 +141,7 @@ cfg = {
'gps': False, 'gps': False,
'bme280': False, 'bme280': False,
'tracker': { 'type': 'NONE' }, 'tracker': { 'type': 'NONE' },
'tide': False,
'boat': { } 'boat': { }
} }
@ -798,13 +799,21 @@ if __name__ == "__main__":
config.write(fh) config.write(fh)
log.info("Created new boat UUID: {}".format(cfg['boat']['uuid'])) log.info("Created new boat UUID: {}".format(cfg['boat']['uuid']))
# Globale Daten, u.a. auch Shutdown-Indikator
appdata = AppData(log, cfg)
# Ggf. Simulationsdaten einschalten # Ggf. Simulationsdaten einschalten
if cfg['simulation']: if cfg['simulation']:
boatdata.enableSimulation() boatdata.enableSimulation()
# Tide wird aktiviert wenn mindestens eine Tidenseite angezeigt wird
for s in config.sections():
if s == 'pages':
continue
if s.startswith('page'):
if config.get(s, "type") == 'Tide':
cfg['tide'] = True
# Globale Daten, u.a. auch Shutdown-Indikator
appdata = AppData(log, cfg)
# Gerät initialisieren u.a. mit den genutzten Seiten # Gerät initialisieren u.a. mit den genutzten Seiten
profile = init_profile(config, cfg, boatdata) profile = init_profile(config, cfg, boatdata)
@ -834,6 +843,7 @@ if __name__ == "__main__":
elif cfg['tracker']['type'] in ['LOCAL', 'SDCARD']: elif cfg['tracker']['type'] in ['LOCAL', 'SDCARD']:
t_tracker = threading.Thread(target=appdata.track.local_tracker, args=(cfg,appdata,boatdata)) 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']:
log.info("Environment sensor enabled") log.info("Environment sensor enabled")

View File

@ -1,8 +1,7 @@
""" """
NAVTEX Tide Vorausschau
- Meldungen anzeigen
""" """
import cairo import cairo
@ -25,6 +24,9 @@ class Tide(Page):
ctx.set_font_size(16) ctx.set_font_size(16)
ctx.set_line_width(2) ctx.set_line_width(2)
ctx.move_to(220, 40)
ctx.show_text("Schulau, Elbe")
x0 = 40 # links unten x0 = 40 # links unten
y0 = 250 y0 = 250
x1 = 380 # rechts oben x1 = 380 # rechts oben
@ -48,3 +50,28 @@ class Tide(Page):
self.draw_text_center(ctx, x0 + (x1 - x0) / 2, y0 + 12, "Zeit, h") self.draw_text_center(ctx, x0 + (x1 - x0) / 2, y0 + 12, "Zeit, h")
ctx.stroke() ctx.stroke()
ymin, ymax = self.app.web.get_tide_minmax()
rawdata = self.app.web.get_tide()
ctx.move_to(x0 - 32, y0 + 8)
ctx.show_text(str(ymin))
ctx.move_to(x0 - 32, y1 + 8)
ctx.show_text(str(ymax))
ctx.move_to(x0 + 16, y0 + 16)
ctx.show_text(f"n = {len(rawdata)}")
dx = (x1 - x0) / len(rawdata)
x = x0
while rawdata[0][0] is None:
x += dx
del rawdata[0]
y = (rawdata[0][0] - ymin) / (ymax - ymin) * (y0 - y1)
ctx.move_to(x, y0 - (rawdata[0][0] - ymin))
del rawdata[0]
x += dx
for val in rawdata:
y = (val[0] - ymin) / (ymax - ymin) * (y0 - y1)
ctx.line_to(x, y0 - y)
x += dx

50
web.py
View File

@ -1,7 +1,7 @@
""" """
Web Interface Web Interface
Regelmäßiges Abfragen von Daten im Internet Regelmäßiges Abfragen von Daten aus dem Internet
- NAVTEX - NAVTEX
- DWD - DWD
- Pegelstände - Pegelstände
@ -13,7 +13,7 @@ Regelmäßiges Abfragen von Daten im Internet
import os import os
import http.client import http.client
import ssl import ssl
import re import json
import sqlite3 import sqlite3
import datetime import datetime
from gi.repository import GLib from gi.repository import GLib
@ -35,7 +35,14 @@ class WebInterface():
if self.cur.fetchone() == None: if self.cur.fetchone() == None:
sql = ("CREATE TABLE IF NOT EXISTS station (" sql = ("CREATE TABLE IF NOT EXISTS station ("
"uuid TEXT PRIMARY KEY NOT NULL," "uuid TEXT PRIMARY KEY NOT NULL,"
"name TEXT" "name TEXT)"
)
self.cur.execute(sql)
sql = ("CREATE TABLE IF NOT EXISTS data ("
"timestamp TEXT PRIMARY KEY NOT NULL,"
"astro NUMBER NOT NULL,"
"forecast NUMBER,"
"measurement NUMBER)"
) )
self.cur.execute(sql) self.cur.execute(sql)
self.log.info(f"Created tide database: {dbpath}") self.log.info(f"Created tide database: {dbpath}")
@ -44,6 +51,7 @@ class WebInterface():
#GLib.timeout_add_seconds(cfg['tide_refresh'] * 60, self.on_timer) #GLib.timeout_add_seconds(cfg['tide_refresh'] * 60, self.on_timer)
GLib.timeout_add_seconds(60 * 60, self.on_timer) GLib.timeout_add_seconds(60 * 60, self.on_timer)
self.running = True self.running = True
self.log.info(f"Web interface started")
def __del__(self): def __del__(self):
self.conn.close() self.conn.close()
@ -62,7 +70,7 @@ class WebInterface():
""" """
if local: if local:
# Für Tests um nicht permanent die Webseite abzufragen # Für Tests um nicht permanent die Webseite abzufragen
with open("DE__714P.json", "r") as fh: with open("/tmp/DE__714P.json", "r") as fh:
content = fh.read() content = fh.read()
else: else:
ssl_context = ssl.create_default_context() ssl_context = ssl.create_default_context()
@ -88,18 +96,26 @@ class WebInterface():
def refresh(self): def refresh(self):
self.log.info("Data refresh") self.log.info("Data refresh")
data = self.bsh_get_data(True) data = self.bsh_get_data(False)
""" #tmpfile = open("/tmp/DE__714P.json", "w")
sql = "INSERT INTO message (msgid, station, content) VALUES (?, ?, ?)" #tmpfile.write(data)
for m in messages: #tmpfile.close()
msg = self.parse_message(m) wvdata = json.loads(data)
self.cur.execute("SELECT COUNT(*) FROM message WHERE msgid=?", (msg['id'],)) sql = "INSERT OR REPLACE INTO data (timestamp, astro, forecast, measurement) VALUES (?, ?, ?, ?)"
result = self.cur.fetchone() for wv in wvdata["curve_forecast"]["data"]:
if result[0] == 0: self.cur.execute(sql, (wv['timestamp'], wv['astro'], wv['curveforecast'], wv['measurement']))
self.log.debug(f"NAVTEX: insert new message '{msg['id']}'") self.conn.commit()
self.cur.execute(sql, (msg['id'], msg['station'], m))
self.conn.commit()
"""
def housekeeping(self): def housekeeping(self):
self.log.info("Housekeeping") self.log.info("Housekeeping")
def get_tide(self):
# 12 Stunden
sql = "select forecast from data where timestamp > '2025-10-05 12:00' and timestamp < '2025-10-06 22:00'"
self.cur.execute(sql)
return self.cur.fetchall()
def get_tide_minmax(self):
sql = "select min(forecast), max(forecast) from data where timestamp > '2025-10-05 12:00' and timestamp < '2025-10-06 22:00'"
self.cur.execute(sql)
return self.cur.fetchone()