Fahrt beenden auf Knopfdruck, Schieberegler, Zuendungspause (2026.9.3.5-.7)
Vier Themen aus einer Sitzung. 1. Die Fahrt endet wieder bei uns statt im Dongle (Abschnitt BW). Der Ignition-OFF-Timeout des FMM003 (900 s) und sein Schlaf-Timeout (ebenfalls 900 s) starten beide beim Zuendungs-Aus und fallen in derselben Sekunde - am 02.09. zweimal beobachtet, einmal ging das Trip-Ende verloren, einmal kam es eine Sekunde vor dem Schlaf an. Ausloeser ist jetzt die Zuendung, die Wartezeit laeuft in Home Assistant. ZUENDUNG_NACHLAUF_S = 180 wird in beiden Wegen abgezogen (ueber das Trip-Signal 1080 s, weil dessen Ende selbst an der verzoegerten Zuendung haengt). 2. Schieberegler, neu in beiden Codebasen. Schrittweite 5 Minuten; der Daumen war im Tagmodus weiss auf weiss und traegt jetzt einen Ring aus --line-strong - ein Token, das genau dort sichtbar ist, wo es gebraucht wird. 3. Knopf "Fahrt beenden" in der Zuletzt-Kachel (Abschnitt BX). Schliesst auf das letzte Lebenszeichen, nicht auf "jetzt", und kennzeichnet das Ende als vorlaeufig. Ein spaet eintreffendes Zuendungs-Aus zieht es nach - innerhalb von sechs Stunden, nur nach vorn, und nur bei einer vorlaeufigen Fahrt. ts_end wandert bewusst NICHT in edited_fields, sonst blockierte der Schutz fuer Handeingaben genau diese Korrektur. 4. Das OTA-Buendel kann auf dem Mac gar nicht entstehen (Abschnitt BV): npm run ota ist eine Windows-PowerShell-Datei, ios-signieren.sh baut ein frisches dist/ und fasst das Buendel nie an. Ausgeliefert war deshalb eine Oberflaeche ohne den Versionshinweis unter richtiger Nummer. Verifiziert: Backend 27/27 (5 Signalwechsel, 14 Zuendungspause, 8 Fahrtende), companion-app tsc sauber und 179/179, Panel als Modul geparst, audi_ha_test auf 2026.9.3.7 sauber gestartet. Live am laufenden Panel und ohne Rueckstand belegt: Wartezeit samt Abbruch, die 180-s-Rechnung, der Regler im Tagmodus und der Knopf von der laufenden Fahrt bis zum verworfenen Kurzvorgang - Fahrten vorher 16, nachher 16. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,10 @@
|
||||
# AGENTS.md — Project state, review findings, open items, and working rules
|
||||
|
||||
**Last updated: 2026-09-03** (Das OTA-Buendel kann auf dem Mac gar nicht entstehen - ausgeliefert war eine
|
||||
**Last updated: 2026-09-03** („Fahrt beenden“ auf Knopfdruck mit vorlaeufigem Ende, Schieberegler in
|
||||
5-Minuten-Schritten und im Tagmodus sichtbar, `2026.9.3.7`, Abschnitt BX.
|
||||
Davor: Die Fahrt endet wieder bei uns statt im Dongle - Zuendung als Ausloeser,
|
||||
eigene Wartezeit, Nachlauf des Geraets abgezogen, Schieberegler, `2026.9.3.5`, Abschnitt BW.
|
||||
Davor: Das OTA-Buendel kann auf dem Mac gar nicht entstehen - ausgeliefert war eine
|
||||
Oberflaeche ohne den Versionshinweis unter richtiger Nummer, repariert mit `2026.9.3.4`,
|
||||
Abschnitt BV. Davor: Zwei Signalwechsel in derselben Sekunde kosteten eine Fahrt - Sperre
|
||||
plus Regressionstest, Bildformat-Pruefung, `2026.9.3.3`, Abschnitt BU. Davor: Rueckblick loest Orte
|
||||
@@ -8762,3 +8766,179 @@ braucht es nicht: die Zip-Einträge schreibt die PowerShell-Fassung ohnehin von
|
||||
ihrem Kopf), `zlib.deflateRawSync` reicht. Dazu ein Wächter, der in der **Git-Historie** den letzten
|
||||
Commit an `bundle.zip` gegen den letzten an `companion-app/src` und `design-system/src` hält — über
|
||||
Git und nicht über Dateidaten, weil ein frischer Klon alle Zeitstempel plattmacht.
|
||||
|
||||
---
|
||||
|
||||
## BW. Die Fahrt endet wieder bei uns, nicht im Dongle (2026.9.3.5)
|
||||
|
||||
### Der Befund: zwei Uhren, dieselbe Sekunde
|
||||
|
||||
Der FMM003 beendet den Trip erst nach seinem `Ignition OFF Timeout` (`11804`) von 900 s — und sein
|
||||
Schlaf-Timeout (`103`) stand auf denselben 900 s. Beide starten beim Zuendungs-Aus. Am 02.09.2026
|
||||
ist das zweimal beobachtet worden, mit **entgegengesetztem Ausgang**:
|
||||
|
||||
| | Zuendung aus | Trip-Ende erwartet | tatsaechlich |
|
||||
|---|---|---|---|
|
||||
| Fahrt A | 16:54:21 | 17:09:21 | **nichts** — naechster Datensatz erst 18:42:04 |
|
||||
| Fahrt B | 21:43:15 | 21:58:15 | 21:58:16 (+901,2 s) |
|
||||
|
||||
Ein Wettlauf, gemessen, nicht vermutet. Die Doku entkraeftet dabei die naheliegende Erklaerung: im
|
||||
Deep Sleep **sendet** das Geraet sehr wohl, High-priority-Datensaetze sogar sofort ("device can save
|
||||
periodical or eventual records and send data to server based on the selected AVL packet priority").
|
||||
Die Prioritaet regelt die Zustellung, nicht die Entstehung — und im Deep Sleep sind `Speed`,
|
||||
`Trip Odometer` und `Total Odometer` aus den Datensaetzen ausgeschlossen, also genau die Groessen, aus
|
||||
denen das Trip-Szenario lebt.
|
||||
|
||||
Der Zielkonflikt ist unaufloesbar, solange das Geraet die Uhr fuehrt: der Eigentuemer will, dass der
|
||||
Dongle frueh einschlaeft (Strom), und dass das Ende ankommt. Beides zugleich geht nicht.
|
||||
|
||||
### Die Loesung: die Wartezeit laeuft, wo nichts schlaeft
|
||||
|
||||
Ausloeser ist jetzt die **Zuendung** (`50000:2` High, `50001:5` On Change seit 01.09.2026 — sie wird
|
||||
im Moment des Wechsels gesendet), die Wartezeit laeuft in Home Assistant. Der Dongle darf danach
|
||||
frueher schlafen als vorher, nicht spaeter.
|
||||
|
||||
**`ZUENDUNG_NACHLAUF_S = 180`** (Geraeteparameter `400`, "Ignition OFF Delay"). Abgezogen wird in
|
||||
**beiden** Wegen: ueber die Zuendung 180 s, ueber das Trip-Signal 1080 s — denn das Trip-Ende haengt
|
||||
selbst an der bereits verzoegerten Zuendung (Fahrt B oben belegt es auf die Sekunde). Der Wert stand
|
||||
bis 31.08. auf 0 und seit **01.09. 09:38** auf 180; **Fahrten aus dieser Zeit enden 180 s zu spaet**,
|
||||
korrigiert wird ab jetzt. `_nachlauf_gegenpruefen()` musste mit — ohne Anpassung haette sie ab sofort
|
||||
bei jeder Fahrt 180 s Abweichung gemeldet.
|
||||
|
||||
**Die Wartezeit laeuft ausserhalb der Fahrtsperre.** Haette die Hintergrundaufgabe die Sperre, stuende
|
||||
ein zurueckkehrendes "on" eine Viertelstunde davor, statt die Fahrt fortzusetzen — das Gegenteil des
|
||||
Zwecks. Das Schliessen selbst ist mit `asyncio.shield()` gegen den Abbruch abgeschirmt: ein Wechsel
|
||||
genau im Schreibmoment duerfte keine halbe Zeile in `fahrten.jsonl` hinterlassen.
|
||||
|
||||
**Die Wartezeit entscheidet nur, OB geschlossen wird, nicht WANN die Fahrt endete.** Das Ende steht
|
||||
beim Zuendungs-Aus fest.
|
||||
|
||||
**Keine doppelte Wartezeit:** `_pausenzeit_s()` liefert 0, solange `TRIP_SENSOR` zugeordnet ist —
|
||||
dann wartet das Geraet bereits. Genau daran war die Pausenregel am 31.08.2026 entfallen.
|
||||
|
||||
**Spaetes Aus** wird ueber die **Geraetezeit** entschieden, nicht ueber die Reihenfolge des
|
||||
Eintreffens: faellt es in die schon geschlossene Fahrt, wird es verworfen und protokolliert; passt es
|
||||
zu keiner, gibt es eine Warnung — dann ist ein Fahrtbeginn entgangen.
|
||||
|
||||
### Was die Daten ueber die Drehzahlquelle sagen
|
||||
|
||||
Aus 21 Geraetekonfigurationen rekonstruiert: `101` ist eine Bitmaske (2 = ACC, 4 = Power Voltage,
|
||||
8 = RPM). Aussetzer der Zuendung gibt es — aber sie sind **kurz (1–2 s) und liegen am Fahrtanfang**,
|
||||
in den ersten 25 Sekunden; fuer einen Ausfall ueber Minuten waehrend der Fahrt gibt es keinen Beleg.
|
||||
Die Stichprobe der aktuellen Konfiguration ist zwei Fahrten gross, das gehoert dazugesagt. Dazu
|
||||
kommt **Start-Stopp**: der RS4 stellt an der Ampel den Motor ab, aus einer Drehzahlquelle ist das
|
||||
nicht vom Abstellen zu unterscheiden. Die abbrechbare Wartezeit verschluckt beides — ein Argument
|
||||
fuer einen grosszuegigen Standardwert, nicht gegen den Ansatz.
|
||||
|
||||
### Der Schieberegler
|
||||
|
||||
`Slider` / `.ads-schieber` im Design-System, `.schieber` im Panel — es gab bisher **nirgends** einen.
|
||||
Ein echtes `input[type=range]` (Tastatur und Vorlesefunktion ohne Zutun), selbst gemalt, weil er
|
||||
sonst im Panel wie Chrome und in der App wie WebKit aussaehe. Der gefuellte Teil kommt aus
|
||||
`--fuell` / `--ads-fuell`, weil ein Range-Feld seinen Wert nicht ans Stylesheet weitergibt und
|
||||
`accent-color` entfaellt, sobald man die Spur selbst gestaltet. Farben wie beim Balken: `--fg` auf
|
||||
`--ios-fill` — Markenrot bleibt den Stellen vorbehalten, die Aufmerksamkeit verlangen.
|
||||
|
||||
Im Panel zieht der `input`-Zweig nur Fuellung und Anzeige nach und ruft **kein** `render()`;
|
||||
gespeichert wird im `change`-Zweig beim Loslassen. Ein Re-Render mitten in der Geste erzeugt den
|
||||
Regler neu und der Daumen springt aus der Hand — dieselbe Trennung wie beim Suchfeld im Setup.
|
||||
|
||||
Erklaerender Text als **Fusszeile der Gruppe**, nicht als Info-Knopf: das ist Apples eigenes Muster
|
||||
fuer Einstellungen.
|
||||
|
||||
### Verifiziert
|
||||
|
||||
Backend **19/19** (5 alte, 14 neue in `tests/fahrterkennung/test_zuendungspause.py`), companion-app
|
||||
`tsc` sauber und **179/179**, Panel als Modul geparst, `audi_ha_test` auf `2026.9.3.5` sauber
|
||||
gestartet. Live im Panel gemessen: Regler 28 px hoch, Fuellung 25 % bei 15 von 60, Ziehen aktualisiert
|
||||
Anzeige und Fuellung **ohne** dass das Element ersetzt wird (`isConnected` bleibt true), Loslassen
|
||||
schreibt — `fahrten_pausenzeit_min = 25` stand danach in `fahrzeugprofil.json`.
|
||||
|
||||
**Ehrliche Luecke:** die Kette "Zuendung aus → Wartezeit → Fahrt geschlossen" ist durch die
|
||||
Regressionstests belegt, nicht durch eine echte Fahrt im Container. Alle drei Koordinator-Eigenschaften,
|
||||
die sie anfasst (`warte_ende_ab`, `ablage`, `zuordnung`), werden in demselben Modul bereits am echten
|
||||
Objekt benutzt.
|
||||
|
||||
---
|
||||
|
||||
## BX. „Fahrt beenden" auf Knopfdruck, mit vorläufigem Ende (2026.9.3.6/.7)
|
||||
|
||||
### Wofür der Knopf da ist
|
||||
|
||||
Wunsch des Eigentümers: das Fahrzeug steht in einer Tiefgarage ohne Empfang, das Gerät kann sein
|
||||
Zündungs-Aus nicht melden, und die Fahrt bliebe offen, bis irgendwann gepufferte Datensätze
|
||||
eintreffen. Der Knopf schliesst sie sofort.
|
||||
|
||||
**Geschlossen wird auf das letzte Lebenszeichen, nicht auf „jetzt".** Das Fahrzeug stand still, als
|
||||
es still stand, nicht als jemand gedrückt hat — und im Anwendungsfall liegen die beiden weit
|
||||
auseinander. `_letztes_lebenszeichen()` gab es dafür schon (`nach_neustart_fortsetzen`).
|
||||
|
||||
**Genau deshalb ist dieses Ende vorläufig.** Der Eigentümer hat den wunden Punkt selbst benannt:
|
||||
fährt das Fahrzeug nach dem Knopfdruck noch aus der Garage heraus, kommt der Rest gepuffert nach,
|
||||
und dann gehört das Ende **nachgezogen** statt verworfen. Neues Feld `ende_vorlaeufig` an der Fahrt;
|
||||
`_vorlaeufiges_ende_korrigieren()` zieht `ts_end` und `duration_s` nach und stösst das Screening neu
|
||||
an.
|
||||
|
||||
Drei Bedingungen dafür, jede aus einem eigenen Grund: nur eine als vorläufig gekennzeichnete Fahrt
|
||||
(eine regulär geschlossene ist bereits richtig), nur ein **späteres** Ende (früher wäre kein
|
||||
Nachtrag, sondern eine Verkürzung), und nur innerhalb von `KORREKTUR_FENSTER_S = 6 h` — jenseits
|
||||
davon gehört das Aus wahrscheinlich zu einer ganz anderen Fahrt.
|
||||
|
||||
**Die Falle, die dabei fast zugeschnappt wäre:** `ts_end` darf **nicht** in `edited_fields` landen.
|
||||
Der Schutz für Handeingaben würde sonst genau die Korrektur blockieren, für die das Feld gebaut ist.
|
||||
Ein Test hält das fest.
|
||||
|
||||
### „vorläufig" hängt am Wert, nicht an der Fahrt
|
||||
|
||||
Entscheidung des Eigentümers zwischen zwei gerenderten Mustern: die Strecke steht mit Tilde da
|
||||
(`~ 14,2 km`), darunter `vorläufig` — und der **Verbrauch erscheint gar nicht**, bis er feststeht.
|
||||
Die Alternative (beide Werte mit Tilde, „vorläufig" links an der Fahrt) ist verworfen.
|
||||
|
||||
Solange die Fahrt **läuft**, steht rechts **nichts** — keine Strecke, kein Verbrauch, auch kein
|
||||
Strich. Ein Strich behauptet „hier fehlt ein Wert"; richtig ist „hier gibt es ihn noch nicht".
|
||||
Dafür hat `Blattzeile` in der App ein optionales `aktion` bekommen und `wert` ist optional geworden.
|
||||
|
||||
### Woran die Oberflächen erkennen, dass eine Fahrt läuft
|
||||
|
||||
Neues Feld `faehrt_seit` im Fahrzeugstatus — der eigene Zwischenstand der Fahrterkennung
|
||||
(`fahrt_start_ts`), nicht der Rohwert einer Entität. Die Zündung allein taugt nicht: beim
|
||||
Trip-Signal steht sie nach dem Abstellen noch 900 s auf „an", und bei laufendem Motor im Stand
|
||||
ebenfalls.
|
||||
|
||||
### Der Knopf
|
||||
|
||||
`.zeilenknopf` / `.dm-zeilenknopf`, Pillenform im Umriss — vom Eigentümer aus zwei gerenderten
|
||||
Fassungen gewählt. 36 px sichtbar, 44 px Trefferhöhe über ein Pseudoelement, damit die Zeile nicht
|
||||
höher wird als ihre Nachbarin. Der Dienst `fahrt_jetzt_beenden` läuft in der App **nicht** über die
|
||||
Warteschlange: im Funkloch abgesetzt und Stunden später nachgeholt schlösse er eine Fahrt, die
|
||||
längst regulär zu Ende ist — dieselbe Begründung wie bei `historieImportieren()`.
|
||||
|
||||
### Verifiziert
|
||||
|
||||
Backend **27/27** (5 Signalwechsel, 14 Zündungspause, 8 neu in
|
||||
`tests/fahrterkennung/test_fahrtende_knopf.py`), companion-app `tsc` sauber und **179/179**, Panel
|
||||
als Modul geparst, `audi_ha_test` auf `2026.9.3.7` sauber gestartet.
|
||||
|
||||
**Live am laufenden Panel, ohne Rückstand:** Meldezeit frisch gesetzt, Zündung an → Zeile zeigt
|
||||
„Aktuelle Fahrt / läuft", Knopf 36 px in einer 66 px hohen Zeile, **keine Wertespalte und kein
|
||||
Chevron**. Knopf gedrückt → `Fahrt seit … von Hand beendet, vorlaeufiges Ende …`, danach
|
||||
`Zündung war nur 0 s an - keine Fahrt angelegt (Grenze 60 s)`. Fahrten vorher 16, nachher 16. Der
|
||||
Trick für die Rückstandsfreiheit ist derselbe wie bei der Wartezeit: liegt der Beginn nahe am
|
||||
letzten Lebenszeichen, verwirft `MINDESTDAUER_S` den Vorgang.
|
||||
|
||||
Beim anschliessenden Zurücksetzen der Zündung hat auch der zweite Zweig gefeuert und richtig
|
||||
gemeldet: `Zuendungs-Aus … ohne laufende Fahrt, und es gehoert zu keiner geschlossenen — ein
|
||||
Fahrtbeginn ist uns entgangen`. Korrekt, denn die Testfahrt war ja verworfen worden.
|
||||
|
||||
**Ehrliche Lücke:** die Korrektur eines vorläufigen Endes durch ein spät eintreffendes Zündungs-Aus
|
||||
ist durch 8 Regressionstests belegt, nicht durch eine echte Tiefgaragenfahrt.
|
||||
|
||||
### Der Regler, im selben Zug
|
||||
|
||||
Schrittweite von 1 auf **5 Minuten** — Apples eigene Seite mahnt für weite Wertebereiche einen
|
||||
Weg zur genauen Eingabe an, und bei 0–60 in Einerschritten sind das 3,8 px je Minute. 13 Rastpunkte
|
||||
treffen sich bequem, und minutengenau ist hier ohnehin Scheingenauigkeit.
|
||||
|
||||
Der Daumen war im **Tagmodus** kaum zu sehen: weiss auf weisser Kachel, nur ein Schatten. Er hat
|
||||
jetzt `border: 1px solid var(--line-strong)` — ein Token, zwei Themen: im Tagmodus zeichnet es ihn
|
||||
ab, im Nachtmodus ist es auf Weiss unsichtbar, wo es nicht gebraucht wird.
|
||||
|
||||
Reference in New Issue
Block a user