Wetterstation erkennen, Einheiten nicht mehr ueberschreiben
Die Station haengt laengst am Websocket und wsMQTTbridge.py legt ihre Felder unter weatherStation/# ab - nur wusste die Automatikdatenbank nichts davon. Das neue Modul macht daraus ein Geraet mit elf Messwerten: Aussentemperatur, Taupunkt, Feuchte, Druck, Wind, Boe und die beiden Richtungen. Wie das Gartenwasser- und das SolarManager-Modul sucht es nichts, sondern schreibt ein festes Geraet hin; die Station meldet sich nicht per Home-Assistant-Discovery. Gebraucht wird sie fuer den Hitzeschutz: dafuer ist die Aussentemperatur die bessere Bedingung als die Raumtemperatur - ist es drinnen schon warm, ist es zum Verschatten zu spaet. Und Wind gab es hier bisher ueberhaupt nicht; ohne ihn laesst sich fuer Markise und Sonnensegel kein Sturmschutz bauen. Nicht dabei sind zwei Topics. IP ist keine Messung. Und QNH steht bei uns gut hundert Hektopascal neben qff (1133 gegen 1023) und ist offenbar nicht auf die Stationshoehe eingestellt - zwei Druecke nebeneinander, von denen einer falsch ist, waeren im Editor eine Falle. Dabei aufgefallen: der UPSERT schrieb unit = VALUES(unit) bedingungslos. Ein Modul, das keine Einheit mitliefert, meint aber "weiss ich nicht" und nicht "loesch die vorhandene" - am 10.09. hat ein Suchlauf den drei Sonnensensoren ihr "Lux" genommen, weil das Tahoma-Modul keine Einheiten kennt. Jetzt COALESCE, wie bei current_value schon laenger. config.ini liegt nicht im Git; der Abschnitt [wetterstation] muss dort von Hand stehen, sonst bleibt das Modul aus. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Wetterstation Module
|
||||
Die eigene Wetterstation am Haus - fest beschrieben, nicht gesucht
|
||||
KEINE Datenbank-Operationen!
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import List, Dict, Tuple
|
||||
from modules.base_module import BaseModule
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Wurzel aller Topics. wsMQTTbridge.py im SolarManager hängt am Websocket der
|
||||
# Station (ws://192.168.179.42/ws) und legt jedes Feld der Nachricht einzeln
|
||||
# unter diese Wurzel - retained, deshalb hat ein frisch verbundener Leser
|
||||
# sofort alle Werte.
|
||||
#
|
||||
# Zwei Eigenheiten der Brücke, die man kennen muss:
|
||||
#
|
||||
# * Die trägen Werte gehen nicht bei jeder Nachricht raus. Die Brücke wirft
|
||||
# tempAmb, hum, qff, dewpt, iaq, avgWindspeed und avgWindDeg aus jeder
|
||||
# Nachricht heraus außer jeder einundzwanzigsten. Wind und Böe kommen
|
||||
# dagegen immer. Für eine Automatik macht das keinen Unterschied - der
|
||||
# Runner hält den zuletzt gesehenen Wert -, für die Fehlersuche schon:
|
||||
# eine Außentemperatur, die minutenlang steht, ist kein Ausfall.
|
||||
#
|
||||
# * Der Zeitstempel kommt von der Station selbst, nicht vom Broker.
|
||||
WURZEL = "weatherStation"
|
||||
|
||||
# Was von der Station als Messwert im Editor auftaucht.
|
||||
#
|
||||
# Nicht dabei sind zwei Topics. "IP" ist keine Messung. Und "QNH [hPa]" ist
|
||||
# der auf Meereshöhe gerechnete Druck nach Standardatmosphäre - er steht bei
|
||||
# uns gut hundert Hektopascal neben qff (1133 gegen 1023) und ist offenbar
|
||||
# nicht auf die Stationshöhe eingestellt. qff rechnet mit der tatsächlichen
|
||||
# Temperatur und ist der Wert, den auch die Wetterkachel auf der Startseite
|
||||
# zeigt. Zwei Drücke nebeneinander, von denen einer falsch ist, wären im
|
||||
# Editor eine Falle.
|
||||
#
|
||||
# Die Windgeschwindigkeiten stehen in km/h - so beschriftet sie
|
||||
# restricted/weather_cards.html, und so passen die Zahlen zur Historie in
|
||||
# solarLog.weatherStation.
|
||||
#
|
||||
# Windrichtung und Böenrichtung sind Grad im Uhrzeigersinn ab Nord, wie beim
|
||||
# Kompass: 0 = aus Norden, 90 = aus Osten, 180 = aus Süden, 270 = aus Westen.
|
||||
# Eine Bedingung darauf ist unhandlich, weil Nord bei 0 und bei 360 liegt -
|
||||
# für "Wind aus Westen" schreibt man zwei Bedingungen (> 225 und < 315).
|
||||
MESSWERTE = [
|
||||
# (Name im Editor, Topic, Typ, Einheit)
|
||||
("Außentemperatur", "tempAmb", "float", "°C"),
|
||||
("Luftfeuchte", "hum", "float", "%"),
|
||||
("Taupunkt", "dewpt", "float", "°C"),
|
||||
("Luftdruck", "qff", "float", "hPa"),
|
||||
("Wind", "windspeed", "float", "km/h"),
|
||||
("Wind im Mittel", "avgWindspeed", "float", "km/h"),
|
||||
("Böe", "maxgust", "float", "km/h"),
|
||||
("Windrichtung", "windDeg", "float", "°"),
|
||||
("Böenrichtung", "gustDeg", "float", "°"),
|
||||
("Luftgüte", "iaq", "float", None),
|
||||
# Kein Wert zum Vergleichen, sondern zum Nachsehen: im Editor steht er
|
||||
# hinter dem Namen und verrät, ob die Brücke noch läuft. Genauso hält es
|
||||
# der Regen mit seinem "Stand".
|
||||
("Stand", "Timestamp", "string", None),
|
||||
]
|
||||
|
||||
|
||||
class WetterstationModule(BaseModule):
|
||||
"""
|
||||
Wetterstation - Implementiert BaseModule Interface
|
||||
|
||||
Wie das Gartenwasser-, das Logic- und das SolarManager-Modul sucht dieses
|
||||
nichts, sondern schreibt ein festes Gerät hin. Die Station meldet sich
|
||||
nicht per Home-Assistant-Discovery; das MQTT-Modul findet sie also nicht.
|
||||
|
||||
Warum sie überhaupt hineingehört: für den Hitzeschutz ist die
|
||||
Außentemperatur die bessere Bedingung als die Raumtemperatur. Wenn es
|
||||
drinnen schon warm ist, ist es zum Verschatten zu spät - die Wärme steht
|
||||
dann bereits im Raum und muss wieder heraus. Draußen sieht man sie
|
||||
kommen. Und Wind gab es hier bisher gar nicht: ohne ihn lässt sich für
|
||||
Markise und Sonnensegel kein Sturmschutz bauen.
|
||||
|
||||
Alles hier ist zum Lesen. Zu schalten gibt es an einer Wetterstation
|
||||
nichts.
|
||||
"""
|
||||
|
||||
def is_enabled(self) -> bool:
|
||||
"""Prüft ob das Wetterstation-Modul aktiviert ist"""
|
||||
return self.config.wetterstation_enable
|
||||
|
||||
def discover(self) -> Tuple[List[Dict], List[Dict]]:
|
||||
"""
|
||||
Erzeugt das eine Gerät aus MESSWERTE - als Sensor, ohne Kommandos.
|
||||
|
||||
Returns:
|
||||
Tuple (actors, sensors)
|
||||
"""
|
||||
logger.info("\n" + "=" * 60)
|
||||
logger.info("WETTERSTATION WIRD ERZEUGT")
|
||||
logger.info("=" * 60)
|
||||
|
||||
states = [{
|
||||
"name": name,
|
||||
"url": WURZEL + "/" + topic,
|
||||
"type": typ,
|
||||
"unit": einheit,
|
||||
} for name, topic, typ, einheit in MESSWERTE]
|
||||
|
||||
geraet = {
|
||||
"type": "Wetter",
|
||||
"name": "Wetterstation",
|
||||
# Die URL eines Geräts ist das Topic seines ersten Messwerts, wie
|
||||
# beim SolarManager. Sie muss nur eindeutig sein und mit mqtt://
|
||||
# beginnen, damit der Runner den MQTT-Transport wählt; abonniert
|
||||
# wird über die Topics der Messwerte.
|
||||
"url": "mqtt://" + states[0]["url"],
|
||||
"states": states,
|
||||
}
|
||||
|
||||
logger.info("1 Gerät mit %d Messwerten", len(states))
|
||||
return [], [geraet]
|
||||
Reference in New Issue
Block a user