Setup-Menü: Sensorkennung per Mehrheitsentscheid statt nächstem Nachbarn; Ellipsis entfernt; Filter/Tanken-Fixes
- entitaetIdKurz(): Präfix per Stimmenmehrheit über alle zugeordneten Sensoren statt des einzelnen nächsten Nachbarn - verhindert Über-Kürzung durch zufällig geteilte Namensteile zwischen verwandten Feldern (can_fuel_volume->fuel_volume, oil_change_due->due waren falsch). - .setup-feld-hinweis: Ellipsis-Kürzung entfernt, voller Sensorname sichtbar. - entitaetKandidaten(): "Nur passende Sensoren anzeigen" filtert jetzt auch nach device_class für Datum/Timestamp-Felder, nicht nur nach Domain/Einheit. - tankFelder(): Kilometerstand/Getankte Liter in .mitEinheit gewrappt (wie alle anderen km/l-Felder im Rest der App). - distanzVorschlag(): negative Vorschläge (fehlerhafte km-Basis eines vorherigen Tankvorgangs) werden nicht mehr angezeigt. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -2759,7 +2759,15 @@ function entitaetKandidaten(feldKey, suchtext, aktuellerWert) {
|
||||
if (e.id === aktuellerWert) return true;
|
||||
if (setupNurPassend) {
|
||||
if (feld.domains && feld.domains.length && !feld.domains.includes(e.domain)) return false;
|
||||
if (feld.units && feld.units.length && !feld.units.includes(e.unit)) return false;
|
||||
if (feld.units && feld.units.length) {
|
||||
if (!feld.units.includes(e.unit)) return false;
|
||||
} else if (feld.device_classes && (feld.device_classes.includes("date") || feld.device_classes.includes("timestamp"))) {
|
||||
// Kein Einheiten-Feld, aber "Datum" ist der angezeigte Output
|
||||
// (feldEinheitAnzeige()) - dieselbe Bedingung hier gespiegelt, damit
|
||||
// "Nur passende Sensoren anzeigen" wirklich nur Sensoren mit
|
||||
// passendem Output zeigt, nicht jeden beliebigen sensor.*.
|
||||
if (e.deviceClass !== "date" && e.deviceClass !== "timestamp") return false;
|
||||
}
|
||||
}
|
||||
if (text && !(e.id.toLowerCase().includes(text) || e.name.toLowerCase().includes(text))) return false;
|
||||
return true;
|
||||
@@ -3517,7 +3525,13 @@ function distanzVorschlag(aktuellerKm) {
|
||||
if (aktuellerKm === "" || aktuellerKm == null || !FILLS.length) return "";
|
||||
const letzte = FILLS.reduce((a, b) => (new Date(b.ts) > new Date(a.ts) ? b : a));
|
||||
if (letzte.odometer_km == null) return "";
|
||||
return Math.round((aktuellerKm - letzte.odometer_km) * 10) / 10;
|
||||
const distanz = Math.round((aktuellerKm - letzte.odometer_km) * 10) / 10;
|
||||
// Ein negativer Wert ist nie eine gefahrene Distanz - kann bei einer
|
||||
// fehlerhaft/verzögert erfassten Kilometerstand-Basis des letzten
|
||||
// Tankvorgangs vorkommen (z. B. ein "auto" erkannter Vorgang, dessen
|
||||
// km-Basis über einen späteren, korrigierten/niedrigeren Kilometerstand
|
||||
// hinausragt). Lieber kein Vorschlag als ein irreführender negativer.
|
||||
return distanz < 0 ? "" : distanz;
|
||||
}
|
||||
|
||||
function tankFelder(praefix, f) {
|
||||
@@ -3541,12 +3555,14 @@ function tankFelder(praefix, f) {
|
||||
return `
|
||||
<div class="feld"><label>Datum</label><input type="date" id="${praefix}Datum" value="${datum}"></div>
|
||||
<div class="feld"><label>Uhrzeit</label><input type="time" id="${praefix}Zeit" value="${zeit}"></div>
|
||||
<div class="feld"><label>Kilometerstand</label><input type="number" id="${praefix}Km" value="${km}"></div>
|
||||
<div class="feld"><label>Kilometerstand</label>
|
||||
<span class="mitEinheit"><input type="number" id="${praefix}Km" value="${km}"><span>km</span></span></div>
|
||||
<div class="feld"><label>Gefahrene Distanz</label>
|
||||
<span class="mitEinheit"><input type="number" step="1" id="${praefix}Distanz" value="${distanz}" placeholder="0"><span>km</span></span></div>
|
||||
<div class="feld"><label>Kraftstoff</label>
|
||||
<select id="${praefix}Kraftstoff">${KRAFTSTOFFSORTEN.map((k) => `<option ${k === kraftstoff ? "selected" : ""}>${k}</option>`).join("")}</select></div>
|
||||
<div class="feld"><label>Getankte Liter</label><input type="number" step="0.01" id="${praefix}Liter" data-tankpreisfeld="${praefix}" value="${liter}" placeholder="0,00"></div>
|
||||
<div class="feld"><label>Getankte Liter</label>
|
||||
<span class="mitEinheit"><input type="number" step="0.01" id="${praefix}Liter" data-tankpreisfeld="${praefix}" value="${liter}" placeholder="0,00"><span>l</span></span></div>
|
||||
<div class="feld"><label>Kosten (real, nach Rabatt)</label>
|
||||
<span class="mitEinheit"><input type="number" step="0.01" id="${praefix}Kosten" data-tankpreisfeld="${praefix}" value="${kosten}" placeholder="0,00"><span>€</span></span></div>
|
||||
${CAR.smartdeal.aktiv ? `<div class="feld"><label>SmartDeal-Ersparnis</label>
|
||||
@@ -4082,35 +4098,47 @@ function setupAndereIdsOhneDomain(ausser) {
|
||||
return ids.map((id) => id.includes(".") ? id.split(".").slice(1).join(".") : id);
|
||||
}
|
||||
|
||||
/* Die Entity-ID ohne Domain und ohne das installationsspezifische Präfix,
|
||||
das sie mit ihrem NÄCHSTEN Verwandten unter den übrigen zugeordneten
|
||||
Sensoren teilt (dem, mit dem sie das längste gemeinsame Präfix hat) - die
|
||||
tatsächliche, stabile Kennung des zugeordneten Sensors, unabhängig davon,
|
||||
wie Geräte-Slug und Integrationsinstanz beim jeweiligen Nutzer heißen
|
||||
(z. B. "testcar_b9_fmm003_testintegratoin_" oder "audi_rs_4_avant_").
|
||||
/* Die Entity-ID ohne Domain und ohne das installationsspezifische Präfix -
|
||||
die tatsächliche, stabile Kennung des zugeordneten Sensors, unabhängig
|
||||
davon, wie Geräte-Slug und Integrationsinstanz beim jeweiligen Nutzer
|
||||
heißen (z. B. "testcar_b9_fmm003_testintegratoin_" oder
|
||||
"audi_rs_4_avant_").
|
||||
|
||||
Bewusst PRO ENTITÄT der beste Nachbar statt eines einzigen, für alle
|
||||
Felder gemeinsamen Präfixes (frühere Fassung) - eine reale Installation
|
||||
hat oft MEHRERE Sensorquellen gleichzeitig (hier: FMM003 für Fahrt-/
|
||||
Tank-/Batteriewerte, eine zweite Integration für Türen/Fenster/
|
||||
Service-Termine, per "Nur passende Sensoren anzeigen" beide gleichzeitig
|
||||
vorgeschlagen) - keine ist objektiv "die Mehrheit". Ein einziges globales
|
||||
Präfix (egal ob per fortlaufender Verengung oder per Mehrheitsentscheid)
|
||||
kann immer nur EINE Quelle richtig kürzen und zeigt die Sensoren der
|
||||
anderen ungekürzt - genau das hat der Nutzer live beobachtet
|
||||
("audi_rs_4_avant_" gewann die Abstimmung, alle FMM003-Felder blieben
|
||||
unangetastet). Mit dem nächsten Verwandten statt einem globalen Sieger
|
||||
kürzt jede Rolle unabhängig von den anderen richtig, egal wie viele
|
||||
verschiedene Quellen gleichzeitig im Spiel sind. Findet sich kein
|
||||
Verwandter mit gemeinsamem Präfix, bleibt die volle domain-freie ID
|
||||
stehen statt einer geratenen, möglicherweise falschen Kürzung. */
|
||||
Das Präfix ist NICHT das mit dem einzelnen nächsten Verwandten geteilte
|
||||
(frühere Fassung) - das kürzte in der Praxis zu viel: zwei Felder
|
||||
derselben Sensorquelle können selbst wieder ein gemeinsames Namens-
|
||||
Teilstück haben, das nichts mit der Installation zu tun hat (z. B. teilen
|
||||
sich "oil_change_due" und "oil_change_distance" das Wortstück
|
||||
"oil_change_", "can_fuel_volume" teilt sich "can_" mit einem anderen
|
||||
CAN-Sensor) - genau das hat der Nutzer live beobachtet: "can_fuel_volume"
|
||||
wurde zu bloß "fuel_volume", "oil_change_due" zu bloß "due". Stattdessen
|
||||
zählt jedes Präfix, das eine Entität mit irgendeiner ANDEREN teilt, als
|
||||
eine Stimme; das Präfix mit den MEISTEN Stimmen gewinnt. Das echte
|
||||
Installationspräfix teilt sich die Entität mit fast allen anderen
|
||||
Sensoren ihrer Quelle (viele Stimmen), ein zufällig geteiltes
|
||||
Namens-Teilstück nur mit dem einen verwandten Feld (eine Stimme) - die
|
||||
Mehrheit entscheidet also richtig, ohne einen einzelnen "nächsten"
|
||||
Nachbarn zu bevorzugen. Bei Gleichstand gewinnt das kürzere Präfix
|
||||
(vorsichtiger - weniger Kürzung im Zweifel). Mehrere gleichzeitige
|
||||
Sensorquellen (z. B. FMM003 und eine zweite, "audi_rs_4_avant_"-
|
||||
präfixte Integration) bleiben dabei weiterhin unabhängig voneinander
|
||||
korrekt gekürzt, da die Stimmen pro Entität und nicht global gezählt
|
||||
werden. Findet sich kein Verwandter mit gemeinsamem Präfix, bleibt die
|
||||
volle domain-freie ID stehen statt einer geratenen, möglicherweise
|
||||
falschen Kürzung. */
|
||||
function entitaetIdKurz(entityId) {
|
||||
if (!entityId) return null;
|
||||
const ohneDomain = entityId.includes(".") ? entityId.split(".").slice(1).join(".") : entityId;
|
||||
let bestesPraefix = null, besteLaenge = 0;
|
||||
const stimmen = new Map();
|
||||
for (const andere of setupAndereIdsOhneDomain(entityId)) {
|
||||
const kandidat = praefixPaar(ohneDomain, andere);
|
||||
if (kandidat && kandidat.length > besteLaenge) { bestesPraefix = kandidat; besteLaenge = kandidat.length; }
|
||||
if (!kandidat) continue;
|
||||
stimmen.set(kandidat, (stimmen.get(kandidat) || 0) + 1);
|
||||
}
|
||||
let bestesPraefix = null, besteStimmen = 0;
|
||||
for (const [kandidat, anzahl] of stimmen) {
|
||||
const besser = anzahl > besteStimmen || (anzahl === besteStimmen && bestesPraefix && kandidat.length < bestesPraefix.length);
|
||||
if (besser) { bestesPraefix = kandidat; besteStimmen = anzahl; }
|
||||
}
|
||||
return bestesPraefix ? ohneDomain.slice(bestesPraefix.length) : ohneDomain;
|
||||
}
|
||||
|
||||
@@ -1265,7 +1265,7 @@ button.leaf:active { background: var(--tile-2); }
|
||||
.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%;
|
||||
max-width: 55%;
|
||||
}
|
||||
.setup-unterfelder { display: flex; flex-direction: column; gap: 12px; }
|
||||
.setup-unterfeld { display: flex; flex-direction: column; gap: 4px; }
|
||||
|
||||
Reference in New Issue
Block a user