sgr-commhandler 0.4.dev20250512__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.
Files changed (39) hide show
  1. sgr_commhandler-0.4.dev20250512/LICENSE.md +14 -0
  2. sgr_commhandler-0.4.dev20250512/PKG-INFO +111 -0
  3. sgr_commhandler-0.4.dev20250512/README.md +84 -0
  4. sgr_commhandler-0.4.dev20250512/pyproject.toml +47 -0
  5. sgr_commhandler-0.4.dev20250512/setup.cfg +4 -0
  6. sgr_commhandler-0.4.dev20250512/setup.py +26 -0
  7. sgr_commhandler-0.4.dev20250512/src/sgr_commhandler/__init__.py +0 -0
  8. sgr_commhandler-0.4.dev20250512/src/sgr_commhandler/api/__init__.py +18 -0
  9. sgr_commhandler-0.4.dev20250512/src/sgr_commhandler/api/configuration_parameter.py +71 -0
  10. sgr_commhandler-0.4.dev20250512/src/sgr_commhandler/api/data_point_api.py +316 -0
  11. sgr_commhandler-0.4.dev20250512/src/sgr_commhandler/api/data_types.py +14 -0
  12. sgr_commhandler-0.4.dev20250512/src/sgr_commhandler/api/device_api.py +226 -0
  13. sgr_commhandler-0.4.dev20250512/src/sgr_commhandler/api/functional_profile_api.py +90 -0
  14. sgr_commhandler-0.4.dev20250512/src/sgr_commhandler/device_builder.py +337 -0
  15. sgr_commhandler-0.4.dev20250512/src/sgr_commhandler/driver/__init__.py +0 -0
  16. sgr_commhandler-0.4.dev20250512/src/sgr_commhandler/driver/contact/__init__.py +7 -0
  17. sgr_commhandler-0.4.dev20250512/src/sgr_commhandler/driver/contact/contact_interface_async.py +184 -0
  18. sgr_commhandler-0.4.dev20250512/src/sgr_commhandler/driver/generic/__init__.py +7 -0
  19. sgr_commhandler-0.4.dev20250512/src/sgr_commhandler/driver/generic/generic_interface_async.py +182 -0
  20. sgr_commhandler-0.4.dev20250512/src/sgr_commhandler/driver/messaging/__init__.py +7 -0
  21. sgr_commhandler-0.4.dev20250512/src/sgr_commhandler/driver/messaging/messaging_interface_async.py +197 -0
  22. sgr_commhandler-0.4.dev20250512/src/sgr_commhandler/driver/modbus/__init__.py +7 -0
  23. sgr_commhandler-0.4.dev20250512/src/sgr_commhandler/driver/modbus/modbus_client_async.py +403 -0
  24. sgr_commhandler-0.4.dev20250512/src/sgr_commhandler/driver/modbus/modbus_interface_async.py +516 -0
  25. sgr_commhandler-0.4.dev20250512/src/sgr_commhandler/driver/modbus/payload_decoder.py +108 -0
  26. sgr_commhandler-0.4.dev20250512/src/sgr_commhandler/driver/modbus/shared_client.py +119 -0
  27. sgr_commhandler-0.4.dev20250512/src/sgr_commhandler/driver/rest/__init__.py +7 -0
  28. sgr_commhandler-0.4.dev20250512/src/sgr_commhandler/driver/rest/authentication.py +207 -0
  29. sgr_commhandler-0.4.dev20250512/src/sgr_commhandler/driver/rest/restapi_interface_async.py +492 -0
  30. sgr_commhandler-0.4.dev20250512/src/sgr_commhandler/utils/__init__.py +1 -0
  31. sgr_commhandler-0.4.dev20250512/src/sgr_commhandler/utils/value_util.py +39 -0
  32. sgr_commhandler-0.4.dev20250512/src/sgr_commhandler/validators/__init__.py +3 -0
  33. sgr_commhandler-0.4.dev20250512/src/sgr_commhandler/validators/resolver.py +71 -0
  34. sgr_commhandler-0.4.dev20250512/src/sgr_commhandler/validators/validator.py +195 -0
  35. sgr_commhandler-0.4.dev20250512/src/sgr_commhandler.egg-info/PKG-INFO +111 -0
  36. sgr_commhandler-0.4.dev20250512/src/sgr_commhandler.egg-info/SOURCES.txt +37 -0
  37. sgr_commhandler-0.4.dev20250512/src/sgr_commhandler.egg-info/dependency_links.txt +1 -0
  38. sgr_commhandler-0.4.dev20250512/src/sgr_commhandler.egg-info/requires.txt +10 -0
  39. sgr_commhandler-0.4.dev20250512/src/sgr_commhandler.egg-info/top_level.txt +1 -0
