Rueckblick misst auf Meter, Streckenwahl gemeinsam (2026.9.1.14)
Der erste Wurf (2026.9.1.12) verwarf jedes Importfenster mit distanz == 0. Zu grob: seit der GNSS-Verfeinerung messen wir Meter, und eine Fahrt von 400 Metern steht im CAN-Wert als Null. Der Eigentuemer hat es auf den Punkt gebracht - "0,0 moechte ich nicht, ab 0,1 schon". Der Rueckblick liest jetzt ebenfalls den GNSS-Zaehler und entscheidet auf eine Nachkommastelle. Dabei stand die Toleranzlogik kurz doppelt im Code - in screening.py und in historienimport.py. Genau die Doppelung, die dieses Projekt bei UNPLAUSIBLE_KMH und MINDESTDAUER_S schon einmal teuer bezahlt hat. Sie liegt jetzt gemeinsam in verlauf.py: strecke_waehlen(grob, fein) - die feine Zahl gilt, solange sie in der Rundungsunschaerfe des Ankers liegt, oder wenn es keinen Anker gibt. ist_gefahren(distanz) - ab 0,1 km ja. Eine unbekannte Strecke gilt als gefahren; nur die gemessene Null ist ein Nein. VERIFIZIERT: 13 Faelle gegen beide Funktionen, darunter die zwei echten Fahrten, die 400-Meter-Fahrt, die 100-Meter-Untergrenze, 40 Meter, fehlender Anker, fehlender GNSS-Wert, gedrifteter Zaehler und beide Seiten der Grenze. Import live: 1 Fenster uebersprungen, null 0-km-Fahrten im Bestand. Livepfad live: vier alte Fahrten korrekt abgelehnt. NICHT live gezeigt: ein Fenster mit 0,1-0,9 km, das der Import nun behaelt - der Recorder enthaelt kein geschlossenes Fenster dieser Groesse. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
@@ -48,6 +48,9 @@ from .verlauf import (
|
||||
MINDESTDAUER_S,
|
||||
durchschnitt_kmh,
|
||||
fahrtsignal,
|
||||
ist_gefahren,
|
||||
strecke_aus_zaehler,
|
||||
strecke_waehlen,
|
||||
hoechstwert_im_fenster,
|
||||
route_aus_verlauf,
|
||||
UNPLAUSIBLE_KMH,
|
||||
@@ -163,6 +166,7 @@ async def _fahrten_importieren(k: Koordinator, verlaeufe: dict) -> dict:
|
||||
|
||||
bestehende = await k.ablage.fahrten_lesen()
|
||||
km_verlauf = verlaeufe["km"]
|
||||
gnss_verlauf = verlaeufe.get("gnss_km") or []
|
||||
lat_verlauf = verlaeufe["lat"]
|
||||
lon_verlauf = verlaeufe["lon"]
|
||||
tank_liter_verlauf = verlaeufe["tank_liter"]
|
||||
@@ -186,10 +190,22 @@ async def _fahrten_importieren(k: Koordinator, verlaeufe: dict) -> dict:
|
||||
if odo_start is not None and odo_end is not None and odo_end >= odo_start:
|
||||
distanz = round(odo_end - odo_start, 1)
|
||||
|
||||
if distanz == 0:
|
||||
# Der Kilometerstand stand an beiden Enden gleich: das Fahrzeug hat
|
||||
# sich nicht bewegt. Zündung an, aber nicht gefahren - Radio, Tür
|
||||
# öffnen, warten. Keine Fahrt.
|
||||
# Der Kilometerstand des Fahrzeugs löst nur ganze Kilometer auf. Wo der
|
||||
# geräteeigene GNSS-Zähler zugeordnet ist, liefert er Meter - dieselbe
|
||||
# Verfeinerung wie im Livepfad (screening._gnss_verfeinern), damit
|
||||
# Rückblick und Livepfad dieselbe Fahrt nicht unterschiedlich bewerten.
|
||||
#
|
||||
# Sie entscheidet hier zusätzlich über Sein oder Nichtsein: eine Fahrt
|
||||
# von 400 Metern steht im CAN-Wert als Null und wäre sonst verworfen
|
||||
# worden, obwohl gefahren wurde.
|
||||
fein = strecke_aus_zaehler(
|
||||
[p for p in gnss_verlauf if f_start <= p[0] <= f_ende]
|
||||
)
|
||||
distanz, gnss_verwendet = strecke_waehlen(distanz, fein)
|
||||
|
||||
if not ist_gefahren(distanz):
|
||||
# Gemessene Null: das Fahrzeug hat sich nicht bewegt. Zündung an,
|
||||
# aber nicht gefahren - Radio, Tür öffnen, warten. Keine Fahrt.
|
||||
#
|
||||
# Die Dauer allein reicht als Prüfung nicht: der Eigentümer hatte
|
||||
# nach dem Löschen aller Nullfahrten bei JEDEM Import wieder eine
|
||||
@@ -197,12 +213,14 @@ async def _fahrten_importieren(k: Koordinator, verlaeufe: dict) -> dict:
|
||||
# 209177 -> 209177 km, vmax 3 km/h). MINDESTDAUER_S ließ sie durch,
|
||||
# weil sie mit 33 Minuten lang genug war.
|
||||
#
|
||||
# Nur die GEMESSENE Null wird verworfen, nicht die unbekannte:
|
||||
# liegt kein Kilometerstand vor, bleibt distanz None und die Fahrt
|
||||
# wird angelegt. Der Preis, bewusst getragen: eine echte Fahrt unter
|
||||
# einem Kilometer, bei der der Zähler nicht umsprang, geht dabei
|
||||
# verloren - sie wäre aber genau der Nulleintrag, den der
|
||||
# Eigentümer nicht im Bestand haben will.
|
||||
# Auf eine Nachkommastelle gerundet, nicht auf Gleichheit mit 0:
|
||||
# ab 0,1 km ist es eine Fahrt (Ansage des Eigentümers, 01.09.2026),
|
||||
# darunter zeigt die Oberfläche ohnehin "0,0 km" an und der Eintrag
|
||||
# sähe aus wie die Nullfahrten, die er gerade ausgeräumt hat.
|
||||
#
|
||||
# Nur die GEMESSENE Null wird verworfen, nicht die unbekannte: liegt
|
||||
# weder Kilometerstand noch GNSS-Zähler vor, bleibt distanz None und
|
||||
# die Fahrt wird angelegt.
|
||||
nicht_gefahren += 1
|
||||
continue
|
||||
|
||||
@@ -221,7 +239,13 @@ async def _fahrten_importieren(k: Koordinator, verlaeufe: dict) -> dict:
|
||||
fahrt = leere_fahrt(f_start, f_ende, "import")
|
||||
fahrt.update({
|
||||
"distance_km": distanz,
|
||||
"km_quelle": "sensor" if distanz is not None else None,
|
||||
"km_quelle": (
|
||||
None
|
||||
if distanz is None
|
||||
else "odometer+gnss"
|
||||
if gnss_verwendet
|
||||
else "sensor"
|
||||
),
|
||||
"odo_start": odo_start,
|
||||
"odo_end": odo_end,
|
||||
"avg_speed_kmh": durchschnitt,
|
||||
@@ -468,6 +492,7 @@ async def importieren(k: Koordinator, start: object, ende: object) -> None:
|
||||
verlaeufe = {
|
||||
"zuendung": await verlauf_lesen(k.hass, fahrtsignal(werte), von, bis),
|
||||
"km": await verlauf_lesen(k.hass, werte.KM_SENSOR, von, bis),
|
||||
"gnss_km": await verlauf_lesen(k.hass, werte.GNSS_KM_SENSOR, von, bis),
|
||||
"tank": await verlauf_lesen(k.hass, werte.TANK_SENSOR, von, bis),
|
||||
"tank_liter": await verlauf_lesen(k.hass, werte.TANK_LITER_SENSOR, von, bis),
|
||||
"tank_distanz": await verlauf_lesen(k.hass, werte.TANK_DISTANZ_SENSOR, von, bis),
|
||||
|
||||
Reference in New Issue
Block a user