Kalender ueber EventKit, Orte nach dem Import, Fotos verkleinert, Signalsperre (2026.9.3.1-.3)
- Kalendertermine gehen nativ ueber EventKit statt ueber das Teilen-Blatt:
Apples Kalender meldet sich beim System gar nicht als Teilen-Ziel an, ein
anderes Dateiformat haette also nie geholfen (Abschnitt BS).
- Der Rueckblick stoesst jetzt selbst das Screening an, wenn er Fahrten
angelegt hat - sonst blieb eine importierte Fahrt ohne Ort liegen, solange
das Fahrzeug steht (Abschnitt BT).
- Fahrzeugfotos werden vor dem Upload im Browser auf 2000 px/WebP gebracht.
Gemessen: 3.099.022 -> 325.994 Bytes. Damit ist die Nachrichtengrenze der
WebSocket-Verbindung kein Thema mehr ("connection lost" auf der realen
Instanz). Formate, die der Browser weder umwandeln noch anzeigen kann,
werden mit klarer Meldung abgelehnt statt roh gespeichert.
- Zwei Wechsel des Fahrtsignals in derselben Sekunde kosteten eine ganze
Fahrt: das "on" ueberholte den noch laufenden Beende-Vorgang und fiel durch
beide Zweige. Neue asyncio-Sperre plus Regressionstest, der ohne sie
nachweislich rot ist (Abschnitt BU).
Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
@@ -254,11 +254,39 @@ async def zuendung_geaendert(
|
||||
# abbrechen - das ist der Mechanismus hinter der Pausenregel.
|
||||
k.warte_ende_ab_abbrechen()
|
||||
|
||||
an_jetzt = neu == "on"
|
||||
# Von hier an nur einer zur Zeit. Home Assistant startet für jeden
|
||||
# Zustandswechsel eine eigene Aufgabe, und dieser Rumpf wartet mehrfach:
|
||||
# _geraetezeit() bis zu zwei Sekunden auf die Meldezeit, danach liest
|
||||
# _echtes_ende() den Verlauf, danach schreibt fahrt_beenden() die Fahrt
|
||||
# und stösst das Screening an.
|
||||
#
|
||||
# Ohne die Sperre überholt der nächste Wechsel den laufenden. Genau das ist
|
||||
# am 02.09.2026 passiert und hat eine ganze Fahrt gekostet: das Gerät hatte
|
||||
# gepuffert, deshalb kamen "Fahrt zu Ende" (Gerätezeit 21:20:55) und "Fahrt
|
||||
# begonnen" in DERSELBEN Sekunde bei Home Assistant an, 21:22:12. Das "off"
|
||||
# ging in den Beende-Zweig und wartete; das "on" traf mitten hinein, sah
|
||||
# fahrt_start_ts noch gesetzt - also "es läuft eine Fahrt" - und passte
|
||||
# damit in keinen der beiden Zweige unten. Es fiel wortlos durch. Danach
|
||||
# räumte der Beende-Vorgang das Feld ab, und das reguläre "off" um 21:58:16
|
||||
# fand keine laufende Fahrt mehr. 36 Minuten Fahrt, live nie gesehen; nur
|
||||
# der Rückblick hat sie später gefunden.
|
||||
#
|
||||
# Die Sperre statt eines früheren Zurücksetzens von fahrt_start_ts: fällt
|
||||
# der Beende-Vorgang unterwegs aus, bleibt der Zwischenstand stehen wie
|
||||
# bisher und der nächste Auslöser schliesst die Fahrt nach. Ein früheres
|
||||
# Löschen hätte sie in dem Fall verloren.
|
||||
async with k.fahrt_sperre:
|
||||
await _signalwechsel(k, neu == "on", ereigniszeit)
|
||||
|
||||
|
||||
async def _signalwechsel(
|
||||
k: Koordinator, an_jetzt: bool, ereigniszeit: datetime.datetime | None
|
||||
) -> None:
|
||||
# Ob eine Fahrt läuft, entscheidet der eigene Zwischenstand
|
||||
# (fahrt_start_ts) - nicht der vorherige Rohwert der Entität. Der wäre bei
|
||||
# einer Funklücke "unavailable" statt "on" gewesen, obwohl die Fahrt die
|
||||
# ganze Zeit lief.
|
||||
# ganze Zeit lief. Gelesen wird er INNERHALB der Sperre: ein Wechsel, der
|
||||
# auf seinen Vorgänger gewartet hat, muss dessen Ergebnis sehen.
|
||||
fahrt_laeuft = k.fahrt_start_ts is not None
|
||||
|
||||
jetzt = datetime.datetime.now(datetime.UTC)
|
||||
@@ -324,6 +352,16 @@ async def nach_neustart_fortsetzen(k: Koordinator) -> None:
|
||||
if zustand_oder_none(k.hass, sensor) == "on":
|
||||
return # fährt noch - der Beobachter übernimmt wie sonst auch
|
||||
|
||||
# Dieselbe Sperre wie im Beobachter: der erste Wechsel des Fahrtsignals
|
||||
# kann eintreffen, während dieser Nachlauf noch schreibt.
|
||||
async with k.fahrt_sperre:
|
||||
await _nachtraeglich_schliessen(k, sensor)
|
||||
|
||||
|
||||
async def _nachtraeglich_schliessen(k: Koordinator, sensor: str) -> None:
|
||||
if k.fahrt_start_ts is None:
|
||||
return # der Beobachter war schneller
|
||||
|
||||
ende_ts = await _letztes_lebenszeichen(k, sensor, k.fahrt_start_ts)
|
||||
_LOGGER.info(
|
||||
"Fahrt seit %s wurde während eines Ausfalls beendet - wird jetzt mit "
|
||||
|
||||
Reference in New Issue
Block a user