ha(H3): превью шаблона с конверсиями; climate и сущности

- config flow: шаг preview (шаблон A/B/F, диапазон/шаг уставки, линейные
  коэффициенты num/den/offset, текст-превью по данным trial: hvac/fan/
  swing/capabilities/текущая температура)
- coordinator: push-driven DataUpdateCoordinator (снимок кэша, доступность
  online/recovering, первичный GET-батч, один batch_commit на действие)
- overrides.py: ConversionSet (ручные линейные конверсии и диапазон поверх
  таблиц ядра, применяются в HA)
- entity.py: DeviceInfo/unique_id/доступность, capabilities-фильтры
- climate: hvac/fan/swing/vertical+horizontal swing/preset ECO-BOOST,
  уставка 16-30 °C (шаг по шаблону), current_temperature
- sensor: room_temperature, error_code, connection_state (диагностика)
- binary_sensor: connectivity + флаги op_status (PROTOCOL §8.4)
- switch: 8 флагов-свойств; select: положения заслонок 0..N-1
- тесты: превью/конверсии/ошибки диапазона, сущности против mock_ac
  (снимок, команды, capabilities-фильтр, ручная конверсия), ConversionSet
- mock_ac: --set NAME=VALUE (0b/0x) для сценариев
- план: demand_control отложен (семантика не зафиксирована)
This commit is contained in:
2026-09-29 12:44:34 +03:00
parent 29f62b639c
commit 3e0b6b3653
21 changed files with 1974 additions and 87 deletions
+28 -7
View File
@@ -5,16 +5,25 @@ import logging
from homeassistant import config_entries
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
import pyfglair
from .const import DOMAIN
from .coordinator import FglairCoordinator, FglairRuntime
from .fglair_client import FglairClient
from .overrides import ConversionSet
_LOGGER = logging.getLogger(__name__)
PLATFORMS: list[str] = []
PLATFORMS = [
Platform.CLIMATE,
Platform.SENSOR,
Platform.BINARY_SENSOR,
Platform.SWITCH,
Platform.SELECT,
]
_LOG_LEVELS = {
0: logging.DEBUG,
@@ -60,23 +69,35 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
finally:
hass.data[DATA_PENDING] -= 1
conversions = ConversionSet.from_entry(entry.data)
coordinator = FglairCoordinator(hass, client, conversions)
try:
await coordinator.async_config_entry_first_refresh()
except Exception:
await coordinator.async_shutdown()
await client.async_stop()
raise
clients[entry.entry_id] = client
entry.runtime_data = client
entry.runtime_data = FglairRuntime(client, coordinator, conversions)
if len(clients) == 1:
pyfglair.set_log_handler(_log_handler)
pyfglair.set_log_level(1)
if PLATFORMS:
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
return True
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
client: FglairClient = entry.runtime_data
await client.async_stop()
runtime: FglairRuntime = entry.runtime_data
unloaded = await hass.config_entries.async_unload_platforms(
entry, PLATFORMS
)
await runtime.coordinator.async_shutdown()
await runtime.client.async_stop()
clients: dict[str, FglairClient] = hass.data.get(DATA_CLIENTS, {})
clients.pop(entry.entry_id, None)
if not clients and not hass.data.get(DATA_PENDING, 0):
await hass.async_add_executor_job(pyfglair.set_log_handler, None)
return True
return unloaded