
前言
在工业现场项目中,边缘网关通常负责采集PLC、仪表和传感器的数据。完成南向采集后,有时需要把实时数据直接发送到客户自己的服务器,由服务器进行存储、展示或二次处理。
本文使用InHand IG502网关,通过DeviceSupervisor Agent(以下简称DSA)采集Modbus数据,再使用“自定义快函数”编写Python脚本,将采集结果通过TCP发送到电脑。
电脑端使用HERCULES作为TCP Server接收数据。本文将从测试环境、网络拓扑、HERCULES配置、DSA配置、完整脚本及常见问题排查几个方面,记录整个验证过程。
一、测试目标
本次需要验证的数据链路为:
Modbus设备
↓
IG502上的DSA采集数据
↓
DSA本地消息总线
↓
自定义快函数获取采集结果
↓
Python socket建立TCP连接
↓
电脑上的HERCULES接收数据
测试完成后,电脑端应能够持续收到IG502转发的JSON格式采集数据。
二、测试环境
本次使用的测试环境如下:
| 项目 | 配置 |
|---|---|
| 边缘网关 | InHand IG502 |
| 边缘应用 | DeviceSupervisor Agent(DSA) |
| 南向采集协议 | Modbus RTU |
| 测试测点 | temp、humidity |
| 电脑IP地址 | 10.5.60.9 |
| TCP服务端口 | 3699 |
| 电脑端测试工具 | HERCULES SETUP Utility 3.2.8 |
IG502和电脑连接到同一个Wi-Fi网络,可以互相Ping通。

需要注意:能够Ping通只代表基本网络可达,并不能证明TCP 3699端口一定可以建立连接。防火墙、端口监听状态和脚本配置仍需单独检查。
三、确认DSA已经采集到数据
在配置TCP转发前,应先确认DSA能够正常读取现场设备的数据。
登录IG502管理页面,进入:
边缘计算 → 设备监控 → 测点监控
重点检查以下内容:
- 控制器处于在线状态。
- 测点左侧显示绿色状态。
- 测点数值能够正常显示。
- 测点采集时间持续更新。
本次测试使用两个测点:
| 测点名称 | 数据类型 | 地址 | 分组 |
|---|---|---|---|
| temp | FLOAT | 40001 | default |
| humidity | WORD | 40002 | default |
如果“测点监控”页面本身没有实时数据,应先检查Modbus参数、串口参数、从站地址、寄存器地址和数据类型。只有南向采集正常后,后续脚本才能获得有效数据。

四、配置HERCULES TCP Server
HERCULES是一款常用的串口和网络调试工具。本次使用它在电脑上建立TCP Server,用来接收IG502发送的数据。
可以从HW-group官方网站下载HERCULES SETUP Utility。
下载并运行HERCULES后,按照以下步骤配置:
- 打开
TCP Server选项卡。 - 在
Port中填写3699。 - 启动TCP Server。
- 按钮显示为
Close时,表示端口已经开始监听。 - 测试过程中保持HERCULES运行。
如果Windows弹出防火墙提示,应允许HERCULES通过当前使用的专用网络。也可以在Windows防火墙中单独创建一条入站规则,放行TCP 3699端口。

