6bf7435434
Replaced the hand-drawn placeholder battery icon with the real Audi CI battery-12v-l/-s (user supplied the actual SVGs) next to "Ruhespannung", matching the existing poi-l/poi-s size-variant convention. Added a km-correction control to the Sommerräder/Winterräder tiles: a pencil icon (Audi CI edit-s) opens an inline field to manually correct the tire-set's accumulated km. The tricky part was persistence - configCarZuProfil() deliberately never writes km back (a stale browser copy could otherwise clobber a since-elapsed automatic increment), so this needed its own backend service, audi_dashboard_reifen_km_setzen, that overwrites only the stored counter and leaves referenz_odo_km alone - the existing odometer-delta tracking in reifenzaehler.py then continues accumulating from the corrected value on its own, no other backend change required. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
142 lines
6.0 KiB
Python
142 lines
6.0 KiB
Python
"""Reifenzähler ohne utility_meter (§7.5, §10 Punkt 6).
|
|
|
|
ABWEICHUNG VOM URSPRÜNGLICHEN LASTENHEFT (Frontend-Anpassung, nach dem
|
|
ursprünglichen Bau nachträglich verlangt): früher war der Zähler = aktueller
|
|
Kilometerstand - fester Startwert je Satz (reifen.saetze.<satz>.
|
|
start_odo_km). Das war falsch, sobald einmal zwischen Sommer und Winter
|
|
umgeschaltet wurde: die Differenz zum Startwert zählt dann alle seither
|
|
gefahrenen Kilometer mit, auch die auf dem jeweils anderen Satz. Jetzt gilt
|
|
stattdessen: jeder gefahrene Kilometer wird dem Satz zugerechnet, der zum
|
|
Zeitpunkt der Fahrt aktiv war. Dafür führt reifen.saetze.<satz>.km selbst den
|
|
fortlaufenden Gesamtstand (statt eines Startwerts), und reifen.
|
|
referenz_odo_km hält den zuletzt verarbeiteten Kilometerstand fest, gegen den
|
|
die nächste Änderung als Delta gemessen wird. start_odo_km/§13 entfällt
|
|
damit vollständig.
|
|
|
|
Ergebnis wird zusätzlich als eigene pyscript-Zustandsvariable bereitgestellt
|
|
(nur zur Kontrolle in Entwicklerwerkzeuge → Zustände, das Frontend liest die
|
|
Werte direkt aus dem veröffentlichten Profil):
|
|
pyscript.reifen_sommer_km, pyscript.reifen_winter_km,
|
|
pyscript.reifen_aktiver_satz
|
|
|
|
Kein Abhängigkeit von total_increasing oder utility_meter-internem Zustand -
|
|
die Fortschreibung braucht nur den zuletzt bekannten Absolutwert des
|
|
Kilometerstand-Sensors. Ein zeitweise `unavailable` Quellsensor (§4.1)
|
|
verliert dadurch nichts: referenz_odo_km bleibt einfach stehen, bis wieder
|
|
ein gültiger Wert kommt, und das nächste Delta wird dann gegen diesen alten
|
|
Stand berechnet - auch km, die während eines HA-Neustarts/Ausfalls gefahren
|
|
wurden, werden so noch dem damals aktiven Satz zugerechnet.
|
|
|
|
Entity-IDs stehen zentral in pyscript/modules/einstellungen.py.
|
|
"""
|
|
|
|
import einstellungen
|
|
import frontend_veroeffentlichung
|
|
import profil
|
|
|
|
|
|
def _aktueller_km():
|
|
try:
|
|
return float(frontend_veroeffentlichung.zustand_oder_none(einstellungen.KM_SENSOR))
|
|
except (TypeError, ValueError):
|
|
return None
|
|
|
|
|
|
def _zustaende_veroeffentlichen(p):
|
|
reifen = p.get("reifen", {})
|
|
saetze = reifen.get("saetze", {})
|
|
for satz_name in ("sommer", "winter"):
|
|
km = saetze.get(satz_name, {}).get("km")
|
|
if km is None:
|
|
state.set(f"pyscript.reifen_{satz_name}_km", "unbekannt")
|
|
else:
|
|
state.set(f"pyscript.reifen_{satz_name}_km", km, new_attributes={"unit_of_measurement": "km"})
|
|
state.set("pyscript.reifen_aktiver_satz", reifen.get("aktiv", "unbekannt"))
|
|
|
|
|
|
def _fortschreiben_und_veroeffentlichen(neuer_km, neuer_aktiv=None):
|
|
"""Rechnet zuerst mit dem bisher aktiven Satz ab (Delta seit
|
|
referenz_odo_km), trägt danach optional einen Satzwechsel ein - in dieser
|
|
Reihenfolge, damit beim Wechseln selbst keine km dem neuen Satz
|
|
zugerechnet werden, die eigentlich noch auf dem alten gefahren wurden."""
|
|
p = profil.profil_lesen()
|
|
if p is None:
|
|
return
|
|
reifen = p.setdefault("reifen", {})
|
|
saetze = reifen.setdefault("saetze", {})
|
|
aktiv = reifen.get("aktiv", "sommer")
|
|
referenz = reifen.get("referenz_odo_km")
|
|
|
|
if referenz is not None and neuer_km is not None:
|
|
delta = round(neuer_km - referenz, 1)
|
|
if delta > 0:
|
|
satz = saetze.setdefault(aktiv, {})
|
|
satz["km"] = round((satz.get("km") or 0) + delta, 1)
|
|
if neuer_km is not None:
|
|
reifen["referenz_odo_km"] = neuer_km
|
|
if neuer_aktiv is not None:
|
|
reifen["aktiv"] = neuer_aktiv
|
|
|
|
profil.profil_schreiben(p)
|
|
frontend_veroeffentlichung.profil_veroeffentlichen()
|
|
_zustaende_veroeffentlichen(p)
|
|
|
|
|
|
@time_trigger("startup")
|
|
def beim_start():
|
|
_fortschreiben_und_veroeffentlichen(_aktueller_km())
|
|
|
|
|
|
# Ohne konfigurierten Kilometerstand-Sensor keinen Trigger registrieren -
|
|
# eine leere Entity-ID als @state_trigger-Ausdruck ist ungetestetes
|
|
# Verhalten, siehe gleiches Muster in fahrterkennung.py.
|
|
if einstellungen.KM_SENSOR:
|
|
@state_trigger(f"{einstellungen.KM_SENSOR}")
|
|
def kilometerstand_geaendert(value=None):
|
|
_fortschreiben_und_veroeffentlichen(_aktueller_km())
|
|
|
|
|
|
@service
|
|
def audi_dashboard_reifen_wechseln(satz=None):
|
|
"""Umschalten des aktiven Reifensatzes (§5.2). Aufruf als
|
|
pyscript.audi_dashboard_reifen_wechseln mit satz="sommer"|"winter"."""
|
|
if satz not in ("sommer", "winter"):
|
|
log.warning(f"audi_dashboard: ungültiger Reifensatz '{satz}'")
|
|
return
|
|
_fortschreiben_und_veroeffentlichen(_aktueller_km(), neuer_aktiv=satz)
|
|
log.info(f"audi_dashboard: aktiver Reifensatz auf '{satz}' umgeschaltet")
|
|
|
|
|
|
@service
|
|
def audi_dashboard_reifen_km_setzen(satz=None, km=None):
|
|
"""Manuelle Korrektur des gefahrenen Kilometerstands eines Reifensatzes
|
|
(Editier-Symbol neben der km-Anzeige in der App). Überschreibt nur den
|
|
gespeicherten Zähler selbst - referenz_odo_km (der zuletzt verarbeitete
|
|
Fahrzeug-Kilometerstand) bleibt unverändert, damit die nächste
|
|
Fortschreibung (kilometerstand_geaendert oben) weiterhin korrekt von hier
|
|
aus weiterzählt, statt auf den neuen Wert einen erneuten Delta seit dem
|
|
alten Stand aufzuschlagen. configCarZuProfil() im Frontend schreibt km nie
|
|
selbst mit (siehe Kommentar dort) - genau deshalb braucht es diesen
|
|
eigenen Service statt eines einfachen Profil-Überschreibens."""
|
|
if satz not in ("sommer", "winter"):
|
|
log.warning(f"audi_dashboard: ungültiger Reifensatz '{satz}'")
|
|
return
|
|
try:
|
|
km = round(float(km), 1)
|
|
except (TypeError, ValueError):
|
|
log.warning(f"audi_dashboard: ungültiger km-Wert '{km}'")
|
|
return
|
|
if km < 0:
|
|
log.warning(f"audi_dashboard: negativer km-Wert '{km}' abgelehnt")
|
|
return
|
|
p = profil.profil_lesen()
|
|
if p is None:
|
|
return
|
|
reifen = p.setdefault("reifen", {})
|
|
saetze = reifen.setdefault("saetze", {})
|
|
saetze.setdefault(satz, {})["km"] = km
|
|
profil.profil_schreiben(p)
|
|
frontend_veroeffentlichung.profil_veroeffentlichen()
|
|
_zustaende_veroeffentlichen(p)
|
|
log.info(f"audi_dashboard: km-Stand '{satz}' manuell auf {km} gesetzt")
|