Distributed Collector Gateway - 使用说明
功能概述
本设备是一个分布式采集网关,支持通过 MQTT 远程控制 MODBUS RTU 轮询参数,并定期上报设备状态信息。
SNTP 时间同步
设备内置 SNTP(Simple 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: 时间同步完成
时间在系统中的应用
同步后的时间会在以下场景中使用:
- 设备状态上报 -
update_time字段显示精确的同步时间 - 数据采集记录 - 可扩展用于记录数据采集时间戳
- 日志时间戳 - 方便调试和问题追踪
注意事项
- 需要网络连接正常才能进行时间同步
- 首次启动时,时间同步可能需要几秒钟
- 如果网络连接异常,设备会使用本地时间继续工作
- 时间同步完成后,系统时间会持续由 SNTP 守护进程维护
设备状态上报
上报主题
CONFIG_MQTT_PUB_TOPIC (在 sdkconfig 中配置)
上报类型
设备会定期上报以下类型的数据:
- 设备状态(
message_type: "device_status") - 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 控制指令都会立即更新轮询参数,无需重启设备。
更新流程
- 发送新的控制指令
- 设备接收并解析 JSON
- 立即更新轮询配置
- 下一次轮询使用新参数
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秒
注意事项
- 轮询间隔最小为 100ms,设置更小的值会被拒绝
- 寄存器数量最大为 125,MODBUS RTU 限制
- 从机地址范围 1-247,0 为广播地址
- 通道号只能是 0 或 1
- 首次发送指令后会自动启动轮询任务
使用 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 驱动器输入 |
Description
Languages
C
57.5%
HTML
41.8%
CMake
0.7%