fa1718f40520b5ceb577314b72447aa9f1f5f6c5
- include/fgl-aircon: types.hpp (Prop/State/Error/Value/Template/ Conversion-linear-custom/PropOverride/Config с задокументированными lifetime-контрактами), templates.hpp (PropInfo-таблицы, интроспекция, конверсии c контрактом Linear num/den!=0), session.hpp (Session: set_int/bool/string, get_prop, batch, cached, set_log_sink с контрактом), c_api.h (extern "C" для cffi/pyfglair). - src/aircon: tables.cpp (шаблоны A=33/B=20/F=34 по PROTOCOL §8.2, template_detect + template_is_known; конверсии: default тождественно, DisplayTemperature raw 0.01°C(+5000)→API 0.1°C; linear с инверсией raw=(api-offset)*den/num и насыщением __builtin_*_overflow; custom fn; af_*_swing base_type integer, kind bool), session.cpp (маппинг имя↔Prop, коэрсинг int-push к kBool по таблице, кэш со спинлоком, оптимистичный кэш, валидация overrides: терминатор/linear/custom_fn), c_api.cpp (шейм, static_assert'ы на все enum-значения, fgl_template_detect -1 для неизвестных). - ayla: set_property_string (Command.str_value, coalescing копирует строку в т.ч. в batch-ветке); kMaxQueue 48 + static_assert (полный батч A=33); commit_batch всегда ставит notify; oversized-строка дропает событие (кэш не затирается); max_queue default 40. - tests/aircon: test_tables (составы/атрибуты/дубли/template_detect/ swings-integer), test_convert (default/linear/custom/диапазоны/насыщение в обе стороны/UB-экстремумы), aircon_runner + test_aircon_mock (маппинг+конверсии+batch=1-notify с ожиданием async REG; SET+кэш+ RO/не-шаблон отказы+клэмпинг raw 450 на модуле; C-API smoke). - Прибор AP-WC1E: полный батч шаблона A одним notify — 28 int/bool свойств (DisplayTemperature 7000→200=20.0°C, DeviceCapabilities=5119), boolean SET (JSON true) принят, RO/клэмп/NOTMPL отказы корректны. - CI: 10/10 ×3 стабильно (3 полных прогона); ESP-IDF esp32 build complete. Ревью независимым агентом: 3 круга — B1 kMaxQueue<батча, B2 linear div/0, B3 c_api контракт -1, B4 batch-строки, BL1 INT64_MIN negation UB, BL2 DisplayTemperature экстремумы, flake aircon_mock — всё закрыто; APPROVED (условие круга 3: фикс + зелёный CI ×3).
aircon / FGLair local control
Реконструкция LAN-протокола FGLair (Fujitsu General, платформа Ayla) и планы монорепозитория стека локального управления кондиционером: базовая C++ библиотека + интеграции ESPHome и Home Assistant.
Состав репозитория (целевая структура)
CMakeLists.txt # базовая библиотека (корень)
include/fgl-aircon/ # публичный API (уровень aircon: конверсии, шаблоны)
src/ayla/ # протокол Ayla LAN + главный цикл сообщений
platform/{posix,esp-idf}/ # платформенный слой
src/aircon/ # конверсии, шаблоны A/B/F, реализация API
third_party/jsmn/ # вендоренный JSON-парсер (MIT)
components/fglair/ # ESPHome external component
custom_components/fglair/ # Home Assistant custom component
tests/{ayla,aircon}/ # тесты протокола / конверсий и шаблонов
tests/acceptance/ # полуавтоматическая приёмка ESPHome<->HA
tools/ # probe_reference.py, probe_mdns.py, fglair-discover
docs/ # документация (ниже) + материалы анализа
Документация
| Файл | Назначение |
|---|---|
PROTOCOL.md |
Спецификация LAN-протокола: шифрование, эндпоинты, машина состояний, тайминги, свойства FGLair. Для людей и агентов. Факты помечены [APK] / [LEGACY] / [ПРОВЕРЕНО НА ПРИБОРЕ] / [HYP]. |
LEGACY_ANALYSIS.md |
Разбор legacy-скрипта: что верно, баги, причины «рассинхронизации ключей» и перегрузки модуля. |
PLAN_CORE_LIBRARY.md |
План C++20-библиотеки fgl-aircon (Linux + ESP-IDF): слои ayla/aircon, конверсии, оценка httpd/json-библиотек, монорепо-структура. |
PLAN_HOME_ASSISTANT.md |
План HA-интеграции: pyfglair (cffi wheel), config flow с превью шаблона, HACS-README со скриншотами. |
PLAN_ESPHOME.md |
План ESPHome-компонента: host+DNS, секреты, кастомные конверсии-лямбды, advanced-пример, приёмка. |
legacy/ |
Изменённый legacy-скрипт (форк gyro-labs/AirCon / hisense_ac): main.py + пакет aircon/. Локальный config_kata.json не версионируется (содержит lanip_key). |
apk/ |
Материалы анализа APK FGLair 3.4.3 (manifest.json; .apk-бинарники лежат локально, не версионируются). |
Краткая выжимка протокола
- Модуль кондиционера (порт 80) сам подключается к серверу приложения (порт 10275):
local_reg.json(keep-alive/notify) →key_exchange.json→ pollcommands.json+ pushproperty/datapoint.json. - Шифрование: AES-256-CBC (no-padding, zero-pad) + HMAC-SHA256; ключи выводятся
из облачного
lanip_keyи двух пар (random, time). CBC-цепочка непрерывна в рамках сессии. - Ключевая механика надёжности (проверено на приборе): модуль игнорирует
400/401-ответы; единственное самолечение — принудительный re-key, который
модуль делает при получении
local_regдля сессии старше ≈44 с. Поэтому keep-alive должен быть 10–15 с — тогда любая рассинхронизация живет секунды, а не 20 минут (как в legacy-скрипте с интервалом 1200 с). - Максимум 2 LAN-сессии (телефон + сервер уживаются), третья — HTTP 503.
- Записи свойств не эхируются — состояние обновляется оптимистично, подтверждение через GET.
- Свойства FGLair (шаблоны A/B/F по oem_model):
operation_mode(0..6),fan_speed(0..4),adjust_temperature(×0.1 °C),display_temperature((v−5000)/100 °C), swing/заслонки, флаги economy/powerful/…, битмаскиop_status,device_capabilities. Полные таблицы — в PROTOCOL.md §8.
Ключевые решения (по уточнениям владельца)
- Монорепозиторий: библиотека в корне,
components/fglair(ESPHome),custom_components/fglair(HA); тесты зеркалят слои (tests/ayla,tests/aircon); библиотека логически разделена наsrc/ayla(протокол) иsrc/aircon(конверсии/шаблоны/API), публичный интерфейс —include/fgl-aircon/. - Конверсии свойств задаются шаблоном по умолчанию, коэффициентами
(linear) или функцией-указателем (ESPHome — лямбды, HA — коэффициенты
- превью рассчитанных значений при настройке).
lanip_keyстатичен (зашит в модуль; за 5 лет ротаций не было). Облако — только provisioning (HA config flow, CLIfglair-discover); для ESPHome ключ копируется из диагностики HA или CLI. При несовпаденииkey_id— устойчивая ошибка, лечение правкой конфига вручную.- ESPHome: везде ESP-IDF framework, подключение по
host(DNS/mDNS), все чувствительные значения — через!secret. - HTTP/JSON: собственный мини-httpd/httpc на BSD-сокетах (одна реализация для lwip/posix) + вендоренный jsmn; esp_http_server/cJSON/ArduinoJson отвергнуты (обоснование — PLAN_CORE §7). Conan не нужен.
- Приёмка: полуавтоматический скрипт
tests/acceptance/(HA long-lived token + REST, ESPHome через aioesphomeapi; quick/burst и 24-часовой режимы).
Порядок реализации
fgl-aircon(M0–M4) — ядро (ayla → aircon), mock-тесты; эталонtools/probe_reference.pyуже проверен на приборе.pyfglair+ HA-интеграция (H1–H5) — параллельно с E1–E2.- ESPHome-компонент (E1–E4).
- Приёмочные прогоны (quick + 24 ч), README компонентов.
- Уточнение оставшихся неизвестных (PROTOCOL.md §10) по мере эксплуатации.
Источники
- APK FGLair 3.4.3 (
apk/com.fujitsu.fglair.apk): классыcom.aylanetworks.aylasdk.lan.*,com.fujitsugeneral.aylasdk.*,com.cafbit.netlib.dns.NetThread, JS-бандлassets/www/dist/build.js. - Legacy-скрипт (
legacy/) — изменённый форк gyro-labs/AirCon (hisense_ac). - Живые эксперименты на AP-WC1E (сентябрь 2026): сессии, re-key, 401/400,
слоты/503, delete_session, записи, mDNS. Рабочие артефакты —
tools/.
Languages
Python
58.1%
C++
38.1%
CMake
1.5%
C
1.4%
Shell
0.9%