Modbus 采集、MQTT/SQL 转发与规则引擎完整 Demo
本 Demo 从一条普通 Modbus TCP 变量开始,依次完成实时采集、MQTT 转发、SQLite 历史数据转发和规则引擎阈值判断,并分别验证每一段链路的实际结果。
本页通道类型为 TcpClient,GatewayRuntime 主动连接 Modbus TCP 从站。设备插件的 DTU ID 保持为空,不使用 TCP 服务端监听、DTU 注册或 DTU ID 连接分配。DTU 接入请参阅 DTU 服务。
实际验证环境
本页截图来自一套真实运行的本机联调环境,不是空表单示意图。测试从站每秒在 950 和 1234 之间交替返回数值,用于同时验证阈值的未触发和触发状态。
| 项目 | 本页实际配置 | 验证目标 |
|---|---|---|
| Modbus TCP 从站 | 127.0.0.1:15030 | 接收 GatewayRuntime 的真实 Modbus 请求并返回 950、1234 |
| 通道 | Demo_Modbus_Channel,TcpClient | GatewayRuntime 主动连接从站 |
| 设备 | Demo_Modbus_Device,ModbusMaster | 每 1000 ms 执行一次采集 |
| 变量 | Demo_Modbus_Value,400001,Int16 | 在线刷新真实采集值 |
| MQTT Broker | 127.0.0.1:18885 | 接收主题 thingsgateway/demo/modbus 的发布消息 |
| SQLite | normal_full_demo.sqlite | 在 historyNumberValue 中写入真实历史记录 |
| 规则流程 | Demo_Modbus_Rule | 判断 Demo_Modbus_Value > 1000 |
| 规则动作 | http://127.0.0.1:17502/rule | 接收规则引擎生成的实际 Webhook 请求 |
127.0.0.1 只适用于 GatewayRuntime、模拟从站、MQTT Broker 和验证服务位于同一台计算机的演示环境。生产部署必须替换为现场设备或服务器可访问的 IP 地址、端口和数据库路径。
一、生成普通 Modbus 测试数据
登录 GatewayRuntime Web,进入“开发配置 → 采集配置”,点击变量列表右上角“显示更多 → 测试数据”。
- 选择“普通测试数据”,不要选择“DTU 测试数据”。
- 变量数量填写
1,设备数量填写1。 - 从站地址填写
127.0.0.1:15030。 - 点击“生成”,创建一组普通 Modbus TCP 通道、设备和变量。

生成后可直接编辑自动创建的对象。本 Demo 将对象名称调整为 Demo_Modbus_Channel、Demo_Modbus_Device 和 Demo_Modbus_Value,便于在转发与规则流程中准确引用。
二、配置 TCP 客户端通道
进入“采集配置 → 通道管理”,编辑 Demo_Modbus_Channel。
| 配置项 | 本页实例值 | 说明 |
|---|---|---|
| 通道名称 | Demo_Modbus_Channel | 在采集、日志和运行状态中标识本链路 |
| 通道类型 | TcpClient | 由 GatewayRuntime 主动连接 Modbus 从站 |
| 远程地址 | 127.0.0.1:15030 | Modbus TCP 从站的 IP 和端口 |
| 连接超时 | 3000 ms | 建立连接和连接操作的超时值 |
| 缓存超时 | 500 ms | 协议数据读取与组包使用的缓存窗口 |
| 最大并发数 | 1 | 保持 Modbus 请求顺序,避免从站并发处理异常 |
| 心跳时间 | 60000 ms | 本 Demo 保持默认值 |

普通 Modbus TCP 采集的关键特征是通道类型为 TcpClient,并填写“远程地址”。DTU 模式通常使用 TcpService 监听地址,由 DTU 主动连接网关。
三、配置 ModbusMaster 设备
进入“采集配置 → 设备管理”,编辑 Demo_Modbus_Device。
| 配置项 | 本页实例值 | 说明 |
|---|---|---|
| 设备名称 | Demo_Modbus_Device | 转发组和规则节点按此名称筛选设备 |
| 设备插件 | ModbusMaster | 作为 Modbus 主站发起读取请求 |
| 关联通道 | Demo_Modbus_Channel | 使用前一步的 TCP 客户端连接 |
| 执行间隔 | 1000 | 每秒执行一次采集 |
| 使能 | 开启 | 保存后启动设备运行态 |

