pyscript-Backend zur echten HA-Integration umgebaut (HACS-fähig)

Das Backend liegt jetzt als custom_components/audi_dashboard/ vor - eine
normale Home-Assistant-Integration mit Config-Flow, einer sensor-Plattform
und 18 Diensten. Damit ist die App über HACS installierbar; bis das Repo auf
GitHub gespiegelt ist (HACS spricht ausschließlich mit GitHub), installiert
homeassistant/installationspaket/install.ps1 denselben Ordner ohne HACS.

Fünf Installationsschritte entfallen ersatzlos: der pyscript:-Block, der
panel_custom:-Block, das Kopieren der Oberfläche nach www/, das langlebige
Zugriffstoken (der Verlauf wird direkt über die recorder-API gelesen) und
"pip install pypdf" (steht in manifest.json). Das Fahrzeugprofil legt die
Integration beim ersten Start aus ihrer Vorlage an.

Drei alte Schwächen sind dabei mit erledigt:
- Die Nutzlast landet nicht mehr in der Recorder-Datenbank
  (_unrecorded_attributes - das kann nur eine echte Entität).
- Eine laufende Fahrt überlebt einen Neustart (Store statt Arbeitsspeicher);
  fiel sie während eines Ausfalls ins Ende, schließt
  nach_neustart_fortsetzen() sie beim letzten aufgezeichneten Zeitpunkt.
- Sensor-Zuordnungen wirken sofort - die Zustandsbeobachter werden neu
  gebunden, der Neustart-Hinweis und der Neustart-Dienst sind weg.

Namensvertrag geändert, beide Oberflächen mitgezogen:
pyscript.audi_dashboard_x -> sensor.audi_dashboard_x,
pyscript.audi_dashboard_y -> audi_dashboard.y. Eine Companion-App vom alten
Stand findet nach dem Umstieg nichts mehr und muss neu gebaut werden; das
Panel liegt in der Integration und kann nicht driften.

Der selbstgebaute Updater entfällt - HACS ist die Update-Mechanik, die Home
Assistant kennt. Die Versionierung schrumpft auf eine Quelle: manifest.json.

Geprüft am laufenden Testcontainer (Container byteweise identisch mit dem
Repo): alle 18 Dienste, Panel, Config-Entry neu laden, Historienimport,
echter Shell-Beleg in-process, Neuinstallation im Wegwerf-Container blank mit
automatisch nachinstalliertem pypdf. Companion-App: tsc sauber, 112/112
Tests, beide Rauchtests gegen das laufende Backend grün. Belegparser 8/8.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-23 23:53:56 +02:00
parent 99cef7c393
commit d8b12da36d
136 changed files with 5289 additions and 17641 deletions
+22 -9
View File
@@ -4,16 +4,29 @@ import { fileURLToPath } from "node:url"
import { defineConfig } from "vite"
import react from "@vitejs/plugin-react"
// Die App-Version kommt aus der Datei VERSION im Projektstamm — derselben, aus
// der auch das Panel seine bekommt (siehe VERSIONIERUNG.md). Sie wird hier fest
// einkompiliert, damit die fertige App weiß, aus welchem Stand sie gebaut
// wurde, und das gegen den vom Backend gemeldeten Stand halten kann.
// Die App-Version kommt aus der manifest.json der Integration — derselben
// Zahl, die HACS anzeigt, die Home Assistant als Version der Integration führt
// und die das Backend über sensor.audi_dashboard_app_version meldet (siehe
// VERSIONIERUNG.md). Sie wird hier fest einkompiliert, damit die fertige App
// weiß, aus welchem Stand sie gebaut wurde, und das gegen den vom Backend
// gemeldeten Stand halten kann.
//
// Absichtlich hart: fehlt die Datei, soll der Build abbrechen statt still eine
// App ohne Versionsangabe zu erzeugen — die könnte ihre eigene Veraltung nicht
// mehr erkennen, und genau das ist der Zweck der ganzen Mechanik.
const versionsDatei = fileURLToPath(new URL("../VERSION", import.meta.url))
const appVersion = readFileSync(versionsDatei, "utf8").trim()
// Bis 2026-08-23 stand die Zahl in einer eigenen Datei VERSION im
// Projektstamm. Die ist mit dem Umbau zur HACS-Integration überflüssig
// geworden: die manifest.json MUSS eine Version tragen, HACS verlangt sie und
// vergleicht danach. Zwei Quellen für dieselbe Angabe wären eine Quelle zu
// viel — sie hätten irgendwann auseinandergelegen, und der Vergleich, den
// diese Zahl trägt, wäre still falsch geworden.
//
// Absichtlich hart: fehlt die Datei oder das Feld, soll der Build abbrechen
// statt still eine App ohne Versionsangabe zu erzeugen — die könnte ihre
// eigene Veraltung nicht mehr erkennen, und genau das ist der Zweck der
// ganzen Mechanik.
const manifestPfad = fileURLToPath(
new URL("../custom_components/audi_dashboard/manifest.json", import.meta.url),
)
const appVersion: string = JSON.parse(readFileSync(manifestPfad, "utf8")).version
if (!appVersion) throw new Error(`Kein "version"-Feld in ${manifestPfad}`)
// Basispfad relativ: die App wird sowohl unter einer eigenen Domain als auch
// aus einem Unterordner heraus ausgeliefert (Home Assistant: /local/dm360/),