Files
fgl-aircon/custom_components/fglair/diagnostics.py
T
petr.polezhaev 43d3ff7dea ha(H4): исправления по ревью — маскировка ключа в дампе, reload-repair, reconfigure сохраняет поля
- major: diagnostics больше не содержит полный lanip_key (esp_home —
  маска, entry_data redacted); ключ для ESPHome — через reconfigure/CLI;
  план §3 синхронизирован; дамп при незагруженной записи не падает
- reconfigure: сохраняет listen_port/keepalive_ms и текущие overrides/
  temp_step; превью-дефолты подхватывают значения записи
- repair fix-flow: подтверждение перезагружает запись (issue снимается
  только когда сессия вышла из key_error; иначе создаётся заново)
- key_issue_id helper, использование async_remove_issue (мёртвый код),
  CONF_EMAIL/PASSWORD в TO_REDACT, placeholders в fix_flow, тест
  плейсхолдеров ru
- тесты обновлены (47 components)
2026-09-29 14:29:36 +03:00

98 lines
3.1 KiB
Python

"""Диагностика fglair: параметры устройства для проверки и поддержки.
Дамп redacted: lanip_key маскируется (HA-конвенция; дампы прикладывают в
issues). Полный ключ для secrets.yaml ESPHome берётся явным действием:
«Настроить заново» (reconfigure) на карточке интеграции или CLI
``python -m pyfglair discover`` на хосте HA.
"""
from __future__ import annotations
from typing import Any, Optional
from homeassistant.components.diagnostics import async_redact_data
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from pyfglair.templates import template_info
from .const import (
CONF_DEVICE_PORT,
CONF_DSN,
CONF_EMAIL,
CONF_HOST,
CONF_LANIP_KEY,
CONF_LANIP_KEY_ID,
CONF_LISTEN_PORT,
CONF_MODEL,
CONF_NAME,
CONF_PASSWORD,
CONF_TEMP_STEP,
CONF_TEMPLATE,
)
from .coordinator import FglairRuntime
REDACTED = "**REDACTED**"
TO_REDACT = {CONF_LANIP_KEY, CONF_PASSWORD, CONF_EMAIL}
def _masked(value: Any) -> Any:
if not isinstance(value, str) or len(value) <= 4:
return REDACTED
return f"{value[:4]}…{REDACTED}"
def _base_diagnostics(entry: ConfigEntry) -> dict[str, Any]:
data = entry.data
return {
"config": {
CONF_HOST: data.get(CONF_HOST),
CONF_DEVICE_PORT: data.get(CONF_DEVICE_PORT),
CONF_DSN: data.get(CONF_DSN),
CONF_NAME: data.get(CONF_NAME),
CONF_MODEL: data.get(CONF_MODEL),
CONF_TEMPLATE: data.get(CONF_TEMPLATE),
CONF_TEMP_STEP: data.get(CONF_TEMP_STEP),
CONF_LISTEN_PORT: data.get(CONF_LISTEN_PORT),
},
"esp_home": {
CONF_DSN: data.get(CONF_DSN),
CONF_LANIP_KEY: _masked(data.get(CONF_LANIP_KEY)),
CONF_LANIP_KEY_ID: data.get(CONF_LANIP_KEY_ID),
CONF_HOST: data.get(CONF_HOST),
},
"entry_data": async_redact_data(dict(data), TO_REDACT),
"overrides": data.get("overrides", {}),
}
async def async_get_config_entry_diagnostics(
hass: HomeAssistant, entry: ConfigEntry
) -> dict[str, Any]:
diag = _base_diagnostics(entry)
runtime: Optional[FglairRuntime] = getattr(entry, "runtime_data", None)
if runtime is None:
diag["runtime"] = {"loaded": False}
return diag
client = runtime.client
values: dict[str, Any] = {}
for info in template_info(client.template):
value = client.cached(info.prop)
if value is None:
continue
values[info.name] = {
"raw": value.int_value,
"display": runtime.conversions.to_display(
info.prop, value.int_value
),
}
diag["runtime"] = {
"loaded": True,
"state": client.state.name.lower(),
"last_error": client.last_error.name.lower(),
"events_dropped": client.events_dropped,
"values": values,
}
return diag