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 исключены из версионирования.
This commit is contained in:
2026-09-17 19:44:49 +03:00
commit 024b290b89
25 changed files with 3904 additions and 0 deletions

104
legacy/control_value.py Normal file
View File

@@ -0,0 +1,104 @@
from .properties import (AcWorkMode, AirFlow, Economy, FanSpeed, FastColdHeat, Quiet, Power,
TemperatureUnit)
def clear_up_change_flags(control: int) -> int:
return control & 2868817502
def get_fan_speed(control: int) -> FanSpeed:
int_val = (control >> 1) & 15
return FanSpeed(int_val)
def set_fan_speed(control: int, value: FanSpeed) -> None:
int_val = value.value
return (control & ~31) | ((int_val << 1) | 1)
def get_power(control: int) -> Power:
int_val = (control >> 6) & 1
return Power(int_val)
def set_power(control: int, value: Power) -> None:
int_val = value.value
return (control & ~(3 << 5)) | (((int_val << 1) | 1) << 5)
def get_work_mode(control: int) -> AcWorkMode:
int_val = (control >> 9) & 7
return AcWorkMode(int_val)
def set_work_mode(control: int, value: AcWorkMode) -> None:
int_val = value.value
return (control & ~(15 << 8)) | (((int_val << 1) | 1) << 8)
def get_heat_cold(control: int) -> FastColdHeat:
int_val = (control >> 13) & 1
return FastColdHeat(int_val)
def set_heat_cold(control: int, value: FastColdHeat) -> None:
int_val = value.value
return (control & ~(3 << 12)) | (((int_val << 1) | 1) << 12)
def get_eco(control: int) -> Economy:
int_val = (control >> 15) & 1
return Economy(int_val)
def set_eco(control: int, value: Economy) -> None:
int_val = value.value
return (control & ~(3 << 14)) | (((int_val << 1) | 1) << 14)
def get_temp(control: int) -> int:
return (control >> 17) & 63
def set_temp(control: int, value: int) -> None:
return (control & ~(127 << 16)) | (((value << 1) | 1) << 16)
def get_fan_power(control: int) -> AirFlow:
int_val = (control >> 25) & 1
return AirFlow(int_val)
def set_fan_power(control: int, value: AirFlow) -> None:
int_val = value.value
return (control & ~(3 << 24)) | (((int_val << 1) | 1) << 24)
def get_fan_lr(control: int) -> AirFlow:
int_val = (control >> 27) & 1
return AirFlow(int_val)
def set_fan_lr(control: int, value: AirFlow) -> None:
int_val = value.value
return (control & ~(3 << 26)) | (((int_val << 1) | 1) << 26)
def get_fan_mute(control: int) -> Quiet:
int_val = (control >> 29) & 1
return Quiet(int_val)
def set_fan_mute(control: int, value: Quiet) -> None:
int_val = value.value
return (control & ~(3 << 28)) | (((int_val << 1) | 1) << 28)
def get_temptype(control: int) -> TemperatureUnit:
int_val = (control >> 31) & 1
return TemperatureUnit(int_val)
def set_temptype(control: int, value: TemperatureUnit) -> None:
int_val = value.value
return (control & ~(3 << 30)) | (((int_val << 1) | 1) << 30)