Files
fgl-aircon/docs/PLAN_HOME_ASSISTANT.md
T
petr.polezhaev 57ee555704 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)
2026-09-29 14:06:39 +03:00

165 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# План: интеграция 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`. Транспорт событий — C-очередь
(`fgl_session_wait_events`) и выделенный python-поток: прямые cffi-колбэки
из потоков ядра небезопасны (у session-потока стек 8 КБ — CPython
падает по stack overflow);
* `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` / `--format 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()` на действие пользователя.
Demand_control: семантика значений в PROTOCOL §8.3 не зафиксирована
(§10) — сущность не создаётся до уточнения; в H3 вместо неё
диагностический sensor состояния связи.
## 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/<entity_id>`. Возможность подтверждена: это
стандартный документированный механизм 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-релиз; публикация `pyfglair` на PyPI (manylinux x86_64/aarch64, cibuildwheel) — штатный installer HA резолвит `requirements` только оттуда |