ha(H4): repair key_mismatch, диагностика для ESPHome, reconfigure, переводы
- repairs: issue key_mismatch (ERROR, fixable) при состоянии key_error, ConfirmRepairFlow, снятие issue при online/unload/remove - config flow: async_step_reconfigure (меню, prefill ручной формы, unique_id_mismatch, update_reload_and_abort) — путь «перепровижинировать» - diagnostics: config/esp_home (dsn/lanip_key/key_id/host для secrets.yaml) + esp_home_masked и redacted entry_data, runtime-снимок значений (raw/display) из кэша ядра - translations: issues.key_mismatch (title/description/fix_flow) en/ru, abort unique_id_mismatch/reconfigure_successful; тест согласованности strings↔en↔ru - FglairClient.events_dropped; mock_ac: параметр key_id в фикстуре - тесты: diagnostics, repairs issue+fix-flow, reconfigure (успех/чужое устройство), translations (45 components)
This commit is contained in:
@@ -8,7 +8,7 @@ from functools import partial
|
||||
from typing import Any
|
||||
|
||||
import voluptuous as vol
|
||||
from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
|
||||
from homeassistant.config_entries import ConfigEntry, ConfigFlow, ConfigFlowResult
|
||||
from homeassistant.helpers import selector
|
||||
|
||||
import pyfglair
|
||||
@@ -259,6 +259,29 @@ class FglairConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
self._devices: list[Device] = []
|
||||
self._pending_data: dict[str, Any] = {}
|
||||
self._trial_properties: dict[Any, Any] = {}
|
||||
self._reconfigure_entry: ConfigEntry | None = None
|
||||
|
||||
async def async_step_reconfigure(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> ConfigFlowResult:
|
||||
"""Повторная настройка (в т.ч. смена LAN-ключа после key_error)."""
|
||||
self._reconfigure_entry = self._get_reconfigure_entry()
|
||||
return await self.async_step_user()
|
||||
|
||||
def _reconfigure_suggestions(self) -> dict[str, Any] | None:
|
||||
entry = self._reconfigure_entry
|
||||
if entry is None:
|
||||
return None
|
||||
fields = (
|
||||
CONF_HOST,
|
||||
CONF_DEVICE_PORT,
|
||||
CONF_DSN,
|
||||
CONF_LANIP_KEY,
|
||||
CONF_LANIP_KEY_ID,
|
||||
CONF_NAME,
|
||||
CONF_MODEL,
|
||||
)
|
||||
return {key: entry.data[key] for key in fields if key in entry.data}
|
||||
|
||||
def _show_form(
|
||||
self,
|
||||
@@ -366,6 +389,8 @@ class FglairConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
if error is None:
|
||||
return await self.async_step_preview()
|
||||
errors["base"] = error
|
||||
if user_input is None and self._reconfigure_entry is not None:
|
||||
user_input = self._reconfigure_suggestions()
|
||||
return self._show_form(
|
||||
"manual", _manual_schema(), errors, user_input,
|
||||
exclude=(CONF_LANIP_KEY,),
|
||||
@@ -472,7 +497,10 @@ class FglairConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
async def _async_trial(self, data: dict[str, Any]) -> str | None:
|
||||
"""None — сессия поднялась; иначе ключ ошибки формы."""
|
||||
await self.async_set_unique_id(data[CONF_DSN], raise_on_progress=False)
|
||||
self._abort_if_unique_id_configured()
|
||||
if self._reconfigure_entry is not None:
|
||||
self._abort_if_unique_id_mismatch()
|
||||
else:
|
||||
self._abort_if_unique_id_configured()
|
||||
result: TrialResult = await self.hass.async_add_executor_job(
|
||||
partial(_run_trial, data)
|
||||
)
|
||||
@@ -488,4 +516,8 @@ class FglairConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
|
||||
def _create_entry(self, data: dict[str, Any]) -> ConfigFlowResult:
|
||||
title = data.get(CONF_NAME) or data[CONF_DSN]
|
||||
if self._reconfigure_entry is not None:
|
||||
return self.async_update_reload_and_abort(
|
||||
self._reconfigure_entry, title=title, data=data
|
||||
)
|
||||
return self.async_create_entry(title=title, data=data)
|
||||
|
||||
Reference in New Issue
Block a user