17149937a6
Fünf vom Nutzer angeforderte Erweiterungen in einer Runde:
- Batteriespannungs-Kachel bekommt eine Messwertliste (Datum, Uhrzeit,
Spannung, optional Außentemperatur über den neuen AUSSENTEMP_SENSOR),
erreichbar über ein neues list-s-Symbol in der Diagramm-Kachel. Werte
über AGM_RUHE_MAX_V (12,8 V) sind keine Ruhespannung, sondern
Lichtmaschinenspannung - die Zeile markiert das jetzt mit
"Generatorspannung" statt es unkommentiert als Messwert auszugeben.
- Jede Zeile der neuen Liste wischbar zum Löschen (neuer Dienst
batterieverlauf_loeschen), über dieselbe Wisch-Mechanik wie Fahrten/
Tankvorgänge in beiden Oberflächen.
- Batteriespannungs-Diagramm im Panel war auf großen Bildschirmen (≥860px,
Spaltenlayout) stark in die Breite gezogen (preserveAspectRatio="none"
bei fester Höhe) - gedeckelt wie die dort bereits vorhandenen Popups.
- Statistik-Tab-Symbol in beiden Oberflächen durch das Audi-CI-Symbol
polls-s ersetzt.
- Neue Möglichkeit, einen Reifensatz zu archivieren ("Neue Räder
anlegen"): der aktuelle Stand (km, Marke, Modell, DOT, Maße, Solldruck,
Kommentar) wandert in ein Archiv, der laufende Satz beginnt bei 0 km neu.
Archiv als aufklappbare Übersicht mit voller Bearbeitungsmöglichkeit,
über drei neue, bewusst nicht über profilSchreiben laufende Dienste
(reifen_archivieren/-aktualisieren/-loeschen) - aus demselben Grund wie
reifen_wechseln: kein im Browser gehaltener Stand darf einen
zwischenzeitlich fortgeschriebenen km-Wert überschreiben.
Live im Testcontainer geprüft (erstmals über :18123 statt :8123 erreichbar)
und dabei zwei echte Layout-Fehler gefunden, die kein Compile-/Testlauf
sehen konnte: die Archiv-Eingabefelder waren durch ein fälschlich
verwendetes .mitEinheit (feste 96px-Breite, eigentlich für Zahl+Einheit
gedacht) abgeschnitten ("Continenta" statt "Continental"), und die
Kilometerzahl in der eingeklappten Archiv-Zeile war klein an das Datum
gequetscht statt wie der Satzname lesbar. Beides behoben, live erneut
bestätigt.
Backend: py_compile clean, services.yaml ergänzt. Panel: node --check
clean. companion-app: tsc/Testsuite (146/146)/Build/OTA-Bündel alle grün.
Manifest 2026.8.25.2 → .8, jeder Neustart im Testcontainer sauber.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
94 lines
3.7 KiB
Python
94 lines
3.7 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. 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.
|
|
|
|
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__)
|
|
|
|
|
|
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
|
|
|
|
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)
|