Files
audi-app/custom_components/audi_dashboard/zuordnung.py
T
tobias 9d70192da3 Audit: Livepfad und Rueckblick messen wieder dasselbe (2026.9.1.17)
BEFUND 1 (behoben): dieselbe Fahrt, zwei Strecken

screening.py las den Verlauf ueber verlauf_lesen(), das den Stand zu Beginn
des Fensters mitliefert. historienimport.py schnitt sein Fenster streng heraus
und verlor genau diesen Punkt. An der echten Fahrt nachgemessen: 6,896 km
gegen 6,816 km fuer denselben Zeitraum.

Neu verlauf.zaehlerstrecke(punkte, start, ende) - der Anker ist der letzte
Datensatz am oder vor dem Beginn, dieselbe Ueberlegung wie bei wert_bei().
Beide Wege schneiden jetzt durch dieselbe Funktion. Nachgewiesen: Rueckblick
6,896, Livepfad 6,896.

Dritter Fall dieser Art nach UNPLAUSIBLE_KMH und MINDESTDAUER_S - und ich
hatte ihn am selben Tag selbst eingebaut.

BEFUND 2 (behoben): STANDARDWERTE gingen unnoetig ueber die Leitung.
zuordnung.py schickte sie mit jeder Katalogantwort; gelesen hat sie seit dem
Entfernen des Zuruecksetzen-Knopfes niemand mehr. Die Konstante bleibt, sie
traegt intern die Vorgabewerte und leitet SCHLUESSEL ab.

BEFUND 3 und 4 bleiben offen und gehoeren dem Eigentuemer: die vier Tage alte
Reichweite auf der Uebersicht (RANGE_SENSOR besser leer lassen) und die
Nullfahrt-Regel, die nur der Rueckblick kennt - im Livepfad hiesse sie, einen
bereits gespeicherten Datensatz automatisch zu loeschen.

SAUBER: 24 Backend-Dateien py_compile, Panel als Modul geparst, tsc --noEmit
und vite build sauber, 165/165 Tests, 27 Katalogeintraege gegen 27
Dataclass-Felder ohne Abweichung, jedes Listenfeld mit so vielen Beispielen wie
Positionen, keine verwaisten Verweise, in der Konsole nur das bekannte
ServiceWorker-Rauschen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-01 19:09:59 +02:00

80 lines
3.5 KiB
Python

"""Sensor-zu-Entität-Zuordnung fürs Setup-Menü (Einstellungen -> Fahrzeug
einrichten -> Setup).
audi_dashboard/entitaeten.json enthält nur die vom Nutzer über das Setup-Menü
geänderten Zuordnungen, keyed nach den Feldnamen aus einstellungen.py.
anwenden() legt sie über die eingebauten Standardwerte.
Wichtig ist, dass JEDES bekannte Feld bei jedem Durchlauf gesetzt wird, nicht
nur die belegten. Eine frühere Fassung übersprang leere Werte - weil die
Zuordnung aber ein dauerhaftes Objekt ist, blieb ein einmal gesetzter Wert
danach für immer stehen. "Zurücksetzen" im Setup-Menü hatte bei allen Feldern
mit leerem Standardwert (15 von 17) schlicht keine Wirkung, und die Oberfläche
zeigte beim nächsten Zeichnen wieder den alten Wert, als sei das Speichern
fehlgeschlagen. Umgekehrt wurde eine Liste aus leeren Einträgen gesetzt statt
übersprungen, was den Sicherheitscheck mit zwölf "unbekannt"-Zeilen füllte und
"Sicher abgestellt" dauerhaft grau werden ließ.
Jedes Feld bei jedem Durchlauf zu schreiben ist damit nicht nur korrekt,
sondern auch idempotent: der Zustand hängt allein an entitaeten.json, nicht an
der Reihenfolge vorheriger Aufrufe.
"""
from __future__ import annotations
from . import einstellungen
from .ablage import Ablage
from .einstellungen import FELDER, SCHLUESSEL, STANDARDWERTE, Sensorzuordnung
def _ist_leer(wert: object) -> bool:
"""Leer heißt: keine Zuordnung. Auch eine Liste, die nur leere Einträge
enthält - das Setup-Menü schickt für unbelegte Positionen ["","",...], und
das ist inhaltlich dasselbe wie gar keine Liste."""
if wert in (None, ""):
return True
if isinstance(wert, list):
return not any(eintrag for eintrag in wert)
return False
class Zuordnung:
"""Hält die wirksame Sensorzuordnung und pflegt sie aus entitaeten.json."""
def __init__(self, ablage: Ablage) -> None:
self._ablage = ablage
self.werte = Sensorzuordnung()
async def anwenden(self) -> None:
"""Setzt für jedes bekannte Feld den wirksamen Wert - den Override,
wenn einer hinterlegt ist, sonst den eingebauten Standardwert."""
overrides = await self._ablage.zuordnung_lesen()
for key in SCHLUESSEL:
wert = overrides.get(key)
standard = STANDARDWERTE[key]
gesetzt = standard if _ist_leer(wert) else wert
setattr(self.werte, key, list(gesetzt) if isinstance(gesetzt, list) else gesetzt)
async def speichern(self, mapping: dict) -> None:
"""Schreibt nur bekannte Schlüssel; 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}
await self._ablage.zuordnung_schreiben(bereinigt)
await self.anwenden()
def aktueller_stand(self) -> dict:
"""Katalog + aktuell wirksamer Wert je Feld, Grundlage für die Entität
sensor.audi_dashboard_entitaeten. Die Werte kommen aus dem
Zuordnungsobjekt selbst, nicht direkt aus der JSON-Datei - damit zeigt
die Oberfläche bereits angewendete Overrides und eingebaute
Standardwerte einheitlich."""
werte = {feld["key"]: getattr(self.werte, feld["key"], None) for feld in FELDER}
# "standardwerte" ist mit dem Zuruecksetzen-Knopf (2026.9.1.11)
# entfallen - niemand liest sie mehr, also gehen sie auch nicht mehr
# ueber die Leitung.
return {"katalog": FELDER, "werte": werte}
__all__ = ["Zuordnung", "einstellungen"]