Ein Update-Knopf, Modell als Auswahlfeld, abgestellt schliesst fahrend aus
- Die Update-Kachel hat genau einen Knopf am Ende. Er traegt in jedem Zustand den naechsten faelligen Schritt (suchen, installieren, Neustart, Neuladen); Beschriftung und Fuellung wechseln mit. Die Abschnitte darueber behalten ihre Werte und verlieren nur ihre Knoepfe. - Abstand unter der Trennlinie von 28 auf 16 px: das padding-top verhindert das Kollabieren des margin der Werteliste, also zaehlt jetzt nur noch das padding. - Modell ist in der App ein Auswahlfeld statt eines Textfelds, wie im Panel. Die Liste liegt als Zweitschrift in daten/fahrzeugmodelle.ts; fahrzeugmodelle.test.ts liest die Panel-Quelle ein und vergleicht sie Eintrag fuer Eintrag, damit die beiden nicht auseinanderlaufen. - Faehrt der Wagen, sagen Uebersicht und Sicherheitsseite das, statt "sicher abgestellt" zu behaupten. Die Zuendung meldet der Dongle in Sekunden, Tuer- und Schlossmeldungen kommen verzoegert - die schnellere Quelle hat Vorrang, weil sonst das Wort nicht stimmt. - tankerkennung: der Tiefststand wird vor dem Anlegen gesetzt. Ein gepufferter Schwung Datensaetze legte sonst denselben Tankvorgang zweimal an, weil der zweite Zustandswechsel waehrend des Wartens noch den alten Tiefststand las (04.09.2026, 29,8 l und 29,7 l). - flespi: nach dem Leeren des Zwischenspeichers wird nur abgeglichen, wenn ein Geraetewert vorliegt. Sonst ueberschrieb der Waechterfehler den frisch gelesenen Stand in der Kachel. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -678,4 +678,30 @@ async def jetzt_lesen(k: Koordinator) -> None:
|
||||
await k.flespi_stand_setzen(stand)
|
||||
# Ein frischer Stand kann eine Abweichung erst sichtbar machen - dann gehört
|
||||
# sie gleich behoben, statt bis zum nächsten Speichern zu warten.
|
||||
await wunsch_uebernehmen(k)
|
||||
#
|
||||
# ABER nur, wenn nach dem Leeren überhaupt schon ein Gerätewert
|
||||
# zurückgekommen ist. Schläft der Dongle, ist der Wert nicht abweichend,
|
||||
# sondern schlicht unbekannt - ein Schreibversuch scheitert dann am Schutz
|
||||
# in schlaf_timeout_schreiben() und ersetzte den eben gelesenen Stand durch
|
||||
# eine Fehlermeldung. Am 05.09.2026 genau so passiert: nach "Jetzt lesen"
|
||||
# stand in der Kachel nur noch "Der Schlafmodus des Geräts ist gerade
|
||||
# unbekannt", statt der Werte.
|
||||
if _schlafwert_bekannt(stand):
|
||||
await wunsch_uebernehmen(k)
|
||||
else:
|
||||
_LOGGER.debug(
|
||||
"Nach dem Leeren liegt noch kein Gerätewert vor - kein Abgleich,"
|
||||
" bis der Dongle sich meldet."
|
||||
)
|
||||
|
||||
|
||||
def _schlafwert_bekannt(stand: dict) -> bool:
|
||||
"""Ob der Anzeigestand einen Schlaf-Timeout vom Gerät kennt.
|
||||
|
||||
Ein ausstehender Wert (`offen`) zählt mit: er ist unterwegs, und das
|
||||
dazugehörige `mode`-Objekt liegt dann in flespi vor."""
|
||||
for zeile in stand.get("werte", []):
|
||||
if zeile.get("schluessel") != SCHLAF_SCHLUESSEL:
|
||||
continue
|
||||
return zeile.get("geraet") is not None or zeile.get("offen") is not None
|
||||
return False
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"version":"2026.9.5.34","sha256":"0de4c2af3534ef74c4bda98de122419e2f4d4c2741a175e73722d757344a3f6b","bytes":324629,"gebaut":"2026-09-05T14:40:28Z"}
|
||||
{"version":"2026.9.5.35","sha256":"8873fddf9a976ff3317fb16cf4ed708ac19ef76dbf8faf4ff29189e2a5f83a75","bytes":324134,"gebaut":"2026-09-05T15:01:50Z"}
|
||||
Binary file not shown.
@@ -2300,8 +2300,26 @@ function standAlterTicken() {
|
||||
|
||||
function vHome() {
|
||||
const g = CAR.gesichert;
|
||||
const statusText = g === null ? "Status unbekannt" : g ? "Sicher abgestellt" : "Nicht sicher abgestellt";
|
||||
const statusDot = g === null ? "warn" : g ? "" : "bad";
|
||||
/* Faehrt der Wagen, kann er nicht gleichzeitig "sicher abgestellt" sein -
|
||||
abgestellt und unterwegs schliessen einander aus (Vorgabe des
|
||||
Eigentuemers, 05.09.2026: "es kann nicht sein dass das fahrzeug sicher
|
||||
abgestellt ist und zeitgleich faehrt").
|
||||
|
||||
Die beiden Aussagen kommen aus verschiedenen Quellen: Tuer-, Fenster- und
|
||||
Schlossmeldungen liefert der EU Data Act mit spuerbarer Verzoegerung, die
|
||||
Zuendung meldet der Dongle in Sekunden. Die schnellere Quelle hat hier
|
||||
Vorrang - nicht weil die andere falsch waere (verriegelt ist der Wagen
|
||||
waehrend der Fahrt tatsaechlich), sondern weil das WORT "abgestellt" dann
|
||||
nicht stimmt.
|
||||
|
||||
Wortlaut wie im Standortmenue: "Zuendung an", nicht "faehrt" - einen
|
||||
Bewegungssensor gibt es nicht, die Zuendung steht auch im Stand mit
|
||||
laufendem Motor auf an. */
|
||||
const faehrt = standortZustand().faehrt;
|
||||
const statusText = faehrt
|
||||
? "Zündung an"
|
||||
: g === null ? "Status unbekannt" : g ? "Sicher abgestellt" : "Nicht sicher abgestellt";
|
||||
const statusDot = faehrt ? "" : g === null ? "warn" : g ? "" : "bad";
|
||||
const pct = CAR.tankPct;
|
||||
const t = naechsterTermin();
|
||||
/* C2/C5/D1: Reihenfolge der myAudi-App - randloses Fahrzeugbild, Name und
|
||||
@@ -2424,7 +2442,14 @@ function vSicherheit() {
|
||||
const tuerenKlappen = sicherheitsGruppe("tueren_klappen");
|
||||
const fensterDach = sicherheitsGruppe("fenster_dach");
|
||||
const licht = sicherheitsGruppe("licht");
|
||||
const sammelText = g === null ? "Zustand nicht vollständig bekannt" : g ? "Fahrzeug ist sicher abgestellt" : "Bitte prüfen";
|
||||
/* Dieselbe Regel wie in vHome(): unterwegs ist der Wagen nicht abgestellt.
|
||||
Die vier Sammelzeilen darunter bleiben stehen und zeigen weiter, was die
|
||||
Tuer-, Fenster- und Schlosssensoren melden - nur die Ueberschrift darf
|
||||
nicht "abgestellt" behaupten, waehrend die Zuendung an ist. */
|
||||
const faehrt = standortZustand().faehrt;
|
||||
const sammelText = faehrt
|
||||
? "Zündung an - Fahrzeug in Betrieb"
|
||||
: g === null ? "Zustand nicht vollständig bekannt" : g ? "Fahrzeug ist sicher abgestellt" : "Bitte prüfen";
|
||||
const zeile = (label, ok, labelBad, labelWarn, route) => {
|
||||
const text = ok === null ? labelWarn : ok ? label : labelBad;
|
||||
const klickbar = !!route;
|
||||
@@ -2439,7 +2464,7 @@ function vSicherheit() {
|
||||
return `
|
||||
<div class="szene bleed schmal"><div class="carbox">${bildMitPlatzhalter(bildAdresse("draufsicht.webp"), "draufsicht.webp", "Draufsicht", "carfix klein")}</div></div>
|
||||
<div class="tile" style="display:flex;align-items:center;gap:12px;padding:16px 20px">
|
||||
${statusKreis(g)}
|
||||
${faehrt ? '<span class="dot"></span>' : statusKreis(g)}
|
||||
<span style="font-size:15px;color:var(--fg)">${esc(sammelText)}</span>
|
||||
</div>
|
||||
<div class="tile sicherheitsliste">
|
||||
@@ -3559,6 +3584,36 @@ function dongleStand(w) {
|
||||
return tage >= 1 ? `bestätigt ${wann} (${tage} T. alt)` : `bestätigt ${wann}`;
|
||||
}
|
||||
|
||||
/* Der EINE Knopf der Update-Kachel. Er traegt in jedem Zustand den naechsten
|
||||
faelligen Schritt - suchen, installieren, Neustart, Neuladen - statt dass
|
||||
ueber dem Suchknopf noch ein zweiter Knopf im Abschnitt steht (Vorgabe des
|
||||
Eigentuemers, 05.09.2026: "warum nicht den update suchen button dafuer
|
||||
verwenden und nur die optik und schrift zur installation anpassen?").
|
||||
|
||||
Die Reihenfolge ist eine Rangfolge, keine Auswahl: liegt ein Neustart an,
|
||||
ist das der naechste Schritt, egal was sonst noch bereitliegt. Ein
|
||||
gleichzeitiges Integrations- UND App-Update gibt es dabei praktisch nicht -
|
||||
das Buendel wird erst angeboten, wenn es zur laufenden Serverfassung passt
|
||||
(buendelPasst), also nach der Integration. Das Panel kennt den App-Teil
|
||||
ohnehin nicht: es laedt seine Dateien bei jedem Aufruf frisch vom Server. */
|
||||
function updateKnopf() {
|
||||
const u = INTEGRATION_UPDATE;
|
||||
const laeuft = INTEGRATION_UPDATE_LAEUFT;
|
||||
const laufend = (text) => `<button class="aktion" style="margin-top:14px" disabled>
|
||||
<span style="display:inline-flex;align-items:center;gap:10px">
|
||||
<span class="lade-spinner" aria-hidden="true"></span>${esc(text)}</span></button>`;
|
||||
if (laeuft === "installieren") return laufend("Installiere …");
|
||||
if (laeuft === "neustart") return laufend("Home Assistant startet neu …");
|
||||
if (laeuft === "pruefen") return laufend("Prüfe …");
|
||||
const knopf = (text, aktion, primaer) =>
|
||||
`<button class="aktion${primaer ? " primaer" : ""}" style="margin-top:14px" data-update="${aktion}">${esc(text)}</button>`;
|
||||
if (u && u.installiert && u.neustart_noetig === false && String(CSS_VERSION) !== String(APP_VERSION))
|
||||
return knopf("Seite neu laden", "neuladen", true);
|
||||
if (u && u.installiert && u.neustart_noetig !== false)
|
||||
return knopf("Installation abschließen und neu starten", "neustart", true);
|
||||
if (u && u.verfuegbar) return knopf("Update installieren", "installieren", true);
|
||||
return knopf("Auf Update prüfen", "pruefen", false);
|
||||
}
|
||||
function vEinst() {
|
||||
return `
|
||||
<div class="tile"><span class="label">Fahrzeug einrichten</span>
|
||||
@@ -3761,12 +3816,12 @@ function vEinst() {
|
||||
if (u.neustart_noetig === false) {
|
||||
return `<span style="display:block;margin-top:8px;color:var(--fg2);font-size:13px;line-height:1.6">
|
||||
Version ${esc(u.version)} installiert - nur Oberflächendateien, kein Neustart nötig.</span>
|
||||
<button class="aktion primaer" style="margin-top:14px" data-update="neuladen">Seite neu laden</button>`;
|
||||
`;
|
||||
}
|
||||
return `<span style="display:block;margin-top:8px;color:var(--fg2);font-size:13px;line-height:1.6">
|
||||
Version ${esc(u.version)} installiert - die neue Fassung wird erst nach einem Neustart
|
||||
geladen.</span>
|
||||
<button class="aktion" style="margin-top:14px" data-update="neustart">Installation abschließen und neu starten</button>`;
|
||||
`;
|
||||
}
|
||||
if (u && u.verfuegbar) {
|
||||
/* Zeitstempel und ein zweiter Pruefknopf gehoeren hierher, nicht nur in
|
||||
@@ -3776,19 +3831,22 @@ function vEinst() {
|
||||
sie aufzufrischen, solange ueberhaupt ein Update angeboten wurde. */
|
||||
return `<dl class="rows"><div class="row" style="border-bottom:0"><dt>Verfügbare Version</dt>
|
||||
<dd>${esc(u.version)}${u.geprueft_am ? `<small>geprüft ${dezeitpunkt(new Date(u.geprueft_am))}</small>` : ""}</dd></div></dl>
|
||||
<button class="aktion primaer" style="margin-top:14px" data-update="installieren">Update installieren</button>`;
|
||||
`;
|
||||
}
|
||||
return u ? `<span class="standmarke">aktuell</span>` : "";
|
||||
})()}
|
||||
${INTEGRATION_UPDATE && INTEGRATION_UPDATE.fehler && !INTEGRATION_UPDATE_LAEUFT
|
||||
? `<span class="label" style="margin-top:10px;color:var(--red)">${esc(INTEGRATION_UPDATE.fehler)}</span>`
|
||||
: ""}
|
||||
<!-- Ein Suchknopf fuer die ganze Kachel, ganz unten - in JEDEM Zustand.
|
||||
Vorher sass er nur im Zweig "ist aktuell", und daneben brauchte es ein
|
||||
zweites "Erneut pruefen", damit sich eine womoeglich wochenalte Zahl
|
||||
ueberhaupt auffrischen liess, solange ein Update angeboten wurde. Das
|
||||
eruebrigt sich so. Wortgleich mit der App (Einstellungen.tsx). -->
|
||||
<button class="aktion" style="margin-top:14px" data-update="pruefen"${INTEGRATION_UPDATE_LAEUFT === "pruefen" ? " disabled" : ""}>${INTEGRATION_UPDATE_LAEUFT === "pruefen" ? "Prüfe …" : "Auf Update prüfen"}</button>
|
||||
<!-- EIN Knopf fuer die ganze Kachel, ganz unten - er ist in jedem
|
||||
Zustand da und traegt jedes Mal den naechsten faelligen Schritt:
|
||||
suchen, installieren, Neustart, Neuladen. Bis zum 05.09.2026 stand
|
||||
darueber noch ein zweiter Knopf im jeweiligen Abschnitt; der
|
||||
Eigentuemer: "warum nicht den update suchen button dafuer verwenden
|
||||
und nur die optik und schrift zur installation anpassen?" - genau das
|
||||
passiert hier, Beschriftung und Fuellung wechseln mit dem Zustand.
|
||||
Wortgleich mit der App (Einstellungen.tsx). -->
|
||||
${updateKnopf()}
|
||||
<!-- Der Zeitpunkt gehoert zum Suchvorgang, nicht zu einem Abschnitt -
|
||||
wortgleich mit der App. -->
|
||||
${INTEGRATION_UPDATE && INTEGRATION_UPDATE.geprueft_am
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"domain": "audi_dashboard",
|
||||
"name": "Audi Dashboard",
|
||||
"version": "2026.9.5.34",
|
||||
"version": "2026.9.5.35",
|
||||
"documentation": "https://gitea.nothaft.cloud/paul/audi-app/src/branch/main/README.md",
|
||||
"issue_tracker": "https://gitea.nothaft.cloud/paul/audi-app/issues",
|
||||
"codeowners": [
|
||||
|
||||
@@ -116,11 +116,14 @@ async def fuellstand_geaendert(
|
||||
# (siehe tankvolumen_geaendert) - genauer, weil ohne den Umweg über das im
|
||||
# Fahrzeugprofil hinterlegte Tankvolumen. Beide gleichzeitig auswerten
|
||||
# würde denselben Tankvorgang zweimal anlegen.
|
||||
# Reihenfolge wie bei tankvolumen_geaendert() - erst der Tiefststand, dann
|
||||
# das Anlegen, sonst legen zwei dicht aufeinanderfolgende Wechsel denselben
|
||||
# Tankvorgang zweimal an.
|
||||
await k.tiefststand_setzen(aktuell)
|
||||
if not k.zuordnung.werte.TANK_LITER_SENSOR:
|
||||
await _automatisch_anlegen(
|
||||
k, f"Füllstandsanstieg {round(anstieg, 1)} Prozentpunkte", ereigniszeit=ereigniszeit
|
||||
)
|
||||
await k.tiefststand_setzen(aktuell)
|
||||
|
||||
|
||||
async def tankvolumen_geaendert(
|
||||
@@ -144,13 +147,22 @@ async def tankvolumen_geaendert(
|
||||
if anstieg < LITER_SCHWELLE:
|
||||
return
|
||||
|
||||
# Der Tiefststand wird VOR dem Anlegen gesetzt, nicht danach.
|
||||
# _automatisch_anlegen() wartet auf Geraetezeit und Ablage; in dieser Zeit
|
||||
# kommt der naechste Zustandswechsel dran und liest oben noch den ALTEN
|
||||
# Tiefststand - beide legen denselben Tankvorgang an. Genau so entstanden
|
||||
# am 04.09.2026 um 21:37:04 zwei Eintraege ueber 29,8 l und 29,7 l, als der
|
||||
# Dongle einen gepufferten Schwung Datensaetze auf einmal ablieferte und
|
||||
# can_fuel_volume in derselben Sekunde 36,8 und 36,7 meldete.
|
||||
# tiefststand_liter_setzen() belegt das Feld als erste Anweisung, also
|
||||
# bevor es selbst wartet - danach sieht der zweite Wechsel den neuen Wert.
|
||||
await k.tiefststand_liter_setzen(aktuell)
|
||||
await _automatisch_anlegen(
|
||||
k,
|
||||
f"Tankvolumenanstieg {round(anstieg, 1)} l",
|
||||
liter_schaetzung=anstieg,
|
||||
ereigniszeit=ereigniszeit,
|
||||
)
|
||||
await k.tiefststand_liter_setzen(aktuell)
|
||||
|
||||
|
||||
async def distanz_seit_tankung(
|
||||
|
||||
Reference in New Issue
Block a user