为什么Clients count可能一直是0
本文脚本采用短连接方式:
收到一条采集消息
↓
建立TCP连接
↓
发送数据
↓
关闭TCP连接
每次连接持续时间很短,因此即使数据已经发送成功,HERCULES中的Clients count也可能显示为0。
判断是否接收成功时,应主要观察Received data区域是否出现数据。
五、先用固定字符串验证TCP链路
首次测试时,不建议直接发送采集数据。可以先创建一个周期触发快函数,每隔几秒发送一次固定字符串。
这样可以快速确认:
- IG502能够访问电脑IP;
- HERCULES正在监听3699端口;
- Windows防火墙没有拦截连接;
- DSA自定义快函数可以正常执行;
- Python脚本可以建立TCP连接并发送数据。
进入:
边缘计算 → 设备监控 → 自定义快函数
新增快函数并配置:
| 参数 | 配置 |
|---|---|
| 名称 | tcp_test |
| 启用 | 是 |
| 模式 | 周期触发 |
| 周期 | 5秒 |
| 入口函数 | main |
测试脚本如下:
import socket
from common.Logger import logger
SERVER_IP = "10.5.60.9"
SERVER_PORT = 3699
def main():
tcp_client = None
try:
logger.info("Starting TCP test")
tcp_client = socket.socket(
socket.AF_INET,
socket.SOCK_STREAM
)
tcp_client.settimeout(5)
tcp_client.connect((SERVER_IP, SERVER_PORT))
message = "IG502 TCP test\r\n"
tcp_client.sendall(message.encode("utf-8"))
logger.info("TCP test sent successfully")
except Exception as e:
logger.error("TCP test failed: %s" % str(e))
finally:
if tcp_client:
tcp_client.close()
保存并启用后,HERCULES的Received data区域应每5秒出现一次:
IG502 TCP test

周期触发的入口函数
周期触发不会向入口函数传入采集消息,因此函数必须写成:
def main():
如果函数定义中增加了不需要的参数,脚本运行时就会出现参数缺失错误。
六、订阅DSA消息并发送真实采集数据
固定字符串测试成功后,说明TCP链路已经正常。接下来配置真实采集数据转发。
可以重新创建一个自定义快函数,配置如下:
| 参数 | 配置 |
|---|---|
| 名称 | tcp_forward |
| 启用 | 是 |
| 模式 | 本地订阅消息触发 |
| 订阅Topic | ds2/eventbus/south/read/+ |
| 入口函数 | main |
ds2/eventbus/south/read/+是DSA南向驱动发布控制器采集结果的消息主题。每完成一轮数据采集,订阅该主题的快函数就会被触发一次。

完整脚本
import json
import socket
from common.Logger import logger
# TCP服务器的IP地址
SERVER_IP = "10.5.60.9"
# TCP服务器监听端口
SERVER_PORT = 3699
def main(payload):
tcp_client = None
try:
logger.info("Received payload: %s" % payload)
# 将DSA采集结果统一转换为bytes
if isinstance(payload, bytes):
message = payload
elif isinstance(payload, str):
message = payload.encode("utf-8")
else:
message = json.dumps(
payload,
ensure_ascii=False
).encode("utf-8")
# 每条消息增加换行,方便接收端区分和显示
message += b"\r\n"
tcp_client = socket.socket(
socket.AF_INET,
socket.SOCK_STREAM
)
tcp_client.settimeout(5)
tcp_client.connect((SERVER_IP, SERVER_PORT))
tcp_client.sendall(message)
logger.info("Collected data sent successfully")
except Exception as e:
logger.error("TCP send failed: %s" % str(e))
finally:
if tcp_client:
tcp_client.close()
保存并启用后,只要DSA继续采集数据,HERCULES就会持续收到JSON内容。