切换到“插件属性”,确认使用普通 Modbus TCP:
| 配置项 | 本页实例值 | 说明 |
|---|---|---|
| Modbus 类型 | ModbusTcp | 使用 Modbus TCP 报文 |
| 默认站号 | 1 | 变量未单独指定站号时使用该值 |
| DTU ID | 空 | 普通 TCP 客户端采集不填写 DTU ID |
| 读写超时时间 | 3000 ms | 单次 Modbus 请求等待响应的最大时间 |
| 数据解析顺序 | ABCD | 多寄存器数据按现场设备字节序调整 |

四、配置变量并验证采集
返回“变量显示”,编辑 Demo_Modbus_Value。
| 配置项 | 本页实例值 | 说明 |
|---|---|---|
| 变量名称 | Demo_Modbus_Value | MQTT、SQLite 和规则引擎中统一使用该名称 |
| 所属设备 | Demo_Modbus_Device | 归属前一步的 ModbusMaster 设备 |
| 变量地址 | 400001 | 保持寄存器的第一个地址 |
| 数据类型 | Int16 | 从一个 16 位保持寄存器解析数值 |
| 读写权限 | 读写 | 本 Demo 保持生成配置;只采集时可按现场要求设为只读 |
| RPC 写入 | 开启 | 与本次读取、转发和规则验证无直接依赖 |

保存后回到采集页面,按以下顺序验收:
Demo_Modbus_Channel显示“在线 1/1”。Demo_Modbus_Device显示绿色在线状态。Demo_Modbus_Value的当前值和原始值持续在950、1234之间变化。- 采集时间持续更新,错误信息为空。

只有采集状态通过后再配置转发和规则引擎。否则后续目标即使显示在线,也可能没有可转发的数据。
五、创建双目标数据转发组
进入“开发配置 → 数据转发”,新增转发组 Demo_Modbus_MQTT_SQL。
| 配置项 | 本页实例值 | 说明 |
|---|---|---|
| 变量范围 | 采集设备 | 从采集设备选择转发变量 |
| 范围配置 | Demo_Modbus_Device | 只转发本 Demo 设备的数据 |
| 触发模式 | 定时或变化 | 数值变化立即触发,同时每秒补充一次定时触发 |
| 定时间隔 | 1000 | 定时触发间隔为 1 秒 |
| 在线过滤 | 开启 | 只转发在线变量 |
| 分批模式 | 不分批 | 单变量 Demo 无需分批 |
| 最大批量 | 1000 | 保持默认上限 |

保存后确认转发组卡片显示 1 变量。本 Demo 在同一个组下创建两个独立目标,MQTT 和 SQLite 的在线状态、日志和实际数据必须分别验收。
六、创建 MQTT 客户端目标
选中 Demo_Modbus_MQTT_SQL,在“转发目标”区域点击新增,选择 MqttClientProducer。
| 配置项 | 本页实例值 | 说明 |
|---|---|---|
| 目标名称 | Demo_MQTT_Target | MQTT 目标的唯一名称 |
| IP 地址 | 127.0.0.1 | 本机 MQTT Broker |
| 端口 | 18885 | 本 Demo Broker 的 TCP 端口 |
| 客户端 ID | DemoGatewayRuntime | Broker 中用于识别 GatewayRuntime 客户端 |
| MQTT 协议版本 | V311 | MQTT 3.1.1 |
| 连接类型 | Tcp | 使用普通 MQTT TCP 连接 |
| QoS 等级 | AtMostOnce | 本 Demo 使用 QoS 0 |
| 详细日志 | 开启 | 联调阶段便于核对连接和发布过程 |

将“变量 Topic 模板”填写为 thingsgateway/demo/modbus。本页没有使用设备名占位符,因此所有选中变量发布到固定 Demo Topic。

