78d70fa4ca
Haelt fest, was bewusst anders geloest wurde als vorgeschlagen, welche drei Fehler beim Umsetzen dazukamen und welcher pyscript-Fallstrick dabei aufgefallen ist.
420 lines
23 KiB
Markdown
420 lines
23 KiB
Markdown
# 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.
|
||
|
||
---
|
||
|
||
> ## ✅ Umgesetzt am 2026-08-13
|
||
>
|
||
> Alle Befunde dieses Dokuments sind behoben — siehe die fünf Commits von
|
||
> `Setup-Zuordnung: Zuruecksetzen wirkt…` bis `Kleinere Befunde und Dokumentation…`.
|
||
> Das Dokument bleibt als Befundprotokoll stehen: es begründet, warum die
|
||
> Änderungen so aussehen, wie sie aussehen.
|
||
>
|
||
> **Zwei Punkte wurden bewusst anders gelöst als hier vorgeschlagen:**
|
||
>
|
||
> 1. *Karte nur bei echtem Ansichtswechsel neu aufbauen* — nicht umgesetzt. `render()` ersetzt den
|
||
> Inhalt per `innerHTML`; eine überlebende Leaflet-Instanz zeigte danach auf ein abgehängtes
|
||
> Element und bliebe leer. Der Neuaufbau hängt am 20-Sekunden-Takt des Backends und ließe sich
|
||
> nur durch einen Umbau der Render-Architektur ändern. Die Begründung steht im Code.
|
||
> Behoben ist dagegen die Standortabfrage, die tatsächlich ungedrosselt lief.
|
||
> 2. *`SPECIFICATION.md`* wurde nicht in Teilen umgeschrieben, sondern hat einen datierten
|
||
> Statushinweis am Anfang bekommen. Ein Umschreiben der §4/§5-Tabellen hätte neue
|
||
> Ungenauigkeiten riskiert.
|
||
>
|
||
> **Drei Fehler kamen beim Umsetzen dazu**, sichtbar erst im laufenden Panel: ein unlesbares Datum
|
||
> ergab „NaN/N" statt eines Strichs, ein fehlender Tanksensor „0 %" statt „unbekannt", und neben dem
|
||
> Typenschild stand die Ausführung doppelt. Alle drei sind mit behoben.
|
||
>
|
||
> Und ein pyscript-Fallstrick ist dabei aufgefallen und im Code vermerkt: **Generatorausdrücke sind
|
||
> nicht implementiert** (`not implemented ast ast_generatorexp`), Mengen-, Listen- und
|
||
> Dict-Comprehensions dagegen schon.
|
||
|
||
---
|
||
|
||
## 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.
|