Fahrzeugdaten, Batterieverlauf, Service mit Werkstatt und Servicebuch, Reifen, die ganze Versicherungs- und Steuergruppe, Einstellungen in voller Tiefe und die Live-Ansicht. Portiert dazu: die eigene Oelwechsel-Prognose (rechnet ab dem letzten Wechsel im Servicebuch neu, weil der Langzeitschnitt dafuer zu traege ist), Kalenderdateien fuer Termine und die CSV-Ausgabe im deutschen Format. Die Live-Ansicht ist gebaut, aber ueber einen Schalter abgeschaltet: die Werte dafuer liefert erst der FMM003. Ein Menuepunkt mit lauter Nullen waere schlechter als keiner. Zwei Stellen, an denen die App bewusst zurueckhaltend ist: ein unbekannter Pruefpunkt erscheint als hohler Ring statt als geratenes Gruen, und der Reifen-Kilometerstand wird nie zurueckgeschrieben, weil ihn der Server fortschreibt. 49 Tests, darunter ein Rendertest ueber alle 21 Seiten in beiden Layouts mit Beispieldaten in der Form, die das Backend wirklich liefert.
DataMetric360 — companion app
Private vehicle app for one car. Ships three ways from one codebase: native iOS and Android via
Capacitor, and embedded as a plain iframe in the Home Assistant dashboard. Architecture and the
decisions behind it: ../COMPANION_APP_ARCHITECTURE.md.
Status
Data layer only. No UI yet — the screens come from the Claude Design draft
(../DESIGN_BRIEF_DATAMETRIC360.md), and get implemented on top
of design-system/'s React components once that draft settles. This package was written first on
purpose: how the app talks to Home Assistant doesn't depend on what the screens look like, so it
survives every design iteration untouched.
Not yet added (deliberately, they'd be guesses today): React/Vite, Capacitor, the native secure-storage
adapter, and the Audi brand assets (fonts/rings/badges — those come from homeassistant/www/ at
implementation time, never into design-system/, see the licence note in the architecture doc).
Layout
src/api/
├── types.ts HA state shapes + domain types (Fahrt, Tankvorgang, …) + the entity-ID table
├── umgebung.ts runtime detection (capacitor/iframe/browser), credential storage, URL helpers
├── rest.ts REST client — replaces hass.states / hass.callService
├── live.ts WebSocket client — push updates, auto-reconnect with backoff
├── warteschlange.ts offline queue for writes made without a connection
└── index.ts DataMetricApi — ties the three together, exposes the domain operations
scripts/smoke.ts verification against a running HA instance
Comments are in German, matching the rest of the project.
What replaces what
The old panel got a hass object injected by panel_custom. That object only exists inside the HA
frontend, which is exactly why the old panel can't run as a standalone app. The mapping:
| Old panel | Here |
|---|---|
hass.states[id].attributes.daten |
rest.datenLesen(id) / DataMetricApi.profilLesen() etc. |
hass.callService(...) |
warteschlange.einreihen(...) via the DataMetricApi methods |
| automatic re-render on state push | live.aufZustand(...) |
Same entities, same pyscript services, same backend files written — only the transport changes.
Every write goes through the queue rather than straight to REST. That's what makes offline edits behave the same as online ones, just delayed: a receipt photographed in a dead zone is persisted and sent when the connection returns, surviving an app restart in between.
Commands
Node is installed at C:\Program Files\nodejs but is not on PATH — prefix it:
$env:Path = "C:\Program Files\nodejs;" + $env:Path
npm run typecheck
npm run smoke
smoke targets http://localhost:18123 (the audi_ha_test Docker container) by default; pass a
different base URL as the first argument.
Verification status (2026-08-10)
tsc --noEmit clean under strict plus noUncheckedIndexedAccess and exactOptionalPropertyTypes.
All 7 smoke checks pass against the running test container, covering URL normalisation, the
http→ws/https→wss mapping, that GET /api/ exists and rejects an unauthenticated request with 401,
and that the WebSocket opens with auth_required — which is the message live.ts's whole auth flow
is built around.
Not yet verified — needs a token: authenticated reads, service calls, and the queue's real
round-trip. Those need a Long-Lived Access Token, which is a deliberate manual step (see the LLAT
provisioning decision in the architecture doc). To do it: create a token in the HA profile page, then
extend scripts/smoke.ts with authenticated cases.