Setup: Erwartungswert je Listenposition, gruen auch dort (2026.9.1.15)
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 und 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. Typografie: .setup-feld-hinweis ist fuer die Kopfzeile gebaut (14px, --fg, rechtsbuendig, max-width 55%). Im 12,5px-Positionslabel wirkt das falsch herum. Eine Regel im Kontext .setup-unterfeld-label .setup-feld-hinweis laesst Groesse und Farbe erben; die Rechtsbuendigkeit kommt aus justify-content: space-between am Label, wie eine Ebene darueber bei .setup-feld-kopf. Verifiziert: alle acht Positionen tragen ihren eigenen Beispielnamen, py_compile und Panel als Modul sauber, audi_ha_test ohne Fehler gestartet. Die Darstellung selbst habe ich nicht im Browser gesehen - das Panel liess sich in der Testinstanz nicht ansteuern. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -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:
|
||||
|
||||
@@ -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.",
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"version":"2026.9.1.14","sha256":"f1fa3a91435bfc80f3f4245e52c488e3487fe12e5031349e1d7d20ca757d4b7d","bytes":265727,"gebaut":"2026-09-01T16:47:50Z"}
|
||||
{"version":"2026.9.1.15","sha256":"c7eda6e1a85b2d4295b0bd21383b66895dfb217a5a788a6ccf92acee467cad4c","bytes":265741,"gebaut":"2026-09-01T16:59:16Z"}
|
||||
Binary file not shown.
@@ -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
|
||||
? `<span class="setup-feld-hinweis">(z. B. <span class="setup-feld-einheit">${esc(name)}</span>)</span>`
|
||||
: "";
|
||||
}
|
||||
|
||||
/* 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 `<div class="entitaet-leer">Keine passende Entität gefunden</div>`;
|
||||
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 `<div class="entitaet-combo">
|
||||
<span class="entitaet-combo-icon">${LUPE_SVG}</span>
|
||||
<input type="text" class="entitaet-combo-input${treffer ? " passend" : ""}" autocomplete="off" spellcheck="false"
|
||||
@@ -4570,12 +4600,13 @@ function setupFeldzeile(feld) {
|
||||
|
||||
Listenfelder bekommen es ebenfalls: dort ist der Name der ersten
|
||||
Position das Muster, nach dem sich die anderen drei richten. */
|
||||
const erwartet = feld.beispiel || "";
|
||||
// Bei Listenfeldern steht das Beispiel NICHT im Kopf, sondern an jeder
|
||||
// Position - siehe unten. Ein einzelner Name im Kopf beschriebe nur die
|
||||
// erste der vier und liesse die anderen drei ohne Erwartungswert dastehen.
|
||||
const erwartet = feld.liste ? "" : feld.beispiel || "";
|
||||
// Der Klammertext in Label-Größe/-Farbe, der Sensorname darin in derselben
|
||||
// kleinen/grauen Schrift wie die Einheit ("[on/off]").
|
||||
const hinweis = erwartet
|
||||
? `<span class="setup-feld-hinweis">(z. B. <span class="setup-feld-einheit">${esc(erwartet)}</span>)</span>`
|
||||
: "";
|
||||
const hinweis = beispielHinweis(erwartet);
|
||||
const kopf = `<div class="setup-feld-kopf">
|
||||
<span class="setup-feld-label">${esc(feld.label)}${einheit ? ` <span class="setup-feld-einheit">[${esc(einheit)}]</span>` : ""}</span>
|
||||
${hinweis}
|
||||
@@ -4585,7 +4616,7 @@ function setupFeldzeile(feld) {
|
||||
<div class="setup-unterfelder">
|
||||
${feld.positionen.map((pos, i) => `
|
||||
<div class="setup-unterfeld">
|
||||
<span class="setup-unterfeld-label">${esc(pos)}</span>
|
||||
<span class="setup-unterfeld-label">${esc(pos)}${beispielHinweis(feldBeispiel(feld, i))}</span>
|
||||
${entitaetCombo(feld.key, i)}
|
||||
${entitaetStatusWarnung((setupZuordnung[feld.key] || [])[i])}
|
||||
</div>`).join("")}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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"],
|
||||
|
||||
Reference in New Issue
Block a user