G780s 工作模式
G780s 是有人科技的 4G DTU 模块,在本系统中充当透明串口-MQTT 桥接器。STM32 通过 USART3(RS-485,115200 波特率)向 G780s 发送 JSON 文本行,G780s 将其发布到 MQTT 主题。
进入 AT 配置模式
G780s 从透明传输模式切换到 AT 配置模式需要特殊序列:
1. 串口静默约 1 秒
2. 发送 +++(无 \r\n)
3. 等待模块回复 a
4. 发送 a(无 \r\n)
5. 等待模块回复 +ok
6. 进入 AT 配置模式
退出配置模式使用 AT+Z\r\n(模块重启)。
关键 AT 配置命令
| 命令 | 用途 | 示例 |
|---|---|---|
AT+EDGERPTMOD=1 | 启用边缘采集模式 + JSON 组包 | 开启后 G780s 自动轮询 Modbus 从站并组包 |
AT+MQTTCFG | 配置 MQTT Broker 地址、Client ID、Keep-Alive | AT+MQTTCFG=mqtt.varka.cn,1883,FM002,60 |
AT+MQTTUSER | 配置 MQTT 用户名和密码 | AT+MQTTUSER=user,pass |
AT+MQTTCONN | 建立 MQTT 连接 | 连接后自动订阅下行主题 |
AT+SSLCFG | TLS 加密配置(规划中) | 切换到 8883 端口 + 证书 |
当前通信架构
实际实现中,G780s 工作在透明传输模式而非边缘采集模式。STM32 固件自行构建 JSON 文本,通过 USART3 发送给 G780s,G780s 作为透传桥将数据发布到 MQTT。
设备 ID 定义在固件中:
#define G780S_JSON_DEVICE_ID "FM002"
MQTT 主题:上行 device/FM002/up,下行 device/FM002/down。
MQTT 客户端配置
服务端使用 mqtt.js 连接 Mosquitto Broker:
// server/services/stm32-mill-api/src/config.js
url: env.MQTT_URL || "mqtt://mqtt.varka.cn:1883",
upTopic: env.MQTT_UP_TOPIC || "device/FM002/up",
downTopicTemplate: env.MQTT_DOWN_TOPIC_TEMPLATE || "device/{dev}/down",
服务端订阅上行主题(QoS 0),每收到一条遥测帧后:
- 解析 JSON(处理 G780s 可能的多行合并问题)
- 持久化到 MySQL
- 发布
cloud_ack到下行主题
下行命令格式
| 命令 | JSON 格式 |
|---|---|
| 继电器控制 | {"cmd":"relay_set","cmd_seq":100,"dev":"FM002","mask":3} |
| 上传周期 | {"cmd":"set_upload_period","cmd_seq":101,"dev":"FM002","seconds":10} |
| OTA 准备 | {"cmd":"ota_prepare","cmd_seq":102,"dev":"FM002"} |
| OTA 开始 | {"cmd":"ota_begin","cmd_seq":103,"dev":"FM002","session_id":"...","session_key":"...","image_size":12345,...} |
| OTA 数据块 | {"cmd":"ota_chunk","cmd_seq":104,"dev":"FM002","offset":0,"payload_len":512,"payload":"base64...",...} |
| OTA 提交 | {"cmd":"ota_commit","cmd_seq":105,"dev":"FM002"} |
设备侧通过 cmd_seq 字段实现命令幂等性。
TLS 加密
当前 MQTT 连接使用明文 1883 端口。TLS 加密已在规划中:
- Mosquitto Broker 启用 8883 端口 + Let’s Encrypt 证书
- G780s 通过
AT+SSLCFG切换到 TLS 模式 - 服务端 URL 变更为
mqtts://mqtt.varka.cn:8883
证书配置需要在 G780s 中导入 CA 证书,使用 PEER 或 ALL 验证模式。
上行遥测帧格式
STM32 固件在 G780s_PrepareTelemetryFrame() 中构建遥测 JSON:
{
"t": "tele",
"dev": "FM002",
"ts": 12345,
"seq": 42,
"temp": [null, null, null, 23.4],
"weight": 1200,
"flow": 12.30,
"total": 1234.567,
"relay_do": 3,
"relay_di": 1,
"heart_count": 10,
"valid": 7,
"status": 15,
"running_slot": "A"
}
| 字段 | 类型 | 说明 |
|---|---|---|
t | string | 帧类型:tele(遥测)、ack(应答)、ota(升级)、alarm(告警) |
dev | string | 设备序列号 |
ts | number | 设备运行时间(秒),HAL_GetTick() / 1000 |
seq | number | 遥测推送序列号,每轮递增 |
temp | array | 4 通道 PT100 温度(°C),读取失败为 null |
weight | number | 重量(克),32 位有符号整数 |
flow | number | 瞬时流量(L/min),由 flow_rate / 100.0 换算 |
total | number | 累计流量(L),由 flow_total / 1000.0 换算 |
relay_do | number | 继电器输出位图(bit0 |
relay_di | number | 继电器输入位图 |
heart_count | number | 单调递增计数器,每个传感器周期 +1 |
valid | number | 有效性位图:bit0=PT100、bit1=称重、bit2=继电器 |
status | number | 系统状态位:bit0~2=传感器状态、bit3=自动模式 |
running_slot | string | 当前固件槽位:"A" 或 "B" |
ACK 帧
设备收到云端命令后回复:
{
"t": "ack",
"dev": "FM002",
"ts": 12345,
"seq": 42,
"cmd_seq": 100,
"cmd": "relay_set",
"result": "ok",
"relay_do": 3,
"relay_di": 1
}
Cloud ACK
服务端收到遥测帧后回复:
{
"t": "cloud_ack",
"ack_seq": 42,
"dev": "FM002",
"result": "ok"
}
设备侧通过 cloud_ack 确认遥测已送达,超时 5 秒未收到则重试。
服务端字段映射
服务端 state.js 根据 t 字段路由帧:"tele" 存储最新遥测并广播 WebSocket,"ack" 记录命令确认,"ota" 更新 OTA 进度。
数据库 measurements 表将 JSON 字段拆分为独立列:
| JSON 字段 | 数据库列 | 类型 |
|---|---|---|
dev | device_id | VARCHAR |
ts | payload_ts | INT |
seq | seq | INT |
flow | flow | DECIMAL |
total | total_value | DECIMAL |
weight | weight | INT |
relay_do | relay_do | INT |
relay_di | relay_di | INT |
temp | temperature_json | JSON |
| 完整帧 | payload | JSON |
唯一约束 (device_id, seq) 防止重复遥测数据入库。
设备侧 JSON 命令处理
固件 G780s_HandleJsonFrame() 逐行解析接收到的 JSON,按 cmd 字段分发:
relay_set:队列化继电器位图命令set_upload_period:修改遥测上传间隔ota_prepare:进入 Bootloader 升级模式ota_begin:初始化 OTA 会话(session_id、session_key、image_size、crc32、sha256、target_slot、chunk_size)ota_chunk:接收 base64 编码的固件数据块ota_abort:中止 OTA 会话ota_commit:完成 OTA(触发校验 + 复位)