modsim 0.5.2__tar.gz → 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {modsim-0.5.2 → modsim-1.0.0}/PKG-INFO +6 -3
- {modsim-0.5.2 → modsim-1.0.0}/README.md +5 -1
- modsim-1.0.0/modsim/__init__.py +1 -0
- {modsim-0.5.2 → modsim-1.0.0}/modsim/main.py +45 -1
- {modsim-0.5.2 → modsim-1.0.0}/pyproject.toml +2 -1
- modsim-0.5.2/modsim/__init__.py +0 -1
- {modsim-0.5.2 → modsim-1.0.0}/LICENSE +0 -0
- {modsim-0.5.2 → modsim-1.0.0}/modsim/__main__.py +0 -0
- {modsim-0.5.2 → modsim-1.0.0}/modsim/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: modsim
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 1.0.0
|
|
4
4
|
Summary: A Simple Modbus TCP Device Simulator used for modpoll tool
|
|
5
5
|
Home-page: https://github.com/gavinying/modsim
|
|
6
6
|
Author: Ying Shaodong
|
|
@@ -11,7 +11,6 @@ Classifier: Programming Language :: Python :: 3.9
|
|
|
11
11
|
Classifier: Programming Language :: Python :: 3.10
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.11
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.13
|
|
15
14
|
Requires-Dist: pymodbus (>=3.6.9,<3.7.0)
|
|
16
15
|
Project-URL: Documentation, https://gavinying.github.io/modsim/
|
|
17
16
|
Project-URL: Repository, https://github.com/gavinying/modsim
|
|
@@ -89,8 +88,12 @@ To verify it, you can test by [modpoll](https://github.com/gavinying/modpoll) to
|
|
|
89
88
|
modpoll \
|
|
90
89
|
--tcp localhost \
|
|
91
90
|
--tcp-port 5020 \
|
|
92
|
-
--config https://raw.githubusercontent.com/gavinying/modpoll/
|
|
91
|
+
--config https://raw.githubusercontent.com/gavinying/modpoll/main/examples/modsim.csv
|
|
93
92
|
```
|
|
94
93
|
|
|
95
94
|
> **_Note_**: add `sudo` before `docker run` command if you want to use the Modbus TCP standard port `502`.
|
|
96
95
|
|
|
96
|
+
## Local server behavior
|
|
97
|
+
|
|
98
|
+
Run the simulator without Docker with `python -m modsim --comm tcp --port 5020`. The default server exposes the four Modbus tables with the sample data shown above. Coil and holding-register writes are supported; discrete inputs and input registers are read-only. Requests outside an initialized address range return a Modbus exception. The server handles SIGINT and SIGTERM by stopping its listener so the port can be reused after shutdown.
|
|
99
|
+
|
|
@@ -70,7 +70,11 @@ To verify it, you can test by [modpoll](https://github.com/gavinying/modpoll) to
|
|
|
70
70
|
modpoll \
|
|
71
71
|
--tcp localhost \
|
|
72
72
|
--tcp-port 5020 \
|
|
73
|
-
--config https://raw.githubusercontent.com/gavinying/modpoll/
|
|
73
|
+
--config https://raw.githubusercontent.com/gavinying/modpoll/main/examples/modsim.csv
|
|
74
74
|
```
|
|
75
75
|
|
|
76
76
|
> **_Note_**: add `sudo` before `docker run` command if you want to use the Modbus TCP standard port `502`.
|
|
77
|
+
|
|
78
|
+
## Local server behavior
|
|
79
|
+
|
|
80
|
+
Run the simulator without Docker with `python -m modsim --comm tcp --port 5020`. The default server exposes the four Modbus tables with the sample data shown above. Coil and holding-register writes are supported; discrete inputs and input registers are read-only. Requests outside an initialized address range return a Modbus exception. The server handles SIGINT and SIGTERM by stopping its listener so the port can be reused after shutdown.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.0.0"
|
|
@@ -25,6 +25,8 @@ The corresponding client can be started as:
|
|
|
25
25
|
|
|
26
26
|
import os
|
|
27
27
|
import asyncio
|
|
28
|
+
import signal
|
|
29
|
+
from contextlib import suppress
|
|
28
30
|
from typing import Any
|
|
29
31
|
|
|
30
32
|
from pymodbus.constants import Endian
|
|
@@ -40,6 +42,7 @@ from pymodbus.server import (
|
|
|
40
42
|
StartAsyncTcpServer,
|
|
41
43
|
StartAsyncTlsServer,
|
|
42
44
|
StartAsyncUdpServer,
|
|
45
|
+
ServerAsyncStop,
|
|
43
46
|
)
|
|
44
47
|
|
|
45
48
|
from . import __version__
|
|
@@ -225,10 +228,51 @@ def app() -> None:
|
|
|
225
228
|
)
|
|
226
229
|
|
|
227
230
|
run_args = setup_server(get_commandline())
|
|
228
|
-
asyncio.run(
|
|
231
|
+
asyncio.run(_run_server_with_signals(run_args), debug=True)
|
|
229
232
|
|
|
230
233
|
_logger.info("exiting.")
|
|
231
234
|
|
|
232
235
|
|
|
236
|
+
async def _run_server_with_signals(args: Any) -> None:
|
|
237
|
+
"""Run the server and close its listener when the process is signaled."""
|
|
238
|
+
loop = asyncio.get_running_loop()
|
|
239
|
+
server_task = asyncio.create_task(run_async_server(args))
|
|
240
|
+
stop_requested = False
|
|
241
|
+
|
|
242
|
+
async def stop_server() -> None:
|
|
243
|
+
for _ in range(100):
|
|
244
|
+
if server_task.done():
|
|
245
|
+
return
|
|
246
|
+
try:
|
|
247
|
+
await ServerAsyncStop()
|
|
248
|
+
return
|
|
249
|
+
except (AttributeError, RuntimeError):
|
|
250
|
+
await asyncio.sleep(0.01)
|
|
251
|
+
|
|
252
|
+
def request_stop() -> None:
|
|
253
|
+
nonlocal stop_requested
|
|
254
|
+
if not stop_requested:
|
|
255
|
+
stop_requested = True
|
|
256
|
+
loop.create_task(stop_server())
|
|
257
|
+
|
|
258
|
+
installed_signals = []
|
|
259
|
+
for signum in (signal.SIGINT, signal.SIGTERM):
|
|
260
|
+
try:
|
|
261
|
+
loop.add_signal_handler(signum, request_stop)
|
|
262
|
+
installed_signals.append(signum)
|
|
263
|
+
except (NotImplementedError, RuntimeError):
|
|
264
|
+
pass
|
|
265
|
+
|
|
266
|
+
try:
|
|
267
|
+
await server_task
|
|
268
|
+
finally:
|
|
269
|
+
for signum in installed_signals:
|
|
270
|
+
loop.remove_signal_handler(signum)
|
|
271
|
+
if not server_task.done():
|
|
272
|
+
server_task.cancel()
|
|
273
|
+
with suppress(asyncio.CancelledError):
|
|
274
|
+
await server_task
|
|
275
|
+
|
|
276
|
+
|
|
233
277
|
if __name__ == "__main__":
|
|
234
278
|
app()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "modsim"
|
|
3
|
-
version = "
|
|
3
|
+
version = "v1.0.0"
|
|
4
4
|
description = "A Simple Modbus TCP Device Simulator used for modpoll tool"
|
|
5
5
|
authors = ["Ying Shaodong <helloysd@gmail.com>"]
|
|
6
6
|
repository = "https://github.com/gavinying/modsim"
|
|
@@ -40,6 +40,7 @@ show_error_codes = true
|
|
|
40
40
|
|
|
41
41
|
[tool.pytest.ini_options]
|
|
42
42
|
testpaths = ["tests"]
|
|
43
|
+
markers = ["integration: local protocol integration test"]
|
|
43
44
|
|
|
44
45
|
[tool.poetry.scripts]
|
|
45
46
|
modsim = "modsim.main:app"
|
modsim-0.5.2/modsim/__init__.py
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.5.2"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|