Review des aktuellen Stands und Plan fuer die native HA-Integration
Zwei Dokumente, beide reine Analyse - kein Code geaendert.
REVIEW_main_2026-08-13.md: 15 Befunde aus den Commits c66ed82..d5562c7,
nach Schaden sortiert, jeder mit Datei-Zeile und der Kette vom Ausloeser zur
Auswirkung. Die drei schwersten liegen im neuen Setup-Menue:
1. Speichern, solange der Katalog noch nicht geladen ist, ueberschreibt
entitaeten.json mit {} und loescht alle Zuordnungen. Faellt erst beim
naechsten Neustart auf, weil die setattr-Werte im Prozess bestehen
bleiben - und entitaeten.json wird von backup.py nicht gesichert.
2. "Zuruecksetzen" wirkt bei 15 von 17 Feldern nicht, weil
overrides_anwenden() leere Werte ueberspringt und der Standardwert bei
fast allen Feldern leer ist. Isoliert nachgestellt.
3. Alle vier Listenpositionen bekommen denselben Sensor, weil der
Vorschlag den Index nicht auswertet. Folge: der Sicherheitscheck prueft
viermal dieselbe Tuer und meldet "Sicher abgestellt", obwohl drei Tueren
nie geprueft wurden.
Jeder Befund ist als belegt oder plausibel gekennzeichnet.
ha_install.md: Plan fuer die Umstellung von pyscript auf eine eigene
Integration mit Konfigurationsdialog - Einrichtung komplett ueber die
Oberflaeche, kein YAML, Updates als Knopfdruck. Alle genannten
Schnittstellen sind an der laufenden 2026.8.1-Instanz geprueft, inklusive
Signaturen.
Zur Verteilung: HACS kann ausschliesslich GitHub und scheidet fuer das
Gitea-Repository aus. App-Repositories akzeptieren zwar beliebige Git-URLs,
Apps sind aber Docker-Container und damit der falsche Behaelter fuer eine
Integration. Nativ bleibt eine eigene UpdateEntity, deren Logik in
updateverwaltung.py bereits zu grossen Teilen existiert.
Festgehalten ist ausserdem, welche der Review-Befunde die Umstellung
konstruktionsbedingt aufloest - unter anderem alle drei oben genannten sowie
die Token-Datei im Klartext, weil eine Integration den Recorder direkt
abfragen kann statt sich selbst ueber HTTP.
This commit is contained in:
@@ -0,0 +1,391 @@
|
||||
# Review: Branch `main`, Commits `c66ed82..d5562c7`
|
||||
|
||||
**Datum:** 2026-08-13 · **Umfang:** 18 Commits, 24 Dateien, +2752/−259 Zeilen
|
||||
**Gegenstand:** Setup-Menü zur Sensor-Zuordnung, Umstellung von WLAN/VAG auf FMM003,
|
||||
Standort-Kachel mit Live-Position, iOS-/Großbildschirm-Optikauflage, DuckDNS und Zertifikate.
|
||||
|
||||
Geprüft wurde gegen eine Arbeitskopie von `origin/main`. Die mit **[belegt]** markierten Befunde
|
||||
sind am Code nachvollzogen oder nachgestellt; **[plausibel]** heißt: aus dem Code abgeleitet, aber
|
||||
nicht im Browser reproduziert.
|
||||
|
||||
---
|
||||
|
||||
## Gesamteindruck
|
||||
|
||||
Handwerklich stark. Das Setup-Menü ersetzt „vor der Installation `einstellungen.py` editieren"
|
||||
durch eine Oberfläche mit Live-Wertvorschau, Unavailable-Warnung, Duplikat-Prüfung und einem
|
||||
ehrlichen Neustart-Hinweis für die drei triggergebundenen Felder. Der Kniff dahinter — `setattr`
|
||||
auf dem laufenden Modul-Objekt, weil alle Leser `einstellungen.KM_SENSOR` als lebenden
|
||||
Attributzugriff machen — ist elegant und im Kopfkommentar sauber begründet.
|
||||
|
||||
Positiv außerdem: Escaping ist im neuen Code durchgängig (kein XSS gefunden), Karten-Ebenen werden
|
||||
vor dem Neuaufbau entfernt, die Haversine-Distanz ist mathematisch korrekt, Listenfelder sind gegen
|
||||
zu kurze Arrays abgesichert, und die Python-Syntax aller acht geänderten pyscript-Dateien ist in
|
||||
Ordnung.
|
||||
|
||||
Die Fehler unten liegen fast alle im selben Bereich — dem neuen Setup-Menü — und **drei davon
|
||||
werden erst nach einem Neustart sichtbar**, also mit maximalem zeitlichem Abstand zur Ursache.
|
||||
|
||||
## Übersicht
|
||||
|
||||
| # | Befund | Wirkung | Ort |
|
||||
|---|---|---|---|
|
||||
| 1 | Speichern bei fehlendem Katalog löscht alle Zuordnungen | Datenverlust | `audi-dashboard-app.js:1773, 2031` |
|
||||
| 2 | „Zurücksetzen" wirkt bei 15 von 17 Feldern nicht | falscher Zustand | `entitaeten.py:188` |
|
||||
| 3 | Alle vier Listenpositionen bekommen denselben Sensor | falsche Sicherheitsaussage | `audi-dashboard-app.js:1976` |
|
||||
| 4 | Vorschlagsschwelle akzeptiert beliebige Sensoren | falscher Fahrt-Trigger | `audi-dashboard-app.js:1980` |
|
||||
| 5 | Geleerte Listen setzen `["","","",""]` | Status dauerhaft „unbekannt" | `entitaeten.py:188` |
|
||||
| 6 | Zuordnung wird nirgends gesichert | Verlust bei Wiederherstellung | `backup.py:32` |
|
||||
| 7 | Kaputte `entitaeten.json` legt das Panel lahm | Totalausfall | `entitaeten.py:159` |
|
||||
| 8 | Standortabfrage im Dauerfeuer bei abgelehnter Freigabe | Akku, Netz | `audi-dashboard-app.js:553/557` |
|
||||
| 9 | Kein Tastaturweg in die Einstellungen unter 860 px | Bedienbarkeit | `audi-dashboard-app.js:3849` |
|
||||
| 10 | `.navmarke` nur in der iOS-Auflage versteckt | Tab-Leiste zerfällt | `audi-dashboard-ios.css:194` |
|
||||
|
||||
---
|
||||
|
||||
# Schwerwiegend
|
||||
|
||||
## 1. Speichern bei fehlendem Katalog löscht die gesamte Zuordnung [belegt]
|
||||
|
||||
**Kette:**
|
||||
|
||||
1. `ENTITAETEN` wird an genau einer Stelle gefüllt (`audi-dashboard-app.js:3723`), aus `hass.states`.
|
||||
2. Der Nachlade-Pfad nach einem HA-Neustart (`:3699-3703`) holt Profil, Fahrten, Tankvorgänge,
|
||||
Status und Batterieverlauf nach — **nicht** aber `pyscript.audi_dashboard_entitaeten`.
|
||||
3. `DATEN_GELADEN` hängt allein am Profil. Die App gilt also als geladen, während der Katalog fehlt.
|
||||
4. Der Knopf „Setup — Sensoren zuordnen" (`:1773`) ist nur an `einrichtenOffen` gekoppelt, nicht an
|
||||
den Katalog. `setupKatalog()` liefert `[]`, das Popup öffnet **ohne eine Zeile und ohne
|
||||
Fehlermeldung**, `setupZuordnung` bleibt `{}`.
|
||||
5. „Speichern" schickt `"{}"` (`:2031`). `overrides_schreiben()` ersetzt die Datei vollständig,
|
||||
ohne Zusammenführen (`entitaeten.py:166-173`).
|
||||
|
||||
**Auswirkung:** `data/entitaeten.json` enthält danach `{}`. Weil die `setattr`-Werte im laufenden
|
||||
Prozess bestehen bleiben, fällt der Verlust **erst beim nächsten Neustart** auf. Zusammen mit
|
||||
Befund 6 (keine Sicherung) gibt es dann nichts zurückzuholen.
|
||||
|
||||
**Vorschlag:** Setup-Knopf sperren, solange `ENTITAETEN` null ist, und in
|
||||
`setupSpeichernAusfuehren()` abbrechen, wenn `setupZuordnung` leer ist. Zusätzlich die Entität in
|
||||
den Nachlade-Pfad aufnehmen.
|
||||
|
||||
## 2. „Zurücksetzen" wirkt bei 15 von 17 Feldern nicht [belegt, nachgestellt]
|
||||
|
||||
`entitaeten.py:188` überspringt leere Werte:
|
||||
|
||||
```python
|
||||
if wert in (None, "", []):
|
||||
continue
|
||||
```
|
||||
|
||||
Der Kopfkommentar derselben Datei beschreibt das Problem exakt richtig — `setattr` verändert das
|
||||
Modul dauerhaft, „Zurücksetzen" muss den Standardwert *aktiv* zurückschreiben. Das Frontend tut das
|
||||
auch (`setupStandardwert`). Nur ist der Standardwert bei 15 der 17 Katalogfelder `""` oder `[]` —
|
||||
und genau die werden übersprungen.
|
||||
|
||||
Nachgestellt:
|
||||
|
||||
```
|
||||
nach Zuordnung: KM_SENSOR = 'sensor.alt_vag_mileage'
|
||||
nach Zurücksetzen: KM_SENSOR = 'sensor.alt_vag_mileage' ← erwartet: ''
|
||||
```
|
||||
|
||||
**Auswirkung:** Für den Nutzer sieht es aus, als hätte das Speichern versagt — `aktueller_stand()`
|
||||
liest aus dem laufenden Modul, das Feld zeigt beim nächsten Zeichnen wieder den alten Wert.
|
||||
Funktioniert nur bei `ZUENDUNG_SENSOR`, `BATTERIE_SENSOR` und `STANDORT_TRACKER`, den drei Feldern
|
||||
mit nicht-leerem Standard.
|
||||
|
||||
## 3. Alle vier Listenpositionen bekommen denselben Sensor [belegt]
|
||||
|
||||
`audi-dashboard-app.js:1976-1981`:
|
||||
|
||||
```js
|
||||
zuordnung[feld.key] = feld.positionen.map((_, i) => {
|
||||
const vorhanden = (werte[feld.key] || [])[i];
|
||||
if (vorhanden) return vorhanden;
|
||||
const vorschlag = entitaetKandidaten(feld.key, "", "")[0]; // i geht nicht ein
|
||||
return vorschlag && entitaetScore(feld, vorschlag, "") >= 3 ? vorschlag.id : "";
|
||||
});
|
||||
```
|
||||
|
||||
`entitaetKandidaten()` hängt nicht vom Index ab und schließt bereits vergebene IDs nicht aus —
|
||||
alle vier Positionen bekommen dieselbe Entität. Betrifft `TUER_SENSOREN`, `FENSTER_SENSOREN`,
|
||||
`TUERSCHLOSS_SENSOREN`.
|
||||
|
||||
**Auswirkung:** Bei einer Frischinstallation (genau der Fall, für den das Menü gebaut wurde) prüft
|
||||
`_sicherheitscheck()` danach viermal dieselbe Tür. **„Sicher abgestellt" meldet gesichert, obwohl
|
||||
drei Türen nie geprüft wurden.** Die Duplikat-Warnung fängt das beim Speichern ab, ist aber mit
|
||||
„Trotzdem speichern" wegklickbar.
|
||||
|
||||
## 4. Die Vorschlagsschwelle akzeptiert beliebige Sensoren [belegt]
|
||||
|
||||
`entitaetScore()` (`:1936`) vergibt: Stichwort +5, Domain +3, device_class +3, Einheit +2. Die
|
||||
Schwelle ist `>= 3` — **ein Domain-Treffer allein genügt**, ohne dass ein einziges Stichwort passt.
|
||||
Verschärfend: `setupNurPassend` wird zwei Zeilen vorher auf `true` gesetzt (`:1971`), wodurch
|
||||
`entitaetKandidaten()` ohnehin hart auf die Domain filtert. Die Schwelle ist damit *immer* erfüllt.
|
||||
Die Reihenfolge kommt aus `Object.keys(HASS.states)`, ist also faktisch willkürlich.
|
||||
|
||||
**Auswirkung:** Ohne passenden Zündungssensor wird `ZUENDUNG_SENSOR` stumm mit dem erstbesten
|
||||
`binary_sensor.*` vorbelegt — Bewegungsmelder, Fensterkontakt, was zuerst kommt. Das Feld sieht
|
||||
ausgefüllt aus, wird mitgespeichert, und **die gesamte Fahrterkennung hängt an einem
|
||||
Zufallssensor**. Bei Einzelfeldern greift keine Duplikat-Warnung. Dasselbe für `TANK_SENSOR` (jeder
|
||||
%-Sensor, etwa Luftfeuchte) und `REFRESH_BUTTON` (jedes `button.*`).
|
||||
|
||||
**Vorschlag:** Schwelle auf `>= 5` — also mindestens ein Stichworttreffer.
|
||||
|
||||
## 5. Geleerte Listenfelder setzen `["","","",""]` [belegt]
|
||||
|
||||
Die Skip-Regel aus Befund 2 prüft auf `[]`. Ein Array aus vier leeren Zeichenketten ist das nicht:
|
||||
|
||||
```python
|
||||
["","","",""] in (None, "", []) # False -> wird per setattr gesetzt
|
||||
```
|
||||
|
||||
`_sicherheitscheck()` zippt dann über vier leere Entity-IDs und erzeugt vier „unbekannt"-Zeilen —
|
||||
mal drei Listen sind das zwölf.
|
||||
|
||||
**Auswirkung:** Weil die Gesamtaussage bewusst `None` wird, sobald *eine* Prüfung unbekannt ist,
|
||||
steht die Übersicht danach **dauerhaft auf „Zustand unbekannt"** statt auf grün.
|
||||
|
||||
Kurios ist die Kombination mit Befund 2: Bei Einzelfeldern wirkt „Zurücksetzen" gar nicht, bei
|
||||
Listenfeldern zu stark. Beides verschwindet mit demselben Fix — statt leere Werte zu überspringen,
|
||||
immer den Standardwert aus `_STANDARDWERTE` zurückschreiben:
|
||||
|
||||
```python
|
||||
def overrides_anwenden():
|
||||
overrides = overrides_lesen()
|
||||
for key in _SCHLUESSEL:
|
||||
wert = overrides.get(key)
|
||||
leer = wert in (None, "", []) or (isinstance(wert, list) and not any(wert))
|
||||
setattr(einstellungen, key, _STANDARDWERTE[key] if leer else wert)
|
||||
```
|
||||
|
||||
## 6. Die Sensor-Zuordnung wird nirgends gesichert [belegt]
|
||||
|
||||
`backup.py:32` sichert `fahrzeugprofil.json`, `fahrten.jsonl`, `tankvorgaenge.jsonl` —
|
||||
`entitaeten.json` fehlt. Auch `audi_dashboard_backup_wiederherstellen` kennt es nicht, `update.ps1`
|
||||
fasst `data/` bewusst nicht an, und in `homeassistant/.gitignore` steht es nicht neben den anderen
|
||||
Laufzeitdateien.
|
||||
|
||||
**Auswirkung:** Nach einer Wiederherstellung ist die komplette Sensor-Zuordnung still weg. In
|
||||
Verbindung mit Befund 1 gibt es keinen Rückweg.
|
||||
|
||||
## 7. Eine beschädigte `entitaeten.json` legt das Panel lahm [belegt]
|
||||
|
||||
`overrides_lesen()` (`entitaeten.py:159`) ruft `json.loads` ohne Absicherung. Der Aufruf steht in
|
||||
`beim_start()` **vor** `alles_veroeffentlichen()` — wirft er, wird gar nichts veröffentlicht, das
|
||||
Panel bleibt komplett leer.
|
||||
|
||||
Geschrieben wird zwar atomar über `.tmp` + `os.replace`, das Risiko ist also gering — der Ausfall
|
||||
wäre aber total. Dieselbe Fehlerklasse, die im Branch `umsetzung-datametric360` bei `profil_lesen()`
|
||||
bereits abgefangen wurde.
|
||||
|
||||
---
|
||||
|
||||
# Mittel
|
||||
|
||||
## 8. Standortabfrage im Dauerfeuer, Karte bei jedem Render neu [belegt]
|
||||
|
||||
`USER_POS_TS` wird nur im Erfolgs-Callback gesetzt (`:553`), nicht im Fehlerfall (`:557`). Die
|
||||
30-Sekunden-Drossel in `standortErfassenFallsNoetig()` (`:560`) greift damit nie, wenn der Nutzer
|
||||
die Standortfreigabe ablehnt oder kein Fix zustande kommt.
|
||||
|
||||
Parallel dazu zerstört `render()` die Vorschaukarte und baut sie neu (`:2879-2880`), sobald die
|
||||
Route `home` ist — bei **jedem** Backend-Update.
|
||||
|
||||
**Auswirkung:** Mit einem GPS-Tracker als Quelle (genau der FMM003-Fall) sind das dutzende
|
||||
`getCurrentPosition({enableHighAccuracy:true})`-Anfragen pro Stunde plus sichtbares Kachelflackern.
|
||||
|
||||
**Vorschlag:** `USER_POS_TS = Date.now()` auch im Fehlerpfad; Karte nur bei echtem Ansichtswechsel
|
||||
neu bauen — die Variable `gleicheAnsicht` gibt es in `render()` bereits.
|
||||
|
||||
## 9. Kein Tastaturweg in die Einstellungen unter 860 px [belegt]
|
||||
|
||||
`audi-dashboard-ios.css:81` versteckt `.profilbtn` — den echten `<button aria-label="Einstellungen">` —
|
||||
und holt ihn erst in der Container-Abfrage ab 860 px zurück (`:230`). Der Ersatz ist ein
|
||||
Klick-Handler auf `#marke` (`:2965`), und das ist ein `<div class="rings" aria-label="Audi">`
|
||||
(`:3849`): ohne `role`, ohne `tabindex`.
|
||||
|
||||
**Auswirkung:** In Telefonbreite gibt es für Tastatur- und Screenreader-Nutzer **keinen** Zugang zu
|
||||
den Einstellungen. Ein `<div>` mit `aria-label` ohne Rolle wird von den meisten Screenreadern nicht
|
||||
einmal angesagt. Gleiche Fehlerklasse wie das Swipe-Löschen aus `AUDIT_2026-08-10.md`.
|
||||
|
||||
**Vorschlag:** `#marke` zu einem `<button aria-label="Einstellungen">` machen; dann kann auch
|
||||
`pointer-events:auto` in `audi-dashboard-ios.css:78` entfallen.
|
||||
|
||||
## 10. `.navmarke` nur in der iOS-Auflage versteckt [belegt]
|
||||
|
||||
`audi-dashboard-app.js:2956-2963` hängt den Ringklon **unbedingt** in `#tabbar`.
|
||||
`.navmarke{display:none}` steht ausschließlich in `audi-dashboard-ios.css:194`. `.tabbar` ist ein
|
||||
`display:grid` mit `repeat(5, 1fr)` (`audi-dashboard.css:211`).
|
||||
|
||||
**Auswirkung:** Lädt `/local/audi-dashboard-ios.css` nicht (404, Cache), wird der Klon ein sechstes
|
||||
Grid-Element — alle Tabs rutschen eine Spalte weiter, „Tanken" fällt in eine zweite Zeile, die
|
||||
Menüleiste zerfällt. Kein theoretischer Fall: Commit `3548f77` dokumentiert genau dieses
|
||||
Deployment-Loch.
|
||||
|
||||
**Vorschlag:** `.navmarke{display:none}` gehört in die Basis-CSS, die Sichtbarkeit in die Auflage.
|
||||
|
||||
## 11. Standort-Menü ohne `pointercancel` [belegt]
|
||||
|
||||
`standortMenuVerdrahten()` (`:706-731`) setzt `smY0` nur in `pointerup` zurück. Alle drei anderen
|
||||
Zeigergesten der Datei haben einen `pointercancel`-Handler (`:2929`, `:3055`, `:3122`), diese nicht.
|
||||
|
||||
**Auswirkung:** Übernimmt das System die Berührung (iOS-Randgeste, Multitouch, eingehender Anruf),
|
||||
bleibt `smY0` gesetzt. Der `pointermove`-Handler ruft dann `preventDefault()` für jede weitere
|
||||
Bewegung — **Scrollen ist in der ganzen App blockiert**, bis irgendwo ein `pointerup` kommt, der
|
||||
dann ein `dy` aus einem veralteten Startpunkt auswertet.
|
||||
|
||||
## 12. Fehlgeschlagenes Reverse-Geocoding wird dauerhaft gecacht [belegt]
|
||||
|
||||
`:572-586` setzt `STANDORT_ADRESSE_KEY` auch im `catch`-Zweig.
|
||||
|
||||
**Auswirkung:** Ein einziger fehlgeschlagener Nominatim-Abruf (Rate-Limit, kurzer Netzausfall) für
|
||||
eine Zelle führt dazu, dass für dieselbe Zelle die **gesamte Sitzung** lang nur Koordinaten
|
||||
angezeigt werden, auch wenn das Netz längst wieder da ist.
|
||||
|
||||
**Vorschlag:** Key nur im Erfolgsfall setzen.
|
||||
|
||||
## 13. Setup-Popup hält den `role="dialog"`-Vertrag nicht ein [belegt]
|
||||
|
||||
`:2774` deklariert `role="dialog" aria-modal="true"`. Es fehlen: Escape zum Schließen (in der Datei
|
||||
gibt es keinen `keydown`-Handler), eine Fokusfalle (Tab wandert in den überdeckten Hintergrund),
|
||||
und der Schalter „Nur passende Sensoren anzeigen" (`:2779`) hat keinen zugänglichen Namen — der
|
||||
Beschriftungstext steht im Geschwister-`<span>` außerhalb des `<label>`.
|
||||
|
||||
Dazu: Die Entitäts-Auswahl öffnet ausschließlich im `click`-Handler (`:3181`). Wer per Tab ins Feld
|
||||
springt und tippt, löst zwar den `input`-Handler aus, der bricht aber ab, weil `setupSucheOffen`
|
||||
noch `null` ist — sichtbar passiert nichts. `role="combobox"`, `aria-expanded` und `aria-controls`
|
||||
fehlen ebenfalls.
|
||||
|
||||
## 14. Standort-Menü nicht per Tastatur bedienbar [belegt]
|
||||
|
||||
Im eingeklappten Zustand steht das Blatt per `transform` überwiegend außerhalb des Sichtbereichs,
|
||||
bleibt aber vollständig im DOM und im Tab-Fokus — Adresse, Route-Link und Teilen-Knopf sind
|
||||
fokussierbar, ohne sichtbar zu sein (kein `inert`, kein `aria-hidden`). Öffnen geht gar nicht per
|
||||
Tastatur: `.standortmenu-griffzone` ist ein `<div>` mit reinen Pointer-Handlern. Der Umschalter
|
||||
Straße/Satellit (`:773`) hat kein `aria-pressed`, sein Label bleibt in beiden Zuständen gleich.
|
||||
|
||||
## 15. `disconnectedCallback()` räumt nur eine von drei Karten ab [belegt]
|
||||
|
||||
`:3815-3817` zerstört `MAP`, nicht aber `SMAP`/`TMAP`. Wird das Panel abgehängt, während Standort-
|
||||
oder Übersichtsseite offen ist, bleibt eine Leaflet-Instanz samt Resize-Listener und
|
||||
Kachel-Abrufen am Leben.
|
||||
|
||||
---
|
||||
|
||||
# Klein
|
||||
|
||||
| Ort | Befund |
|
||||
|---|---|
|
||||
| `audi-dashboard-ios.css:88, 208` | `main{padding:…}` (0,0,1) verliert gegen `main#view` (1,0,1) in `audi-dashboard.css:197`. Auf Großbildschirmen bleibt der Seitenrand bei 20 px statt der beabsichtigten 44 px. **Achtung:** `.standort-vollbild{margin:0 -20px}` (`audi-dashboard.css:704`) passt heute genau dazu — beides gehört zusammen angefasst. |
|
||||
| `audi-dashboard-app.js:3190/3612` | „Nur passende Sensoren anzeigen" wirkt nicht, solange ein Dropdown offen ist: Der Klick-Handler ersetzt das Overlay-DOM, bevor das `change`-Event des Kontrollkästchens ausgeliefert wird. [plausibel] |
|
||||
| `audi-dashboard-app.js:2966` | Theme-Umschalten ruft kein `render()` — die Leaflet-Kacheln bleiben bis zum nächsten Backend-Update im alten Stil. Durch die neue Dauerkarte auf der Übersicht deutlich sichtbarer als früher. |
|
||||
| `audi-dashboard-app.js:804` | `${de(CAR.tankPct)} %` zeigt ohne Tanksensor „0 %“, während direkt daneben korrekt „Reichweite unbekannt“ steht. |
|
||||
| `audi-dashboard-app.js:496, 518, 117` | Toter Code: `fahrzeugGlyphPfade()` nie aufgerufen, `zustand.parkplatz` nie gelesen, `standortGenauigkeitM`/`standortZeit` gemappt aber ungenutzt. Kommentare behaupten das Gegenteil. |
|
||||
| `audi-dashboard-app.js:595` | Einzige Interpolation im neuen Code, die ohne `esc()` in ein Attribut geht. Heute nicht ausnutzbar, weil `_zu_zahl()` im Backend nur Zahlen durchlässt — als Härtung trotzdem sinnvoll, ebenso `Number.isFinite` in `standortBekannt()`. |
|
||||
|
||||
---
|
||||
|
||||
# Dokumentation
|
||||
|
||||
## AGENTS.md widerspricht sich an sechs Stellen [belegt]
|
||||
|
||||
Die Datei ist auf 427 Zeilen gewachsen; neue Einträge wurden angehängt statt eingearbeitet.
|
||||
|
||||
| Stelle | Aussage | Widerspruch |
|
||||
|---|---|---|
|
||||
| Z. 94 | „trip detection via the iPhone WLAN sensor" | Z. 249 ff.: läuft über `ZUENDUNG_SENSOR`, WLAN „fully removed" |
|
||||
| Z. 110 | „Codec JSON → MQTT/TLS → Mosquitto" | Z. 227 ff.: Schwenk auf flespi, „not MQTT at all" |
|
||||
| Z. 93 | „4 modules" | tatsächlich 5 (`entitaeten.py` neu) |
|
||||
| Z. 97 | „3.130 lines" | tatsächlich 3.873 |
|
||||
| Z. 100 | „`einstellungen.py` — the one file edited before install" | genau das ersetzt jetzt das Setup-Menü |
|
||||
| Z. 320 | `STANDORT_TRACKER` „left empty" | steht auf `device_tracker.testzone_fmm003` |
|
||||
|
||||
Dazu veraltete Codeverweise: `fakeTrack()` liegt bei `:421` statt `:414`, die Statistik-Behauptung
|
||||
in `INSTALL.md` bei Z. 229 statt Z. 204.
|
||||
|
||||
Die Datei verlangt selbst „nicht festhalten, was Code und Git-History schon zeigen" (Z. 47) —
|
||||
Z. 282–401 sind 120 Zeilen Changelog-Prosa für fünf Einträge, und Z. 249–279 dupliziert inhaltlich
|
||||
Z. 133–153.
|
||||
|
||||
## INSTALL.md [belegt]
|
||||
|
||||
- **Zirkuläre Schrittfolge:** Schritt 4 verweist auf „siehe Schritt 9 zuerst" (Z. 96), Schritt 7
|
||||
setzt Schritt 4 voraus (Z. 176). Die Reihenfolge 4→9→7→4 wird nirgends aufgelöst.
|
||||
- **Ausgelieferte Default-Entities werden verschwiegen:** `ZUENDUNG_SENSOR`, `BATTERIE_SENSOR` und
|
||||
`STANDORT_TRACKER` sind mit den `testzone_fmm003`-Entities der Autoren-Instanz vorbelegt. Bei
|
||||
einer Frischinstallation zeigen sie ins Leere. Z. 108–110 behauptet nur für KM/TANK/RANGE
|
||||
„unbelegt".
|
||||
- **Override-Datei nicht benannt:** Z. 104 spricht von „einer Override-Datei" — der Pfad
|
||||
`/config/audi_dashboard/entitaeten.json` steht nirgends, und ihre fehlende Sicherung (Befund 6)
|
||||
ist nicht erwähnt.
|
||||
- Schritt 2 verweist auf `fahrzeugprofil.example.json`, deren Z. 2 weiterhin den „WLAN-Namen"
|
||||
verlangt, obwohl `fahrzeug.wlan_name` im selben Branch entfernt wurde.
|
||||
|
||||
## WLAN-Reste in der übrigen Doku [belegt]
|
||||
|
||||
Im Code ist die Entfernung vollständig (keine Fundstelle). In der Doku nicht:
|
||||
`SPECIFICATION.md` (Z. 16, 147, 181, 196, 217), `homeassistant/README.md:106` und die Profilvorlage
|
||||
nennen WLAN-Sensor und `TommiG1/HA_VAG-EU-Data-Act` weiterhin als aktuellen Stand.
|
||||
|
||||
## `update.ps1` [belegt]
|
||||
|
||||
Für `www/` ist das Skript nach dem Fix **vollständig** — `audi-dashboard-ios.css` und `badges/`
|
||||
sind ergänzt, Cache-Busting greift auch für die neue CSS-Datei.
|
||||
|
||||
**Verbleibende Lücke:** `homeassistant/data/shell_beleg_parser.py` ist Code, kein Datenbestand —
|
||||
`belegverarbeitung.py:41` lädt ihn aus `/config/audi_dashboard/`. `update.ps1` schließt `data/`
|
||||
pauschal aus, `INSTALL.md` behandelt ihn als Einmal-Kopie. **Änderungen am Beleg-Parser, dem
|
||||
einzigen getesteten Teil des Repos, kämen auf keiner Instanz an.**
|
||||
|
||||
## `design/` [belegt]
|
||||
|
||||
`dm360-host.html` lädt `audi-dashboard-app.js` (Z. 12) und `audi-dashboard-ios.css` (Z. 33) — beide
|
||||
existieren in `design/` nicht. Aus der Repo-Kopie ist das Board funktionslos; es läuft nur im
|
||||
Claude-Design-Projekt. Nirgends dokumentiert.
|
||||
|
||||
`design/README.md:19` führt `audi-dashboard-ios.css` in der Inhaltstabelle des Ordners (die Datei
|
||||
liegt in `homeassistant/www/`) und behauptet, die Auflage „rührt `audi-dashboard-app.js` nicht an" —
|
||||
Z. 57–59 derselben Datei beschreibt, dass genau dort der Stylesheet-Loader ergänzt wurde.
|
||||
|
||||
**Markenassets:** Der Diff fügt keine neuen Binärdateien hinzu. `DataMetric360 Board.dc.html`
|
||||
verwendet die vorhandenen Audi-Type-Dateien per `@font-face` — das Lizenzrisiko bleibt unverändert,
|
||||
nicht erhöht.
|
||||
|
||||
## `.gitignore` [belegt]
|
||||
|
||||
`installationspaket/` ist korrekt ergänzt und schließt nichts Getracktes aus. Es fehlt
|
||||
`data/entitaeten.json` neben den anderen drei Laufzeitdateien — heute harmlos, weil die Datei nur
|
||||
unter `/config/audi_dashboard/` entsteht, aber inkonsistent zum eigenen Grundsatz der Datei.
|
||||
|
||||
---
|
||||
|
||||
# Was den Branch `umsetzung-datametric360` betrifft
|
||||
|
||||
**Der flespi-Schwenk macht `homeassistant/FMM003_MAPPING.md` überholt.** Das Dokument beschreibt
|
||||
Codec JSON über MQTT/TLS mit eigener CA und einem `mosquitto_sub`-Mitschnitt. Mit flespi läuft es
|
||||
über den nativen Codec8/TCP-Kanal mit IMEI-Authentifizierung, ohne Zertifikate und ohne eingehenden
|
||||
Port; die Feldzuordnung entstünde aus der flespi-REST-API. Beim Zusammenführen anpassen oder
|
||||
ersetzen.
|
||||
|
||||
**Das CORS-Rätsel ist damit auch erklärt.** Die Notiz auf `main`, der `http:`-Block sei aus der
|
||||
`configuration.yaml` entfernt worden, „nachdem HA angefangen hat, ihn zu migrieren beziehungsweise
|
||||
zu ignorieren", erklärt, warum `cors_allowed_origins` in HA 2026.8 wirkungslos blieb — auch bei
|
||||
gleichem Ursprung. Gehört in `homeassistant/REVERSE_PROXY.md` nachgetragen.
|
||||
|
||||
**Die Falle beim Zusammenführen** steht bereits in `AGENTS.md` dieses Branches: `profil_lesen()`
|
||||
gibt hier bei fehlender Profildatei `None` zurück, `profil.py` ist auf `main` unverändert und geht
|
||||
konfliktfrei durch — die dortigen Aufrufstellen prüfen das aber nicht.
|
||||
|
||||
---
|
||||
|
||||
# Empfehlung
|
||||
|
||||
Reihenfolge nach Schaden:
|
||||
|
||||
1. **Befund 1** (Datenverlust) — zwei Riegel, wenige Zeilen.
|
||||
2. **Befunde 2 und 5** (Zurücksetzen) — ein gemeinsamer Fix in `overrides_anwenden()`.
|
||||
3. **Befunde 3 und 4** (falsche Vorbelegung) — Index in den Vorschlag einbeziehen, Schwelle auf 5.
|
||||
4. **Befund 6** (Sicherung) — eine Zeile in `backup.py`, plus Wiederherstellung.
|
||||
5. **Befund 7** (Absicherung beim Lesen), **8** (Akku), **9/10** (Bedienbarkeit, Robustheit).
|
||||
|
||||
Die Punkte 1 bis 4 betreffen alle das neue Setup-Menü und lassen sich in einem Zug erledigen.
|
||||
+247
@@ -0,0 +1,247 @@
|
||||
# DataMetric360 als native Home-Assistant-Integration
|
||||
|
||||
**Stand: 2026-08-13.** Vorhaben: Das HA-Backend von „pyscript-Skripte plus Dateien kopieren" auf
|
||||
eine **eigene Integration mit Konfigurationsdialog** umstellen — Einrichtung vollständig über die
|
||||
Oberfläche, kein YAML, Updates als Knopfdruck in HAs eigener Update-Liste.
|
||||
|
||||
Alle unten genannten Schnittstellen sind **an der laufenden Instanz geprüft** (Home Assistant
|
||||
2026.8.1 im Container `audi_ha_test`), nicht aus der Dokumentation abgeschrieben. Die geprüften
|
||||
Signaturen stehen jeweils dabei.
|
||||
|
||||
Verwandte Dokumente: `homeassistant/INSTALL.md` (heutiger, manueller Weg — bleibt gültig, bis diese
|
||||
Umstellung steht), `UMSETZUNGSPLAN.md`, `REVIEW_main_2026-08-13.md` (die Fehler, die hier
|
||||
konstruktionsbedingt verschwinden).
|
||||
|
||||
---
|
||||
|
||||
## 1. Was heute nötig ist — und was davon bleibt
|
||||
|
||||
| Heute | Nach der Umstellung |
|
||||
|---|---|
|
||||
| HACS installieren, darüber pyscript | entfällt |
|
||||
| drei Ordner nach `/config/` kopieren (`pyscript/`, `data/`, `www/`) | einmalig **ein** Ordner nach `custom_components/` |
|
||||
| zwei Blöcke in `configuration.yaml` einfügen | entfällt vollständig |
|
||||
| Entity-IDs zuordnen | bleibt, aber als HA-Konfigurationsdialog statt als selbstgebautes Menü |
|
||||
| langlebiges Token in `audi_dashboard/ha_token.txt` ablegen | **entfällt ersatzlos** |
|
||||
| `pip install pypdf` von Hand | entfällt (`manifest.json` → `requirements`) |
|
||||
| Neustart | einmalig, wie bei jeder Integration |
|
||||
| Updates über `update.ps1` per Samba | Knopfdruck in *Einstellungen → System → Updates* |
|
||||
|
||||
## 2. Die Bausteine, die HA dafür mitbringt
|
||||
|
||||
Alle in 2026.8.1 vorhanden und geprüft:
|
||||
|
||||
| Baustein | Ersetzt |
|
||||
|---|---|
|
||||
| `EntitySelector` mit `domain`, `device_class`, `multiple`, `reorder`, `exclude_entities` | das gesamte Setup-Menü (`entitaeten.py` + ~800 Zeilen JS) |
|
||||
| `panel_custom.async_register_panel(...)` | den `panel_custom`-Block in `configuration.yaml` |
|
||||
| `hass.http.async_register_static_paths([StaticPathConfig(url_path, path, cache_headers)])` | Kopieren nach `/config/www/` samt Cache-Busting-Stub |
|
||||
| `ConfigEntry.add_update_listener(...)` | den „wirkt erst nach Neustart"-Hinweis bei den drei triggergebundenen Feldern |
|
||||
| `async_track_state_change_event` / `async_track_time_interval` / `async_track_time_change` | `@state_trigger` / `@time_trigger("period")` / `@time_trigger("cron")` |
|
||||
| `recorder.history.get_significant_states(...)` | den HTTP-Aufruf auf `/api/history/period` **samt Token-Datei** |
|
||||
| `hass.async_add_executor_job(...)` | `task.executor(io.open, ...)` |
|
||||
| `Store` (`homeassistant.helpers.storage`) | handgeschriebenes JSON-I/O (optional, siehe §6) |
|
||||
| `HomeAssistantView` / `websocket_api.async_register_command` | die 16-KB-Attributgrenze für Fahrten und Tankvorgänge |
|
||||
| `UpdateEntity` (`INSTALL`, `PROGRESS`, `BACKUP`, `RELEASE_NOTES`) | `updateverwaltung.py` als sichtbare Update-Entität |
|
||||
|
||||
Der wichtigste Einzelfund: **`EntitySelector` kann `exclude_entities`.** Die Duplikat-Prüfung wäre
|
||||
damit keine wegklickbare Warnung mehr, sondern schlicht nicht anwählbar.
|
||||
|
||||
## 3. Aufbau
|
||||
|
||||
```
|
||||
custom_components/datametric360/
|
||||
├── manifest.json Abhängigkeiten, "config_flow": true, Version
|
||||
├── const.py Rollen-Tabelle (heute FELDER in entitaeten.py)
|
||||
├── config_flow.py Ersteinrichtung + Optionen (die 17 Sensor-Rollen)
|
||||
├── __init__.py Dienste, Horcher, Zeitgeber, Panel, statische Dateien
|
||||
├── update.py UpdateEntity gegen das eigene Gitea
|
||||
├── api.py HomeAssistantView für die Companion-App (später)
|
||||
└── www/ audi-dashboard-app.js, .css, badges/ — mitgeliefert
|
||||
```
|
||||
|
||||
### Konfigurationsdialog
|
||||
|
||||
Statt einer eigenen Katalogverwaltung reicht ein Schema. Skizze für zwei der 17 Rollen:
|
||||
|
||||
```python
|
||||
vol.Schema({
|
||||
vol.Required("zuendung_sensor"): EntitySelector(
|
||||
EntitySelectorConfig(domain=["binary_sensor"])
|
||||
),
|
||||
vol.Optional("tuer_sensoren", default=[]): EntitySelector(
|
||||
EntitySelectorConfig(domain=["binary_sensor"], device_class=["door"],
|
||||
multiple=True, reorder=True)
|
||||
),
|
||||
})
|
||||
```
|
||||
|
||||
Suche, Übersetzung, Gerätezuordnung und Mehrfachauswahl kommen von HA. Die vier Türpositionen
|
||||
werden zu einer sortierbaren Mehrfachauswahl — die Reihenfolge ersetzt die heutigen festen
|
||||
Positionsfelder.
|
||||
|
||||
### Panel und Dateien
|
||||
|
||||
```python
|
||||
await hass.http.async_register_static_paths([
|
||||
StaticPathConfig("/datametric360", hass.config.path("custom_components/datametric360/www"),
|
||||
cache_headers=False),
|
||||
])
|
||||
panel_custom.async_register_panel(
|
||||
hass, frontend_url_path="datametric360", webcomponent_name="audi-dashboard-panel",
|
||||
sidebar_title="Mein Audi", sidebar_icon="mdi:car-sports",
|
||||
module_url=f"/datametric360/audi-dashboard-app.js?v={VERSION}",
|
||||
)
|
||||
```
|
||||
|
||||
Die Versionsnummer in der URL macht den Lade-Stub `audi-dashboard-panel.js` und
|
||||
`audi-dashboard-version.json` überflüssig — das Cache-Problem löst sich, weil die Integration ihre
|
||||
eigene Version kennt.
|
||||
|
||||
**Das Frontend selbst bleibt unangetastet.** Alle 3.873 Zeilen `audi-dashboard-app.js` laufen
|
||||
weiter; nur das Setup-Menü darin wird überflüssig.
|
||||
|
||||
## 4. Übersetzung der pyscript-Eigenheiten
|
||||
|
||||
Mechanisch, kein Neuentwurf. Die Fachlogik — Fahrterkennung, Tankerkennung, Beleg-Parser,
|
||||
Reifenzähler, Prognose — geht nahezu unverändert mit.
|
||||
|
||||
| pyscript | Integration |
|
||||
|---|---|
|
||||
| `@service def audi_dashboard_x()` | `hass.services.async_register(DOMAIN, "x", handler, schema)` |
|
||||
| `@state_trigger(f"{SENSOR}")` | `async_track_state_change_event(hass, [sensor], handler)` |
|
||||
| `@time_trigger("period(now, 20 seconds)")` | `async_track_time_interval(hass, handler, timedelta(seconds=20))` |
|
||||
| `@time_trigger("cron(0 4 * * *)")` | `async_track_time_change(hass, handler, hour=4, minute=0, second=0)` |
|
||||
| `task.unique()` + `task.sleep()` | `asyncio.Task` merken und bei Bedarf `cancel()` |
|
||||
| `task.executor(io.open, …)` | `hass.async_add_executor_job(...)` |
|
||||
| `state.set("pyscript.x", …)` | eigene Entität oder `HomeAssistantView` (siehe §6) |
|
||||
| `subprocess.run(shell_beleg_parser.py)` | `pypdf` direkt importieren, in einem Executor-Job |
|
||||
| `urllib.request` auf `/api/history/period` | `recorder.history.get_significant_states(...)` |
|
||||
|
||||
Die letzte Zeile ist die wichtigste: Sie beseitigt **zwei** Befunde auf einmal — den blockierenden
|
||||
Aufruf, den HA seit 2026.8 abbricht (siehe `REVIEW_main_2026-08-13.md`, und derselbe Fehler wurde
|
||||
im Branch `umsetzung-datametric360` bereits behoben), **und** die Token-Datei im Klartext.
|
||||
|
||||
## 5. Installation und Updates
|
||||
|
||||
Hier liegt der eigentliche Knackpunkt, deshalb ausführlich.
|
||||
|
||||
### HACS scheidet aus
|
||||
|
||||
HACS spricht ausschließlich mit GitHub. Anfragen, auch GitLab, Gitea oder Codeberg zuzulassen, gibt
|
||||
es seit Jahren; umgesetzt sind sie nicht. Das Repository liegt auf `gitea.nothaft.cloud` — HACS ist
|
||||
damit kein Weg, außer man spiegelt nach GitHub.
|
||||
|
||||
### „App" ist der falsche Behälter
|
||||
|
||||
App-Repositories (früher Add-ons) akzeptieren **beliebige Git-URLs**, auch selbst gehostete; nötig
|
||||
ist nur eine `repository.yaml` im Wurzelverzeichnis. Das ist die einzige Stelle, an der Gitea
|
||||
nativ mitspielen würde.
|
||||
|
||||
Inhaltlich passt es trotzdem nicht: Apps sind **Docker-Container** neben Home Assistant. Eine
|
||||
Integration muss *im* HA-Prozess laufen, um Entitäten anzulegen, Dienste zu registrieren und ein
|
||||
Panel einzuhängen. Eine App kann das nicht.
|
||||
|
||||
*(Es gäbe den Trick, eine winzige App zu bauen, die nichts weiter tut, als die Integration nach
|
||||
`custom_components/` zu schreiben — dann käme auch die Erstinstallation aus dem eigenen Gitea. Ein
|
||||
Docker-Container für einen einmaligen Kopiervorgang ist das aus meiner Sicht nicht wert; der
|
||||
Vollständigkeit halber notiert.)*
|
||||
|
||||
### Der native Weg: eigene UpdateEntity
|
||||
|
||||
`UpdateEntity` lässt die Integration ihre Updates selbst melden — sichtbar in **Einstellungen →
|
||||
System → Updates**, derselben Liste wie HA-Kern und Apps. Geprüfte Möglichkeiten:
|
||||
|
||||
```
|
||||
UpdateEntityFeature: INSTALL, SPECIFIC_VERSION, PROGRESS, BACKUP, RELEASE_NOTES
|
||||
async_install(version: str | None, backup: bool, **kwargs) -> None
|
||||
```
|
||||
|
||||
`BACKUP` gibt es genau für das, was `updateverwaltung.py` heute von Hand macht: vor dem Einspielen
|
||||
den alten Code sichern.
|
||||
|
||||
**Die Logik ist bereits vorhanden.** `updateverwaltung.py` klont flach, vergleicht Versionen,
|
||||
sichert nach `code_backups/` und ersetzt die Dateien. Das wandert nahezu unverändert in
|
||||
`async_install()`. Neu sind nur zwei Eigenschaften:
|
||||
|
||||
```python
|
||||
@property
|
||||
def installed_version(self) -> str: return VERSION # aus manifest.json
|
||||
@property
|
||||
def latest_version(self) -> str | None: return self._neueste # aus Gitea
|
||||
```
|
||||
|
||||
Für `latest_version` empfiehlt sich statt der heutigen Zeitstempel-Zahl aus
|
||||
`audi-dashboard-version.json` ein **Git-Tag**. Gitea bietet eine GitHub-kompatible Schnittstelle:
|
||||
|
||||
```
|
||||
GET https://gitea.nothaft.cloud/api/v1/repos/paul/audi-app/releases/latest
|
||||
```
|
||||
|
||||
Ein einzelner HTTP-Aufruf, kein Klonen. In HA steht dann „1.4.0 → 1.5.0" statt einer nichtssagenden
|
||||
Zahl, und die Release-Beschreibung lässt sich über `release_notes` direkt anzeigen.
|
||||
|
||||
### Was bleibt
|
||||
|
||||
**Die Erstinstallation bleibt ein einmaliges Kopieren** des Ordners nach `custom_components/`. Für
|
||||
Integrationen aus Nicht-GitHub-Quellen gibt es keinen nativen Installationsweg. Jedes weitere
|
||||
Update ist danach ein Knopfdruck.
|
||||
|
||||
## 6. Datenhaltung — bewusst zu entscheiden
|
||||
|
||||
Zwei Möglichkeiten, beide vertretbar:
|
||||
|
||||
- **`Store`** (`.storage/datametric360`): atomar, versioniert, mit Migrationspfad. Nachteil: für
|
||||
Menschen nicht mehr lesbar, und die heutige Sicherung über `backup.py` müsste neu gedacht werden.
|
||||
- **JSON-Dateien behalten** unter `/config/audi_dashboard/`, gelesen über Executor-Jobs. Nachteil:
|
||||
kein Migrationspfad. Vorteil: Fahrten und Tankvorgänge bleiben von Hand einsehbar und mit den
|
||||
bestehenden Sicherungen kompatibel.
|
||||
|
||||
**Empfehlung:** Dateien behalten. Bei einem Fahrzeugprofil, einem Fahrtenbuch und einer
|
||||
Tankhistorie ist Lesbarkeit mehr wert als Migrationskomfort — und die vorhandene Sicherungslogik
|
||||
bleibt gültig.
|
||||
|
||||
Unabhängig davon: Fahrten und Tankvorgänge gehören **nicht** in Entitäts-Attribute (16-KB-Grenze,
|
||||
siehe `frontend_veroeffentlichung.py`), sondern hinter einen `HomeAssistantView`. Das ist zugleich
|
||||
die saubere Schnittstelle für die Companion-App, die heute Attribut-Blobs auslesen muss.
|
||||
|
||||
## 7. Was dabei konstruktionsbedingt verschwindet
|
||||
|
||||
Aus `REVIEW_main_2026-08-13.md`:
|
||||
|
||||
- **Befund 1** (Speichern mit leerem Katalog löscht alle Zuordnungen) — der Konfigurationsdialog
|
||||
validiert serverseitig, ein leeres Formular kommt gar nicht durch.
|
||||
- **Befunde 2 und 5** (Zurücksetzen wirkungslos bzw. zu stark) — die `setattr`-Override-Ebene
|
||||
entfällt komplett; HA verwaltet Optionen selbst.
|
||||
- **Befunde 3 und 4** (falsche Vorbelegung, beliebige Sensoren) — HAs Entity-Picker schlägt nichts
|
||||
vor, der Nutzer wählt; `exclude_entities` verhindert Doppelbelegung.
|
||||
- **Befund 7** (kaputte `entitaeten.json` legt das Panel lahm) — die Datei existiert nicht mehr.
|
||||
- Der Neustart-Zwang bei den drei triggergebundenen Feldern — `add_update_listener` lädt die
|
||||
Integration neu und registriert die Horcher dabei mit den neuen Entity-IDs.
|
||||
|
||||
Nicht gelöst werden dadurch: die Frontend-Befunde (Standort-Dauerfeuer, Barrierefreiheit,
|
||||
`.navmarke`) — das Frontend bleibt ja unverändert.
|
||||
|
||||
## 8. Aufwand und Reihenfolge
|
||||
|
||||
Realistisch einige Tage, nicht Wochen — der Großteil ist Umschreiben von Dekoratoren.
|
||||
|
||||
1. **Zuerst die drei Setup-Fehler roh fixen** (etwa eine Stunde). Sonst läuft die Instanz bis zur
|
||||
Umstellung mit einem Datenverlust-Pfad.
|
||||
2. **Gerüst aufsetzen:** `manifest.json`, `config_flow.py`, Panel- und Dateiregistrierung. Die
|
||||
pyscript-Skripte laufen dabei zunächst unverändert weiter.
|
||||
3. **Logik Datei für Datei herüberziehen**, beginnend mit `fahrtabschluss_logik.py` — dort
|
||||
verschwinden Token und blockierender Aufruf zuerst.
|
||||
4. **`update.py`** gegen das Gitea-Repository.
|
||||
5. **`api.py`** für die Companion-App, sobald diese so weit ist.
|
||||
|
||||
### Was dabei zu beachten ist
|
||||
|
||||
- **Neuladen im laufenden Betrieb entfällt.** pyscript lädt bei jeder Dateiänderung neu; eine
|
||||
Integration braucht einen Neustart oder ein Neuladen. Beim Entwickeln spürbar, im Betrieb egal.
|
||||
- **Die Companion-App liest heute `pyscript.audi_dashboard_*`.** Werden daraus eigene Entitäten
|
||||
oder ein eigener Endpunkt, ändert sich die Tabelle `ENTITAETEN` in
|
||||
`companion-app/src/api/types.ts` — eine Datei, überschaubar.
|
||||
- **`shell_beleg_parser.py` wandert mit in die Integration.** Heute liegt er unter
|
||||
`/config/audi_dashboard/` und wird von keinem Update-Pfad ausgeliefert (siehe Review) — als Teil
|
||||
des Integrationsordners löst sich das mit.
|
||||
Reference in New Issue
Block a user