slmp-connect-python 0.8.0__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.
- {slmp_connect_python-0.8.0 → slmp_connect_python-1.0.0}/MANIFEST.in +2 -2
- {slmp_connect_python-0.8.0/slmp_connect_python.egg-info → slmp_connect_python-1.0.0}/PKG-INFO +3 -8
- {slmp_connect_python-0.8.0 → slmp_connect_python-1.0.0}/README.md +30 -35
- {slmp_connect_python-0.8.0 → slmp_connect_python-1.0.0}/pyproject.toml +111 -112
- {slmp_connect_python-0.8.0 → slmp_connect_python-1.0.0}/slmp/__init__.py +206 -206
- {slmp_connect_python-0.8.0 → slmp_connect_python-1.0.0}/slmp/async_client.py +3 -2
- {slmp_connect_python-0.8.0 → slmp_connect_python-1.0.0}/slmp/cli.py +51 -49
- {slmp_connect_python-0.8.0 → slmp_connect_python-1.0.0}/slmp/client.py +4 -3
- {slmp_connect_python-0.8.0 → slmp_connect_python-1.0.0}/slmp/core.py +18 -0
- {slmp_connect_python-0.8.0 → slmp_connect_python-1.0.0}/slmp/utils.py +9 -3
- {slmp_connect_python-0.8.0 → slmp_connect_python-1.0.0/slmp_connect_python.egg-info}/PKG-INFO +3 -8
- {slmp_connect_python-0.8.0 → slmp_connect_python-1.0.0}/LICENSE +0 -0
- {slmp_connect_python-0.8.0 → slmp_connect_python-1.0.0}/setup.cfg +0 -0
- {slmp_connect_python-0.8.0 → slmp_connect_python-1.0.0}/slmp/_operations.py +0 -0
- {slmp_connect_python-0.8.0 → slmp_connect_python-1.0.0}/slmp/constants.py +0 -0
- {slmp_connect_python-0.8.0 → slmp_connect_python-1.0.0}/slmp/device_ranges.py +0 -0
- {slmp_connect_python-0.8.0 → slmp_connect_python-1.0.0}/slmp/error_codes.py +0 -0
- {slmp_connect_python-0.8.0 → slmp_connect_python-1.0.0}/slmp/errors.py +0 -0
- {slmp_connect_python-0.8.0 → slmp_connect_python-1.0.0}/slmp/py.typed +0 -0
- {slmp_connect_python-0.8.0 → slmp_connect_python-1.0.0}/slmp_connect_python.egg-info/SOURCES.txt +0 -0
- {slmp_connect_python-0.8.0 → slmp_connect_python-1.0.0}/slmp_connect_python.egg-info/dependency_links.txt +0 -0
- {slmp_connect_python-0.8.0 → slmp_connect_python-1.0.0}/slmp_connect_python.egg-info/entry_points.txt +0 -0
- {slmp_connect_python-0.8.0 → slmp_connect_python-1.0.0}/slmp_connect_python.egg-info/requires.txt +0 -0
- {slmp_connect_python-0.8.0 → slmp_connect_python-1.0.0}/slmp_connect_python.egg-info/top_level.txt +0 -0
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
prune tests
|
|
2
|
-
prune internal_docs
|
|
1
|
+
prune tests
|
|
2
|
+
prune internal_docs
|
{slmp_connect_python-0.8.0/slmp_connect_python.egg-info → slmp_connect_python-1.0.0}/PKG-INFO
RENAMED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: slmp-connect-python
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 1.0.0
|
|
4
4
|
Summary: SLMP Connect Python: client library for MELSEC SLMP binary communication
|
|
5
5
|
Author: fa-yoshinobu
|
|
6
6
|
License-Expression: MIT
|
|
7
7
|
Project-URL: Homepage, https://github.com/fa-yoshinobu/plc-comm-slmp-python
|
|
8
8
|
Project-URL: Repository, https://github.com/fa-yoshinobu/plc-comm-slmp-python
|
|
9
9
|
Project-URL: Issues, https://github.com/fa-yoshinobu/plc-comm-slmp-python/issues
|
|
10
|
-
Keywords: slmp,melsec,
|
|
11
|
-
Classifier: Development Status ::
|
|
10
|
+
Keywords: slmp,melsec,plc,3e,4e,binary
|
|
11
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
12
12
|
Classifier: Intended Audience :: Developers
|
|
13
13
|
Classifier: Programming Language :: Python :: 3
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.10
|
|
@@ -33,14 +33,9 @@ Requires-Dist: twine>=5.1; extra == "dev"
|
|
|
33
33
|
Dynamic: license-file
|
|
34
34
|
|
|
35
35
|
[](https://github.com/fa-yoshinobu/plc-comm-slmp-python/actions/workflows/ci.yml)
|
|
36
|
-
[](https://fa-yoshinobu.github.io/plc-comm-docs-site/slmp/python/GETTING_STARTED/)
|
|
37
36
|
[](https://pypi.org/project/slmp-connect-python/)
|
|
38
37
|
[](https://www.python.org/downloads/)
|
|
39
38
|
[](LICENSE)
|
|
40
|
-
[](https://github.com/astral-sh/ruff)
|
|
41
|
-
[](https://github.com/fa-yoshinobu/plc-comm-slmp-python/releases/latest)
|
|
42
|
-
[](https://www.python.org/)
|
|
43
|
-
[](https://www.mkdocs.org/)
|
|
44
39
|
|
|
45
40
|
# MELSEC SLMP for Python
|
|
46
41
|
|
|
@@ -1,25 +1,20 @@
|
|
|
1
1
|
[](https://github.com/fa-yoshinobu/plc-comm-slmp-python/actions/workflows/ci.yml)
|
|
2
|
-
[](https://fa-yoshinobu.github.io/plc-comm-docs-site/slmp/python/GETTING_STARTED/)
|
|
3
2
|
[](https://pypi.org/project/slmp-connect-python/)
|
|
4
3
|
[](https://www.python.org/downloads/)
|
|
5
4
|
[](LICENSE)
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
## Supported
|
|
16
|
-
|
|
17
|
-
The maintained
|
|
18
|
-
|
|
19
|
-
## Supported device types
|
|
20
|
-
|
|
21
|
-
The maintained device and range tables are in [Supported registers](docsrc/user/SUPPORTED_REGISTERS.md). Use that page for supported device families, address syntax, and profile-specific notes.
|
|
22
|
-
|
|
5
|
+
|
|
6
|
+
# MELSEC SLMP for Python
|
|
7
|
+
|
|
8
|
+
Python library for MELSEC SLMP (Binary 3E/4E) PLC communication.
|
|
9
|
+
|
|
10
|
+
## Supported PLC profiles
|
|
11
|
+
|
|
12
|
+
The maintained profile table is in [PLC profiles](docsrc/user/PROFILES.md). Choose one exact canonical PLC profile from that table.
|
|
13
|
+
|
|
14
|
+
## Supported device types
|
|
15
|
+
|
|
16
|
+
The maintained device and range tables are in [Supported registers](docsrc/user/SUPPORTED_REGISTERS.md). Use that page for supported device families, address syntax, and profile-specific notes.
|
|
17
|
+
|
|
23
18
|
## Installation
|
|
24
19
|
|
|
25
20
|
```bash
|
|
@@ -43,24 +38,24 @@ asyncio.run(main())
|
|
|
43
38
|
|
|
44
39
|
## Documentation
|
|
45
40
|
|
|
46
|
-
| Page | Use it for |
|
|
47
|
-
| --- | --- |
|
|
48
|
-
| [Full documentation site](https://fa-yoshinobu.github.io/plc-comm-docs-site/) | Unified docs for all PLC communication libraries. |
|
|
49
|
-
| [Getting started](docsrc/user/GETTING_STARTED.md) | Install the package, connect to your PLC, and run your first SLMP read/write. |
|
|
50
|
-
| [Usage guide](docsrc/user/USAGE_GUIDE.md) | Use the high-level API and common SLMP workflows. |
|
|
51
|
-
| [Supported registers](docsrc/user/SUPPORTED_REGISTERS.md) | Check supported device families, address syntax, and numbering rules. |
|
|
52
|
-
| [PLC profiles](docsrc/user/PROFILES.md) | Choose the canonical MELSEC profile and frame behavior. |
|
|
53
|
-
| [Examples](samples/README.md) | Run maintained Python samples. |
|
|
41
|
+
| Page | Use it for |
|
|
42
|
+
| --- | --- |
|
|
43
|
+
| [Full documentation site](https://fa-yoshinobu.github.io/plc-comm-docs-site/) | Unified docs for all PLC communication libraries. |
|
|
44
|
+
| [Getting started](docsrc/user/GETTING_STARTED.md) | Install the package, connect to your PLC, and run your first SLMP read/write. |
|
|
45
|
+
| [Usage guide](docsrc/user/USAGE_GUIDE.md) | Use the high-level API and common SLMP workflows. |
|
|
46
|
+
| [Supported registers](docsrc/user/SUPPORTED_REGISTERS.md) | Check supported device families, address syntax, and numbering rules. |
|
|
47
|
+
| [PLC profiles](docsrc/user/PROFILES.md) | Choose the canonical MELSEC profile and frame behavior. |
|
|
48
|
+
| [Examples](samples/README.md) | Run maintained Python samples. |
|
|
49
|
+
|
|
50
|
+
## Hardware verified
|
|
54
51
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
Live-device verification is maintained in [Latest communication verification](docsrc/user/LATEST_COMMUNICATION_VERIFICATION.md).
|
|
58
|
-
See that page for verified PLC models, transports, dates, limitations, and retained validation notes.
|
|
52
|
+
Live-device verification is maintained in [Latest communication verification](docsrc/user/LATEST_COMMUNICATION_VERIFICATION.md).
|
|
53
|
+
See that page for verified PLC models, transports, dates, limitations, and retained validation notes.
|
|
59
54
|
|
|
60
55
|
## License and registry
|
|
61
56
|
|
|
62
|
-
| Item | Value |
|
|
63
|
-
| --- | --- |
|
|
64
|
-
| License | [MIT](LICENSE) |
|
|
65
|
-
| Registry | [PyPI](https://pypi.org/project/slmp-connect-python/) |
|
|
66
|
-
| Package | `slmp-connect-python` |
|
|
57
|
+
| Item | Value |
|
|
58
|
+
| --- | --- |
|
|
59
|
+
| License | [MIT](LICENSE) |
|
|
60
|
+
| Registry | [PyPI](https://pypi.org/project/slmp-connect-python/) |
|
|
61
|
+
| Package | `slmp-connect-python` |
|
|
@@ -1,112 +1,111 @@
|
|
|
1
|
-
[build-system]
|
|
2
|
-
requires = ["setuptools>=69", "wheel"]
|
|
3
|
-
build-backend = "setuptools.build_meta"
|
|
4
|
-
|
|
5
|
-
[project]
|
|
6
|
-
name = "slmp-connect-python"
|
|
7
|
-
version = "0.
|
|
8
|
-
description = "SLMP Connect Python: client library for MELSEC SLMP binary communication"
|
|
9
|
-
readme = "README.md"
|
|
10
|
-
requires-python = ">=3.10"
|
|
11
|
-
dependencies = []
|
|
12
|
-
authors = [{ name = "fa-yoshinobu" }]
|
|
13
|
-
license = "MIT"
|
|
14
|
-
|
|
15
|
-
license-files = ["LICENSE"]
|
|
16
|
-
keywords = ["slmp", "melsec", "
|
|
17
|
-
classifiers = [
|
|
18
|
-
"Development Status ::
|
|
19
|
-
"Intended Audience :: Developers",
|
|
20
|
-
"Programming Language :: Python :: 3",
|
|
21
|
-
"Programming Language :: Python :: 3.10",
|
|
22
|
-
"Programming Language :: Python :: 3.11",
|
|
23
|
-
"Programming Language :: Python :: 3.12",
|
|
24
|
-
"Programming Language :: Python :: 3.13",
|
|
25
|
-
"Programming Language :: Python :: 3.14",
|
|
26
|
-
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
27
|
-
"Topic :: System :: Networking",
|
|
28
|
-
]
|
|
29
|
-
|
|
30
|
-
[project.urls]
|
|
31
|
-
Homepage = "https://github.com/fa-yoshinobu/plc-comm-slmp-python"
|
|
32
|
-
Repository = "https://github.com/fa-yoshinobu/plc-comm-slmp-python"
|
|
33
|
-
Issues = "https://github.com/fa-yoshinobu/plc-comm-slmp-python/issues"
|
|
34
|
-
|
|
35
|
-
[project.optional-dependencies]
|
|
36
|
-
dev = [
|
|
37
|
-
"build>=1.2",
|
|
38
|
-
"mypy>=1.10",
|
|
39
|
-
"pre-commit>=3.7",
|
|
40
|
-
"pytest>=8.0",
|
|
41
|
-
"pytest-asyncio>=0.23",
|
|
42
|
-
"pytest-cov>=5.0",
|
|
43
|
-
"ruff>=0.6",
|
|
44
|
-
"twine>=5.1",
|
|
45
|
-
]
|
|
46
|
-
|
|
47
|
-
[project.scripts]
|
|
48
|
-
slmp-connection-check = "slmp.cli:connection_check_main"
|
|
49
|
-
slmp-device-range-probe = "slmp.cli:device_range_probe_main"
|
|
50
|
-
slmp-register-boundary-probe = "slmp.cli:register_boundary_probe_main"
|
|
51
|
-
slmp-other-station-check = "slmp.cli:other_station_check_main"
|
|
52
|
-
slmp-open-items-recheck = "slmp.cli:open_items_recheck_main"
|
|
53
|
-
slmp-g-hg-extended-device-recheck = "slmp.cli:g_hg_extended_device_recheck_main"
|
|
54
|
-
slmp-g-hg-extended-device-coverage = "slmp.cli:g_hg_extended_device_coverage_main"
|
|
55
|
-
slmp-extended-device-recheck = "slmp.cli:extended_device_recheck_main"
|
|
56
|
-
slmp-pending-live-verification = "slmp.cli:pending_live_verification_main"
|
|
57
|
-
slmp-init-model-docs = "slmp.cli:init_model_docs_main"
|
|
58
|
-
slmp-manual-label-verification = "slmp.cli:manual_label_verification_main"
|
|
59
|
-
slmp-read-soak = "slmp.cli:read_soak_main"
|
|
60
|
-
slmp-mixed-read-load = "slmp.cli:mixed_read_load_main"
|
|
61
|
-
slmp-tcp-concurrency = "slmp.cli:tcp_concurrency_main"
|
|
62
|
-
slmp-regression-suite = "slmp.cli:regression_suite_main"
|
|
63
|
-
|
|
64
|
-
[tool.setuptools.packages.find]
|
|
65
|
-
include = ["slmp*"]
|
|
66
|
-
exclude = ["tests*", "scripts*", "internal_docs*"]
|
|
67
|
-
|
|
68
|
-
[tool.setuptools]
|
|
69
|
-
include-package-data = true
|
|
70
|
-
exclude-package-data = { "*" = ["TODO.md", ".pre-commit-config.yaml"] }
|
|
71
|
-
|
|
72
|
-
[tool.setuptools.package-data]
|
|
73
|
-
slmp = ["py.typed"]
|
|
74
|
-
|
|
75
|
-
[tool.ruff]
|
|
76
|
-
line-length = 120
|
|
77
|
-
target-version = "py310"
|
|
78
|
-
|
|
79
|
-
[tool.ruff.lint]
|
|
80
|
-
select = ["E", "F", "I", "B", "UP"]
|
|
81
|
-
|
|
82
|
-
[tool.ruff.lint.per-file-ignores]
|
|
83
|
-
"slmp/error_codes.py" = ["E501"]
|
|
84
|
-
|
|
85
|
-
[tool.ruff.lint.isort]
|
|
86
|
-
known-first-party = ["slmp"]
|
|
87
|
-
|
|
88
|
-
[tool.mypy]
|
|
89
|
-
files = ["slmp"]
|
|
90
|
-
warn_unused_configs = true
|
|
91
|
-
disallow_untyped_defs = true
|
|
92
|
-
check_untyped_defs = true
|
|
93
|
-
disallow_incomplete_defs = true
|
|
94
|
-
no_implicit_optional = true
|
|
95
|
-
warn_redundant_casts = true
|
|
96
|
-
warn_unused_ignores = true
|
|
97
|
-
warn_return_any = true
|
|
98
|
-
strict_equality = true
|
|
99
|
-
|
|
100
|
-
[tool.coverage.run]
|
|
101
|
-
source = ["slmp"]
|
|
102
|
-
branch = true
|
|
103
|
-
|
|
104
|
-
[tool.pytest.ini_options]
|
|
105
|
-
testpaths = ["tests"]
|
|
106
|
-
asyncio_mode = "auto"
|
|
107
|
-
|
|
108
|
-
[tool.coverage.report]
|
|
109
|
-
show_missing = true
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=69", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "slmp-connect-python"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "SLMP Connect Python: client library for MELSEC SLMP binary communication"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
dependencies = []
|
|
12
|
+
authors = [{ name = "fa-yoshinobu" }]
|
|
13
|
+
license = "MIT"
|
|
14
|
+
|
|
15
|
+
license-files = ["LICENSE"]
|
|
16
|
+
keywords = ["slmp", "melsec", "plc", "3e", "4e", "binary"]
|
|
17
|
+
classifiers = [
|
|
18
|
+
"Development Status :: 5 - Production/Stable",
|
|
19
|
+
"Intended Audience :: Developers",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3.10",
|
|
22
|
+
"Programming Language :: Python :: 3.11",
|
|
23
|
+
"Programming Language :: Python :: 3.12",
|
|
24
|
+
"Programming Language :: Python :: 3.13",
|
|
25
|
+
"Programming Language :: Python :: 3.14",
|
|
26
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
27
|
+
"Topic :: System :: Networking",
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
[project.urls]
|
|
31
|
+
Homepage = "https://github.com/fa-yoshinobu/plc-comm-slmp-python"
|
|
32
|
+
Repository = "https://github.com/fa-yoshinobu/plc-comm-slmp-python"
|
|
33
|
+
Issues = "https://github.com/fa-yoshinobu/plc-comm-slmp-python/issues"
|
|
34
|
+
|
|
35
|
+
[project.optional-dependencies]
|
|
36
|
+
dev = [
|
|
37
|
+
"build>=1.2",
|
|
38
|
+
"mypy>=1.10",
|
|
39
|
+
"pre-commit>=3.7",
|
|
40
|
+
"pytest>=8.0",
|
|
41
|
+
"pytest-asyncio>=0.23",
|
|
42
|
+
"pytest-cov>=5.0",
|
|
43
|
+
"ruff>=0.6",
|
|
44
|
+
"twine>=5.1",
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
[project.scripts]
|
|
48
|
+
slmp-connection-check = "slmp.cli:connection_check_main"
|
|
49
|
+
slmp-device-range-probe = "slmp.cli:device_range_probe_main"
|
|
50
|
+
slmp-register-boundary-probe = "slmp.cli:register_boundary_probe_main"
|
|
51
|
+
slmp-other-station-check = "slmp.cli:other_station_check_main"
|
|
52
|
+
slmp-open-items-recheck = "slmp.cli:open_items_recheck_main"
|
|
53
|
+
slmp-g-hg-extended-device-recheck = "slmp.cli:g_hg_extended_device_recheck_main"
|
|
54
|
+
slmp-g-hg-extended-device-coverage = "slmp.cli:g_hg_extended_device_coverage_main"
|
|
55
|
+
slmp-extended-device-recheck = "slmp.cli:extended_device_recheck_main"
|
|
56
|
+
slmp-pending-live-verification = "slmp.cli:pending_live_verification_main"
|
|
57
|
+
slmp-init-model-docs = "slmp.cli:init_model_docs_main"
|
|
58
|
+
slmp-manual-label-verification = "slmp.cli:manual_label_verification_main"
|
|
59
|
+
slmp-read-soak = "slmp.cli:read_soak_main"
|
|
60
|
+
slmp-mixed-read-load = "slmp.cli:mixed_read_load_main"
|
|
61
|
+
slmp-tcp-concurrency = "slmp.cli:tcp_concurrency_main"
|
|
62
|
+
slmp-regression-suite = "slmp.cli:regression_suite_main"
|
|
63
|
+
|
|
64
|
+
[tool.setuptools.packages.find]
|
|
65
|
+
include = ["slmp*"]
|
|
66
|
+
exclude = ["tests*", "scripts*", "internal_docs*"]
|
|
67
|
+
|
|
68
|
+
[tool.setuptools]
|
|
69
|
+
include-package-data = true
|
|
70
|
+
exclude-package-data = { "*" = ["TODO.md", ".pre-commit-config.yaml"] }
|
|
71
|
+
|
|
72
|
+
[tool.setuptools.package-data]
|
|
73
|
+
slmp = ["py.typed"]
|
|
74
|
+
|
|
75
|
+
[tool.ruff]
|
|
76
|
+
line-length = 120
|
|
77
|
+
target-version = "py310"
|
|
78
|
+
|
|
79
|
+
[tool.ruff.lint]
|
|
80
|
+
select = ["E", "F", "I", "B", "UP"]
|
|
81
|
+
|
|
82
|
+
[tool.ruff.lint.per-file-ignores]
|
|
83
|
+
"slmp/error_codes.py" = ["E501"]
|
|
84
|
+
|
|
85
|
+
[tool.ruff.lint.isort]
|
|
86
|
+
known-first-party = ["slmp"]
|
|
87
|
+
|
|
88
|
+
[tool.mypy]
|
|
89
|
+
files = ["slmp"]
|
|
90
|
+
warn_unused_configs = true
|
|
91
|
+
disallow_untyped_defs = true
|
|
92
|
+
check_untyped_defs = true
|
|
93
|
+
disallow_incomplete_defs = true
|
|
94
|
+
no_implicit_optional = true
|
|
95
|
+
warn_redundant_casts = true
|
|
96
|
+
warn_unused_ignores = true
|
|
97
|
+
warn_return_any = true
|
|
98
|
+
strict_equality = true
|
|
99
|
+
|
|
100
|
+
[tool.coverage.run]
|
|
101
|
+
source = ["slmp"]
|
|
102
|
+
branch = true
|
|
103
|
+
|
|
104
|
+
[tool.pytest.ini_options]
|
|
105
|
+
testpaths = ["tests"]
|
|
106
|
+
asyncio_mode = "auto"
|
|
107
|
+
|
|
108
|
+
[tool.coverage.report]
|
|
109
|
+
show_missing = true
|
|
110
|
+
|
|
111
|
+
|
|
@@ -1,206 +1,206 @@
|
|
|
1
|
-
"""SLMP client library with high-level helpers as the recommended user surface.
|
|
2
|
-
|
|
3
|
-
The primary user-facing entry points are:
|
|
4
|
-
|
|
5
|
-
- ``read_typed`` / ``write_typed``
|
|
6
|
-
- ``read_words_single_request`` / ``read_dwords_single_request``
|
|
7
|
-
- ``read_words_chunked`` / ``read_dwords_chunked``
|
|
8
|
-
- ``write_bit_in_word``
|
|
9
|
-
- ``read_named`` / ``write_named``
|
|
10
|
-
- ``poll``
|
|
11
|
-
"""
|
|
12
|
-
|
|
13
|
-
__version__ = "0.8.0"
|
|
14
|
-
|
|
15
|
-
from .async_client import AsyncSlmpClient
|
|
16
|
-
from .client import SlmpClient
|
|
17
|
-
from .constants import Command, FrameType, ModuleIONo, PLCSeries
|
|
18
|
-
from .core import (
|
|
19
|
-
DEVICE_CODES,
|
|
20
|
-
BlockReadResult,
|
|
21
|
-
CpuOperationState,
|
|
22
|
-
CpuOperationStatus,
|
|
23
|
-
DeviceBlockResult,
|
|
24
|
-
DeviceRef,
|
|
25
|
-
ExtensionSpec,
|
|
26
|
-
LabelArrayReadPoint,
|
|
27
|
-
LabelArrayReadResult,
|
|
28
|
-
LabelArrayWritePoint,
|
|
29
|
-
LabelRandomReadResult,
|
|
30
|
-
LabelRandomWritePoint,
|
|
31
|
-
LongTimerResult,
|
|
32
|
-
MonitorResult,
|
|
33
|
-
RandomReadResult,
|
|
34
|
-
SlmpPlcProfile,
|
|
35
|
-
SlmpResponse,
|
|
36
|
-
SlmpTarget,
|
|
37
|
-
SlmpTraceFrame,
|
|
38
|
-
TypeNameInfo,
|
|
39
|
-
decode_cpu_operation_state,
|
|
40
|
-
parse_device,
|
|
41
|
-
parse_extended_device,
|
|
42
|
-
)
|
|
43
|
-
from .device_ranges import (
|
|
44
|
-
SlmpDeviceRangeCatalog,
|
|
45
|
-
SlmpDeviceRangeCategory,
|
|
46
|
-
SlmpDeviceRangeEntry,
|
|
47
|
-
SlmpDeviceRangeNotation,
|
|
48
|
-
build_device_range_catalog_for_plc_profile,
|
|
49
|
-
normalize_plc_profile,
|
|
50
|
-
plc_profile_label,
|
|
51
|
-
read_device_range_catalog_for_plc_profile,
|
|
52
|
-
read_device_range_catalog_for_plc_profile_sync,
|
|
53
|
-
)
|
|
54
|
-
from .error_codes import (
|
|
55
|
-
SlmpEndCodeLanguage,
|
|
56
|
-
get_end_code_message,
|
|
57
|
-
get_end_code_name,
|
|
58
|
-
is_remote_password_end_code,
|
|
59
|
-
)
|
|
60
|
-
from .errors import (
|
|
61
|
-
SlmpBoundaryBehaviorWarning,
|
|
62
|
-
SlmpError,
|
|
63
|
-
SlmpPracticalPathWarning,
|
|
64
|
-
SlmpUnsupportedDeviceError,
|
|
65
|
-
)
|
|
66
|
-
from .utils import (
|
|
67
|
-
QueuedAsyncSlmpClient,
|
|
68
|
-
SlmpAddress,
|
|
69
|
-
SlmpConnectionOptions,
|
|
70
|
-
format_address,
|
|
71
|
-
normalize_address,
|
|
72
|
-
open_and_connect,
|
|
73
|
-
open_and_connect_sync,
|
|
74
|
-
parse_address,
|
|
75
|
-
poll,
|
|
76
|
-
poll_sync,
|
|
77
|
-
read_bits,
|
|
78
|
-
read_bits_sync,
|
|
79
|
-
read_dwords,
|
|
80
|
-
read_dwords_chunked,
|
|
81
|
-
read_dwords_chunked_sync,
|
|
82
|
-
read_dwords_single_request,
|
|
83
|
-
read_dwords_single_request_sync,
|
|
84
|
-
read_dwords_sync,
|
|
85
|
-
read_named,
|
|
86
|
-
read_named_sync,
|
|
87
|
-
read_typed,
|
|
88
|
-
read_typed_sync,
|
|
89
|
-
read_words,
|
|
90
|
-
read_words_chunked,
|
|
91
|
-
read_words_chunked_sync,
|
|
92
|
-
read_words_single_request,
|
|
93
|
-
read_words_single_request_sync,
|
|
94
|
-
read_words_sync,
|
|
95
|
-
try_parse_address,
|
|
96
|
-
write_bit_in_word,
|
|
97
|
-
write_bit_in_word_sync,
|
|
98
|
-
write_bits,
|
|
99
|
-
write_bits_sync,
|
|
100
|
-
write_dwords_chunked,
|
|
101
|
-
write_dwords_chunked_sync,
|
|
102
|
-
write_dwords_single_request,
|
|
103
|
-
write_dwords_single_request_sync,
|
|
104
|
-
write_named,
|
|
105
|
-
write_named_sync,
|
|
106
|
-
write_typed,
|
|
107
|
-
write_typed_sync,
|
|
108
|
-
write_words_chunked,
|
|
109
|
-
write_words_chunked_sync,
|
|
110
|
-
write_words_single_request,
|
|
111
|
-
write_words_single_request_sync,
|
|
112
|
-
)
|
|
113
|
-
|
|
114
|
-
__all__ = [
|
|
115
|
-
"AsyncSlmpClient",
|
|
116
|
-
"BlockReadResult",
|
|
117
|
-
"Command",
|
|
118
|
-
"CpuOperationState",
|
|
119
|
-
"CpuOperationStatus",
|
|
120
|
-
"DEVICE_CODES",
|
|
121
|
-
"DeviceBlockResult",
|
|
122
|
-
"DeviceRef",
|
|
123
|
-
"ExtensionSpec",
|
|
124
|
-
"FrameType",
|
|
125
|
-
"LabelArrayReadPoint",
|
|
126
|
-
"LabelArrayReadResult",
|
|
127
|
-
"LabelArrayWritePoint",
|
|
128
|
-
"LabelRandomReadResult",
|
|
129
|
-
"LabelRandomWritePoint",
|
|
130
|
-
"LongTimerResult",
|
|
131
|
-
"ModuleIONo",
|
|
132
|
-
"MonitorResult",
|
|
133
|
-
"PLCSeries",
|
|
134
|
-
"QueuedAsyncSlmpClient",
|
|
135
|
-
"SlmpConnectionOptions",
|
|
136
|
-
"SlmpEndCodeLanguage",
|
|
137
|
-
"SlmpAddress",
|
|
138
|
-
"RandomReadResult",
|
|
139
|
-
"SlmpClient",
|
|
140
|
-
"SlmpBoundaryBehaviorWarning",
|
|
141
|
-
"SlmpError",
|
|
142
|
-
"SlmpPlcProfile",
|
|
143
|
-
"SlmpPracticalPathWarning",
|
|
144
|
-
"SlmpUnsupportedDeviceError",
|
|
145
|
-
"SlmpResponse",
|
|
146
|
-
"SlmpTarget",
|
|
147
|
-
"SlmpTraceFrame",
|
|
148
|
-
"TypeNameInfo",
|
|
149
|
-
"decode_cpu_operation_state",
|
|
150
|
-
"format_address",
|
|
151
|
-
"get_end_code_message",
|
|
152
|
-
"get_end_code_name",
|
|
153
|
-
"is_remote_password_end_code",
|
|
154
|
-
"SlmpDeviceRangeCatalog",
|
|
155
|
-
"SlmpDeviceRangeCategory",
|
|
156
|
-
"SlmpDeviceRangeEntry",
|
|
157
|
-
"SlmpDeviceRangeNotation",
|
|
158
|
-
"normalize_address",
|
|
159
|
-
"normalize_plc_profile",
|
|
160
|
-
"open_and_connect",
|
|
161
|
-
"open_and_connect_sync",
|
|
162
|
-
"parse_address",
|
|
163
|
-
"parse_extended_device",
|
|
164
|
-
"parse_device",
|
|
165
|
-
"poll",
|
|
166
|
-
"poll_sync",
|
|
167
|
-
"read_bits",
|
|
168
|
-
"read_bits_sync",
|
|
169
|
-
"read_dwords",
|
|
170
|
-
"read_dwords_chunked",
|
|
171
|
-
"read_dwords_chunked_sync",
|
|
172
|
-
"read_dwords_single_request",
|
|
173
|
-
"read_dwords_single_request_sync",
|
|
174
|
-
"read_dwords_sync",
|
|
175
|
-
"read_named",
|
|
176
|
-
"read_named_sync",
|
|
177
|
-
"read_typed",
|
|
178
|
-
"read_typed_sync",
|
|
179
|
-
"read_device_range_catalog_for_plc_profile",
|
|
180
|
-
"read_device_range_catalog_for_plc_profile_sync",
|
|
181
|
-
"read_words",
|
|
182
|
-
"read_words_chunked",
|
|
183
|
-
"read_words_chunked_sync",
|
|
184
|
-
"read_words_single_request",
|
|
185
|
-
"read_words_single_request_sync",
|
|
186
|
-
"read_words_sync",
|
|
187
|
-
"write_bit_in_word",
|
|
188
|
-
"write_bit_in_word_sync",
|
|
189
|
-
"write_bits",
|
|
190
|
-
"write_bits_sync",
|
|
191
|
-
"write_dwords_chunked",
|
|
192
|
-
"write_dwords_chunked_sync",
|
|
193
|
-
"write_dwords_single_request",
|
|
194
|
-
"write_dwords_single_request_sync",
|
|
195
|
-
"write_named",
|
|
196
|
-
"write_named_sync",
|
|
197
|
-
"write_typed",
|
|
198
|
-
"write_typed_sync",
|
|
199
|
-
"write_words_chunked",
|
|
200
|
-
"write_words_chunked_sync",
|
|
201
|
-
"write_words_single_request",
|
|
202
|
-
"write_words_single_request_sync",
|
|
203
|
-
"try_parse_address",
|
|
204
|
-
"build_device_range_catalog_for_plc_profile",
|
|
205
|
-
"plc_profile_label",
|
|
206
|
-
]
|
|
1
|
+
"""SLMP client library with high-level helpers as the recommended user surface.
|
|
2
|
+
|
|
3
|
+
The primary user-facing entry points are:
|
|
4
|
+
|
|
5
|
+
- ``read_typed`` / ``write_typed``
|
|
6
|
+
- ``read_words_single_request`` / ``read_dwords_single_request``
|
|
7
|
+
- ``read_words_chunked`` / ``read_dwords_chunked``
|
|
8
|
+
- ``write_bit_in_word``
|
|
9
|
+
- ``read_named`` / ``write_named``
|
|
10
|
+
- ``poll``
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
__version__ = "0.8.0"
|
|
14
|
+
|
|
15
|
+
from .async_client import AsyncSlmpClient
|
|
16
|
+
from .client import SlmpClient
|
|
17
|
+
from .constants import Command, FrameType, ModuleIONo, PLCSeries
|
|
18
|
+
from .core import (
|
|
19
|
+
DEVICE_CODES,
|
|
20
|
+
BlockReadResult,
|
|
21
|
+
CpuOperationState,
|
|
22
|
+
CpuOperationStatus,
|
|
23
|
+
DeviceBlockResult,
|
|
24
|
+
DeviceRef,
|
|
25
|
+
ExtensionSpec,
|
|
26
|
+
LabelArrayReadPoint,
|
|
27
|
+
LabelArrayReadResult,
|
|
28
|
+
LabelArrayWritePoint,
|
|
29
|
+
LabelRandomReadResult,
|
|
30
|
+
LabelRandomWritePoint,
|
|
31
|
+
LongTimerResult,
|
|
32
|
+
MonitorResult,
|
|
33
|
+
RandomReadResult,
|
|
34
|
+
SlmpPlcProfile,
|
|
35
|
+
SlmpResponse,
|
|
36
|
+
SlmpTarget,
|
|
37
|
+
SlmpTraceFrame,
|
|
38
|
+
TypeNameInfo,
|
|
39
|
+
decode_cpu_operation_state,
|
|
40
|
+
parse_device,
|
|
41
|
+
parse_extended_device,
|
|
42
|
+
)
|
|
43
|
+
from .device_ranges import (
|
|
44
|
+
SlmpDeviceRangeCatalog,
|
|
45
|
+
SlmpDeviceRangeCategory,
|
|
46
|
+
SlmpDeviceRangeEntry,
|
|
47
|
+
SlmpDeviceRangeNotation,
|
|
48
|
+
build_device_range_catalog_for_plc_profile,
|
|
49
|
+
normalize_plc_profile,
|
|
50
|
+
plc_profile_label,
|
|
51
|
+
read_device_range_catalog_for_plc_profile,
|
|
52
|
+
read_device_range_catalog_for_plc_profile_sync,
|
|
53
|
+
)
|
|
54
|
+
from .error_codes import (
|
|
55
|
+
SlmpEndCodeLanguage,
|
|
56
|
+
get_end_code_message,
|
|
57
|
+
get_end_code_name,
|
|
58
|
+
is_remote_password_end_code,
|
|
59
|
+
)
|
|
60
|
+
from .errors import (
|
|
61
|
+
SlmpBoundaryBehaviorWarning,
|
|
62
|
+
SlmpError,
|
|
63
|
+
SlmpPracticalPathWarning,
|
|
64
|
+
SlmpUnsupportedDeviceError,
|
|
65
|
+
)
|
|
66
|
+
from .utils import (
|
|
67
|
+
QueuedAsyncSlmpClient,
|
|
68
|
+
SlmpAddress,
|
|
69
|
+
SlmpConnectionOptions,
|
|
70
|
+
format_address,
|
|
71
|
+
normalize_address,
|
|
72
|
+
open_and_connect,
|
|
73
|
+
open_and_connect_sync,
|
|
74
|
+
parse_address,
|
|
75
|
+
poll,
|
|
76
|
+
poll_sync,
|
|
77
|
+
read_bits,
|
|
78
|
+
read_bits_sync,
|
|
79
|
+
read_dwords,
|
|
80
|
+
read_dwords_chunked,
|
|
81
|
+
read_dwords_chunked_sync,
|
|
82
|
+
read_dwords_single_request,
|
|
83
|
+
read_dwords_single_request_sync,
|
|
84
|
+
read_dwords_sync,
|
|
85
|
+
read_named,
|
|
86
|
+
read_named_sync,
|
|
87
|
+
read_typed,
|
|
88
|
+
read_typed_sync,
|
|
89
|
+
read_words,
|
|
90
|
+
read_words_chunked,
|
|
91
|
+
read_words_chunked_sync,
|
|
92
|
+
read_words_single_request,
|
|
93
|
+
read_words_single_request_sync,
|
|
94
|
+
read_words_sync,
|
|
95
|
+
try_parse_address,
|
|
96
|
+
write_bit_in_word,
|
|
97
|
+
write_bit_in_word_sync,
|
|
98
|
+
write_bits,
|
|
99
|
+
write_bits_sync,
|
|
100
|
+
write_dwords_chunked,
|
|
101
|
+
write_dwords_chunked_sync,
|
|
102
|
+
write_dwords_single_request,
|
|
103
|
+
write_dwords_single_request_sync,
|
|
104
|
+
write_named,
|
|
105
|
+
write_named_sync,
|
|
106
|
+
write_typed,
|
|
107
|
+
write_typed_sync,
|
|
108
|
+
write_words_chunked,
|
|
109
|
+
write_words_chunked_sync,
|
|
110
|
+
write_words_single_request,
|
|
111
|
+
write_words_single_request_sync,
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
__all__ = [
|
|
115
|
+
"AsyncSlmpClient",
|
|
116
|
+
"BlockReadResult",
|
|
117
|
+
"Command",
|
|
118
|
+
"CpuOperationState",
|
|
119
|
+
"CpuOperationStatus",
|
|
120
|
+
"DEVICE_CODES",
|
|
121
|
+
"DeviceBlockResult",
|
|
122
|
+
"DeviceRef",
|
|
123
|
+
"ExtensionSpec",
|
|
124
|
+
"FrameType",
|
|
125
|
+
"LabelArrayReadPoint",
|
|
126
|
+
"LabelArrayReadResult",
|
|
127
|
+
"LabelArrayWritePoint",
|
|
128
|
+
"LabelRandomReadResult",
|
|
129
|
+
"LabelRandomWritePoint",
|
|
130
|
+
"LongTimerResult",
|
|
131
|
+
"ModuleIONo",
|
|
132
|
+
"MonitorResult",
|
|
133
|
+
"PLCSeries",
|
|
134
|
+
"QueuedAsyncSlmpClient",
|
|
135
|
+
"SlmpConnectionOptions",
|
|
136
|
+
"SlmpEndCodeLanguage",
|
|
137
|
+
"SlmpAddress",
|
|
138
|
+
"RandomReadResult",
|
|
139
|
+
"SlmpClient",
|
|
140
|
+
"SlmpBoundaryBehaviorWarning",
|
|
141
|
+
"SlmpError",
|
|
142
|
+
"SlmpPlcProfile",
|
|
143
|
+
"SlmpPracticalPathWarning",
|
|
144
|
+
"SlmpUnsupportedDeviceError",
|
|
145
|
+
"SlmpResponse",
|
|
146
|
+
"SlmpTarget",
|
|
147
|
+
"SlmpTraceFrame",
|
|
148
|
+
"TypeNameInfo",
|
|
149
|
+
"decode_cpu_operation_state",
|
|
150
|
+
"format_address",
|
|
151
|
+
"get_end_code_message",
|
|
152
|
+
"get_end_code_name",
|
|
153
|
+
"is_remote_password_end_code",
|
|
154
|
+
"SlmpDeviceRangeCatalog",
|
|
155
|
+
"SlmpDeviceRangeCategory",
|
|
156
|
+
"SlmpDeviceRangeEntry",
|
|
157
|
+
"SlmpDeviceRangeNotation",
|
|
158
|
+
"normalize_address",
|
|
159
|
+
"normalize_plc_profile",
|
|
160
|
+
"open_and_connect",
|
|
161
|
+
"open_and_connect_sync",
|
|
162
|
+
"parse_address",
|
|
163
|
+
"parse_extended_device",
|
|
164
|
+
"parse_device",
|
|
165
|
+
"poll",
|
|
166
|
+
"poll_sync",
|
|
167
|
+
"read_bits",
|
|
168
|
+
"read_bits_sync",
|
|
169
|
+
"read_dwords",
|
|
170
|
+
"read_dwords_chunked",
|
|
171
|
+
"read_dwords_chunked_sync",
|
|
172
|
+
"read_dwords_single_request",
|
|
173
|
+
"read_dwords_single_request_sync",
|
|
174
|
+
"read_dwords_sync",
|
|
175
|
+
"read_named",
|
|
176
|
+
"read_named_sync",
|
|
177
|
+
"read_typed",
|
|
178
|
+
"read_typed_sync",
|
|
179
|
+
"read_device_range_catalog_for_plc_profile",
|
|
180
|
+
"read_device_range_catalog_for_plc_profile_sync",
|
|
181
|
+
"read_words",
|
|
182
|
+
"read_words_chunked",
|
|
183
|
+
"read_words_chunked_sync",
|
|
184
|
+
"read_words_single_request",
|
|
185
|
+
"read_words_single_request_sync",
|
|
186
|
+
"read_words_sync",
|
|
187
|
+
"write_bit_in_word",
|
|
188
|
+
"write_bit_in_word_sync",
|
|
189
|
+
"write_bits",
|
|
190
|
+
"write_bits_sync",
|
|
191
|
+
"write_dwords_chunked",
|
|
192
|
+
"write_dwords_chunked_sync",
|
|
193
|
+
"write_dwords_single_request",
|
|
194
|
+
"write_dwords_single_request_sync",
|
|
195
|
+
"write_named",
|
|
196
|
+
"write_named_sync",
|
|
197
|
+
"write_typed",
|
|
198
|
+
"write_typed_sync",
|
|
199
|
+
"write_words_chunked",
|
|
200
|
+
"write_words_chunked_sync",
|
|
201
|
+
"write_words_single_request",
|
|
202
|
+
"write_words_single_request_sync",
|
|
203
|
+
"try_parse_address",
|
|
204
|
+
"build_device_range_catalog_for_plc_profile",
|
|
205
|
+
"plc_profile_label",
|
|
206
|
+
]
|
|
@@ -30,6 +30,7 @@ from .core import (
|
|
|
30
30
|
_raise_response_error,
|
|
31
31
|
_require_explicit_plc_profile_for_xy,
|
|
32
32
|
_resolve_connection_profile,
|
|
33
|
+
_resolve_port,
|
|
33
34
|
build_device_modification_flags,
|
|
34
35
|
decode_cpu_operation_state,
|
|
35
36
|
decode_response,
|
|
@@ -72,7 +73,7 @@ class AsyncSlmpClient:
|
|
|
72
73
|
def __init__(
|
|
73
74
|
self,
|
|
74
75
|
host: str,
|
|
75
|
-
port: int =
|
|
76
|
+
port: int | None = None,
|
|
76
77
|
*,
|
|
77
78
|
transport: str = "tcp",
|
|
78
79
|
timeout: float = 3.0,
|
|
@@ -93,10 +94,10 @@ class AsyncSlmpClient:
|
|
|
93
94
|
explicit family.
|
|
94
95
|
"""
|
|
95
96
|
self.host = host
|
|
96
|
-
self.port = port
|
|
97
97
|
self.transport_type = transport.lower()
|
|
98
98
|
if self.transport_type not in {"tcp", "udp"}:
|
|
99
99
|
raise ValueError("transport must be 'tcp' or 'udp'")
|
|
100
|
+
self.port = _resolve_port(port, self.transport_type)
|
|
100
101
|
self.timeout = timeout
|
|
101
102
|
if not _allow_manual_profile:
|
|
102
103
|
if plc_profile is None:
|
|
@@ -41,6 +41,7 @@ from .core import (
|
|
|
41
41
|
SlmpTarget,
|
|
42
42
|
SlmpTraceFrame,
|
|
43
43
|
TypeNameInfo,
|
|
44
|
+
_resolve_port,
|
|
44
45
|
decode_device_words,
|
|
45
46
|
encode_device_spec,
|
|
46
47
|
pack_bit_values,
|
|
@@ -58,7 +59,7 @@ class SlmpClient(_StandardSlmpClient):
|
|
|
58
59
|
def __init__(
|
|
59
60
|
self,
|
|
60
61
|
host: str,
|
|
61
|
-
port: int =
|
|
62
|
+
port: int | None = None,
|
|
62
63
|
*,
|
|
63
64
|
transport: str = "tcp",
|
|
64
65
|
timeout: float = 3.0,
|
|
@@ -915,18 +916,18 @@ def _render_compatibility_matrix_markdown(
|
|
|
915
916
|
|
|
916
917
|
def _default_regression_help_scripts() -> tuple[str, ...]:
|
|
917
918
|
return (
|
|
918
|
-
"slmp_connection_check.py",
|
|
919
|
-
"slmp_device_range_probe.py",
|
|
920
|
-
"slmp_register_boundary_probe.py",
|
|
921
|
-
"slmp_init_model_docs.py",
|
|
922
|
-
"slmp_other_station_check.py",
|
|
923
|
-
"slmp_open_items_recheck.py",
|
|
924
|
-
"slmp_pending_live_verification.py",
|
|
925
|
-
"slmp_manual_label_verification.py",
|
|
926
|
-
"slmp_special_device_probe.py",
|
|
927
|
-
"slmp_read_soak.py",
|
|
928
|
-
"slmp_mixed_read_load.py",
|
|
929
|
-
"slmp_tcp_concurrency.py",
|
|
919
|
+
"slmp_connection_check.py",
|
|
920
|
+
"slmp_device_range_probe.py",
|
|
921
|
+
"slmp_register_boundary_probe.py",
|
|
922
|
+
"slmp_init_model_docs.py",
|
|
923
|
+
"slmp_other_station_check.py",
|
|
924
|
+
"slmp_open_items_recheck.py",
|
|
925
|
+
"slmp_pending_live_verification.py",
|
|
926
|
+
"slmp_manual_label_verification.py",
|
|
927
|
+
"slmp_special_device_probe.py",
|
|
928
|
+
"slmp_read_soak.py",
|
|
929
|
+
"slmp_mixed_read_load.py",
|
|
930
|
+
"slmp_tcp_concurrency.py",
|
|
930
931
|
"slmp_extended_device_device_recheck.py",
|
|
931
932
|
"slmp_g_hg_extended_device_recheck.py",
|
|
932
933
|
"slmp_g_hg_extended_device_coverage.py",
|
|
@@ -1151,9 +1152,9 @@ class ExtendedDeviceWordProbeSpec:
|
|
|
1151
1152
|
direct_memory_specification: int
|
|
1152
1153
|
|
|
1153
1154
|
|
|
1154
|
-
@dataclass(frozen=True)
|
|
1155
|
-
class LatencySummary:
|
|
1156
|
-
"""Summary statistics for request latency."""
|
|
1155
|
+
@dataclass(frozen=True)
|
|
1156
|
+
class LatencySummary:
|
|
1157
|
+
"""Summary statistics for request latency."""
|
|
1157
1158
|
|
|
1158
1159
|
count: int
|
|
1159
1160
|
avg_ms: float
|
|
@@ -1774,20 +1775,20 @@ def _write_scaffold_file(path: Path, content: str, *, force: bool) -> bool:
|
|
|
1774
1775
|
return True
|
|
1775
1776
|
|
|
1776
1777
|
|
|
1777
|
-
def _parse_manual_verdict(text: str) -> str | None:
|
|
1778
|
-
lowered = text.strip().lower()
|
|
1779
|
-
if lowered in {"y", "yes"}:
|
|
1778
|
+
def _parse_manual_verdict(text: str) -> str | None:
|
|
1779
|
+
lowered = text.strip().lower()
|
|
1780
|
+
if lowered in {"y", "yes"}:
|
|
1780
1781
|
return "OK"
|
|
1781
1782
|
if lowered in {"n", "no"}:
|
|
1782
1783
|
return "NG"
|
|
1783
|
-
if lowered in {"s", "skip"}:
|
|
1784
|
-
return "SKIP"
|
|
1785
|
-
return None
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
def _parse_positive_int_list(text: str) -> tuple[int, ...]:
|
|
1789
|
-
parts = [part.strip() for part in text.split(",")]
|
|
1790
|
-
if not parts or any(not part for part in parts):
|
|
1784
|
+
if lowered in {"s", "skip"}:
|
|
1785
|
+
return "SKIP"
|
|
1786
|
+
return None
|
|
1787
|
+
|
|
1788
|
+
|
|
1789
|
+
def _parse_positive_int_list(text: str) -> tuple[int, ...]:
|
|
1790
|
+
parts = [part.strip() for part in text.split(",")]
|
|
1791
|
+
if not parts or any(not part for part in parts):
|
|
1791
1792
|
raise ValueError(f"comma-separated positive integer list expected: {text!r}")
|
|
1792
1793
|
values = tuple(_int_auto(part) for part in parts)
|
|
1793
1794
|
if any(value <= 0 for value in values):
|
|
@@ -1811,12 +1812,12 @@ def _render_model_docs_readme(*, series: str, model: str, folder_name: str) -> s
|
|
|
1811
1812
|
f"- Model: `{model}`",
|
|
1812
1813
|
"- Host: fill in when the target is assigned",
|
|
1813
1814
|
"- Primary SLMP ports: fill in when the target is assigned",
|
|
1814
|
-
"",
|
|
1815
|
-
"## Expected Files",
|
|
1816
|
-
"",
|
|
1817
|
-
"- `read_soak_latest.md`",
|
|
1818
|
-
" - repeated single-command read soak result",
|
|
1819
|
-
"- `mixed_read_load_latest.md`",
|
|
1815
|
+
"",
|
|
1816
|
+
"## Expected Files",
|
|
1817
|
+
"",
|
|
1818
|
+
"- `read_soak_latest.md`",
|
|
1819
|
+
" - repeated single-command read soak result",
|
|
1820
|
+
"- `mixed_read_load_latest.md`",
|
|
1820
1821
|
" - mixed 0401/0403/0406 read load result",
|
|
1821
1822
|
"- `tcp_concurrency_latest.md`",
|
|
1822
1823
|
" - practical multi-client TCP read concurrency result",
|
|
@@ -1923,13 +1924,13 @@ def _render_model_other_station_targets_example() -> str:
|
|
|
1923
1924
|
"remote_station_01,0x00,0x01,0x03FF,0x00",
|
|
1924
1925
|
"remote_station_02,0x00,0x02,0x03FF,0x00",
|
|
1925
1926
|
"",
|
|
1926
|
-
]
|
|
1927
|
-
)
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
def _initialize_model_docs(
|
|
1931
|
-
*,
|
|
1932
|
-
root: Path,
|
|
1927
|
+
]
|
|
1928
|
+
)
|
|
1929
|
+
|
|
1930
|
+
|
|
1931
|
+
def _initialize_model_docs(
|
|
1932
|
+
*,
|
|
1933
|
+
root: Path,
|
|
1933
1934
|
series: str,
|
|
1934
1935
|
model: str,
|
|
1935
1936
|
force: bool = False,
|
|
@@ -1937,12 +1938,12 @@ def _initialize_model_docs(
|
|
|
1937
1938
|
folder_name = f"{_sanitize_report_component(series)}_{_sanitize_report_component(model)}"
|
|
1938
1939
|
model_dir = root / folder_name
|
|
1939
1940
|
created: list[Path] = []
|
|
1940
|
-
skipped: list[Path] = []
|
|
1941
|
-
files: list[tuple[Path, str]] = [
|
|
1942
|
-
(model_dir / "README.md", _render_model_docs_readme(series=series, model=model, folder_name=folder_name)),
|
|
1943
|
-
(model_dir / "current_plc_boundary_specs_example.txt", _render_model_boundary_specs_example()),
|
|
1944
|
-
(
|
|
1945
|
-
model_dir / "current_register_boundary_focus_specs_example.txt",
|
|
1941
|
+
skipped: list[Path] = []
|
|
1942
|
+
files: list[tuple[Path, str]] = [
|
|
1943
|
+
(model_dir / "README.md", _render_model_docs_readme(series=series, model=model, folder_name=folder_name)),
|
|
1944
|
+
(model_dir / "current_plc_boundary_specs_example.txt", _render_model_boundary_specs_example()),
|
|
1945
|
+
(
|
|
1946
|
+
model_dir / "current_register_boundary_focus_specs_example.txt",
|
|
1946
1947
|
_render_model_register_boundary_specs_example(),
|
|
1947
1948
|
),
|
|
1948
1949
|
(model_dir / "other_station_targets_example.txt", _render_model_other_station_targets_example()),
|
|
@@ -2265,7 +2266,7 @@ def connection_check_main(argv: Sequence[str] | None = None) -> int:
|
|
|
2265
2266
|
"""Perform SLMP binary connection check."""
|
|
2266
2267
|
parser = argparse.ArgumentParser(description="SLMP binary connection check")
|
|
2267
2268
|
parser.add_argument("--host", required=True, help="PLC IP address or host name")
|
|
2268
|
-
parser.add_argument("--port", type=int, default=
|
|
2269
|
+
parser.add_argument("--port", type=int, default=None, help="SLMP port (default: 1025 for TCP, 1035 for UDP)")
|
|
2269
2270
|
parser.add_argument("--transport", choices=("tcp", "udp"), default="tcp")
|
|
2270
2271
|
parser.add_argument("--timeout", type=float, default=3.0)
|
|
2271
2272
|
parser.add_argument("--series", choices=("ql", "iqr"), default="ql")
|
|
@@ -2341,6 +2342,7 @@ def connection_check_main(argv: Sequence[str] | None = None) -> int:
|
|
|
2341
2342
|
help="use indirect specification flag (@)",
|
|
2342
2343
|
)
|
|
2343
2344
|
args = parser.parse_args(list(argv) if argv is not None else None)
|
|
2345
|
+
args.port = _resolve_port(args.port, args.transport)
|
|
2344
2346
|
|
|
2345
2347
|
target = SlmpTarget(
|
|
2346
2348
|
network=args.network,
|
|
@@ -4238,8 +4240,8 @@ def pending_live_verification_main(argv: Sequence[str] | None = None) -> int:
|
|
|
4238
4240
|
return 0
|
|
4239
4241
|
|
|
4240
4242
|
|
|
4241
|
-
def manual_label_verification_main(argv: Sequence[str] | None = None) -> int:
|
|
4242
|
-
"""Perform interactive manual label write verification with restore."""
|
|
4243
|
+
def manual_label_verification_main(argv: Sequence[str] | None = None) -> int:
|
|
4244
|
+
"""Perform interactive manual label write verification with restore."""
|
|
4243
4245
|
parser = argparse.ArgumentParser(
|
|
4244
4246
|
description=(
|
|
4245
4247
|
"Write temporary values to explicit label tags, let a human verify the effect, "
|
|
@@ -29,6 +29,7 @@ from .core import (
|
|
|
29
29
|
_raise_response_error,
|
|
30
30
|
_require_explicit_plc_profile_for_xy,
|
|
31
31
|
_resolve_connection_profile,
|
|
32
|
+
_resolve_port,
|
|
32
33
|
build_device_modification_flags,
|
|
33
34
|
decode_cpu_operation_state,
|
|
34
35
|
decode_response,
|
|
@@ -60,7 +61,7 @@ class SlmpClient:
|
|
|
60
61
|
def __init__(
|
|
61
62
|
self,
|
|
62
63
|
host: str,
|
|
63
|
-
port: int =
|
|
64
|
+
port: int | None = None,
|
|
64
65
|
*,
|
|
65
66
|
transport: str = "tcp",
|
|
66
67
|
timeout: float = 3.0,
|
|
@@ -78,7 +79,7 @@ class SlmpClient:
|
|
|
78
79
|
|
|
79
80
|
Args:
|
|
80
81
|
host: PLC IP address.
|
|
81
|
-
port: PLC port number. Defaults to
|
|
82
|
+
port: PLC port number. Defaults to 1025 for TCP and 1035 for UDP.
|
|
82
83
|
transport: Transport protocol ('tcp' or 'udp'). Defaults to 'tcp'.
|
|
83
84
|
timeout: Socket timeout in seconds. Defaults to 3.0.
|
|
84
85
|
plc_profile: Canonical high-level PLC profile. The standard client
|
|
@@ -90,10 +91,10 @@ class SlmpClient:
|
|
|
90
91
|
trace_hook: Optional callback for tracing requests and responses.
|
|
91
92
|
"""
|
|
92
93
|
self.host = host
|
|
93
|
-
self.port = port
|
|
94
94
|
self.transport = transport.lower()
|
|
95
95
|
if self.transport not in {"tcp", "udp"}:
|
|
96
96
|
raise ValueError("transport must be 'tcp' or 'udp'")
|
|
97
|
+
self.port = _resolve_port(port, self.transport)
|
|
97
98
|
self.timeout = timeout
|
|
98
99
|
if not _allow_manual_profile:
|
|
99
100
|
if plc_profile is None:
|
|
@@ -39,6 +39,24 @@ from .errors import (
|
|
|
39
39
|
SlmpUnsupportedDeviceError,
|
|
40
40
|
)
|
|
41
41
|
|
|
42
|
+
DEFAULT_TCP_PORT = 1025
|
|
43
|
+
DEFAULT_UDP_PORT = 1035
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _default_port_for_transport(transport: str) -> int:
|
|
47
|
+
normalized = transport.lower()
|
|
48
|
+
if normalized == "tcp":
|
|
49
|
+
return DEFAULT_TCP_PORT
|
|
50
|
+
if normalized == "udp":
|
|
51
|
+
return DEFAULT_UDP_PORT
|
|
52
|
+
raise ValueError("transport must be 'tcp' or 'udp'")
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _resolve_port(port: int | None, transport: str) -> int:
|
|
56
|
+
if port is None:
|
|
57
|
+
return _default_port_for_transport(transport)
|
|
58
|
+
return port
|
|
59
|
+
|
|
42
60
|
|
|
43
61
|
@dataclass(frozen=True)
|
|
44
62
|
class SlmpTarget:
|
|
@@ -17,6 +17,7 @@ from .core import (
|
|
|
17
17
|
_require_explicit_plc_profile_for_xy,
|
|
18
18
|
_resolve_connection_profile,
|
|
19
19
|
_resolve_plc_profile_defaults,
|
|
20
|
+
_resolve_port,
|
|
20
21
|
_validate_direct_dword_read_device,
|
|
21
22
|
parse_device,
|
|
22
23
|
)
|
|
@@ -68,14 +69,15 @@ class SlmpConnectionOptions:
|
|
|
68
69
|
|
|
69
70
|
The options object is the recommended input for :func:`open_and_connect`
|
|
70
71
|
and :func:`open_and_connect_sync`. It keeps transport-level settings and
|
|
71
|
-
protocol-level defaults together so maintained documentation can point users to
|
|
72
|
+
protocol-level defaults together so maintained documentation can point users to
|
|
72
73
|
one explicit connection entry point.
|
|
73
74
|
|
|
74
75
|
Attributes:
|
|
75
76
|
host: PLC hostname or IP address.
|
|
76
77
|
plc_profile: Canonical high-level PLC profile. This is the only
|
|
77
78
|
application-level PLC selector for the recommended helper layer.
|
|
78
|
-
port: TCP or UDP port used by the SLMP endpoint.
|
|
79
|
+
port: TCP or UDP port used by the SLMP endpoint. Defaults to
|
|
80
|
+
``1025`` for TCP and ``1035`` for UDP when omitted.
|
|
79
81
|
transport: Transport name such as ``"tcp"`` or ``"udp"``.
|
|
80
82
|
timeout: Socket timeout in seconds.
|
|
81
83
|
default_target: Optional routing target applied to requests.
|
|
@@ -90,7 +92,7 @@ class SlmpConnectionOptions:
|
|
|
90
92
|
|
|
91
93
|
host: str
|
|
92
94
|
plc_profile: object
|
|
93
|
-
port: int =
|
|
95
|
+
port: int | None = None
|
|
94
96
|
transport: str = "tcp"
|
|
95
97
|
timeout: float = 3.0
|
|
96
98
|
default_target: SlmpTarget | None = None
|
|
@@ -105,6 +107,8 @@ class SlmpConnectionOptions:
|
|
|
105
107
|
def __post_init__(self) -> None:
|
|
106
108
|
if self.plc_profile is None:
|
|
107
109
|
raise ValueError("plc_profile is required. Use an explicit canonical PLC profile such as 'melsec:iq-r'.")
|
|
110
|
+
transport = self.transport.lower()
|
|
111
|
+
port = _resolve_port(self.port, transport)
|
|
108
112
|
(
|
|
109
113
|
normalized_plc_profile,
|
|
110
114
|
plc_series,
|
|
@@ -117,6 +121,8 @@ class SlmpConnectionOptions:
|
|
|
117
121
|
frame_type=None,
|
|
118
122
|
address_profile=None,
|
|
119
123
|
)
|
|
124
|
+
object.__setattr__(self, "transport", transport)
|
|
125
|
+
object.__setattr__(self, "port", port)
|
|
120
126
|
object.__setattr__(self, "plc_profile", normalized_plc_profile)
|
|
121
127
|
object.__setattr__(self, "plc_series", plc_series)
|
|
122
128
|
object.__setattr__(self, "frame_type", frame_type)
|
{slmp_connect_python-0.8.0 → slmp_connect_python-1.0.0/slmp_connect_python.egg-info}/PKG-INFO
RENAMED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: slmp-connect-python
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 1.0.0
|
|
4
4
|
Summary: SLMP Connect Python: client library for MELSEC SLMP binary communication
|
|
5
5
|
Author: fa-yoshinobu
|
|
6
6
|
License-Expression: MIT
|
|
7
7
|
Project-URL: Homepage, https://github.com/fa-yoshinobu/plc-comm-slmp-python
|
|
8
8
|
Project-URL: Repository, https://github.com/fa-yoshinobu/plc-comm-slmp-python
|
|
9
9
|
Project-URL: Issues, https://github.com/fa-yoshinobu/plc-comm-slmp-python/issues
|
|
10
|
-
Keywords: slmp,melsec,
|
|
11
|
-
Classifier: Development Status ::
|
|
10
|
+
Keywords: slmp,melsec,plc,3e,4e,binary
|
|
11
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
12
12
|
Classifier: Intended Audience :: Developers
|
|
13
13
|
Classifier: Programming Language :: Python :: 3
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.10
|
|
@@ -33,14 +33,9 @@ Requires-Dist: twine>=5.1; extra == "dev"
|
|
|
33
33
|
Dynamic: license-file
|
|
34
34
|
|
|
35
35
|
[](https://github.com/fa-yoshinobu/plc-comm-slmp-python/actions/workflows/ci.yml)
|
|
36
|
-
[](https://fa-yoshinobu.github.io/plc-comm-docs-site/slmp/python/GETTING_STARTED/)
|
|
37
36
|
[](https://pypi.org/project/slmp-connect-python/)
|
|
38
37
|
[](https://www.python.org/downloads/)
|
|
39
38
|
[](LICENSE)
|
|
40
|
-
[](https://github.com/astral-sh/ruff)
|
|
41
|
-
[](https://github.com/fa-yoshinobu/plc-comm-slmp-python/releases/latest)
|
|
42
|
-
[](https://www.python.org/)
|
|
43
|
-
[](https://www.mkdocs.org/)
|
|
44
39
|
|
|
45
40
|
# MELSEC SLMP for Python
|
|
46
41
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{slmp_connect_python-0.8.0 → slmp_connect_python-1.0.0}/slmp_connect_python.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{slmp_connect_python-0.8.0 → slmp_connect_python-1.0.0}/slmp_connect_python.egg-info/requires.txt
RENAMED
|
File without changes
|
{slmp_connect_python-0.8.0 → slmp_connect_python-1.0.0}/slmp_connect_python.egg-info/top_level.txt
RENAMED
|
File without changes
|