Files
DistributedCollectorGateway/README.md

14 KiB
Raw Blame History

Distributed Collector Gateway - 使用说明

功能概述

本设备是一个分布式采集网关,支持通过 MQTT 远程控制 MODBUS RTU 轮询参数,并定期上报设备状态信息。

新增功能

  • 离线数据存储网络断开时自动存储数据到Flash
  • 自动补传网络恢复后自动补传离线数据到MQTT服务器
  • SPIFFS文件系统ESP-IDF原生支持稳定可靠
  • 8MB存储容量可存储约11小时离线数据注意SPIFFS最小文件4KB

SNTP 时间同步

设备内置 SNTPSimple Network Time Protocol时间同步功能在网络连接成功后会自动同步系统时间。

时间同步特性

  • 自动同步:获取 IP 地址后自动启动 SNTP 客户端
  • 多服务器支持:配置了中国地区多个 NTP 服务器
    • cn.pool.ntp.org - 中国 NTP 服务器
    • ntp1.aliyun.com - 阿里云 NTP 服务器
    • ntp.tencent.com - 腾讯云 NTP 服务器
  • 时区设置自动设置为北京时间CST-8
  • 超时保护:等待时间同步最长 10 秒,超时后使用本地时间继续运行

时间同步状态

设备会在启动日志中显示时间同步状态:

I (xxxx) SNTP_ESP: 初始化SNTP服务
I (xxxx) SNTP_ESP: 时区设置为北京时间 (CST-8)
I (xxxx) SNTP_ESP: 当前时间: 1970-01-01 08:00:00 Thursday  (同步前)
I (xxxx) SNTP_ESP: 时间同步成功: 2026-02-01 15:30:45  (同步后)
I (xxxx) SNTP_ESP: 时间同步完成

时间在系统中的应用

同步后的时间会在以下场景中使用:

  1. 设备状态上报 - update_time 字段显示精确的同步时间
  2. 数据采集记录 - 可扩展用于记录数据采集时间戳
  3. 日志时间戳 - 方便调试和问题追踪

注意事项

  • 需要网络连接正常才能进行时间同步
  • 首次启动时,时间同步可能需要几秒钟
  • 如果网络连接异常,设备会使用本地时间继续工作
  • 时间同步完成后,系统时间会持续由 SNTP 守护进程维护

设备状态上报

上报主题

CONFIG_MQTT_PUB_TOPIC (在 sdkconfig 中配置)

上报类型

设备会定期上报以下类型的数据:

  1. 设备状态message_type: "device_status"
  2. MODBUS 采集数据function_code: 3

设备状态上报格式

{
  "message_type": "device_status",
  "mac_address": "D0:CF:13:1B:C3:94",
  "ip_address": "192.168.1.100",
  "chip_model": "ESP32-S3",
  "idf_version": "v5.5.2-dirty",
  "uptime": 16,
  "uptime_desc": "16秒",
  "free_heap": 312996,
  "status": "online",
  "status_desc": "在线",
  "update_time": "2026-02-01 15:30:45",
  "led1_state": 1,
  "led1_desc": "常亮",
  "led1_function": "网络状态灯",
  "led2_state": 4,
  "led2_desc": "心跳",
  "led2_function": "通信状态灯",
  "modbus_enabled": 1,
  "modbus_enabled_desc": "启用",
  "modbus_channel": 0,
  "modbus_channel_desc": "通道0 (UART0)",
  "modbus_slave_addr": 1,
  "modbus_interval": 1000,
  "heap_status": "充足"
}

字段说明

基本信息

字段 类型 说明
message_type string 消息类型:"device_status"
mac_address string 设备 WiFi MAC 地址(唯一标识)
ip_address string 设备 IP 地址
chip_model string 芯片型号
idf_version string ESP-IDF 版本

运行状态

字段 类型 说明
uptime number 设备运行时间(秒)
uptime_desc string 运行时间中文描述(如:"1天5小时30分"
free_heap number 剩余堆内存(字节)
heap_status string 内存状态:"充足" / "一般" / "紧张"
status string 设备状态:"online"
status_desc string 设备状态中文描述:"在线"
update_time string 状态更新时间YYYY-MM-DD HH:MM:SS通过 SNTP 同步)

LED 状态

字段 类型 说明
led1_state number LED1 状态0=关闭, 1=常亮, 2=慢闪, 3=快闪, 4=心跳
led1_desc string LED1 状态中文描述
led1_function string LED1 功能:"网络状态灯"
led2_state number LED2 状态:同 LED1
led2_desc string LED2 状态中文描述
led2_function string LED2 功能:"通信状态灯"

MODBUS 轮询状态

