Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
janiversen committed Feb 9, 2025
2 parents de93b82 + d0d2084 commit 56eefe6
Show file tree
Hide file tree
Showing 28 changed files with 600 additions and 75 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ helps make pymodbus a better product.

:ref:`Authors`: contains a complete list of volunteers have contributed to each major version.

Version 3.8.5
-------------
* New simulator is WIP, not to be used. (#2568)
* dev_id=0 no response expected (returns ExceptionResponse(0xff)). (#2567)
* New simulator datastore. (#2535)

Version 3.8.4
-------------
* Parameterize string encoding in convert_to_registers and convert_from_registers (#2558)
Expand Down
4 changes: 2 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ Our releases is defined as X.Y.Z, and we have strict rules what to release when:

Upgrade examples:

- 3.8.1 -> 3.8.3: just plugin the new version, no changes needed.
- 3.8.1 -> 3.8.5: just plugin the new version, no changes needed.
- 3.7.1 -> 3.8.0: Smaller changes to the pymodbus calls might be needed
- 2.5.4 -> 3.0.0: Major changes in the application might be needed

Current release is `3.8.4 <https://github.com/pymodbus-dev/pymodbus/releases/tag/v3.8.4>`_.
Current release is `3.8.5 <https://github.com/pymodbus-dev/pymodbus/releases/tag/v3.8.5>`_.

Bleeding edge (not released) is `dev <https://github.com/pymodbus-dev/pymodbus/tree/dev>`_.

Expand Down
5 changes: 3 additions & 2 deletions doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ Please select a topic in the left hand column.
source/client
source/server
source/repl
source/simulator3
source/simulator
source/examples
source/authors
source/changelog
source/internals
source/roadmap
.. include:: ../README.rst

.. include:: ../README.rst
Binary file modified doc/source/_static/examples.tgz
Binary file not shown.
Binary file modified doc/source/_static/examples.zip
Binary file not shown.
2 changes: 1 addition & 1 deletion doc/source/library/simulator/config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ each containing a list of servers/devices
}
You can define as many server and devices as you like, when starting
:ref:`pymodbus.simulator` you select one server and one device to simulate.
:ref:`pymodbus.simulator (v3.x)` you select one server and one device to simulate.

A entry in “device_list” correspond to the dict you can use as parameter
to datastore_simulator is you want to construct your own simulator.
Expand Down
8 changes: 4 additions & 4 deletions doc/source/library/simulator/web.rst
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
Web frontend
============
Web frontend v3.x
=================

TO BE DOCUMENTED.



pymodbus.simulator
------------------
pymodbus.simulator (v3.x)
-------------------------

The easiest way to run the simulator with web is to use "pymodbus.simulator" from the commandline.

Expand Down
2 changes: 1 addition & 1 deletion doc/source/roadmap.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ It is the community that decides how pymodbus evolves NOT the maintainers !

The following bullet points are what the maintainers focus on:

- 3.8.5 bug fix release, with:
- 3.8.6 bug fix release, with:
- Currently not planned
- 3.9.0, with:
- All of branch wait_next_api
Expand Down
102 changes: 84 additions & 18 deletions doc/source/simulator.rst
Original file line number Diff line number Diff line change
@@ -1,40 +1,106 @@
Simulator
=========

The simulator is a full fledged modbus simulator, which is
constantly being evolved with user ideas / amendments.
**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 datastore simulator allows the user to (all automated)
The simulator allows the user to (all automated):

- simulate a modbus device by adding a simple configuration,
- test how a client handles modbus exceptions,
- 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 allows the user to (online / manual)
The web interface (activated optionally) allows the user to:

- test how a client handles modbus errors,
- test how a client handles communication errors like divided messages,
- run your test server in the cloud,
- introduce modbus errors (like e.g. wrong length),
- introduce communication errors (like splitting a message),
- monitor requests/responses,
- inject modbus errors like malicious a response,
- 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 with unix domain sockets in your test harness,
- spin up a test server in your test harness,
- set expected responses with a simple REST API command,
- check the result with another simple REST API command,
- check the result with a simple REST API command,
- test your client app in a true end-to-end fashion.

.. toctree::
:maxdepth: 4
:hidden:
The web server uses the REST API internally, which helps to ensure that it
actually works.


Data model configuration
------------------------

.. warning:: from v3.9.0 this is available as a "normal" datastore model.

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` should be used to mirror the physical device.

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

A server consist of communication parameters and a device or a list of devices

:class:`SimDataType` is a helper class that defines legal datatypes.

:class:`SimActions` is a helper class that defines built in actions.

:github:`examples/simulator_datamodel.py` contains usage examples.

SimData
^^^^^^^

.. autoclass:: pymodbus.simulator.SimData
:members:
:undoc-members:
:show-inheritance:

SimDevice
^^^^^^^^^

.. autoclass:: pymodbus.simulator.SimDevice
:members:
:undoc-members:
:show-inheritance:

SimDataType
^^^^^^^^^^^

.. autoclass:: pymodbus.simulator.SimDataType
:members:
:undoc-members:
:show-inheritance:


Simulator server
----------------

.. note:: This is a v4.0.0 functionality currently not available, please see the 3x simulator server.


Web frontend
------------

.. note:: This is a v4.0.0 functionality currently not available, please see the 3x simulator server.


REST API
--------

library/simulator/config
library/simulator/datastore
library/simulator/web
library/simulator/restapi
.. note:: This is a v4.0.0 functionality currently not available, please see the 3x simulator server.
42 changes: 42 additions & 0 deletions doc/source/simulator3.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
Simulator (3.x)
===============

.. warning:: Beginning with v3.9.0 and ending with v4.0.0 this simulator will be replaced by a new version.

The simulator is a full fledged modbus simulator, which is
constantly being evolved with user ideas / amendments.

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 datastore simulator allows the user to (all automated)

- simulate a modbus device by adding a simple configuration,
- test how a client handles modbus exceptions,
- test a client apps correct use of the simulated device.

The web interface allows the user to (online / manual)

- test how a client handles modbus errors,
- test how a client handles communication errors like divided messages,
- run your test server in the cloud,
- monitor requests/responses,
- inject modbus errors like malicious a response,
- see/Change values online.

The REST API allow the test process to be automated

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

.. toctree::
:maxdepth: 4
:hidden:

library/simulator/config
library/simulator/datastore
library/simulator/web
library/simulator/restapi
3 changes: 2 additions & 1 deletion examples/client_async_calls.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,8 @@ async def async_execute_diagnostic_requests(client):
assert not rr.isError() # test that call was OK
rr = await client.diag_getclear_modbus_response(slave=SLAVE)
assert not rr.isError() # test that call was OK
assert not await client.diag_force_listen_only(slave=SLAVE, no_response_expected=True)
rr = await client.diag_force_listen_only(slave=SLAVE, no_response_expected=True)
assert rr.isError() # test that call was OK, error indicate no response


# ------------------------
Expand Down
71 changes: 71 additions & 0 deletions examples/simulator_datamodel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#!/usr/bin/env python3
"""Pymodbus simulator datamodel examples.
**WORK IN PROGRESS, do NOT use**
This example shows how to configure the simulator datamodel to mimic a real
device.
There are different examples, to show the flexibility of the simulator datamodel.
.. tip:: This is NOT the pymodbus simulator, that is started as pymodbus.simulator.
"""

from pymodbus.simulator import SimCheckConfig, SimData, SimDataType, SimDevice


def define_registers():
"""Define simulator data model.
Coils and direct inputs are expressed as bits representing a relay in the device.
There are no real difference between coils and direct inputs, but historically
they have been divided.
Holding registers and input registers are the same, but historically they have
been divided.
Coils and direct inputs are handled 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 a
register only contains 1 bit.
- In a shared model the address is the register containing the bits. So a single bit CANNOT
be addressed directly.
"""
# Define a group of coils (remark difference between shared and non-shared)
block_coil = [SimData(0, count=100, datatype=SimDataType.DEFAULT),
SimData(0, True, 16)]
block_coil_shared = [SimData(0, 0xFFFF, 16)]

# SimData can be reused with copying
block_direct = block_coil

# Define a group of registers (remark NO difference between shared and non-shared)
block_holding = [SimData(10, count=100, datatype=SimDataType.DEFAULT),
SimData(10, 123.4, datatype=SimDataType.FLOAT32),
SimData(12, 123456789.3, datatype=SimDataType.FLOAT64),
SimData(17, value=123, count=5, datatype=SimDataType.INT32),
SimData(27, "Hello ", datatype=SimDataType.STRING)]
block_input = block_holding
block_shared = [SimData(10, 123.4, datatype=SimDataType.FLOAT32),
SimData(12, 123456789.3, datatype=SimDataType.FLOAT64),
SimData(16, 0xf0f0, datatype=SimDataType.BITS),
SimData(17, value=123, count=5, datatype=SimDataType.INT32),
SimData(27, "Hello ", datatype=SimDataType.STRING)]

device_block = SimDevice(1, False,
block_coil=block_coil,
block_direct=block_direct,
block_holding=block_holding,
block_input=block_input)
device_shared = SimDevice(2, False,
block_shared=block_coil_shared+block_shared)
assert not SimCheckConfig([device_block])
assert not SimCheckConfig([device_shared])
assert not SimCheckConfig([device_shared, device_block])

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

if __name__ == "__main__":
main()
2 changes: 1 addition & 1 deletion pymodbus/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@
from pymodbus.pdu import ExceptionResponse


__version__ = "3.8.4"
__version__ = "3.8.5"
__version_full__ = f"[pymodbus, version {__version__}]"
Loading

0 comments on commit 56eefe6

Please sign in to comment.