Files
fgl-aircon/docs/PLAN_HOME_ASSISTANT.md
Petr Polezhaev 790cee3c78 refactor: legacy и apk перенесены в docs/, дедупликация исходников legacy
- docs/legacy/: рабочая раскладка изменённого форка (main.py + пакет
  aircon/); плоские дубликаты .py удалены, вложенный .git клона удалён
  (это изменённая копия, а не чистый клон), __pycache__ и .gitignore
  апстрима убраны. Локальный config_kata.json не версионируется
  (содержит lanip_key устройства).
- docs/apk/: манифест APK; бинарники *.apk и icon.png не версионируются.
- Обновлены пути в документации и tools/.
2026-09-17 19:48:55 +03:00

147 lines
8.8 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 (`fglair` custom component)
Аудитория — агенты-реализаторы. Протокол — `docs/PROTOCOL.md`, библиотека —
`docs/PLAN_CORE_LIBRARY.md` (`fglair-core`, C++20).
## 1. Архитектура
```
Home Assistant (custom component `fglair`)
│ использует python-пакет pyfglair (cffi-bindings к libfglair-core.so)
▼
pyfglair (wheel: linux x86_64/aarch64; cffi; собирает fglair-core через cmake)
│
▼
fglair-core (C++) ←—— mock-тесты; тот же код, что и на ESP32 (ESP-IDF)
```
Компонент — тонкий: переводит API библиотеки в сущности HA. Вся протокольная
логика (сессия, шифрование, pacing, re-key, восстановление) — в C-ядре.
Обоснование: пользователь требует переиспользования библиотеки из п.2;
cffi-wheel — рабочий путь (HA-контейнеры: x86_64/aarch64 debian; cibuildwheel
покрывает). Fallback (если сборка wheel станет блокером): libfglair собирается
в docker при старте интеграции один раз (dev-mode) — не рекомендуется для
продакшна; чисто-Python повторная реализация протокола — запрещена (дубль
логики, расползание с ESP32-веткой).
## 2. Состав репозиториев
1. **`pyfglair`** (python-пакет):
* `pyfglair/_corebuild.py` — cmake-сборка при упаковке wheel;
* `pyfglair/_cffi.py` — cffi-декларации поверх `include/fgl/c_api.h`
(extern "C"-шейм ядра);
* `pyfglair/session.py` — pythonic-обёртка: `Session(cfg)`, колбэки ядра
мостятся в `asyncio` через `loop.call_soon_threadsafe`;
* `pyfglair/provision.py` — облачный discovery (перенос `docs/legacy/aircon/discovery.py`
на современный aiohttp): вход e-mail/пароль/регион → dsn, ip, oem_model,
lanip_key, lanip_key_id;
* CLI: `python -m pyfglair discover` / `python -m pyfglair monitor`.
2. **`ha-fglair`** (custom component, HACS-совместимый):
* `custom_components/fglair/…` (см. §4);
* `manifest.json`: `requirements: ["pyfglair>=1.0.0"]`, `domain: fglair`,
`config_flow: true`, `iot_class: local_push`.
## 3. Конфигурация (config flow)
Вариант A — облачный (удобный):
1. Пользователь вводит e-mail/пароль FGLair + регион EU/US/CN.
2. Интеграция через `pyfglair.provision` получает список устройств
(name, model, ip, dsn, lanip_key, lanip_key_id) и показывает их.
3. Выбор устройства → `ConfigEntry` (те же поля, что `config_kata.json`)
→ шаг «пробное подключение» (старт сессии, ожидание ONLINE ≤ 10 с).
Вариант B — ручной: ввод ip/dsn/lanip_key/lanip_key_id по полям или импорт
существующего `config_*.json` (миграция с legacy-скрипта).
Ключ считается **статичным** (см. PLAN_CORE_LIBRARY §8): облако используется
только здесь, при настройке. В рантайме — никогда.
Repair-флоу (редкий, теоретический):
* Состояние ядра `key_error` (несовпадение `key_id`) → repair «Ключ устройства
изменён — перепровижинируйте». Повторный вход в облако по требованию
пользователя, обновление полей ConfigEntry. Никаких автоматических
перечитываний облака.
**Диагностика**: Device-страница HA показывает `lanip_key`, `lanip_key_id`,
`dsn`, ip — чтобы пользователь мог скопировать их в конфиг ESPHome (см.
PLAN_ESPHOME). В redacted-дамп lanip_key маскируется, в полном — виден.
## 4. Структура компонента
```
custom_components/fglair/
manifest.json
config_flow.py # flow + options flow + repair
const.py
fglair_client.py # FglairClient: владеет FglSession (фоновый поток)
coordinator.py # push-driven coordinator (polling-интервал только watchdog)
climate.py # ClimateEntity
sensor.py # комнатная температура, error_code, op_status-флаги
switch.py # economy, powerful, coil_dry, min_heat, outdoor_low_noise,
# human_det_auto_save, wifi_led, indoor_fan_control
select.py # af_vertical/horizontal_direction (если N>1), demand_control
binary_sensor.py # connectivity
diagnostics.py
translations/{en,ru,...}.json
```
## 5. Маппинг сущностей (шаблон A; B/F — по capabilities)
**Climate**:
* HVAC: `OFF`↔`operation_mode=0`; `COOL/HEAT/DRY/FAN_ONLY/AUTO`↔3/6/4/5/2;
`turn_on` → `operation_mode=1`.
* `target_temperature` ↔ `adjust_temperature` (×0.1 °C, шаг 0.5 °C);
* `current_temperature` ← `display_temperature` ((v−5000)/100);
* `fan_mode` ↔ `fan_speed` (quiet/low/medium/high/auto);
* `swing_mode` ↔ `af_vertical_swing`+`af_horizontal_swing` (off/vertical/
horizontal/both);
* presets: `ECO`→economy_mode, `BOOST`→powerful_mode (взаимоисключающие);
* capabilities из `device_capabilities` скрывают недоступные режимы.
**Sensors**: room temp, error_code (с текстами), op_status (флаги defrost /
oil recovery / pump down / maintenance / check operation / запреты).
**Binary sensor**: connectivity (ONLINE). **Switch/Select** — по списку §4.
Записи идут batch'ем на действие пользователя (одно `batch_commit()` на вызов
`set_temperature`/`set_hvac_mode`/…) — ядро само склеит в один local_reg notify.
## 6. Runtime-модель
* Один `FglairClient` на `ConfigEntry`: фоновый daemon-thread с сессией ядра;
колбэки → `asyncio` → coordinator push-update.
* Состояния ядра транслируются: `online` → entities available; `recovering` —
доступны (последние значения), помечено diagnostic-сенсором; `offline` →
unavailable; `key_error` → unavailable + repair.
* Keep-alive/rotация ключей/переподключение — полностью в ядре (15 с;
самолечение десинхрона ≤15 с — PROTOCOL.md §4.4).
* Выгрузка: `stop()` (delete_session, освобождает слот на модуле).
## 7. Требования к надёжности (acceptance)
1. 24 ч непрерывной работы: 0 рассинхронов; в логе ядра — штатные re-key
каждые 45–60 с; сущности обновляются < 1 с после изменений с пульта.
2. Параллельная работа с приложением на телефоне: обе сессии живут (2 слота);
без взаимных сбоев.
3. Вкл/выкл питания модуля: восстановление ≤ 120 с (backoff).
4. Burst 10 изменений уставки из UI: ≤ 2 local_reg notify.
5. `key_error` (симуляция смены lanip_key_id): repair отрабатывает.
6. Перезапуск HA: корректный delete_session, повторная регистрация.
## 8. Тесты
* `pytest` + mock `pyfglair` (fake session, scripted callbacks): flow, entities,
repair, unload.
* Интеграционный тест с mock-модулем (`test/integration/mock_ac.py` ядра) через
настоящий wheel: полный цикл в CI.
* Ручной чек-лист на реальном приборе (совпадает с M5 ядра).
## 9. Этапы
| # | Содержимое |
|---|-----------|
| H1 | wheel `pyfglair`: сборка, cffi-bindings, обёртка Session, CLI discover/monitor |
| H2 | компонент: manifest, config_flow (облако + ручной + импорт), client/coordinator, climate |
| H3 | sensor/switch/select/binary_sensor, capabilities, translations, диагностика с lanip_key |
| H4 | repair-флоу, unload, тесты, публикация в HACS (custom) |