feat: 实现 sensor_report 主动上报功能

vd960DBN:
- 新增 g_report_active 全局标志控制传感器数据主动上报
- handle_report_config: 解析 active_report JSON 字段,设置/清除标志
- tcp_json_push_sensor: 检查 g_report_active 开关,仅在启用时推送

DBNetClient:
- tcp_json_client.py: 新增 report_config(active_report) 方法
- main.py: 线圈标签页添加"启用主动上报"复选框
- main.py: 注册 sensor_report push 处理器,实时显示推送数据
This commit is contained in:
wangfq
2026-07-02 13:42:59 +08:00
parent 615b369690
commit 8526023e06
3 changed files with 96 additions and 20 deletions

View File

@@ -22,6 +22,7 @@ class DBNetApp:
self.root.minsize(800, 600) self.root.minsize(800, 600)
self.client = DBNetClient(log_callback=self.log) self.client = DBNetClient(log_callback=self.log)
self.client.on_push("sensor_report", self.on_sensor_report)
self.client.on_push("loop_data", self.on_loop_data) self.client.on_push("loop_data", self.on_loop_data)
self.client.on_push("event_report", self.on_event_report) self.client.on_push("event_report", self.on_event_report)
@@ -196,31 +197,46 @@ class DBNetApp:
ttk.Separator(f, orient=tk.HORIZONTAL).grid(row=2, column=0, columnspan=2, ttk.Separator(f, orient=tk.HORIZONTAL).grid(row=2, column=0, columnspan=2,
sticky=tk.EW, pady=8) sticky=tk.EW, pady=8)
# Row 3: 灵敏度 # Row 2.5: 主动上报
ttk.Label(f, text="线圈灵敏度 (0x8A):", font=("", 10, "bold")).grid(row=3, column=0, sticky=tk.W) ttk.Label(f, text="主动上报 (sensor_report):", font=("", 10, "bold")).grid(row=3, column=0, sticky=tk.W)
sens_row = ttk.Frame(f) report_row = ttk.Frame(f)
sens_row.grid(row=4, column=0, columnspan=2, sticky=tk.W, pady=2) report_row.grid(row=4, column=0, columnspan=2, sticky=tk.W, pady=2)
ttk.Button(sens_row, text="读取灵敏度", command=self._do_loop_sens_read).pack(side=tk.LEFT, padx=2) self.report_var = tk.BooleanVar(value=False)
self.report_cb = ttk.Checkbutton(report_row, text="启用主动上报",
variable=self.report_var,
command=self._do_report_config)
self.report_cb.pack(side=tk.LEFT, padx=2)
self.report_status = ttk.Label(report_row, text="", foreground="gray")
self.report_status.pack(side=tk.LEFT, padx=5)
ttk.Separator(f, orient=tk.HORIZONTAL).grid(row=5, column=0, columnspan=2, ttk.Separator(f, orient=tk.HORIZONTAL).grid(row=5, column=0, columnspan=2,
sticky=tk.EW, pady=8) sticky=tk.EW, pady=8)
# Row 6: 参数 # Row 6: 灵敏度
ttk.Label(f, text="线圈参数 (0x63/0x64):", font=("", 10, "bold")).grid(row=6, column=0, sticky=tk.W) ttk.Label(f, text="线圈灵敏度 (0x8A):", font=("", 10, "bold")).grid(row=6, column=0, sticky=tk.W)
param_row = ttk.Frame(f) sens_row = ttk.Frame(f)
param_row.grid(row=7, column=0, columnspan=2, sticky=tk.W, pady=2) sens_row.grid(row=7, column=0, columnspan=2, sticky=tk.W, pady=2)
ttk.Button(param_row, text="查询参数", command=self._do_loop_param_query).pack(side=tk.LEFT, padx=2) ttk.Button(sens_row, text="读取灵敏度", command=self._do_loop_sens_read).pack(side=tk.LEFT, padx=2)
ttk.Label(param_row, text="参数设置通过 Raw JSON 标签页发送 loop_param_set。",
foreground="gray").pack(side=tk.LEFT, padx=10)
ttk.Separator(f, orient=tk.HORIZONTAL).grid(row=8, column=0, columnspan=2, ttk.Separator(f, orient=tk.HORIZONTAL).grid(row=8, column=0, columnspan=2,
sticky=tk.EW, pady=8) sticky=tk.EW, pady=8)
# Row 9: 参数
ttk.Label(f, text="线圈参数 (0x63/0x64):", font=("", 10, "bold")).grid(row=9, column=0, sticky=tk.W)
param_row = ttk.Frame(f)
param_row.grid(row=10, column=0, columnspan=2, sticky=tk.W, pady=2)
ttk.Button(param_row, text="查询参数", command=self._do_loop_param_query).pack(side=tk.LEFT, padx=2)
ttk.Label(param_row, text="参数设置通过 Raw JSON 标签页发送 loop_param_set。",
foreground="gray").pack(side=tk.LEFT, padx=10)
ttk.Separator(f, orient=tk.HORIZONTAL).grid(row=11, column=0, columnspan=2,
sticky=tk.EW, pady=8)
# Response display # Response display
self.loop_text = scrolledtext.ScrolledText(f, height=14, wrap=tk.WORD, self.loop_text = scrolledtext.ScrolledText(f, height=12, wrap=tk.WORD,
font=("Consolas", 9)) font=("Consolas", 9))
self.loop_text.grid(row=9, column=0, columnspan=2, sticky="nsew") self.loop_text.grid(row=12, column=0, columnspan=2, sticky="nsew")
f.rowconfigure(9, weight=1) f.rowconfigure(12, weight=1)
f.columnconfigure(0, weight=1) f.columnconfigure(0, weight=1)
return f return f
@@ -516,12 +532,49 @@ class DBNetApp:
self.raw_resp.insert(tk.END, f"Parse error: {e}\n") self.raw_resp.insert(tk.END, f"Parse error: {e}\n")
# Push handlers # Push handlers
def on_sensor_report(self, cmd, data):
"""接收设备主动上报的传感器数据"""
import json as _json
text = _json.dumps(data, indent=2, ensure_ascii=False)
self.log(f"<<< PUSH sensor_report")
# 显示在线圈参数标签页
self.root.after(0, self._show_sensor_push, text)
def on_loop_data(self, cmd, data): def on_loop_data(self, cmd, data):
self.log(f"<<< PUSH loop_data: {data}") self.log(f"<<< PUSH loop_data: {data}")
def on_event_report(self, cmd, data): def on_event_report(self, cmd, data):
self.log(f"<<< PUSH event_report: {data}") self.log(f"<<< PUSH event_report: {data}")
def _show_sensor_push(self, text):
"""在线圈标签页追加传感器推送数据"""
import time
self.loop_text.insert(tk.END,
f"--- PUSH {time.strftime('%H:%M:%S')} ---\n{text}\n\n")
self.loop_text.see(tk.END)
def _do_report_config(self):
"""上报开关切换"""
enabled = self.report_var.get()
self._bg_run(
lambda: self.client.report_config(enabled),
lambda r: self._show_report_config_result(r, enabled))
def _show_report_config_result(self, resp, enabled):
if isinstance(resp, Exception):
self.report_status.config(text=str(resp), foreground="red")
self.report_var.set(not enabled) # revert
else:
code = resp.get("code", -1)
if code == 0:
self.report_status.config(
text="✓ 已启用" if enabled else "✓ 已关闭",
foreground="green")
else:
self.report_status.config(
text=f"{resp.get('msg','')}", foreground="red")
self.report_var.set(not enabled) # revert
def main(): def main():
root = tk.Tk() root = tk.Tk()