保存后等待目标卡片显示“在线”。Broker 端实际收到的消息包含以下关键数据:
[
{
"Name": "Demo_Modbus_Value",
"DeviceName": "Demo_Modbus_Device",
"Value": 1234,
"IsOnline": true,
"ChannelName": "Demo_Modbus_Channel",
"RegisterAddress": "400001",
"DataType": "Int16"
}
]
生产环境应按 Broker 安全策略填写用户名、密码、TLS 证书、QoS、保留消息和离线缓存,不要直接照搬本机无认证参数。
七、创建 SQLite 历史数据目标
在同一转发组下继续新增目标,选择 HisDataForwardTarget,数据库类型选择 Sqlite。
| 配置项 | 本页实例值 | 说明 |
|---|---|---|
| 目标名称 | Demo_SQLite_Target | SQLite 目标的唯一名称 |
| 数据库类型 | Sqlite | 使用本地 SQLite 文件验证 SQL 转发 |
| 连接字符串 | Data Source=E:\tgall\src\.codex-runtime\gateway-full-demo-6125-20260729-01\normal_full_demo.sqlite | 本次实际验证文件路径,生产环境必须替换 |
| 数值历史表名 | historyNumberValue | 数值变量写入该表 |
| 字符串历史表名 | historyStringValue | 字符串变量写入该表 |
| 时区偏移 | +08:00 | 按当前项目时区保存时间 |
| 强制插入 | 开启 | Demo 中便于连续观察新增记录 |
| 默认采样策略 | Change | 变量变化时生成历史记录 |

保存后等待 Demo_SQLite_Target 显示“在线”。本次实际写入的 historyNumberValue 记录包含 VariableId、DeviceName、VariableName、Value、CollectTime、IsOnline 和 CreateTime 等字段。
需要写入 MySQL、PostgreSQL 或 SQL Server 时,仍使用历史数据目标,切换“数据库类型”并填写对应连接字符串。表名、分表策略、采样策略和历史保留策略应按项目数据库规范重新确认。
八、分别验收 MQTT 和 SQLite 转发
回到数据转发详情页,确认:
- 转发组显示
2 目标、2 在线、1 变量。 Demo_MQTT_Target和Demo_SQLite_Target都显示“在线”。- 转发组和两个目标的最近活跃时间持续更新。

目标在线只说明目标运行态已经启动,不能代替结果验收。本页另外使用真实接收端和数据库查询同时检查两类结果:MQTT Topic 中出现 Demo_Modbus_Value,SQLite 的 historyNumberValue 中出现同一变量的实际值。

| 检查项 | 通过标准 |
|---|---|
| Modbus 请求 | 请求数持续增加,证明 GatewayRuntime 正在向普通 Modbus TCP 从站发起读取 |
| MQTT 消息 | 消息数大于 0,Topic 为 thingsgateway/demo/modbus |
| MQTT 内容 | 包含 Demo_Modbus_Value、Demo_Modbus_Device 和实际值 950 或 1234 |
| SQLite 记录 | historyNumberValue 记录数持续增加 |
| SQLite 内容 | 最近记录的 VariableName 为 Demo_Modbus_Value,数值与同一时刻采集值一致 |
九、配置规则引擎
进入“开发配置 → 规则引擎”,创建或打开流程 Demo_Modbus_Rule。本 Demo 使用三个节点:
- “变量通知规则”监听
Demo_Modbus_Value的变化。 - “阈值触发”判断变量值是否大于
1000。 - “Webhook 推送”把规则数据发送到本地验收端。
连接关系如下:
| 起点 | 终点 | 用途 |
|---|---|---|
变量通知规则 Result | 阈值触发 Input | 把实时数值送入阈值判断 |
变量通知规则 VariableBasicData | Webhook 推送 Data | 把完整变量对象送入规则动作 |
本页 MQTT 和 SQLite 是“数据转发”页面中的两个数据转发目标。Webhook 只用于演示规则引擎动作,不是本页的数据转发示例,也不能代替 MQTT 或 SQL 目标验收。
配置变量通知节点
选中“变量通知规则”节点,填写以下初始输入参数:
| 参数 | 实例值 | 说明 |
|---|---|---|
DeviceNames | Demo_Modbus_Device | 只匹配本 Demo 采集设备 |
VariableNames | Demo_Modbus_Value | 只匹配本 Demo 变量 |
CollectGroups | 空 | 不额外按采集组过滤 |

