Fahrtzeiten vom Geraet, Trip und Zuendung getrennt (2026.9.1.3)
Enthaelt 2026.9.1.2, das nie einzeln ausgeliefert wurde. FAHRT- UND TANKZEITEN KOMMEN VOM GERAET Fahrtbeginn war datetime.now() - die Uhrzeit, zu der Home Assistant den Wechsel verarbeitet. Hat das Geraet gepuffert (Funkloch, Tiefgarage, Tiefschlaf), liegt die Wahrheit beliebig weit davor. Gemessen: ein Datensatz mit Fahrtende trug die Geraetezeit 07:29:04 und kam um 07:35:23 an. Neue Sensorrolle MELDEZEIT_SENSOR (message_timestamp, Unix-Sekunden). Der Wert ist UTC, keine Ortszeit - nachgemessen lag der Versatz zur UTC-Uhr von HA bei Sekunden, nicht bei zwei Stunden; eine Zeitzonenumrechnung baute einen Zwei-Stunden-Fehler ein. geraetezeit() liegt in verlauf.py, weil Fahrt- und Tankerkennung denselben Zeitstempel bestimmen muessen. tankerkennung._automatisch_anlegen() stempelte bisher ebenfalls mit now(); ein aus einem gepufferten Datensatz erkannter Tankvorgang trug damit die Uhrzeit des Auftauchens. Die flespi-Integration setzt die Entitaeten eines Datensatzes nacheinander - gemessen Zuendung 07:35:23.633, zugehoerige Meldezeit 2 ms spaeter. Wer sofort liest, bekommt den vorigen Datensatz: beim Fahren zehn Sekunden daneben, im Stand Stunden (On Stop Min Period = 43200 s). geraetezeit() wartet deshalb bis zu 2 s auf den passenden Wert. Zwei Notbremsen, beide live ausgeloest: Zeitstempel in der Zukunft und Ende vor dem Beginn. TRIP UND ZUENDUNG SIND ZWEI ROLLEN ZUENDUNG_SENSOR zeigte auf das Trip-Signal; im Setup stand "Zuendung/ACC" ueber einer Trip-Entitaet und die echte Zuendung war nirgends zugeordnet. Neu: TRIP_SENSOR loest Fahrten aus, ZUENDUNG_SENSOR liefert nur noch die Anzeige "faehrt/steht". verlauf.fahrtsignal() ist die eine Stelle, die entscheidet - Trip-Status wenn zugeordnet, sonst Zuendung, damit bestehende Installationen unveraendert weiterlaufen und Livepfad und Rueckblick nicht auseinanderlaufen. VERIFIZIERT in audi_ha_test, jeder Weg einzeln: - Fahrtbeginn 08:30:03 (Geraetezeit) statt 08:38:27 (Ankunft) - Fahrtende 08:04:40 -> 08:09:22 statt 08:11:04 -> 08:11:24 - Tankvorgang 08:18:45 statt 08:38:51 - 20 Minuten frueher - Meldezeit in der Zukunft und Ende vor Beginn: Warnung, Ankunft genommen - Zuendung schalten legt keine Fahrt mehr an, Trip-Signal schon Der Livetest fing dabei einen NameError, den py_compile nicht sehen konnte: der Import von geraetezeit in tankerkennung.py fehlte. Kompiliert ist nicht verifiziert. Alle Testdatensaetze wurden ueber die eigenen Dienste wieder entfernt; Bestand unveraendert 11 Fahrten, 13 Tankvorgaenge, keine offene Fahrt. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
@@ -26,7 +26,13 @@ from typing import TYPE_CHECKING
|
||||
from . import screening
|
||||
from .ablage import neue_id
|
||||
from .veroeffentlichung import zustand_oder_none
|
||||
from .verlauf import MINDESTDAUER_S, verlauf_lesen, zeit_normalisiert
|
||||
from .verlauf import (
|
||||
MINDESTDAUER_S,
|
||||
fahrtsignal,
|
||||
geraetezeit,
|
||||
verlauf_lesen,
|
||||
zeit_normalisiert,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .koordinator import Koordinator
|
||||
@@ -77,7 +83,23 @@ def leere_fahrt(start_ts: datetime.datetime, ende_ts: datetime.datetime, quelle:
|
||||
|
||||
|
||||
|
||||
async def zuendung_geaendert(k: Koordinator, neu: str | None, alt: str | None) -> None:
|
||||
async def _geraetezeit(
|
||||
k: Koordinator,
|
||||
ereigniszeit: datetime.datetime | None,
|
||||
standard: datetime.datetime,
|
||||
) -> datetime.datetime:
|
||||
"""Die Meldezeit des Geräts - siehe verlauf.geraetezeit()."""
|
||||
return await geraetezeit(
|
||||
k.hass, k.zuordnung.werte.MELDEZEIT_SENSOR, ereigniszeit, standard
|
||||
)
|
||||
|
||||
|
||||
async def zuendung_geaendert(
|
||||
k: Koordinator,
|
||||
neu: str | None,
|
||||
alt: str | None,
|
||||
ereigniszeit: datetime.datetime | None = None,
|
||||
) -> None:
|
||||
"""Reagiert auf jede Zustandsänderung der Zündungs-Entität.
|
||||
|
||||
"unavailable"/"unknown" ist kein Zündungszustand, sondern Funkstille des
|
||||
@@ -119,9 +141,16 @@ async def zuendung_geaendert(k: Koordinator, neu: str | None, alt: str | None) -
|
||||
# ganze Zeit lief.
|
||||
fahrt_laeuft = k.fahrt_start_ts is not None
|
||||
|
||||
jetzt = datetime.datetime.now(datetime.UTC)
|
||||
|
||||
if an_jetzt and not fahrt_laeuft:
|
||||
await k.fahrt_start_setzen(datetime.datetime.now(datetime.UTC))
|
||||
_LOGGER.info("Fahrt gestartet um %s", k.fahrt_start_ts)
|
||||
beginn = await _geraetezeit(k, ereigniszeit, jetzt)
|
||||
await k.fahrt_start_setzen(beginn)
|
||||
_LOGGER.info(
|
||||
"Fahrt gestartet um %s (%s)",
|
||||
k.fahrt_start_ts,
|
||||
"Gerätezeit" if beginn != jetzt else "Ankunft in HA",
|
||||
)
|
||||
# Die Anzeige "fährt/steht" hängt an derselben Entität - sofort neu
|
||||
# veröffentlichen, statt bis zum nächsten 20-Sekunden-Takt zu warten.
|
||||
await k.fahrzeugstatus_veroeffentlichen()
|
||||
@@ -134,7 +163,17 @@ async def zuendung_geaendert(k: Koordinator, neu: str | None, alt: str | None) -
|
||||
# zu warten haette daraus eine halbe Stunde gemacht und zwei
|
||||
# aufeinanderfolgende Fahrten verschmolzen, die das Geraet sauber
|
||||
# getrennt hatte.
|
||||
await fahrt_beenden(k, k.fahrt_start_ts, datetime.datetime.now(datetime.UTC))
|
||||
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 -
|
||||
# dann ist die Ankunftszeit die ehrlichere Angabe.
|
||||
if ende < k.fahrt_start_ts:
|
||||
_LOGGER.warning(
|
||||
"Meldezeit %s liegt vor dem Fahrtbeginn %s - nehme die Ankunft",
|
||||
ende.isoformat(), k.fahrt_start_ts.isoformat(),
|
||||
)
|
||||
ende = jetzt
|
||||
await fahrt_beenden(k, k.fahrt_start_ts, ende)
|
||||
|
||||
await k.fahrzeugstatus_veroeffentlichen()
|
||||
|
||||
@@ -157,7 +196,7 @@ async def nach_neustart_fortsetzen(k: Koordinator) -> None:
|
||||
if k.fahrt_start_ts is None:
|
||||
return
|
||||
|
||||
sensor = k.zuordnung.werte.ZUENDUNG_SENSOR
|
||||
sensor = fahrtsignal(k.zuordnung.werte)
|
||||
if zustand_oder_none(k.hass, sensor) == "on":
|
||||
return # fährt noch - der Beobachter übernimmt wie sonst auch
|
||||
|
||||
|
||||
Reference in New Issue
Block a user