Fahrt beenden auf Knopfdruck, Schieberegler, Zuendungspause (2026.9.3.5-.7)
Vier Themen aus einer Sitzung. 1. Die Fahrt endet wieder bei uns statt im Dongle (Abschnitt BW). Der Ignition-OFF-Timeout des FMM003 (900 s) und sein Schlaf-Timeout (ebenfalls 900 s) starten beide beim Zuendungs-Aus und fallen in derselben Sekunde - am 02.09. zweimal beobachtet, einmal ging das Trip-Ende verloren, einmal kam es eine Sekunde vor dem Schlaf an. Ausloeser ist jetzt die Zuendung, die Wartezeit laeuft in Home Assistant. ZUENDUNG_NACHLAUF_S = 180 wird in beiden Wegen abgezogen (ueber das Trip-Signal 1080 s, weil dessen Ende selbst an der verzoegerten Zuendung haengt). 2. Schieberegler, neu in beiden Codebasen. Schrittweite 5 Minuten; der Daumen war im Tagmodus weiss auf weiss und traegt jetzt einen Ring aus --line-strong - ein Token, das genau dort sichtbar ist, wo es gebraucht wird. 3. Knopf "Fahrt beenden" in der Zuletzt-Kachel (Abschnitt BX). Schliesst auf das letzte Lebenszeichen, nicht auf "jetzt", und kennzeichnet das Ende als vorlaeufig. Ein spaet eintreffendes Zuendungs-Aus zieht es nach - innerhalb von sechs Stunden, nur nach vorn, und nur bei einer vorlaeufigen Fahrt. ts_end wandert bewusst NICHT in edited_fields, sonst blockierte der Schutz fuer Handeingaben genau diese Korrektur. 4. Das OTA-Buendel kann auf dem Mac gar nicht entstehen (Abschnitt BV): npm run ota ist eine Windows-PowerShell-Datei, ios-signieren.sh baut ein frisches dist/ und fasst das Buendel nie an. Ausgeliefert war deshalb eine Oberflaeche ohne den Versionshinweis unter richtiger Nummer. Verifiziert: Backend 27/27 (5 Signalwechsel, 14 Zuendungspause, 8 Fahrtende), companion-app tsc sauber und 179/179, Panel als Modul geparst, audi_ha_test auf 2026.9.3.7 sauber gestartet. Live am laufenden Panel und ohne Rueckstand belegt: Wartezeit samt Abbruch, die 180-s-Rechnung, der Regler im Tagmodus und der Knopf von der laufenden Fahrt bis zum verworfenen Kurzvorgang - Fahrten vorher 16, nachher 16. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
@@ -19,6 +19,7 @@ hier behoben: der Zwischenstand liegt in einem Store (siehe koordinator.py),
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import datetime
|
||||
import logging
|
||||
from typing import TYPE_CHECKING
|
||||
@@ -72,6 +73,50 @@ NACHLAUF_S = 900
|
||||
# Datensaetze schreibt - beim Fahren alle 10 s, im Stand deutlich seltener.
|
||||
NACHLAUF_TOLERANZ_S = 120
|
||||
|
||||
# Der Nachlauf des Zuendungselements selbst (FMM003: "Ignition OFF Delay",
|
||||
# Parameter 400).
|
||||
#
|
||||
# Das Geraet meldet "Zuendung aus" nicht beim Abfall der Drehzahl, sondern erst
|
||||
# diese Spanne spaeter - eine Entprellung gegen Start-Stopp und gegen kurze
|
||||
# Aussetzer des CAN-Signals. Beide sind nachgewiesen: in den beiden Fahrten vom
|
||||
# 02.09.2026 kippte die Zuendung je einmal in den ersten 25 Sekunden fuer unter
|
||||
# eine Sekunde weg und kam sofort zurueck.
|
||||
#
|
||||
# Der gemeldete Zeitpunkt liegt damit systematisch zu spaet, und zwar in BEIDEN
|
||||
# Wegen: auch das Trip-Ende des Geraets haengt an der verzoegerten Zuendung.
|
||||
# Nachgemessen am 02.09.2026: Zuendung aus 21:43:15, Trip aus 21:58:16 - genau
|
||||
# NACHLAUF_S spaeter. Wer das Trip-Signal als Ausloeser nimmt, muss deshalb
|
||||
# beide Spannen abziehen.
|
||||
#
|
||||
# Der Wert stand bis zum 31.08.2026 auf 0 und seit dem 01.09.2026 09:38 auf
|
||||
# 180 s (aus den Geraetekonfigurationen rekonstruiert). Fahrten aus der Zeit
|
||||
# dazwischen enden 180 s zu spaet - korrigiert wird ab jetzt, rueckwirkend nur
|
||||
# von Hand.
|
||||
#
|
||||
# Wie NACHLAUF_S die Konfiguration des Geraets und bewusst keine Einstellung in
|
||||
# der Oberflaeche.
|
||||
ZUENDUNG_NACHLAUF_S = 180
|
||||
|
||||
# Wie lange nach einem vorlaeufigen Ende ein spaeter eintreffendes Zuendungs-Aus
|
||||
# dieses Ende noch korrigieren darf.
|
||||
#
|
||||
# Der Fall, fuer den es das gibt: das Fahrzeug steht in einer Tiefgarage ohne
|
||||
# Empfang, der Nutzer beendet die Fahrt von Hand, und die gepufferten
|
||||
# Datensaetze treffen erst Stunden spaeter ein. Der Abstand zwischen dem
|
||||
# vorlaeufigen Ende (dem letzten Lebenszeichen vor dem Funkloch) und dem
|
||||
# echten Zuendungs-Aus ist hoechstens so gross wie die Funkluecke plus die
|
||||
# Restfahrt. Sechs Stunden decken das reichlich ab und begrenzen zugleich den
|
||||
# Schaden, falls ein Aus doch zu einer ganz anderen Fahrt gehoert.
|
||||
KORREKTUR_FENSTER_S = 6 * 3600
|
||||
|
||||
# Unsere eigene Wartezeit nach dem Zuendungs-Aus, wenn die Zuendung selbst der
|
||||
# Ausloeser ist. Anders als die beiden Nachlaufzeiten oben gehoert sie UNS und
|
||||
# steht deshalb in der Oberflaeche: sie beantwortet die Frage, ab wann eine
|
||||
# Unterbrechung keine Pause mehr ist, sondern das Ende der Fahrt. Das haengt am
|
||||
# Fahrverhalten, nicht am Geraet.
|
||||
STANDARD_PAUSENZEIT_MIN = 15
|
||||
PAUSENZEIT_MAX_MIN = 60
|
||||
|
||||
|
||||
def leere_fahrt(
|
||||
start_ts: datetime.datetime,
|
||||
@@ -123,6 +168,12 @@ def leere_fahrt(
|
||||
"route": None,
|
||||
"pausen": [],
|
||||
"source": quelle,
|
||||
# Das Ende steht nur vorlaeufig fest - gesetzt vom Knopf "Fahrt
|
||||
# beenden", solange das Geraet sein Zuendungs-Aus noch nicht gemeldet
|
||||
# hat. Die Oberflaechen zeigen die Strecke dann mit Tilde und dem
|
||||
# Zusatz "vorlaeufig"; _spaetes_aus() zieht das Ende nach, sobald der
|
||||
# gepufferte Datensatz eintrifft.
|
||||
"ende_vorlaeufig": False,
|
||||
"status": "offen",
|
||||
"edited_fields": [],
|
||||
}
|
||||
@@ -147,23 +198,28 @@ async def _echtes_ende(
|
||||
anschliessend. Ohne diese Klemme entstuende aus dreissig Sekunden Zuendung
|
||||
eine Viertelstunde Fahrt.
|
||||
|
||||
NUR wenn die Fahrten wirklich vom Trip-Signal ausgeloest werden. Ist
|
||||
TRIP_SENSOR nicht zugeordnet, uebernimmt die Zuendung diese Aufgabe
|
||||
(verlauf.fahrtsignal()) - und die hat keinen Nachlauf. Dort abzuziehen
|
||||
wuerde jede Fahrt um eine Viertelstunde verkuerzen und jede kuerzere ganz
|
||||
verschwinden lassen. Der Nachlauf gehoert zum Trip-Element des Geraets,
|
||||
nicht zu uns; ohne dieses Element gibt es ihn nicht."""
|
||||
if not k.zuordnung.werte.TRIP_SENSOR:
|
||||
ZWEI Nachlaeufe, nicht einer. Das Zuendungselement meldet selbst schon
|
||||
verzoegert (ZUENDUNG_NACHLAUF_S), und das Trip-Ende haengt an dieser bereits
|
||||
verzoegerten Zuendung - wer ueber das Trip-Signal kommt, muss deshalb beide
|
||||
Spannen abziehen, wer ueber die Zuendung kommt, nur die eine. Bis zum
|
||||
03.09.2026 wurde nur NACHLAUF_S abgezogen; seit der Ignition OFF Delay am
|
||||
01.09.2026 auf 180 s steht, endeten die Fahrten dadurch 180 s zu spaet."""
|
||||
nachlauf = ZUENDUNG_NACHLAUF_S
|
||||
ueber_trip = bool(k.zuordnung.werte.TRIP_SENSOR)
|
||||
if ueber_trip:
|
||||
nachlauf += NACHLAUF_S
|
||||
if not nachlauf:
|
||||
return signal_ende
|
||||
gerechnet = signal_ende - datetime.timedelta(seconds=NACHLAUF_S)
|
||||
gerechnet = signal_ende - datetime.timedelta(seconds=nachlauf)
|
||||
if gerechnet <= start_ts:
|
||||
_LOGGER.info(
|
||||
"Trip-Signal lief %s s, also nicht laenger als der Nachlauf (%s s) - "
|
||||
"Signal lief %s s, also nicht laenger als der Nachlauf (%s s) - "
|
||||
"es wurde nicht gefahren",
|
||||
int((signal_ende - start_ts).total_seconds()), NACHLAUF_S,
|
||||
int((signal_ende - start_ts).total_seconds()), nachlauf,
|
||||
)
|
||||
return start_ts
|
||||
await _nachlauf_gegenpruefen(k, start_ts, signal_ende, gerechnet)
|
||||
if ueber_trip:
|
||||
await _nachlauf_gegenpruefen(k, start_ts, signal_ende, gerechnet)
|
||||
return gerechnet
|
||||
|
||||
|
||||
@@ -192,7 +248,12 @@ async def _nachlauf_gegenpruefen(
|
||||
aus = [ts for ts, wert in punkte if wert == "off"]
|
||||
if not aus:
|
||||
return
|
||||
abweichung = abs((aus[-1] - gerechnet).total_seconds())
|
||||
# Der beobachtete Wechsel traegt den Nachlauf des Zuendungselements noch in
|
||||
# sich, das gerechnete Ende nicht mehr - erst ohne ihn meinen beide Zahlen
|
||||
# denselben Zeitpunkt. Ohne diese Zeile meldete die Pruefung seit dem
|
||||
# 01.09.2026 bei JEDER Fahrt eine Abweichung von 180 s.
|
||||
beobachtet = aus[-1] - datetime.timedelta(seconds=ZUENDUNG_NACHLAUF_S)
|
||||
abweichung = abs((beobachtet - gerechnet).total_seconds())
|
||||
if abweichung > NACHLAUF_TOLERANZ_S:
|
||||
_LOGGER.warning(
|
||||
"Fahrtende gerechnet auf %s (Trip-Ende minus %s s), die Zuendung ging "
|
||||
@@ -305,12 +366,11 @@ async def _signalwechsel(
|
||||
return
|
||||
|
||||
if not an_jetzt and fahrt_laeuft:
|
||||
# Ohne Wartezeit: der FMM003 bringt die Pausenregel selbst mit
|
||||
# (Trip Odometer -> "Ignition OFF Timeout" = 900 s). Was hier
|
||||
# ankommt, ist bereits eine beendete Fahrt - noch einmal 15 Minuten
|
||||
# zu warten haette daraus eine halbe Stunde gemacht und zwei
|
||||
# aufeinanderfolgende Fahrten verschmolzen, die das Geraet sauber
|
||||
# getrennt hatte.
|
||||
# Ob hier noch gewartet wird, entscheidet _pausenzeit_s(): liegt ein
|
||||
# Trip-Signal an, bringt das Geraet seine Pausentoleranz selbst mit,
|
||||
# und eine zweite obendrauf haette zwei getrennte Fahrten verschmolzen.
|
||||
# Loest die Zuendung aus, gibt es diese Toleranz nicht - dann ist die
|
||||
# Wartezeit unsere.
|
||||
signal_ende = await _geraetezeit(k, ereigniszeit, jetzt)
|
||||
# Ein Ende vor dem Beginn kann es nicht geben. Passiert, wenn die
|
||||
# Meldezeit aus einem älteren Datensatz stammt als der Fahrtbeginn -
|
||||
@@ -321,15 +381,229 @@ async def _signalwechsel(
|
||||
signal_ende.isoformat(), k.fahrt_start_ts.isoformat(),
|
||||
)
|
||||
signal_ende = jetzt
|
||||
# Erst jetzt den Nachlauf des Geraets abziehen: signal_ende ist der
|
||||
# Zeitpunkt, zu dem das TRIP-SIGNAL endete, nicht der, zu dem das
|
||||
# Fahrzeug abgestellt wurde.
|
||||
# Erst jetzt die Nachlaeufe des Geraets abziehen: signal_ende ist der
|
||||
# Zeitpunkt, zu dem das SIGNAL endete - die verzoegerte Zuendung oder
|
||||
# das noch spaetere Trip-Ende -, nicht der, zu dem das Fahrzeug
|
||||
# abgestellt wurde.
|
||||
ende = await _echtes_ende(k, k.fahrt_start_ts, signal_ende)
|
||||
pause_s = await _pausenzeit_s(k)
|
||||
if pause_s:
|
||||
_LOGGER.info(
|
||||
"Zuendung aus, Fahrtende waere %s - warte %s s, ob sie zurueckkommt",
|
||||
ende.isoformat(), pause_s,
|
||||
)
|
||||
k.warte_ende_ab(_nach_pause_beenden(k, k.fahrt_start_ts, ende, pause_s))
|
||||
await k.fahrzeugstatus_veroeffentlichen()
|
||||
return
|
||||
await fahrt_beenden(k, k.fahrt_start_ts, ende)
|
||||
|
||||
if not an_jetzt and not fahrt_laeuft:
|
||||
await _spaetes_aus(k, ereigniszeit, jetzt)
|
||||
|
||||
await k.fahrzeugstatus_veroeffentlichen()
|
||||
|
||||
|
||||
async def _pausenzeit_s(k: Koordinator) -> int:
|
||||
"""Unsere eigene Wartezeit nach dem Zuendungs-Aus, in Sekunden.
|
||||
|
||||
Null, solange ein Trip-Signal zugeordnet ist: dann wartet das Geraet
|
||||
bereits (Ignition OFF Timeout), und beides zusammen haette aus einer
|
||||
Viertelstunde eine halbe gemacht. Genau daran ist die Wartezeit am
|
||||
31.08.2026 entfallen - sie kommt hier nur fuer den Weg ueber die Zuendung
|
||||
zurueck.
|
||||
"""
|
||||
if k.zuordnung.werte.TRIP_SENSOR:
|
||||
return 0
|
||||
try:
|
||||
profil = await k.ablage.profil_lesen()
|
||||
wert = (profil.get("einstellungen") or {}).get("fahrten_pausenzeit_min")
|
||||
minuten = int(wert)
|
||||
except (AttributeError, TypeError, ValueError):
|
||||
minuten = STANDARD_PAUSENZEIT_MIN
|
||||
return max(0, min(minuten, PAUSENZEIT_MAX_MIN)) * 60
|
||||
|
||||
|
||||
async def _nach_pause_beenden(
|
||||
k: Koordinator,
|
||||
start_ts: datetime.datetime,
|
||||
ende_ts: datetime.datetime,
|
||||
pause_s: int,
|
||||
) -> None:
|
||||
"""Schliesst die Fahrt, wenn die Zuendung die Wartezeit ueber aus bleibt.
|
||||
|
||||
Laeuft als Hintergrundaufgabe und bewusst AUSSERHALB von k.fahrt_sperre:
|
||||
der naechste Wechsel bricht sie ueber warte_ende_ab_abbrechen() ab, und das
|
||||
ginge nicht, wenn sie die Sperre die ganze Wartezeit ueber hielte - das
|
||||
"on" stuende dann eine Viertelstunde davor, statt die Fahrt fortzusetzen.
|
||||
|
||||
Das Schliessen selbst ist gegen den Abbruch abgeschirmt. Ohne shield()
|
||||
koennte ein Wechsel, der genau in diesem Moment eintrifft, mitten im
|
||||
Schreiben abbrechen - und eine halb geschriebene Zeile in fahrten.jsonl
|
||||
waere schlimmer als eine Fahrt zu viel.
|
||||
|
||||
Das Ende steht schon fest (Zuendungszeitpunkt minus Nachlauf) und wird
|
||||
nicht nachgerechnet: die Wartezeit entscheidet nur, OB geschlossen wird,
|
||||
nicht WANN die Fahrt zu Ende war.
|
||||
"""
|
||||
await asyncio.sleep(pause_s)
|
||||
await asyncio.shield(_jetzt_schliessen(k, start_ts, ende_ts))
|
||||
|
||||
|
||||
async def _jetzt_schliessen(
|
||||
k: Koordinator, start_ts: datetime.datetime, ende_ts: datetime.datetime
|
||||
) -> None:
|
||||
async with k.fahrt_sperre:
|
||||
if k.fahrt_start_ts != start_ts:
|
||||
_LOGGER.info(
|
||||
"Wartezeit abgelaufen, aber die Fahrt von %s laeuft nicht mehr - "
|
||||
"jemand war schneller",
|
||||
start_ts.isoformat(),
|
||||
)
|
||||
return
|
||||
await fahrt_beenden(k, start_ts, ende_ts)
|
||||
|
||||
|
||||
async def _spaetes_aus(
|
||||
k: Koordinator,
|
||||
ereigniszeit: datetime.datetime | None,
|
||||
jetzt: datetime.datetime,
|
||||
) -> None:
|
||||
"""Ein Zuendungs-Aus, waehrend keine Fahrt laeuft.
|
||||
|
||||
Kommt regelmaessig vor, sobald das Geraet gepuffert hat: die Fahrt ist
|
||||
laengst geschlossen - die Wartezeit ist abgelaufen, oder
|
||||
nach_neustart_fortsetzen() hat aufgeraeumt - und das zugehoerige Aus trifft
|
||||
erst danach ein, unter Umstaenden zusammen mit dem naechsten "on".
|
||||
|
||||
Entschieden wird ueber die GERAETEZEIT und nicht ueber die Reihenfolge des
|
||||
Eintreffens; dann ist es gleichgueltig, ob das Signal vor, mit oder nach dem
|
||||
naechsten "on" ankommt. Ohne laufende Fahrt gibt es ohnehin nichts zu
|
||||
schliessen - der Unterschied liegt nur im Protokoll, und der ist es wert:
|
||||
ein Aus, das NICHT zur letzten Fahrt gehoert, heisst, dass uns ein
|
||||
Fahrtbeginn entgangen ist.
|
||||
"""
|
||||
ende = await _geraetezeit(k, ereigniszeit, jetzt)
|
||||
echt = ende - datetime.timedelta(seconds=ZUENDUNG_NACHLAUF_S)
|
||||
|
||||
juengste = None
|
||||
juengstes_ende = None
|
||||
for fahrt in await k.ablage.fahrten_lesen():
|
||||
roh = fahrt.get("ts_end")
|
||||
if not roh:
|
||||
continue
|
||||
ts = zeit_normalisiert(roh)
|
||||
if juengstes_ende is None or ts > juengstes_ende:
|
||||
juengste, juengstes_ende = fahrt, ts
|
||||
|
||||
if juengste is not None and await _vorlaeufiges_ende_korrigieren(
|
||||
k, juengste, juengstes_ende, echt
|
||||
):
|
||||
return
|
||||
|
||||
if juengstes_ende is not None and echt <= juengstes_ende + datetime.timedelta(
|
||||
seconds=NACHLAUF_TOLERANZ_S
|
||||
):
|
||||
_LOGGER.info(
|
||||
"Zuendungs-Aus (Geraetezeit %s) gehoert zur bereits geschlossenen "
|
||||
"Fahrt mit Ende %s - verworfen",
|
||||
echt.isoformat(), juengstes_ende.isoformat(),
|
||||
)
|
||||
return
|
||||
_LOGGER.warning(
|
||||
"Zuendungs-Aus (Geraetezeit %s) ohne laufende Fahrt, und es gehoert zu "
|
||||
"keiner geschlossenen (letztes Ende %s) - ein Fahrtbeginn ist uns "
|
||||
"entgangen",
|
||||
echt.isoformat(), juengstes_ende.isoformat() if juengstes_ende else "keines",
|
||||
)
|
||||
|
||||
|
||||
async def _vorlaeufiges_ende_korrigieren(
|
||||
k: Koordinator,
|
||||
fahrt: dict,
|
||||
ende_bisher: datetime.datetime,
|
||||
echt: datetime.datetime,
|
||||
) -> bool:
|
||||
"""Zieht das Ende einer von Hand beendeten Fahrt nach, sobald das Geraet
|
||||
sein Zuendungs-Aus nachliefert. Gibt zurueck, ob korrigiert wurde.
|
||||
|
||||
Der Knopf "Fahrt beenden" schliesst auf das letzte Lebenszeichen - mehr
|
||||
weiss in dem Moment niemand. Faehrt das Fahrzeug danach noch, kommt der
|
||||
Rest gepuffert nach, und genau dann gehoert das Ende nachgezogen statt
|
||||
verworfen.
|
||||
|
||||
Drei Bedingungen, jede aus einem eigenen Grund: nur eine als vorlaeufig
|
||||
gekennzeichnete Fahrt (eine regulaer geschlossene ist bereits richtig),
|
||||
nur ein SPAETERES Ende (frueher waere kein Nachtrag, sondern eine
|
||||
Verkuerzung), und nur innerhalb von KORREKTUR_FENSTER_S (sonst gehoert das
|
||||
Aus wahrscheinlich zu einer ganz anderen Fahrt).
|
||||
|
||||
ts_end wandert bewusst NICHT in edited_fields: das Feld ist keine
|
||||
Handeingabe, und dort eingetragen wuerde es genau diese Korrektur beim
|
||||
naechsten Mal blockieren.
|
||||
"""
|
||||
if not fahrt.get("ende_vorlaeufig"):
|
||||
return False
|
||||
if echt <= ende_bisher:
|
||||
return False
|
||||
if (echt - ende_bisher).total_seconds() > KORREKTUR_FENSTER_S:
|
||||
_LOGGER.warning(
|
||||
"Zuendungs-Aus (Geraetezeit %s) liegt %.0f h nach dem vorlaeufigen "
|
||||
"Ende %s - zu weit auseinander, nicht korrigiert",
|
||||
echt.isoformat(),
|
||||
(echt - ende_bisher).total_seconds() / 3600,
|
||||
ende_bisher.isoformat(),
|
||||
)
|
||||
return False
|
||||
|
||||
start_ts = zeit_normalisiert(fahrt["ts_start"])
|
||||
await k.ablage.fahrt_aktualisieren(
|
||||
fahrt["trip_id"],
|
||||
{
|
||||
"ts_end": echt.isoformat(),
|
||||
"duration_s": int((echt - start_ts).total_seconds()),
|
||||
"ende_vorlaeufig": False,
|
||||
},
|
||||
)
|
||||
_LOGGER.info(
|
||||
"Fahrt %s: vorlaeufiges Ende %s auf %s nachgezogen (+%.0f s)",
|
||||
fahrt["trip_id"], ende_bisher.isoformat(), echt.isoformat(),
|
||||
(echt - ende_bisher).total_seconds(),
|
||||
)
|
||||
await k.fahrten_veroeffentlichen()
|
||||
await screening.durchfuehren(k)
|
||||
return True
|
||||
|
||||
|
||||
async def jetzt_beenden(k: Koordinator) -> bool:
|
||||
"""Beendet die laufende Fahrt auf Knopfdruck. Gibt zurueck, ob es eine gab.
|
||||
|
||||
Geschlossen wird auf das LETZTE LEBENSZEICHEN, nicht auf "jetzt": das
|
||||
Fahrzeug stand still, als es still stand, nicht als jemand gedrueckt hat -
|
||||
und in dem Fall, fuer den der Knopf gedacht ist (Tiefgarage ohne Empfang),
|
||||
liegen die beiden weit auseinander.
|
||||
|
||||
Das Ende gilt als vorlaeufig. Trifft das Zuendungs-Aus des Geraets spaeter
|
||||
gepuffert ein, zieht _vorlaeufiges_ende_korrigieren() es nach.
|
||||
|
||||
Dieselbe Sperre wie im Beobachter, und die Pruefung auf eine laufende Fahrt
|
||||
steht INNERHALB: zwischen Knopfdruck und Sperre kann sie regulaer geendet
|
||||
haben.
|
||||
"""
|
||||
k.warte_ende_ab_abbrechen()
|
||||
async with k.fahrt_sperre:
|
||||
if k.fahrt_start_ts is None:
|
||||
_LOGGER.info("\"Fahrt beenden\" gedrueckt, aber es laeuft keine Fahrt")
|
||||
return False
|
||||
start_ts = k.fahrt_start_ts
|
||||
ende = await _letztes_lebenszeichen(k, fahrtsignal(k.zuordnung.werte), start_ts)
|
||||
_LOGGER.info(
|
||||
"Fahrt seit %s von Hand beendet, vorlaeufiges Ende %s",
|
||||
start_ts.isoformat(), ende.isoformat(),
|
||||
)
|
||||
await fahrt_beenden(k, start_ts, ende, vorlaeufig=True)
|
||||
return True
|
||||
|
||||
|
||||
|
||||
async def nach_neustart_fortsetzen(k: Koordinator) -> None:
|
||||
"""Schließt eine Fahrt ab, die während eines HA-Ausfalls zu Ende ging.
|
||||
@@ -386,7 +660,10 @@ async def _letztes_lebenszeichen(
|
||||
|
||||
|
||||
async def fahrt_beenden(
|
||||
k: Koordinator, start_ts: datetime.datetime, ende_ts: datetime.datetime
|
||||
k: Koordinator,
|
||||
start_ts: datetime.datetime,
|
||||
ende_ts: datetime.datetime,
|
||||
vorlaeufig: bool = False,
|
||||
) -> None:
|
||||
dauer_s = int((ende_ts - start_ts).total_seconds())
|
||||
if dauer_s < MINDESTDAUER_S:
|
||||
@@ -403,6 +680,7 @@ async def fahrt_beenden(
|
||||
)
|
||||
return
|
||||
fahrt = leere_fahrt(start_ts, ende_ts, "ha", reifen.aktiver_satz(await k.ablage.profil_lesen()))
|
||||
fahrt["ende_vorlaeufig"] = vorlaeufig
|
||||
await k.ablage.fahrt_anhaengen(fahrt)
|
||||
await k.fahrt_start_setzen(None)
|
||||
await k.fahrten_veroeffentlichen()
|
||||
|
||||
Reference in New Issue
Block a user