8c96d9b78e
Die Token liegen seit jeher in entry.options, geschrieben vom Options-Flow unter Einstellungen -> Geraete & Dienste -> Konfigurieren. Der Weg bleibt und ist der Rueckfall, wenn die App den Server nicht erreicht - genau der Fall, in dem ein abgelaufener Token auffaellt. Erreichbar ist er aber nur ueber HAs eigene Weboberflaeche; die iOS-App zeigt keine Konfigurationsdialoge. Die neue Kachel ist die Bedienflaeche dafuer, kein zweiter Speicherort. Der Wert kommt nie zurueck: veroeffentlicht werden nur "gesetzt/nicht gesetzt" und die letzten vier Zeichen (unter zwoelf Zeichen Laenge gar nichts). Auch das Protokoll bekommt ihn nicht, und das Panel leert das Eingabefeld sofort nach dem Absenden. Bewusst NICHT im Fahrzeugprofil: sicherung.py sichert fahrzeugprofil.json, und "Backup exportieren" laedt es als Datei auf das Geraet - ein Token dort wanderte in jede Sicherung und jede weitergegebene Datei. Ein Dienst statt zwei: zugang_setzen(dienst, token), leerer Text loescht. In der App nicht ueber die Warteschlange - ein Stunden spaeter nachgereichter Token ueberschriebe womoeglich einen inzwischen eingetragenen neuen. CONF_FLESPI_TOKEN ist neu und noch ohne Leser; der Flespi-Weg zum Auslesen der Geraetekonfiguration ist damit vorbereitet, aber nicht gebaut. Verifiziert: py_compile auf sechs Backend-Dateien, Panel als Modul geparst, companion-app tsc sauber und 179/179, audi_ha_test auf 2026.9.3.8 sauber gestartet. Live am laufenden Panel der ganze Kreis, Container hinterher wie vorgefunden: Wegwerf-Token gesetzt -> "gesetzt . ...0000", der Wert selbst taucht in den veroeffentlichten Attributen nirgends auf (darauf geprueft), ueber die Sicherheitsabfrage geloescht -> wieder "nicht gesetzt", der Gitea-Token unberuehrt. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
89 lines
3.6 KiB
Python
89 lines
3.6 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_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)
|
|
),
|
|
}),
|
|
self.config_entry.options,
|
|
),
|
|
)
|