Keine Phantomfahrt beim Neustart, Tankstand auf wert_bei() (2026.9.1.1)
zuendung_geaendert() prueste den neuen Zustand, aber nicht den alten. Beim Hochfahren taucht die Zuendungs-Entitaet neu auf; das kommt als Wechsel mit old_state = None an. Steht das Trip-Signal ohnehin auf "an" - beim FMM003 der Normalfall -, las der Beobachter das als "Zuendung ging gerade an" und legte eine Fahrt an, deren Beginn schlicht der Zeitpunkt des Neustarts war. Daher der Eintrag 30.08. 19:43 bis 31.08. 08:37, 12,9 h, 0 km. Die Pruefung ist "if alt is None: return" - dieselbe, die _kilometerstand_geaendert() im Koordinator seit jeher hat. Eine wirklich laufende Fahrt geht nicht verloren: deren Beginn liegt im Store und wird von nach_neustart_fortsetzen() aufgenommen. Nachgewiesen: zwei Neustarts hintereinander bei trip_status = on und leerem Zwischenstand, null "Fahrt gestartet"-Zeilen und fahrt_start_ts bleibt null. Vorher entstand unter genau diesen Bedingungen jedes Mal eine. _verbrauch_screenen() liest die Literstaende jetzt ebenfalls mit wert_bei() statt naechster_wert() - dieselbe Doppelbewertung gegenueber historienimport.py wie beim Kilometerstand, eine Ebene tiefer. naechster_wert() bleibt bei Breiten-/Laengengrad: eine Position ist kein Zaehler. Auf Anweisung des Eigentuemers ausserdem die zwoelf Fahrten mit distance_km == 0 geloescht (ueber den Dienst fahrt_loeschen, nach einem backup_jetzt) und "Open items" in AGENTS.md aufgeraeumt: vier Karteileichen des MQTT-Wegs entfernt, Cloudflare-Zugang und iPhone-Signatur als erledigt gebucht, Befund 07 als Nutzereingabe geschlossen, QR-Scanner auf den halben Umfang gekuerzt. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
# AGENTS.md — Project state, review findings, open items, and working rules
|
||||
|
||||
**Last updated: 2026-08-31** (Streckenberechnung: `wert_bei()` statt `naechster_wert()` und
|
||||
**Last updated: 2026-09-01** (Phantomfahrten beim Neustart abgestellt, Tankstand auf `wert_bei()`
|
||||
nachgezogen, zwölf Nullfahrten gelöscht, „Open items" von vier MQTT-Karteileichen befreit;
|
||||
Manifest `2026.9.1.1`, siehe Abschnitt AX. Davor am 2026-08-31: Streckenberechnung: `wert_bei()`
|
||||
statt `naechster_wert()` und
|
||||
Rückwärtssprünge verworfen, Manifest `2026.8.31.6`, siehe Abschnitt AW. Davor am selben Tag:
|
||||
Audit über Panel und iOS-App: sieben Befunde, sechs behoben,
|
||||
`ZUENDUNG_SENSOR` auf das Trip-Signal des FMM003 umgelegt; Manifest `2026.8.31.5`, siehe
|
||||
@@ -439,15 +442,26 @@ wraps the web app for iPhone; a PWA home-screen install is the accepted intermed
|
||||
- [x] Offline UX per design brief (offline marker, visible pending queue)
|
||||
- [ ] **QR-Code-Scanner fürs Token-Onboarding (angefragt 2026-08-28, noch nicht geplant/gebaut)** —
|
||||
2026-08-11 bewusst weggelassen ("nur wenn es einfach bleibt"), der Owner will das jetzt doch als
|
||||
Alternative zum manuellen Einfügen. Ursprünglicher Plan aus `UMSETZUNGSPLAN.md` Phase 10 Stufe 2,
|
||||
Schritt 6: Barcode-Plugin (`@capacitor-mlkit/barcode-scanning`) + Kamera-Berechtigung in der App,
|
||||
Gegenstück eine kleine statische Seite unter HA `/local/dm360-qr.html`, die den Token **clientseitig**
|
||||
(Offline-JS-QR-Bibliothek, keine Netzabfrage) als QR anzeigt — Inhalt `{"url": "...", "token": "..."}`.
|
||||
Noch nicht scoped/umgesetzt.
|
||||
Alternative zum manuellen Einfügen.
|
||||
|
||||
### B) Infrastructure / commissioning (partly waits for FMM003 hardware)
|
||||
**Umfang halbiert am 2026-09-01:** Home Assistant zeigt den Token beim Anlegen bereits selbst
|
||||
als QR-Code an. Die geplante eigene Seite unter `/local/dm360-qr.html` entfällt damit ersatzlos —
|
||||
gebraucht wird nur noch die **Scanner-Seite in der App** (Barcode-Plugin
|
||||
`@capacitor-mlkit/barcode-scanning` + Kamera-Berechtigung). Offen bleibt eine Frage, die vor dem
|
||||
Bauen zu klären ist: HAs eigener QR trägt nur den Token, nicht die Instanz-URL — die muss also
|
||||
weiterhin von Hand kommen oder aus dem Netz gefunden werden.
|
||||
|
||||
- [ ] Switch `datametric360.de` nameservers at all-inkl to Cloudflare ("full setup") —
|
||||
### B) Infrastructure / commissioning
|
||||
|
||||
> **Aufgeräumt am 2026-09-01.** Vier Einträge sind hier ersatzlos entfallen, weil der
|
||||
> MQTT-/Mosquitto-Weg seit dem Wechsel auf flespi (2026-08-13) nicht mehr existiert: FMM003
|
||||
> verkabeln, Broker-Erreichbarkeit, MQTT Client Type, erste Codec-JSON aufzeichnen. Das Gerät
|
||||
> läuft seit dem 13.08. produktiv über flespi; die Feldzuordnung steht und ist gemessen (siehe
|
||||
> Abschnitt AU).
|
||||
|
||||
- [x] Switch `datametric360.de` nameservers at all-inkl to Cloudflare ("full setup") — **erledigt,
|
||||
vom Eigentümer bestätigt am 2026-09-01: Domain liegt bei Cloudflare, Nameserver stehen, die
|
||||
iOS-App ist darüber angebunden.**
|
||||
prerequisite for the tunnel; domain carries nothing else, so this is consequence-free. Step-by-
|
||||
step runbook for this and everything below it now exists:
|
||||
[`homeassistant/INTERNET_ZUGRIFF_EINRICHTEN.md`](homeassistant/INTERNET_ZUGRIFF_EINRICHTEN.md)
|
||||
@@ -463,43 +477,11 @@ wraps the web app for iPhone; a PWA home-screen install is the accepted intermed
|
||||
2026-08-28: corrected the stale `/local/dm360/*` assumption (never built) to the app's real
|
||||
remote need, its OTA bundle at `/audi_dashboard_static/app/*` (`@capgo/capacitor-updater`). See
|
||||
`homeassistant/REVERSE_PROXY.md`.
|
||||
- [ ] Install/wire the FMM003; record firmware version (Codec JSON is firmware-dependent)
|
||||
- [x] Generate TLS certificates for Mosquitto + device (small private CA) — done 2026-08-11, 10-year
|
||||
validity; Mosquitto configured (`certfile`/`keyfile`/`cafile`/`require_certificate: true`).
|
||||
Remaining: upload root/client cert/key to the FMM003 Security tab — filenames must end in
|
||||
`.pem`/`.pem.crt`/`.pem.key` (Configurator rejects plain `.crt`/`.key`, content-agnostic check)
|
||||
- [ ] Decide broker reachability for the vehicle — **reopened 2026-08-11 evening**: port-forward
|
||||
8883 on the Speedport Smart 4 Plus looked correctly configured (rule present, right internal
|
||||
IP, right port) and internal reachability was confirmed (`homeassistant.local:8883` open from
|
||||
the LAN, Mosquitto TLS listener genuinely up, TLS cert chain end-to-end verified byte-for-byte
|
||||
against the FMM003's uploaded client cert), but the port stayed **closed from outside**
|
||||
(confirmed via external port checker, both before and after a router reboot that changed the
|
||||
dynamic WAN IP — DNS/DuckDNS matched correctly each time, so not a DNS or CGNAT issue).
|
||||
Community reports (ComputerBase, Telekom Hilft) describe this as a known, Telekom-acknowledged
|
||||
firmware bug on this router model; a full disable-the-firewall workaround doesn't exist on this
|
||||
model either. Port-forward rule has been removed again. **New direction: route the FMM003
|
||||
through flespi instead** (native Teltonika/Codec8 channel, IMEI-based auth, no certs, no
|
||||
inbound port needed at all — flespi has a stable public endpoint; HA pulls data back out via
|
||||
flespi's REST API or MQTT, outbound-only). Free flespi tier (10 devices/2 channels) is enough
|
||||
for one vehicle. Next step: user creates the flespi account + Teltonika channel; a `flespi`
|
||||
custom integration is already present in this HA instance (unconfigured) — check what it
|
||||
needs once flespi-side setup exists.
|
||||
Unrelated but still valid from the same session: DuckDNS hostname
|
||||
`datametric360.duckdns.org` reliably updating; Let's Encrypt for HA's own local UI works (root
|
||||
cause of the earlier DNS-01 failures was a stray `aliases` entry in the DuckDNS add-on config,
|
||||
not DNS/network — see COMPANION_APP_ARCHITECTURE.md §5 item 2a). HA's SSL config now lives in
|
||||
Settings → System → Network (UI), not `configuration.yaml`'s old `http:` block, which was
|
||||
removed after HA started migrating/ignoring it. The Mosquitto TLS setup itself (cert chain,
|
||||
`require_certificate: true`, `certfile`/`keyfile`/`cafile`) is verified correct and can be
|
||||
reused as-is if a self-hosted broker is ever revisited.
|
||||
- [ ] MQTT Client Type on the FMM003 ("Custom server" not selectable in practice, "AWS IoT Custom"
|
||||
pointed at a self-hosted broker was confirmed working by two independent community reports) —
|
||||
**moot for now** given the flespi pivot above: flespi uses the device's native Codec8/TCP
|
||||
channel, not MQTT at all, so Server Settings should switch to Protocol: TCP against the flespi
|
||||
channel host/port instead, and Codec set to "Codec 8 Extended". Revisit this item only if a
|
||||
self-hosted broker is picked back up later.
|
||||
- [ ] Capture the first real Codec JSON message (`mosquitto_sub`/MQTT Explorer) and build the
|
||||
field mapping from it — **do not guess beforehand** (explicit decision)
|
||||
**Gegenstandslos seit dem Wechsel auf flespi (2026-08-13):** das Gerät spricht dort seinen
|
||||
nativen Codec-8-Kanal über TCP, ohne Zertifikate. Der Mosquitto-Aufbau bleibt nur als
|
||||
Bauanleitung stehen, falls je ein eigener Broker zurückkommt.
|
||||
- [x] Move trip detection to FMM003 ignition — done 2026-08-12. `fahrterkennung.py` rewritten:
|
||||
trigger is now `einstellungen.ZUENDUNG_SENSOR`
|
||||
(`binary_sensor.testzone_fmm003_engine_ignition_or_acc_status`, on = trip running) instead
|
||||
@@ -1730,9 +1712,12 @@ wraps the web app for iPhone; a PWA home-screen install is the accepted intermed
|
||||
2026-08-11 (`UMSETZUNGSPLAN.md` Phase 2): swipe-delete keyboard fallback, popup keyboard
|
||||
access, and self-hosting Leaflet stay unfixed in this panel and are addressed only in
|
||||
DataMetric360.
|
||||
- [ ] Optional: persist the RAM-only states (trip start, fuel low-water-mark) — deliberately
|
||||
deferred; may become moot with the FMM003 switch
|
||||
- [ ] Upload vehicle photos to `www/bilder/`, set `steuer.faellig` (operational data, not code)
|
||||
- [x] Persist the RAM-only states (trip start, fuel low-water-mark) — erledigt mit dem Umbau zur
|
||||
echten Integration: beide liegen im Laufzeit-Store des Koordinators
|
||||
(`…_laufzeit`: `fahrt_start_ts`, `tiefststand_pct`, `tiefststand_liter`) und überleben einen
|
||||
Neustart. Am 2026-09-01 am laufenden Container nachgesehen.
|
||||
- [x] Fahrzeugfoto hochladen — erledigt, über die App (`seitenansicht.webp`, 2026-08-31)
|
||||
- [ ] `steuer.faellig` setzen (Betriebsdaten, kein Code) — steht noch auf `None`
|
||||
|
||||
### D) Once the panel is superseded
|
||||
|
||||
@@ -6277,12 +6262,14 @@ aus deutschen Kommentaren sehen wie Klassen aus, und `ads-dot--${status}` wird z
|
||||
Laufzeit zusammengesetzt und taucht in keiner Suche auf — sechs Design-System-Klassen
|
||||
standen deshalb zunächst falsch auf der Liste und wurden vor dem Melden aussortiert.
|
||||
|
||||
### Offen: Befund 07, Erstzulassung
|
||||
### Geschlossen: Befund 07, Erstzulassung
|
||||
|
||||
`fahrzeug.erstzulassung` ist leer, deshalb steht bei der Hauptuntersuchung in beiden
|
||||
Oberflächen „kein Eintrag im Wartungsplan" — ohne dieses Datum gibt es keinen Anker,
|
||||
weder aus dem Wartungsplan noch aus einer Fahrzeugmeldung. Kein Codefehler; einzutragen
|
||||
unter Einstellungen → Fahrzeug einrichten. Bewusst nicht erfunden.
|
||||
weder aus dem Wartungsplan noch aus einer Fahrzeugmeldung. Kein Codefehler.
|
||||
|
||||
**Am 2026-09-01 vom Eigentümer geschlossen:** das ist eine Eingabe des App-Nutzers unter
|
||||
Einstellungen → Fahrzeug einrichten, kein offener Punkt des Projekts. Nicht wieder aufmachen.
|
||||
|
||||
### Was am Panel und an der App in Ordnung war
|
||||
|
||||
@@ -6358,6 +6345,54 @@ in der Praxis beantwortet sie der Code bereits, nur mit der falschen Antwort.
|
||||
(`screening.py:246`), während der Import dort `wert_bei()` nimmt. Dieselbe Doppelung
|
||||
wie oben, eine Ebene tiefer. Bewusst außerhalb des Auftrags gelassen.
|
||||
|
||||
## AX. Phantomfahrten beim Neustart, und der Tankstand zieht nach (2026.9.1.1)
|
||||
|
||||
### Jeder Neustart legte eine Fahrt an
|
||||
|
||||
`zuendung_geaendert()` prüfte den neuen Zustand, aber nicht den alten. Beim Hochfahren von
|
||||
Home Assistant taucht die Zündungs-Entität neu auf; das kommt als Zustandswechsel mit
|
||||
`old_state = None` an. Steht das Trip-Signal ohnehin auf „an" — beim FMM003 der Normalfall,
|
||||
solange die Zündung nicht sauber aus war —, las der Beobachter das als „Zündung ging gerade an"
|
||||
und legte eine Fahrt an, deren **Beginn schlicht der Zeitpunkt des Neustarts** war.
|
||||
|
||||
Daher der Eintrag `30.08. 19:43 → 31.08. 08:37, 12,9 h, 0 km`, und daher die Fahrt, die am
|
||||
31.08. um 21:18:45 UTC beim Ausliefern von `2026.8.31.6` entstand.
|
||||
|
||||
Die Prüfung ist `if alt is None: return` — dieselbe, die `_kilometerstand_geaendert()` im
|
||||
Koordinator seit jeher hat. Eine wirklich laufende Fahrt geht dabei nicht verloren: deren Beginn
|
||||
liegt im Store und wird von `nach_neustart_fortsetzen()` aufgenommen.
|
||||
|
||||
Nachgewiesen: zwei Neustarts hintereinander bei `trip_status = on` und leerem Zwischenstand,
|
||||
**null** `Fahrt gestartet`-Zeilen im Protokoll und `fahrt_start_ts` bleibt `null`. Vorher
|
||||
entstand unter genau diesen Bedingungen jedes Mal eine.
|
||||
|
||||
**Was das nicht löst, und der Eigentümer ausdrücklich will:** einen Beginn und ein Ende, die
|
||||
*aus den Daten des Dongles* stammen. Heute ist der Beginn `datetime.now()` im Moment, in dem
|
||||
Home Assistant den Wechsel verarbeitet — gemessen 0,5 bis 139 s nach dem Zeitstempel des Geräts,
|
||||
nach einer Funklücke Minuten. Und ein Wechsel, den es nie gab, wird nie erkannt: die echte Fahrt
|
||||
vom 31.08., 22:03–22:13 Ortszeit, hat die Live-Erkennung nicht gesehen, weil `trip_status`
|
||||
schon seit 18:39 auf „an" stand. Eigenes Arbeitspaket, hängt an der Konfiguration des Geräts.
|
||||
|
||||
### Der Tankstand liest jetzt wie der Kilometerstand
|
||||
|
||||
`_verbrauch_screenen()` holte die Literstände weiter mit `naechster_wert()`, während
|
||||
`historienimport.py` `wert_bei()` nimmt — dieselbe Doppelbewertung wie in Abschnitt AW, eine
|
||||
Ebene tiefer. Der zeitlich nächstgelegene Stand zum Fahrtbeginn kann schon in der Fahrt liegen
|
||||
und hätte dann einen Teil des Verbrauchs vorweggenommen.
|
||||
|
||||
`naechster_wert()` bleibt an einer Stelle richtig und steht dort weiter: Breiten- und
|
||||
Längengrad in `_position_screenen()` sind keine Zähler.
|
||||
|
||||
### Nullfahrten entfernt
|
||||
|
||||
Auf Anweisung des Eigentümers („0 km Fahrten sind keine Fahrten und damit zu entfernen") wurden
|
||||
am 2026-09-01 die zwölf Fahrten mit `distance_km == 0` gelöscht — über den eigenen Dienst
|
||||
`fahrt_loeschen`, nicht durch Hantieren an der Datei, und nach einem `backup_jetzt`
|
||||
(`backups/20260901_072541`). Bestand danach: 11 Fahrten, keine mit 0 km.
|
||||
|
||||
Das ist eine Abkehr von der Linie in Abschnitt W und AV, wo Nullfahrten bewusst stehen blieben.
|
||||
Sie gilt, weil der Eigentümer sie ausdrücklich getroffen hat — nicht als neue Gewohnheit.
|
||||
|
||||
## Working conventions (observed — keep them)
|
||||
|
||||
- German is the project language: identifiers, comments, commits, UI texts. Exceptions:
|
||||
|
||||
Reference in New Issue
Block a user