跳转到主要内容

ModBus TCP代理

项目描述

ModBus TCP代理

ModBus proxy Python Versions Pypi status License CI

许多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]

以服务形式运行

  1. 将配置文件移动到您能记住的位置,例如:到/usr/lib/mproxy-conf.yaml
  2. 转到/etc/systemd/system/
  3. 使用nano或其他您选择的文本编辑器创建服务文件mproxy.service
  4. 该文件应包含以下信息
[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
  1. 运行systemctl daemon-reload
  2. systemctl enable mproxy.service
  3. 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

致谢

项目负责人

贡献者

暂无。为何不成为第一个呢?

历史

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。

项目详情


下载文件

下载适用于您的平台的文件。如果您不确定选择哪个,请了解更多关于 安装软件包 的信息。

源代码分布

modbus_proxy-0.8.0.tar.gz (13.8 kB 查看散列值)

上传时间: 源代码

构建分布

modbus_proxy-0.8.0-py2.py3-none-any.whl (9.6 kB 查看散列值)

上传时间: Python 2 Python 3

支持

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF 赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误记录 StatusPage StatusPage 状态页面