Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SimData update (Still not operational). #2601

Merged
merged 1 commit into from
Mar 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Please select a topic in the left hand column.
source/server
source/repl
source/simulator3
source/simulator
source/simulator/simulator
source/examples
source/authors
source/changelog
Expand Down
Binary file modified doc/source/_static/examples.tgz
Binary file not shown.
Binary file modified doc/source/_static/examples.zip
Binary file not shown.
20 changes: 10 additions & 10 deletions doc/source/library/pymodbus.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,6 @@ Extra functions
:undoc-members:
:show-inheritance:

.. automodule:: pymodbus.device
:members:
:undoc-members:
:show-inheritance:

.. automodule:: pymodbus.events
:members:
:undoc-members:
:show-inheritance:

.. automodule:: pymodbus.exceptions
:members:
:undoc-members:
Expand Down Expand Up @@ -75,3 +65,13 @@ PDU classes
:members:
:undoc-members:
:show-inheritance:

.. automodule:: pymodbus.pdu.device
:members:
:undoc-members:
:show-inheritance:

.. automodule:: pymodbus.pdu.events
:members:
:undoc-members:
:show-inheritance:
4 changes: 2 additions & 2 deletions doc/source/server.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Server
======
Server (3.x)
============

Pymodbus offers servers with transport protocols for

Expand Down
114 changes: 0 additions & 114 deletions doc/source/simulator.rst

This file was deleted.

54 changes: 54 additions & 0 deletions doc/source/simulator/datamodel.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
Data model configuration
------------------------
The simulator data model represent the registers and parameters of the simulated devices.
The data model is defined using :class:`SimData` and :class:`SimDevice` before starting the
server and cannot be changed without restarting the server.

:class:`SimData` defines a group of continuous identical registers. This is the basis of the model,
multiple :class:`SimData` are used to mirror the physical device.

:class:`SimDevice` defines device parameters and a list of :class:`SimData`. The
list of :class:`SimData` can be added as shared registers or as 4 separate blocks as defined in modbus.
:class:`SimDevice` are used to simulate a single device, while a list of
:class:`SimDevice` simulates a multipoint line (rs485 line) or a serial forwarder.

A server consist of communication parameters and a list of :class:`SimDevice`


Usage examples
^^^^^^^^^^^^^^
.. literalinclude:: ../../../examples/server_datamodel.py
:language: python


Class definitions
^^^^^^^^^^^^^^^^^
.. autoclass:: pymodbus.simulator.SimData
:members:
:undoc-members:
:show-inheritance:
:member-order: bysource

.. autoclass:: pymodbus.simulator.SimDevice
:members:
:undoc-members:
:show-inheritance:
:member-order: bysource

.. autoclass:: pymodbus.simulator.SimDataType
:members:
:undoc-members:
:show-inheritance:
:member-order: bysource

.. autoclass:: pymodbus.simulator.SimValueType
:members:
:undoc-members:
:show-inheritance:
:member-order: bysource

.. autoclass:: pymodbus.simulator.SimAction
:members:
:undoc-members:
:show-inheritance:
:member-order: bysource
4 changes: 4 additions & 0 deletions doc/source/simulator/restapi.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
REST API
--------

.. note:: This is a v4.0.0 functionality currently not available, please see the 3x simulator server.
4 changes: 4 additions & 0 deletions doc/source/simulator/server.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Simulator server
----------------

.. note:: This is a v4.0.0 functionality currently not available, please see the 3x simulator server.
49 changes: 49 additions & 0 deletions doc/source/simulator/simulator.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
Server/Simulator
================

**WORK IN PROGRESS, do NOT use**

The simulator is a full fledged modbus server/simulator.

The purpose of the simulator is to provide support for client
application test harnesses with end-to-end testing simulating real life
modbus devices.

The simulator allows the user to (all automated):

- simulate a modbus device by adding a simple configuration,
- simulate a multipoint line, but adding multiple device configurations,
- simulate devices that are not conforming to the protocol,
- simulate communication problems (data loss etc),
- test how a client handles modbus response and exceptions,
- test a client apps correct use of the simulated device.

The web interface (activated optionally) allows the user to:

- introduce modbus errors (like e.g. wrong length),
- introduce communication errors (like splitting a message),
- monitor requests/responses,
- see/Change values online.
- inject modbus errors like malicious a response,
- run your test server in the cloud,

The REST API allow the test process to be automated