字段 类型 说明
modbus_enabled number MODBUS 轮询是否启用0=禁用, 1=启用)
modbus_enabled_desc string 轮询状态中文描述:"启用" / "禁用" / "未配置"
modbus_channel number 当前使用的 RS485 通道0 或 1
modbus_channel_desc string 通道中文描述
modbus_slave_addr number 当前轮询的从机地址
modbus_interval number 当前轮询间隔(毫秒)

中文提示字段说明

带有 _desc 后缀的字段是中文提示字段,设计用于:

  • 直接显示在 Web 页面上,无需额外转换
  • 不会被程序解析,仅用于展示
  • 提升用户体验,让状态更直观

Web 页面可以选择显示:

  • 程序解析字段(如 led1_state)用于逻辑判断
  • 中文描述字段(如 led1_desc)用于界面显示

上报时机

  • MQTT 订阅成功后立即上报一次
  • 之后每隔 10 秒上报一次(可在 main.c 中修改 mqtt_start_device_status_task(10000) 的参数)

MODBUS 控制说明

本设备是一个分布式采集网关,支持通过 MQTT 远程控制 MODBUS RTU 轮询参数。

MQTT 控制指令

控制主题

发布控制指令到订阅主题:CONFIG_MQTT_SUB_TOPIC (在 sdkconfig 中配置)

指令格式 (JSON)

{
  "command": "modbus_poll",
  "channel": 0,
  "slave_addr": 1,
  "start_addr": 0,
  "reg_count": 2,
  "interval": 1000,
  "enabled": true
}

参数说明

参数 类型 必填 说明
command string 固定为 "modbus_poll"
channel number RS485 通道号 (0 或 1)
slave_addr number 从机地址 (1-247)
start_addr number 起始寄存器地址 (0-65535)
reg_count number 读取寄存器数量 (1-125)
interval number 轮询间隔(毫秒),最小 100ms
enabled boolean 是否启用轮询,默认 true

使用示例

示例 1读取设备地址 1 的寄存器

{
  "command": "modbus_poll",
  "channel": 0,
  "slave_addr": 1,
  "start_addr": 0,
  "reg_count": 2,
  "interval": 1000
}

设备会每 1 秒读取一次从机地址 1从寄存器 0 开始的 2 个寄存器。

示例 2读取设备地址 10 的寄存器

{
  "command": "modbus_poll",
  "channel": 0,
  "slave_addr": 10,
  "start_addr": 0,
  "reg_count": 5,
  "interval": 2000
}

设备会每 2 秒读取一次从机地址 10从寄存器 0 开始的 5 个寄存器。

示例 3读取指定范围的寄存器

{
  "command": "modbus_poll",
  "channel": 0,
  "slave_addr": 1,
  "start_addr": 10,
  "reg_count": 4,
  "interval": 500
}

