Package: modbus-proxy
ModBus TCP proxyMany modbus devices support only one or very few clients. This proxy acts as a bridge between the client and the modbus device. It can be seen as a
layer 7 reverse proxy.
This allows multiple clients to communicate with the same modbus device.When multiple clients are connected, cross messages are avoided by serializing communication on a first come first served REQ/REP basis.InstallationFrom within your favorite python 3 environment type:$ pip install modbus-proxyNote: On some systemspippoints to a python 2 installation.
You might need to usepip3command instead.Additionally, if you want logging configuration:YAML:pip install modbus-proxy[yaml](see below)TOML:pip install modbus-proxy[toml](see below)Running the serverFirst, you will need write a configuration file where you specify for each modbus device you which to control:modbus connection (the modbus device url)listen interface (to which url your clients should connect)Configuration files can be written in YAML (.ymlor.yaml) or TOML (.toml).Suppose you have a PLC modbus device listening onplc1.acme.org:502and you want your clients to
connect to your machine on port 9000. A YAML configuration would look like this: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)Assuming you saved this file asmodbus-config.yml, start the server with:$modbus-proxy-c./modbus-config.ymlNow, instead of connecting your client(s) toplc1.acme.org:502you just need to
tell them to connect to*machine*:9000(wheremachineis the host where
modbus-proxy is running).Note that the server is capable of handling multiple modbus devices. Here is a
configuration example for 2 devices:devices:-modbus:url:plc1.acme.org:502listen:bind:0:9000-modbus:url:plc2.acme.org:502listen:bind:0:9001If you have asinglemodbus device, you can avoid writting a configuration file by
providing all arguments in the command line:modbus-proxy-btcp://0:9000--modbustcp://plc1.acme.org:502(hint: runmodbus-proxy --helpto see all available options)Running the examplesTo run the examples you will need to haveumodbusinstalled (do it
withpip install umodbus).Start thesimple_tcp_server.py(this will simulate an actual modbus hardware):$pythonexamples/simple_tcp_server.py-b:5020You can run the example client just to be sure direct communication works:$pythonexamples/simple_tcp_client.py-a0:5020
holdingregisters:[1,2,3,4]Now for the real test:Start a modbus-proxy bridge server with:$modbus-proxy-btcp://:9000--modbustcp://:5020Finally run a the example client but now address the proxy instead of the server
(notice we are now using port9000and not5020):$pythonexamples/simple_tcp_client.py-a0:9000
holdingregisters:[1,2,3,4]DockerThis project ships with a basicDockerfilewhich you can use
as a base to launch modbus-proxy inside a docker container.First, build the docker image with:$dockerbuild-tmodbus-proxy.To bridge a single modbus device without needing a configuration file is
straight forward:$dockerrun-d-p5020:502modbus-proxy-btcp://0:502--modbustcp://plc1.acme.org:502Now you should be able to access your modbus device through the modbus-proxy by
connecting your client(s) to<your-hostname/ip>:5020.If, instead, you want to use a configuration file, you must mount the file so
it is visible by the container.Assuming you have prepared aconf.ymlin the current directory:devices:-modbus:url:plc1.acme.org:502listen:bind:0:502Here is an example of how to run the container:dockerrun-p5020:502-v$PWD/conf.yml:/src/conf.ymlmodbus-proxy-c/src/conf.ymlNote that for each modbus device you add in the configuration file you need
to publish the corresponding bind port on the host
(-p <host port>:<container port>argument).Logging configurationLogging configuration can be added to the configuration file by adding a newloggingkeyword.The logging configuration will be passed tologging.config.dictConfig()so the file contents must obey theConfiguration dictionary schema.Here is a YAML example:devices:-modbus:url:plc1.acme.org:502listen:bind:0:9000logging:version:1formatters:standard:format:"%(asctime)s%(levelname)8s%(name)s:%(message)s"handlers:console:class:logging.StreamHandlerformatter:standardroot:handlers:['console']level:DEBUG--log-config-file(deprecated)Logging configuration file.If a relative path is given, it is relative to the current working directory.If a.confor.inifile is given, it is passed directly tologging.config.fileConfig()so the file contents must
obey theConfiguration file format.A simple logging configuration (also available atlog.conf)
which mimics the default configuration looks like this:[formatters]keys=standard[handlers]keys=console[loggers]keys=root[formatter_standard]format=%(asctime)s%(levelname)8s%(name)s:%(message)s[handler_console]class=StreamHandlerformatter=standard[logger_root]level=INFOhandlers=consoleA more verbose example logging with a rotating file handler:log-verbose.confThe same example above (also available atlog.yml) can be achieved in YAML with:version:1formatters:standard:format:"%(asctime)s%(levelname)8s%(name)s:%(message)s"handlers:console:class:logging.StreamHandlerformatter:standardroot:handlers:['console']level:DEBUGCreditsDevelopment LeadTiago Coutinhocoutinhotiago@gmail.comContributorsNone yet. Why not be the first?History0.6.1 (2021-09-29)Change default command line--modbus-connection-timefrom 0.1 to 0Add basic unit testsGithub actionsRepository cleanup0.5.0 (2021-09-28)Add support for multiple devicesAdapt docker to changesDeprecate--log-config-filecommand line parameter0.4.2 (2021-09-23)Add connection time delay (fixes #4)0.4.1 (2021-01-26)Logging improvements0.4.0 (2021-01-26)Logging improvements0.3.0 (2021-01-25)More robust server (fixes #2)0.2.0 (2021-01-23)Document (README)Add docker intructions (fixes #1)Fix setup dependencies and meta data0.1.1 (2020-12-02)Fix project package0.1.0 (2020-11-11)First release on PyPI.