Fahrterkennung: FMM003-Funklöcher reißen keine Fahrt mehr auseinander

Die Zündungs-Entität stammt vom FMM003-Tracker; verliert er unterwegs
kurz die Verbindung, meldet Home Assistant "unavailable" statt eines
echten Zündungszustands. Die Live-Erkennung wertete das bisher wie
"aus" - eine Funklücke über der Pausenzeit teilte eine durchgehende
Fahrt in zwei. zuendung_geaendert() ignoriert "unavailable"/"unknown"
jetzt vollständig und leitet "fährt gerade" aus dem eigenen
Zwischenstand (fahrt_start_ts) statt aus dem letzten Rohwert ab.

historienimport.py bekommt zusätzlich eine Plausibilitätsprüfung: eine
errechnete Durchschnittsgeschwindigkeit über 300 km/h deutet auf einen
Kilometerstand-Ausreißer an der Fahrtgrenze hin, nicht auf eine echte
Fahrt - die Strecke wird dann verworfen statt eine unmögliche Fahrt
anzuzeigen.

Tankerkennung: optionaler zweiter Sensor für das Tankvolumen in Litern
(TANK_LITER_SENSOR, direkt vom CAN) neben dem bisherigen
Prozent-Füllstand. Ist er zugeordnet, übernimmt er die automatische
Tankerkennung vollständig - genauer als der Umweg über das im
Fahrzeugprofil hinterlegte Tankvolumen, und der erkannte Anstieg
liefert gleich eine grobe Vorbelegung für die getankte Menge statt
eines leeren Feldes. Ohne den Sensor bleibt alles beim Alten. Der
historische Import zieht mit derselben Präferenz nach.

Manifest auf 2026.8.25.2, beide Änderungsrunden live im Testcontainer
verifiziert (py_compile, Neustart, sauberes Setup-Log).

Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
2026-08-25 22:04:26 +02:00
co-authored by Claude Sonnet 5
parent f97ceab3ad
commit 70253e83a5
7 changed files with 295 additions and 37 deletions
@@ -78,24 +78,39 @@ async def pausenzeit_sekunden(k: Koordinator) -> int:
async def zuendung_geaendert(k: Koordinator, neu: str | None, alt: str | None) -> None:
"""Reagiert auf jede Zustandsänderung der Zündungs-Entität."""
"""Reagiert auf jede Zustandsänderung der Zündungs-Entität.
"unavailable"/"unknown" ist kein Zündungszustand, sondern Funkstille des
Trackers - beim FMM003 z. B. in Tiefgaragen oder Funklöchern, auch mitten
in einer laufenden Fahrt. Würde das wie "aus" gewertet, risse jede solche
Lücke eine einzelne Fahrt in zwei auseinander, sobald sie länger als die
Pausenzeit dauert (der Tracker meldet sich zurück, die Zündung steht laut
letztem echten Wert immer noch auf "on", also sieht es wie eine neue
Fahrt aus). Ohne Signal ist deshalb "keine Aussage", nicht "aus": der
Zustand bleibt unangetastet, bis wieder ein echter Wert kommt."""
if neu not in ("on", "off"):
return
# Eine noch wartende Ende-Bestätigung aus einer vorherigen Änderung
# abbrechen - das ist der Mechanismus hinter der Pausenregel.
k.warte_ende_ab_abbrechen()
an_jetzt = neu == "on"
an_vorher = alt == "on"
# Ob eine Fahrt läuft, entscheidet der eigene Zwischenstand
# (fahrt_start_ts) - nicht der vorherige Rohwert der Entität. Der wäre bei
# einer Funklücke "unavailable" statt "on" gewesen, obwohl die Fahrt die
# ganze Zeit lief.
fahrt_laeuft = k.fahrt_start_ts is not None
if an_jetzt and not an_vorher:
if k.fahrt_start_ts is None:
await k.fahrt_start_setzen(datetime.datetime.now(datetime.UTC))
_LOGGER.info("Fahrt gestartet um %s", k.fahrt_start_ts)
if an_jetzt and not fahrt_laeuft:
await k.fahrt_start_setzen(datetime.datetime.now(datetime.UTC))
_LOGGER.info("Fahrt gestartet um %s", k.fahrt_start_ts)
# Die Anzeige "fährt/steht" hängt an derselben Entität - sofort neu
# veröffentlichen, statt bis zum nächsten 20-Sekunden-Takt zu warten.
await k.fahrzeugstatus_veroeffentlichen()
return
if an_vorher and not an_jetzt and k.fahrt_start_ts is not None:
if not an_jetzt and fahrt_laeuft:
start_ts = k.fahrt_start_ts
abbruch_ts = datetime.datetime.now(datetime.UTC)
wartezeit = await pausenzeit_sekunden(k)