Skip to content

Pymodbus Simulator Guide


The Pymodbus Simulator is a Modbus Server that can be used as an endpoint for testing communication with the Modbus Device Service Component.

The simulator is available on Docker Hub at iotechsys/pymodbus-sim.

Running the simulator

The Pymodbus simulator can be run with the following command:

docker run -d --rm --name pymodbus-sim iotechsys/pymodbus-sim:1.0

The above command will start the simulator and initialise all registers to 0 within each primary table.

The above command does not make use of any optional arguments, so the default configuration of TCP protocol with port 5020 is used.


For most use cases, it is recommended to run the simulator with an Xrt device profile. Please see the Profile configuration section below.

Configuration Options


When run with an Xrt device profile, the simulator will initialise only registers which are covered by a resource. It will not allow any reads or writes outside these registers, making it easier to check that modbus requests to the simulator are correct. This profile must be mounted into the Docker container at runtime to allow the simulator to access the file.

The Pymodbus simulator can be run with a device profile using the following command:

docker run -d --rm \
-v host_dir_with_profile:/sim_files \
--name pymodbus-sim iotechsys/pymodbus-sim:1.0 \
--profile /sim_files/modbus_device_profile.json

In the above command, the -v option is used to mount a directory containing a profile into the docker container. This profile is then selected using the --profile option.


The default transmission protocol is TCP, however a serial connection is also possible using the option --comm serial. Additional configuration is also required for a serial connection. For more information, read the Serial Connection section below.


The --port argument is used to specify the port on which the simulator should be available.

For a TCP connection, the default value is 5020. For a serial connection, this option must be set.


The --script argument is used to specify a file which details how the values within the simulator should be set on initialisation and/or how they should be updated over time. This file may contain one or both of the following Python functions.


The --script option can only be used when --profile is also set.

To set values once upon startup, the set_initial(resources) function may be implemented. This takes in a map of available resources resources as the only parameter. This map is keyed by resource name, and contains a Resource object for each. To set the value of any given resource, retrieve its Resource object and use the set_value(value) function. For example:

def set_initial(resources):
    this_resource = resources.get("resource name")

The set_value(value) function does not apply any scale or additive on the resource, and must be passed the exact value to be stored in the register(s).

Type conversion for resources with a different valueType and rawType is also not supported. The value is written as the resource rawType if one is present, otherwise it is written as the valueType.

For string resources, a string can be passed directly to set_value(value).

The update_values(resources) function can also be implemented in order to update values at a given interval. This also takes in the same resources map in the same format. A Resource object also contains a get_value() function, which is useful for incrementing values over time. For example:

def update_values(resources):
    this_resource = resources.get("resource name")
    previous_value = this_resource.get_value()
    this_resource.set_value(previous_value + 3)


The --delay option determines the time in seconds between iterations of the update_values() function. For this to have any effect, the script argument must also be used to select a file containing the update_values() function.

The default value of --delay is 1 second.


The --log argument sets the log level for the simulator. Valid options are: critical, error, warning, info and debug.

The default log level is info.

Serial Connection

To facilitate a virtual serial connection from within a Docker container, the socat command line tool is required.

First, a TCP listener is set up inside the container. This is done automatically whenever the argument --comm serial is used, and requires the use of another argument --serial_over_tcp_port, specifying the TCP port on which to transfer the data out from the container.

For example:

docker run -d --rm\
-v host_dir_with_profile:/sim_files \
--network=host \
--name pymodbus-sim iotechsys/pymodbus-sim:1.0 \
--profile /sim_files/modbus_device_profile.json \
--comm serial \
--serial_over_tcp_port 50103

On the host machine, socat must again be used to transfer the data from the TCP connection back to a virtual serial port. This can be done with the following command:

socat pty,link=/tmp/virtualport,raw,echo=0 tcp:localhost:50103

After using the above command, a device can be configured within Xrt using "address": "/tmp/virtualport".