配置阈值节点
选中“阈值触发”节点,设置:
| 参数 | 实例值 | 说明 |
|---|---|---|
Threshold | 1000 | 阈值 |
Hysteresis | 0 | 本 Demo 不使用回差 |
CompareOperator | > | 输入值大于 1000 时触发 |
当输入为 1234 时,实际运行值显示 Triggered=true、RisingEdge=true;当输入恢复为 950 时,显示 Triggered=false、FallingEdge=true。

配置规则动作节点
选中“Webhook 推送”节点,填写以下参数:
| 参数 | 实例值 | 说明 |
|---|---|---|
Url | http://127.0.0.1:17502/rule | 本机规则验收服务地址 |
Enabled | 开启 | 启用规则动作 |
Data | 连接变量通知节点的 VariableBasicData | 传入当前变量对象 |
请求体模板如下:
{"source":"rule-engine","device":"{{DeviceName}}","variable":"{{Name}}","value":{{Value}}}
实际运行时节点显示 Success=true、ErrorMessage 为空,并持续更新 LastPushTime。

保存并启用流程后,完整画布如下。节点上的实时参数会跟随 Modbus 值刷新。

规则动作在高值状态下的实际运行结果如下,输入为 1234,阈值判断已触发,Webhook 动作返回成功。

十、完整验收清单
按链路顺序验收,不要跳过前置步骤:
| 阶段 | 必须满足的结果 |
|---|---|
| 普通 Modbus 通道 | TcpClient 在线,远程地址指向真实从站,不填写 DTU ID |
| Modbus 设备 | ModbusMaster 在线,执行间隔持续生效 |
| 变量采集 | Demo_Modbus_Value 在 950、1234 之间刷新,采集时间更新且无错误 |
| MQTT 目标 | 目标在线,Broker 实际收到正确 Topic 和变量 JSON |
| SQLite 目标 | 目标在线,historyNumberValue 实际新增记录且值正确 |
| 规则低值 | 输入 950,Triggered=false,下降沿切换时 FallingEdge=true |
| 规则高值 | 输入 1234,Triggered=true,上升沿切换时 RisingEdge=true |
| 规则动作 | Success=true,ErrorMessage 为空,接收端收到 /rule 请求 |
生产环境替换项
| Demo 配置 | 生产环境要求 |
|---|---|
127.0.0.1:15030 | 替换为 PLC、仪表、协议网关或真实 Modbus TCP 从站地址 |
单变量 400001 | 按正式点表导入全部变量,并核对地址、数据类型、字节序和读写权限 |
MQTT 127.0.0.1:18885 | 替换为正式 Broker,配置认证、TLS、QoS、Topic 规范和离线缓存 |
| 本地 SQLite 文件 | 按容量和查询要求选择正式数据库、表结构、分表与保留策略 |
阈值 1000 | 按工艺含义设置阈值、回差、边沿触发和防抖策略 |
| 本机 Webhook | 替换为 MES、告警平台、通知服务或其他正式规则动作地址 |
故障排查
| 现象 | 重点检查 |
|---|---|
| 通道离线 | 从 GatewayRuntime 主机测试从站 IP/端口;确认通道为 TcpClient,远程地址不是绑定地址 |
| 设备在线但变量异常 | 核对站号、功能码对应的地址格式、数据类型、字节序、超时和从站返回报文 |
| 转发组没有变量 | 确认变量范围为“采集设备”,范围配置与 Demo_Modbus_Device 名称完全一致 |
| MQTT 目标离线 | 检查 Broker 监听端口、客户端 ID 冲突、认证、TLS、协议版本和目标日志 |
| MQTT 在线但无消息 | 检查转发组触发模式、在线过滤、变量数量和 Topic 模板,并在 Broker 端真实订阅验证 |
| SQLite 目标离线 | 检查连接字符串、目录写入权限、数据库类型和历史表名 |
| SQLite 在线但无记录 | 检查采样策略、强制插入、变量数据类型和转发组最近活跃时间 |
| 规则节点无输入 | 核对 DeviceNames、VariableNames 大小写和空格,确认变量本身持续变化 |
| 阈值始终不触发 | 检查输入连线、阈值、比较符、数值类型和实时 Input 值 |
Webhook Success=false | 检查 URL、接收服务、请求体模板、网络策略和节点 ErrorMessage |