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-AliveAT+MQTTCFG=mqtt.varka.cn,1883,FM002,60
AT+MQTTUSER配置 MQTT 用户名和密码AT+MQTTUSER=user,pass
AT+MQTTCONN建立 MQTT 连接连接后自动订阅下行主题
AT+SSLCFGTLS 加密配置(规划中)切换到 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),每收到一条遥测帧后:

  1. 解析 JSON(处理 G780s 可能的多行合并问题)
  2. 持久化到 MySQL
  3. 发布 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"
}
字段类型说明
tstring帧类型:tele(遥测)、ack(应答)、ota(升级)、alarm(告警)
devstring设备序列号
tsnumber设备运行时间(秒),HAL_GetTick() / 1000
seqnumber遥测推送序列号,每轮递增
temparray4 通道 PT100 温度(°C),读取失败为 null
weightnumber重量(克),32 位有符号整数
flownumber瞬时流量(L/min),由 flow_rate / 100.0 换算
totalnumber累计流量(L),由 flow_total / 1000.0 换算
relay_donumber继电器输出位图(bit0bit15 = CH1CH16)
relay_dinumber继电器输入位图
heart_countnumber单调递增计数器,每个传感器周期 +1
validnumber有效性位图:bit0=PT100、bit1=称重、bit2=继电器
statusnumber系统状态位:bit0~2=传感器状态、bit3=自动模式
running_slotstring当前固件槽位:"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 字段数据库列类型
devdevice_idVARCHAR
tspayload_tsINT
seqseqINT
flowflowDECIMAL
totaltotal_valueDECIMAL
weightweightINT
relay_dorelay_doINT
relay_direlay_diINT
temptemperature_jsonJSON
完整帧payloadJSON

唯一约束 (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(触发校验 + 复位)