"""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.. 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..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() 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")