- 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 исключены из версионирования.
8.7 KiB
План: интеграция для 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. Состав репозиториев
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.
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 — облачный (удобный):
- Пользователь вводит e-mail/пароль FGLair + регион EU/US/CN.
- Интеграция через
pyfglair.provisionполучает список устройств (name, model, ip, dsn, lanip_key, lanip_key_id) и показывает их. - Выбор устройства →
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)
- 24 ч непрерывной работы: 0 рассинхронов; в логе ядра — штатные re-key каждые 45–60 с; сущности обновляются < 1 с после изменений с пульта.
- Параллельная работа с приложением на телефоне: обе сессии живут (2 слота); без взаимных сбоев.
- Вкл/выкл питания модуля: восстановление ≤ 120 с (backoff).
- Burst 10 изменений уставки из UI: ≤ 2 local_reg notify.
key_error(симуляция смены lanip_key_id): repair отрабатывает.- Перезапуск HA: корректный delete_session, повторная регистрация.
8. Тесты
pytest+ mockpyfglair(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) |