f337820fc8
Batteriespannung: Werte unter 8V (Sensor-/Verbindungsfehler, nicht physikalisch
plausibel für eine 12V-Bleibatterie) werden nicht mehr erfasst - live und beim
Import. "Neue Räder anlegen"-Knopf sitzt jetzt auf derselben Zeile wie "Montiert".
Fahrten: start_lat/-lon, end_lat/-lon und route wurden bisher nur beim
rückwirkenden Import befüllt, nie bei live erkannten Fahrten (dem Normalfall) -
Screening trägt sie jetzt aus dem GPS-Verlauf nach, unabhängig vom
Kilometerstand-Status. fakeTrack() (eine erfundene Linie) ist entfernt, die
Karte zeichnet jetzt die echte Route oder eine ehrliche Gerade zwischen den
bekannten Punkten. CARTOs anonyme Kartenkacheln verlangen inzwischen einen
API-Schlüssel ("API key required" auf jeder Karte in beiden Apps) - auf
schlüssellose OpenStreetMap-Kacheln umgestellt. Start/Ziel zeigen jetzt Datum
und Uhrzeit über der Adresse; die fehlerhafte "Status"-Zeile ist entfernt.
Batteriespannungs-Diagramm nutzt auf großen Bildschirmen die volle
Spaltenbreite statt einer festen 400px-Deckelung.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
112 lines
4.6 KiB
Python
112 lines
4.6 KiB
Python
"""Langfristige Aufzeichnung der 12V-Batteriespannung (Mein Audi -> Zustand
|
|
-> Batteriespannung antippen).
|
|
|
|
Eine über die Jahre absinkende Spannung deutet auf eine alternde Batterie hin
|
|
- dafür braucht es einen Verlauf, nicht nur den aktuellen Wert.
|
|
|
|
Ein Eintrag pro Tag ({datum, min, min_ts, max, max_ts}) reicht dafür und hält
|
|
die Datei auch über viele Jahre klein, selbst wenn der Sensor mehrfach pro
|
|
Stunde meldet (aktive Fahrt: Motor an/aus, Ladezustand des Alternators
|
|
wechselt laufend). Die Prüfung läuft deshalb alle 5 Minuten und trägt jede
|
|
Messung in den Tageseintrag ein; die Ablage erweitert dabei nur min/max samt
|
|
dem genauen Zeitstempel der jeweiligen Extremmessung - robust gegen Neustarts
|
|
und schwankende Erreichbarkeit.
|
|
|
|
Der Tagesminimalwert ist die für die Entladung aussagekräftige Größe: er fällt
|
|
typischerweise auf den Moment kurz nach dem Start, bevor der Alternator die
|
|
Ladespannung hochfährt - also am nächsten an die "echte" Ruhespannung heran,
|
|
ohne 2+ Stunden Standzeit abwarten zu müssen. Deshalb verwendet auch die
|
|
Ladezustands-/Gesundheitsauswertung im Frontend (AGM_RUHE_MAX_V) den
|
|
Tagesminimalwert, nicht den Maximalwert.
|
|
|
|
Es wird bewusst NICHT gefiltert, welche Messwerte gespeichert werden - min UND
|
|
max jedes Tages werden roh aufgezeichnet, solange die Messung überhaupt
|
|
plausibel ist (siehe SPANNUNG_MIN_V unten). Die AGM-Ruhespannungs-Grenze wird
|
|
erst beim Anzeigen angewendet: Tage, an denen selbst der Minimalwert über der
|
|
Grenze liegt (Fahrzeug nie im Ruhezustand beobachtet, z. B. bei einer sehr
|
|
langen Fahrt), tauchen dort nicht in der Statistik auf.
|
|
|
|
Eine Ausnahme von "roh aufzeichnen" gibt es: Werte unter SPANNUNG_MIN_V sind
|
|
für eine 12V-Bleibatterie physikalisch nicht plausibel (selbst tiefentladen
|
|
liegt die Ruhespannung deutlich darüber) und deuten auf einen Sensor-/
|
|
Verbindungsfehler statt auf eine echte Messung hin - sie werden gar nicht erst
|
|
aufgezeichnet, damit ein einzelner Ausreißer nicht als Tagesminimum in der
|
|
Liste und im Diagramm landet.
|
|
|
|
Ohne zugeordneten BATTERIE_SENSOR passiert hier bewusst nichts, statt
|
|
Platzhalter-Nullwerte aufzuzeichnen.
|
|
|
|
Optional wird bei jeder neuen Tagesminimum-Messung auch die aktuelle
|
|
Außentemperatur (AUSSENTEMP_SENSOR, CAN ambient air temperature) mit
|
|
aufgezeichnet - für die Messwertliste (Datum, Uhrzeit, Außentemperatur), nicht
|
|
für die Ladezustandsauswertung selbst. Ohne zugeordneten Temperatursensor
|
|
bleibt das Feld None, genau wie beim Batteriesensor.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import datetime
|
|
import logging
|
|
from typing import TYPE_CHECKING
|
|
|
|
from .veroeffentlichung import zustand_oder_none
|
|
|
|
if TYPE_CHECKING:
|
|
from .koordinator import Koordinator
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
# Physikalisch plausible Untergrenze für eine 12V-Bleibatterie - darunter ist
|
|
# es ein Sensor-/Verbindungsfehler, keine echte Messung (siehe Moduldocstring).
|
|
SPANNUNG_MIN_V = 8.0
|
|
|
|
|
|
async def pruefen(k: Koordinator) -> None:
|
|
sensor = k.zuordnung.werte.BATTERIE_SENSOR
|
|
if not sensor:
|
|
return
|
|
wert = zustand_oder_none(k.hass, sensor)
|
|
if wert is None:
|
|
return
|
|
try:
|
|
spannung = float(wert)
|
|
except (TypeError, ValueError):
|
|
return
|
|
if spannung < SPANNUNG_MIN_V:
|
|
_LOGGER.warning(
|
|
"Batteriespannung %s V unter der Plausibilitätsgrenze (%s V) - nicht erfasst",
|
|
spannung, SPANNUNG_MIN_V,
|
|
)
|
|
return
|
|
|
|
aussentemp = None
|
|
temp_wert = zustand_oder_none(k.hass, k.zuordnung.werte.AUSSENTEMP_SENSOR)
|
|
if temp_wert is not None:
|
|
try:
|
|
aussentemp = float(temp_wert)
|
|
except (TypeError, ValueError):
|
|
pass
|
|
|
|
jetzt = datetime.datetime.now(datetime.UTC)
|
|
heute = datetime.date.today().isoformat()
|
|
await k.ablage.batterieverlauf_tageswert_aktualisieren(
|
|
heute, jetzt.isoformat(), spannung, aussentemp
|
|
)
|
|
await k.batterieverlauf_veroeffentlichen()
|
|
_LOGGER.debug("Batteriespannung erfasst (%s: %s V)", heute, spannung)
|
|
|
|
|
|
async def eintrag_loeschen(k: Koordinator, datum: str | None) -> None:
|
|
"""Löscht einen Tageseintrag aus der Messwertliste (Wischen zum Löschen).
|
|
|
|
Entfernt nur diesen einen Tag - min/max anderer Tage bleiben unberührt,
|
|
das Diagramm zeichnet beim nächsten Aufruf einfach ohne diesen Punkt."""
|
|
if not datum:
|
|
_LOGGER.warning("batterieverlauf_loeschen ohne datum aufgerufen")
|
|
return
|
|
if await k.ablage.batterieverlauf_eintrag_loeschen(datum):
|
|
await k.batterieverlauf_veroeffentlichen()
|
|
_LOGGER.info("Batteriespannungs-Tageseintrag %s gelöscht", datum)
|
|
else:
|
|
_LOGGER.warning("Batteriespannungs-Tageseintrag %s nicht gefunden", datum)
|