Neustart-Festhaenger, OTA-Pruefsumme, Statistik-Kopfzahl (2026.8.31.4)
Die App blieb nach einem Neustart von Home Assistant auf dem alten Stand stehen, mit einer 502-Fehlerzeile, die erst ein Beenden der App wegbekam. Zwei Ursachen: 502/503/504 galten als harter Ladefehler statt als "Server faehrt gerade hoch", und nach dem Wiederverbinden wurde genau einmal nachgeladen - schlug das fehl, kam nie wieder ein Versuch. Beides behoben, vier Regressionstests dazu. OTA: das Buendel ist von HEAD ueber die Platte bis zu den ausgelieferten Bytes nachweislich deckungsgleich. Die Fassung haengt jetzt trotzdem als ?v= an der Adresse (der statische Pfad kommt ohne Cache-Control, aber mit ETag), und ein Pruefsummenfehler wird erklaert statt durchgereicht. Statistik: der Gesamtwert steht jetzt als grosse Zahl in der Kopfzeile, darunter bleiben vier Spalten - fuenf passen auf dem Telefon nachweislich nicht in eine Zeile. Fahrzeugfoto ohne Beschnitt und ohne Bodenschatten, damit auch ohne den Schalter dafuer. Setup filtert zusaetzlich nach dem Signalnamen aus dem Katalog. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
# AGENTS.md — Project state, review findings, open items, and working rules
|
||||
|
||||
**Last updated: 2026-08-30** (owner findings batch - vehicle pin, tile chevrons, select arrows,
|
||||
**Last updated: 2026-08-31** (Neustart-Festhänger der App, OTA-Prüfsumme, Statistik-Kopfzahl,
|
||||
Setup-Filter und die gemessene Wahrheit über die Dongle-Konfiguration; Manifest `2026.8.31.4`,
|
||||
siehe Abschnitte AT und AU. Davor: 2026-08-30 (owner findings batch - vehicle pin, tile chevrons, select arrows,
|
||||
SmartDeal dialog, address cache and pull-to-refresh; manifest `2026.8.30.19`, see sections AO, AP and AQ.
|
||||
Before that: design-audit follow-through - the five priority items applied to
|
||||
both codebases, plus the location preview's wrong pin; manifest `2026.8.30.8`, see section AN.
|
||||
@@ -6050,6 +6052,143 @@ rendering bug in a view.
|
||||
|
||||
---
|
||||
|
||||
## AT. Neustart-Festhänger, OTA-Prüfsumme, Statistik-Kopfzahl, Setup-Filter (2026.8.31.4)
|
||||
|
||||
### Die App blieb nach einem Neustart von Home Assistant hängen
|
||||
|
||||
Gemeldet: während Update und Neustart zeigte die App „502 Error" unter einem längst
|
||||
gedrückten „Jetzt neu starten", und die Meldung blieb stehen, nachdem Home Assistant
|
||||
wieder lief — erst ein Beenden der App half. Zwei Ursachen, beide in
|
||||
`DatenKontext.tsx`:
|
||||
|
||||
1. **502 galt als harter Ladefehler.** `ApiFehler.istNetzproblem` ist nur `status === null`;
|
||||
ein Vorschaltserver, der antwortet, während Home Assistant noch hochfährt, liefert
|
||||
aber 502/503/504. Neu: `istVoruebergehend` fasst beides zusammen (500 bewusst **nicht** —
|
||||
das bessert sich durch Warten nicht). Solange schon Daten da sind, erscheint keine
|
||||
Fehlerzeile mehr.
|
||||
2. **Nach dem Wiederverbinden wurde genau einmal nachgeladen.** Die Websocket-Verbindung
|
||||
steht regelmäßig ein paar Sekunden vor der REST-Schnittstelle. Schlug dieser eine
|
||||
Versuch fehl, kam nie wieder ein `"verbunden"` — und damit nie wieder ein Versuch; die
|
||||
App blieb bis zum Beenden auf dem Stand von vor dem Neustart, mitsamt Fehlerzeile.
|
||||
Neu: `nachladenBisEsKlappt()` mit wachsenden Abständen (2/4/8/15/30/60 s, zusammen gut
|
||||
zwei Minuten), sauber abgeräumt beim Verlassen.
|
||||
|
||||
Dazu ein Fehler, den dieselbe Stelle verdeckt hat: `neuLaden` hing an `bereit`, der Effekt
|
||||
darunter aber nur an `api` — die dort festgehaltene Fassung sah `bereit` für immer als
|
||||
`false`. `bereit` liegt jetzt in einem Ref, `neuLaden` ist stabil. Vier Regressionstests
|
||||
(`DatenKontext.test.tsx`), gegen den alten Stand als fehlschlagend nachgewiesen.
|
||||
|
||||
Panel-seitig kein Gegenstück nötig: es hängt an Home Assistants eigener Verbindung, deren
|
||||
Wiederanlauf schon in Abschnitt N behandelt ist.
|
||||
|
||||
### „App-Update: failed to download / checksum failed"
|
||||
|
||||
**Das Bündel ist nachweislich in Ordnung.** Geprüft von Ende zu Ende: der Blob bei
|
||||
`HEAD`, die Datei auf der Platte und die tatsächlich über HTTP ausgelieferten Bytes
|
||||
haben alle denselben SHA-256, den auch `bundle.json` nennt; git behandelt die Zip als
|
||||
binär (`i/-text`), `core.autocrlf` kann ihr nichts anhaben. Die Prüfsumme, die das
|
||||
Plugin vergleicht, ist genau dieser Wert (`CapgoUpdater.swift`, `calcChecksum` über die
|
||||
heruntergeladene Zip vor dem Entpacken).
|
||||
|
||||
Der Fehler fiel zusammen mit dem Neustart — ein Download, der mitten hineinläuft, liefert
|
||||
je nach Zeitpunkt einen Abbruch („failed to download") oder unvollständige Bytes
|
||||
(„checksum"). Zwei Änderungen in `ota.ts`:
|
||||
|
||||
- Die Fassung hängt jetzt als `?v=` an der Bündel-Adresse. Home Assistant liefert
|
||||
`/audi_dashboard_static/` **ohne** `Cache-Control`, aber mit `ETag` und
|
||||
`Last-Modified` (nachgemessen) — genau der Fall, in dem jeder Zwischenspeicher nach
|
||||
eigenem Ermessen eine Weile die alte Datei behalten darf. Dieselbe Vorsorge trifft das
|
||||
Panel seit jeher für sein eigenes Bündel.
|
||||
- Ein Prüfsummenfehler wird nicht mehr wortwörtlich durchgereicht, sondern erklärt: „Das
|
||||
Update kam unvollständig an … sobald Home Assistant wieder läuft, noch einmal
|
||||
versuchen."
|
||||
|
||||
### Statistik: der Gesamtwert steht in der Kopfzeile
|
||||
|
||||
Erst sollte „Absolut" eine fünfte Spalte links werden. Am laufenden Panel gemessen passt
|
||||
das nicht: die Kachel ist auf dem Telefon innen **307px** breit, ein sechsstelliger
|
||||
Kilometerstand wie `209.177` misst in Audi Type Wide 300 **67px** bei 16px und 54px bei
|
||||
13px — fünf Spalten gingen nur mit kleinerer Schrift. Der Eigentümer hat daraufhin
|
||||
entschieden, den Gesamtwert dorthin zu setzen, wo man ihn zuerst liest: **die große Zahl
|
||||
oben in „Distanz und Fahrzeit" und „Getankte Menge und Kosten" ist jetzt der Gesamtwert,
|
||||
nicht mehr der des laufenden Jahres** — die Jahreszahl im Titel entfällt entsprechend.
|
||||
Darunter bleiben vier Spalten (Jahr/Monat/Woche/Tag), jetzt als `repeat(4, minmax(0,1fr))`
|
||||
statt `auto-fit`, das auf dem Telefon nur drei Spalten zuließ und die vierte umbrach.
|
||||
`ZEITRAEUME` rechnet weiter alle fünf, angezeigt wird `ZEITRAUM_SPALTEN`.
|
||||
|
||||
### Kein Schatten, kein Beschnitt — und kein Schalter mehr dafür
|
||||
|
||||
Gemessen statt geschätzt: das Foto ist 2000×1125 (16:9), der Kasten stand auf 16:8 und
|
||||
`object-fit: cover` schnitt oben und unten je ein Viertel ab — das Dach lag darin. Statt
|
||||
das Verhältnis auf 16:9 festzuschreiben (was beim nächsten Foto in einem anderen Format
|
||||
wieder schneiden würde) bestimmt jetzt das Bild selbst die Höhe; der Platzhalter behält
|
||||
sein festes Verhältnis, er hat keines von sich aus. Nachgemessen: Kasten 367×207 zu
|
||||
2000×1125 — kein Beschnitt.
|
||||
|
||||
Gleichzeitig sind der Ausblend-Verlauf und der Bodenschatten entfallen (beide Codebasen,
|
||||
inklusive der `height:220px`-Regel im iOS-Overlay, die den Beschnitt sonst auf breiten
|
||||
Schirmen wieder erzwungen hätte). Damit hatte der Schalter **„Fahrbahn unter dem
|
||||
Fahrzeug"** nichts mehr zu schalten und ist ebenfalls weg — samt `bodenAn`/`szeneKlasse()`
|
||||
im Panel und `useBoden`/`bodenKlasse`/`OHNE_SZENE` in der App. Der Regressionstest für
|
||||
den geteilten Einstellungsspeicher (`theme.test.tsx`) prüft das jetzt an
|
||||
`useTabBeschriftung` statt an `useBoden` — dieselbe Aussage, ein noch vorhandener Schalter.
|
||||
|
||||
### Setup: „Nur passende Sensoren" sucht nach dem Signalnamen
|
||||
|
||||
Domain und Einheit lassen bei einem Fahrzeug mit siebzig Sensoren immer noch Dutzende
|
||||
übrig. Der Name, der neben der Überschrift als „(z. B. …)" steht, ist der tatsächliche
|
||||
Signalname der Integration (`beispiel` in `FELDER`) und trifft genau einen. Er filtert
|
||||
jetzt mit — **mit Rückfall**: findet er nichts, bleibt die ungefilterte Liste stehen, denn
|
||||
er stammt aus dieser einen Installation. Zusätzlich zählt er in `entitaetScore()` mit 8
|
||||
Punkten, damit auch der Vorschlag für ein leeres Feld davon profitiert.
|
||||
|
||||
## AU. Der Dongle: was die Konfiguration wirklich bewirkt (2026-08-31)
|
||||
|
||||
Nachgemessen an der echten Aufzeichnung im Testcontainer (7 bzw. 30 Tage Recorder), nicht
|
||||
aus der Konfigurationsanzeige abgelesen.
|
||||
|
||||
**Was gut funktioniert.** Beim Fahren liefert das Gerät alle **10 s** (p90) einen Satz —
|
||||
das ist die eingestellte `Min Period` für „Moving", und sie gilt für Geschwindigkeit wie
|
||||
für Position gleichermaßen (771 bzw. 1165 Punkte in 7 Tagen). Für Strecke, Route,
|
||||
Durchschnitt und vmax reicht das: in denselben 7 Tagen wurde ein Höchstwert von 118 km/h
|
||||
erfasst. `can_fuel_volume` löst **0,1 l** auf (Werte wie 18,9 / 19,1 / 19,5 über 30 Tage;
|
||||
in einzelnen Wochen sieht man nur ganze Liter, das ist die Meldung des Fahrzeugs, nicht
|
||||
die Auflösung des Sensors) — die Grenze `MIN_STRECKE_VERBRAUCH_KM = 3.0` bleibt damit
|
||||
richtig hergeleitet. Der Füllstand in Prozent springt in 1-%-Schritten.
|
||||
|
||||
**Was nicht funktioniert: das rohe Zündsignal als Fahrterkennung.**
|
||||
`engine_ignition_or_acc_status` ist der ungefilterte Zündungseingang. In der Aufzeichnung:
|
||||
am 29.08. drei Wechsel innerhalb von **30 Millisekunden**, danach ein Aus/Ein-Paar mit
|
||||
**10 Sekunden** Abstand — und am 30./31.08. dreizehn Stunden am Stück „an", ohne Fahrt.
|
||||
Solange die App eine Pausentoleranz hatte, hat die das aufgefangen. Seit deren Entfernung
|
||||
(Abschnitt AS) trennt jeder solche Aussetzer eine Fahrt in zwei.
|
||||
|
||||
**Die Begründung für das Entfernen war falsch.** Der `Ignition OFF Timeout` von 900 s
|
||||
unter *Trip \ Odometer* verzögert **nicht** dieses Signal, sondern ausschließlich das
|
||||
geräteeigene Trip-Element ([Teltonika-Wiki](https://wiki.teltonika-gps.com/view/FMM003_Trip/Odometer_settings):
|
||||
„timeout value to detect Trip end once the Ignition … is off"). Es gab also nie zwei
|
||||
Zeitgeber hintereinander — es gab unseren, und daneben einen ungenutzten des Geräts.
|
||||
|
||||
**Die Empfehlung, noch nicht umgesetzt (Entscheidung des Eigentümers):**
|
||||
`ZUENDUNG_SENSOR` auf
|
||||
`binary_sensor.…_trip_status_true_if_trip_started_false_if_stopped` legen. Dieses Signal
|
||||
|
||||
- beginnt erst, wenn Zündung **und** Bewegung **und** `Start Speed` zusammenkommen —
|
||||
dreizehn Stunden Standlicht-Zündung erzeugen damit keine Fahrt,
|
||||
- endet erst 900 s nach Zündung aus — die Pausentoleranz kommt vom Gerät, ohne dass wir
|
||||
einen zweiten Zeitgeber bauen,
|
||||
- ist millisekundenfestes Prellen los.
|
||||
|
||||
Der Preis: das Fahrtende liegt 15 Minuten hinter dem tatsächlichen. Das war mit der
|
||||
eigenen Pausentoleranz genauso und ist damit kein Rückschritt; wer es genauer will, müsste
|
||||
das Ende nachträglich auf den letzten Punkt mit Geschwindigkeit > 0 zurückrechnen — eigenes
|
||||
Arbeitspaket, hier bewusst nicht angefangen.
|
||||
|
||||
**Weiter offen, unabhängig davon:** echte Funklöcher. Im gemessenen Zeitraum gab es
|
||||
mitten in der Fahrt eine Lücke von **2739 s** ohne einen einzigen Satz. Dagegen hilft keine
|
||||
Einstellung am Gerät; das ist der in Abschnitt P/W beschriebene Fall, den die
|
||||
Plausibilitätsgrenze (`UNPLAUSIBLE_KMH`) abfängt.
|
||||
|
||||
## Working conventions (observed — keep them)
|
||||
|
||||
- German is the project language: identifiers, comments, commits, UI texts. Exceptions:
|
||||
|
||||
Reference in New Issue
Block a user