Regler stellt den Schlaf-Timeout des Dongles (2026.9.3.10)
Der Regler "Fahrt beenden" ist jetzt eine Zahl fuer zwei Dinge: unsere eigene
Wartezeit bis zum Fahrtende und der Schlaf-Timeout des FMM003 (103). So lange
bleibt der Dongle wach und wartet darauf, dass es gleich weitergeht; danach
schlaeft er. Die 180 s Ignition OFF Delay laufen davor und bleiben unsichtbar -
sie werden nur von der Fahrtdauer abgezogen. Der Regler geht deshalb von 1 bis
60 in Einerschritten; das Geraet kennt kein Timeout 0.
flespi.py liest und schreibt die Geraete-Konfiguration. Drei Annahmen sind an
der echten API gefallen und stehen als Messung im Modulkopf: der Wert liegt in
current (nicht value), die Einstellung heisst sleep_mode mit dem Wert eine Ebene
tiefer unter mode, und ein PUT braucht {"properties": ..., "address": ...}.
Die eigene Auftrags-Warteschlange ist wieder entfallen. Sie war fuer "das Geraet
schlaeft" gebaut - das gilt aber nur fuer das Geraet, nicht fuer die
Schnittstelle: die vollstaendige Konfiguration kam herein, waehrend das Fahrzeug
seit dem Vortag stand. flespi puffert selbst (pending + address=connection), ein
zweites Auftragsbuch waere eine zweite Warteschlange fuer dieselbe Aufgabe.
Gegengelesen wird nach jedem Schreiben; als Erfolg zaehlt current ODER pending -
letzteres ist bei stehendem Fahrzeug der Normalfall.
Live gegen den echten Account belegt: Token sieht genau ein Geraet, 127
Einstellungen bei parkendem Fahrzeug gelesen, Regler 15 geschrieben und als
pending bestaetigt (Nachbarfelder unveraendert), zweiter Neustart ohne erneute
Anfrage.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1834,9 +1834,9 @@ function terminText(t) {
|
||||
Updates vom Backend, siehe datenLaden()) selbständig hoch und schaltet
|
||||
dabei die Einheit um - Sek. bis 60, dann Min. bis 60, dann Std. bis 24,
|
||||
dann Tage. */
|
||||
function standAlterText() {
|
||||
if (LETZTES_UPDATE_TS == null) return "unbekannt";
|
||||
const sekunden = Math.max(0, Math.floor((Date.now() - LETZTES_UPDATE_TS) / 1000));
|
||||
function alterText(ts) {
|
||||
if (ts == null || !Number.isFinite(ts)) return "unbekannt";
|
||||
const sekunden = Math.max(0, Math.floor((Date.now() - ts) / 1000));
|
||||
if (sekunden < 60) return `vor ${sekunden} Sek.`;
|
||||
const minuten = Math.floor(sekunden / 60);
|
||||
if (minuten < 60) return `vor ${minuten} Min.`;
|
||||
@@ -1844,6 +1844,9 @@ function standAlterText() {
|
||||
if (stunden < 24) return `vor ${stunden} Std.`;
|
||||
return `vor ${Math.floor(stunden / 24)} Tage`;
|
||||
}
|
||||
function standAlterText() {
|
||||
return alterText(LETZTES_UPDATE_TS);
|
||||
}
|
||||
function standAlterTicken() {
|
||||
if (!ROOT || !CAR) return;
|
||||
const sy = $("#sync span"); if (sy) sy.textContent = standAlterText();
|
||||
@@ -3100,16 +3103,47 @@ function vEinst() {
|
||||
</div>` : ""}
|
||||
<div class="tile"><span class="label">Fahrt beenden</span>
|
||||
<div class="schieber" style="margin-top:14px">
|
||||
<input type="range" min="0" max="60" step="5" value="${CONFIG.pausenzeit}"
|
||||
style="--fuell:${(CONFIG.pausenzeit / 60) * 100}%" data-pausenzeit
|
||||
<input type="range" min="1" max="60" step="1" value="${CONFIG.pausenzeit}"
|
||||
style="--fuell:${((CONFIG.pausenzeit - 1) / 59) * 100}%" data-pausenzeit
|
||||
aria-label="Minuten bis zum automatischen Fahrtende">
|
||||
<output>${CONFIG.pausenzeit === 0 ? "sofort" : CONFIG.pausenzeit + " Min."}</output>
|
||||
<output>${CONFIG.pausenzeit} Min.</output>
|
||||
</div>
|
||||
<span class="label" style="margin-top:14px;color:var(--fg2);letter-spacing:0;
|
||||
text-transform:none;font-size:12.5px;line-height:1.6">
|
||||
Hier können Sie einstellen, wie viele Minuten nach Ausschalten der Zündung die
|
||||
Fahrt automatisch beendet werden soll.</span>
|
||||
Fahrt automatisch beendet werden soll. Derselbe Wert stellt den Schlaf-Timeout
|
||||
des Dongles: so lange bleibt er nach dem Abstellen wach und wartet darauf,
|
||||
dass es gleich weitergeht. Danach schläft er — das spart Strom, kostet beim
|
||||
Fortsetzen aber ein paar Sekunden fürs Aufwachen.</span>
|
||||
</div>
|
||||
${DONGLE && DONGLE.aktiv ? `<div class="tile"><span class="label">Dongle</span>
|
||||
${DONGLE.stand && DONGLE.stand.fehler
|
||||
? `<span class="label" style="margin-top:8px;color:var(--bad);letter-spacing:0;
|
||||
text-transform:none;font-size:12.5px;line-height:1.6">${esc(DONGLE.stand.fehler)}</span>`
|
||||
: ""}
|
||||
${DONGLE.stand && (DONGLE.stand.werte || []).length ? `<dl class="rows">
|
||||
${DONGLE.stand.werte.map((w) => `<div class="row">
|
||||
<dt>${esc(w.titel)} <small style="color:var(--fg3)">${esc(w.nummer)}</small></dt>
|
||||
<dd${w.abweichung ? ` style="color:var(--warn)"` : ""}>${
|
||||
w.geraet === null || w.geraet === undefined ? "–" : esc(String(w.geraet))
|
||||
}${w.einheit ? " " + esc(w.einheit) : ""}${
|
||||
w.offen !== null && w.offen !== undefined
|
||||
? ` <small>→ ${esc(String(w.offen))}, unterwegs</small>`
|
||||
: w.abweichung ? ` <small>(wir: ${esc(String(w.unser))})</small>` : ""
|
||||
}</dd>
|
||||
</div>`).join("")}
|
||||
</dl>` : ""}
|
||||
<button class="aktion" data-dongle ${DONGLE_LAEUFT ? "disabled" : ""}>${
|
||||
DONGLE_LAEUFT ? `<span class="lade-spinner"></span>Liest …` : "Jetzt lesen"
|
||||
}</button>
|
||||
<span class="label" style="margin-top:14px;color:var(--fg2);letter-spacing:0;
|
||||
text-transform:none;font-size:12.5px;line-height:1.6">
|
||||
${DONGLE.stand && DONGLE.stand.gelesen_am
|
||||
? `Gelesen ${esc(alterText(Date.parse(DONGLE.stand.gelesen_am)))}. `
|
||||
: "Noch nicht gelesen. "}Lesen und Schreiben gehen nur bei laufender Zündung —
|
||||
Der Regler oben schreibt den Schlaf-Timeout sofort hierher; bis das Gerät sich
|
||||
das nächste Mal meldet, steht die Änderung als „unterwegs" daneben.</span>
|
||||
</div>` : ""}
|
||||
<div class="tile"><span class="label">Darstellung</span>
|
||||
<div class="seg">
|
||||
<button data-mode="nacht" class="${HOST.dataset.theme === "nacht" ? "on" : ""}">Nacht</button>
|
||||
@@ -4158,6 +4192,13 @@ let INTEGRATION_UPDATE = null;
|
||||
/* Nur "gesetzt/nicht gesetzt" je Dienst - der Token selbst kommt nie ueber
|
||||
die Leitung, siehe zugaenge.py im Backend. */
|
||||
let ZUGAENGE = [];
|
||||
/* Was am Dongle steht, was noch aussteht - siehe flespi.py im Backend.
|
||||
null, solange kein flespi-Token hinterlegt ist. */
|
||||
let DONGLE = null;
|
||||
// true, waehrend "Jetzt lesen" laeuft. Wie INTEGRATION_UPDATE_LAEUFT und aus
|
||||
// demselben Grund: der Abruf geht ueber zwei Netze (wir -> flespi -> Geraet)
|
||||
// und darf nicht wie ein toter Knopf aussehen.
|
||||
let DONGLE_LAEUFT = false;
|
||||
// "pruefen" | "installieren" | "neustart" | null - während einer dieser drei
|
||||
// Aktionen läuft, siehe vEinst()'s Integration-Update-Kachel. Eigens statt
|
||||
// über serviceRufen() (das feuert-und-vergisst), weil diese drei Aktionen
|
||||
@@ -6001,6 +6042,18 @@ function ereignisseVerdrahten() {
|
||||
// div ohne data-go, aber die Reihenfolge haelt das auch dann, wenn die
|
||||
// Kachel spaeter einmal anders gebaut wird.
|
||||
if (e.target.closest("[data-fahrtbeenden]")) { serviceRufen("fahrt_jetzt_beenden", {}); return; }
|
||||
if (e.target.closest("[data-dongle]")) {
|
||||
// Nicht ueber serviceRufen(): das feuert und vergisst, hier soll der Knopf
|
||||
// aber zeigen, dass gerade zwei Netze befragt werden - und danach wieder
|
||||
// freigeben. Das Ergebnis (auch ein Fehler) kommt ueber die veroeffentlichte
|
||||
// Entitaet zurueck, siehe flespi.py; deshalb hier nur der Ladezustand.
|
||||
if (DONGLE_LAEUFT) return;
|
||||
DONGLE_LAEUFT = true; render();
|
||||
HASS.callService(DOMAIN, "dongle_lesen", {})
|
||||
.catch((f) => console.error("dongle_lesen", f))
|
||||
.finally(() => { DONGLE_LAEUFT = false; render(); });
|
||||
return;
|
||||
}
|
||||
const tokSpeichern = e.target.closest("[data-tokenspeichern]");
|
||||
if (tokSpeichern) {
|
||||
const dienst = tokSpeichern.dataset.tokenspeichern;
|
||||
@@ -6391,6 +6444,9 @@ async function datenLaden(erzwingen) {
|
||||
ZUGAENGE = versionState.attributes.daten
|
||||
? versionState.attributes.daten.zugaenge ?? []
|
||||
: [];
|
||||
DONGLE = versionState.attributes.daten
|
||||
? versionState.attributes.daten.dongle ?? null
|
||||
: null;
|
||||
}
|
||||
if (entitaetenState && entitaetenState.attributes) ENTITAETEN = entitaetenState.attributes.daten;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user