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
from web import WebInterface
from tracker import Tracker
from navtex import NAVTEX
@ -14,6 +15,13 @@ class AppData():
self.log = logger
if cfg['navtex']:
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.frontend = None
self.bv_lat = None

View File

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

View File

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

View File

@ -6,7 +6,7 @@ Virtuelles Multifunktionsgerät OBP60v
Zwei Displayvarianten
1. Fliegendes OBP60 auf großem Bildschirm. 400x300 Display
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
einem lokal angeschlossenen GPS-Empfänger.
@ -141,6 +141,7 @@ cfg = {
'gps': False,
'bme280': False,
'tracker': { 'type': 'NONE' },
'tide': False,
'boat': { }
}
@ -798,13 +799,21 @@ if __name__ == "__main__":
config.write(fh)
log.info("Created new boat UUID: {}".format(cfg['boat']['uuid']))
# Globale Daten, u.a. auch Shutdown-Indikator
appdata = AppData(log, cfg)
# Ggf. Simulationsdaten einschalten
if cfg['simulation']:
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
profile = init_profile(config, cfg, boatdata)
@ -834,6 +843,7 @@ if __name__ == "__main__":
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

@ -1,7 +1,6 @@
"""
NAVTEX
- Meldungen anzeigen
Tide Vorausschau
"""
@ -25,6 +24,9 @@ class Tide(Page):
ctx.set_font_size(16)
ctx.set_line_width(2)
ctx.move_to(220, 40)
ctx.show_text("Schulau, Elbe")
x0 = 40 # links unten
y0 = 250
x1 = 380 # rechts oben
@ -48,3 +50,28 @@ class Tide(Page):
self.draw_text_center(ctx, x0 + (x1 - x0) / 2, y0 + 12, "Zeit, h")
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

48
web.py
View File

@ -1,7 +1,7 @@
"""
Web Interface
Regelmäßiges Abfragen von Daten im Internet
Regelmäßiges Abfragen von Daten aus dem Internet
- NAVTEX
- DWD
- Pegelstände
@ -13,7 +13,7 @@ Regelmäßiges Abfragen von Daten im Internet
import os
import http.client
import ssl
import re
import json
import sqlite3
import datetime
from gi.repository import GLib
@ -35,7 +35,14 @@ class WebInterface():
if self.cur.fetchone() == None:
sql = ("CREATE TABLE IF NOT EXISTS station ("
"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.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(60 * 60, self.on_timer)
self.running = True
self.log.info(f"Web interface started")
def __del__(self):
self.conn.close()
@ -62,7 +70,7 @@ class WebInterface():
"""
if local:
# 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()
else:
ssl_context = ssl.create_default_context()
@ -88,18 +96,26 @@ class WebInterface():
def refresh(self):
self.log.info("Data refresh")
data = self.bsh_get_data(True)
"""
sql = "INSERT INTO message (msgid, station, content) VALUES (?, ?, ?)"
for m in messages:
msg = self.parse_message(m)
self.cur.execute("SELECT COUNT(*) FROM message WHERE msgid=?", (msg['id'],))
result = self.cur.fetchone()
if result[0] == 0:
self.log.debug(f"NAVTEX: insert new message '{msg['id']}'")
self.cur.execute(sql, (msg['id'], msg['station'], m))
self.conn.commit()
"""
data = self.bsh_get_data(False)
#tmpfile = open("/tmp/DE__714P.json", "w")
#tmpfile.write(data)
#tmpfile.close()
wvdata = json.loads(data)
sql = "INSERT OR REPLACE INTO data (timestamp, astro, forecast, measurement) VALUES (?, ?, ?, ?)"
for wv in wvdata["curve_forecast"]["data"]:
self.cur.execute(sql, (wv['timestamp'], wv['astro'], wv['curveforecast'], wv['measurement']))
self.conn.commit()
def housekeeping(self):
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()