feat(iot_mqtt): 传感器MQTT主动上报改为双速率间隔上报

- 新增传感器数据缓存(_cached_sr), 0xC0帧到达时更新缓存, 不上报
- 根据各通道 variation 决定上报间隔:
  空闲态(diff < 10): 使用 g_report_cfg.interval 秒
  变化态(diff >= 10): 固定 300ms 快速上报
- interval=0 时自动退化为最小 1s 空闲间隔
- 断线时清缓存+复位计时, 重连后等新帧首发
- 消除对 g_pkg_uart_2.flag 的硬依赖, 从缓存自主定时上报

新增常量:
  IOT_MQTT_FAST_INTERVAL_MS     300
  IOT_MQTT_VARIATION_THRESHOLD  10
  IOT_MQTT_IDLE_INTERVAL_MIN_MS 1000
This commit is contained in:
wangfq
2026-07-13 10:57:40 +08:00
parent c2fb459a80
commit 403770e1c8
@@ -42,6 +42,17 @@ static uint32_t _iot_reconnect_deadline = 0;
static uint32_t _iot_reconnect_backoff = 0; static uint32_t _iot_reconnect_backoff = 0;
static uint32_t _iot_connect_start = 0; // TCP connect 开始时刻 static uint32_t _iot_connect_start = 0; // TCP connect 开始时刻
/*===========================================================================
* 传感器数据缓存 & 上报间隔控制
*===========================================================================*/
#define IOT_MQTT_FAST_INTERVAL_MS 300 // 变化态快速上报间隔 (ms)
#define IOT_MQTT_VARIATION_THRESHOLD 10 // diff 阈值: >= 此值进入快速上报
#define IOT_MQTT_IDLE_INTERVAL_MIN_MS 1000 // 空闲间隔最小 1s (防 interval=0 死锁)
static LUP_SensorReport _cached_sr; // 最新传感器数据缓存
static uint8_t _cached_sr_valid; // 缓存有效标志
static uint32_t _last_publish_ms; // 上次上报时刻 (ms)
/*=========================================================================== /*===========================================================================
* Buffers * Buffers
*===========================================================================*/ *===========================================================================*/
@@ -363,29 +374,71 @@ static void iot_process_recv(void) {
} }
/*=========================================================================== /*===========================================================================
* 传感器数据上报 * 传感器数据上报 (双速率: 空闲态按 interval 上报, 变化态 300ms 快速上报)
*
* Step 1 — 消费 Loop MCU 新帧 → 更新缓存
* Step 2 — 对所有通道检测 variation, 决定上报间隔
* Step 3 — 间隔门控: 时间到了才从缓存发布
*===========================================================================*/ *===========================================================================*/
void iot_mqtt_publish_sensor(void) { void iot_mqtt_publish_sensor(void) {
if (g_iot_state != IOT_STATE_READY) return; if (g_iot_state != IOT_STATE_READY) return;
if (!g_report_cfg.enable) return; if (!g_report_cfg.enable) return;
/* Reuse g_pkg_uart_2 sensor frame from Loop MCU */ /*--- Step 1: 消费 0xC0 帧 → 更新缓存 ---*/
if (g_pkg_uart_2.flag == 0) return; if (g_pkg_uart_2.flag != 0
if (g_pkg_uart_2.pkg[0] != 0x7F) return; && g_pkg_uart_2.pkg[0] == 0x7F
if (g_pkg_uart_2.pkg[3] != 0xC0) return; && g_pkg_uart_2.pkg[3] == 0xC0) {
LUP_SensorReport sr; LUP_SensorReport sr;
memset(&sr, 0, sizeof(sr)); memset(&sr, 0, sizeof(sr));
int ret = lup_parse_sensor_report(g_pkg_uart_2.pkg, g_pkg_uart_2.offset, &sr); int ret = lup_parse_sensor_report(g_pkg_uart_2.pkg, g_pkg_uart_2.offset, &sr);
if (ret != 0) { InitPkgUart(&g_pkg_uart_2); // 读完即清, 不持有
if (ret == 0) {
memcpy(&_cached_sr, &sr, sizeof(sr));
_cached_sr_valid = 1;
} else {
PRINT("IOT: sensor parse failed (%d)\n", ret); PRINT("IOT: sensor parse failed (%d)\n", ret);
InitPkgUart(&g_pkg_uart_2); }
return;
} }
/* 全通道一次性上报,字段按 DLD960_IoT_MQTT协议.md §5.2 V1.02: /* 尚无缓存数据 → 不发 */
ch, level, iscar, loop_ok, freq, diff, sens, cndtn, misc.{type,value} if (!_cached_sr_valid) return;
注意: mqttBuf 需 ≥ 1024 才能容纳 4 通道全字段封包 (~800 字节) */
/*--- Step 2: 判断是否进入变化态 (任一通道 diff >= 10) ---*/
uint32_t interval_ms;
uint8_t fast_mode = 0;
{
uint8_t i;
for (i = 0; i < _cached_sr.coil_count; i++) {
if (_cached_sr.coils[i].variation >= IOT_MQTT_VARIATION_THRESHOLD) {
fast_mode = 1;
break;
}
}
}
if (fast_mode) {
interval_ms = IOT_MQTT_FAST_INTERVAL_MS; // 300ms
} else {
/* 空闲态: 使用配置的 interval (秒→毫秒), 最小 1s */
uint32_t cfg_ms = (uint32_t)g_report_cfg.interval * 1000;
interval_ms = (cfg_ms >= IOT_MQTT_IDLE_INTERVAL_MIN_MS)
? cfg_ms : IOT_MQTT_IDLE_INTERVAL_MIN_MS;
}
/*--- Step 3: 间隔门控 ---*/
{
uint32_t now = mstick();
if (_last_publish_ms != 0
&& (now - _last_publish_ms) < interval_ms) {
return; // 未到间隔
}
_last_publish_ms = now;
}
/*--- Step 4: 构建 JSON → 发布 (字段与 V1.02 协议一致) ---*/
static char data_json[1024]; static char data_json[1024];
static char payload[1400]; static char payload[1400];
char *p = data_json; char *p = data_json;
@@ -395,11 +448,11 @@ void iot_mqtt_publish_sensor(void) {
uint8_t i; uint8_t i;
written = snprintf(p, remaining, "{\"channels\":["); written = snprintf(p, remaining, "{\"channels\":[");
if (written < 0 || written >= remaining) goto done; if (written < 0 || written >= remaining) return;
p += written; remaining -= written; p += written; remaining -= written;
for (i = 0; i < sr.coil_count; i++) { for (i = 0; i < _cached_sr.coil_count; i++) {
const LUP_CoilSensor *cs = &sr.coils[i]; const LUP_CoilSensor *cs = &_cached_sr.coils[i];
const char *misc_type_str = "time"; const char *misc_type_str = "time";
uint32_t misc_val = 0; uint32_t misc_val = 0;
@@ -421,7 +474,7 @@ void iot_mqtt_publish_sensor(void) {
cs->freq, cs->variation, cs->freq, cs->variation,
cs->sensitivity, cs->condition, cs->sensitivity, cs->condition,
misc_type_str, misc_val); misc_type_str, misc_val);
if (written < 0 || written >= remaining) goto done; if (written < 0 || written >= remaining) return;
p += written; remaining -= written; p += written; remaining -= written;
} }
@@ -437,9 +490,6 @@ void iot_mqtt_publish_sensor(void) {
snprintf(topic, sizeof(topic), "dld960/%s/dev", g_iot_dev_serial); snprintf(topic, sizeof(topic), "dld960/%s/dev", g_iot_dev_serial);
mqtt_publish(topic, payload, 0); mqtt_publish(topic, payload, 0);
} }
done:
InitPkgUart(&g_pkg_uart_2);
} }
/*=========================================================================== /*===========================================================================
@@ -519,6 +569,8 @@ void iot_mqtt_handle_sock_int(uint8_t socketid, uint8_t intstat) {
g_iot_state = IOT_STATE_DISCONNECTED; g_iot_state = IOT_STATE_DISCONNECTED;
g_iot_socket = 0xFF; g_iot_socket = 0xFF;
_iot_recv_len = 0; _iot_recv_len = 0;
_cached_sr_valid = 0; // 清缓存: 重连后等新帧
_last_publish_ms = 0; // 复位: 重连后立即首发
_iot_reconnect_backoff = IOT_MQTT_RECONNECT_MIN_MS; _iot_reconnect_backoff = IOT_MQTT_RECONNECT_MIN_MS;
_iot_reconnect_deadline = mstick() + _iot_reconnect_backoff; _iot_reconnect_deadline = mstick() + _iot_reconnect_backoff;
} }