收到的数据结构类似:
{
"controllers": [
{
"name": "saas",
"health": 1,
"timestamp": 1785378505,
"measures": [
{
"name": "temp",
"health": 1,
"timestamp": 1785378505,
"timestampMsec": 1785378505620,
"measureIndex": 0,
"rawbytes": "",
"value": 0.0
},
{
"name": "humidity",
"health": 1,
"timestamp": 1785378505,
"timestampMsec": 1785378505620,
"measureIndex": 1,
"rawbytes": "",
"value": 0
}
]
}
]
}
实际字段和数值会根据控制器、测点及DSA版本发生变化。
七、关键问题:入口函数参数
测试过程中,脚本最初写成:
def main(topic, payload):
DSA日志反复出现:
The script may run incorrectly
(main() missing 1 required positional argument: 'payload')
这条日志说明,当前IG502上的DSA在触发这个本地订阅快函数时,只传入了一个参数。
因此,本次测试环境中正确的函数定义为:
def main(payload):
修改入口函数后,采集数据立即成功发送到HERCULES。
不同DSA版本、不同快函数类型的入口参数可能存在差异。配置时应结合当前版本的默认示例和实际日志判断。
可以记住本文中的两个入口形式:
| 触发模式 | 入口函数 |
|---|---|
| 周期触发 | def main(): |
| 本地订阅消息触发 | def main(payload): |
八、如何通过日志判断问题
DSA日志是排查自定义快函数问题最直接的方式。
1. TCP发送成功
Received payload: ...
Collected data sent successfully
说明脚本已经获得采集消息,并完成TCP发送。
2. 连接被拒绝
Connection refused
通常表示电脑IP可以到达,但目标端口没有服务监听。检查:
- HERCULES是否运行;
- 是否选择了
TCP Server; - 监听端口是否为3699;
- 脚本端口是否与HERCULES一致。
3. 连接超时
timed out
常见原因包括:
SERVER_IP填写错误;- IG502到电脑的路由不通;
- Windows防火墙拦截TCP 3699;
- 网络启用了客户端隔离;
- 服务器端口没有正确放行。
4. 入口函数缺少参数
missing required positional argument
说明触发模式与函数定义不匹配。检查当前使用的是周期触发还是本地订阅消息触发,并按照本文对应的函数形式修改。
5. 日志没有Received payload
如果脚本编译成功,但一直没有出现:
Received payload
应检查:
- 快函数是否已经启用;
- 模式是否为“本地订阅消息触发”;
- Topic是否为
ds2/eventbus/south/read/+; - 入口函数是否填写为
main; - 测点监控页面是否持续产生采集数据。
九、局域网测试注意事项
本文中IG502和电脑连接同一个Wi-Fi,能够互相Ping通。
如果现场采用类似架构,还需要关注以下事项:
- 确认电脑当前实际使用的无线网卡IP。
- 不要误填电脑的虚拟网卡、VPN网卡或有线网卡IP。
- 确认无线网络没有开启客户端隔离。
- 确认电脑系统防火墙允许TCP 3699入站。
- 确认HERCULES保持监听状态。
脚本中的目标地址应填写电脑在该网络中的实际地址:
SERVER_IP = "10.5.60.9"
SERVER_PORT = 3699
如果电脑IP由DHCP自动分配,地址可能在重新连接网络后发生变化。长期运行时,建议为电脑配置固定地址或DHCP地址保留。
十、正式项目中的优化建议
本文脚本用于功能验证,采用每条数据建立一次TCP连接的方式,逻辑简单且方便排查。
正式项目中还可以根据实际需求增加:
- 断线重连;
- 失败重试和重试间隔;
- 本地缓存,避免网络中断时丢失数据;
- 长连接和心跳检测;
- 消息长度或结束符定义;
- 数据序号和时间戳;
- 服务端响应确认;
- 身份认证和传输加密;
- 日志大小和输出频率控制。
TCP本身只负责传输字节流,不会自动划分消息边界。本文通过:
message += b"\r\n"
为每条消息增加换行符,方便HERCULES显示。正式项目中,客户端和服务器应提前约定清晰的消息边界规则。
十一、总结
本文完成了以下验证:
IG502采集Modbus数据
↓
DSA发布南向采集消息
↓
自定义快函数接收payload
↓
Python socket连接电脑TCP 3699
↓
HERCULES成功接收JSON数据
整个过程中最重要的几点是:
- 先在测点监控页面确认南向采集正常。
- 先使用固定字符串验证TCP链路,再转发真实数据。
- 周期触发使用
main()。 - 本文设备的本地订阅消息触发使用
main(payload)。 - Ping通不代表TCP端口一定可用。
- 通过DSA日志可以快速判断是触发、参数还是网络问题。
按照这种分阶段验证方式,可以较快地完成IG502采集数据到自建TCP服务器的联调。
InHand IG502 DSA DeviceSupervisor 工业网关 Python TCP Modbus 边缘计算 工业物联网

1438

被折叠的 条评论
为什么被折叠?