View File

@@ -312,6 +312,15 @@ class DBNetClient:
{"auto_mode": auto_mode, {"auto_mode": auto_mode,
"channels": channels}) "channels": channels})
def report_config(self, active_report: bool = True) -> dict:
"""配置主动上报开关
active_report=True → 设备主动推送传感器数据 (sensor_report)
active_report=False → 停止主动上报
"""
return self._tcp.send_command("report_config",
{"active_report": active_report})
# Push # Push
def on_push(self, cmd: str, handler: callable) -> None: def on_push(self, cmd: str, handler: callable) -> None:
self._tcp.on_push(cmd, handler) self._tcp.on_push(cmd, handler)

View File

@@ -31,6 +31,7 @@ uint32_t g_json_auth_timer = 0;
uint8_t g_json_pwd_retry = 0; uint8_t g_json_pwd_retry = 0;
uint32_t g_json_lockout_timer = 0; uint32_t g_json_lockout_timer = 0;
TcpJsonPending g_json_pending = {0, 0, 0, "", 0}; TcpJsonPending g_json_pending = {0, 0, 0, "", 0};
uint8_t g_report_active = 0; // 0=不主动上报, 1=主动上报传感器数据
/*=========================================================================== /*===========================================================================
* Frame Receive Buffer (line-delimited JSON) * Frame Receive Buffer (line-delimited JSON)
@@ -549,17 +550,29 @@ static void handle_loop_param_query(uint8_t socket, uint32_t msg_id, const char
PRINT("JSON: loop_param_query sent\n"); PRINT("JSON: loop_param_query sent\n");
} }
/* 4.15 report_config */ /* 4.15 report_config — 配置主动上报开关 */
static void handle_report_config(uint8_t socket, uint32_t msg_id, const char *json) { static void handle_report_config(uint8_t socket, uint32_t msg_id, const char *json) {
char *data = json_get_data_str(json); char *data = json_get_data_str(json);
if (!data) { if (!data) {
json_send_error(socket, msg_id, "report_config", JSON_CODE_PARAM_ERR, "missing data"); json_send_error(socket, msg_id, "report_config", JSON_CODE_PARAM_ERR, "missing data");
return; return;
} }
// Store report config for future push support
// Parse active_report flag
reset_tmp();
simple_parse_json(data, "\"active_report\"", g_tmp_value);
if (strlen(g_tmp_value) > 0) {
if (strstr(g_tmp_value, "true")) {
g_report_active = 1;
} else {
g_report_active = 0;
}
}
free(data); free(data);
json_send_ok(socket, msg_id, "report_config", NULL);
PRINT("JSON: report_config (push not yet implemented)\n"); json_send_ok(socket, msg_id, "report_config",
g_report_active ? "{\"active_report\":true}" : "{\"active_report\":false}");
PRINT("JSON: report_config active_report=%d\n", g_report_active);
} }
/* 4.16 loop_version_query — 获取地感MCU版本号 (CMD 0x4A) */ /* 4.16 loop_version_query — 获取地感MCU版本号 (CMD 0x4A) */
@@ -1101,9 +1114,10 @@ void tcp_json_poll(void) {
* g_pkg_uart_2 that hasn't been consumed by BLE. * g_pkg_uart_2 that hasn't been consumed by BLE.
*===========================================================================*/ *===========================================================================*/
void tcp_json_push_sensor(void) { void tcp_json_push_sensor(void) {
// Check: socket active, authed, and data available // Check: socket active, authed, report enabled
if (g_json_socket_listen == 0xFF) return; if (g_json_socket_listen == 0xFF) return;
if (g_json_auth_state != JSON_STATE_AUTHED) return; if (g_json_auth_state != JSON_STATE_AUTHED) return;
if (!g_report_active) return; // 主动上报未开启
// Only proceed if g_pkg_uart_2 has data and it's a 0xC0 sensor report // Only proceed if g_pkg_uart_2 has data and it's a 0xC0 sensor report
if (g_pkg_uart_2.flag == 0) return; if (g_pkg_uart_2.flag == 0) return;