This commit is contained in:
aZholtikov committed 2026-10-31 09:25:15 +03:00
1 parent 30bbbc9303
commit 0daf4de19f
3 files changed
+71 -113

No files matched your search

+30 -57
View File
@@ -1,8 +1,3 @@
# esp_component_template
esp_component_template
```c
#include <stdio.h>
#include <string.h>
@@ -12,7 +7,7 @@ esp_component_template
#include "esp_event.h"
#include "zh_nrf24_gateway.h"
// #include "zh_nrf24_config.h"
#include "zh_nrf24_config.h"
static const char *TAG = "MAIN";
@@ -32,31 +27,23 @@ static const zh_nrf_gateway_config_t s_gw_config = {
.spi_clock_hz = 0,
};
static void dump_bindings(const char *reason)
static void handle_paired_event(const zh_nrf_gateway_binding_t *b)
{
zh_nrf_gateway_binding_t tmp[ZH_NRF_GATEWAY_MAX_BINDINGS];
size_t got = zh_nrf_gateway_bindings_get(tmp, ZH_NRF_GATEWAY_MAX_BINDINGS);
ESP_LOGI(TAG, ">>> SENSOR PAIRED: id=%u type=%u (%s)",
b->id, b->type,
zh_get_nrf24_sensor_type_name((zh_nrf24_sensor_type_t)b->type));
ESP_LOGI(TAG, "=== Bindings (%s): %u total ===", reason, (unsigned)got);
for (size_t i = 0; i < got; i++) {
ESP_LOGI(TAG, " [%u] id=%u type=%u (%s)",
(unsigned)i,
tmp[i].id, tmp[i].type,
zh_get_nrf24_sensor_type_name((zh_nrf24_sensor_type_t)tmp[i].type));
}
/* Здесь можно добавить:
* - публикацию в MQTT: "sensor/paired" {id, type};
* - сохранение метаданных во внешнюю БД;
* - запись в журнал / уведомление;
* - поиск пользователя, которому принадлежит новое устройство,
* и т.п.
*/
}
static void gateway_event_handler(void *arg,
esp_event_base_t base,
int32_t id,
void *event_data)
static void handle_sensor_data_event(const zh_nrf24_sensor_transmitted_data_t *d)
{
if (base != ZH_NRF_GATEWAY_EVENTS) return;
switch (id)
{
case ZH_NRF_GATEWAY_EVENT_SENSOR_DATA: {
const zh_nrf24_sensor_transmitted_data_t *d = event_data;
const char *name = zh_get_nrf24_sensor_type_name((zh_nrf24_sensor_type_t)d->type);
ESP_LOGI(TAG, "<<< sensor id=%d type=%s battery=%.2fV",
@@ -92,25 +79,27 @@ static void gateway_event_handler(void *arg,
default:
break;
}
break;
}
default:
break;
}
}
/* Пример: удаление одной привязки (из MQTT, кнопки, HTTP и т.п.) */
static void demo_manual_delete(void)
static void gateway_event_handler(void *arg,
esp_event_base_t base,
int32_t id,
void *event_data)
{
uint8_t id = 5;
uint8_t type = ZH_NRF24_SENSOR_BME280;
if (base != ZH_NRF_GATEWAY_EVENTS) return;
if (zh_nrf_gateway_binding_exists(id, type)) {
ESP_LOGI(TAG, "Binding {id=%u, type=%u} exists, deleting", id, type);
esp_err_t err = zh_nrf_gateway_binding_delete(id, type);
ESP_LOGI(TAG, "delete → %s", esp_err_to_name(err));
} else {
ESP_LOGW(TAG, "Binding {id=%u, type=%u} not found, nothing to do", id, type);
switch (id)
{
case ZH_NRF_GATEWAY_EVENT_SENSOR_DATA:
handle_sensor_data_event((const zh_nrf24_sensor_transmitted_data_t *)event_data);
break;
case ZH_NRF_GATEWAY_EVENT_SENSOR_PAIRED:
handle_paired_event((const zh_nrf_gateway_binding_t *)event_data);
break;
default:
break;
}
}
@@ -126,24 +115,8 @@ void app_main(void)
NULL, NULL));
ESP_ERROR_CHECK(zh_nrf_gateway_init(&s_gw_config));
dump_bindings("after init");
ESP_ERROR_CHECK(zh_nrf_gateway_start());
ESP_LOGI(TAG, "Gateway running: channel=%d, address=0x%06X",
GW_CHANNEL, GW_ADDRESS);
/* Здесь можно, например, ждать команд по MQTT/HTTP и вызывать:
*
* zh_nrf_gateway_binding_delete(id, type) — точное удаление
* zh_nrf_gateway_bindings_delete_by_id(id) — всё с этим id
* zh_nrf_gateway_bindings_delete_by_type(type) — всё этого типа
* zh_nrf_gateway_binding_clear_all() — полный сброс
* zh_nrf_gateway_binding_exists(id, type) — проверка
* zh_nrf_gateway_bindings_get(...) / _count() — чтение
*
* После удаления id сразу доступен для следующего pairing-запроса
* того же типа.
*/
}
```
+23 -42
View File
@@ -6,7 +6,12 @@
* Receives RF sensor telemetry and posts it as events on the default
* ESP event loop. Pairing is fully internal: the gateway allocates
* per-type device IDs, persists the binding table in NVS and sends
* ACK packets. No pairing event reaches the event loop.
* ACK packets.
*
* Events emitted:
* - ZH_NRF_GATEWAY_EVENT_SENSOR_DATA — sensor telemetry
* - ZH_NRF_GATEWAY_EVENT_SENSOR_PAIRED — a new {id, type} binding was
* created and the ACK was successfully delivered to the sensor
*
* Binding table semantics:
* - each binding is a pair {id, type};
@@ -38,8 +43,18 @@ ESP_EVENT_DECLARE_BASE(ZH_NRF_GATEWAY_EVENTS);
typedef enum
{
/** Sensor telemetry received (data: zh_nrf24_sensor_transmitted_data_t) */
/**
* Sensor telemetry received.
* Event data: zh_nrf24_sensor_transmitted_data_t
*/
ZH_NRF_GATEWAY_EVENT_SENSOR_DATA,
/**
* A new {id, type} binding was created (pairing succeeded and the
* ACK was delivered to the sensor).
* Event data: zh_nrf_gateway_binding_t
*/
ZH_NRF_GATEWAY_EVENT_SENSOR_PAIRED,
} zh_nrf_gateway_event_t;
typedef struct
@@ -68,61 +83,27 @@ esp_err_t zh_nrf_gateway_start(void);
/* ===================== BINDING TABLE API ===================== */
/**
* @brief Copy current bindings into @p buf.
*
* Thread-safe. Returns number of entries copied (≤ max_count and ≤
* current table size). Use with zh_nrf_gateway_bindings_count() to
* decide buffer size.
*/
size_t zh_nrf_gateway_bindings_get(zh_nrf_gateway_binding_t *buf, size_t max_count);
/** @brief Current number of bindings in the table. */
size_t zh_nrf_gateway_bindings_count(void);
/**
* @brief Check whether a {id, type} binding exists.
*
* @return true if the binding is present in the table
*/
bool zh_nrf_gateway_binding_exists(uint8_t id, uint8_t type);
/**
* @brief Delete a {id, type} binding.
*
* Composite key: both @p id AND @p type must match an existing entry.
* If only one of them matches, nothing is deleted and ESP_ERR_NOT_FOUND
* is returned. The id becomes immediately available for the next
* pairing request of the same type. The change is persisted to NVS.
* Composite key: both @p id AND @p type must match. If only one matches,
* nothing is deleted and ESP_ERR_NOT_FOUND is returned.
*
* @return ESP_OK on success
* @return ESP_ERR_NOT_FOUND no such {id, type} pair in the table
* @return ESP_ERR_INVALID_ARG id out of 1..254, or unknown type
* @return ESP_ERR_INVALID_STATE gateway not initialized
* @return other NVS error
* @return ESP_OK / ESP_ERR_NOT_FOUND / ESP_ERR_INVALID_ARG / ESP_ERR_INVALID_STATE / NVS error
*/
esp_err_t zh_nrf_gateway_binding_delete(uint8_t id, uint8_t type);
/**
* @brief Delete every binding whose id equals @p id (any type).
*
* Use when the same physical device changed its type and the old
* binding must be dropped regardless of the type field.
*
* @return Number of bindings deleted (≥ 0), or negative ESP error code
*/
/** Delete every binding whose id equals @p id (any type). Returns count, or -err. */
int zh_nrf_gateway_bindings_delete_by_id(uint8_t id);
/**
* @brief Delete every binding whose type equals @p type (any id).
*
* Use for mass-forget of one sensor category.
*
* @return Number of bindings deleted (≥ 0), or negative ESP error code
*/
/** Delete every binding whose type equals @p type (any id). Returns count, or -err. */
int zh_nrf_gateway_bindings_delete_by_type(uint8_t type);
/** @brief Remove all bindings (persisted). */
/** Remove all bindings (persisted). */
esp_err_t zh_nrf_gateway_binding_clear_all(void);
#ifdef __cplusplus
+18 -14
View File
@@ -68,7 +68,6 @@ static const char *TAG = "NRF_GW";
#define NVS_NAMESPACE "zh_gw"
#define NVS_KEY_BINDINGS "bindings"
/* Valid id range for allocation */
#define BINDING_ID_MIN 1
#define BINDING_ID_MAX 254
@@ -205,14 +204,13 @@ static esp_err_t nrf_irq_init(void)
/* ============================================================
* NVS BINDING TABLE
* ============================================================ */
static esp_err_t bindings_load(void)
{
nvs_handle_t h;
esp_err_t err = nvs_open(NVS_NAMESPACE, NVS_READONLY, &h);
if (err != ESP_OK) {
memset(&s_ctx.bindings, 0, sizeof(s_ctx.bindings));
return ESP_OK; /* empty table on first run */
return ESP_OK;
}
size_t size = sizeof(s_ctx.bindings);
@@ -253,7 +251,6 @@ static esp_err_t bindings_save(void)
return err;
}
/* Find first free id in [BINDING_ID_MIN, BINDING_ID_MAX] for @p type. */
static uint8_t bindings_alloc_id(uint8_t type)
{
for (uint16_t id = BINDING_ID_MIN; id <= BINDING_ID_MAX; id++) {
@@ -299,7 +296,6 @@ static esp_err_t bindings_delete(uint8_t id, uint8_t type)
/* ============================================================
* BINDING TABLE PUBLIC API
* ============================================================ */
size_t zh_nrf_gateway_bindings_get(zh_nrf_gateway_binding_t *buf, size_t max_count)
{
if (!buf || max_count == 0 || !s_ctx.bindings_mutex) return 0;
@@ -338,8 +334,6 @@ bool zh_nrf_gateway_binding_exists(uint8_t id, uint8_t type)
esp_err_t zh_nrf_gateway_binding_delete(uint8_t id, uint8_t type)
{
if (!s_ctx.initialized) return ESP_ERR_INVALID_STATE;
/* Argument validation */
if (id == 0 || id == 0xFF) return ESP_ERR_INVALID_ARG;
if (zh_get_nrf24_sensor_payload_size(type) == 0) return ESP_ERR_INVALID_ARG;
@@ -382,11 +376,8 @@ int zh_nrf_gateway_bindings_delete_by_id(uint8_t id)
xSemaphoreGive(s_ctx.bindings_mutex);
if (err != ESP_OK) return -(int)err;
if (deleted > 0) {
ESP_LOGI(TAG, "Deleted %d binding(s) with id=%u", deleted, id);
} else {
ESP_LOGW(TAG, "No bindings with id=%u", id);
}
if (deleted > 0) ESP_LOGI(TAG, "Deleted %d binding(s) with id=%u", deleted, id);
else ESP_LOGW(TAG, "No bindings with id=%u", id);
return deleted;
}
@@ -491,7 +482,6 @@ static bool send_pairing_ack(uint8_t req_type, uint16_t token, uint8_t new_id)
/* ============================================================
* ОБРАБОТКА ПАКЕТОВ
* ============================================================ */
static void handle_pairing_request(const uint8_t *data)
{
uint8_t req_type = data[0];
@@ -533,8 +523,22 @@ static void handle_pairing_request(const uint8_t *data)
xSemaphoreTake(s_ctx.bindings_mutex, portMAX_DELAY);
bindings_delete(new_id, req_type);
xSemaphoreGive(s_ctx.bindings_mutex);
} else {
return;
}
/* --- ACK delivered → binding is final. Notify the application. --- */
ESP_LOGI(TAG, "Pairing complete: id=%u type=%u", new_id, req_type);
zh_nrf_gateway_binding_t paired = {
.id = new_id,
.type = req_type,
};
esp_err_t post_err = esp_event_post(ZH_NRF_GATEWAY_EVENTS,
ZH_NRF_GATEWAY_EVENT_SENSOR_PAIRED,
&paired, sizeof(paired),
pdMS_TO_TICKS(100));
if (post_err != ESP_OK) {
ESP_LOGW(TAG, "esp_event_post(paired) failed: %s", esp_err_to_name(post_err));
}
}