Setup-Menü für Sensor-Zuordnung + Umstellung von WLAN/VAG-Integration auf FMM003
Setup-Menü (Einstellungen -> Fahrzeug einrichten -> Setup): ordnet alle von der App genutzten Sensor-Rollen echten HA-Entitäten zu, statt sie in einstellungen.py von Hand einzutragen - durchsuchbares Dropdown je Feld, Vorauswahl aus vorhandenen Entitäten, Schalter für "nur passende Sensoren". Neues Modul entitaeten.py (Katalog + JSON-Override, zur Laufzeit über setattr() auf einstellungen angewendet, kein Neustart nötig außer für die drei trigger-gebundenen Felder). Zusätzlich: Fahrzeug-WLAN-Erkennung und alle Entity-IDs der nicht mehr genutzten TommiG1/HA_VAG-EU-Data-Act-Integration entfernt. Fahrterkennung läuft jetzt über den Zündungs-/ACC-Status des neu angebundenen Teltonika FMM003 (ersetzt die WLAN-Verbindungserkennung); Standort und 12V- Batteriespannung kommen ebenfalls vom FMM003. Kilometerstand, Tankfüllstand, Reichweite, Türen/Fenster/Schlösser sowie Ölwechsel-/Inspektionsdaten haben dadurch vorerst keine Quelle mehr und zeigen "unbekannt" - die Funktionen selbst bleiben erhalten und lassen sich über das neue Setup-Menü jederzeit neu zuordnen. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -7,106 +7,85 @@ des Fahrzeugprofils (data/fahrzeugprofil.json) und über die Oberfläche
|
||||
Fahrzeugstatus-Abfrage brauchen sie als festen Wert, bevor überhaupt ein
|
||||
Profil gelesen werden kann.
|
||||
|
||||
In Home Assistant unter Entwicklerwerkzeuge -> Zustände nachschlagen.
|
||||
In Home Assistant unter Entwicklerwerkzeuge -> Zustände nachschlagen. Werte
|
||||
lassen sich außerdem über das Setup-Menü in der Oberfläche zuordnen (siehe
|
||||
entitaeten.py) - Änderungen von dort werden zur Laufzeit auf diese Variablen
|
||||
angewendet (überschreiben also die hier hinterlegten Standardwerte), ohne
|
||||
diese Datei anzufassen.
|
||||
|
||||
Die drei ersten (WLAN, Kilometerstand, Tankfüllstand) werden vom Backend
|
||||
zwingend gebraucht (§7.1, §7.2, §7.4, §7.5). Alles danach speist nur die
|
||||
Übersicht im Frontend (§5.1, §5.2, §9) — bleibt ein Wert leer ("") oder passt
|
||||
eine Entity-ID nicht zur tatsächlichen Integration, liefert
|
||||
zustand_oder_none() in frontend_veroeffentlichung.py für das jeweilige Feld
|
||||
None statt abzustürzen; die Oberfläche zeigt dann „unbekannt" statt eines
|
||||
falschen Werts.
|
||||
|
||||
Alle Entity-IDs unten sind an der echten Integration TommiG1/HA_VAG-EU-Data-Act
|
||||
(Version 0.6.35, per HACS installiert) real geprüft, nicht nur vermutet: das
|
||||
Gerät heißt dort "Audi RS 4 Avant" (mit Leerzeichen vor der "4") - deshalb
|
||||
"rs_4" mit Unterstrich im Slug, nicht "rs4". Eine ältere Integrationsversion
|
||||
hatte hier noch deutsche Feldnamen (z. B. "..._tur_vorne_links"); die aktuelle
|
||||
Version benennt englisch (z. B. "..._front_left_door").
|
||||
2026-08-12: Die HACS-Integration TommiG1/HA_VAG-EU-Data-Act (bisherige
|
||||
Quelle für Kilometerstand, Tankfüllstand, Türen/Fenster/Schlösser,
|
||||
Ölwechsel-/Inspektionsdaten) wird nicht mehr verwendet - die zugehörigen
|
||||
Entity-IDs sind deshalb unten bewusst leer. Neue Datenquelle ist der
|
||||
Teltonika FMM003 (GPS-Tracker mit CAN-Anbindung, siehe AGENTS.md Abschnitt
|
||||
B); er liefert Standort, Zündungsstatus und Batteriespannung, aber keinen
|
||||
Tankfüllstand, keine Tür-/Fenster-/Schlossdaten und keine Ölwechsel-/
|
||||
Inspektionstermine - die entsprechenden Kacheln zeigen deshalb bis auf
|
||||
Weiteres "unbekannt" statt eines falschen Werts (siehe zustand_oder_none()
|
||||
in frontend_veroeffentlichung.py). Bleibt ein Wert leer ("") oder passt eine
|
||||
Entity-ID nicht zur tatsächlichen Integration, liefert zustand_oder_none()
|
||||
für das jeweilige Feld None statt abzustürzen.
|
||||
"""
|
||||
|
||||
# Companion-App-Sensor für das aktuell verbundene WLAN (iOS-App:
|
||||
# Einstellungen -> Companion App -> Sensoren -> "Verbundenes WLAN")
|
||||
WLAN_SENSOR = "sensor.iphone_wifi_connection"
|
||||
# Fahrterkennung (§7.1): Start/Ende einer Fahrt wird über den Zündungs-/ACC-
|
||||
# Status des FMM003 erkannt (on = Fahrt läuft), nicht mehr über die WLAN-
|
||||
# Verbindung des iPhones zum Fahrzeug (siehe fahrterkennung.py).
|
||||
ZUENDUNG_SENSOR = "binary_sensor.testzone_fmm003_engine_ignition_or_acc_status"
|
||||
|
||||
# Kilometerstand aus der HACS-Integration TommiG1/HA_VAG-EU-Data-Act
|
||||
KM_SENSOR = "sensor.audi_rs_4_avant_mileage"
|
||||
# Kilometerstand - bisher aus der TommiG1-Integration, aktuell keine Quelle
|
||||
# vorhanden. Der FMM003 liefert unter sensor.testzone_fmm003_total_calculated_mileage
|
||||
# einen selbst berechneten Wert, der aber auf einer anderen Zählbasis beruht
|
||||
# als der echte Fahrzeug-Kilometerstand (GPS-Streckenberechnung statt
|
||||
# Tacho) - bewusst NICHT automatisch übernommen, um Reifenzähler,
|
||||
# Ölwechsel-Prognose und Fahrtabschluss-Screening nicht mit einem
|
||||
# inkonsistenten Basiswert zu verfälschen. Bei Bedarf über das Setup-Menü
|
||||
# gezielt zuordnen.
|
||||
KM_SENSOR = ""
|
||||
|
||||
# Tankfüllstand aus derselben Integration (Prozent)
|
||||
TANK_SENSOR = "sensor.audi_rs_4_avant_fuel_level"
|
||||
# Tankfüllstand (Prozent) - keine Quelle mehr vorhanden (der FMM003 ist kein
|
||||
# Tankgeber).
|
||||
TANK_SENSOR = ""
|
||||
|
||||
# Reichweite (§5.1 Übersicht)
|
||||
RANGE_SENSOR = "sensor.audi_rs_4_avant_range_primary"
|
||||
# Reichweite (§5.1 Übersicht) - keine Quelle mehr vorhanden.
|
||||
RANGE_SENSOR = ""
|
||||
|
||||
# 12V-Batteriespannung (Mein Audi -> Zustand). Die aktuell genutzte
|
||||
# HACS-Integration (TommiG1/HA_VAG-EU-Data-Act 0.6.35) liefert dafür KEINEN
|
||||
# Sensor (real geprüft: kein "battery"/"voltage"-Entity unter diesem Gerät) -
|
||||
# deshalb hier bewusst leer gelassen. Liefert später eine andere Quelle (z. B.
|
||||
# ein OBD-Adapter) eine Spannung, einfach die Entity-ID eintragen; bis dahin
|
||||
# zeigt die Oberfläche "unbekannt" statt eines falschen Werts (siehe
|
||||
# zustand_oder_none() in frontend_veroeffentlichung.py).
|
||||
BATTERIE_SENSOR = ""
|
||||
# 12V-Batteriespannung (Mein Audi -> Zustand). Vom FMM003 geliefert -
|
||||
# external_power_voltage ist die vom Gerät gemessene Bordnetzspannung des
|
||||
# Fahrzeugs, NICHT battery_voltage (das ist die interne Pufferbatterie des
|
||||
# Trackers selbst und hat mit der Fahrzeugbatterie nichts zu tun).
|
||||
BATTERIE_SENSOR = "sensor.testzone_fmm003_external_power_voltage"
|
||||
|
||||
# Der von der Integration selbst bereitgestellte Knopf für eine sofortige
|
||||
# Neuabfrage beim Fahrzeug (Entity-Domäne "button", real geprüft) - genau der
|
||||
# Weg, den "Ziehen zum Aktualisieren" im Frontend auslöst (siehe
|
||||
# audi_dashboard_jetzt_aktualisieren() in frontend_api.py), statt eines
|
||||
# generischen homeassistant.update_entity auf einzelne Sensoren.
|
||||
REFRESH_BUTTON = "button.audi_rs_4_avant_refresh_now"
|
||||
# Knopf für eine sofortige Neuabfrage beim Fahrzeug - kam aus der
|
||||
# TommiG1-Integration, keine Entsprechung beim FMM003 vorhanden.
|
||||
REFRESH_BUTTON = ""
|
||||
|
||||
# Türen (§4.1) - die Integration liefert vier Einzelsensoren statt eines
|
||||
# Summensensors. binary_sensor, device_class "door": "off" = zu (real
|
||||
# geprüft).
|
||||
TUER_SENSOREN = [
|
||||
"binary_sensor.audi_rs_4_avant_front_left_door",
|
||||
"binary_sensor.audi_rs_4_avant_front_right_door",
|
||||
"binary_sensor.audi_rs_4_avant_rear_left_door",
|
||||
"binary_sensor.audi_rs_4_avant_rear_right_door",
|
||||
]
|
||||
# Türen (§4.1) - keine Quelle mehr vorhanden.
|
||||
TUER_SENSOREN = []
|
||||
|
||||
# Fenster (§4.1) - device_class "window": "off" = zu (real geprüft)
|
||||
FENSTER_SENSOREN = [
|
||||
"binary_sensor.audi_rs_4_avant_front_left_window",
|
||||
"binary_sensor.audi_rs_4_avant_front_right_window",
|
||||
"binary_sensor.audi_rs_4_avant_rear_left_window",
|
||||
"binary_sensor.audi_rs_4_avant_rear_right_window",
|
||||
]
|
||||
# Fenster (§4.1) - keine Quelle mehr vorhanden.
|
||||
FENSTER_SENSOREN = []
|
||||
|
||||
# Verriegelung - kein lock.*-Entity vorhanden, sondern vier
|
||||
# Türschloss-Einzelsensoren. binary_sensor mit device_class "lock" (real
|
||||
# geprüft): "on" = entriegelt, "off" = verriegelt (Home-Assistant-Konvention
|
||||
# für diese device_class).
|
||||
TUERSCHLOSS_SENSOREN = [
|
||||
"binary_sensor.audi_rs_4_avant_front_left_door_lock",
|
||||
"binary_sensor.audi_rs_4_avant_front_right_door_lock",
|
||||
"binary_sensor.audi_rs_4_avant_rear_left_door_lock",
|
||||
"binary_sensor.audi_rs_4_avant_rear_right_door_lock",
|
||||
]
|
||||
# Verriegelung - keine Quelle mehr vorhanden.
|
||||
TUERSCHLOSS_SENSOREN = []
|
||||
|
||||
# Heckklappe und Motorhaube - von der Integration separat von den vier Türen
|
||||
# geführt, für "Sicher abgestellt" (§9) aber ebenso relevant wie diese
|
||||
HECKKLAPPE_SENSOR = "binary_sensor.audi_rs_4_avant_tailgate"
|
||||
HECKKLAPPENSCHLOSS_SENSOR = "binary_sensor.audi_rs_4_avant_tailgate_lock"
|
||||
HAUBE_SENSOR = "binary_sensor.audi_rs_4_avant_hood"
|
||||
HAUBENSCHLOSS_SENSOR = "binary_sensor.audi_rs_4_avant_hood_lock"
|
||||
# Heckklappe und Motorhaube - keine Quelle mehr vorhanden.
|
||||
HECKKLAPPE_SENSOR = ""
|
||||
HECKKLAPPENSCHLOSS_SENSOR = ""
|
||||
HAUBE_SENSOR = ""
|
||||
HAUBENSCHLOSS_SENSOR = ""
|
||||
|
||||
# Vom Fahrzeug selbst gemeldete Service-Fälligkeit (ergänzt die App-eigene,
|
||||
# aus dem Servicebuch berechnete Prognose - siehe fahrzeugMeldung() im
|
||||
# Frontend). Je ein Datum (ISO mit Zeitzone) und eine Streckenangabe in km;
|
||||
# die Streckensensoren liefern negative Werte (Restkilometer als Countdown),
|
||||
# im Frontend wird davon nur der Betrag angezeigt.
|
||||
NAECHSTER_OELWECHSEL_SENSOR = "sensor.audi_rs_4_avant_oil_change_due"
|
||||
OELWECHSEL_STRECKE_SENSOR = "sensor.audi_rs_4_avant_oil_change_distance"
|
||||
NAECHSTE_INSPEKTION_SENSOR = "sensor.audi_rs_4_avant_inspection_due"
|
||||
INSPEKTION_STRECKE_SENSOR = "sensor.audi_rs_4_avant_inspection_distance"
|
||||
# aus dem Servicebuch berechnete Prognose) - keine Quelle mehr vorhanden.
|
||||
NAECHSTER_OELWECHSEL_SENSOR = ""
|
||||
OELWECHSEL_STRECKE_SENSOR = ""
|
||||
NAECHSTE_INSPEKTION_SENSOR = ""
|
||||
INSPEKTION_STRECKE_SENSOR = ""
|
||||
|
||||
# Live-GPS-Position des Fahrzeugs (Übersicht -> Standort-Kachel). Erwartet
|
||||
# eine device_tracker.*-Entity mit "latitude"/"longitude"-Attributen (HA-
|
||||
# Konvention, siehe _standort() in frontend_veroeffentlichung.py) - bleibt
|
||||
# leer, solange keine Quelle angebunden ist (siehe AGENTS.md Abschnitt B,
|
||||
# FMM003/flespi offen); die Oberfläche zeigt dann "kein GPS-Signal" statt
|
||||
# eines falschen Werts, genau wie bei BATTERIE_SENSOR oben.
|
||||
STANDORT_TRACKER = ""
|
||||
# Konvention, siehe _standort() in frontend_veroeffentlichung.py) - jetzt
|
||||
# vom FMM003 geliefert.
|
||||
STANDORT_TRACKER = "device_tracker.testzone_fmm003"
|
||||
|
||||
# Update-Funktion (Einstellungen -> "Update suchen", siehe
|
||||
# updateverwaltung.py): Git-Repository, in das dieses Projekt gepflegt wird -
|
||||
|
||||
@@ -0,0 +1,188 @@
|
||||
"""Sensor-zu-Entität-Zuordnung fürs Setup-Menü (Einstellungen -> Fahrzeug
|
||||
einrichten -> Setup).
|
||||
|
||||
Ersetzt NICHT das manuelle Eintragen in einstellungen.py (dessen Kommentare
|
||||
sind die eigentliche Dokumentation der Integration und bleiben unangetastet),
|
||||
sondern legt eine zusätzliche, zur Laufzeit angewendete Override-Ebene
|
||||
darüber: data/entitaeten.json enthält nur die vom Nutzer über das Setup-Menü
|
||||
geänderten Zuordnungen, keyed nach den einstellungen.py-Variablennamen.
|
||||
|
||||
Warum das funktioniert, ohne jede Verbraucher-Datei anzufassen: Alle
|
||||
bestehenden Leser (frontend_veroeffentlichung.py, fahrterkennung.py, ...)
|
||||
machen `import einstellungen` und lesen dann `einstellungen.KM_SENSOR` -
|
||||
ein lebendiger Attributzugriff auf das Modul-Objekt, kein `from einstellungen
|
||||
import KM_SENSOR` (das würde den Wert beim Import einfrieren). overrides_
|
||||
anwenden() unten nutzt genau das: setattr(einstellungen, key, wert) ändert
|
||||
das Attribut auf dem bereits importierten Modul-Objekt, jeder spätere
|
||||
Zugriff `einstellungen.KM_SENSOR` liefert sofort den neuen Wert.
|
||||
|
||||
Eine Ausnahme (siehe TRIGGER_GEBUNDEN unten): mehrere @state_trigger(f"...")-
|
||||
Dekoratoren backen ZUENDUNG_SENSOR/KM_SENSOR/TANK_SENSOR einmalig beim
|
||||
Modul-Laden in die Trigger-Registrierung ein. Eine Änderung dieser drei
|
||||
Felder wirkt für die Fahrterkennung selbst erst nach einem Neustart von
|
||||
Home Assistant (bzw. pyscript.reload) - das Setup-Menü weist deshalb bei
|
||||
diesen drei Feldern ausdrücklich darauf hin, statt automatisch und riskant
|
||||
einen Selbst-Reload aus einer laufenden pyscript-Funktion heraus zu
|
||||
versuchen.
|
||||
"""
|
||||
|
||||
import io
|
||||
import json
|
||||
import os
|
||||
|
||||
import einstellungen
|
||||
|
||||
BASIS = "/config/audi_dashboard"
|
||||
OVERRIDES_PFAD = f"{BASIS}/entitaeten.json"
|
||||
|
||||
# Vier gleich aufgebaute Positionen, wie schon in frontend_veroeffentlichung.py
|
||||
# (dort POSITIONEN genannt) - hier dupliziert statt importiert, damit
|
||||
# entitaeten.py nicht von frontend_veroeffentlichung.py abhängt (wäre die
|
||||
# falsche Richtung: die Veröffentlichung importiert diese Datei, nicht
|
||||
# umgekehrt).
|
||||
POSITIONEN = ["vorne links", "vorne rechts", "hinten links", "hinten rechts"]
|
||||
|
||||
# Katalog aller von der App genutzten Entity-Rollen, fürs Setup-Menü im
|
||||
# Frontend. Reihenfolge = Anzeige-Reihenfolge innerhalb jeder Gruppe.
|
||||
# domains/device_classes/units sind Erwartungen fürs Frontend-seitige
|
||||
# Filtern+Vorschlagen (Schalter "Nur passende Sensoren anzeigen") - eine
|
||||
# fehlende oder leere Liste bedeutet "keine Einschränkung" bzw. "diese Rolle
|
||||
# hat üblicherweise keine Einheit" (binary_sensor/button/device_tracker).
|
||||
FELDER = [
|
||||
{"key": "ZUENDUNG_SENSOR", "label": "Zündung/ACC-Status", "gruppe": "fahrterkennung",
|
||||
"hinweis": "on = Fahrt läuft, erkennt Fahrtbeginn/-ende (ersetzt die frühere WLAN-Erkennung).",
|
||||
"domains": ["binary_sensor"], "device_classes": [], "units": [], "liste": False, "pflicht": True,
|
||||
"stichworte": ["zündung", "ignition", "acc", "motor", "engine"]},
|
||||
{"key": "KM_SENSOR", "label": "Kilometerstand", "gruppe": "fahrterkennung",
|
||||
"hinweis": "Gesamt-Kilometerstand des Fahrzeugs - für Fahrtabschluss-Screening, Reifenzähler und Ölwechsel-Prognose.",
|
||||
"domains": ["sensor"], "device_classes": ["distance"], "units": ["km", "mi"], "liste": False, "pflicht": False,
|
||||
"stichworte": ["kilometer", "km", "mileage", "odometer", "tacho", "laufleistung"]},
|
||||
{"key": "TANK_SENSOR", "label": "Tankfüllstand", "gruppe": "fahrterkennung",
|
||||
"hinweis": "Füllstand in Prozent - für die automatische Tankerkennung.",
|
||||
"domains": ["sensor"], "device_classes": [], "units": ["%"], "liste": False, "pflicht": False,
|
||||
"stichworte": ["tank", "fuel", "kraftstoff", "füllstand", "level"]},
|
||||
{"key": "RANGE_SENSOR", "label": "Reichweite", "gruppe": "uebersicht",
|
||||
"hinweis": "Für die Übersicht - bleibt leer, zeigt die Oberfläche \"unbekannt\".",
|
||||
"domains": ["sensor"], "device_classes": ["distance"], "units": ["km", "mi"], "liste": False, "pflicht": False,
|
||||
"stichworte": ["reichweite", "range"]},
|
||||
{"key": "BATTERIE_SENSOR", "label": "12V-Batteriespannung", "gruppe": "uebersicht",
|
||||
"hinweis": "Nicht jede Integration liefert diesen Wert - bleibt er leer, zeigt \"Mein Audi\" \"unbekannt\".",
|
||||
"domains": ["sensor"], "device_classes": ["voltage"], "units": ["V"], "liste": False, "pflicht": False,
|
||||
"stichworte": ["batterie", "battery", "spannung", "volt", "12v"]},
|
||||
{"key": "REFRESH_BUTTON", "label": "Sofort-Aktualisierung (Knopf)", "gruppe": "uebersicht",
|
||||
"hinweis": "Der von der Integration bereitgestellte Knopf für \"Ziehen zum Aktualisieren\".",
|
||||
"domains": ["button"], "device_classes": [], "units": [], "liste": False, "pflicht": False,
|
||||
"stichworte": ["refresh", "aktualisieren", "update", "abrufen", "poll"]},
|
||||
{"key": "TUER_SENSOREN", "label": "Türen", "gruppe": "sicherheit",
|
||||
"hinweis": "\"aus\"/off = zu. Für \"Sicher abgestellt\" wichtig.",
|
||||
"domains": ["binary_sensor"], "device_classes": ["door"], "units": [], "liste": True, "positionen": POSITIONEN,
|
||||
"pflicht": False, "stichworte": ["tür", "door"]},
|
||||
{"key": "FENSTER_SENSOREN", "label": "Fenster", "gruppe": "sicherheit",
|
||||
"hinweis": "\"aus\"/off = zu.",
|
||||
"domains": ["binary_sensor"], "device_classes": ["window"], "units": [], "liste": True, "positionen": POSITIONEN,
|
||||
"pflicht": False, "stichworte": ["fenster", "window"]},
|
||||
{"key": "TUERSCHLOSS_SENSOREN", "label": "Türschlösser", "gruppe": "sicherheit",
|
||||
"hinweis": "\"on\" = entriegelt, \"aus\"/off = verriegelt (device_class \"lock\"-Konvention).",
|
||||
"domains": ["binary_sensor"], "device_classes": ["lock"], "units": [], "liste": True, "positionen": POSITIONEN,
|
||||
"pflicht": False, "stichworte": ["schloss", "lock", "verriegel", "entriegel"]},
|
||||
{"key": "HECKKLAPPE_SENSOR", "label": "Heckklappe", "gruppe": "sicherheit",
|
||||
"hinweis": "\"aus\"/off = zu.",
|
||||
"domains": ["binary_sensor"], "device_classes": ["door", "opening"], "units": [], "liste": False, "pflicht": False,
|
||||
"stichworte": ["heckklappe", "tailgate", "kofferraum", "trunk"]},
|
||||
{"key": "HECKKLAPPENSCHLOSS_SENSOR", "label": "Heckklappenschloss", "gruppe": "sicherheit",
|
||||
"hinweis": "\"on\" = entriegelt, \"aus\"/off = verriegelt.",
|
||||
"domains": ["binary_sensor"], "device_classes": ["lock"], "units": [], "liste": False, "pflicht": False,
|
||||
"stichworte": ["heckklappe", "tailgate", "schloss", "lock"]},
|
||||
{"key": "HAUBE_SENSOR", "label": "Motorhaube", "gruppe": "sicherheit",
|
||||
"hinweis": "\"aus\"/off = zu.",
|
||||
"domains": ["binary_sensor"], "device_classes": ["door", "opening"], "units": [], "liste": False, "pflicht": False,
|
||||
"stichworte": ["haube", "hood", "bonnet", "motorhaube"]},
|
||||
{"key": "HAUBENSCHLOSS_SENSOR", "label": "Haubenschloss", "gruppe": "sicherheit",
|
||||
"hinweis": "\"on\" = entriegelt, \"aus\"/off = verriegelt.",
|
||||
"domains": ["binary_sensor"], "device_classes": ["lock"], "units": [], "liste": False, "pflicht": False,
|
||||
"stichworte": ["haube", "hood", "schloss", "lock"]},
|
||||
{"key": "NAECHSTER_OELWECHSEL_SENSOR", "label": "Nächster Ölwechsel (Datum)", "gruppe": "uebersicht",
|
||||
"hinweis": "Vom Fahrzeug selbst gemeldete Fälligkeit, ergänzt die App-eigene Servicebuch-Prognose.",
|
||||
"domains": ["sensor"], "device_classes": ["date", "timestamp"], "units": [], "liste": False, "pflicht": False,
|
||||
"stichworte": ["ölwechsel", "oil", "service", "change"]},
|
||||
{"key": "OELWECHSEL_STRECKE_SENSOR", "label": "Nächster Ölwechsel (Restkilometer)", "gruppe": "uebersicht",
|
||||
"hinweis": "Meldet die Integration oft als negativen Countdown - die App zeigt nur den Betrag.",
|
||||
"domains": ["sensor"], "device_classes": ["distance"], "units": ["km", "mi"], "liste": False, "pflicht": False,
|
||||
"stichworte": ["ölwechsel", "oil", "distance", "strecke"]},
|
||||
{"key": "NAECHSTE_INSPEKTION_SENSOR", "label": "Nächste Inspektion (Datum)", "gruppe": "uebersicht",
|
||||
"hinweis": "Vom Fahrzeug selbst gemeldete Fälligkeit.",
|
||||
"domains": ["sensor"], "device_classes": ["date", "timestamp"], "units": [], "liste": False, "pflicht": False,
|
||||
"stichworte": ["inspektion", "inspection", "service"]},
|
||||
{"key": "INSPEKTION_STRECKE_SENSOR", "label": "Nächste Inspektion (Restkilometer)", "gruppe": "uebersicht",
|
||||
"hinweis": "Meldet die Integration oft als negativen Countdown - die App zeigt nur den Betrag.",
|
||||
"domains": ["sensor"], "device_classes": ["distance"], "units": ["km", "mi"], "liste": False, "pflicht": False,
|
||||
"stichworte": ["inspektion", "inspection", "distance", "strecke"]},
|
||||
{"key": "STANDORT_TRACKER", "label": "GPS-Standort", "gruppe": "standort",
|
||||
"hinweis": "Braucht latitude/longitude-Attribute (HA-Konvention für device_tracker).",
|
||||
"domains": ["device_tracker"], "device_classes": [], "units": [], "liste": False, "pflicht": False,
|
||||
"stichworte": ["standort", "gps", "tracker", "position", "ortung"]},
|
||||
]
|
||||
|
||||
# Mehrere @state_trigger(f"...")-Dekoratoren (fahrterkennung.py,
|
||||
# fahrtabschluss.py, tankerkennung.py, reifenzaehler.py) backen diese drei
|
||||
# Felder beim Modul-Laden ein (siehe Kopfkommentar) - im Setup-Menü als
|
||||
# "wirkt erst nach Neustart"-Hinweis markiert.
|
||||
_TRIGGER_GEBUNDEN = {"ZUENDUNG_SENSOR", "KM_SENSOR", "TANK_SENSOR"}
|
||||
for _feld in FELDER:
|
||||
_feld["trigger_gebunden"] = _feld["key"] in _TRIGGER_GEBUNDEN
|
||||
|
||||
_SCHLUESSEL = {feld["key"] for feld in FELDER}
|
||||
|
||||
|
||||
# --------------------------------------------------------------- JSON-I/O ---
|
||||
# Gleiches Muster wie profil.profil_lesen()/profil_schreiben(): io.open nur
|
||||
# über task.executor (pyscript-Einschränkung, siehe Kopfkommentar dort),
|
||||
# atomares Schreiben über eine .tmp-Datei + os.replace.
|
||||
|
||||
def overrides_lesen():
|
||||
if not os.path.exists(OVERRIDES_PFAD):
|
||||
return {}
|
||||
f = task.executor(io.open, OVERRIDES_PFAD, "r")
|
||||
inhalt = f.read()
|
||||
f.close()
|
||||
return json.loads(inhalt) if inhalt.strip() else {}
|
||||
|
||||
|
||||
def overrides_schreiben(mapping):
|
||||
"""Schreibt nur bekannte Schlüssel (siehe FELDER); unbekannte werden
|
||||
stillschweigend verworfen, damit ein späterer Katalog-Umbau keine
|
||||
Datenleichen in entitaeten.json hinterlässt."""
|
||||
bereinigt = {k: v for k, v in mapping.items() if k in _SCHLUESSEL}
|
||||
os.makedirs(BASIS, exist_ok=True)
|
||||
tmp = OVERRIDES_PFAD + ".tmp"
|
||||
text = json.dumps(bereinigt, ensure_ascii=False, indent=2)
|
||||
f = task.executor(io.open, tmp, "w")
|
||||
f.write(text)
|
||||
f.close()
|
||||
os.replace(tmp, OVERRIDES_PFAD)
|
||||
|
||||
|
||||
# ------------------------------------------------------- Anwenden/Lesen ---
|
||||
|
||||
def overrides_anwenden():
|
||||
"""setattr(einstellungen, key, wert) für jeden in entitaeten.json
|
||||
hinterlegten, nicht-leeren Wert - siehe Kopfkommentar, warum das
|
||||
ausreicht, damit alle bestehenden Verbraucher den neuen Wert sofort
|
||||
sehen (Ausnahme: die drei TRIGGER_GEBUNDEN-Felder, dort erst nach
|
||||
Neustart)."""
|
||||
overrides = overrides_lesen()
|
||||
for key, wert in overrides.items():
|
||||
if key not in _SCHLUESSEL:
|
||||
continue
|
||||
if wert in (None, "", []):
|
||||
continue
|
||||
setattr(einstellungen, key, wert)
|
||||
|
||||
|
||||
def aktueller_stand():
|
||||
"""Katalog + aktuell wirksamer Wert je Feld (aus dem einstellungen-Modul
|
||||
selbst gelesen, nicht direkt aus der JSON-Datei) - zeigt damit sowohl
|
||||
bereits angewendete Overrides als auch die eingebauten Standardwerte
|
||||
einheitlich. Grundlage für pyscript.audi_dashboard_entitaeten."""
|
||||
werte = {feld["key"]: getattr(einstellungen, feld["key"], None) for feld in FELDER}
|
||||
return {"katalog": FELDER, "werte": werte}
|
||||
@@ -20,6 +20,7 @@ tankvorgaenge_veroeffentlichen() auf einen Zeitraum eingeschränkt werden
|
||||
"""
|
||||
|
||||
import einstellungen
|
||||
import entitaeten
|
||||
import profil
|
||||
|
||||
|
||||
@@ -39,6 +40,12 @@ def batterieverlauf_veroeffentlichen():
|
||||
state.set("pyscript.audi_dashboard_batterieverlauf", "aktuell", new_attributes={"daten": profil.batterieverlauf_lesen()})
|
||||
|
||||
|
||||
def entitaeten_veroeffentlichen():
|
||||
"""Katalog + aktuell wirksame Zuordnung fürs Setup-Menü (Einstellungen ->
|
||||
Fahrzeug einrichten -> Setup) - siehe entitaeten.py."""
|
||||
state.set("pyscript.audi_dashboard_entitaeten", "aktuell", new_attributes={"daten": entitaeten.aktueller_stand()})
|
||||
|
||||
|
||||
def beleg_ergebnis_veroeffentlichen(daten):
|
||||
"""Ergebnis eines Beleg-Uploads (geparste Werte fürs Ausfüllen eines
|
||||
Entwurfs, oder ein Fehler wie 'Falsches Belegdatum') fürs Frontend, nach
|
||||
@@ -190,3 +197,4 @@ def alles_veroeffentlichen():
|
||||
tankvorgaenge_veroeffentlichen()
|
||||
fahrzeugstatus_veroeffentlichen()
|
||||
batterieverlauf_veroeffentlichen()
|
||||
entitaeten_veroeffentlichen()
|
||||
|
||||
Reference in New Issue
Block a user