设备会每 500ms 读取一次从机地址 1从寄存器 10 开始的 4 个寄存器(地址 10, 11, 12, 13

示例 4停止轮询

{
  "command": "modbus_poll",
  "channel": 0,
  "slave_addr": 1,
  "start_addr": 0,
  "reg_count": 2,
  "interval": 1000,
  "enabled": false
}

设置 "enabled": false 可以暂停轮询任务。

示例 5使用 RS485 通道 1

{
  "command": "modbus_poll",
  "channel": 1,
  "slave_addr": 5,
  "start_addr": 0,
  "reg_count": 10,
  "interval": 1000
}

使用 RS485 通道 1 进行轮询。

数据上报

上报主题

CONFIG_MQTT_PUB_TOPIC (在 sdkconfig 中配置)

上报数据格式 (JSON)

{
  "channel": "RS485-1",
  "slave_addr": 1,
  "function_code": 3,
  "status": "success",
  "byte_count": 4,
  "register_count": 2,
  "registers": [
    556,
    998
  ]
}

字段说明

字段 类型 说明
channel string RS485 通道名称
slave_addr number 从机地址
function_code number MODBUS 功能码(始终为 3
status string 状态:"success""exception"
byte_count number 数据字节数
register_count number 寄存器数量
registers array 寄存器值数组

异常响应格式

{
  "channel": "RS485-1",
  "slave_addr": 1,
  "function_code": 131,
  "status": "exception",
  "exception_code": 2
}
字段 类型 说明
exception_code number 异常码:
1 - 非法功能
2 - 非法数据地址
3 - 非法数据值
4 - 服务器设备故障

动态更新

每次发送 MQTT 控制指令都会立即更新轮询参数,无需重启设备。

更新流程

  1. 发送新的控制指令
  2. 设备接收并解析 JSON
  3. 立即更新轮询配置
  4. 下一次轮询使用新参数

MQTT 控制指令

控制主题

发布控制指令到订阅主题:CONFIG_MQTT_SUB_TOPIC (在 sdkconfig 中配置)

指令格式 (JSON)

{
  "command": "modbus_poll",
  "channel": 0,
  "slave_addr": 1,
  "start_addr": 0,
  "reg_count": 2,
  "interval": 1000,
  "enabled": true
}

参数说明

参数 类型 必填 说明
command string 固定为 "modbus_poll"
channel number RS485 通道号 (0 或 1)
slave_addr number 从机地址 (1-247)
start_addr number 起始寄存器地址 (0-65535)
reg_count number 读取寄存器数量 (1-125)
interval number 轮询间隔(毫秒),最小 100ms
enabled boolean 是否启用轮询,默认 true

支持的指令类型

当前支持以下控制指令:

1. MODBUS 轮询控制

{
  "command": "modbus_poll",
  "channel": 0,
  "slave_addr": 1,
  "start_addr": 0,
  "reg_count": 2,
  "interval": 1000,
  "enabled": true
}

2. 设备状态上报间隔控制(可选扩展)

可通过修改 main.c 中的参数来调整状态上报间隔:

mqtt_start_device_status_task(10000);  // 10000ms = 10秒

或运行时调用 API

mqtt_update_report_interval(5000);  // 5秒

离线数据存储

功能特性

设备支持离线数据存储功能,确保网络断开时数据不丢失:

  • 自动检测实时监测网络状态通过MQTT连接状态
  • 离线存储网络断开时自动存储数据到Flash
  • 自动补传网络恢复后自动补传离线数据到MQTT服务器
  • LittleFS文件系统:提供断电保护和磨损均衡
  • 8MB存储容量可存储约11小时离线数据

存储容量

数据类型 数据量 可存储时长
MODBUS数据 200字节/条1秒/次) 约11小时注意SPIFFS最小文件4KB

工作流程

正常模式(网络在线)

数据产生 → 直接发布到MQTT → 不存储

离线模式(网络断开)

数据产生 → 存储到Flash SPIFFS → 等待网络恢复

补传模式(网络恢复)

检测网络恢复 → 读取最旧数据 → 发布到MQTT → 删除已传数据 → 继续下一条

存储结构

/flash/
├── data/
│   ├── modbus/              # MODBUS采集数据
│   │   ├── 1738452345.json  # 时间戳命名
│   │   └── ...
│   └── status/              # 设备状态数据
│       └── ...
└── index.json              # 索引文件

日志示例

存储离线数据

I (xxxx) mqtt_esp: Network is offline, stopping offline data upload
I (xxxx) mqtt_esp: Storing offline data (type=1, size=256)
I (xxxx) OFFLINE_STORAGE: Storage usage: 512 / 8388608 bytes (0.0%)

补传离线数据

I (xxxx) mqtt_esp: Network is online, starting offline data upload
I (xxxx) mqtt_esp: Found 10 offline data files, uploading...
I (xxxx) mqtt_esp: Publishing offline data (type=1, size=256)
I (xxxx) mqtt_esp: Offline data published successfully, msg_id=12345

存储策略

  • 自动循环覆盖最多存储10,000个文件超出自动删除最旧数据
  • 时间戳排序:按时间戳顺序补传,确保数据时间顺序
  • 原子写入:使用临时文件+重命名机制
  • 断电保护SPIFFS提供基本的断电保护

注意事项

  1. 首次启动会自动初始化并挂载SPIFFS文件系统
  2. 空间管理:存储满后自动循环覆盖最旧数据
  3. 补传速率:每秒处理一条数据,避免阻塞新数据上传
  4. Flash寿命SPIFFS无磨损均衡建议定期格式化
  5. 最小文件限制SPIFFS最小文件4KB小文件会浪费空间
  6. 格式化:如需清空所有数据,可调用 flash_spiffs_format()

详细文档请参考:离线数据存储和补传功能说明

注意事项

  1. 轮询间隔最小为 100ms,设置更小的值会被拒绝
  2. 寄存器数量最大为 125MODBUS RTU 限制
  3. 从机地址范围 1-2470 为广播地址
  4. 通道号只能是 0 或 1
  5. 首次发送指令后会自动启动轮询任务
  6. 离线存储容量约11小时,超出会循环覆盖最旧数据

使用 mosquitto_cli 测试

发送控制指令

mosquitto_pub -h <broker_ip> -p 1883 -t <sub_topic> -m '{
  "command": "modbus_poll",
  "channel": 0,
  "slave_addr": 1,
  "start_addr": 0,
  "reg_count": 2,
  "interval": 1000
}'

监听数据上报

mosquitto_sub -h <broker_ip> -p 1883 -t <pub_topic>

硬件连接

RS485 通道 0 (UART0)

引脚 GPIO 功能
RO (RX) GPIO 41 RS485 接收器输出
DE/RE GPIO 42 数据使能/接收器使能
DI (TX) GPIO 44 RS485 驱动器输入

RS485 通道 1 (UART2)

引脚 GPIO 功能
RO (RX) GPIO 43 RS485 接收器输出
DE/RE GPIO 2 数据使能/接收器使能
DI (TX) GPIO 1 RS485 驱动器输入