Initialer Import: HA-Panel, Design-System, Companion-App
Drei zusammengehörige Teile in einem Repository: - homeassistant/ Das fertige, im Einsatz befindliche Home-Assistant-Panel (panel_custom Custom Element + pyscript-Backend). Echte Fahrzeug- und Personendaten (fahrzeugprofil.json, fahrten.jsonl, tankvorgaenge.jsonl, Tankbelege) bleiben per .gitignore außen vor; die anonymisierte Vorlage fahrzeugprofil.example.json ist mit dabei. - design-system/ Eigenständige React-Komponentenbibliothek (@audi-dash/ui), die die visuelle Sprache des Panels nachbildet - ohne Audi-Markenzeichen und ohne die lizenzierte Hausschrift. Dient als Grundlage für Claude Design. War bis hierher ein eigenes Repository und ist in dieses eingeschmolzen worden. - companion-app/ Datenschicht der neuen App DataMetric360 (iOS/Android via Capacitor, zusätzlich als Iframe im HA-Dashboard). Noch ohne Oberfläche: REST- und WebSocket-Zugriff auf Home Assistant plus Warteschlange für Änderungen ohne Netz. Ersetzt das eingespritzte hass-Objekt, das nur innerhalb des HA-Frontends existiert. Dazu die Projektdokumentation: SPECIFICATION.md (Ist-Stand des Panels), COMPANION_APP_ARCHITECTURE.md (Architekturentscheidungen der neuen App), AUDIT_2026-08-10.md, DESIGN_BRIEF_DATAMETRIC360.md und der ursprüngliche Bauauftrag. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
/* ================================================================
|
||||
Datenschicht DataMetric360 - Sammelexport
|
||||
================================================================
|
||||
Ein Zugang für die gesamte Oberfläche: REST für Lesen und Schreiben,
|
||||
WebSocket für Push, Warteschlange fürs Funkloch. Welche Bildschirme es
|
||||
gibt, ist hier bewusst unbekannt - diese Schicht überlebt jeden
|
||||
Entwurfsdurchlauf unverändert. */
|
||||
|
||||
export * from "./types.ts";
|
||||
export * from "./umgebung.ts";
|
||||
export * from "./rest.ts";
|
||||
export * from "./live.ts";
|
||||
export * from "./warteschlange.ts";
|
||||
|
||||
import { ENTITAETEN } from "./types.ts";
|
||||
import type { Fahrt, Fahrzeugstatus, Profil, Tankvorgang } from "./types.ts";
|
||||
import { HassRest } from "./rest.ts";
|
||||
import { HassLive } from "./live.ts";
|
||||
import { Warteschlange } from "./warteschlange.ts";
|
||||
|
||||
/** Bündelt die drei Bausteine und bildet die Fachvorgänge ab, die das alte
|
||||
Dashboard über hass.callService erledigt hat. */
|
||||
export class DataMetricApi {
|
||||
readonly rest: HassRest;
|
||||
readonly live: HassLive;
|
||||
readonly warteschlange: Warteschlange;
|
||||
|
||||
constructor() {
|
||||
this.rest = new HassRest();
|
||||
this.live = new HassLive();
|
||||
this.warteschlange = new Warteschlange(this.rest);
|
||||
|
||||
/* Sobald die Verbindung wieder steht, wartende Änderungen nachliefern -
|
||||
ohne dass die Oberfläche etwas anstoßen muss. */
|
||||
this.live.aufVerbindung((zustand) => {
|
||||
if (zustand === "verbunden") void this.warteschlange.abarbeiten();
|
||||
});
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ Lesen */
|
||||
|
||||
profilLesen(): Promise<Profil> {
|
||||
return this.rest.datenLesen<Profil>(ENTITAETEN.profil);
|
||||
}
|
||||
|
||||
fahrtenLesen(): Promise<Fahrt[]> {
|
||||
return this.rest.datenLesen<Fahrt[]>(ENTITAETEN.fahrten);
|
||||
}
|
||||
|
||||
tankvorgaengeLesen(): Promise<Tankvorgang[]> {
|
||||
return this.rest.datenLesen<Tankvorgang[]>(ENTITAETEN.tankvorgaenge);
|
||||
}
|
||||
|
||||
fahrzeugstatusLesen(): Promise<Fahrzeugstatus> {
|
||||
return this.rest.datenLesen<Fahrzeugstatus>(ENTITAETEN.fahrzeugstatus);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------- Schreiben
|
||||
Alle schreibenden Vorgänge laufen über die Warteschlange, nicht direkt
|
||||
über rest.dienstAufrufen(). Damit verhält sich die App im Funkloch
|
||||
genauso wie mit Netz - nur eben zeitversetzt. */
|
||||
|
||||
profilSchreiben(profil: Profil): Promise<unknown> {
|
||||
return this.warteschlange.einreihen(
|
||||
"pyscript",
|
||||
"audi_dashboard_profil_schreiben",
|
||||
{ profil_json: JSON.stringify(profil) },
|
||||
"Fahrzeugdaten speichern",
|
||||
);
|
||||
}
|
||||
|
||||
belegHochladen(pdfBase64: string, dateiname: string, tankId?: string): Promise<unknown> {
|
||||
return this.warteschlange.einreihen(
|
||||
"pyscript",
|
||||
"audi_dashboard_beleg_hochladen",
|
||||
{ pdf_base64: pdfBase64, dateiname, ...(tankId ? { tank_id: tankId } : {}) },
|
||||
`Beleg „${dateiname}" hochladen`,
|
||||
);
|
||||
}
|
||||
|
||||
fahrtLoeschen(tripId: string): Promise<unknown> {
|
||||
return this.warteschlange.einreihen(
|
||||
"pyscript",
|
||||
"audi_dashboard_fahrt_loeschen",
|
||||
{ trip_id: tripId },
|
||||
"Fahrt löschen",
|
||||
);
|
||||
}
|
||||
|
||||
tankvorgangLoeschen(tankId: string): Promise<unknown> {
|
||||
return this.warteschlange.einreihen(
|
||||
"pyscript",
|
||||
"audi_dashboard_tankvorgang_loeschen",
|
||||
{ tank_id: tankId },
|
||||
"Tankvorgang löschen",
|
||||
);
|
||||
}
|
||||
|
||||
/** Stößt eine sofortige Aktualisierung im Backend an (Pull-to-refresh). */
|
||||
jetztAktualisieren(): Promise<unknown> {
|
||||
return this.rest.dienstAufrufen("pyscript", "audi_dashboard_jetzt_aktualisieren");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user