863284e540
Gemeldet: Wartungsplan leer, Erstzulassung 01.03.2025, erwartet 01.03.2028 -
gezeigt wurden drei verschiedene Antworten (Uebersicht 01.08.2026, Mein Audi
"August 2026", Service "kein Eintrag im Wartungsplan").
Ursache war das Profilfeld hauptuntersuchung_faellig ("08/2026"), das die
Ableitung ueberstimmte, in keiner Oberflaeche ein Eingabefeld hatte und im
Backend kein Schema. Drei Bildschirme verarbeiteten denselben Wert
verschieden. Das Feld ist samt Lese- und Schreibweg entfernt; es gibt jetzt
zwei Quellen: Wartungsplan + 24 Monate, sonst Erstzulassung + 36 Monate.
Dabei mitbehoben:
* Die Service-Kachel verschluckte abgeleitete Termine, sobald kein
Wartungsplan-Eintrag dahinterstand.
* monatePlus() in der App verlor einen Tag ueber die Zeitumstellung (drei von
fuenf gemessenen Faellen) - betraf Oelwechsel- und Inspektionsprognose
genauso. Das Panel rechnete dort seit jeher richtig.
* Die App verlangte fuer jeden Wartungsplan-Eintrag eine Kilometerangabe. Eine
Hauptuntersuchung ist rein datumsbasiert; ohne km waere der erste HU-Eintrag
ignoriert worden. Ausserdem nahm das Panel den ersten Treffer der Liste, die
App den juengsten - beide nehmen jetzt den juengsten.
* Monatsgenauigkeit ("03/2025") bleibt auf beiden Seiten erhalten.
Neu: paritaet_hu.test.ts vergleicht die App gegen die aus der Panel-Quelle
herausgeschnittenen Originalfunktionen, 15 Faelle. Gesamt 292 App-Tests, 73
Python-Tests mit 231 Untertests, 0 Tracebacks. Live an der Testinstanz auf
allen drei gemeldeten Bildschirmen geprueft.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
101 lines
4.4 KiB
Python
101 lines
4.4 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
|
|
|
|
import logging
|
|
|
|
from . import einstellungen
|
|
from .ablage import Ablage
|
|
from .einstellungen import FELDER, SCHLUESSEL, STANDARDWERTE, Sensorzuordnung
|
|
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
|
|
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.
|
|
|
|
Räumt dabei einmalig auf: Schlüssel, die der Katalog nicht mehr kennt,
|
|
werden aus entitaeten.json entfernt. `speichern()` filtert sie schon
|
|
beim Schreiben heraus, aber eine bestehende Datei behielt sie bis zum
|
|
nächsten Speichern - und ein Feld, das es nicht mehr gibt, soll auch
|
|
nicht mehr in den Daten stehen. Angefallen ist das mit dem Entfernen
|
|
von TRIP_SENSOR am 05.09.2026."""
|
|
overrides = await self._ablage.zuordnung_lesen()
|
|
verwaist = [k for k in overrides if k not in SCHLUESSEL]
|
|
if verwaist:
|
|
_LOGGER.info(
|
|
"Zuordnung: %s kennt der Katalog nicht mehr - entfernt",
|
|
", ".join(sorted(verwaist)),
|
|
)
|
|
await self._ablage.zuordnung_schreiben(
|
|
{k: v for k, v in overrides.items() if k in SCHLUESSEL}
|
|
)
|
|
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"]
|