Files
fgl-aircon/docs/PLAN_HOME_ASSISTANT.md
Petr Polezhaev 024b290b89 docs: реконструкция LAN-протокола FGLair, анализ legacy, планы fglair-core/HA/ESPHome
- 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 исключены из версионирования.
2026-09-17 19:44:49 +03:00

8.7 KiB
Raw Blame History

План: интеграция для 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)