Zeilenenden vereinheitlichen: LF ueberall ausser im Fremdcode
Bisher entschied jede Arbeitsstation fuer sich, welche Zeilenenden ein Commit bekommt: Git fuer Windows setzt core.autocrlf=input in seiner System-Konfiguration, die NAS setzt nichts. Weil der Bestand ausserdem in sich gemischt war - 34 PHP-Dateien mit LF, 30 mit CRLF -, gab es gar kein richtiges Zeilenende, an das ein Werkzeug sich haette halten koennen. Jede Ergaenzung mit LF in einer CRLF-Datei ergab eine gemischte Datei; helper.php und js/solar/homeMQTT.js waren bereits so entstanden. .gitattributes macht die Zeilenenden zur Eigenschaft des Repositorys. LF, weil dieses Verzeichnis der Web-Ordner der NAS ist und von Linux ausgeliefert wird - und weil Git fuer Windows mit "input" ohnehin schon dorthin zeigt. restricted/WebAuthn bleibt ausgenommen und damit byteweise so, wie die Bibliothek geliefert wurde; darunter liegen 292 Zertifikate. Von den 47 geaenderten Dateien wurde nachgerechnet keine einzige im Inhalt angefasst - der Vergleich HEAD-ohne-CR gegen Index ist ueberall gleich. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,238 +1,238 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Gartenwasser Module
|
||||
Die beiden Ventilsteuerungen und der Regen - 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__)
|
||||
|
||||
# Topic, auf das gatherRainData.py im SolarManager seine Regensummen legt.
|
||||
# Dasselbe Topic steht dort noch einmal im Quelltext. Bewusst kein
|
||||
# Konfigurationseintrag: er müsste in beiden Repositorien gleich lauten, und
|
||||
# eine Einstellung, die man an zwei Orten gleich halten muss, ist keine.
|
||||
REGEN_TOPIC = "Wetter/Regen"
|
||||
|
||||
# Welche Regenfenster als Messwert im Editor auftauchen. gatherRainData.py
|
||||
# veröffentlicht immer tage1 bis tage7; welche davon jemand braucht, entscheidet
|
||||
# allein diese Liste. Die drei Zonen der alten auto_watering.py brauchten 1, 2
|
||||
# und 5 Tage - der Rest steht da, damit eine neue Zone keinen Eingriff im
|
||||
# SolarManager kostet.
|
||||
REGEN_FENSTER = [1, 2, 3, 5, 7]
|
||||
|
||||
# Die beiden ESP32-Ventilsteuerungen. Sie melden sich nicht per
|
||||
# Home-Assistant-Discovery, das MQTT-Modul findet sie also nicht.
|
||||
#
|
||||
# topic Wurzel aller Topics dieser Steuerung
|
||||
# modi Nutzlast des /auto-Topics -> Beschriftung im Editor. Dieselben
|
||||
# Klartexte stehen in der Whitelist von ajax/watering.php.
|
||||
# zonen Ventilnummer -> Name der Zone. Eine Steuerung bedient mehrere
|
||||
# Zonen; "vorn" zum Beispiel Ventil 1 für die Tröge und Ventil 6
|
||||
# für den Garten. Aus jeder Zone werden zwei Messwerte.
|
||||
STEUERUNGEN = [
|
||||
{
|
||||
"name": "Gartenwasser vorn",
|
||||
"topic": "Gartenwasser/vorn",
|
||||
"modi": [{"Trog": "Tröge"}, {"Vorn": "Garten vorn"}, {"Stop": "Stopp"}],
|
||||
"zonen": [(1, "Tröge"), (6, "Garten vorn")],
|
||||
},
|
||||
{
|
||||
"name": "Gartenwasser hinten",
|
||||
"topic": "Gartenwasser/hinten",
|
||||
"modi": [{"Hoch": "Hochbeete"}, {"Stop": "Stopp"}],
|
||||
"zonen": [(6, "Hochbeete")],
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
class GartenwasserModule(BaseModule):
|
||||
"""
|
||||
Gartenwasser Modul - Implementiert BaseModule Interface
|
||||
|
||||
Anders als die übrigen Module sucht dieses nichts, es schreibt drei feste
|
||||
Geräte hin - wie das Logic-Modul auch:
|
||||
|
||||
* Die Ventilsteuerungen sprechen MQTT, aber ohne Home-Assistant-
|
||||
Discovery. Ohne dieses Modul kennt die Datenbank sie nicht, und im
|
||||
Automatik-Editor lässt sich die Bewässerung nicht auswählen.
|
||||
* "Regen" ist gar kein Gerät, sondern das, was gatherRainData.py im
|
||||
SolarManager von Open-Meteo holt.
|
||||
|
||||
Von Hand in die Datenbank geschrieben würden die Zeilen zwar jeden
|
||||
Discovery-Lauf überleben (es wird nur mit ON DUPLICATE KEY UPDATE
|
||||
geschrieben, nie gelöscht), aber niemand wüsste mehr, woher sie kommen.
|
||||
|
||||
Zusammen ersetzt das restricted/gartenbewaesserung/auto_watering.py: die
|
||||
Zeitfenster werden Bedingungen auf Sonnenauf- und -untergang, die
|
||||
Regenschwellen Bedingungen auf "Regen ... Tage", und geschaltet wird über
|
||||
das Kommando "Automatik".
|
||||
|
||||
Zwei Zusagen der Ventilsteuerung stecken in den Messwerten unten, und ohne
|
||||
sie stimmt die Automatik nicht mehr:
|
||||
|
||||
* LastWatering trägt je Ventil ein "daysSinceWatering<n>" - die Anzahl
|
||||
Tage, nicht den Zeitstempel. Das Feld fehlt, solange für ein Ventil
|
||||
keine Bewässerung bekannt ist.
|
||||
* WateringToday wird um Mitternacht zurückgesetzt.
|
||||
* Running sagt retained, ob gerade etwas läuft, und fällt über eine
|
||||
Last-Will-Nachricht auch dann auf false, wenn die Steuerung wegbricht.
|
||||
"""
|
||||
|
||||
def is_enabled(self) -> bool:
|
||||
"""Prüft ob Gartenwasser aktiviert ist"""
|
||||
return self.config.gartenwasser_enable
|
||||
|
||||
def discover(self) -> Tuple[List[Dict], List[Dict]]:
|
||||
"""
|
||||
Erzeugt die beiden Ventilsteuerungen als Actors und den Regen als Sensor
|
||||
|
||||
Returns:
|
||||
Tuple (actors, sensors)
|
||||
"""
|
||||
logger.info("\n" + "=" * 60)
|
||||
logger.info("GARTENWASSER-GERÄTE WERDEN ERZEUGT")
|
||||
logger.info("=" * 60)
|
||||
|
||||
actors = [self._steuerung(s) for s in STEUERUNGEN]
|
||||
sensors = [self._regen()]
|
||||
return actors, sensors
|
||||
|
||||
@staticmethod
|
||||
def _steuerung(steuerung: Dict) -> Dict:
|
||||
"""
|
||||
Eine Ventilsteuerung: ein Kommando, zwei Messwerte je Zone.
|
||||
|
||||
Das Kommando trägt seinen Klartext im Parameter und nicht im Namen.
|
||||
Ein Kommando ohne Parameter schickt im Runner eine leere Nutzlast
|
||||
(siehe MQTTTransport.senden), der Modus muss also der Parameter sein -
|
||||
im Editor liest sich das dann als "Automatik Modus = Hochbeete".
|
||||
"""
|
||||
topic = steuerung["topic"]
|
||||
|
||||
# Läuft an dieser Steuerung gerade etwas? Der Wächter für jede Regel,
|
||||
# die hier etwas anstoßen will - die Zonen einer Steuerung hängen an
|
||||
# derselben Leitung, zwei gleichzeitig gibt es nicht.
|
||||
#
|
||||
# Gelesen wird das aus Running und nicht aus Timers: Timers ist nicht
|
||||
# retained und wird nur im Sekundentakt gesendet, solange etwas läuft.
|
||||
# Der Runner sähe im Ruhezustand gar nichts und behielte nach einem
|
||||
# Lauf den zuletzt gesehenen Wert - also genau das Gegenteil von
|
||||
# verlässlich. Running ist retained und fällt über eine
|
||||
# Last-Will-Nachricht auch dann auf false, wenn die Steuerung mitten
|
||||
# im Gießen wegbricht.
|
||||
states = [{
|
||||
"name": "Bewässerung läuft",
|
||||
"url": topic + "/Running",
|
||||
"value_path": "running",
|
||||
"type": "bool",
|
||||
}, {
|
||||
# Klartext der laufenden Automatik ("Hoch", "Trog", "Vorn"), leer
|
||||
# wenn von Hand oder gar nicht bewässert wird.
|
||||
"name": "Laufender Modus",
|
||||
"url": topic + "/Running",
|
||||
"value_path": "mode",
|
||||
"type": "string",
|
||||
}]
|
||||
|
||||
for valve, zone in steuerung["zonen"]:
|
||||
if len(steuerung["zonen"]) > 1:
|
||||
# Bei einer Steuerung mit nur einer Zone wäre das derselbe Wert
|
||||
# wie "Bewässerung läuft" - ein zweiter Messwert, der nie etwas
|
||||
# anderes sagt, macht die Auswahl nur länger.
|
||||
states.append({
|
||||
"name": "Bewässerung läuft " + zone,
|
||||
"url": topic + "/Running",
|
||||
"value_path": "running%d" % valve,
|
||||
"type": "bool",
|
||||
})
|
||||
states.append({
|
||||
# Ersetzt die Zwölf-Stunden-Sperre von auto_watering.py:
|
||||
# "heute noch nicht bewässert" heißt hier schlicht "= 0".
|
||||
#
|
||||
# Dass das trägt, liegt an der Steuerung: sie setzt den Wert um
|
||||
# Mitternacht zurück. Die Nachricht ist retained, und der Runner
|
||||
# sieht nur die Zahl hinter dem value_path - den Tag, den die
|
||||
# Nutzlast als "wateringDay" mitführt, kann er nicht prüfen.
|
||||
# Ohne den Reset stünde nach einer bewässerungsfreien Nacht die
|
||||
# Summe von gestern als "heute" da, und die Zone bliebe trocken.
|
||||
"name": "Bewässert heute " + zone,
|
||||
"url": topic + "/WateringToday",
|
||||
"value_path": "wateringDurationTodaySecs%d" % valve,
|
||||
"type": "integer",
|
||||
"unit": "s",
|
||||
})
|
||||
states.append({
|
||||
# Der Trockenheits-Notlauf (max_dry_days in auto_watering.py).
|
||||
# Ein Zeitstempel nützte hier nichts: der Runner vergleicht
|
||||
# Datumsangaben nur gegen einen festen Wert, "länger als fünf
|
||||
# Tage her" ist damit nicht formulierbar. Die Steuerung liefert
|
||||
# deshalb gleich die Anzahl Tage - dafür wurde ihre Firmware
|
||||
# erweitert, das Feld gab es vorher nicht.
|
||||
#
|
||||
# Für ein Ventil, das noch nie lief, lässt sie das Feld weg
|
||||
# statt eine 0 zu schicken. Eine 0 hieße "heute bewässert" und
|
||||
# würde den Notlauf für immer unterdrücken; ohne Feld bleibt
|
||||
# der Messwert leer, und die Bedingung greift schlicht nicht.
|
||||
"name": "Tage seit Bewässerung " + zone,
|
||||
"url": topic + "/LastWatering",
|
||||
"value_path": "daysSinceWatering%d" % valve,
|
||||
"type": "integer",
|
||||
"unit": "Tage",
|
||||
})
|
||||
|
||||
return {
|
||||
"type": "Bewässerung",
|
||||
"name": steuerung["name"],
|
||||
"url": "mqtt://" + topic,
|
||||
"commands": [{
|
||||
"command": "Automatik",
|
||||
"url": topic + "/auto",
|
||||
"parameters": [{
|
||||
"name": "Modus",
|
||||
"type": "string",
|
||||
"url": topic + "/auto",
|
||||
"values": steuerung["modi"],
|
||||
}],
|
||||
}],
|
||||
"states": states,
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def _regen() -> Dict:
|
||||
"""
|
||||
Der Regen als Gerät: je Zeitraum ein Messwert, dazu der Stand.
|
||||
|
||||
"Regen heute" ist der bereits gefallene Regen des laufenden Tages, die
|
||||
übrigen zählen ihn plus die abgeschlossenen Tage davor - so hat auch
|
||||
auto_watering.py gerechnet.
|
||||
|
||||
Der Stand ist kein Messwert zum Vergleichen, sondern zum Nachsehen: im
|
||||
Editor steht er hinter dem Namen ("= 04.09.2026 09:00:00") und verrät,
|
||||
ob der Sammler noch läuft. Bleibt er länger aus, leert gatherRainData.py
|
||||
die Zahlen von sich aus, und die Bewässerung setzt aus.
|
||||
"""
|
||||
states = [{
|
||||
"name": "Regen heute" if tage == 1 else "Regen %d Tage" % tage,
|
||||
"url": REGEN_TOPIC,
|
||||
"value_path": "tage%d" % tage,
|
||||
"type": "float",
|
||||
"unit": "mm",
|
||||
} for tage in REGEN_FENSTER]
|
||||
|
||||
states.append({
|
||||
"name": "Stand",
|
||||
"url": REGEN_TOPIC,
|
||||
"value_path": "stand",
|
||||
"type": "string",
|
||||
})
|
||||
|
||||
return {
|
||||
"type": "Wetter",
|
||||
"name": "Regen",
|
||||
"url": "mqtt://" + REGEN_TOPIC,
|
||||
"states": states,
|
||||
}
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Gartenwasser Module
|
||||
Die beiden Ventilsteuerungen und der Regen - 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__)
|
||||
|
||||
# Topic, auf das gatherRainData.py im SolarManager seine Regensummen legt.
|
||||
# Dasselbe Topic steht dort noch einmal im Quelltext. Bewusst kein
|
||||
# Konfigurationseintrag: er müsste in beiden Repositorien gleich lauten, und
|
||||
# eine Einstellung, die man an zwei Orten gleich halten muss, ist keine.
|
||||
REGEN_TOPIC = "Wetter/Regen"
|
||||
|
||||
# Welche Regenfenster als Messwert im Editor auftauchen. gatherRainData.py
|
||||
# veröffentlicht immer tage1 bis tage7; welche davon jemand braucht, entscheidet
|
||||
# allein diese Liste. Die drei Zonen der alten auto_watering.py brauchten 1, 2
|
||||
# und 5 Tage - der Rest steht da, damit eine neue Zone keinen Eingriff im
|
||||
# SolarManager kostet.
|
||||
REGEN_FENSTER = [1, 2, 3, 5, 7]
|
||||
|
||||
# Die beiden ESP32-Ventilsteuerungen. Sie melden sich nicht per
|
||||
# Home-Assistant-Discovery, das MQTT-Modul findet sie also nicht.
|
||||
#
|
||||
# topic Wurzel aller Topics dieser Steuerung
|
||||
# modi Nutzlast des /auto-Topics -> Beschriftung im Editor. Dieselben
|
||||
# Klartexte stehen in der Whitelist von ajax/watering.php.
|
||||
# zonen Ventilnummer -> Name der Zone. Eine Steuerung bedient mehrere
|
||||
# Zonen; "vorn" zum Beispiel Ventil 1 für die Tröge und Ventil 6
|
||||
# für den Garten. Aus jeder Zone werden zwei Messwerte.
|
||||
STEUERUNGEN = [
|
||||
{
|
||||
"name": "Gartenwasser vorn",
|
||||
"topic": "Gartenwasser/vorn",
|
||||
"modi": [{"Trog": "Tröge"}, {"Vorn": "Garten vorn"}, {"Stop": "Stopp"}],
|
||||
"zonen": [(1, "Tröge"), (6, "Garten vorn")],
|
||||
},
|
||||
{
|
||||
"name": "Gartenwasser hinten",
|
||||
"topic": "Gartenwasser/hinten",
|
||||
"modi": [{"Hoch": "Hochbeete"}, {"Stop": "Stopp"}],
|
||||
"zonen": [(6, "Hochbeete")],
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
class GartenwasserModule(BaseModule):
|
||||
"""
|
||||
Gartenwasser Modul - Implementiert BaseModule Interface
|
||||
|
||||
Anders als die übrigen Module sucht dieses nichts, es schreibt drei feste
|
||||
Geräte hin - wie das Logic-Modul auch:
|
||||
|
||||
* Die Ventilsteuerungen sprechen MQTT, aber ohne Home-Assistant-
|
||||
Discovery. Ohne dieses Modul kennt die Datenbank sie nicht, und im
|
||||
Automatik-Editor lässt sich die Bewässerung nicht auswählen.
|
||||
* "Regen" ist gar kein Gerät, sondern das, was gatherRainData.py im
|
||||
SolarManager von Open-Meteo holt.
|
||||
|
||||
Von Hand in die Datenbank geschrieben würden die Zeilen zwar jeden
|
||||
Discovery-Lauf überleben (es wird nur mit ON DUPLICATE KEY UPDATE
|
||||
geschrieben, nie gelöscht), aber niemand wüsste mehr, woher sie kommen.
|
||||
|
||||
Zusammen ersetzt das restricted/gartenbewaesserung/auto_watering.py: die
|
||||
Zeitfenster werden Bedingungen auf Sonnenauf- und -untergang, die
|
||||
Regenschwellen Bedingungen auf "Regen ... Tage", und geschaltet wird über
|
||||
das Kommando "Automatik".
|
||||
|
||||
Zwei Zusagen der Ventilsteuerung stecken in den Messwerten unten, und ohne
|
||||
sie stimmt die Automatik nicht mehr:
|
||||
|
||||
* LastWatering trägt je Ventil ein "daysSinceWatering<n>" - die Anzahl
|
||||
Tage, nicht den Zeitstempel. Das Feld fehlt, solange für ein Ventil
|
||||
keine Bewässerung bekannt ist.
|
||||
* WateringToday wird um Mitternacht zurückgesetzt.
|
||||
* Running sagt retained, ob gerade etwas läuft, und fällt über eine
|
||||
Last-Will-Nachricht auch dann auf false, wenn die Steuerung wegbricht.
|
||||
"""
|
||||
|
||||
def is_enabled(self) -> bool:
|
||||
"""Prüft ob Gartenwasser aktiviert ist"""
|
||||
return self.config.gartenwasser_enable
|
||||
|
||||
def discover(self) -> Tuple[List[Dict], List[Dict]]:
|
||||
"""
|
||||
Erzeugt die beiden Ventilsteuerungen als Actors und den Regen als Sensor
|
||||
|
||||
Returns:
|
||||
Tuple (actors, sensors)
|
||||
"""
|
||||
logger.info("\n" + "=" * 60)
|
||||
logger.info("GARTENWASSER-GERÄTE WERDEN ERZEUGT")
|
||||
logger.info("=" * 60)
|
||||
|
||||
actors = [self._steuerung(s) for s in STEUERUNGEN]
|
||||
sensors = [self._regen()]
|
||||
return actors, sensors
|
||||
|
||||
@staticmethod
|
||||
def _steuerung(steuerung: Dict) -> Dict:
|
||||
"""
|
||||
Eine Ventilsteuerung: ein Kommando, zwei Messwerte je Zone.
|
||||
|
||||
Das Kommando trägt seinen Klartext im Parameter und nicht im Namen.
|
||||
Ein Kommando ohne Parameter schickt im Runner eine leere Nutzlast
|
||||
(siehe MQTTTransport.senden), der Modus muss also der Parameter sein -
|
||||
im Editor liest sich das dann als "Automatik Modus = Hochbeete".
|
||||
"""
|
||||
topic = steuerung["topic"]
|
||||
|
||||
# Läuft an dieser Steuerung gerade etwas? Der Wächter für jede Regel,
|
||||
# die hier etwas anstoßen will - die Zonen einer Steuerung hängen an
|
||||
# derselben Leitung, zwei gleichzeitig gibt es nicht.
|
||||
#
|
||||
# Gelesen wird das aus Running und nicht aus Timers: Timers ist nicht
|
||||
# retained und wird nur im Sekundentakt gesendet, solange etwas läuft.
|
||||
# Der Runner sähe im Ruhezustand gar nichts und behielte nach einem
|
||||
# Lauf den zuletzt gesehenen Wert - also genau das Gegenteil von
|
||||
# verlässlich. Running ist retained und fällt über eine
|
||||
# Last-Will-Nachricht auch dann auf false, wenn die Steuerung mitten
|
||||
# im Gießen wegbricht.
|
||||
states = [{
|
||||
"name": "Bewässerung läuft",
|
||||
"url": topic + "/Running",
|
||||
"value_path": "running",
|
||||
"type": "bool",
|
||||
}, {
|
||||
# Klartext der laufenden Automatik ("Hoch", "Trog", "Vorn"), leer
|
||||
# wenn von Hand oder gar nicht bewässert wird.
|
||||
"name": "Laufender Modus",
|
||||
"url": topic + "/Running",
|
||||
"value_path": "mode",
|
||||
"type": "string",
|
||||
}]
|
||||
|
||||
for valve, zone in steuerung["zonen"]:
|
||||
if len(steuerung["zonen"]) > 1:
|
||||
# Bei einer Steuerung mit nur einer Zone wäre das derselbe Wert
|
||||
# wie "Bewässerung läuft" - ein zweiter Messwert, der nie etwas
|
||||
# anderes sagt, macht die Auswahl nur länger.
|
||||
states.append({
|
||||
"name": "Bewässerung läuft " + zone,
|
||||
"url": topic + "/Running",
|
||||
"value_path": "running%d" % valve,
|
||||
"type": "bool",
|
||||
})
|
||||
states.append({
|
||||
# Ersetzt die Zwölf-Stunden-Sperre von auto_watering.py:
|
||||
# "heute noch nicht bewässert" heißt hier schlicht "= 0".
|
||||
#
|
||||
# Dass das trägt, liegt an der Steuerung: sie setzt den Wert um
|
||||
# Mitternacht zurück. Die Nachricht ist retained, und der Runner
|
||||
# sieht nur die Zahl hinter dem value_path - den Tag, den die
|
||||
# Nutzlast als "wateringDay" mitführt, kann er nicht prüfen.
|
||||
# Ohne den Reset stünde nach einer bewässerungsfreien Nacht die
|
||||
# Summe von gestern als "heute" da, und die Zone bliebe trocken.
|
||||
"name": "Bewässert heute " + zone,
|
||||
"url": topic + "/WateringToday",
|
||||
"value_path": "wateringDurationTodaySecs%d" % valve,
|
||||
"type": "integer",
|
||||
"unit": "s",
|
||||
})
|
||||
states.append({
|
||||
# Der Trockenheits-Notlauf (max_dry_days in auto_watering.py).
|
||||
# Ein Zeitstempel nützte hier nichts: der Runner vergleicht
|
||||
# Datumsangaben nur gegen einen festen Wert, "länger als fünf
|
||||
# Tage her" ist damit nicht formulierbar. Die Steuerung liefert
|
||||
# deshalb gleich die Anzahl Tage - dafür wurde ihre Firmware
|
||||
# erweitert, das Feld gab es vorher nicht.
|
||||
#
|
||||
# Für ein Ventil, das noch nie lief, lässt sie das Feld weg
|
||||
# statt eine 0 zu schicken. Eine 0 hieße "heute bewässert" und
|
||||
# würde den Notlauf für immer unterdrücken; ohne Feld bleibt
|
||||
# der Messwert leer, und die Bedingung greift schlicht nicht.
|
||||
"name": "Tage seit Bewässerung " + zone,
|
||||
"url": topic + "/LastWatering",
|
||||
"value_path": "daysSinceWatering%d" % valve,
|
||||
"type": "integer",
|
||||
"unit": "Tage",
|
||||
})
|
||||
|
||||
return {
|
||||
"type": "Bewässerung",
|
||||
"name": steuerung["name"],
|
||||
"url": "mqtt://" + topic,
|
||||
"commands": [{
|
||||
"command": "Automatik",
|
||||
"url": topic + "/auto",
|
||||
"parameters": [{
|
||||
"name": "Modus",
|
||||
"type": "string",
|
||||
"url": topic + "/auto",
|
||||
"values": steuerung["modi"],
|
||||
}],
|
||||
}],
|
||||
"states": states,
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def _regen() -> Dict:
|
||||
"""
|
||||
Der Regen als Gerät: je Zeitraum ein Messwert, dazu der Stand.
|
||||
|
||||
"Regen heute" ist der bereits gefallene Regen des laufenden Tages, die
|
||||
übrigen zählen ihn plus die abgeschlossenen Tage davor - so hat auch
|
||||
auto_watering.py gerechnet.
|
||||
|
||||
Der Stand ist kein Messwert zum Vergleichen, sondern zum Nachsehen: im
|
||||
Editor steht er hinter dem Namen ("= 04.09.2026 09:00:00") und verrät,
|
||||
ob der Sammler noch läuft. Bleibt er länger aus, leert gatherRainData.py
|
||||
die Zahlen von sich aus, und die Bewässerung setzt aus.
|
||||
"""
|
||||
states = [{
|
||||
"name": "Regen heute" if tage == 1 else "Regen %d Tage" % tage,
|
||||
"url": REGEN_TOPIC,
|
||||
"value_path": "tage%d" % tage,
|
||||
"type": "float",
|
||||
"unit": "mm",
|
||||
} for tage in REGEN_FENSTER]
|
||||
|
||||
states.append({
|
||||
"name": "Stand",
|
||||
"url": REGEN_TOPIC,
|
||||
"value_path": "stand",
|
||||
"type": "string",
|
||||
})
|
||||
|
||||
return {
|
||||
"type": "Wetter",
|
||||
"name": "Regen",
|
||||
"url": "mqtt://" + REGEN_TOPIC,
|
||||
"states": states,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user