diff --git a/AGENTS.md b/AGENTS.md index 8fa4873..0fc4711 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,6 +1,7 @@ # AGENTS.md — Project state, review findings, open items, and working rules -**Last updated: 2026-09-01** (Rueckblick ohne Nullfahrten, Streckenwahl gemeinsam in `verlauf.py`, +**Last updated: 2026-09-01** (Setup: gruene Bestaetigung und Erwartungswert je Listenposition, +`2026.9.1.15`, Abschnitt BG. Davor: Rueckblick ohne Nullfahrten, Streckenwahl gemeinsam in `verlauf.py`, `2026.9.1.14`, Abschnitt BF. Davor: Fahrtstrecke auf 100 m: CAN als Anker, GNSS als Nachkommastelle, `2026.9.1.10`, Abschnitt BE. Davor: Nachlauf-Abzug nur mit zugeordnetem `TRIP_SENSOR`, `2026.9.1.9`; davor „502" beim Neustart entschärft, OTA-Bündel auf `2026.9.1.8` @@ -6879,6 +6880,45 @@ weglaesst. innerhalb einer einzigen langen `trip_status`-Phase. Nachweisbar bleibt es an den 13 Faellen; live zeigt es sich bei der naechsten kurzen Fahrt. +## BG. Setup: gruene Bestaetigung, Erwartungswert je Position (2026.9.1.11–.15) + +Zwei Wuensche des Eigentuemers vom 01.09.2026, die zusammengehoeren. + +### Gruen, wenn die Zuordnung zum Beispielnamen passt + +Enthaelt die zugeordnete Entitaet den Beispielnamen der Rolle, faerbt sich das Feld leicht gruen. +Dieselbe Pruefung, die `entitaetScore()` ohnehin mit 8 gewichtet - hier nur fuers Auge, damit man +eine richtig belegte Rolle sieht, ohne den langen Entity-Namen Zeichen fuer Zeichen mit dem Beispiel +daneben zu vergleichen. + +Bewusst **nur ein Hinweis, keine Bedingung**: Installationen mit anderer Datenquelle haben andere +Namen und sind trotzdem richtig zugeordnet. Deshalb gruen als Bestaetigung, aber kein Rot und keine +Warnung, wenn es fehlt. Und nicht waehrend gesucht wird - dann steht die Sucheingabe im Feld, nicht +die Zuordnung. Die Farbe kommt per `color-mix` aus dem vorhandenen `--ok`-Ton und dem Feldgrund +statt aus einem eigenen Gruen, damit sie in beiden Themen ruhig bleibt. + +`„Auf Standard zuruecksetzen"` ist im selben Zug entfallen - Knopf, Symbol, Zuhoerer, CSS und der +nur dafuer vorhandene Helfer `setupStandardwert()`. + +### Listenfelder brauchen vier Beispiele, nicht eines + +Tuer- und Fenstersensoren haben vier Positionen, aber nur **einen** Beispielnamen +(`front_left_door`). Der beschreibt die erste; die anderen drei koennen ihn nie enthalten. Folge: +nur die erste Position konnte gruen werden, und im Kopf stand ein Erwartungswert, der fuer drei von +vier Zeilen nicht galt. + +Neu: `"beispiele"` je Position im Feld-Katalog, `feldBeispiel(feld, idx)` im Panel. Der +Erwartungswert steht jetzt **an jeder Position** statt im Kopf - rechtsbuendig, in der kleinen grauen +Schrift des Positionslabels. Auch die Sortierung der Vorschlagsliste nutzt ihn, sonst stuende in +allen vier Zeilen dieselbe Entitaet oben. + +**Merkposten zur Typografie:** `.setup-feld-hinweis` ist fuer die Kopfzeile gebaut (14px, `--fg`, +rechtsbuendig, `max-width: 55%`). Im 12,5px-Positionslabel wirkt das falsch herum - groesser und +dunkler als die Zeile, in der es steht. Eine eigene Regel im Kontext +`.setup-unterfeld-label .setup-feld-hinweis` laesst es Groesse und Farbe erben; die Rechtsbuendigkeit +kommt aus `justify-content: space-between` am Label, wie eine Ebene darueber bei +`.setup-feld-kopf`. + ## Working conventions (observed — keep them) - German is the project language: identifiers, comments, commits, UI texts. Exceptions: diff --git a/custom_components/audi_dashboard/einstellungen.py b/custom_components/audi_dashboard/einstellungen.py index f848b66..afa5d73 100644 --- a/custom_components/audi_dashboard/einstellungen.py +++ b/custom_components/audi_dashboard/einstellungen.py @@ -293,11 +293,26 @@ FELDER: list[dict] = [ "hinweis": "\"aus\"/off = zu. Für \"Sicher abgestellt\" wichtig.", "domains": ["binary_sensor"], "device_classes": ["door"], "units": [], "liste": True, "positionen": POSITIONEN, "pflicht": False, "beispiel": "front_left_door", + # Ein Beispielname je Position. "beispiel" allein beschreibt nur die + # erste; die anderen drei koennen "front_left_door" nie enthalten und + # standen deshalb ohne Erwartungswert da. + "beispiele": [ + "front_left_door", + "front_right_door", + "rear_left_door", + "rear_right_door", + ], "stichworte": ["tür", "door"]}, {"key": "FENSTER_SENSOREN", "label": "Fenster", "gruppe": "sicherheit", "hinweis": "\"aus\"/off = zu.", "domains": ["binary_sensor"], "device_classes": ["window"], "units": [], "liste": True, "positionen": POSITIONEN, "pflicht": False, "beispiel": "front_left_window", + "beispiele": [ + "front_left_window", + "front_right_window", + "rear_left_window", + "rear_right_window", + ], "stichworte": ["fenster", "window"]}, {"key": "HECKKLAPPE_SENSOR", "label": "Heckklappe", "gruppe": "sicherheit", "hinweis": "\"aus\"/off = zu.", diff --git a/custom_components/audi_dashboard/frontend/app/bundle.json b/custom_components/audi_dashboard/frontend/app/bundle.json index e73bdd1..09eda17 100644 --- a/custom_components/audi_dashboard/frontend/app/bundle.json +++ b/custom_components/audi_dashboard/frontend/app/bundle.json @@ -1 +1 @@ -{"version":"2026.9.1.14","sha256":"f1fa3a91435bfc80f3f4245e52c488e3487fe12e5031349e1d7d20ca757d4b7d","bytes":265727,"gebaut":"2026-09-01T16:47:50Z"} \ No newline at end of file +{"version":"2026.9.1.15","sha256":"c7eda6e1a85b2d4295b0bd21383b66895dfb217a5a788a6ccf92acee467cad4c","bytes":265741,"gebaut":"2026-09-01T16:59:16Z"} \ No newline at end of file diff --git a/custom_components/audi_dashboard/frontend/app/bundle.zip b/custom_components/audi_dashboard/frontend/app/bundle.zip index c0a7d63..279bfc1 100644 Binary files a/custom_components/audi_dashboard/frontend/app/bundle.zip and b/custom_components/audi_dashboard/frontend/app/bundle.zip differ diff --git a/custom_components/audi_dashboard/frontend/audi-dashboard-app.js b/custom_components/audi_dashboard/frontend/audi-dashboard-app.js index 0c33259..71b65d6 100644 --- a/custom_components/audi_dashboard/frontend/audi-dashboard-app.js +++ b/custom_components/audi_dashboard/frontend/audi-dashboard-app.js @@ -3044,7 +3044,7 @@ function entitaetName(id) { Domain/Einheit/Device-Class sind Zusatzpunkte fürs Sortieren, wenn der Schalter "Nur passende Sensoren" aus ist (dann filtern sie nicht hart, siehe entitaetKandidaten()). */ -function entitaetScore(feld, e, suchtext) { +function entitaetScore(feld, e, suchtext, idx) { let score = 0; const hay = (e.id + " " + e.name).toLowerCase(); for (const wort of feld.stichworte || []) if (hay.includes(wort)) score += 5; @@ -3054,12 +3054,15 @@ function entitaetScore(feld, e, suchtext) { // Der Signalname aus dem Katalog ("z. B. can_fuel_volume") ist der // treffsicherste Hinweis, den es gibt - deutlich mehr wert als ein // einzelnes Stichwort. - if (feld.beispiel && hay.includes(feld.beispiel.toLowerCase())) score += 8; + // Bei Listenfeldern der Name der jeweiligen Position, nicht der der ersten - + // sonst stuende in allen vier Zeilen dieselbe Entitaet oben. + const beispiel = feldBeispiel(feld, idx); + if (beispiel && hay.includes(beispiel.toLowerCase())) score += 8; if (suchtext && hay.includes(suchtext.trim().toLowerCase())) score += 10; return score; } -function entitaetKandidaten(feldKey, suchtext, aktuellerWert) { +function entitaetKandidaten(feldKey, suchtext, aktuellerWert, idx) { const feld = setupKatalog().find((f) => f.key === feldKey); if (!feld) return []; const text = (suchtext || "").trim().toLowerCase(); @@ -3101,7 +3104,7 @@ function entitaetKandidaten(feldKey, suchtext, aktuellerWert) { ); if (genau.length) liste = genau; } - liste.sort((a, b) => entitaetScore(feld, b, suchtext) - entitaetScore(feld, a, suchtext)); + liste.sort((a, b) => entitaetScore(feld, b, suchtext, idx) - entitaetScore(feld, a, suchtext, idx)); return liste.slice(0, 60); } @@ -3192,11 +3195,34 @@ function setupSchliessen() { anderer Datenquelle, deren Namen nicht passen und die trotzdem richtig zugeordnet sind. Deshalb grün als Bestätigung, aber kein Rot und keine Warnung, wenn es fehlt. */ -function entitaetPasstZumBeispiel(key, wert) { +function entitaetPasstZumBeispiel(key, idx, wert) { if (!wert) return false; - const feld = setupKatalog().find((f) => f.key === key); - if (!feld || !feld.beispiel) return false; - return String(wert).toLowerCase().includes(String(feld.beispiel).toLowerCase()); + const beispiel = feldBeispiel(setupKatalog().find((f) => f.key === key), idx); + if (!beispiel) return false; + return String(wert).toLowerCase().includes(String(beispiel).toLowerCase()); +} + +/* Der Beispielname für eine bestimmte Position einer Rolle. + + Listenfelder (Tür- und Fenstersensoren, vier Positionen) haben je Position + einen eigenen Namen: die zweite Position kann "front_left_door" nie + enthalten. Ohne diese Unterscheidung stand nur bei der ersten Position ein + Erwartungswert, und nur sie konnte grün werden - vom Eigentümer beanstandet + am 01.09.2026. */ +function feldBeispiel(feld, idx) { + if (!feld) return null; + if (idx != null && Array.isArray(feld.beispiele) && feld.beispiele[idx]) { + return feld.beispiele[idx]; + } + return feld.beispiel || null; +} + +/* Der Klammertext "(z. B. …)" - im Kopf einer Rolle wie an einer + Listenposition derselbe Bau, damit beide gleich aussehen. */ +function beispielHinweis(name) { + return name + ? `(z. B. ${esc(name)})` + : ""; } /* Entity-IDs, die im Arbeitsstand mehr als einer Rolle zugeordnet sind. */ @@ -4513,7 +4539,11 @@ function feldEinheitAnzeige(feld) { } function entitaetZeilenMarkup(feldId, key, suchtext, aktuellerWert) { - const kandidaten = entitaetKandidaten(key, suchtext, aktuellerWert); + // Die Position steckt in der Feld-Kennung ("KEY:idx") - sie entscheidet, + // welcher Beispielname die Vorschlagsliste anfuehrt. + const teile = String(feldId).split(":"); + const idx = teile.length === 2 ? Number(teile[1]) : null; + const kandidaten = entitaetKandidaten(key, suchtext, aktuellerWert, idx); if (!kandidaten.length) return `
Keine passende Entität gefunden
`; return kandidaten.map((e) => { const zustand = HASS.states[e.id] ? HASS.states[e.id].state : null; @@ -4536,7 +4566,7 @@ function entitaetCombo(key, idx) { // Waehrend gesucht wird nicht gruen faerben - der Text im Feld ist dann // die Sucheingabe und nicht die Zuordnung, die Faerbung wuerde ihm // widersprechen. - const treffer = !offen && entitaetPasstZumBeispiel(key, wert); + const treffer = !offen && entitaetPasstZumBeispiel(key, idx, wert); return `
${LUPE_SVG} (z. B. ${esc(erwartet)})` - : ""; + const hinweis = beispielHinweis(erwartet); const kopf = `
${esc(feld.label)}${einheit ? ` [${esc(einheit)}]` : ""} ${hinweis} @@ -4585,7 +4616,7 @@ function setupFeldzeile(feld) {
${feld.positionen.map((pos, i) => `
- ${esc(pos)} + ${esc(pos)}${beispielHinweis(feldBeispiel(feld, i))} ${entitaetCombo(feld.key, i)} ${entitaetStatusWarnung((setupZuordnung[feld.key] || [])[i])}
`).join("")} diff --git a/custom_components/audi_dashboard/frontend/audi-dashboard.css b/custom_components/audi_dashboard/frontend/audi-dashboard.css index 23c3311..803546c 100644 --- a/custom_components/audi_dashboard/frontend/audi-dashboard.css +++ b/custom_components/audi_dashboard/frontend/audi-dashboard.css @@ -1378,7 +1378,17 @@ img.carfix.klein { aspect-ratio: auto; height: auto; } } .setup-unterfelder { display: flex; flex-direction: column; gap: 12px; } .setup-unterfeld { display: flex; flex-direction: column; gap: 4px; } -.setup-unterfeld-label { font-size: 12.5px; color: var(--fg3); } +/* Positionsname links, Erwartungswert rechts - derselbe Bau wie + .setup-feld-kopf eine Ebene darueber, damit beide Zeilen dieselbe Kante + haben. Der Hinweis erbt hier die kleine graue Schrift des Labels; die + 14px/--fg-Form von .setup-feld-hinweis passt nur in die Kopfzeile. */ +.setup-unterfeld-label { + font-size: 12.5px; color: var(--fg3); + display: flex; align-items: baseline; justify-content: space-between; gap: 10px; +} +.setup-unterfeld-label .setup-feld-hinweis { + font-size: inherit; color: inherit; max-width: none; flex: 0 0 auto; +} .entitaet-combo { position: relative; } .entitaet-combo-icon { diff --git a/custom_components/audi_dashboard/manifest.json b/custom_components/audi_dashboard/manifest.json index e2d70d8..9b20cdb 100644 --- a/custom_components/audi_dashboard/manifest.json +++ b/custom_components/audi_dashboard/manifest.json @@ -1,7 +1,7 @@ { "domain": "audi_dashboard", "name": "Audi Dashboard", - "version": "2026.9.1.14", + "version": "2026.9.1.15", "documentation": "https://gitea.nothaft.cloud/paul/audi-app/src/branch/main/README.md", "issue_tracker": "https://gitea.nothaft.cloud/paul/audi-app/issues", "codeowners": ["@paul"],