python-snap7 1.3__tar.gz → 1.4__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.
- {python-snap7-1.3 → python_snap7-1.4}/MANIFEST.in +0 -1
- python_snap7-1.4/PKG-INFO +33 -0
- python_snap7-1.4/README.rst +21 -0
- python_snap7-1.4/pyproject.toml +69 -0
- python_snap7-1.4/python_snap7.egg-info/PKG-INFO +33 -0
- {python-snap7-1.3 → python_snap7-1.4}/python_snap7.egg-info/SOURCES.txt +12 -10
- {python-snap7-1.3 → python_snap7-1.4}/python_snap7.egg-info/requires.txt +2 -2
- python_snap7-1.4/setup.cfg +4 -0
- {python-snap7-1.3 → python_snap7-1.4}/snap7/__init__.py +5 -4
- {python-snap7-1.3 → python_snap7-1.4}/snap7/client/__init__.py +93 -91
- {python-snap7-1.3 → python_snap7-1.4}/snap7/common.py +27 -22
- python_snap7-1.4/snap7/error.py +104 -0
- {python-snap7-1.3 → python_snap7-1.4}/snap7/exceptions.py +0 -1
- {python-snap7-1.3 → python_snap7-1.4}/snap7/logo.py +8 -12
- {python-snap7-1.3 → python_snap7-1.4}/snap7/partner.py +9 -13
- {python-snap7-1.3 → python_snap7-1.4}/snap7/server/__init__.py +58 -69
- {python-snap7-1.3 → python_snap7-1.4}/snap7/server/__main__.py +2 -3
- python_snap7-1.4/snap7/types.py +324 -0
- python_snap7-1.4/snap7/util/__init__.py +200 -0
- python_snap7-1.4/snap7/util/db.py +604 -0
- python_snap7-1.4/snap7/util/getters.py +719 -0
- python_snap7-1.4/snap7/util/setters.py +536 -0
- {python-snap7-1.3/test → python_snap7-1.4/tests}/test_client.py +128 -113
- {python-snap7-1.3/test → python_snap7-1.4/tests}/test_common.py +4 -3
- {python-snap7-1.3/test → python_snap7-1.4/tests}/test_logo_client.py +15 -8
- {python-snap7-1.3/test → python_snap7-1.4/tests}/test_mainloop.py +26 -20
- {python-snap7-1.3/test → python_snap7-1.4/tests}/test_partner.py +8 -8
- {python-snap7-1.3/test → python_snap7-1.4/tests}/test_server.py +33 -29
- python_snap7-1.4/tests/test_util.py +608 -0
- python-snap7-1.3/PKG-INFO +0 -68
- python-snap7-1.3/README.rst +0 -42
- python-snap7-1.3/python_snap7.egg-info/PKG-INFO +0 -68
- python-snap7-1.3/setup.cfg +0 -13
- python-snap7-1.3/setup.py +0 -66
- python-snap7-1.3/snap7/error.py +0 -104
- python-snap7-1.3/snap7/types.py +0 -327
- python-snap7-1.3/snap7/util.py +0 -1878
- python-snap7-1.3/test/test_util.py +0 -567
- {python-snap7-1.3 → python_snap7-1.4}/LICENSE +0 -0
- {python-snap7-1.3 → python_snap7-1.4}/python_snap7.egg-info/dependency_links.txt +0 -0
- {python-snap7-1.3 → python_snap7-1.4}/python_snap7.egg-info/entry_points.txt +0 -0
- {python-snap7-1.3 → python_snap7-1.4}/python_snap7.egg-info/top_level.txt +0 -0
- {python-snap7-1.3 → python_snap7-1.4}/snap7/py.typed +0 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: python-snap7
|
|
3
|
+
Version: 1.4
|
|
4
|
+
Summary: Python wrapper for the snap7 library
|
|
5
|
+
Author-email: Gijs Molenaar <gijsmolenaar@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/gijzelaerr/python-snap7
|
|
8
|
+
Project-URL: Documentation, https://python-snap7.readthedocs.io/en/latest/
|
|
9
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
10
|
+
Classifier: Environment :: Console
|
|
11
|
+
Classifier: Topic :: System :: Hardware
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Intended Audience :: Manufacturing
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: POSIX
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Requires-Python: >=3.8
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Provides-Extra: test
|
|
24
|
+
Requires-Dist: pytest; extra == "test"
|
|
25
|
+
Requires-Dist: mypy; extra == "test"
|
|
26
|
+
Requires-Dist: types-setuptools; extra == "test"
|
|
27
|
+
Requires-Dist: ruff; extra == "test"
|
|
28
|
+
Provides-Extra: cli
|
|
29
|
+
Requires-Dist: rich; extra == "cli"
|
|
30
|
+
Requires-Dist: click; extra == "cli"
|
|
31
|
+
Provides-Extra: doc
|
|
32
|
+
Requires-Dist: sphinx; extra == "doc"
|
|
33
|
+
Requires-Dist: sphinx_rtd_theme; extra == "doc"
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
About
|
|
2
|
+
=====
|
|
3
|
+
|
|
4
|
+
This is a ctypes-based Python wrapper for snap7. Snap7 is an open-source,
|
|
5
|
+
32/64 bit, multi-platform Ethernet communication suite for interfacing natively
|
|
6
|
+
with Siemens S7 PLCs.
|
|
7
|
+
|
|
8
|
+
Python-snap7 is tested with Python 3.9+, on Windows, Linux and OS X.
|
|
9
|
+
|
|
10
|
+
The full documentation is available on `Read The Docs <https://python-snap7.readthedocs.io/en/latest/>`_.
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
Installation
|
|
14
|
+
============
|
|
15
|
+
|
|
16
|
+
If you are running Windows, Mac OS X or GNU/Linux on an Intel x64 or ARM 64 compatible platform you can use the binary wheel installation::
|
|
17
|
+
|
|
18
|
+
$ pip install python-snap7
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
Otherwise, please read the `online installation documentation <https://python-snap7.readthedocs.io/en/latest/installation.html>`_.
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68.0.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "python-snap7"
|
|
7
|
+
version = "1.4"
|
|
8
|
+
description = "Python wrapper for the snap7 library"
|
|
9
|
+
authors = [
|
|
10
|
+
{name = "Gijs Molenaar", email = "gijsmolenaar@gmail.com"},
|
|
11
|
+
]
|
|
12
|
+
classifiers = [
|
|
13
|
+
"Development Status :: 5 - Production/Stable",
|
|
14
|
+
"Environment :: Console",
|
|
15
|
+
"Topic :: System :: Hardware",
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"Intended Audience :: Manufacturing",
|
|
18
|
+
"License :: OSI Approved :: MIT License",
|
|
19
|
+
"Operating System :: POSIX",
|
|
20
|
+
"Programming Language :: Python :: 3.8",
|
|
21
|
+
"Programming Language :: Python :: 3.9",
|
|
22
|
+
"Programming Language :: Python :: 3.10",
|
|
23
|
+
"Programming Language :: Python :: 3.11",
|
|
24
|
+
"Programming Language :: Python :: 3.12",
|
|
25
|
+
]
|
|
26
|
+
license = {text = "MIT"}
|
|
27
|
+
requires-python = ">=3.8"
|
|
28
|
+
|
|
29
|
+
[project.urls]
|
|
30
|
+
Homepage = "https://github.com/gijzelaerr/python-snap7"
|
|
31
|
+
Documentation = "https://python-snap7.readthedocs.io/en/latest/"
|
|
32
|
+
|
|
33
|
+
[project.optional-dependencies]
|
|
34
|
+
test = ["pytest", "mypy", "types-setuptools", "ruff"]
|
|
35
|
+
cli = ["rich", "click" ]
|
|
36
|
+
doc = ["sphinx", "sphinx_rtd_theme"]
|
|
37
|
+
|
|
38
|
+
[tool.setuptools.package-data]
|
|
39
|
+
snap7 = ["py.typed", "lib/libsnap7.so", "lib/snap7.dll", "lib/libsnap7.dylib"]
|
|
40
|
+
|
|
41
|
+
[tool.setuptools.packages.find]
|
|
42
|
+
include = ["snap7*"]
|
|
43
|
+
|
|
44
|
+
[project.scripts]
|
|
45
|
+
snap7-server = "snap7.server.__main__:main"
|
|
46
|
+
|
|
47
|
+
[tool.pytest.ini_options]
|
|
48
|
+
testpaths = ["tests"]
|
|
49
|
+
markers =[
|
|
50
|
+
"client",
|
|
51
|
+
"common",
|
|
52
|
+
"logo",
|
|
53
|
+
"mainloop",
|
|
54
|
+
"partner",
|
|
55
|
+
"server",
|
|
56
|
+
"util"
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
[tool.mypy]
|
|
60
|
+
ignore_missing_imports = true
|
|
61
|
+
|
|
62
|
+
[tool.ruff]
|
|
63
|
+
output-format = "full"
|
|
64
|
+
line-length = 130
|
|
65
|
+
target-version = "py38"
|
|
66
|
+
|
|
67
|
+
[lint]
|
|
68
|
+
ignore = []
|
|
69
|
+
mccabe.max-complexity = 10
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: python-snap7
|
|
3
|
+
Version: 1.4
|
|
4
|
+
Summary: Python wrapper for the snap7 library
|
|
5
|
+
Author-email: Gijs Molenaar <gijsmolenaar@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/gijzelaerr/python-snap7
|
|
8
|
+
Project-URL: Documentation, https://python-snap7.readthedocs.io/en/latest/
|
|
9
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
10
|
+
Classifier: Environment :: Console
|
|
11
|
+
Classifier: Topic :: System :: Hardware
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Intended Audience :: Manufacturing
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: POSIX
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Requires-Python: >=3.8
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Provides-Extra: test
|
|
24
|
+
Requires-Dist: pytest; extra == "test"
|
|
25
|
+
Requires-Dist: mypy; extra == "test"
|
|
26
|
+
Requires-Dist: types-setuptools; extra == "test"
|
|
27
|
+
Requires-Dist: ruff; extra == "test"
|
|
28
|
+
Provides-Extra: cli
|
|
29
|
+
Requires-Dist: rich; extra == "cli"
|
|
30
|
+
Requires-Dist: click; extra == "cli"
|
|
31
|
+
Provides-Extra: doc
|
|
32
|
+
Requires-Dist: sphinx; extra == "doc"
|
|
33
|
+
Requires-Dist: sphinx_rtd_theme; extra == "doc"
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
LICENSE
|
|
2
2
|
MANIFEST.in
|
|
3
3
|
README.rst
|
|
4
|
-
|
|
5
|
-
setup.py
|
|
4
|
+
pyproject.toml
|
|
6
5
|
python_snap7.egg-info/PKG-INFO
|
|
7
6
|
python_snap7.egg-info/SOURCES.txt
|
|
8
7
|
python_snap7.egg-info/dependency_links.txt
|
|
@@ -17,14 +16,17 @@ snap7/logo.py
|
|
|
17
16
|
snap7/partner.py
|
|
18
17
|
snap7/py.typed
|
|
19
18
|
snap7/types.py
|
|
20
|
-
snap7/util.py
|
|
21
19
|
snap7/client/__init__.py
|
|
22
20
|
snap7/server/__init__.py
|
|
23
21
|
snap7/server/__main__.py
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
22
|
+
snap7/util/__init__.py
|
|
23
|
+
snap7/util/db.py
|
|
24
|
+
snap7/util/getters.py
|
|
25
|
+
snap7/util/setters.py
|
|
26
|
+
tests/test_client.py
|
|
27
|
+
tests/test_common.py
|
|
28
|
+
tests/test_logo_client.py
|
|
29
|
+
tests/test_mainloop.py
|
|
30
|
+
tests/test_partner.py
|
|
31
|
+
tests/test_server.py
|
|
32
|
+
tests/test_util.py
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"""
|
|
2
2
|
The Snap7 Python library.
|
|
3
3
|
"""
|
|
4
|
-
|
|
4
|
+
|
|
5
|
+
from importlib.metadata import version, PackageNotFoundError
|
|
5
6
|
|
|
6
7
|
from . import client
|
|
7
8
|
from . import common
|
|
@@ -11,9 +12,9 @@ from . import server
|
|
|
11
12
|
from . import types
|
|
12
13
|
from . import util
|
|
13
14
|
|
|
14
|
-
__all__ = [
|
|
15
|
+
__all__ = ["client", "common", "error", "logo", "server", "types", "util"]
|
|
15
16
|
|
|
16
17
|
try:
|
|
17
|
-
__version__ =
|
|
18
|
-
except
|
|
18
|
+
__version__ = version("python-snap7")
|
|
19
|
+
except PackageNotFoundError:
|
|
19
20
|
__version__ = "0.0rc0"
|
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Snap7 client used for connection to a siemens 7 server.
|
|
3
3
|
"""
|
|
4
|
+
|
|
4
5
|
import re
|
|
5
6
|
import logging
|
|
6
|
-
from ctypes import byref, create_string_buffer, sizeof
|
|
7
|
+
from ctypes import CFUNCTYPE, byref, create_string_buffer, sizeof
|
|
7
8
|
from ctypes import Array, c_byte, c_char_p, c_int, c_int32, c_uint16, c_ulong, c_void_p
|
|
8
9
|
from datetime import datetime
|
|
9
|
-
from typing import List, Optional, Tuple, Union
|
|
10
|
+
from typing import Any, Callable, List, Optional, Tuple, Union
|
|
10
11
|
|
|
11
12
|
from ..common import check_error, ipv4, load_library
|
|
12
13
|
from ..types import S7SZL, Areas, BlocksList, S7CpInfo, S7CpuInfo, S7DataItem
|
|
13
14
|
from ..types import S7OrderCode, S7Protection, S7SZLList, TS7BlockInfo, WordLen
|
|
14
15
|
from ..types import S7Object, buffer_size, buffer_type, cpu_statuses, param_types
|
|
15
|
-
from ..types import
|
|
16
|
+
from ..types import RemotePort, wordlen_to_ctypes, block_types
|
|
17
|
+
|
|
16
18
|
logger = logging.getLogger(__name__)
|
|
17
19
|
|
|
18
20
|
|
|
@@ -68,8 +70,7 @@ class Client:
|
|
|
68
70
|
self.destroy()
|
|
69
71
|
|
|
70
72
|
def create(self):
|
|
71
|
-
"""Creates a SNAP7 client.
|
|
72
|
-
"""
|
|
73
|
+
"""Creates a SNAP7 client."""
|
|
73
74
|
logger.info("creating snap7 client")
|
|
74
75
|
self._library.Cli_Create.restype = c_void_p
|
|
75
76
|
self._pointer = S7Object(self._library.Cli_Create())
|
|
@@ -190,9 +191,7 @@ class Client:
|
|
|
190
191
|
logger.info(f"connecting to {address}:{tcpport} rack {rack} slot {slot}")
|
|
191
192
|
|
|
192
193
|
self.set_param(RemotePort, tcpport)
|
|
193
|
-
return self._library.Cli_ConnectTo(
|
|
194
|
-
self._pointer, c_char_p(address.encode()),
|
|
195
|
-
c_int(rack), c_int(slot))
|
|
194
|
+
return self._library.Cli_ConnectTo(self._pointer, c_char_p(address.encode()), c_int(rack), c_int(slot))
|
|
196
195
|
|
|
197
196
|
def db_read(self, db_number: int, start: int, size: int) -> bytearray:
|
|
198
197
|
"""Reads a part of a DB from a PLC
|
|
@@ -220,9 +219,7 @@ class Client:
|
|
|
220
219
|
|
|
221
220
|
type_ = wordlen_to_ctypes[WordLen.Byte.value]
|
|
222
221
|
data = (type_ * size)()
|
|
223
|
-
result =
|
|
224
|
-
self._pointer, db_number, start, size,
|
|
225
|
-
byref(data)))
|
|
222
|
+
result = self._library.Cli_DBRead(self._pointer, db_number, start, size, byref(data))
|
|
226
223
|
check_error(result, context="client")
|
|
227
224
|
return bytearray(data)
|
|
228
225
|
|
|
@@ -250,8 +247,7 @@ class Client:
|
|
|
250
247
|
size = len(data)
|
|
251
248
|
cdata = (type_ * size).from_buffer_copy(data)
|
|
252
249
|
logger.debug(f"db_write db_number:{db_number} start:{start} size:{size} data:{data}")
|
|
253
|
-
return self._library.Cli_DBWrite(self._pointer, db_number, start, size,
|
|
254
|
-
byref(cdata))
|
|
250
|
+
return self._library.Cli_DBWrite(self._pointer, db_number, start, size, byref(cdata))
|
|
255
251
|
|
|
256
252
|
def delete(self, block_type: str, block_num: int) -> int:
|
|
257
253
|
"""Delete a block into AG.
|
|
@@ -283,11 +279,9 @@ class Client:
|
|
|
283
279
|
_buffer = buffer_type()
|
|
284
280
|
size = c_int(sizeof(_buffer))
|
|
285
281
|
block_type = block_types[_type]
|
|
286
|
-
result = self._library.Cli_FullUpload(self._pointer, block_type,
|
|
287
|
-
block_num, byref(_buffer),
|
|
288
|
-
byref(size))
|
|
282
|
+
result = self._library.Cli_FullUpload(self._pointer, block_type, block_num, byref(_buffer), byref(size))
|
|
289
283
|
check_error(result, context="client")
|
|
290
|
-
return bytearray(_buffer)[:size.value], size.value
|
|
284
|
+
return bytearray(_buffer)[: size.value], size.value
|
|
291
285
|
|
|
292
286
|
def upload(self, block_num: int) -> bytearray:
|
|
293
287
|
"""Uploads a block from AG.
|
|
@@ -302,15 +296,14 @@ class Client:
|
|
|
302
296
|
Buffer with the uploaded block.
|
|
303
297
|
"""
|
|
304
298
|
logger.debug(f"db_upload block_num: {block_num}")
|
|
305
|
-
block_type = block_types[
|
|
299
|
+
block_type = block_types["DB"]
|
|
306
300
|
_buffer = buffer_type()
|
|
307
301
|
size = c_int(sizeof(_buffer))
|
|
308
302
|
|
|
309
|
-
result = self._library.Cli_Upload(self._pointer, block_type, block_num,
|
|
310
|
-
byref(_buffer), byref(size))
|
|
303
|
+
result = self._library.Cli_Upload(self._pointer, block_type, block_num, byref(_buffer), byref(size))
|
|
311
304
|
|
|
312
305
|
check_error(result, context="client")
|
|
313
|
-
logger.info(f
|
|
306
|
+
logger.info(f"received {size} bytes")
|
|
314
307
|
return bytearray(_buffer)
|
|
315
308
|
|
|
316
309
|
@error_wrap
|
|
@@ -332,8 +325,7 @@ class Client:
|
|
|
332
325
|
type_ = c_byte
|
|
333
326
|
size = len(data)
|
|
334
327
|
cdata = (type_ * len(data)).from_buffer_copy(data)
|
|
335
|
-
return self._library.Cli_Download(self._pointer, block_num,
|
|
336
|
-
byref(cdata), size)
|
|
328
|
+
return self._library.Cli_Download(self._pointer, block_num, byref(cdata), size)
|
|
337
329
|
|
|
338
330
|
def db_get(self, db_number: int) -> bytearray:
|
|
339
331
|
"""Uploads a DB from AG using DBRead.
|
|
@@ -357,35 +349,33 @@ class Client:
|
|
|
357
349
|
"""
|
|
358
350
|
logger.debug(f"db_get db_number: {db_number}")
|
|
359
351
|
_buffer = buffer_type()
|
|
360
|
-
result = self._library.Cli_DBGet(
|
|
361
|
-
self._pointer, db_number, byref(_buffer),
|
|
362
|
-
byref(c_int(buffer_size)))
|
|
352
|
+
result = self._library.Cli_DBGet(self._pointer, db_number, byref(_buffer), byref(c_int(buffer_size)))
|
|
363
353
|
check_error(result, context="client")
|
|
364
354
|
return bytearray(_buffer)
|
|
365
355
|
|
|
366
356
|
def read_area(self, area: Areas, dbnumber: int, start: int, size: int) -> bytearray:
|
|
367
357
|
"""Reads a data area from a PLC
|
|
368
|
-
|
|
358
|
+
With it you can read DB, Inputs, Outputs, Merkers, Timers and Counters.
|
|
369
359
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
360
|
+
Args:
|
|
361
|
+
area: area to be read from.
|
|
362
|
+
dbnumber: number of the db to be read from. In case of Inputs, Marks or Outputs, this should be equal to 0.
|
|
363
|
+
start: byte index to start reading.
|
|
364
|
+
size: number of bytes to read.
|
|
375
365
|
|
|
376
|
-
|
|
377
|
-
|
|
366
|
+
Returns:
|
|
367
|
+
Buffer with the data read.
|
|
378
368
|
|
|
379
|
-
|
|
380
|
-
|
|
369
|
+
Raises:
|
|
370
|
+
:obj:`ValueError`: if the area is not defined in the `Areas`
|
|
381
371
|
|
|
382
|
-
|
|
383
|
-
>>> import snap7
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
372
|
+
Example:
|
|
373
|
+
import snap7.util.db >>> import snap7
|
|
374
|
+
>>> client = snap7.client.Client()
|
|
375
|
+
>>> client.connect("192.168.0.1", 0, 0)
|
|
376
|
+
>>> buffer = client.read_area(snap7.util.db.DB, 1, 10, 4) # Reads the DB number 1 from the byte 10 to the byte 14.
|
|
377
|
+
>>> buffer
|
|
378
|
+
bytearray(b'\\x00\\x00')
|
|
389
379
|
"""
|
|
390
380
|
if area not in Areas:
|
|
391
381
|
raise ValueError(f"{area} is not implemented in types")
|
|
@@ -396,10 +386,12 @@ class Client:
|
|
|
396
386
|
else:
|
|
397
387
|
wordlen = WordLen.Byte
|
|
398
388
|
type_ = wordlen_to_ctypes[wordlen.value]
|
|
399
|
-
logger.debug(
|
|
389
|
+
logger.debug(
|
|
390
|
+
f"reading area: {area.name} dbnumber: {dbnumber} start: {start} amount: {size} "
|
|
391
|
+
f"wordlen: {wordlen.name}={wordlen.value}"
|
|
392
|
+
)
|
|
400
393
|
data = (type_ * size)()
|
|
401
|
-
result = self._library.Cli_ReadArea(self._pointer, area.value, dbnumber, start,
|
|
402
|
-
size, wordlen.value, byref(data))
|
|
394
|
+
result = self._library.Cli_ReadArea(self._pointer, area.value, dbnumber, start, size, wordlen.value, byref(data))
|
|
403
395
|
check_error(result, context="client")
|
|
404
396
|
return bytearray(data)
|
|
405
397
|
|
|
@@ -417,11 +409,13 @@ class Client:
|
|
|
417
409
|
Snap7 error code.
|
|
418
410
|
|
|
419
411
|
Exmaple:
|
|
412
|
+
>>> import snap7.util.db
|
|
420
413
|
>>> import snap7
|
|
421
414
|
>>> client = snap7.client.Client()
|
|
422
415
|
>>> client.connect("192.168.0.1", 0, 0)
|
|
423
416
|
>>> buffer = bytearray([0b00000001])
|
|
424
|
-
|
|
417
|
+
# Writes the bit 0 of the byte 10 from the DB number 1 to TRUE.
|
|
418
|
+
>>> client.write_area(snap7.util.DB, 1, 10, buffer)
|
|
425
419
|
"""
|
|
426
420
|
if area == Areas.TM:
|
|
427
421
|
wordlen = WordLen.Timer
|
|
@@ -431,11 +425,12 @@ class Client:
|
|
|
431
425
|
wordlen = WordLen.Byte
|
|
432
426
|
type_ = wordlen_to_ctypes[WordLen.Byte.value]
|
|
433
427
|
size = len(data)
|
|
434
|
-
logger.debug(
|
|
435
|
-
|
|
428
|
+
logger.debug(
|
|
429
|
+
f"writing area: {area.name} dbnumber: {dbnumber} start: {start}: size {size}: "
|
|
430
|
+
f"wordlen {wordlen.name}={wordlen.value} type: {type_}"
|
|
431
|
+
)
|
|
436
432
|
cdata = (type_ * len(data)).from_buffer_copy(data)
|
|
437
|
-
return self._library.Cli_WriteArea(self._pointer, area.value, dbnumber, start,
|
|
438
|
-
size, wordlen.value, byref(cdata))
|
|
433
|
+
return self._library.Cli_WriteArea(self._pointer, area.value, dbnumber, start, size, wordlen.value, byref(cdata))
|
|
439
434
|
|
|
440
435
|
def read_multi_vars(self, items) -> Tuple[int, S7DataItem]:
|
|
441
436
|
"""Reads different kind of variables from a PLC simultaneously.
|
|
@@ -446,8 +441,7 @@ class Client:
|
|
|
446
441
|
Returns:
|
|
447
442
|
Tuple with the return code from the snap7 library and the list of items.
|
|
448
443
|
"""
|
|
449
|
-
result = self._library.Cli_ReadMultiVars(self._pointer, byref(items),
|
|
450
|
-
c_int32(len(items)))
|
|
444
|
+
result = self._library.Cli_ReadMultiVars(self._pointer, byref(items), c_int32(len(items)))
|
|
451
445
|
check_error(result, context="client")
|
|
452
446
|
return result, items
|
|
453
447
|
|
|
@@ -494,10 +488,7 @@ class Client:
|
|
|
494
488
|
|
|
495
489
|
data = (c_uint16 * size)()
|
|
496
490
|
count = c_int(size)
|
|
497
|
-
result = self._library.Cli_ListBlocksOfType(
|
|
498
|
-
self._pointer, _blocktype,
|
|
499
|
-
byref(data),
|
|
500
|
-
byref(count))
|
|
491
|
+
result = self._library.Cli_ListBlocksOfType(self._pointer, _blocktype, byref(data), byref(count))
|
|
501
492
|
|
|
502
493
|
logger.debug(f"number of items found: {count}")
|
|
503
494
|
|
|
@@ -563,8 +554,7 @@ class Client:
|
|
|
563
554
|
"""
|
|
564
555
|
if len(password) > 8:
|
|
565
556
|
raise ValueError("Maximum password length is 8")
|
|
566
|
-
return self._library.Cli_SetSessionPassword(self._pointer,
|
|
567
|
-
c_char_p(password.encode()))
|
|
557
|
+
return self._library.Cli_SetSessionPassword(self._pointer, c_char_p(password.encode()))
|
|
568
558
|
|
|
569
559
|
@error_wrap
|
|
570
560
|
def clear_session_password(self) -> int:
|
|
@@ -593,14 +583,12 @@ class Client:
|
|
|
593
583
|
"""
|
|
594
584
|
if not re.match(ipv4, address):
|
|
595
585
|
raise ValueError(f"{address} is invalid ipv4")
|
|
596
|
-
result = self._library.Cli_SetConnectionParams(self._pointer, address,
|
|
597
|
-
c_uint16(local_tsap),
|
|
598
|
-
c_uint16(remote_tsap))
|
|
586
|
+
result = self._library.Cli_SetConnectionParams(self._pointer, address, c_uint16(local_tsap), c_uint16(remote_tsap))
|
|
599
587
|
if result != 0:
|
|
600
588
|
raise ValueError("The parameter was invalid")
|
|
601
589
|
|
|
602
590
|
def set_connection_type(self, connection_type: int):
|
|
603
|
-
"""
|
|
591
|
+
"""Sets the connection resource type, i.e the way in which the Clients connects to a PLC.
|
|
604
592
|
|
|
605
593
|
Args:
|
|
606
594
|
connection_type: 1 for PG, 2 for OP, 3 to 10 for S7 Basic
|
|
@@ -609,8 +597,7 @@ class Client:
|
|
|
609
597
|
:obj:`ValueError`: if the result of setting the connection type is
|
|
610
598
|
different than 0.
|
|
611
599
|
"""
|
|
612
|
-
result = self._library.Cli_SetConnectionType(self._pointer,
|
|
613
|
-
c_uint16(connection_type))
|
|
600
|
+
result = self._library.Cli_SetConnectionType(self._pointer, c_uint16(connection_type))
|
|
614
601
|
if result != 0:
|
|
615
602
|
raise ValueError("The parameter was invalid")
|
|
616
603
|
|
|
@@ -642,8 +629,7 @@ class Client:
|
|
|
642
629
|
type_ = wordlen_to_ctypes[wordlen.value]
|
|
643
630
|
data = (type_ * size)()
|
|
644
631
|
logger.debug(f"ab_read: start: {start}: size {size}: ")
|
|
645
|
-
result = self._library.Cli_ABRead(self._pointer, start, size,
|
|
646
|
-
byref(data))
|
|
632
|
+
result = self._library.Cli_ABRead(self._pointer, start, size, byref(data))
|
|
647
633
|
check_error(result, context="client")
|
|
648
634
|
return bytearray(data)
|
|
649
635
|
|
|
@@ -662,8 +648,7 @@ class Client:
|
|
|
662
648
|
size = len(data)
|
|
663
649
|
cdata = (type_ * size).from_buffer_copy(data)
|
|
664
650
|
logger.debug(f"ab write: start: {start}: size: {size}: ")
|
|
665
|
-
return self._library.Cli_ABWrite(
|
|
666
|
-
self._pointer, start, size, byref(cdata))
|
|
651
|
+
return self._library.Cli_ABWrite(self._pointer, start, size, byref(cdata))
|
|
667
652
|
|
|
668
653
|
def as_ab_read(self, start: int, size: int, data) -> int:
|
|
669
654
|
"""Reads a part of IPU area from a PLC asynchronously.
|
|
@@ -677,8 +662,7 @@ class Client:
|
|
|
677
662
|
Snap7 code.
|
|
678
663
|
"""
|
|
679
664
|
logger.debug(f"ab_read: start: {start}: size {size}: ")
|
|
680
|
-
result = self._library.Cli_AsABRead(self._pointer, start, size,
|
|
681
|
-
byref(data))
|
|
665
|
+
result = self._library.Cli_AsABRead(self._pointer, start, size, byref(data))
|
|
682
666
|
check_error(result, context="client")
|
|
683
667
|
return result
|
|
684
668
|
|
|
@@ -697,13 +681,12 @@ class Client:
|
|
|
697
681
|
size = len(data)
|
|
698
682
|
cdata = (type_ * size).from_buffer_copy(data)
|
|
699
683
|
logger.debug(f"ab write: start: {start}: size: {size}: ")
|
|
700
|
-
result = self._library.Cli_AsABWrite(
|
|
701
|
-
self._pointer, start, size, byref(cdata))
|
|
684
|
+
result = self._library.Cli_AsABWrite(self._pointer, start, size, byref(cdata))
|
|
702
685
|
check_error(result, context="client")
|
|
703
686
|
return result
|
|
704
687
|
|
|
705
688
|
def as_compress(self, time: int) -> int:
|
|
706
|
-
"""
|
|
689
|
+
"""Performs the Compress action asynchronously.
|
|
707
690
|
|
|
708
691
|
Args:
|
|
709
692
|
time: timeout.
|
|
@@ -927,12 +910,7 @@ class Client:
|
|
|
927
910
|
check_error(result, context="client")
|
|
928
911
|
|
|
929
912
|
return datetime(
|
|
930
|
-
year=buffer[5] + 1900,
|
|
931
|
-
month=buffer[4] + 1,
|
|
932
|
-
day=buffer[3],
|
|
933
|
-
hour=buffer[2],
|
|
934
|
-
minute=buffer[1],
|
|
935
|
-
second=buffer[0]
|
|
913
|
+
year=buffer[5] + 1900, month=buffer[4] + 1, day=buffer[3], hour=buffer[2], minute=buffer[1], second=buffer[0]
|
|
936
914
|
)
|
|
937
915
|
|
|
938
916
|
@error_wrap
|
|
@@ -969,10 +947,30 @@ class Client:
|
|
|
969
947
|
check_error(result, context="client")
|
|
970
948
|
return result
|
|
971
949
|
|
|
972
|
-
def set_as_callback(self,
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
950
|
+
def set_as_callback(self, call_back: Callable[..., Any]) -> int:
|
|
951
|
+
logger.info("setting event callback")
|
|
952
|
+
callback_wrap: Callable[..., Any] = CFUNCTYPE(None, c_void_p, c_int, c_int)
|
|
953
|
+
|
|
954
|
+
def wrapper(usrptr: Optional[c_void_p], op_code: int, op_result: int) -> int:
|
|
955
|
+
"""Wraps python function into a ctypes function
|
|
956
|
+
|
|
957
|
+
Args:
|
|
958
|
+
usrptr: not used
|
|
959
|
+
op_code:
|
|
960
|
+
op_result:
|
|
961
|
+
|
|
962
|
+
Returns:
|
|
963
|
+
Should return an int
|
|
964
|
+
"""
|
|
965
|
+
logger.info(f"callback event: op_code: {op_code} op_result: {op_result}")
|
|
966
|
+
call_back(op_code, op_result)
|
|
967
|
+
return 0
|
|
968
|
+
|
|
969
|
+
self._callback = callback_wrap(wrapper)
|
|
970
|
+
usrPtr = c_void_p()
|
|
971
|
+
|
|
972
|
+
result = self._library.Cli_SetAsCallback(self._pointer, self._callback, usrPtr)
|
|
973
|
+
check_error(result, context="client")
|
|
976
974
|
return result
|
|
977
975
|
|
|
978
976
|
def wait_as_completion(self, timeout: int) -> int:
|
|
@@ -1017,7 +1015,10 @@ class Client:
|
|
|
1017
1015
|
Returns:
|
|
1018
1016
|
Snap7 code.
|
|
1019
1017
|
"""
|
|
1020
|
-
logger.debug(
|
|
1018
|
+
logger.debug(
|
|
1019
|
+
f"reading area: {area.name} dbnumber: {dbnumber} start: {start} amount: {size} "
|
|
1020
|
+
f"wordlen: {wordlen.name}={wordlen.value}"
|
|
1021
|
+
)
|
|
1021
1022
|
result = self._library.Cli_AsReadArea(self._pointer, area.value, dbnumber, start, size, wordlen.value, pusrdata)
|
|
1022
1023
|
check_error(result, context="client")
|
|
1023
1024
|
return result
|
|
@@ -1050,8 +1051,9 @@ class Client:
|
|
|
1050
1051
|
Snap7 code.
|
|
1051
1052
|
"""
|
|
1052
1053
|
type_ = wordlen_to_ctypes[WordLen.Byte.value]
|
|
1053
|
-
logger.debug(
|
|
1054
|
-
|
|
1054
|
+
logger.debug(
|
|
1055
|
+
f"writing area: {area.name} dbnumber: {dbnumber} start: {start}: size {size}: " f"wordlen {wordlen} type: {type_}"
|
|
1056
|
+
)
|
|
1055
1057
|
cdata = (type_ * len(pusrdata)).from_buffer_copy(pusrdata)
|
|
1056
1058
|
res = self._library.Cli_AsWriteArea(self._pointer, area.value, dbnumber, start, size, wordlen.value, byref(cdata))
|
|
1057
1059
|
check_error(res, context="client")
|
|
@@ -1238,7 +1240,7 @@ class Client:
|
|
|
1238
1240
|
Returns:
|
|
1239
1241
|
Snap7 code.
|
|
1240
1242
|
"""
|
|
1241
|
-
block_type = block_types[
|
|
1243
|
+
block_type = block_types["DB"]
|
|
1242
1244
|
result = self._library.Cli_AsUpload(self._pointer, block_type, block_num, byref(_buffer), byref(size))
|
|
1243
1245
|
check_error(result, context="client")
|
|
1244
1246
|
return result
|
|
@@ -1350,7 +1352,7 @@ class Client:
|
|
|
1350
1352
|
text = create_string_buffer(buffer_size)
|
|
1351
1353
|
response = self._library.Cli_ErrorText(error_code, byref(text), text_length)
|
|
1352
1354
|
check_error(response)
|
|
1353
|
-
result = bytearray(text)[:text_length.value].decode().strip(
|
|
1355
|
+
result = bytearray(text)[: text_length.value].decode().strip("\x00")
|
|
1354
1356
|
return result
|
|
1355
1357
|
|
|
1356
1358
|
def get_cp_info(self) -> S7CpInfo:
|
|
@@ -1437,7 +1439,7 @@ class Client:
|
|
|
1437
1439
|
cdata = (c_byte * len(data)).from_buffer_copy(data)
|
|
1438
1440
|
response = self._library.Cli_IsoExchangeBuffer(self._pointer, byref(cdata), byref(size))
|
|
1439
1441
|
check_error(response)
|
|
1440
|
-
result = bytearray(cdata)[:size.value]
|
|
1442
|
+
result = bytearray(cdata)[: size.value]
|
|
1441
1443
|
return result
|
|
1442
1444
|
|
|
1443
1445
|
def mb_read(self, start: int, size: int) -> bytearray:
|
|
@@ -1499,7 +1501,7 @@ class Client:
|
|
|
1499
1501
|
items_count = c_int(sizeof(szl_list))
|
|
1500
1502
|
response = self._library.Cli_ReadSZLList(self._pointer, byref(szl_list), byref(items_count))
|
|
1501
1503
|
check_error(response, context="client")
|
|
1502
|
-
result = bytearray(szl_list.List)[:items_count.value]
|
|
1504
|
+
result = bytearray(szl_list.List)[: items_count.value]
|
|
1503
1505
|
return result
|
|
1504
1506
|
|
|
1505
1507
|
def set_plc_system_datetime(self) -> int:
|