Files
audi-app/companion-app
Paul Nothaft 571d12310f Phase 8: Audi-Schrift, Vier-Ringe und Typenschilder
Die drei Schriftschnitte stammen aus dem Panel, wo sie als base64 im
Stylesheet lagen - als eigene woff2-Dateien sind sie zwischenspeicherbar
statt bei jedem Laden erneut uebertragen zu werden. Typenschilder und Ringe
wechseln mit dem Erscheinungsbild.

Lizenzgrenze eingehalten und geprueft: design-system bleibt unveraendert und
enthaelt keine Markendateien, weil es nach aussen hochgeladen wird. Die App
darf sie nutzen, weil sie nur seitlich installiert wird.

Dabei noch eine Typungenauigkeit korrigiert: technik und ausstattung im
Profil sind Listen von Gruppen, waren aber wie die uebrigen Abschnitte als
Objekt deklariert.
2026-08-11 11:19:38 +02:00
..

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.