ModBus TCP代理
项目描述
ModBus TCP代理
许多modbus设备只支持一个或非常少的客户端。这个代理充当客户端和modbus设备之间的桥梁。它可以被视为第7层反向代理。这允许多个客户端与同一个modbus设备通信。
当多个客户端连接时,通过按先到先服务的REQ/REP顺序序列化通信来避免交叉消息。
安装
在您喜欢的python 3环境中输入
$ pip install modbus-proxy
注意:在某些系统上,pip
指向python 2安装。您可能需要使用pip3
命令。
另外,如果您需要日志配置
- YAML:
pip install modbus-proxy[yaml]
(见下文) - TOML:
pip install modbus-proxy[toml]
(见下文)
运行服务器
首先,您需要编写一个配置文件,其中指定要控制的每个modbus设备的以下内容
- modbus连接(modbus设备的URL)
- 监听接口(客户端应连接到的URL)
配置文件可以编写为YAML(.yml或.yaml)或TOML(.toml)。
假设您有一个监听在plc1.acme.org:502的PLC modbus设备,并且您希望您的客户端连接到您的机器的9000端口。一个YAML配置将如下所示
devices:
- modbus:
url: plc1.acme.org:502 # device url (mandatory)
timeout: 10 # communication timeout (s) (optional, default: 10)
connection_time: 0.1 # delay after connection (s) (optional, default: 0)
listen:
bind: 0:9000 # listening address (mandatory)
unit_id_remapping: # remap/forward unit IDs (optional, empty by default)
1: 0
假设您将此文件保存为modbus-config.yml
,请使用以下命令启动服务器:
$ modbus-proxy -c ./modbus-config.yml
现在,您不需要将客户端连接到plc1.acme.org:502
,只需告诉它们连接到*machine*:9000
(其中machine是modbus-proxy运行的主机)。
请注意,服务器能够处理多个modbus设备。以下是2个设备的配置示例:
devices:
- modbus:
url: plc1.acme.org:502
listen:
bind: 0:9000
- modbus:
url: plc2.acme.org:502
listen:
bind: 0:9001
如果您只有一个单个 modbus设备,您可以通过命令行提供所有参数来避免编写配置文件。
modbus-proxy -b tcp://0:9000 --modbus tcp://plc1.acme.org:502
(提示:运行modbus-proxy --help
以查看所有可用选项)
转发单元标识符
您还可以在代理的同时将一个单元ID转发到另一个。如果目标modbus服务器上的单元索引不支持您的客户端之一,这会很有用。
devices:
- modbus: ... # see above.
listen: ... # see above.
unit_id_remapping:
1: 0
上述操作将请求单元ID 1转发到实际modbus服务器上的单元ID 0。
请注意,反向操作也适用:如果您将单元ID 1转发到单元ID 0,则来自单元0的所有响应都将看起来像来自1,因此如果您想为某些客户端使用单元ID 0,为其他客户端使用单元ID 1,可能会出现问题(在这种情况下,请为所有客户端使用单元ID 1)。
运行示例
要运行示例,您需要安装umodbus(使用pip install umodbus
进行安装)。
启动simple_tcp_server.py
(这将模拟实际的modbus硬件)
$ python examples/simple_tcp_server.py -b :5020
您可以通过运行示例客户端来确保直接通信正常
$ python examples/simple_tcp_client.py -a 0:5020
holding registers: [1, 2, 3, 4]
现在进行真正的测试
使用以下命令启动modbus-proxy网桥服务器:
$ modbus-proxy -b tcp://:9000 --modbus tcp://:5020
最后,运行示例客户端,但现在将地址指向代理而不是服务器(注意我们现在使用端口9000而不是5020)
$ python examples/simple_tcp_client.py -a 0:9000
holding registers: [1, 2, 3, 4]
以服务形式运行
- 将配置文件移动到您能记住的位置,例如:到
/usr/lib/mproxy-conf.yaml
- 转到
/etc/systemd/system/
- 使用nano或其他您选择的文本编辑器创建服务文件
mproxy.service
- 该文件应包含以下信息
[Unit]
Description=Modbus-Proxy
After=network.target
[Service]
Type=simple
Restart=always
ExecStart = modbus-proxy -c ./usr/lib/mproxy-conf.yaml
[Install]
WantedBy=multi-user.target
运行systemctl daemon-reload
systemctl enable mproxy.service
systemctl start mproxy.service
这里给出的文件名是示例,您可以选择其他名称。
Docker
该项目附带一个基本的Dockerfile,您可以使用它作为在Docker容器中启动modbus-proxy的基础。
首先,使用以下命令构建Docker镜像:
$ docker build -t modbus-proxy .
要无需配置文件即可桥接单个modbus设备,操作简单
$ docker run -d -p 5020:502 modbus-proxy -b tcp://0:502 --modbus tcp://plc1.acme.org:502
现在,您应该能够通过连接客户端到<your-hostname/ip>:5020
通过modbus-proxy访问您的modbus设备。
如果您想使用配置文件,则必须挂载文件以便容器可以看到。
假设您已在当前目录中准备好了conf.yml
devices:
- modbus:
url: plc1.acme.org:502
listen:
bind: 0:502
以下是运行容器的示例
docker run -p 5020:502 -v $PWD/conf.yml:/config/modbus-proxy.yml modbus-proxy
默认情况下,Dockerfile将运行modbus-proxy -c /config/modbus-proxy.yml
,因此如果您挂载了该卷,您不需要传递任何参数。
请注意,对于配置文件中添加的每个modbus设备,您需要在主机上发布相应的绑定端口(使用-p <host port>:<container port>
参数)。
日志配置
您可以通过添加新的logging
关键字将日志配置添加到配置文件中。
日志配置将通过logging.config.dictConfig()
传递,因此文件内容必须遵守配置字典模式。
以下是一个YAML示例
devices:
- modbus:
url: plc1.acme.org:502
listen:
bind: 0:9000
logging:
version: 1
formatters:
standard:
format: "%(asctime)s %(levelname)8s %(name)s: %(message)s"
handlers:
console:
class: logging.StreamHandler
formatter: standard
root:
handlers: ['console']
level: DEBUG
--log-config-file
(已弃用)
日志配置文件。
如果给定相对路径,则是相对于当前工作目录的相对路径。
如果提供一个 .conf
或 .ini
文件,它将被直接传递给 logging.config.fileConfig(),因此文件内容必须遵循 配置文件格式。
一个简单的日志配置(也见 log.conf),类似于默认配置,如下所示
[formatters]
keys=standard
[handlers]
keys=console
[loggers]
keys=root
[formatter_standard]
format=%(asctime)s %(levelname)8s %(name)s: %(message)s
[handler_console]
class=StreamHandler
formatter=standard
[logger_root]
level=INFO
handlers=console
一个更详细的示例日志配置,使用滚动文件处理器:log-verbose.conf
上面的相同示例(也见 log.yml)可以用 YAML 实现
version: 1
formatters:
standard:
format: "%(asctime)s %(levelname)8s %(name)s: %(message)s"
handlers:
console:
class: logging.StreamHandler
formatter: standard
root:
handlers: ['console']
level: DEBUG
致谢
项目负责人
- 蒂亚戈·库蒂尼奥 coutinhotiago@gmail.com
贡献者
暂无。为何不成为第一个呢?
历史
0.6.1 (2021-09-29)
- 将默认命令行
--modbus-connection-time
从 0.1 更改为 0 - 添加基本单元测试
- Github 动作
- 仓库清理
0.5.0 (2021-09-28)
- 添加对多台设备的支持
- 适配 Docker 变更
- 弃用
--log-config-file
命令行参数
0.4.2 (2021-09-23)
- 添加连接时间延迟(修复 #4)
0.4.1 (2021-01-26)
- 日志改进
0.4.0 (2021-01-26)
- 日志改进
0.3.0 (2021-01-25)
- 更健壮的服务器(修复 #2)
0.2.0 (2021-01-23)
- 文档(README)
- 添加 Docker 指令(修复 #1)
- 修复设置依赖和元数据
0.1.1 (2020-12-02)
- 修复项目包
0.1.0 (2020-11-11)
- 首次发布在 PyPI。
项目详情
下载文件
下载适用于您的平台的文件。如果您不确定选择哪个,请了解更多关于 安装软件包 的信息。