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:
@@ -14,7 +14,7 @@ import { readFileSync } from "node:fs"
|
||||
import { fileURLToPath } from "node:url"
|
||||
import { dirname, resolve } from "node:path"
|
||||
|
||||
import { ENTITAETEN } from "../src/api/types.ts"
|
||||
import { DIENST_DOMAIN, ENTITAETEN } from "../src/api/types.ts"
|
||||
import { HassRest } from "../src/api/rest.ts"
|
||||
import { Warteschlange } from "../src/api/warteschlange.ts"
|
||||
import { ablageSetzen, websocketUrl, type Ablage } from "../src/api/umgebung.ts"
|
||||
@@ -104,10 +104,19 @@ try {
|
||||
"tankprozent" in status && "gesichert" in status && "sicherheitscheck" in status,
|
||||
Object.keys(status).slice(0, 6).join(", "),
|
||||
)
|
||||
/* Wie viele Punkte es sind, hängt an der Sensor-Zuordnung der Instanz: vier
|
||||
Türen, vier Fenster, Heckklappe, Motorhaube — unbelegte Rollen liefern gar
|
||||
keinen Eintrag. Eine feste Zahl zu erwarten hieße, die Zuordnung der
|
||||
Testinstanz zu prüfen statt das Backend; genau daran scheiterte diese
|
||||
Prüfung seit dem Entfernen der Türschloss-Erkennung (16 → 10), ohne dass
|
||||
irgendetwas kaputt gewesen wäre. Geprüft wird deshalb die vereinbarte
|
||||
Form: label ist Text, ok ist true/false/null (null = Sensor unbekannt). */
|
||||
const punkte = (status["sicherheitscheck"] ?? []) as { label?: unknown; ok?: unknown }[]
|
||||
pruefe(
|
||||
"Sicherheitscheck liefert alle 16 Einzelprüfungen",
|
||||
Array.isArray(status["sicherheitscheck"]) && (status["sicherheitscheck"] as unknown[]).length === 16,
|
||||
`${(status["sicherheitscheck"] as unknown[] | undefined)?.length ?? 0} Punkte`,
|
||||
"Sicherheitscheck liefert Punkte in der vereinbarten Form",
|
||||
Array.isArray(punkte) &&
|
||||
punkte.every((p) => typeof p.label === "string" && (p.ok === null || typeof p.ok === "boolean")),
|
||||
`${punkte.length} Punkte`,
|
||||
)
|
||||
} catch (e) {
|
||||
pruefe("Fahrzeugstatus lesen", false, e instanceof Error ? e.message : String(e))
|
||||
@@ -128,17 +137,17 @@ for (const [name, id] of [
|
||||
/* -------------------------------------------------------- Dienstaufruf */
|
||||
|
||||
try {
|
||||
await rest.dienstAufrufen("pyscript", "audi_dashboard_jetzt_aktualisieren")
|
||||
pruefe("Dienstaufruf audi_dashboard_jetzt_aktualisieren", true)
|
||||
await rest.dienstAufrufen(DIENST_DOMAIN, "jetzt_aktualisieren")
|
||||
pruefe("Dienstaufruf audi_dashboard.jetzt_aktualisieren", true)
|
||||
} catch (e) {
|
||||
pruefe("Dienstaufruf audi_dashboard_jetzt_aktualisieren", false, e instanceof Error ? e.message : String(e))
|
||||
pruefe("Dienstaufruf audi_dashboard.jetzt_aktualisieren", false, e instanceof Error ? e.message : String(e))
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------ Warteschlange */
|
||||
|
||||
try {
|
||||
const warteschlange = new Warteschlange(rest)
|
||||
await warteschlange.einreihen("pyscript", "audi_dashboard_jetzt_aktualisieren", {}, "Rauchtest")
|
||||
await warteschlange.einreihen(DIENST_DOMAIN, "jetzt_aktualisieren", {}, "Rauchtest")
|
||||
|
||||
/* einreihen() stößt die Abarbeitung selbst an, ohne sie abzuwarten - ein
|
||||
sofortiger eigener abarbeiten()-Aufruf liefe deshalb ins Leere (der Lauf
|
||||
|
||||
Reference in New Issue
Block a user