- 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).
64 lines
2.5 KiB
C++
64 lines
2.5 KiB
C++
// Публичная сессия fgl-aircon: обёртка над ayla-сессией с таблицами свойств
|
||
// шаблонов, конверсиями и кэшем значений.
|
||
#pragma once
|
||
|
||
#include "fgl-aircon/templates.hpp"
|
||
#include "fgl-aircon/types.hpp"
|
||
|
||
namespace fgl::aircon {
|
||
|
||
// Глобальный приёмник логов ядра (nullptr — отключено). Быстрый, реентерабельный.
|
||
// КОНТРАКТ: вызывать ДО create() сессий; не менять при живых сессиях.
|
||
using LogSink = void (*)(int level, const char* msg, size_t len, void* ctx);
|
||
void set_log_sink(LogSink sink, void* ctx);
|
||
void set_log_level(int min_level); // 0=debug..3=error, default 1
|
||
|
||
class Session {
|
||
public:
|
||
// Создаёт сессию (одноразовые аллокации). nullptr при некорректном конфиге.
|
||
static Session* create(const Config& cfg, const Callbacks& cbs);
|
||
~Session();
|
||
|
||
Session(const Session&) = delete;
|
||
Session& operator=(const Session&) = delete;
|
||
|
||
// Запуск (httpd + сессионный поток). false — ошибка bind/listen.
|
||
bool start();
|
||
// Штатное завершение: DELETE-команда + notify, ожидание выдачи ≤2с.
|
||
void stop();
|
||
|
||
State state() const;
|
||
Error last_error() const;
|
||
|
||
// ---- Управление свойствами (потокобезопасны; очередь с coalescing) ----
|
||
// set_int/set_bool: read-only свойства и свойства не из шаблона → false.
|
||
// Значение клампится по диапазону (override), конверсия from_input.
|
||
bool set_int(Prop prop, int64_t value);
|
||
bool set_bool(Prop prop, bool value);
|
||
bool set_string(Prop prop, const char* value); // только строковые
|
||
|
||
// Запросить обновление (ответ придёт on_property с cmd_id).
|
||
bool get_prop(Prop prop);
|
||
|
||
// Пакет команд: один local_reg notify=1 на commit.
|
||
bool batch_begin();
|
||
bool batch_commit();
|
||
bool batch_abort();
|
||
|
||
// Кэш значений (обновляется push'ами; set_* — оптимистично).
|
||
bool cached(Prop prop, Value* out) const;
|
||
|
||
// Телеметрия.
|
||
uint32_t rekey_count() const;
|
||
uint32_t pushes_ok() const;
|
||
uint32_t pushes_bad() const;
|
||
uint32_t commands_served() const;
|
||
|
||
private:
|
||
Session();
|
||
struct Impl;
|
||
Impl* impl_;
|
||
};
|
||
|
||
} // namespace fgl::aircon
|