Setup-Menue: Sensorkennung ohne installationsspezifisches Praefix, Einheit statt Live-Wert

Korrektur zur letzten Aenderung, vom Nutzer live erkannt:
- "fmm003_" war hart einprogrammiert und liess trotzdem noch
  installationsspezifisches Rauschen stehen (Geraete-Slug, Instanzname der
  Integration). Jetzt wird das laengste gemeinsame Praefix ueber alle
  aktuell zugeordneten Sensoren berechnet (setupGemeinsamesPraefix()) -
  nichts mehr hartkodiert. Faellt bei einer einzelnen Entitaet aus
  anderer Quelle korrekt auf die volle ID zurueck, statt falsch zu kuerzen
  (live bestaetigt: TANK_DISTANZ_SENSOR zeigte den vollen Namen, weil er
  auf eine andere Integration zeigte).
- Der Live-Wert des Sensors gehoert nicht mehr neben die ID - stattdessen
  zeigt das Label selbst jetzt die ERWARTETE Art des Werts an
  ("Tankfuellstand [%]", "12V-Batteriespannung [V]"), statisch aus dem
  FELDER-Katalog abgeleitet, unabhaengig von einer aktuellen Zuordnung.

Version 2026.8.28.5, live im Testcontainer verifiziert (acht echte
Setup-Zeilen gegen die Nutzerbeispiele geprueft).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-28 10:45:45 +02:00
parent b1cd03be51
commit af64fc39e3
4 changed files with 132 additions and 66 deletions
@@ -4061,40 +4061,77 @@ function sheetMarkup() {
/* ------------------------------------------------------------ Setup-Popup */
const LUPE_SVG = `<svg viewBox="0 0 20 20" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"><circle cx="8.5" cy="8.5" r="6"/><path d="m17 17-4.3-4.3"/></svg>`;
/* Nur der Teil der Entity-ID nach "fmm003_" - die tatsächliche, technische
Kennung des zugeordneten Sensors, kürzer und aussagekräftiger als der
volle "binary_sensor.testcar_b9_fmm003_..."-Pfad. Ohne "fmm003_" im Namen
(z. B. eine andere Marke/Integration) bleibt der Domain-freie Rest
stehen, statt nichts anzuzeigen. */
/* Das gemeinsame Präfix aller aktuell zugeordneten Sensoren (domain-frei),
bis zum letzten gemeinsamen "_" - z. B. "testcar_b9_fmm003_testintegratoin_".
NICHT hart auf "fmm003_" verdrahtet: sowohl der Geräte-Slug
("testcar_b9") als auch der Instanzname der Integration
("testintegratoin") sind installationsspezifisch, vom Nutzer beim
Einrichten seines eigenen flespi-Kanals selbst vergeben - bei ihm heißt
das anders. Nur was WIRKLICH von allen zugeordneten Sensoren geteilt
wird, ist reines Rauschen; alles danach ist die eigentliche, stabile
Signalbezeichnung. Mit weniger als zwei zugeordneten Sensoren (nichts zum
Vergleichen) oder wenn Sensoren aus zwei erkennbar verschiedenen Quellen
kommen (kein gemeinsames Präfix), liefert das null - dann zeigt
entitaetIdKurz() lieber die volle, ungekürzte ID als eine geratene,
möglicherweise falsche Kürzung. */
function setupGemeinsamesPraefix() {
const ids = [];
for (const feld of setupKatalog()) {
const wert = setupZuordnung[feld.key];
if (feld.liste) { for (const w of (wert || [])) if (w) ids.push(w); }
else if (wert) ids.push(wert);
}
const ohneDomain = ids.map((id) => id.includes(".") ? id.split(".").slice(1).join(".") : id);
if (ohneDomain.length < 2) return null;
let praefix = ohneDomain[0];
for (const s of ohneDomain.slice(1)) {
let i = 0;
while (i < praefix.length && i < s.length && praefix[i].toLowerCase() === s[i].toLowerCase()) i++;
praefix = praefix.slice(0, i);
if (!praefix) return null;
}
const idxUnter = praefix.lastIndexOf("_");
return idxUnter > 0 ? praefix.slice(0, idxUnter + 1) : null;
}
/* Die Entity-ID ohne Domain und ohne das gemeinsame, installationsspezifische
Präfix (siehe setupGemeinsamesPraefix()) - die tatsächliche, stabile
Kennung des zugeordneten Sensors, unabhängig davon, wie Geräte-Slug und
Integrationsinstanz beim jeweiligen Nutzer heißen. Passt das gemeinsame
Präfix nicht auf DIESE Entität (z. B. eine einzelne Entität aus einer
anderen Quelle als der Rest), bleibt die volle domain-freie ID stehen. */
function entitaetIdKurz(entityId) {
if (!entityId) return null;
const ohneDomain = entityId.includes(".") ? entityId.split(".").slice(1).join(".") : entityId;
const idx = ohneDomain.toLowerCase().indexOf("fmm003_");
return idx >= 0 ? ohneDomain.slice(idx + "fmm003_".length) : ohneDomain;
const praefix = setupGemeinsamesPraefix();
if (praefix && ohneDomain.toLowerCase().startsWith(praefix.toLowerCase())) {
return ohneDomain.slice(praefix.length);
}
return ohneDomain;
}
/* Aktueller Wert + Einheit einer Entität, oder null ohne brauchbaren
Zustand (nicht zugeordnet, unavailable/unknown) - dieselbe Zustandslogik
wie in entitaetZeilenMarkup() unten, hier für eine einzelne Entität statt
einer ganzen Kandidatenliste. */
function entitaetWertKurz(entityId) {
if (!entityId || !HASS.states[entityId]) return null;
const zustand = HASS.states[entityId].state;
if (zustand === "unavailable" || zustand === "unknown") return null;
const einheit = HASS.states[entityId].attributes && HASS.states[entityId].attributes.unit_of_measurement;
return `${zustand}${einheit ? " " + einheit : ""}`;
}
/* Ersetzt den bisherigen statischen Beschreibungstext im Setup ("on = Fahrt
läuft", "Optional, vom CAN...") - Nutzerwunsch: statt einer generischen
Erklärung zeigt die Kopfzeile jetzt die Kennung UND die aktuelle Meldung
des tatsächlich zugeordneten Sensors, direkt neben der Feld-Überschrift.
Ohne Zuordnung (leer) gibt es nichts zu zeigen. */
function setupErwarteterSensor(entityId) {
const kurz = entitaetIdKurz(entityId);
if (!kurz) return "";
const wert = entitaetWertKurz(entityId);
return wert != null ? `${kurz} · ${wert}` : kurz;
/* Die Art des erwarteten Werts, als kurzes Klammer-Etikett direkt neben der
Feld-Überschrift ("Tankfüllstand [%]", "12V-Batteriespannung [V]") - eine
feste Eigenschaft der FELD-ROLLE selbst (aus dem FELDER-Katalog,
einstellungen.py), unabhängig davon, ob und welcher Sensor gerade
zugeordnet ist. Bewusst NICHT der Live-Wert eines Sensors - der gehört
nirgends mehr hin, siehe entitaetIdKurz()'s eigenen Kommentar zur
Kopfzeile. binary_sensor liefert immer den Rohzustand "on"/"off"
(unabhängig von device_class - die beeinflusst nur, wie ANDERE
HA-Oberflächen ihn anzeigen, nicht den Rohwert, den diese App liest).
Bei mehreren möglichen Einheiten (z. B. "L"/"l") die klein geschriebene
Variante bevorzugt, sonst die erste genannte. Ohne passenden Fall (Knopf,
GPS-Koordinate) kein Etikett. */
function feldEinheitAnzeige(feld) {
if (feld.domains && feld.domains.includes("binary_sensor")) return "on/off";
if (feld.domains && feld.domains.includes("button")) return null;
if (feld.units && feld.units.length) {
return feld.units.find((u) => u === u.toLowerCase() && u !== u.toUpperCase()) || feld.units[0];
}
if (feld.device_classes && (feld.device_classes.includes("date") || feld.device_classes.includes("timestamp"))) {
return "Datum";
}
return null;
}
function entitaetZeilenMarkup(feldId, key, suchtext, aktuellerWert) {
@@ -4133,11 +4170,14 @@ function entitaetCombo(key, idx) {
function setupFeldzeile(feld) {
// Bei einem Listenfeld (vier Positionen wie Tür-/Fenstersensoren) gibt es
// keinen EINEN zugeordneten Sensor für die Kopfzeile - jede Position hat
// ihre eigene Zuordnung, siehe die Unterfelder unten.
const erwartet = feld.liste ? "" : setupErwarteterSensor(setupZuordnung[feld.key]);
// keinen EINEN zugeordneten Sensor, dessen Kennung sich anzeigen ließe -
// jede Position hat ihre eigene Zuordnung, siehe die Unterfelder unten.
// Das Einheiten-Etikett neben dem Label gilt dagegen für die ganze Rolle
// und wird auch dort gezeigt.
const einheit = feldEinheitAnzeige(feld);
const erwartet = feld.liste ? "" : entitaetIdKurz(setupZuordnung[feld.key]);
const kopf = `<div class="setup-feld-kopf">
<span class="setup-feld-label">${esc(feld.label)}</span>
<span class="setup-feld-label">${esc(feld.label)}${einheit ? ` <span class="setup-feld-einheit">[${esc(einheit)}]</span>` : ""}</span>
${erwartet ? `<span class="setup-feld-hinweis">${esc(erwartet)}</span>` : ""}
</div>`;
if (feld.liste) {
@@ -1255,12 +1255,14 @@ button.leaf:active { background: var(--tile-2); }
.setup-gruppe-titel { font-size: 11px; letter-spacing: .1em; text-transform: uppercase; color: var(--fg3); margin-bottom: 6px; }
.setup-feldzeile { padding: 12px 0; border-bottom: 1px solid var(--line); }
.setup-feldzeile:last-child { border-bottom: none; }
/* Nutzerwunsch: der zugeordnete Sensor (Kennung + aktueller Wert, siehe
setupErwarteterSensor() in audi-dashboard-app.js) steht NEBEN der
Feld-Überschrift, nicht mehr wie die frühere statische Beschreibung
darunter - deshalb Zeile statt Spalte. */
/* Nutzerwunsch: die Kennung des zugeordneten Sensors (entitaetIdKurz() in
audi-dashboard-app.js) steht NEBEN der Feld-Überschrift, nicht mehr wie
die frühere statische Beschreibung darunter - deshalb Zeile statt Spalte.
Die erwartete Einheit (feldEinheitAnzeige()) hängt direkt am Label selbst
("Tankfüllstand [%]"), losgelöst davon, ob/welcher Sensor zugeordnet ist. */
.setup-feld-kopf { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; margin-bottom: 8px; }
.setup-feld-label { font-size: 14.5px; color: var(--fg); flex: 0 1 auto; }
.setup-feld-einheit { color: var(--fg3); font-size: 12.5px; }
.setup-feld-hinweis {
font-size: 12.5px; color: var(--fg2); line-height: 1.4; text-align: right;
white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 55%;
@@ -1,7 +1,7 @@
{
"domain": "audi_dashboard",
"name": "Audi Dashboard",
"version": "2026.8.28.4",
"version": "2026.8.28.5",
"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"],