- spin up a test server in your test harness,
- set expected responses with a simple REST API command,
- check the result with a simple REST API command,
- test your client app in a true end-to-end fashion.

The web server uses the REST API internally, which helps to ensure that it
actually works.


.. toctree::
:maxdepth: 8
:caption: Contents:
:hidden:

./datamodel
./server
./web
./restapi
4 changes: 4 additions & 0 deletions doc/source/simulator/web.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Web frontend
------------

.. note:: This is a v4.0.0 functionality currently not available, please see the 3x simulator server.
8 changes: 5 additions & 3 deletions doc/source/upgrade_40.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,17 @@ Please replace by result.convert_from_registers() and/or convert_to_registers()
Simple replacements
-------------------

please replace
please replace parameters as follows

- slave= with device_id=
- slaves= with device_ids=
- ModbusServerContext(slaves=) with ModbusServerContext(devices=)

please rename
please rename classes/methods as follows

- ModbusSlaveContext to ModbusDeviceContext
- RemoteSlaveContext to RemoteDeviceContext
- report_slave_id() with report_device_id()
- report_slave_id to report_device_id
- diag_read_slave_message_count with diag_read_device_message_count
- diag_read_slave_no_response_count with diag_read_device_no_response_count
- diag_read_slave_nak_count with diag_read_device_nak_count
Expand Down
78 changes: 78 additions & 0 deletions examples/server_datamodel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#!/usr/bin/env python3
"""Pymodbus server datamodel examples.

This file shows examples of how to configure the datamodel for the server/simulator.

There are different examples showing the flexibility of the datamodel.
"""

from pymodbus.simulator import SimData, SimDataType, SimDevice


def define_datamodel():
"""Define register groups.

Coils and direct inputs are modeled as bits representing a relay in the device.
There are no real difference between coils and direct inputs, but historically
they have been divided. Please be aware the coils and direct inputs are addressed differently
in shared vs non-shared models.
- In a non-shared model the address is the bit directly.
It can be thought of as if 1 register == 1 bit.
- In a shared model the address is the register containing the bits.
1 register == 16bit, so a single bit CANNOT be addressed directly.

Holding registers and input registers are modeled as int/float/string representing a sensor in the device.
There are no real difference between holding registers and input registers, but historically they have
been divided.
Please be aware that 1 sensor might be modeled as several register because it needs more than
16 bit for accuracy (e.g. a INT32).
"""
# SimData can be instantiated with positional or optional parameters:
assert SimData(
5, 17, 10, SimDataType.REGISTERS
) == SimData(
address=5, value=17, count=10, datatype=SimDataType.REGISTERS
)

# Define a group of coils/direct inputs non-shared (address=15..31 each 1 bit)
block1 = SimData(address=15, value=True, count=16, datatype=SimDataType.BITS)
# Define a group of coils/direct inputs shared (address=15..31 each 16 bit)
block2 = SimData(address=15, value=0xFFFF, count=16, datatype=SimDataType.BITS)

# Define a group of holding/input registers (remark NO difference between shared and non-shared)
block3 = SimData(10, 123.4, datatype=SimDataType.FLOAT32)
block4 = SimData(17, value=123, count=5, datatype=SimDataType.INT64)
block5 = SimData(27, "Hello ", datatype=SimDataType.STRING)

# Please use SimDataType.DEFAULT to define register limits.
# this datatype only uses 1 object, whereas SimDataType.REGISTERS uses <count> objects,
# mean SimDataType.DEFAULT is factors more efficient and much less memory consuming
block_def = SimData(0, count=1000, datatype=SimDataType.DEFAULT)

# SimDevice can be instantiated with positional or optional parameters:
assert SimDevice(
5,False, [block_def, block5]
) == SimDevice(
id=5, type_check=False, block_shared=[block_def, block5]
)

# SimDevice can define either a shared or a non-shared register model
SimDevice(1, False, block_shared=[block_def, block5])
SimDevice(2, False,
block_coil=[block1],
block_direct=[block1],
block_holding=[block2],
block_input=[block3, block4])
# Remark: it is legal to reuse SimData, the object is only used for configuration,
# not for runtime.

# id=0 in a SimDevice act as a "catch all". Requests to an unknown id is executed in this SimDevice.
SimDevice(0, block_shared=[block2])


def main():
"""Combine setup and run."""
define_datamodel()

if __name__ == "__main__":
main()
Loading