Files
audi-app/custom_components/audi_dashboard/config_flow.py
T
tobias 4d4890034a Regler stellt den Schlaf-Timeout des Dongles (2026.9.3.10)
Der Regler "Fahrt beenden" ist jetzt eine Zahl fuer zwei Dinge: unsere eigene
Wartezeit bis zum Fahrtende und der Schlaf-Timeout des FMM003 (103). So lange
bleibt der Dongle wach und wartet darauf, dass es gleich weitergeht; danach
schlaeft er. Die 180 s Ignition OFF Delay laufen davor und bleiben unsichtbar -
sie werden nur von der Fahrtdauer abgezogen. Der Regler geht deshalb von 1 bis
60 in Einerschritten; das Geraet kennt kein Timeout 0.

flespi.py liest und schreibt die Geraete-Konfiguration. Drei Annahmen sind an
der echten API gefallen und stehen als Messung im Modulkopf: der Wert liegt in
current (nicht value), die Einstellung heisst sleep_mode mit dem Wert eine Ebene
tiefer unter mode, und ein PUT braucht {"properties": ..., "address": ...}.

Die eigene Auftrags-Warteschlange ist wieder entfallen. Sie war fuer "das Geraet
schlaeft" gebaut - das gilt aber nur fuer das Geraet, nicht fuer die
Schnittstelle: die vollstaendige Konfiguration kam herein, waehrend das Fahrzeug
seit dem Vortag stand. flespi puffert selbst (pending + address=connection), ein
zweites Auftragsbuch waere eine zweite Warteschlange fuer dieselbe Aufgabe.

Gegengelesen wird nach jedem Schreiben; als Erfolg zaehlt current ODER pending -
letzteres ist bei stehendem Fahrzeug der Normalfall.

Live gegen den echten Account belegt: Token sieht genau ein Geraet, 127
Einstellungen bei parkendem Fahrzeug gelesen, Regler 15 geschrieben und als
pending bestaetigt (Nachbarfelder unveraendert), zweiter Neustart ohne erneute
Anfrage.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 20:00:39 +02:00

94 lines
4.0 KiB
Python

"""Einrichtung über die Oberfläche (Einstellungen -> Geräte & Dienste ->
Integration hinzufügen -> Audi Dashboard).
Bewusst ohne Eingabefelder im Ersteinrichtungs-Schritt. Es gäbe genau eine
Sache zu fragen - welche Entität welche Rolle im Fahrzeug spielt -, und die
gehört nicht hierher: die Zuordnung wird im Setup-Menü der App selbst
vorgenommen, wo neben jedem Feld steht, wofür es gebraucht wird und was
passiert, wenn es leer bleibt. Sie hier abzufragen hieße, dieselbe Auswahl an
zwei Stellen zu pflegen - und die schlechtere von beiden zuerst zu zeigen.
Eine einzige Instanz, erzwungen über single_config_entry in manifest.json:
die App gehört zu genau einem Fahrzeug, und alle Bestände liegen unter einem
festen Pfad.
Der OptionsFlow unten ist die einzige Ausnahme: ein Gitea-Zugriffstoken für
das Selbst-Update (siehe aktualisierung.py) - ein echtes Geheimnis, das
deshalb in HAs eigenem, verschlüsseltem Config-Entry-Speicher landet
(entry.options), nicht in configuration.yaml.
"""
from __future__ import annotations
from typing import Any
import voluptuous as vol
from homeassistant.config_entries import ConfigEntry, ConfigFlow, ConfigFlowResult, OptionsFlow
from homeassistant.core import callback
from homeassistant.helpers import selector
from .const import CONF_FLESPI_GERAET, CONF_FLESPI_TOKEN, CONF_GITEA_TOKEN, DOMAIN
class AudiDashboardConfigFlow(ConfigFlow, domain=DOMAIN):
"""Ein Bestätigungsschritt, mehr braucht es nicht."""
VERSION = 1
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
if self._async_current_entries():
return self.async_abort(reason="single_instance_allowed")
if user_input is None:
return self.async_show_form(step_id="user")
return self.async_create_entry(title="Audi Dashboard", data={})
@staticmethod
@callback
def async_get_options_flow(config_entry: ConfigEntry) -> OptionsFlow:
return AudiDashboardOptionsFlow()
class AudiDashboardOptionsFlow(OptionsFlow):
"""Einstellungen -> Geräte & Dienste -> Audi Dashboard -> Konfigurieren.
Zwei Felder, beide freiwillig: der Gitea-Token fürs Selbst-Update und der
flespi-Token fürs Auslesen der Geräte-Konfiguration. Leer lassen schaltet
die jeweilige Funktion ab (aktualisierung.py verlangt einen nicht-leeren
Token, sonst gibt es eine verständliche Fehlermeldung statt eines
unbehandelten Fehlers).
Dieser Weg bleibt der Rückfall neben der Kachel „Zugänge" in App und Panel
(siehe zugaenge.py): er ist der einzige, der auch dann trägt, wenn die App
den Server gerade nicht erreicht - genau der Fall, in dem ein abgelaufener
Token auffällt. Beide schreiben in dieselben entry.options, es gibt keinen
zweiten Wahrheitsort."""
async def async_step_init(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
if user_input is not None:
return self.async_create_entry(title="", data=user_input)
return self.async_show_form(
step_id="init",
data_schema=self.add_suggested_values_to_schema(
vol.Schema({
vol.Optional(CONF_GITEA_TOKEN, default=""): selector.TextSelector(
selector.TextSelectorConfig(type=selector.TextSelectorType.PASSWORD)
),
vol.Optional(CONF_FLESPI_TOKEN, default=""): selector.TextSelector(
selector.TextSelectorConfig(type=selector.TextSelectorType.PASSWORD)
),
# Leer lassen, solange der Token genau ein Gerät sieht - dann
# ermittelt flespi.geraet_finden() die Nummer selbst. Sieht er
# mehrere, wird bewusst nicht geraten und die Nummer gehört
# hierher.
vol.Optional(CONF_FLESPI_GERAET, default=""): selector.TextSelector(),
}),
self.config_entry.options,
),
)