- PROTOCOL.md: полная спецификация (KDF, envelope/CBC-цепочка, local_reg, key exchange, commands.json 206/200, datapoint push, тайминги, таблицы свойств шаблонов A/B/F, облачный provisioning). Факты из APK помечены [APK], проверенные живыми экспериментами на AP-WC1E — [ПРОВЕРЕНО НА ПРИБОРЕ]: mDNS только :10276; лимит 2 LAN-сессии (3-я -> 503); принудительный re-key при возрасте сессии >= ~44с (единственный механизм самолечения десинхрона — 400/401 модуль игнорирует); записи не эхируются; delete_session освобождает слот. - LEGACY_ANALYSIS.md: причины рассинхрона (keep-alive 1200с вместо 10-15с + seq_no-фильтр) и перегрузки модуля; требования к новой реализации. - PLAN_CORE_LIBRARY.md: план C++20-библиотеки fglair-core (Linux + ESP-IDF), ключ lanip_key считается статичным, ротация — только ошибка + ручной перепровижининг. - PLAN_HOME_ASSISTANT.md: pyfglair (cffi wheel) + custom component, облачный provisioning только в config flow, ключ виден в диагностике для копирования в ESPHome. - PLAN_ESPHOME.md: external component, только ESP-IDF framework. - tools/probe_reference.py: эталонный клиент протокола (проверен на приборе end-to-end); tools/probe_mdns.py — mDNS-проба. - legacy/: снимок скрипта (апстрим gyro-labs/AirCon, вложенный клон не версионируется); apk/*.apk исключены из версионирования.
147 lines
8.7 KiB
Markdown
147 lines
8.7 KiB
Markdown
# План: интеграция для 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 (перенос `legacy/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) |
|