Ölwechsel/Inspektion-Anzeige repariert, Selbst-Update der Integration gebaut
Zwei getrennte Themen in einem Commit, beide in derselben Sitzung entstanden:
1. Ölwechsel/Inspektion wurden komplett ausgeblendet ("kein Eintrag im
Servicebuch"), sobald kein Servicebucheintrag vorlag - selbst wenn der
zugeordnete Sensor eine gültige Fälligkeit meldete. In beiden Frontends
prüfte die Anzeige nur den Servicebuch-Zweig, bevor sie die
Fahrzeugmeldung überhaupt las. Jetzt steht die Fahrzeugmeldung für sich;
fehlt zusätzlich ein Servicebucheintrag, übernimmt eine neue,
fahrtenlog-basierte Prognose (kmProTagAusFahrten()/meldungsPrognose())
die Hochrechnung statt der Servicebuch-Rate - deckelt auf die vom
Fahrzeug selbst gemeldete Zeitgrenze, falls zu wenig gefahren wird.
2. install.ps1 als Update-Weg wird von Windows Smart App Control blockiert,
ohne Umgehungsmöglichkeit. Die Integration lädt sich jetzt auf
Tastendruck selbst von Gitea (aktualisierung.py), verifiziert das
Manifest vor jedem Tausch und tauscht per os.rename mit automatischem
Rollback bei Fehlern - install.ps1 bleibt nur noch für die
Erstinstallation nötig. Zugangstoken über einen neuen OptionsFlow in
entry.options, nie in configuration.yaml.
Nebenbei: mehrere seit der HACS-Ausschluss-Entscheidung liegen gebliebene
falsche HACS-Referenzen in Code-Kommentaren und einem UI-Text korrigiert.
Details, Sicherheitsbegründung und Verifikationsstand in AGENTS.md,
Abschnitte I und J.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -15,7 +15,9 @@ nicht die Schema-Prüfung.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import datetime
|
||||
import json
|
||||
import logging
|
||||
from collections.abc import Callable, Coroutine
|
||||
from typing import Any
|
||||
|
||||
@@ -24,9 +26,19 @@ import voluptuous as vol
|
||||
from homeassistant.core import HomeAssistant, ServiceCall
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
|
||||
from . import belege, bilder, fahrterkennung, historienimport, reifen, screening, sicherung
|
||||
from . import (
|
||||
aktualisierung,
|
||||
belege,
|
||||
bilder,
|
||||
fahrterkennung,
|
||||
historienimport,
|
||||
reifen,
|
||||
screening,
|
||||
sicherung,
|
||||
)
|
||||
from .const import (
|
||||
BILDER_ORDNER,
|
||||
CONF_GITEA_TOKEN,
|
||||
D_BACKUP_JETZT,
|
||||
D_BACKUP_WIEDERHERSTELLEN,
|
||||
D_BELEG_HOCHLADEN,
|
||||
@@ -45,10 +57,14 @@ from .const import (
|
||||
D_TANKVORGANG_AKTUALISIEREN,
|
||||
D_TANKVORGANG_LOESCHEN,
|
||||
D_TANKVORGANG_MANUELL,
|
||||
D_UPDATE_INSTALLIEREN,
|
||||
D_UPDATE_PRUEFEN,
|
||||
DOMAIN,
|
||||
)
|
||||
from .koordinator import Koordinator
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
# Ein JSON-Feld darf als Zeichenkette oder schon ausgepackt ankommen: das
|
||||
# Panel schickt JSON.stringify(...), ein Aufruf aus einer Automation heraus
|
||||
# reicht dagegen naheliegenderweise die Struktur selbst durch.
|
||||
@@ -126,6 +142,8 @@ SCHEMATA: dict[str, vol.Schema] = {
|
||||
vol.Required("start"): cv.string,
|
||||
vol.Required("ende"): cv.string,
|
||||
}),
|
||||
D_UPDATE_PRUEFEN: vol.Schema({}),
|
||||
D_UPDATE_INSTALLIEREN: vol.Schema({}),
|
||||
}
|
||||
|
||||
Fabrik = Callable[[ServiceCall], Coroutine[Any, Any, None]]
|
||||
@@ -202,6 +220,59 @@ def registrieren(hass: HomeAssistant, k: Koordinator) -> None:
|
||||
"audi_dashboard_historienimport",
|
||||
)
|
||||
|
||||
async def update_pruefen(_aufruf: ServiceCall) -> None:
|
||||
"""Fragt bei Gitea nach, ob eine neuere Fassung vorliegt - ohne
|
||||
etwas herunterzuladen. Läuft nur auf Tastendruck, siehe
|
||||
aktualisierung.py's Moduldocstring."""
|
||||
token = k.entry.options.get(CONF_GITEA_TOKEN, "")
|
||||
jetzt = datetime.datetime.now(datetime.timezone.utc).isoformat()
|
||||
try:
|
||||
ergebnis = await aktualisierung.version_pruefen(hass, token, k.version)
|
||||
k.letzte_update_pruefung = {
|
||||
"verfuegbar": ergebnis["verfuegbar"],
|
||||
"version": ergebnis["version"],
|
||||
"geprueft_am": ergebnis["geprueft_am"],
|
||||
"installiert": False,
|
||||
"fehler": None,
|
||||
}
|
||||
except aktualisierung.AktualisierungsFehler as fehler:
|
||||
_LOGGER.warning("Update-Prüfung fehlgeschlagen: %s", fehler)
|
||||
k.letzte_update_pruefung = {
|
||||
"verfuegbar": False,
|
||||
"version": None,
|
||||
"geprueft_am": jetzt,
|
||||
"installiert": False,
|
||||
"fehler": str(fehler),
|
||||
}
|
||||
await k.app_version_veroeffentlichen()
|
||||
|
||||
async def update_installieren(_aufruf: ServiceCall) -> None:
|
||||
"""Lädt die neueste Fassung von Gitea und ersetzt den
|
||||
Integrationsordner. Home Assistant muss danach von Hand neu
|
||||
gestartet werden - kein automatischer Reload aus dem eigenen,
|
||||
noch laufenden Aufruf heraus, siehe aktualisierung.py."""
|
||||
token = k.entry.options.get(CONF_GITEA_TOKEN, "")
|
||||
jetzt = datetime.datetime.now(datetime.timezone.utc).isoformat()
|
||||
try:
|
||||
ergebnis = await aktualisierung.update_installieren(hass, token)
|
||||
k.letzte_update_pruefung = {
|
||||
"verfuegbar": False,
|
||||
"version": ergebnis["version"],
|
||||
"geprueft_am": jetzt,
|
||||
"installiert": True,
|
||||
"fehler": None,
|
||||
}
|
||||
except aktualisierung.AktualisierungsFehler as fehler:
|
||||
_LOGGER.warning("Update-Installation fehlgeschlagen: %s", fehler)
|
||||
k.letzte_update_pruefung = {
|
||||
"verfuegbar": (k.letzte_update_pruefung or {}).get("verfuegbar", False),
|
||||
"version": (k.letzte_update_pruefung or {}).get("version"),
|
||||
"geprueft_am": jetzt,
|
||||
"installiert": False,
|
||||
"fehler": str(fehler),
|
||||
}
|
||||
await k.app_version_veroeffentlichen()
|
||||
|
||||
bilder_ordner = hass.config.path(BILDER_ORDNER)
|
||||
|
||||
behandler: dict[str, Callable[[ServiceCall], Coroutine[Any, Any, None]]] = {
|
||||
@@ -245,6 +316,8 @@ def registrieren(hass: HomeAssistant, k: Koordinator) -> None:
|
||||
D_BACKUP_WIEDERHERSTELLEN: _als_dienst(
|
||||
lambda a: sicherung.wiederherstellen(k, dict(a.data))
|
||||
),
|
||||
D_UPDATE_PRUEFEN: update_pruefen,
|
||||
D_UPDATE_INSTALLIEREN: update_installieren,
|
||||
}
|
||||
|
||||
for name, funktion in behandler.items():
|
||||
|
||||
Reference in New Issue
Block a user