petr.polezhaev
397be6236d
ha(H1): ниты повторного ревью — гарантия destroy при повторном close, rate-limit warn
...
- close() из другого потока после close из reader-колбэка теперь джойнит
reader (гарантия, что destroy завершён к возврату);
- предупреждения о переполнении очередей не чаще 1/30 с;
- events_dropped сохраняет последнее значение после close;
- find_library выбирает .so по версии (а не по длине имени).
2026-09-29 11:55:36 +03:00
petr.polezhaev
b84bd8d555
ha(H1): исправления по ревью — жизненный цикл сессии, самодостаточный wheel
...
- C1: единственный владелец stop+destroy — reader-поток; close() только
выставляет флаг и ждёт; повторный close и close из колбэка безопасны
(регресс-тесты; TSan на close с мёртвым модулем — 0 гонок)
- M1: wheel собирается с bundled mbedtls (нет внешней soname mbedcrypto);
попутно исправлена bundled-ветка CMake (-lSTATIC)
- C-API: счётчики потерянных событий/логов, лог-кольцо без union-балласта,
атомарные fn/ctx лог-синка
- provision: валидация формата облачных ответов; CLI: человеческие ошибки
(exit 2), --out с правами 0600, console_script pyfglair
- упаковка: MANIFEST.in (sdist с C++-исходниками), очистка stale .so,
readme в метаданных; find_library без ложных .bak
- тесты: close-сценарии, доставка логов, ошибки CLI/provision, C-API очередь
2026-09-29 11:48:32 +03:00
petr.polezhaev
0292404756
ha(H1): pyfglair — cffi-ядро (очередь событий), wheel, CLI discover/monitor
...
- CMake: shared-таргет fgl-aircon-shared (FGL_BUILD_SHARED, PIC, SOVERSION)
- C-API: fgl_prop_raw_range + кольцевые очереди событий/логов
(fgl_session_poll/wait_events, fgl_log_poll/wait_events): прямые колбэки
из потоков ядра со стеком 8 КБ небезопасны для интерпретатора Python
- pyfglair: _corebuild (cmake->wheel), _cffi (ABI), Session (reader-поток ->
loop.call_soon_threadsafe), templates (интроспекция C-таблиц), provision
(aiohttp), CLI discover/monitor + esphome-secrets
- setup.py/pyproject: платформенный wheel py3-none-linux_x86_64 с .so
- tests/pyfglair: templates, provision (мок-облако), session + CLI против
mock_ac.py; scripts/py-ci.sh; ci.sh запускает python-часть
2026-09-29 11:31:57 +03:00
petr.polezhaev
97842276c8
core(M4): полировка по нитам финального ревью
...
- fglair-discover: fchmod 0600 и при перезаписи существующего --out.
- fglctl: #include <cstdlib>; точная проверка обрезки config
(n == sizeof-1 && !feof); валидация 'monitor <sec>' (endptr/errno).
- docs: отчёт soak — формулировка «ответы на batch GET»; индекс reports.
Ревью M4 независимым агентом: 2 круга, APPROVED.
2026-09-29 01:30:30 +03:00
petr.polezhaev
31cd56f082
core(M4): fglctl, fglair-discover, README библиотеки; M5 — вне скоупа core-релиза
...
- README.md (корень): сборка POSIX/ESP-IDF-компонентом, тесты, получение
ключа (fglair-discover), примеры fglctl; planned-компоненты помечены.
- examples/cli/fglctl.cpp: monitor/get/set/status на публичном API
(batch GET шаблона, конверсии, wait_online, логи в stderr, exit-коды;
сборка с -Wall -Wextra -Werror).
- tools/fglair-discover: облачный provisioning (eu/us/cn, endpoints и
app_id/secret из PROTOCOL §7), --format json|esphome-secrets, --out 0600,
обработка URLError/KeyError; stdlib-only.
- tests/tools/test_fglair_discover.py: мок-облако (http.server), 4 теста,
ctest tools_fglair_discover.
- docs/reports/M4_SOAK.md: 60-мин soak на AP-WC1E — 0 рассинхронов,
33/33 свойства (вкл. строковые), 273 опроса модуля, pushes_bad=0;
24-ч прогон — приёмочный шаг перед релизом.
- План: M4 ✅ ; M5 (FglHub/mDNS) — ВНЕ СКОУПА core-релиза.
- Гигиена: config_kata.json (корень+docs/legacy) в .gitignore; MQTT-креды
из docs/legacy/run.sh заменены плейсхолдером (история чистится отдельно).
- Фиксы ревью: mock арм fail-pushes после активации (флейк san-сборки);
fglctl: валидация strtoll (abc/99 — отказ, exit!=0), чтение config с
предупреждением об обрезке, Config{} вместо memset; discover: 0600.
CI: 11/11 ×3 (gcc-Rel, gcc-ASan/UBSan, clang); ESP-IDF esp32 build complete.
2026-09-29 01:16:58 +03:00
petr.polezhaev
fa1718f405
core(M3): aircon-слой — шаблоны A/B/F, конверсии+override, публичный API + C-API
...
- 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).
2026-09-28 20:16:54 +03:00
petr.polezhaev
17bea87fdf
core(M2): машина состояний сессии Ayla LAN + mock-модуль + интеграционные сценарии
...
- session.{hpp,cpp}: state machine (idle/registering/online/recovering/
offline/key_error); httpd-обработчики key_exchange (200/426/412, re-key
прозрачно), commands (одна команда, 206/200, envelope, глобальный seq_no),
datapoint (unpack -> PropertyEvent / 401+тишина 50с для re-key-восстановления);
сессионный поток: local_reg POST?dsn/PUT (local_ip_for), keep-alive, backoff
x1.6->60с, 503->offline/NoSlot, activation-timeout->recovering, delete_session
с ожиданием выдачи; очередь с coalescing + batch; телеметрия; колбэки из
двух потоков с задокументированным контрактом; буферы datapoint-пути в Impl.
- platform: local_ip_for (UDP-connect) posix+esp-idf; стек httpd 24576
(переполнение 16КБ поймано gdb на Release).
- mock_ac.py: мок-модуль, stdlib-only чистый python AES-256 (свёрстан с
pycryptodome); сценарии: 503, no-poll, rekey-every, stale-gap (эмуляция
'вернувшегося' приложения), fail-pushes (битая подпись), garbage-pushes
(обрыв блока), break-outbound (исходящий десинк -> модуль ре-кает на
local_reg, как probe1-3), push-every, fail-first-ke.
- session_runner + test_session_mock.py: 9 сценариев через ctest, включая
самосинхронизацию CBC и восстановление после исходящего десинка.
- Прибор AP-WC1E: активация <=1с; re-key семантика ИСПРАВЛЕНА по живым
тестам: re-key при зазоре local_reg >= ~44-50с (не по возрасту сессии!);
при честном keep-alive 15с сессия стабильна без re-key; PROTOCOL/LEGACY/
PLAN обновлены; восстановление = тишина >порога + возврат.
- CI: 7/7 x3 (gcc-Rel, gcc-ASan/UBSan, clang); ESP-IDF esp32 build complete.
Ревью под-агентом: 2 круга (стек httpd, залипание состояний, dangling cfg,
физика десинка) — APPROVED.
2026-09-27 14:56:47 +03:00
petr.polezhaev
fe3bda646f
docs: M0, M1 отмечены выполненными в плане библиотеки
2026-09-22 15:46:27 +03:00
petr.polezhaev
fd5f125d04
core(M1): ayla-криптография, конверт, JSON (jsmn), HTTP-клиент
...
- crypto: KDF Ayla (двойной HMAC, suffix 0x30/31/32; app/dev направления),
AES-256-CBC с непрерывной цепочкой (iv обновляется mbedtls на месте),
Java-паддинг >=1 NUL; mode-latch против misuse (encrypt|decrypt);
zeroize ключей при повторном init; векторы из APK (4 сессии × 4 сообщения,
включая legacy-приём без NUL) — scripts/gen_kdf_vectors.py.
- envelope: pack/unpack {"enc","sign"}; расшифровка (движение цепочки)
ДО проверки подписи; сравнение подписи в константном времени;
extract_seq_no — depth-1 сканер без лимита токенов (OOB после escape
исправлен, регресс-тесты по ASan-репро ревьюера).
- json: Writer (фикс. буфер, стек глубин, escape, ok()=false при
переполнении) + Doc на jsmn (64 токена, unescape, overflow-guard).
- httpc: блокирующий POST/PUT для local_reg (статус 200-599, дренаж,
shutdown перед close).
- third_party/jsmn (MIT, JSMN_STATIC).
- CMake: mbedtls системный (/usr/include/mbedtls3) или FetchContent;
IDF: PRIV_REQUIRES mbedtls.
- CI: 3 конфигурации — gcc-Release, gcc-Debug+ASan/UBSan, clang-Release;
6/6 тестов стабильно; ESP-IDF esp32 build complete.
Ревью под-агентом: 3 круга (OOB-блокер + тестовые флаки закрыты), APPROVED.
2026-09-22 15:46:18 +03:00
petr.polezhaev
e6f6e2d5f4
core(M0): монорепо-каркас — CMake (posix+esp-idf), платслой, лог, мини-httpd
...
- CMakeLists в корне: ветвление ESP_PLATFORM (idf_component_register,
lwip/esp_timer/esp_hw_support/pthread) / POSIX (статическая библиотека
fgl-aircon, C++20, -fno-exceptions -fno-rtti, -Werror).
- src/ayla/platform: сокеты/потоки/CSPRNG/время; posix (getrandom, poll,
pthread_join) и esp-idf (lwip_select, esp_fill_random, pthread-слой IDF);
tcp_shutdown/tcp_local_port/thread_join для управляемой остановки.
- src/ayla: log (sink, без printf); мини-httpd/1.1 (keep-alive, Content-Length,
лимиты заголовков/тела, ephemeral-порт, жизненный цикл с гарантией
завершения потока: shutdown(active)→join→close).
- tests/ayla: platform (join, loopback+shutdown) и httpd (404, keep-alive,
обработчик/парсинг, oversize-400, stop при живом соединении, стрим
заголовков). doctest через FetchContent.
- scripts/ci.sh: сборка+ctest. ESP-IDF v5.5.5 esp32: смоук-сборка с ядром
как компонентом — Project build complete.
Ревью под-агентом: 3 круга, все блокеры (жизненный цикл httpd) закрыты, APPROVED.
2026-09-22 00:27:33 +03:00
petr.polezhaev
301cf5cf70
docs: корректировки планов — монорепо, слои ayla/aircon, конверсии, приёмка
...
- PLAN_CORE: монорепозиторий (CMakeLists в корне; components/fglair,
custom_components/fglair, include/fgl-aircon, src/{ayla,aircon},
src/ayla/platform); логическое разделение ayla (протокол+цикл) /
aircon (конверсии+шаблоны+API); тесты зеркалят слои (tests/{ayla,aircon});
конверсии: шаблон / линейные коэффициенты / функция-указатель
(лямбды ESPHome); оценка httpd/json (jsmn вендор, свой мини-httpd на
BSD-сокетах, conan не нужен); README библиотеки в M4.
- PLAN_ESPHOME: host вместо ip_address (DNS + Ayla-mDNS :10276),
секреты в примерах, кастомные конверсии через !lambda, advanced-пример
(триггеры режимов + LVGL с пропусками), README-план, скрипт приёмки
(aioesphomeapi + HA REST).
- PLAN_HOME_ASSISTANT: шаг config flow с превью рассчитанных значений
шаблона (через cffi в C-ядро, без дублей), README с HACS-инструкцией
и заглушками под скриншоты с описаниями, приёмка (long-lived token).
- Убраны реальные dsn/ip/lanip_key/key_id из примеров; probe_mdns.py
принимает DSN аргументом.
2026-09-21 13:20:29 +03:00
petr.polezhaev
9469f0104c
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
petr.polezhaev
359203abfe
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