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-часть
This commit is contained in:
2026-09-29 11:31:57 +03:00
parent 97842276c8
commit 0292404756
26 changed files with 2236 additions and 63 deletions
+51 -1
View File
@@ -12,7 +12,10 @@ extern "C" {
// Версия библиотеки.
const char* fgl_version(void);
// Логирование.
// Логирование. Логи ядра всегда пишутся в кольцевой буфер (см.
// fgl_log_wait_events) — sink лишь дополнительный прямой колбэк. Прямой
// колбэк вызывается из потоков ядра с малым стеком (session-поток — 8 КБ):
// вызывать из него Python нельзя; для cffi используйте очередь.
typedef void (*fgl_log_sink_fn)(int level, const char* msg, unsigned len,
void* ctx);
void fgl_log_set_sink(fgl_log_sink_fn sink, void* ctx);
@@ -130,6 +133,49 @@ typedef struct {
// Непрозрачная сессия (определение — в реализации).
typedef struct fgl_session fgl_session_t;
// ---------------------------------------------------------------------------
// Очередь событий (опросный транспорт для cffi/pyfglair).
// КОНТРАКТ: колбэки fgl_callbacks_t вызываются из потоков ядра с малым стеком
// (session-поток — 8 КБ), поэтому вызывать из них интерпретатор Python
// небезопасно. Вместо этого ядро складывает события/логи в ограниченные
// кольцевые буферы, а python-поток забирает их fgl_session_wait_events /
// fgl_log_wait_events. Колбэки fgl_callbacks_t при этом продолжают работать
// (для C/C++ потребителей).
// ---------------------------------------------------------------------------
typedef enum {
FGL_EVENT_STATE = 0,
FGL_EVENT_PROPERTY = 1,
} fgl_event_type_t;
typedef struct {
int level;
char msg[160];
} fgl_log_event_t;
typedef struct {
fgl_event_type_t type;
union {
struct {
fgl_state_t state;
fgl_error_t error;
} state;
fgl_property_event_t property;
fgl_log_event_t log;
} data;
} fgl_event_t;
// Неблокирующая выборка событий; возвращает число заполненных out
// (0..max_events). При переполнении буфера самые старые события теряются.
int fgl_session_poll_events(fgl_session_t* s, fgl_event_t* out, int max_events);
// Блокирующая выборка: ждёт событие/таймаут (timeout_ms; < 0 — бесконечно).
// Возвращает число заполненных out.
int fgl_session_wait_events(fgl_session_t* s, fgl_event_t* out, int max_events,
int timeout_ms);
// Логи ядра (общий кольцевой буфер; включается при создании C-API-сессии).
int fgl_log_poll_events(fgl_log_event_t* out, int max_events);
int fgl_log_wait_events(fgl_log_event_t* out, int max_events, int timeout_ms);
fgl_session_t* fgl_session_create(const fgl_config_t* cfg,
const fgl_callbacks_t* cbs);
void fgl_session_destroy(fgl_session_t* s);
@@ -156,6 +202,10 @@ int fgl_template_detect(const char* oem_model); // -1 — неизвестно
const char* fgl_prop_name(fgl_template_t t, fgl_prop_t prop); // NULL — нет
const char* fgl_prop_base_type(fgl_template_t t, fgl_prop_t prop);
int fgl_prop_read_only(fgl_template_t t, fgl_prop_t prop); // -1 — нет
// raw-диапазон свойства из таблицы шаблона: 1 — определён (min/max заполнены),
// 0 — диапазона нет, -1 — свойства нет в шаблоне.
int fgl_prop_raw_range(fgl_template_t t, fgl_prop_t prop, int64_t* min,
int64_t* max);
int64_t fgl_convert_to_display(fgl_template_t t, fgl_prop_t prop,
int64_t raw);
int64_t fgl_convert_from_input(fgl_template_t t, fgl_prop_t prop,