# План: интеграция Home Assistant (`custom_components/fglair`) Аудитория — агенты-реализаторы. Протокол — `docs/PROTOCOL.md`; ядро — `docs/PLAN_CORE_LIBRARY.md` (`fgl-aircon`, C++20, монорепо: библиотека в корне, компонент HA здесь). ## 1. Архитектура ``` Home Assistant (custom component `fglair`) │ использует python-пакет pyfglair (cffi-bindings к libfgl-aircon.so) ▼ pyfglair (wheel: linux x86_64/aarch64; cffi; собирает библиотеку из корня репозитория через cmake) │ ▼ fgl-aircon (C++, корень монорепо) ←—— тот же код, что и на ESP32 (ESP-IDF) ``` Компонент — тонкий: переводит API библиотеки в сущности HA. Вся протокольная логика (сессия, шифрование, pacing, re-key, восстановление) — в C-ядре. Обоснование: переиспользование библиотеки (требование владельца); cffi-wheel — рабочий путь (HA-контейнеры x86_64/aarch64 debian; cibuildwheel). Fallback, если сборка wheel станет блокером: сборка .so при старте в docker (dev-режим). Чисто-Python повторная реализация протокола — запрещена. ## 2. Состав 1. **`pyfglair`** (python-пакет): * `pyfglair/_corebuild.py` — cmake-сборка при упаковке wheel; * `pyfglair/_cffi.py` — cffi-декларации поверх `include/fgl-aircon/c_api.h`; * `pyfglair/session.py` — обёртка `Session(cfg)`; колбэки ядра → asyncio через `loop.call_soon_threadsafe`; * `pyfglair/templates.py` — интроспекция шаблонов через cffi-вызовы `fgl_template_info_get` / `fgl_convert_to_display` (для превью в config flow; единый источник данных — C-таблицы, дублей нет); * `pyfglair/provision.py` — облачный discovery (перенос логики `docs/legacy/aircon/discovery.py` на современный aiohttp): e-mail/ пароль/регион → dsn, host/ip, oem_model, lanip_key, lanip_key_id; * CLI: `python -m pyfglair discover` / `monitor` / `--output esphome-secrets` (печать блока для secrets.yaml ESPHome). 2. **`custom_components/fglair/`**: ``` manifest.json # requirements: ["pyfglair>=1.0.0"], config_flow: true config_flow.py # flow + options + repair fglair_client.py # фоновый поток с FglSession coordinator.py # push-driven coordinator climate.py sensor.py switch.py select.py binary_sensor.py diagnostics.py # lanip_key/key_id/dsn видны для копирования в ESPHome translations/{en,ru}.json ``` ## 3. Config flow Шаг 1 — **подключение** (один из вариантов): * A (облачный): e-mail/пароль FGLair + регион → список устройств (name, model, host) → выбор. * B (ручной): host/dsn/lanip_key/lanip_key_id по полям, либо импорт `config_*.json` (миграция с legacy). Шаг 2 — **пробное подключение**: старт сессии, ожидание ONLINE ≤10 с, чтение базовых свойств. Ошибка → назад с сообщением. Шаг 3 — **выбор шаблона С ПРЕВЬЮ РЕЗУЛЬТАТОВ** (требование): после выбора шаблона (обычно определён по oem_model автоматически) — форма-предпросмотр рассчитанных значений через `pyfglair.templates` (вызовы в C-ядро): | Поле превью | Пример значения | |---|---| | hvac-режимы | off, cool, dry, fan, heat, auto (operation_mode 0–6) | | fan-режимы | quiet/low/medium/high/auto (0–4) | | Диапазон уставки | 16.0–30.0 °C, шаг 0.5 (adjust_temperature raw 160–300, ×0.1) | | Текущая температура | display_temperature 7000 → 20.0 °C | | Заслонки | vertical 0–4 (af_vertical_num_dir), horizontal 0–6 | | Битмаска capabilities | heat, cool, economy, powerful, min_heat, swing … | Пользователь оценивает корректность (сверяет с приложением FGLair) и подтверждает → создаётся `ConfigEntry`. При расхождении — возможность выбрать другой шаблон или задать конверсию коэффициентами (linear: num/den/offset) и диапазон вручную на этом же шаге. Repair (теоретический): `key_error` → «Ключ устройства изменён — перепровижинируйте» (повторный облако-вход по требованию). Облако в рантайме не используется, ключ статичен. **Диагностика**: device-страница показывает `dsn`, `lanip_key`, `lanip_key_id`, `host` — источник для копирования в secrets ESPHome. В redacted-дампе ключ маскируется. ## 4. Сущности Как раньше (climate: hvac/fan/swing/preset ECO-BOOST; current_temperature ← display_temperature; sensors: room temp, error_code, op_status-флаги; switch: economy/powerful/coil_dry/min_heat/outdoor_low_noise/ human_det_auto_save/wifi_led/indoor_fan_control; select: заслонки, demand_control; binary_sensor: connectivity). capabilities фильтруют режимы/пресеты. Записи — один `batch_commit()` на действие пользователя. ## 5. Runtime Один `FglairClient` на `ConfigEntry` (daemon-thread, сессия ядра); колбэки → asyncio → push-coordinator. Состояния: `online` → available; `recovering` → доступны (последние значения) + diagnostic-сенсор; `offline` → unavailable; `key_error` → unavailable + repair. Keep-alive 15 с (самолечение десинхрона ≤15 с). Выгрузка: `stop()` (delete_session). ## 6. README компонента (после реализации; для людей, коротко) Структура (`screenshots/step-N.png` — заглушки-плейсхолдеры, владелец заменит реальными скриншотами; рядом с каждой — описание что должно быть видно): 1. **Установка через HACS**: * HACS → ⋮ → Custom repositories → URL репозитория, категория Integration → Add. Скриншот: диалог добавления custom repository с заполненным URL и выбранной категорией Integration. * FGLair → Download → перезапуск HA. Скриншот: страница загрузки интеграции с кнопкой Download (версия видна). 2. **Добавление устройства**: Settings → Devices & Services → Add Integration → «FGLair». Скриншот: диалог поиска интеграции с введённым «FGLair» и выделенным результатом. 3. **Вход в облако** (шаг 1A): e-mail/пароль/регион. Скриншот: форма с заполненными регионом EU и e-mail (пароль скрыт). 4. **Выбор устройства**: список найденных кондиционеров. Скриншот: список с одним устройством (имя, модель, host). 5. **Проверка шаблона с превью** (шаг 3): Скриншот: форма превью — таблица рассчитанных значений (режимы, диапазон температур, пример конверсии температуры), кнопки Confirm/Change template. 6. **Готово**: карточка устройства со списком сущностей. Скриншот: страница устройства с созданными climate/sensor/switch сущностями. 7. **Где взять ключ для ESPHome**: диагностика устройства. Скриншот: страница Diagnostics с полями dsn/lanip_key/lanip_key_id. 8. Troubleshooting: 503 (оба слота заняты — телефон+ESP?), key_error, недоступность. ## 7. Приёмка (полуавтоматическая, `tests/acceptance/test_esphome_ha.py`) Совместно с ESPHome-компонентом (топология и детали — PLAN_ESPHOME §8). Со стороны HA скрипт использует **long-lived access token** (профиль → Security → Long-lived access tokens) и REST API: вызов сервисов `/api/services/climate/set_temperature|set_hvac_mode|set_fan_mode|set_swing_mode` и чтение `/api/states/`. Возможность подтверждена: это стандартный документированный механизм HA REST API, отдельная авторизация (OAuth-флоу) не нужна — пользователь просто создаёт токен и передаёт скрипту (`--ha-url`, `--ha-token`). Режимы: quick (матрица burst/не-burst, обе стороны, с возвратом) и `--long` (24 ч, ежечасное изменение с проверкой и возвратом, CSV-отчёт). Скрипт НЕ открывает собственную сессию к кондиционеру (оба слота заняты HA+ESP). ## 8. Этапы | # | Содержимое | |---|-----------| | H1 | wheel `pyfglair` (сборка из корня монорепо), cffi-обёртки, CLI discover/monitor | | H2 | компонент: manifest, config flow (облако/ручной/импорт) + пробное подключение | | H3 | шаг «превью шаблона» с ручными конверсиями; climate + сущности | | H4 | repair, диагностика (ключ для ESPHome), translations | | H5 | README с HACS-инструкцией и заглушками скриншотов (§6), скрипт приёмки (§7), HACS-релиз |