Skip to content

Commit db4b933

Browse files
authored
SimData update. (#2601)
1 parent 2f87de9 commit db4b933

21 files changed

+357
-239
lines changed

doc/index.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Please select a topic in the left hand column.
1414
source/server
1515
source/repl
1616
source/simulator3
17-
source/simulator
17+
source/simulator/simulator
1818
source/examples
1919
source/authors
2020
source/changelog

doc/source/_static/examples.tgz

1.21 KB
Binary file not shown.

doc/source/_static/examples.zip

1.32 KB
Binary file not shown.

doc/source/library/pymodbus.rst

+10-10
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,6 @@ Extra functions
66
:undoc-members:
77
:show-inheritance:
88

9-
.. automodule:: pymodbus.device
10-
:members:
11-
:undoc-members:
12-
:show-inheritance:
13-
14-
.. automodule:: pymodbus.events
15-
:members:
16-
:undoc-members:
17-
:show-inheritance:
18-
199
.. automodule:: pymodbus.exceptions
2010
:members:
2111
:undoc-members:
@@ -75,3 +65,13 @@ PDU classes
7565
:members:
7666
:undoc-members:
7767
:show-inheritance:
68+
69+
.. automodule:: pymodbus.pdu.device
70+
:members:
71+
:undoc-members:
72+
:show-inheritance:
73+
74+
.. automodule:: pymodbus.pdu.events
75+
:members:
76+
:undoc-members:
77+
:show-inheritance:

doc/source/server.rst

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
Server
2-
======
1+
Server (3.x)
2+
============
33

44
Pymodbus offers servers with transport protocols for
55

doc/source/simulator.rst

-114
This file was deleted.

doc/source/simulator/datamodel.rst

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
Data model configuration
2+
------------------------
3+
The simulator data model represent the registers and parameters of the simulated devices.
4+
The data model is defined using :class:`SimData` and :class:`SimDevice` before starting the
5+
server and cannot be changed without restarting the server.
6+
7+
:class:`SimData` defines a group of continuous identical registers. This is the basis of the model,
8+
multiple :class:`SimData` are used to mirror the physical device.
9+
10+
:class:`SimDevice` defines device parameters and a list of :class:`SimData`. The
11+
list of :class:`SimData` can be added as shared registers or as 4 separate blocks as defined in modbus.
12+
:class:`SimDevice` are used to simulate a single device, while a list of
13+
:class:`SimDevice` simulates a multipoint line (rs485 line) or a serial forwarder.
14+
15+
A server consist of communication parameters and a list of :class:`SimDevice`
16+
17+
18+
Usage examples
19+
^^^^^^^^^^^^^^
20+
.. literalinclude:: ../../../examples/server_datamodel.py
21+
:language: python
22+
23+
24+
Class definitions
25+
^^^^^^^^^^^^^^^^^
26+
.. autoclass:: pymodbus.simulator.SimData
27+
:members:
28+
:undoc-members:
29+
:show-inheritance:
30+
:member-order: bysource
31+
32+
.. autoclass:: pymodbus.simulator.SimDevice
33+
:members:
34+
:undoc-members:
35+
:show-inheritance:
36+
:member-order: bysource
37+
38+
.. autoclass:: pymodbus.simulator.SimDataType
39+
:members:
40+
:undoc-members:
41+
:show-inheritance:
42+
:member-order: bysource
43+
44+
.. autoclass:: pymodbus.simulator.SimValueType
45+
:members:
46+
:undoc-members:
47+
:show-inheritance:
48+
:member-order: bysource
49+
50+
.. autoclass:: pymodbus.simulator.SimAction
51+
:members:
52+
:undoc-members:
53+
:show-inheritance:
54+
:member-order: bysource

doc/source/simulator/restapi.rst

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
REST API
2+
--------
3+
4+
.. note:: This is a v4.0.0 functionality currently not available, please see the 3x simulator server.

doc/source/simulator/server.rst

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Simulator server
2+
----------------
3+
4+
.. note:: This is a v4.0.0 functionality currently not available, please see the 3x simulator server.

doc/source/simulator/simulator.rst

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
Server/Simulator
2+
================
3+
4+
**WORK IN PROGRESS, do NOT use**
5+
6+
The simulator is a full fledged modbus server/simulator.
7+
8+
The purpose of the simulator is to provide support for client
9+
application test harnesses with end-to-end testing simulating real life
10+
modbus devices.
11+
12+
The simulator allows the user to (all automated):
13+
14+
- simulate a modbus device by adding a simple configuration,
15+
- simulate a multipoint line, but adding multiple device configurations,
16+
- simulate devices that are not conforming to the protocol,
17+
- simulate communication problems (data loss etc),
18+
- test how a client handles modbus response and exceptions,
19+
- test a client apps correct use of the simulated device.
20+
21+
The web interface (activated optionally) allows the user to:
22+
23+
- introduce modbus errors (like e.g. wrong length),
24+
- introduce communication errors (like splitting a message),
25+
- monitor requests/responses,
26+
- see/Change values online.
27+
- inject modbus errors like malicious a response,
28+
- run your test server in the cloud,
29+
30+
The REST API allow the test process to be automated
31+
32+
- spin up a test server in your test harness,
33+
- set expected responses with a simple REST API command,
34+
- check the result with a simple REST API command,
35+
- test your client app in a true end-to-end fashion.
36+
37+
The web server uses the REST API internally, which helps to ensure that it
38+
actually works.
39+
40+
41+
.. toctree::
42+
:maxdepth: 8
43+
:caption: Contents:
44+
:hidden:
45+
46+
./datamodel
47+
./server
48+
./web
49+
./restapi

doc/source/simulator/web.rst

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Web frontend
2+
------------
3+
4+
.. note:: This is a v4.0.0 functionality currently not available, please see the 3x simulator server.

doc/source/upgrade_40.rst

+5-3
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,17 @@ Please replace by result.convert_from_registers() and/or convert_to_registers()
2727
Simple replacements
2828
-------------------
2929

30-
please replace
30+
please replace parameters as follows
31+
3132
- slave= with device_id=
3233
- slaves= with device_ids=
3334
- ModbusServerContext(slaves=) with ModbusServerContext(devices=)
3435

35-
please rename
36+
please rename classes/methods as follows
37+
3638
- ModbusSlaveContext to ModbusDeviceContext
3739
- RemoteSlaveContext to RemoteDeviceContext
38-
- report_slave_id() with report_device_id()
40+
- report_slave_id to report_device_id
3941
- diag_read_slave_message_count with diag_read_device_message_count
4042
- diag_read_slave_no_response_count with diag_read_device_no_response_count
4143
- diag_read_slave_nak_count with diag_read_device_nak_count

examples/server_datamodel.py

+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
#!/usr/bin/env python3
2+
"""Pymodbus server datamodel examples.
3+
4+
This file shows examples of how to configure the datamodel for the server/simulator.
5+
6+
There are different examples showing the flexibility of the datamodel.
7+
"""
8+
9+
from pymodbus.simulator import SimData, SimDataType, SimDevice
10+
11+
12+
def define_datamodel():
13+
"""Define register groups.
14+
15+
Coils and direct inputs are modeled as bits representing a relay in the device.
16+
There are no real difference between coils and direct inputs, but historically
17+
they have been divided. Please be aware the coils and direct inputs are addressed differently
18+
in shared vs non-shared models.
19+
- In a non-shared model the address is the bit directly.
20+
It can be thought of as if 1 register == 1 bit.
21+
- In a shared model the address is the register containing the bits.
22+
1 register == 16bit, so a single bit CANNOT be addressed directly.
23+
24+
Holding registers and input registers are modeled as int/float/string representing a sensor in the device.
25+
There are no real difference between holding registers and input registers, but historically they have
26+
been divided.
27+
Please be aware that 1 sensor might be modeled as several register because it needs more than
28+
16 bit for accuracy (e.g. a INT32).
29+
"""
30+
# SimData can be instantiated with positional or optional parameters:
31+
assert SimData(
32+
5, 17, 10, SimDataType.REGISTERS
33+
) == SimData(
34+
address=5, value=17, count=10, datatype=SimDataType.REGISTERS
35+
)
36+
37+
# Define a group of coils/direct inputs non-shared (address=15..31 each 1 bit)
38+
block1 = SimData(address=15, value=True, count=16, datatype=SimDataType.BITS)
39+
# Define a group of coils/direct inputs shared (address=15..31 each 16 bit)
40+
block2 = SimData(address=15, value=0xFFFF, count=16, datatype=SimDataType.BITS)
41+
42+
# Define a group of holding/input registers (remark NO difference between shared and non-shared)
43+
block3 = SimData(10, 123.4, datatype=SimDataType.FLOAT32)
44+
block4 = SimData(17, value=123, count=5, datatype=SimDataType.INT64)
45+
block5 = SimData(27, "Hello ", datatype=SimDataType.STRING)
46+
47+
# Please use SimDataType.DEFAULT to define register limits.
48+
# this datatype only uses 1 object, whereas SimDataType.REGISTERS uses <count> objects,
49+
# mean SimDataType.DEFAULT is factors more efficient and much less memory consuming
50+
block_def = SimData(0, count=1000, datatype=SimDataType.DEFAULT)
51+
52+
# SimDevice can be instantiated with positional or optional parameters:
53+
assert SimDevice(
54+
5,False, [block_def, block5]
55+
) == SimDevice(
56+
id=5, type_check=False, block_shared=[block_def, block5]
57+
)
58+
59+
# SimDevice can define either a shared or a non-shared register model
60+
SimDevice(1, False, block_shared=[block_def, block5])
61+
SimDevice(2, False,
62+
block_coil=[block1],
63+
block_direct=[block1],
64+
block_holding=[block2],
65+
block_input=[block3, block4])
66+
# Remark: it is legal to reuse SimData, the object is only used for configuration,
67+
# not for runtime.
68+
69+
# id=0 in a SimDevice act as a "catch all". Requests to an unknown id is executed in this SimDevice.
70+
SimDevice(0, block_shared=[block2])
71+
72+
73+
def main():
74+
"""Combine setup and run."""
75+
define_datamodel()
76+
77+
if __name__ == "__main__":
78+
main()

0 commit comments

Comments
 (0)