Fahrten: Verbrauch-Näherung, 0V-Zustandsanzeige gefiltert, Plausibilitätsgrenze für die Live-Vervollständigung

Verbrauch (l/100km) war bislang totes Schema - kein Codepfad füllte
verbrauch_l_100km je. Jetzt aus der Literstand-Differenz (TANK_LITER_SENSOR)
über die Distanz genähert, live und beim Import, in beiden Frontends.

Die "Zustand"-Kachel zeigte die Batteriespannung ungefiltert direkt vom
Sensor, unabhängig von der Plausibilitätsgrenze der Verlaufsaufzeichnung -
ein Sensorausreißer (0V) zeigte sich dort weiterhin, obwohl die Messwertliste
ihn längst verwarf. Dieselbe Grenze gilt jetzt auch für diesen Anzeigepfad.

Reale Fahrtendaten zeigten eine Fahrt mit 22km in 67s (~1180 km/h) - die
Live-Vervollständigung (screening.py) hatte anders als der Import keine
Plausibilitätsprüfung der Durchschnittsgeschwindigkeit. Jetzt gemeinsam in
verlauf.py (UNPLAUSIBLE_KMH/durchschnitt_kmh) für beide Pfade. Dabei einen
zweiten echten Bug gefunden: _fahrt_screenen() zog sein Ergebnis nie ins
In-Memory-Objekt nach (nur in die Ablage) - eine im selben Durchlauf gerade
erst ermittelte Distanz blieb für spätere Schritte (z. B. Verbrauch) bis zum
nächsten Screening unsichtbar. Beide Stellen jetzt behoben.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
2026-08-27 21:01:57 +02:00
co-authored by Claude Sonnet 5
parent cf57c5f1a5
commit 80d73e8afd
12 changed files with 344 additions and 30 deletions
@@ -85,6 +85,25 @@ def zahl(wert: object) -> float | None:
return None
# Kein Auto dieser Art erreicht diesen Schnitt. Eine errechnete
# Durchschnittsgeschwindigkeit darüber ist kein Beleg für eine schnelle
# Fahrt, sondern für einen fehlerhaften Kilometerstand-Sprung am Fahrtrand
# (z. B. ein Ausreißer im Verlauf oder ein knapp daneben liegender
# wert_bei()/naechster_wert()-Treffer über eine Lücke hinweg). Gemeinsam für
# den Import (historienimport.py) und die Live-Vervollständigung
# (screening.py) - beide dürfen dieselbe Strecke nie unterschiedlich
# bewerten.
UNPLAUSIBLE_KMH = 300
def durchschnitt_kmh(distanz_km: float | None, dauer_s: float | None) -> float | None:
"""km/h aus Strecke und Dauer, oder None wenn eine der beiden fehlt oder
die Dauer nicht positiv ist."""
if distanz_km is None or not dauer_s or dauer_s <= 0:
return None
return round(distanz_km / (dauer_s / 3600.0), 1)
def wert_bei(
verlauf: list[Verlaufspunkt], zeitpunkt: datetime.datetime
) -> float | None:
@@ -134,6 +153,26 @@ def route_aus_verlauf(
return punkte if len(punkte) >= 2 else None
def verbrauch_aus_literstaenden(
start_liter: float | None, end_liter: float | None, distance_km: float | None
) -> float | None:
"""l/100km aus der Differenz zweier Literstände (TANK_LITER_SENSOR) und
der gefahrenen Strecke - eine Näherung, kein vom Fahrzeug selbst für
diese eine Fahrt gemeldeter Wert (ein solcher OBD-Sensor steht als
offener Punkt in AGENTS.md; taucht einer auf, ersetzt er diese Näherung).
None, wenn einer der Werte fehlt, die Strecke nicht positiv ist, oder der
Literstand nicht gefallen ist (z. B. ein Tankvorgang während der Fahrt,
oder unveränderter Füllstand) - in beiden Fällen ist der Quotient nicht
aussagekräftig."""
if start_liter is None or end_liter is None or not distance_km or distance_km <= 0:
return None
verbraucht = start_liter - end_liter
if verbraucht <= 0:
return None
return round(verbraucht / distance_km * 100, 1)
def naechster_wert(
zielzeit: datetime.datetime, verlauf: list[Verlaufspunkt]
) -> float | None: