Rueckblick legt keine Fahrten ohne gefahrene Strecke mehr an (2026.9.1.12)

Der Eigentuemer hatte auf der realen Instanz alle Nullfahrten geloescht - und
bei JEDEM Import kam eine davon wieder: 31.08.2026, 14:48-15:21, 33 Minuten,
209177 -> 209177 km, vmax 3 km/h. MINDESTDAUER_S liess sie durch, weil sie mit
33 Minuten lang genug war; eine Pruefung auf die Strecke gab es im Rueckblick
nicht.

Steht der Kilometerstand an beiden Enden gleich, hat sich das Fahrzeug nicht
bewegt - Zuendung an, aber nicht gefahren. Solche Fenster werden jetzt
uebersprungen und als eigene Zahl gemeldet, damit der Import nicht
stillschweigend etwas weglaesst.

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 Zaehler
nicht umsprang, geht verloren - sie waere aber genau der Nulleintrag, den der
Eigentuemer nicht im Bestand haben will.

Beide Oberflaechen melden die neue Zahl (Paritaetsregel).

VERIFIZIERT im Testcontainer ueber den echten Dienst: 1 Fahrt angelegt,
2 Fenster als "nicht gefahren" uebersprungen, null Fahrten mit 0 km im Bestand.
py_compile, Panel als Modul, tsc --noEmit sauber, 165/165 gruen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-01 18:36:33 +02:00
parent 02187ee129
commit be95b40d79
7 changed files with 41 additions and 5 deletions
+1
View File
@@ -163,6 +163,7 @@ export interface ImportErgebnis {
fahrten_angelegt?: number;
fahrten_uebersprungen?: number;
fahrten_zu_kurz?: number;
fahrten_nicht_gefahren?: number;
tankvorgaenge_angelegt?: number;
tankvorgaenge_uebersprungen?: number;
batterie_tage?: number;
@@ -44,6 +44,14 @@ export function ergebnisText(d: ImportErgebnis): string {
"Zündungen zu kurz für eine Fahrt",
),
)
if (d.fahrten_nicht_gefahren)
teile.push(
anzahl(
d.fahrten_nicht_gefahren,
"Zündung ohne gefahrene Strecke",
"Zündungen ohne gefahrene Strecke",
),
)
if (d.tankvorgaenge_angelegt)
teile.push(anzahl(d.tankvorgaenge_angelegt, "Tankvorgang", "Tankvorgänge"))
if (d.batterie_tage)
@@ -1 +1 @@
{"version":"2026.9.1.11","sha256":"02c280790b205ea78638997a92aca00dbe7c099c2ad897ccf7eee50394e598b2","bytes":265708,"gebaut":"2026-09-01T16:21:24Z"}
{"version":"2026.9.1.12","sha256":"5a2d5547cbc6db6850e46892ea422de08642f86fc634b5887322389b4e0af589","bytes":265724,"gebaut":"2026-09-01T16:35:22Z"}
@@ -4269,6 +4269,7 @@ function importErgebnisText(d) {
const teile = [anzahl(d.fahrten_angelegt || 0, "Fahrt", "Fahrten") + " angelegt"];
if (d.fahrten_uebersprungen) teile.push(`${de(d.fahrten_uebersprungen)} bereits vorhanden`);
if (d.fahrten_zu_kurz) teile.push(anzahl(d.fahrten_zu_kurz, "Zündung zu kurz für eine Fahrt", "Zündungen zu kurz für eine Fahrt"));
if (d.fahrten_nicht_gefahren) teile.push(anzahl(d.fahrten_nicht_gefahren, "Zündung ohne gefahrene Strecke", "Zündungen ohne gefahrene Strecke"));
if (d.tankvorgaenge_angelegt) teile.push(anzahl(d.tankvorgaenge_angelegt, "Tankvorgang", "Tankvorgänge"));
if (d.batterie_tage) teile.push(anzahl(d.batterie_tage, "Tag Batteriespannung", "Tage Batteriespannung"));
return teile.join(" · ");
@@ -159,7 +159,7 @@ async def _fahrten_importieren(k: Koordinator, verlaeufe: dict) -> dict:
Zielkoordinaten aus den übrigen Verläufen ergänzt."""
fenster = _fahrtfenster(verlaeufe["zuendung"])
if not fenster:
return {"angelegt": 0, "uebersprungen": 0, "zu_kurz": 0}
return {"angelegt": 0, "uebersprungen": 0, "zu_kurz": 0, "nicht_gefahren": 0}
bestehende = await k.ablage.fahrten_lesen()
km_verlauf = verlaeufe["km"]
@@ -168,7 +168,7 @@ async def _fahrten_importieren(k: Koordinator, verlaeufe: dict) -> dict:
tank_liter_verlauf = verlaeufe["tank_liter"]
tempo_verlauf = verlaeufe["tempo"]
angelegt = uebersprungen = zu_kurz = 0
angelegt = uebersprungen = zu_kurz = nicht_gefahren = 0
neue: list[dict] = []
for f_start, f_ende in fenster:
@@ -186,6 +186,26 @@ 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.
#
# Die Dauer allein reicht als Prüfung nicht: der Eigentümer hatte
# nach dem Löschen aller Nullfahrten bei JEDEM Import wieder eine
# davon im Bestand (31.08.2026, 14:48-15:21, 33 Minuten,
# 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.
nicht_gefahren += 1
continue
durchschnitt = durchschnitt_kmh(distanz, dauer_s)
if durchschnitt is not None and durchschnitt > UNPLAUSIBLE_KMH:
_LOGGER.warning(
@@ -223,7 +243,12 @@ async def _fahrten_importieren(k: Koordinator, verlaeufe: dict) -> dict:
angelegt += 1
await k.ablage.fahrten_ergaenzen(neue)
return {"angelegt": angelegt, "uebersprungen": uebersprungen, "zu_kurz": zu_kurz}
return {
"angelegt": angelegt,
"uebersprungen": uebersprungen,
"zu_kurz": zu_kurz,
"nicht_gefahren": nicht_gefahren,
}
async def _tankvorgaenge_importieren(k: Koordinator, verlaeufe: dict) -> dict:
@@ -476,6 +501,7 @@ async def importieren(k: Koordinator, start: object, ende: object) -> None:
"fahrten_angelegt": fahrten["angelegt"],
"fahrten_uebersprungen": fahrten["uebersprungen"],
"fahrten_zu_kurz": fahrten["zu_kurz"],
"fahrten_nicht_gefahren": fahrten.get("nicht_gefahren", 0),
"tankvorgaenge_angelegt": tank["angelegt"],
"tankvorgaenge_uebersprungen": tank["uebersprungen"],
"batterie_tage": batterie["tage"],
@@ -1,7 +1,7 @@
{
"domain": "audi_dashboard",
"name": "Audi Dashboard",
"version": "2026.9.1.11",
"version": "2026.9.1.12",
"documentation": "https://gitea.nothaft.cloud/paul/audi-app/src/branch/main/README.md",
"issue_tracker": "https://gitea.nothaft.cloud/paul/audi-app/issues",
"codeowners": ["@paul"],