@@ -0,0 +1,14 @@
1
+ Copyright(c) 2022 Verein SmartGridready Switzerland
2
+
3
+ This Open Source Software is BSD 3 clause licensed:
4
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
5
+ 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
6
+ 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in
7
+ the documentation and/or other materials provided with the distribution.
8
+ 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from
9
+ this software without specific prior written permission.
10
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
11
+ THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
12
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
13
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
14
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,111 @@
1
+ Metadata-Version: 2.1
2
+ Name: sgr-commhandler
3
+ Version: 0.4.dev20250512
4
+ Summary: SmartGridready CommHandler Library
5
+ Home-page: https://github.com/SmartGridready/SGrPython/commhandler#readme
6
+ Author: Robin Schoch, Matthias Krebs
7
+ Maintainer: Matthias Krebs
8
+ License: BSD-3-Clause
9
+ Project-URL: Homepage, https://www.smartgridready.ch/
10
+ Project-URL: Documentation, https://smartgridready.github.io/SGrPython/docs/commhandler/
11
+ Project-URL: Repository, https://github.com/SmartGridready/SGrPython.git
12
+ Project-URL: Issues, https://github.com/SmartGridready/SGrPython/issues
13
+ Project-URL: Changelog, https://github.com/SmartGridready/SGrPython/blob/master/commhandler/CHANGELOG.md
14
+ Requires-Python: >=3.9
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE.md
17
+ Requires-Dist: Jinja2<4.0.0,>=3.0.0
18
+ Requires-Dist: jmespath<2.0.0,>=1.0.0
19
+ Requires-Dist: pymodbus<4.0.0,>=3.0.0
20
+ Requires-Dist: setuptools<70.0.0,>=68.0.0
21
+ Requires-Dist: xsdata<23.0.0,>=22.0.0
22
+ Requires-Dist: xmlschema<4.0.0,>=3.0.0
23
+ Requires-Dist: aiohttp<4.0.0,>=3.0.0
24
+ Requires-Dist: certifi
25
+ Requires-Dist: cachetools<6.0.0,>=5.0.0
26
+ Requires-Dist: sgr-specification<3.0.0,>=2.1.0
27
+
28
+ # SmartGridready CommHandler
29
+
30
+ The _commhandler_ library provides the interfaces and drivers to access devices.
31
+
32
+
33
+ ## Contents
34
+
35
+ - [Directory Structure](#directory-structure)
36
+ - [Build Instructions](#build-instructions)
37
+
38
+
39
+ ## Directory Structure
40
+
41
+ - `pyproject.toml` is the main project configuration file.
42
+ - `setup.py` is used to build the library package using _setuptools_.
43
+ - `requirements.txt` contains the dependencies required to use the library.
44
+ - `requirements-dev.txt` contains the dependencies required to run tests.
45
+ - `src/sgr_commhandler` contains the source code of the library, with _sgr_commhandler_ being the root of the namespace.
46
+ - `tests` contains unit and integration tests.
47
+ - `examples` contains basic examples of using the library.
48
+ See [SGrPythonSamples](https://github.com/SmartGridready/SGrPythonSamples) for more detailed examples.
49
+
50
+
51
+ ## Build Instructions
52
+
53
+ ### Prerequisites
54
+
55
+ Check out the [SGrPython](https://github.com/SmartGridready/SGrPython) repository, e.g. in `SGrPython`.
56
+
57
+ Create and activate virtual environment:
58
+
59
+ ```bash
60
+ cd SGrPython
61
+ python -m venv .venv
62
+
63
+ # On Linux call this:
64
+ source ./.venv/bin/activate
65
+
66
+ # On Windows call this:
67
+ .\.venv\Scripts\Activate.ps1
68
+ ```
69
+
70
+ Make sure you have the _specification_ library `sgr-specification` installed in your virtual environment.
71
+ See [specification](../specification/README.md) for instructions.
72
+
73
+
74
+ ### Run Tests
75
+
76
+ You can run tests using `pytest` while in virtual environment.
77
+
78
+ It is not necessary to install the package locally, if you only want to run tests.
79
+
80
+ ```bash
81
+ cd SGrPython/commhandler
82
+ pip install -r requirements-dev.txt
83
+
84
+ pytest
85
+ ```
86
+
87
+
88
+ ### Build and Use Package
89
+
90
+ Build package and install in virtual environment:
91
+
92
+ ```bash
93
+ cd SGrPython/commhandler
94
+ pip install -e .
95
+ ```
96
+
97
+ You can use the package `sgr-commhandler` from within the virtual environment now.
98
+
99
+ **Note:**
100
+ The designated package name `sgr-commhandler` must not be used until the _PyPI_ administrators have
101
+ approved a SmartGridready organization account!
102
+
103
+
104
+ ### Clean Up
105
+
106
+ Deactivate the virtual environment after use:
107
+
108
+ ```bash
109
+ cd SGrPython
110
+ deactivate
111
+ ```
@@ -0,0 +1,84 @@
1
+ # SmartGridready CommHandler
2
+
3
+ The _commhandler_ library provides the interfaces and drivers to access devices.
4
+
5
+
6
+ ## Contents
7
+
8
+ - [Directory Structure](#directory-structure)
9
+ - [Build Instructions](#build-instructions)
10
+
11
+
12
+ ## Directory Structure
13
+
14
+ - `pyproject.toml` is the main project configuration file.
15
+ - `setup.py` is used to build the library package using _setuptools_.
16
+ - `requirements.txt` contains the dependencies required to use the library.
17
+ - `requirements-dev.txt` contains the dependencies required to run tests.
18
+ - `src/sgr_commhandler` contains the source code of the library, with _sgr_commhandler_ being the root of the namespace.
19
+ - `tests` contains unit and integration tests.
20
+ - `examples` contains basic examples of using the library.
21
+ See [SGrPythonSamples](https://github.com/SmartGridready/SGrPythonSamples) for more detailed examples.
22
+
23
+
24
+ ## Build Instructions
25
+
26
+ ### Prerequisites
27
+
28
+ Check out the [SGrPython](https://github.com/SmartGridready/SGrPython) repository, e.g. in `SGrPython`.
29
+
30
+ Create and activate virtual environment:
31
+
32
+ ```bash
33
+ cd SGrPython
34
+ python -m venv .venv
35
+
36
+ # On Linux call this:
37
+ source ./.venv/bin/activate
38
+
39
+ # On Windows call this:
40
+ .\.venv\Scripts\Activate.ps1
41
+ ```
42
+
43
+ Make sure you have the _specification_ library `sgr-specification` installed in your virtual environment.
44
+ See [specification](../specification/README.md) for instructions.
45
+
46
+
47
+ ### Run Tests
48
+
49
+ You can run tests using `pytest` while in virtual environment.
50
+
51
+ It is not necessary to install the package locally, if you only want to run tests.
52
+
53
+ ```bash
54
+ cd SGrPython/commhandler
55
+ pip install -r requirements-dev.txt
56
+
57
+ pytest
58
+ ```
59
+
60
+
61
+ ### Build and Use Package
62
+
63
+ Build package and install in virtual environment:
64
+
65
+ ```bash
66
+ cd SGrPython/commhandler
67
+ pip install -e .
68
+ ```
69
+
70
+ You can use the package `sgr-commhandler` from within the virtual environment now.
71
+
72
+ **Note:**
73
+ The designated package name `sgr-commhandler` must not be used until the _PyPI_ administrators have
74
+ approved a SmartGridready organization account!
75
+
76
+
77
+ ### Clean Up
78
+
79
+ Deactivate the virtual environment after use:
80
+
81
+ ```bash
82
+ cd SGrPython
83
+ deactivate
84
+ ```
@@ -0,0 +1,47 @@
1
+ [build-system]
2
+ requires = ["setuptools"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "sgr-commhandler"
7
+ dynamic = ["version"]
8
+ description = "SmartGridready CommHandler Library"
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ license = { text = "BSD-3-Clause" }
12
+ authors = [
13
+ { name = "Robin Schoch" },
14
+ { name = "Matthias Krebs" }
15
+ ]
16
+ maintainers = [
17
+ { name = "Matthias Krebs" }
18
+ ]
19
+ dependencies = [
20
+ "Jinja2>=3.0.0,<4.0.0",
21
+ "jmespath>=1.0.0,<2.0.0",
22
+ "pymodbus>=3.0.0,<4.0.0",
23
+ "setuptools>=68.0.0,<70.0.0",
24
+ "xsdata>=22.0.0,<23.0.0",
25
+ "xmlschema>=3.0.0,<4.0.0",
26
+ "aiohttp>=3.0.0,<4.0.0",
27
+ "certifi",
28
+ "cachetools>=5.0.0,<6.0.0",
29
+ "sgr-specification>=2.1.0,<3.0.0"
30
+ ]
31
+
32
+ [project.urls]
33
+ Homepage = "https://www.smartgridready.ch/"
34
+ Documentation = "https://smartgridready.github.io/SGrPython/docs/commhandler/"
35
+ Repository = "https://github.com/SmartGridready/SGrPython.git"
36
+ Issues = "https://github.com/SmartGridready/SGrPython/issues"
37
+ Changelog = "https://github.com/SmartGridready/SGrPython/blob/master/commhandler/CHANGELOG.md"
38
+
39
+ [tool.pyright]
40
+ exclude = ["**/node_modules", "**/__pycache__", "examples"]
41
+
42
+ [tool.pytest.ini_options]
43
+ pythonpath = [ "src" ]
44
+ asyncio_default_fixture_loop_scope = "session"
45
+ asyncio_mode = "strict"
46
+ log_cli = true
47
+ log_cli_level = "DEBUG"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,26 @@
1
+ from setuptools import setup, find_packages
2
+
3
+ def read_requirements() -> list[str]:
4
+ with open("./requirements.txt", "r") as file:
5
+ return file.read().splitlines()
6
+
7
+ setup(
8
+ name="sgr-commhandler",
9
+ version="0.4.dev20250512",
10
+ packages=find_packages(where="src"),
11
+ package_dir={"": "src"},
12
+ install_requires=read_requirements(),
13
+ url="https://github.com/SmartGridready/SGrPython/commhandler#readme",
14
+ project_urls={
15
+ "Issue Tracker": "https://github.com/SmartGridready/SGrPython/issues",
16
+ "Source": "https://github.com/SmartGridready/SGrPython",
17
+ "Docs": "https://smartgridready.github.io/SGrPython/docs/commhandler/"
18
+ },
19
+ license="BSD-3",
20
+ license_files=["LICENSE.md"],
21
+ author="Verein SmartGridready",
22
+ description="SGr Commhandler",
23
+ long_description="Communication Handler Library",
24
+ long_description_content_type="text/plain",
25
+ python_requires=">=3.9",
26
+ )
@@ -0,0 +1,18 @@
1
+ __all__ = [
2
+ "SGrBaseInterface",
3
+ "FunctionalProfile",
4
+ "DataPoint",
5
+ "DataPointProtocol",
6
+ "DataPointValidator",
7
+ "DeviceInformation",
8
+ "ConfigurationParameter",
9
+ ]
10
+
11
+ from sgr_commhandler.api.configuration_parameter import ConfigurationParameter
12
+ from sgr_commhandler.api.data_point_api import (
13
+ DataPoint,
14
+ DataPointProtocol,
15
+ DataPointValidator,
16
+ )
17
+ from sgr_commhandler.api.device_api import DeviceInformation, SGrBaseInterface
18
+ from sgr_commhandler.api.functional_profile_api import FunctionalProfile
@@ -0,0 +1,71 @@
1
+ from typing import Optional
2
+
3
+ from sgr_specification.v0.product import (
4
+ ConfigurationList,
5
+ ConfigurationListElement,
6
+ )
7
+
8
+
9
+ def build_configuration_parameters(params: Optional[ConfigurationList]) -> list['ConfigurationParameter']:
10
+ """
11
+ Constructs a configuration parameter list.
12
+
13
+ Parameters
14
+ ----------
15
+ params : Optional[ConfigurationList]
16
+ The configuration list of an EID
17
+
18
+ Returns
19
+ -------
20
+ list[ConfigurationParameter]
21
+ a list of configuration parameters
22
+ """
23
+ if params is None:
24
+ return []
25
+ return [
26
+ ConfigurationParameter(x) for x in params.configuration_list_element
27
+ ]
28
+
29
+
30
+ class ConfigurationParameter:
31
+ """
32
+ Implements an EID configuration parameter.
33
+ """
34
+
35
+ def __init__(self, parameter: ConfigurationListElement):
36
+ """
37
+ Constructs a configuration parameter.
38
+
39
+ Parameters
40
+ ----------
41
+ parameter : ConfigurationListElement
42
+ A configuration list element of the SGr specification
43
+ """
44
+ translation = parameter.configuration_description
45
+ self.label = translation[0].label
46
+ self.name = parameter.name
47
+ self.type = parameter.data_type
48
+ self.description = translation[0].text_element
49
+ self.default_value = parameter.default_value
50
+
51
+ def __str__(self) -> str:
52
+ """
53
+ Converts to string.
54
+
55
+ Returns
56
+ ----------
57
+ str
58
+ A string
59
+ """
60
+ return f'{self.label} - {self.name}'
61
+
62
+ def __repr__(self):
63
+ """
64
+ Gets an object description as string.
65
+
66
+ Returns
67
+ ----------
68
+ str
69
+ A string
70
+ """
71
+ return f'{self.label} - {self.name}'
@@ -0,0 +1,316 @@
1
+ from asyncio import run
2
+ from collections.abc import Callable
3
+ from typing import Any, Generic, Protocol, TypeVar
4
+
5
+ from sgr_specification.v0.generic import DataDirectionProduct, Units
6
+
7
+ from sgr_commhandler.api.data_types import DataTypes
8
+
9
+ """Defines a generic data type."""
10
+ T = TypeVar('T')
11
+
12
+
13
+ class DataPointValidator(Protocol):
14
+ """
15
+ Defines an interface for data point validators.
16
+ """
17
+
18
+ def validate(self, value: Any) -> bool:
19
+ """
20
+ Validates the compatibility of a value.
21
+
22
+ Parameters
23
+ ----------
24
+ value : Any
25
+ the value to validate
26
+
27
+ Returns
28
+ -------
29
+ bool
30
+ true if value is compatible, false otherwise
31
+ """
32
+ ...
33
+
34
+ def data_type(self) -> DataTypes:
35
+ """
36
+ Gets the validator's data type.
37
+
38
+ Returns
39
+ -------
40
+ DataTypes
41
+ the data type enumeration
42
+ """
43
+ ...
44
+
45
+ def options(self) -> list[Any]:
46
+ """
47
+ Gets the validator's options.
48
+
49
+ Returns
50
+ -------
51
+ list[Any]
52
+ the options
53
+ """
54
+ return []
55
+
56
+
57
+ class DataPointProtocol(Protocol):
58
+ """
59
+ Defines an interface for data point protocols.
60
+ """
61
+
62
+ async def set_val(self, value: Any):
63
+ """
64
+ Writes the data point value.
65
+
66
+ Parameters
67
+ ----------
68
+ value : Any
69
+ the data point value to write
70
+ """
71
+ ...
72
+
73
+ async def get_val(self, skip_cache: bool = False) -> Any:
74
+ """
75
+ Reads the data point value.
76
+
77
+ Parameters
78
+ ----------
79
+ skip_cache : bool
80
+ does not use cache if true
81
+
82
+ Returns
83
+ -------
84
+ Any
85
+ the data point value
86
+ """
87
+ ...
88
+
89
+ def name(self) -> tuple[str, str]:
90
+ """
91
+ Gets the functional profile and data point names.
92
+
93
+ Returns
94
+ -------
95
+ tuple[str, str]
96
+ the functional profile and data point names as tuple
97
+ """
98
+ ...
99
+
100
+ def direction(self) -> DataDirectionProduct:
101
+ """
102
+ Gets the data direction of the data point.
103
+
104
+ Returns
105
+ -------
106
+ DataDirectionProduct
107
+ the data point direction
108
+ """
109
+ ...
110
+
111
+ def unit(self) -> Units:
112
+ """
113
+ Gets the unit of measurement of the data point.
114
+
115
+ Returns
116
+ -------
117
+ Units
118
+ the unit
119
+ """
120
+ ...
121
+
122
+ def can_subscribe(self) -> bool:
123
+ """
124
+ Defines if subscribe() is allowed.
125
+
126
+ Returns
127
+ -------
128
+ bool
129
+ True if allowed, False otherwise
130
+ """
131
+ return False
132
+
133
+ def subscribe(self, fn: Callable[[Any], None]):
134
+ """
135
+ Subscribes to changes of the data point value.
136
+
137
+ Parameters
138
+ ----------
139
+ fn : Callable[[Any], None]
140
+ the callback method
141
+ """
142
+ raise Exception('Unsupported operation')
143
+
144
+ def unsubscribe(self):
145
+ """
146
+ Unsubscribes from changes of the data point value.
147
+ """
148
+ raise Exception('Unsupported operation')
149
+
150
+
151
+ class DataPoint(Generic[T]):
152
+ """
153
+ Implements a data point of a generic data type.
154
+ """
155
+
156
+ def __init__(
157
+ self, protocol: DataPointProtocol, validator: DataPointValidator
158
+ ):
159
+ """
160
+ Constructs a data point.
161
+
162
+ Parameters
163
+ ----------
164
+ protocol : DataPointProtocol
165
+ the underlying protocol
166
+ validator : DataPointValidator
167
+ the data point's value validator
168
+ """
169
+ self._protocol = protocol
170
+ self._validator = validator
171
+
172
+ def name(self) -> tuple[str, str]:
173
+ """
174
+ Gets the data point name.
175
+
176
+ Returns
177
+ -------
178
+ tuple[str, str]
179
+ the functional profile and data point name
180
+ """
181
+ return self._protocol.name()
182
+
183
+ async def get_value_async(self) -> T:
184
+ """
185
+ Gets the data point value asynchronously.
186
+
187
+ Returns
188
+ -------
189
+ T
190
+ the data point value
191
+
192
+ Raises
193
+ ------
194
+ Exception
195
+ when read value is not compatible with data type
196
+ """
197
+ value = await self._protocol.get_val()
198
+ if self._validator.validate(value):
199
+ return value
200
+ raise Exception(
201
+ f'invalid value read from device, {value}, validator: {self._validator.data_type()}'
202
+ )
203
+
204
+ def get_value(self) -> T:
205
+ """
206
+ Gets the data point value synchronously.
207
+
208
+ Returns
209
+ -------
210
+ T
211
+ the data point value
212
+
213
+ Raises
214
+ ------
215
+ Exception
216
+ when read value is not compatible with data type
217
+ """
218
+ return run(self.get_value_async())
219
+
220
+ async def set_value_async(self, value: T):
221
+ """
222
+ Sets the data point value asynchronously.
223
+
224
+ Parameters
225
+ ----------
226
+ value: T
227
+ the data point value
228
+ """
229
+ if self._validator.validate(value):
230
+ return await self._protocol.set_val(value)
231
+ raise Exception('invalid data to write to device')
232
+
233
+ def set_value(self, value: T):
234
+ """
235
+ Sets the data point value synchronously.
236
+
237
+ Parameters
238
+ ----------
239
+ value: T
240
+ the data point value
241
+ """
242
+ return run(self.set_value_async(value))
243
+
244
+ def subscribe(self, fn: Callable[[Any], None]):
245
+ """
246
+ Subscribes to data point value changes.
247
+
248
+ Parameters
249
+ ----------
250
+ fn : Callable[[Any], None]
251
+ the handler method
252
+ """
253
+ self._protocol.subscribe(fn)
254
+
255
+ def unsubscribe(self):
256
+ """
257
+ Unsubscribes from data point value changes.
258
+ """
259
+ self._protocol.unsubscribe()
260
+
261
+ def direction(self) -> DataDirectionProduct:
262
+ """
263
+ Gets the data point direction.
264
+
265
+ Returns
266
+ -------
267
+ DataDirectionProduct
268
+ the data point direction
269
+ """
270
+ return self._protocol.direction()
271
+
272
+ def data_type(self) -> DataTypes:
273
+ """
274
+ Gets the data point data type.
275
+
276
+ Returns
277
+ -------
278
+ DataTypes
279
+ the data point data type
280
+ """
281
+ return self._validator.data_type()
282
+
283
+ def unit(self) -> Units:
284
+ """
285
+ Gets the unit of measurement of the data point.
286
+
287
+ Returns
288
+ -------
289
+ Units
290
+ the unit
291
+ """
292
+ return self._protocol.unit()
293
+
294
+ def describe(
295
+ self,
296
+ ) -> tuple[tuple[str, str], DataDirectionProduct, DataTypes, Units]:
297
+ """
298
+ Describes the data point.
299
+
300
+ Returns
301
+ -------
302
+ tuple[tuple[str, str], DataDirectionProduct, DataTypes, Units]
303
+ the data point information
304
+ """
305
+ return self.name(), self.direction(), self.data_type(), self.unit()
306
+
307
+ def options(self) -> list[Any]:
308
+ """
309
+ Describes the data point options.
310
+
311
+ Returns
312
+ -------
313
+ list[Any]
314
+ the data point options
315
+ """
316
+ return self._validator.options()