e1180f8e34
Frontend, kleinere Befunde: - Das Standort-Menue liess sich nur wischen oder ueber den Kartenmarker oeffnen. Der Griff ist jetzt ein Knopf mit aria-expanded, damit auch per Tastatur erreichbar; der Umschalter Strasse/Satellit hat aria-pressed und ein Label, das den Zustand nennt. - Der Filterschalter "Nur passende Sensoren anzeigen" wirkte nicht, solange eine Auswahlliste offen war: der Klick-Handler ersetzte das Overlay-DOM, bevor das change-Ereignis des Kontrollkaestchens ausgeliefert wurde. Er wird jetzt vor dem Schliessen der Liste behandelt. - Der Theme-Wechsel zeichnete nicht neu, die Leaflet-Kacheln blieben bis zum naechsten Backend-Update im alten Stil - seit der Dauerkarte auf der Uebersicht deutlich sichtbar. - Toter Code entfernt (fahrzeugGlyphPfade, .dot.neutral) und zwei Kommentare berichtigt, die Gegenteiliges behaupteten. Dokumentation: - AGENTS.md widersprach sich an sechs Stellen. Berichtigt: Fahrterkennung laeuft ueber die Zuendung, nicht ueber WLAN; Datenweg ist flespi, nicht MQTT; Modulzahl und Zeilenzahl stimmen wieder; Entity-IDs werden im Setup-Menue zugeordnet, nicht in einstellungen.py; STANDORT_TRACKER ist belegt, nicht leer. - SPECIFICATION.md beschreibt durchgehend den Stand vor der FMM003- Umstellung. Statt es zu Teilen umzuschreiben und dabei Ungenauigkeiten zu riskieren, steht jetzt ein datierter Hinweis am Anfang, der die drei geaenderten Punkte benennt und auf AGENTS.md verweist. Alles Uebrige des Dokuments gilt unveraendert weiter. - INSTALL.md: Die zirkulaere Schrittfolge (Schritt 4 verweist auf 9, Schritt 7 auf 4) ist als solche benannt und aufgeloest. Die Override-Datei ist mit Pfad genannt, samt dem Hinweis, dass sie gesichert wird. Und die drei mit Test-Entitaeten der Entwicklungsinstanz vorbelegten Rollen sind erwaehnt - auf einer frischen Installation zeigen sie ins Leere. - README, Profilvorlage: WLAN-Reste entfernt, zwei Falschaussagen aus dem ersten Review nachgezogen (Statistik rechnet echt, die 97-Prozent-Volltankungsregel wurde entfernt), Dateiuebersicht um die fuenf fehlenden pyscript-Dateien und entitaeten.py ergaenzt. - update.ps1 liefert jetzt auch shell_beleg_parser.py aus. Die Datei liegt in data/, ist aber Code - Aenderungen am Belegleser, dem einzigen getesteten Teil des Projekts, kamen bisher auf keiner Instanz an. - design/README: Zwei Dateien der Inhaltstabelle liegen gar nicht in dem Ordner, weshalb das Board aus der Repo-Kopie heraus leer bleibt - jetzt vermerkt. Ausserdem die Behauptung berichtigt, die Auflage ruehre audi-dashboard-app.js nicht an: der Stylesheet-Loader wurde dort ergaenzt. Geprueft: Panel laedt, alle neun pyscript-Entitaeten werden veroeffentlicht, Zuordnen und Zuruecksetzen funktionieren, keine neuen Fehler im Protokoll.
432 lines
33 KiB
Markdown
432 lines
33 KiB
Markdown
# AGENTS.md — Project state, review findings, open items, and working rules
|
|
|
|
**Last updated: 2026-08-12** (Setup-menu polish batch). This file is the entry point for every new agent
|
|
session: what this repo is, what is finished, what is missing, and how to work here. Detail lives in
|
|
the linked documents — this file points, it does not duplicate.
|
|
|
|
> **Maintenance rule (binding):** whenever you change this repo in a way that affects anything
|
|
> recorded here — completing an open item, making or reversing a decision, adding/removing a
|
|
> component, discovering a new gap — **update this file in the same session** (tick the checkbox,
|
|
> adjust the status table, bump the "Last updated" date). This file must always be written in
|
|
> **English**, even though the rest of the project is German.
|
|
|
|
**How this file is loaded:** Claude Code does not read `AGENTS.md` natively; the root `CLAUDE.md`
|
|
imports it via `@AGENTS.md` (official recommended pattern). Other agents (Codex, Cursor, Copilot)
|
|
read `AGENTS.md` directly. Edit content here, not in `CLAUDE.md`.
|
|
|
|
---
|
|
|
|
## Working rules
|
|
|
|
### Karpathy guidelines (adopted as project standard)
|
|
|
|
From [`multica-ai/andrej-karpathy-skills`](https://github.com/multica-ai/andrej-karpathy-skills),
|
|
behavioral rules derived from Andrej Karpathy's observations on LLM coding failures. They bias
|
|
toward caution over speed — for trivial tasks, use judgment.
|
|
|
|
1. **Think before coding.** Don't assume. Don't hide confusion. Surface tradeoffs. State
|
|
assumptions explicitly; if multiple interpretations exist, present them — don't pick silently.
|
|
If a simpler approach exists, say so. Push back when warranted. If something is unclear, stop
|
|
and ask.
|
|
2. **Simplicity first.** Minimum code that solves the problem. Nothing speculative: no features
|
|
beyond what was asked, no abstractions for single-use code, no unrequested configurability, no
|
|
error handling for impossible scenarios. If 200 lines could be 50, rewrite.
|
|
3. **Surgical changes.** Touch only what you must. Don't "improve" adjacent code, comments, or
|
|
formatting; don't refactor what isn't broken; match existing style. Remove only orphans **your**
|
|
change created; mention (don't delete) pre-existing dead code. Every changed line should trace
|
|
directly to the request.
|
|
4. **Goal-driven execution.** Define success criteria, loop until verified. "Fix the bug" → write a
|
|
test that reproduces it, then make it pass. For multi-step tasks, state a brief plan with a
|
|
verify step per item.
|
|
|
|
### Claude Code practices (current guidance, 2026)
|
|
|
|
- Keep this file **concise and specific** — instructions concrete enough to verify ("run X before
|
|
Y"), markdown headers/bullets, no dense prose. Context files reduce adherence as they grow;
|
|
target roughly ≤200 lines of actual instruction.
|
|
- Don't record here what the code or git history already shows (directory dumps, dependency
|
|
lists) — record pitfalls, rationale, decisions, and conventions that differ from defaults.
|
|
- Conflicting instructions get picked arbitrarily — when updating, **remove** superseded rules
|
|
rather than stacking corrections.
|
|
- Verify loading with `/context` (file must appear under **Memory files**); edit via `/memory`.
|
|
- **This file (plus the session's task list) is the source of truth for what's done — not a leftover
|
|
plan-mode file.** A `~/.claude/plans/*.md` file surfaced by the system as "not yet complete" can be
|
|
stale: plan files aren't marked complete when their work finishes. Before claiming a feature is
|
|
unbuilt (e.g. "the Setup menu isn't implemented yet"), check the `[x]`/`[ ]` items below and/or the
|
|
task list — trust those over an old plan file's own claim about its status. (Caused a real mistake
|
|
2026-08-12: told the user the Setup menu wasn't built yet, when it had shipped hours earlier in
|
|
the same project — see the "Setup menu" `[x]` entry further down.)
|
|
|
|
---
|
|
|
|
## What this project is
|
|
|
|
Private replacement for the Audi *connect plug & play* app (discontinued end of 2026), for exactly
|
|
one vehicle (**Audi RS 4 Avant competition**), single user, self-hosted on Home Assistant, access
|
|
via Tailscale only. Read-only toward the vehicle — no remote control. Covers: vehicle status, trip
|
|
log, fuel log with Shell receipt parsing, service forecasting, insurance/tax, tire management.
|
|
|
|
**License rule (hard):** Audi Type fonts, four-rings SVG, and model-badge SVGs are cleared **only
|
|
for this one private, unpublished installation**. Therefore `design-system/` is brand-free (it gets
|
|
uploaded to Claude Design), while the HA panel and the future sideload-only app may use the real
|
|
assets. Never mix these the other way around.
|
|
|
|
**Reading order for a new session:**
|
|
1. This file (overview + open items)
|
|
2. `SPECIFICATION.md` — authoritative for the HA panel, incl. §7 "Known Gaps"
|
|
3. `COMPANION_APP_ARCHITECTURE.md` — authoritative for DataMetric360 (decided, barely built)
|
|
4. `AUDIT_2026-08-10.md` — accessibility/platform audit of the panel (partly done, rest below)
|
|
5. `bauauftrag.md` — **historical only**; code has diverged (see SPECIFICATION.md §7)
|
|
|
|
## The three projects in this repo
|
|
|
|
| Area | What | Status |
|
|
|---|---|---|
|
|
| `homeassistant/` | HA panel (`panel_custom`): pyscript backend + vanilla-JS frontend | ✅ **finished, in use** |
|
|
| `design-system/` | React component library `@audi-dash/ui`, brand-free, feeds Claude Design | ✅ done as a kit (20 components, 1,690 lines) |
|
|
| `companion-app/` | **DataMetric360** — successor app (Capacitor iOS/Android + HA iframe); will **replace** the panel | 🚧 data layer only (~930 lines TS), **no UI** |
|
|
| `design/` | Export of the Claude Design draft for DataMetric360 | 🚧 interim (wrong model, main screens only) |
|
|
|
|
Root files: `dashboard-muster*.html` = original static prototype (superseded, reference only),
|
|
`bauauftrag.md`/`.html` = original build brief (historical), `DESIGN_BRIEF_DATAMETRIC360.md` = the
|
|
prompt for the Claude Design project.
|
|
|
|
**`homeassistant/` in one paragraph:** 10 pyscript scripts + 5 modules (`pyscript/modules/`); trip
|
|
detection via the FMM003 ignition sensor with pause tolerance (the iPhone WLAN sensor is gone — see
|
|
section B), two-stage trip completion via HA history screening (odometer often updates only on the
|
|
next trip), fill-up detection on fuel-level rise, Shell PDF parser (`data/shell_beleg_parser.py`,
|
|
subprocess, the only tested part of the repo), tire km counter, backup, self-update, image
|
|
management. Frontend: one file `www/audi-dashboard-app.js`
|
|
(~4,000 lines, custom element, no framework/bundler), 5 tabs + ~19 detail routes, cache-busting via
|
|
`audi-dashboard-version.json` + loader stub. Entity IDs are assigned **in the UI** (Settings →
|
|
Fahrzeug einrichten → Setup), stored as overrides in `data/entitaeten.json`;
|
|
`pyscript/modules/einstellungen.py` holds only the built-in defaults. Deploy: `update.ps1`
|
|
(robocopy to Samba share) or — still inactive — self-update from git.
|
|
|
|
**`companion-app/` — what exists:** dependency-free, strictly typed TS data layer (`src/api/`):
|
|
REST client (`rest.ts`), WebSocket client with auth flow + reconnect backoff (`live.ts`),
|
|
persistent offline write queue (`warteschlange.ts`, strict FIFO), environment detection
|
|
capacitor/iframe/browser (`umgebung.ts`), types + entity table (`types.ts`), facade
|
|
`DataMetricApi` (`index.ts`). Smoke test ran 7/7 green against Docker HA `audi_ha_test`
|
|
(localhost:18123) — unauthenticated only; token-authenticated reads/writes untested.
|
|
|
|
**DataMetric360 architecture (short — details in `COMPANION_APP_ARCHITECTURE.md`):**
|
|
- Future data source: **Teltonika FMM003** on the CAN bus, fully replacing the iPhone WLAN sensor
|
|
and the VAG integration.
|
|
- **Current data path (since 2026-08-12): FMM003 → flespi (native Codec8/TCP, IMEI auth) → HA.**
|
|
Both earlier directions are dropped: Traccar first, then the self-hosted MQTT/TLS broker — the
|
|
router's port-forward turned out to be unusable. The decision logs deliberately remain in the
|
|
architecture doc, marked ÜBERHOLT. Details and open steps in section B below.
|
|
- Frontend access: HA REST + WebSocket with a long-lived access token (no `hass` object).
|
|
- External access: Cloudflare Tunnel + reverse proxy with a path allowlist; HA itself stays
|
|
unreachable. Domain **`datametric360.app`** registered (all-inkl, 2026-08-11).
|
|
- Distribution: **sideload only** (license reason) — hence real Audi assets are allowed there.
|
|
- Trip detection moves to FMM003 ignition; the pause-tolerance feature
|
|
(`fahrten_pausenzeit_min`) is a deliberate product decision and must be preserved.
|
|
|
|
---
|
|
|
|
## Review findings (2026-08-11)
|
|
|
|
### HA panel — known gaps (most also in SPECIFICATION.md §7)
|
|
|
|
- **GPS is dead schema for trip records specifically:** `start_lat/lon`, addresses, `route`,
|
|
`avg_speed_kmh` on individual trips never populated. The trip-detail map draws a **fabricated**
|
|
line via `fakeTrack()` (`audi-dashboard-app.js:414`) — not a real track. (Unrelated: the
|
|
Übersicht's live Standort-Kachel is no longer in this state — `STANDORT_TRACKER` now points at
|
|
a real `device_tracker`, see section B/C. This item is only about per-trip route data, which
|
|
nothing currently populates.)
|
|
- **No GPS fallback in trip completion:** trips without an odometer match stay `status="offen"`
|
|
forever (`modules/fahrtabschluss_logik.py:16-20`).
|
|
- **RAM-only state:** running trip (`_fahrt_start_ts`) and fuel low-water-mark
|
|
(`_tiefststand_pct`) do not survive an HA restart. Deliberately deferred hardening.
|
|
- **Inactive features:** `UPDATE_REPO_URL = ""` (self-update inactive) in
|
|
`pyscript/modules/einstellungen.py`. `www/bilder/` has no vehicle photos (all slots show
|
|
placeholders); `steuer.faellig` unset. (`BATTERIE_SENSOR` was the same kind of gap until
|
|
2026-08-12 — now wired to the FMM003's `external_power_voltage`, see section B/C below. Several
|
|
*other* fields are newly inactive since the same date for a different reason — the
|
|
`TommiG1/HA_VAG-EU-Data-Act` integration they depended on was dropped: `KM_SENSOR`,
|
|
`TANK_SENSOR`, `RANGE_SENSOR`, `REFRESH_BUTTON`, all door/window/lock sensors, oil-change/
|
|
inspection sensors. All are configurable again via the new Setup menu, see section C.)
|
|
- **Robustness:** `profil_lesen()` in `modules/profil.py` does not handle a missing/corrupt
|
|
`fahrzeugprofil.json` — all callers throw.
|
|
- **Tests:** only the receipt parser is tested (`data/tests/test_shell_beleg_parser.py`, 10 real
|
|
receipts) — and its test PDFs are gitignored, so a fresh clone can't run it. Backend and
|
|
frontend: no tests, no CI.
|
|
- **Leaflet via CDN:** trip map needs public internet in addition to the Tailscale tunnel.
|
|
|
|
### Documentation drift (small fixes; align docs to code)
|
|
|
|
- `homeassistant/README.md:99`, `INSTALL.md:204`, and the header comment
|
|
`audi-dashboard-app.js:13-15` claim the statistics view shows sample numbers — **false**;
|
|
`vStat()` computes real values from `TRIPS`/`FILLS`.
|
|
- `homeassistant/README.md:110` mentions the removed 97% full-tank rule (removal documented in
|
|
`belegverarbeitung.py:18-20`); the README file list omits 5 pyscript files.
|
|
- Obsolete comment `belegverarbeitung.py:41` ("TODO: Datei ablegen" — file has long existed).
|
|
|
|
### Audit leftovers (`AUDIT_2026-08-10.md` §4, deliberately left open)
|
|
|
|
- 🟠 Swipe-to-delete has no gesture-free fallback — screen-reader/switch-control users cannot
|
|
delete trips/fill-ups. Needs a design decision (long-press vs. "…" button vs. action sheet).
|
|
- 🟡 Popup close-by-tap-outside is not keyboard-reachable (needs a quick manual check).
|
|
- 🟡 Self-host Leaflet JS/CSS (tiles necessarily stay remote).
|
|
- Audit's own note: these three may be better done in DataMetric360 than retrofitted — the panel
|
|
gets replaced anyway.
|
|
|
|
### companion-app / design-system
|
|
|
|
- **Not wired together:** `companion-app` does not reference `@audi-dash/ui` anywhere (no
|
|
dependency, no import, no workspace root). The link exists only in prose.
|
|
- Both packages: no `node_modules`, no `dist` — smoke tests need `npm install` first
|
|
(design-system additionally `npm run build`; `scripts/smoke.mjs` imports from `../dist/`).
|
|
- No unit tests, no Storybook (substitute: SSR smoke over 21 cases in design-system).
|
|
- `design/` export (2026-08-11) has two known, already-commissioned fixes not yet in the export:
|
|
shows **RS 6 instead of RS 4**, and **16 sub-pages** the HA panel already has are missing
|
|
(list in `design/README.md`).
|
|
|
|
---
|
|
|
|
## Open items
|
|
|
|
### A) Build DataMetric360 (the big block)
|
|
|
|
- [ ] Fix the Claude Design draft (RS 4, not RS 6) and extend it by the 16 missing sub-pages;
|
|
then re-export to `design/`
|
|
- [ ] `companion-app`: set up Vite + React + Capacitor scaffold; wire `@audi-dash/ui` as a real
|
|
dependency (possibly add a workspace/monorepo root)
|
|
- [ ] Implement the screens from the design draft on top of the existing `DataMetricApi` layer
|
|
- [ ] Add Audi assets (fonts/rings/badges) at implementation time from `homeassistant/www/` —
|
|
**never** into `design-system/`
|
|
- [ ] Secure storage for the LLAT (iOS Keychain / Android Keystore via Capacitor plugin; the
|
|
`ablageSetzen()` hook already exists)
|
|
- [ ] Onboarding: manual token paste (required); QR scan only if it stays simple (QR generated
|
|
locally under HA `/local/`, architecture §3)
|
|
- [ ] Authenticated smoke tests of the data layer (reads, service calls, queue round-trip)
|
|
against `audi_ha_test` with a real token
|
|
- [ ] Offline UX per design brief (offline marker, visible pending queue)
|
|
|
|
### B) Infrastructure / commissioning (partly waits for FMM003 hardware)
|
|
|
|
- [ ] Switch `datametric360.app` nameservers at all-inkl to Cloudflare ("full setup") —
|
|
prerequisite for the tunnel; domain carries nothing else, so this is consequence-free
|
|
- [ ] Decide hostname split (app on apex + API on `api.` subdomain, or vice versa)
|
|
- [ ] Choose reverse proxy (Nginx Proxy Manager vs. Traefik) — **can be done before hardware**
|
|
against the existing HA API
|
|
- [ ] Define the reverse-proxy path allowlist (depends on final entity/service names)
|
|
- [ ] 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)
|
|
- [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
|
|
of the iPhone WLAN sensor; same `task.unique()` pause-tolerance pattern kept unchanged.
|
|
`sensor.iphone_wifi_connection` and the `fahrzeug.wlan_name` profile field are fully removed
|
|
(backend and frontend). At the same time, all entity IDs sourced from the now-abandoned
|
|
`TommiG1/HA_VAG-EU-Data-Act` HACS integration were blanked in `einstellungen.py`
|
|
(`KM_SENSOR`, `TANK_SENSOR`, `RANGE_SENSOR`, `REFRESH_BUTTON`, door/window/lock sensors,
|
|
oil-change/inspection sensors) — the consuming features (Übersicht tiles, Reifenzähler,
|
|
automatic Tankerkennung, Fahrtabschluss-Screening) are untouched and degrade gracefully to
|
|
"unbekannt"/inactive per the existing `zustand_oder_none()` convention, rather than being
|
|
deleted; `fahrtabschluss.py`/`tankerkennung.py`/`reifenzaehler.py` now guard their
|
|
`@state_trigger(f"{einstellungen.KM_SENSOR}")`-style decorators with
|
|
`if einstellungen.KM_SENSOR:` (untested previously whether pyscript tolerates an empty
|
|
trigger string — not worth relying on). `STANDORT_TRACKER` now points at the real
|
|
`device_tracker.testzone_fmm003` and `BATTERIE_SENSOR` at
|
|
`sensor.testzone_fmm003_external_power_voltage` (the vehicle's 12V bus voltage as measured
|
|
by the tracker — NOT `sensor.testzone_fmm003_battery_voltage`, which is the tracker's own
|
|
internal backup cell and unrelated to the car). Real entity list for this device: the user's
|
|
`Entiaeten.csv` export (OneDrive, not in this repo). Verified in `audi_ha_test`: pyscript
|
|
reload (`pyscript.reload`) produced no errors/warnings for any of the changed files; the
|
|
Übersicht correctly shows "Status unbekannt" and em-dash placeholders for the now-blank VAG
|
|
fields instead of crashing (that container itself has no `device_tracker.testzone_fmm003`
|
|
registered, so Standort still shows "Kein GPS-Signal" there — expected, the real HA instance
|
|
has it). `INSTALL.md` step 4 and its troubleshooting table have since been rewritten
|
|
(2026-08-12) to point at the Setup menu instead of manual `einstellungen.py` edits, and to
|
|
use the current FMM003 field names (`ZUENDUNG_SENSOR`/`STANDORT_TRACKER`/`BATTERIE_SENSOR`)
|
|
instead of `WLAN_SENSOR`/TommiG1 — not live-tested against a real install (INSTALL.md itself
|
|
was never run end-to-end in this project, per its own opening note), but consistent with the
|
|
actual code.
|
|
|
|
### C) Maintain the existing HA panel (low priority — being replaced)
|
|
|
|
- [x] Wide-screen/desktop layout (`@container (min-width:860px)` in `audi-dashboard-ios.css`,
|
|
turns the same `.tabbar` into a 264px side-nav via CSS only, no JS/markup duplication) — done
|
|
2026-08-11 from the Claude Design "DataMetric360 Board" draft (`claude.ai/design` project
|
|
`c28a8d4d-ec4e-4178-9e49-ab5b90c02097`). Found and fixed a real regression while verifying it
|
|
live in `audi_ha_test`: the overlay's `:host > div{height:100%}` (meant to drop the old
|
|
412px-cap for the sidebar layout) was applied unconditionally instead of only inside the
|
|
`@container` block, which broke the **normal mobile layout too** — HA doesn't reliably
|
|
propagate a real height down through `panel_custom`, so `height:100%` collapsed `main#view` to
|
|
~0px (tabbar rendered right under the header, content invisible). Fix: kept the outer wrapper
|
|
viewport-anchored (`min(880px, calc(100dvh - 24px))`, matching `audi-dashboard.css`'s original
|
|
reasoning) at all widths, and only drop the 880px cap (`calc(100dvh - 24px)`, still
|
|
viewport-anchored, not parent-relative) inside `@container (min-width:860px)`. Verified live at
|
|
both narrow (mobile tab bar, full content) and wide (1144px container, grid side-nav,
|
|
navigation clicks, settings back-arrow) — screenshots taken, no regressions found.
|
|
- [x] Desktop-Sidebar-Markenklon (`.navmarke`) nachgezogen — done 2026-08-12. The user compared the
|
|
deployed app against the live Claude Design "Board" (the two-viewport comparison page, which
|
|
genuinely iframes this project's own `audi-dashboard-app.js`/`-ios.css`, not a static mockup)
|
|
and asked why the desktop Audi-rings placement differed: Design showed the rings pinned above
|
|
the sidebar nav list, ours showed them in the content header next to the title. Root cause,
|
|
confirmed via `DesignSync get_file` + byte-diff: `audi-dashboard-app.js` was already fully in
|
|
sync (identical), but `audi-dashboard-ios.css` had drifted — the Design project had since
|
|
added a `.navmarke` sidebar clone of the rings (only visible in the `@container
|
|
(min-width:860px)` block; `.rings{display:none!important}` hides the header copy there so the
|
|
mark appears once) plus a filled-pill active-tab style (`.tabpille`), neither pulled back
|
|
locally. Diffed the two full files first to confirm every change was additive/CSS-only, then
|
|
replaced the local file wholesale. Verified in `audi_ha_test` at both 402px and 1400px: rings
|
|
now sit above the nav list on desktop, gear icon alone in the content header, mobile view
|
|
unaffected, no console errors beyond the pre-existing missing-vehicle-photo 404 gap.
|
|
- [x] Standort-Kachel (live vehicle GPS position on the Übersicht, above "Zuletzt") — done
|
|
2026-08-12. New tile with a real (non-fake) Leaflet mini-map, opens a fullscreen "Standort"
|
|
route on tap; fullscreen has 4 floating controls (map style, center-on-vehicle,
|
|
center-on-user, fit-both) and a draggable myAudi-style bottom sheet (peek/expand/close by
|
|
drag or tap, opens on vehicle-marker click) showing distance-to-user, address (client-side
|
|
reverse geocoding via the public Nominatim API — same "public API, no key, low single-
|
|
vehicle volume" reasoning as the existing Leaflet-CDN gap below), fährt/steht/"Letzter
|
|
Parkplatz" state, fuel/range, and Route (Google Maps deep link) / Teilen (Web Share API)
|
|
actions. Backend: new `STANDORT_TRACKER` entity-ID setting in `einstellungen.py` (device_
|
|
tracker with lat/lon attributes), published via a new `_standort()` helper in
|
|
`frontend_veroeffentlichung.py`. The built-in default points at the author's test device
|
|
(`device_tracker.testzone_fmm003`); until the FMM003 actually delivers positions (section B),
|
|
that entity does not exist and the tile shows "Kein GPS-Signal vom Fahrzeug". Verified end-to-end in `audi_ha_test` with a manually
|
|
created `device_tracker.test_fahrzeug` test entity (tile, fullscreen map, and menu all
|
|
confirmed rendering/populating correctly); the device's own location (browser Geolocation
|
|
API) and the Route/Teilen deep links work independently of the vehicle-GPS gap. Pushed to
|
|
the Claude Design project (`c28a8d4d-ec4e-4178-9e49-ab5b90c02097`, "DataMetric360 Board")
|
|
for visual refinement — the JS/CSS ship functionally complete but visually plain
|
|
(placeholder vehicle-marker glyph, default `.aktion`/`.tile` styling); Claude Design's job is
|
|
polish, not structure. One known rough edge: reverse-geocoded address didn't resolve within
|
|
a few seconds in the `audi_ha_test` container (no crash, stays on "Adresse wird ermittelt …"
|
|
indefinitely) — likely just that container's outbound network to Nominatim specifically;
|
|
unconfirmed whether this reproduces on the real HA instance.
|
|
- [x] Setup menu (Einstellungen → Fahrzeug einrichten → last item when expanded) — done
|
|
2026-08-12. Lets the user map every sensor role the app uses (~18 roles, 3 of them 4-item
|
|
door/window/lock lists) to real HA entities from a searchable dropdown, instead of hand-
|
|
editing `einstellungen.py`. New backend module `pyscript/modules/entitaeten.py`: a
|
|
`FELDER` catalog (label, hint, expected domain/device_class/unit, keywords, whether it's
|
|
one of the trigger-bound fields) plus JSON override I/O (`data/entitaeten.json`, same
|
|
atomic-write pattern as `profil.py`) and `overrides_anwenden()`, which does
|
|
`setattr(einstellungen, key, value)` on the already-imported `einstellungen` module — every
|
|
existing consumer does `import einstellungen` + live attribute access (verified: none use
|
|
`from einstellungen import X`), so this needs no changes to any consumer file. New service
|
|
`audi_dashboard_entitaeten_schreiben` (`frontend_api.py`) and publication
|
|
`entitaeten_veroeffentlichen()` (`frontend_veroeffentlichung.py`) follow the project's
|
|
existing read-via-state/write-via-service pattern. Frontend: new popup (`vSetupPopup()`,
|
|
modeled on the existing `.sheet` pattern) with a from-scratch searchable-combobox component
|
|
(none existed in the repo before) — client-side only, built directly from `HASS.states`, no
|
|
new backend read service; a global "Nur passende Sensoren anzeigen" switch hard-filters
|
|
candidates by domain/unit, a keyword+domain+unit score ranks and auto-suggests for empty
|
|
fields. Deliberately does NOT auto-apply changes for the three trigger-bound fields
|
|
(`ZUENDUNG_SENSOR`/`KM_SENSOR`/`TANK_SENSOR` — `@state_trigger` bakes the entity ID in at
|
|
module-load time) — the UI shows an inline "wirkt erst nach Neustart" hint instead of
|
|
attempting a risky self-`pyscript.reload()` from inside a running service call. Two real
|
|
bugs found and fixed during live verification, both now also pushed to the Claude Design
|
|
project: (1) a full popup re-render on every keystroke fought the search input for focus —
|
|
fixed by patching just the candidate-list DOM node on `input`, matching the same fix the
|
|
existing `data-tankpreisfeld` handler already uses for the identical reason; (2) the popup
|
|
background used `--tile-2`, which Design had since changed to a translucent
|
|
`rgba(255,255,255,.1)` in the night theme (for the frosted-glass tile look elsewhere) — made
|
|
the whole popup partially see-through against the app content behind it. Fixed by switching
|
|
to `--tile-deckend` (Design's own opaque-surface token, already used by `.standortmenu` for
|
|
the same reason), with `var(--canvas)` as a defensive fallback.
|
|
- [x] Fresh-install packaging + `update.ps1` fix — done 2026-08-12. While preparing a short
|
|
quick-install checklist, found that `update.ps1` never copied `audi-dashboard-ios.css` or
|
|
`www/badges/*` — both are loaded by the running app (the ios overlay is injected by the app
|
|
itself via JS, badges by the model picker since item #51), so every `update.ps1` run since
|
|
those were added silently left the deployed copy stale on those two. Fixed (script now copies
|
|
both). Also removed two stray `*.bak-before-audit-merge` files from `www/` (already gitignored
|
|
at repo root, never committed, just local clutter from an earlier merge). New
|
|
`installationspaket/` — a generated, gitignored bundle (pyscript/, www/ minus the two backup
|
|
files, data/ with only the example profile + receipt parser, `configuration_snippet.yaml`,
|
|
`update.ps1`) plus a short `ANLEITUNG.md` checklist for copying to a fresh HA instance;
|
|
`INSTALL.md` stays the authoritative, detailed reference. Regenerate on demand, don't keep it
|
|
permanently in sync — it's a deployment snapshot, not a second source of truth.
|
|
- [x] Setup-menu polish: 5 additions on top of the existing Setup popup — done 2026-08-12.
|
|
Backend (`pyscript/modules/entitaeten.py`): a `_STANDARDWERTE` snapshot taken at module-load
|
|
time (before `overrides_anwenden()` ever runs), exposed via `aktueller_stand()` as
|
|
`standardwerte` — needed because `setattr()` on the live `einstellungen` module is permanent
|
|
for the process, so "reset to default" has to write the original value back explicitly rather
|
|
than just omitting the override. New service `audi_dashboard_neustart` (`frontend_api.py`)
|
|
wrapping `homeassistant.restart()`, called only from an explicit user-confirmed button, never
|
|
automatically. Frontend (`audi-dashboard-app.js`): (1) live current-value preview next to each
|
|
candidate in the search dropdown (`entitaetZeilenMarkup`, reads `HASS.states[e.id].state`);
|
|
(2) inline warning under a field if its currently assigned entity is `unavailable`/`unknown`/
|
|
missing (`entitaetStatusWarnung`); (3) duplicate-assignment check on save
|
|
(`setupDuplikate`) — blocks with a confirm-sheet ("trotzdem speichern?") rather than silently
|
|
allowing the same entity in two roles; (4) per-field reset button (only shown when the current
|
|
value differs from `standardwerte`), reverts to the built-in default; (5) after saving, if any
|
|
of the 3 trigger-bound fields actually changed (`setupGeaenderteTriggerFelder`, compares
|
|
against a snapshot taken when the popup opened), a confirm-sheet offers "Jetzt neu starten"
|
|
calling the new service. Verified live in `audi_ha_test`: value preview and unavailable-warning
|
|
confirmed correct (`ZUENDUNG_SENSOR`'s configured entity genuinely doesn't exist in this test
|
|
container → "Entität nicht gefunden." shown as designed); duplicate-check correctly caught both
|
|
a deliberately-forced KM/TANK collision and pre-existing door/window/lock auto-suggestion
|
|
collisions (a real side effect of this container's limited matching entities, not a bug);
|
|
reset button appeared/disappeared correctly as values diverged from/matched the default;
|
|
save round-tripped through the real service into `data/entitaeten.json` (byte-inspected) and
|
|
into the published `pyscript.audi_dashboard_fahrzeugstatus` state; restart-needed sheet named
|
|
exactly the changed trigger-bound field(s) and no others. Did not actually trigger a restart
|
|
during verification (would have restarted the shared test container) — the service call itself
|
|
was left unexercised beyond confirming it registers without error at pyscript load time.
|
|
- [ ] Fix remaining documentation drift (statistics claim, README gaps, obsolete TODO comment) —
|
|
text-only changes; INSTALL.md's WLAN/TommiG1 drift and stale variable names were fixed
|
|
2026-08-12 (see section B)
|
|
- [ ] Harden `profil_lesen()` against missing/corrupt `fahrzeugprofil.json`
|
|
- [ ] Decide whether the 3 audit leftovers get fixed here or 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)
|
|
|
|
### D) Once the panel is superseded
|
|
|
|
- [ ] **Archive** `audi-dashboard-app.js`, don't delete (settled decision, architecture §1)
|
|
|
|
---
|
|
|
|
## Working conventions (observed — keep them)
|
|
|
|
- German is the project language: identifiers, comments, commits, UI texts. Exceptions:
|
|
`design-system/` uses English props/JSDoc (Claude Design audience) — and **this file**, which is
|
|
English by rule.
|
|
- Decisions are logged, including rejected ones (see the Traccar section of the architecture
|
|
doc); superseded sections stay in place marked "ÜBERHOLT" rather than being deleted.
|
|
- Numbers in `de-DE` format; font weights 300/400 only, never ≥600 (only those cuts exist).
|
|
- Real vehicle/movement data stays local (`data/` contents and receipt PDFs are gitignored).
|
|
- Security principle: HA is never publicly exposed; only narrowly scoped surfaces (MQTT broker,
|
|
proxy allowlist) may be exposed, each by explicit decision.
|