OpenSMI-Core 0.2.1__tar.gz → 0.3__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.
- opensmi_core-0.3/PKG-INFO +84 -0
- {opensmi_core-0.2.1 → opensmi_core-0.3}/pyproject.toml +3 -1
- opensmi_core-0.3/src/OpenSMI_Core.egg-info/PKG-INFO +84 -0
- opensmi_core-0.3/src/OpenSMI_Core.egg-info/scm_version.json +8 -0
- {opensmi_core-0.2.1 → opensmi_core-0.3}/src/opensmi/core/subscription_manager.py +72 -29
- opensmi_core-0.2.1/PKG-INFO +0 -32
- opensmi_core-0.2.1/src/OpenSMI_Core.egg-info/PKG-INFO +0 -32
- opensmi_core-0.2.1/src/OpenSMI_Core.egg-info/scm_version.json +0 -8
- {opensmi_core-0.2.1 → opensmi_core-0.3}/.github/workflows/api-docs.yml +0 -0
- {opensmi_core-0.2.1 → opensmi_core-0.3}/.github/workflows/python-publish.yml +0 -0
- {opensmi_core-0.2.1 → opensmi_core-0.3}/.gitignore +0 -0
- {opensmi_core-0.2.1 → opensmi_core-0.3}/.gitlab-ci.yml +0 -0
- {opensmi_core-0.2.1 → opensmi_core-0.3}/LICENSE +0 -0
- {opensmi_core-0.2.1 → opensmi_core-0.3}/LICENSES/MIT.txt +0 -0
- {opensmi_core-0.2.1 → opensmi_core-0.3}/README.md +0 -0
- {opensmi_core-0.2.1 → opensmi_core-0.3}/setup.cfg +0 -0
- {opensmi_core-0.2.1 → opensmi_core-0.3}/src/OpenSMI_Core.egg-info/SOURCES.txt +0 -0
- {opensmi_core-0.2.1 → opensmi_core-0.3}/src/OpenSMI_Core.egg-info/dependency_links.txt +0 -0
- {opensmi_core-0.2.1 → opensmi_core-0.3}/src/OpenSMI_Core.egg-info/requires.txt +0 -0
- {opensmi_core-0.2.1 → opensmi_core-0.3}/src/OpenSMI_Core.egg-info/scm_file_list.json +0 -0
- {opensmi_core-0.2.1 → opensmi_core-0.3}/src/OpenSMI_Core.egg-info/top_level.txt +0 -0
- {opensmi_core-0.2.1 → opensmi_core-0.3}/src/opensmi/core/__init__.py +0 -0
- {opensmi_core-0.2.1 → opensmi_core-0.3}/src/opensmi/core/async_task_mixin.py +0 -0
- {opensmi_core-0.2.1 → opensmi_core-0.3}/src/opensmi/core/base_server.py +0 -0
- {opensmi_core-0.2.1 → opensmi_core-0.3}/src/opensmi/core/base_ua_object.py +0 -0
- {opensmi_core-0.2.1 → opensmi_core-0.3}/src/opensmi/core/config.py +0 -0
- {opensmi_core-0.2.1 → opensmi_core-0.3}/src/opensmi/core/enums.py +0 -0
- {opensmi_core-0.2.1 → opensmi_core-0.3}/src/opensmi/core/errors.py +0 -0
- {opensmi_core-0.2.1 → opensmi_core-0.3}/src/opensmi/core/frozen.py +0 -0
- {opensmi_core-0.2.1 → opensmi_core-0.3}/src/opensmi/core/hook.py +0 -0
- {opensmi_core-0.2.1 → opensmi_core-0.3}/src/opensmi/core/lifecycle_mixin.py +0 -0
- {opensmi_core-0.2.1 → opensmi_core-0.3}/src/opensmi/core/logging.py +0 -0
- {opensmi_core-0.2.1 → opensmi_core-0.3}/src/opensmi/core/meta.py +0 -0
- {opensmi_core-0.2.1 → opensmi_core-0.3}/src/opensmi/core/mixin_helpers.py +0 -0
- {opensmi_core-0.2.1 → opensmi_core-0.3}/src/opensmi/core/protocols.py +0 -0
- {opensmi_core-0.2.1 → opensmi_core-0.3}/src/opensmi/core/repr_mixin.py +0 -0
- {opensmi_core-0.2.1 → opensmi_core-0.3}/src/opensmi/core/signal.py +0 -0
- {opensmi_core-0.2.1 → opensmi_core-0.3}/src/opensmi/core/ua.py +0 -0
- {opensmi_core-0.2.1 → opensmi_core-0.3}/src/opensmi/core/ua_enums.py +0 -0
- {opensmi_core-0.2.1 → opensmi_core-0.3}/src/opensmi/core/ua_node_util.py +0 -0
- {opensmi_core-0.2.1 → opensmi_core-0.3}/src/opensmi/core/unit_all.py +0 -0
- {opensmi_core-0.2.1 → opensmi_core-0.3}/src/opensmi/core/unit_base.py +0 -0
- {opensmi_core-0.2.1 → opensmi_core-0.3}/src/opensmi/core/unset.py +0 -0
- {opensmi_core-0.2.1 → opensmi_core-0.3}/tests/test_signal.py +0 -0
- {opensmi_core-0.2.1 → opensmi_core-0.3}/tests/test_unit.py +0 -0
- {opensmi_core-0.2.1 → opensmi_core-0.3}/tools/auto_generate_units.py +0 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: OpenSMI-Core
|
|
3
|
+
Version: 0.3
|
|
4
|
+
Summary: Smart Machine Interface core functionality for server and client applications.
|
|
5
|
+
Author-email: Carsten Harms <Carsten.Harms@dfki.de>, Simon Jungbluth <Simon.Jungbluth@smartfactory.de>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Classifier: Development Status :: 4 - Beta
|
|
8
|
+
Classifier: Intended Audience :: Developers
|
|
9
|
+
Classifier: Intended Audience :: Information Technology
|
|
10
|
+
Classifier: Intended Audience :: Manufacturing
|
|
11
|
+
Classifier: Intended Audience :: Science/Research
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
17
|
+
Classifier: Topic :: Communications
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Interface Engine/Protocol Translator
|
|
20
|
+
Classifier: Topic :: Software Development :: Embedded Systems
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
22
|
+
Classifier: Typing :: Typed
|
|
23
|
+
Requires-Python: >=3.11
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSES/MIT.txt
|
|
26
|
+
Requires-Dist: asyncua<3,>=2.0.1
|
|
27
|
+
Requires-Dist: structlog>=26
|
|
28
|
+
Requires-Dist: typing-extensions>=4.16.0
|
|
29
|
+
Provides-Extra: rich
|
|
30
|
+
Requires-Dist: rich>=15.0.0; extra == "rich"
|
|
31
|
+
Requires-Dist: colorama>=0.4; sys_platform == "win32" and extra == "rich"
|
|
32
|
+
Provides-Extra: json
|
|
33
|
+
Requires-Dist: orjson<4,>=3; extra == "json"
|
|
34
|
+
Dynamic: license-file
|
|
35
|
+
|
|
36
|
+

|
|
37
|
+
|
|
38
|
+
[](https://smartfactory-kl.github.io/opensmi-core/)
|
|
39
|
+
[](https://pypi.org/project/opensmi-core/)
|
|
40
|
+
[](https://pypi.org/project/opensmi-core/)
|
|
41
|
+
[](LICENSE)
|
|
42
|
+
|
|
43
|
+
# OpenSMI Core
|
|
44
|
+
|
|
45
|
+
Core functionality for other OpenSMI packages such as:
|
|
46
|
+
|
|
47
|
+
- [OpenSMI Client](https://github.com/SmartFactory-KL/opensmi-client)
|
|
48
|
+
- [OpenSMI Server](https://github.com/SmartFactory-KL/opensmi-server)
|
|
49
|
+
|
|
50
|
+
## Features
|
|
51
|
+
|
|
52
|
+
- (Nested) Configuration parsing into dataclasses from TOML files (See [config.py](src/opensmi/core/config.py))
|
|
53
|
+
- Lifecycle management via mixin and `@lifecycle` decorators, allowing explicit ordering
|
|
54
|
+
(See [lifecycle_mixin.py](src/opensmi/core/lifecycle_mixin.py))
|
|
55
|
+
- Simple callbacks via `Signal` (similar to [aiosignal](https://pypi.org/project/aiosignal/), but without freezing)
|
|
56
|
+
(See [signal.py](src/opensmi/core/signal.py))
|
|
57
|
+
- [asyncua](https://pypi.org/project/asyncua/) (OPC UA) helpers
|
|
58
|
+
- Node helper functions (See [ua_node_util.py](src/opensmi/core/ua_node_util.py))
|
|
59
|
+
- SubscriptionManager (See [subscription_manager.py](src/opensmi/core/subscription_manager.py))
|
|
60
|
+
- Enums for OpenSMI machine, component and skill states
|
|
61
|
+
- All [UN/CEFACT-Rec20](https://unece.org/trade/documents/2021/06/uncefact-rec20-0) units as a type-checkable enum.
|
|
62
|
+
(See [unit_all.py](src/opensmi/core/unit_all.py))
|
|
63
|
+
- [Structured Logging](https://pypi.org/project/structlog/) configuration (See [logging.py](src/opensmi/core/logging.py))
|
|
64
|
+
|
|
65
|
+
> [!warning]
|
|
66
|
+
> This library is currently pre-1.0 — expect refactoring outside above-mentioned functionality.
|
|
67
|
+
|
|
68
|
+
## Installation
|
|
69
|
+
|
|
70
|
+
Requires Python 3.11+.
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
pip install opensmi-core
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Project Status
|
|
77
|
+
|
|
78
|
+
OpenSMI began as a closed-source project at [SmartFactory-KL](https://smartfactory.de/), in active use in our model
|
|
79
|
+
factory since 2020. Its OPC UA information model has been refined across many iterations of research and
|
|
80
|
+
demonstrator use. The framework was open-sourced in 2026 following substantial refactoring and cleanup.
|
|
81
|
+
|
|
82
|
+
## License
|
|
83
|
+
|
|
84
|
+
[MIT License](LICENSE)
|
|
@@ -5,12 +5,14 @@ build-backend = "setuptools.build_meta"
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "OpenSMI-Core"
|
|
7
7
|
dynamic = ["version"]
|
|
8
|
-
|
|
8
|
+
readme = "README.md"
|
|
9
9
|
description = "Smart Machine Interface core functionality for server and client applications."
|
|
10
10
|
authors = [
|
|
11
11
|
{ name = "Carsten Harms", email = "Carsten.Harms@dfki.de" },
|
|
12
12
|
{ name = "Simon Jungbluth", email = "Simon.Jungbluth@smartfactory.de" },
|
|
13
13
|
]
|
|
14
|
+
license = "MIT"
|
|
15
|
+
license-files = ["LICENSES/MIT.txt"]
|
|
14
16
|
|
|
15
17
|
# see https://pypi.org/classifiers/
|
|
16
18
|
classifiers = [
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: OpenSMI-Core
|
|
3
|
+
Version: 0.3
|
|
4
|
+
Summary: Smart Machine Interface core functionality for server and client applications.
|
|
5
|
+
Author-email: Carsten Harms <Carsten.Harms@dfki.de>, Simon Jungbluth <Simon.Jungbluth@smartfactory.de>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Classifier: Development Status :: 4 - Beta
|
|
8
|
+
Classifier: Intended Audience :: Developers
|
|
9
|
+
Classifier: Intended Audience :: Information Technology
|
|
10
|
+
Classifier: Intended Audience :: Manufacturing
|
|
11
|
+
Classifier: Intended Audience :: Science/Research
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
17
|
+
Classifier: Topic :: Communications
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Interface Engine/Protocol Translator
|
|
20
|
+
Classifier: Topic :: Software Development :: Embedded Systems
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
22
|
+
Classifier: Typing :: Typed
|
|
23
|
+
Requires-Python: >=3.11
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSES/MIT.txt
|
|
26
|
+
Requires-Dist: asyncua<3,>=2.0.1
|
|
27
|
+
Requires-Dist: structlog>=26
|
|
28
|
+
Requires-Dist: typing-extensions>=4.16.0
|
|
29
|
+
Provides-Extra: rich
|
|
30
|
+
Requires-Dist: rich>=15.0.0; extra == "rich"
|
|
31
|
+
Requires-Dist: colorama>=0.4; sys_platform == "win32" and extra == "rich"
|
|
32
|
+
Provides-Extra: json
|
|
33
|
+
Requires-Dist: orjson<4,>=3; extra == "json"
|
|
34
|
+
Dynamic: license-file
|
|
35
|
+
|
|
36
|
+

|
|
37
|
+
|
|
38
|
+
[](https://smartfactory-kl.github.io/opensmi-core/)
|
|
39
|
+
[](https://pypi.org/project/opensmi-core/)
|
|
40
|
+
[](https://pypi.org/project/opensmi-core/)
|
|
41
|
+
[](LICENSE)
|
|
42
|
+
|
|
43
|
+
# OpenSMI Core
|
|
44
|
+
|
|
45
|
+
Core functionality for other OpenSMI packages such as:
|
|
46
|
+
|
|
47
|
+
- [OpenSMI Client](https://github.com/SmartFactory-KL/opensmi-client)
|
|
48
|
+
- [OpenSMI Server](https://github.com/SmartFactory-KL/opensmi-server)
|
|
49
|
+
|
|
50
|
+
## Features
|
|
51
|
+
|
|
52
|
+
- (Nested) Configuration parsing into dataclasses from TOML files (See [config.py](src/opensmi/core/config.py))
|
|
53
|
+
- Lifecycle management via mixin and `@lifecycle` decorators, allowing explicit ordering
|
|
54
|
+
(See [lifecycle_mixin.py](src/opensmi/core/lifecycle_mixin.py))
|
|
55
|
+
- Simple callbacks via `Signal` (similar to [aiosignal](https://pypi.org/project/aiosignal/), but without freezing)
|
|
56
|
+
(See [signal.py](src/opensmi/core/signal.py))
|
|
57
|
+
- [asyncua](https://pypi.org/project/asyncua/) (OPC UA) helpers
|
|
58
|
+
- Node helper functions (See [ua_node_util.py](src/opensmi/core/ua_node_util.py))
|
|
59
|
+
- SubscriptionManager (See [subscription_manager.py](src/opensmi/core/subscription_manager.py))
|
|
60
|
+
- Enums for OpenSMI machine, component and skill states
|
|
61
|
+
- All [UN/CEFACT-Rec20](https://unece.org/trade/documents/2021/06/uncefact-rec20-0) units as a type-checkable enum.
|
|
62
|
+
(See [unit_all.py](src/opensmi/core/unit_all.py))
|
|
63
|
+
- [Structured Logging](https://pypi.org/project/structlog/) configuration (See [logging.py](src/opensmi/core/logging.py))
|
|
64
|
+
|
|
65
|
+
> [!warning]
|
|
66
|
+
> This library is currently pre-1.0 — expect refactoring outside above-mentioned functionality.
|
|
67
|
+
|
|
68
|
+
## Installation
|
|
69
|
+
|
|
70
|
+
Requires Python 3.11+.
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
pip install opensmi-core
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Project Status
|
|
77
|
+
|
|
78
|
+
OpenSMI began as a closed-source project at [SmartFactory-KL](https://smartfactory.de/), in active use in our model
|
|
79
|
+
factory since 2020. Its OPC UA information model has been refined across many iterations of research and
|
|
80
|
+
demonstrator use. The framework was open-sourced in 2026 following substantial refactoring and cleanup.
|
|
81
|
+
|
|
82
|
+
## License
|
|
83
|
+
|
|
84
|
+
[MIT License](LICENSE)
|
|
@@ -4,10 +4,13 @@
|
|
|
4
4
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
7
|
+
import asyncio
|
|
7
8
|
import contextlib
|
|
9
|
+
import time
|
|
8
10
|
from abc import ABC, abstractmethod
|
|
11
|
+
from asyncio import Task
|
|
9
12
|
from collections.abc import Iterable
|
|
10
|
-
from typing import Any
|
|
13
|
+
from typing import Any, Never
|
|
11
14
|
|
|
12
15
|
import structlog
|
|
13
16
|
from asyncua import ua
|
|
@@ -46,49 +49,74 @@ class SubscriptionManager:
|
|
|
46
49
|
_ua_client: Client
|
|
47
50
|
_ua_subscription: Subscription
|
|
48
51
|
|
|
49
|
-
def __init__(
|
|
50
|
-
|
|
52
|
+
def __init__(
|
|
53
|
+
self,
|
|
54
|
+
*,
|
|
55
|
+
ua_client: Client,
|
|
56
|
+
publishing_interval_ms: float = 100,
|
|
57
|
+
heartbeat_stale_after: float = 10.0,
|
|
58
|
+
) -> None:
|
|
59
|
+
"""Create a new instance.
|
|
60
|
+
|
|
61
|
+
:param ua_client: OPC UA client to use.
|
|
62
|
+
:param publishing_interval_ms: Publishing interval in milliseconds for OPC UA subscription
|
|
63
|
+
:param heartbeat_stale_after: Time in seconds until any subscription should be received.
|
|
64
|
+
"""
|
|
65
|
+
self._publishing_interval_ms = publishing_interval_ms
|
|
66
|
+
self._ua_client = ua_client
|
|
67
|
+
|
|
51
68
|
self._data_subscription_map: dict[NodeId, list[UaDataChangeSubscriber]] = {}
|
|
52
69
|
""" Maps a OPC UA node to a list of handlers for data change notifications. """
|
|
53
70
|
self._event_subscription_map: dict[NodeId, list[UaEventSubscriber]] = {}
|
|
54
71
|
""" Maps a OPC UA node to a list of handlers for event notifications. """
|
|
55
72
|
|
|
56
|
-
self.
|
|
57
|
-
|
|
73
|
+
self._heartbeat_task: Task[Never] | None = None
|
|
74
|
+
self._last_heartbeat = time.monotonic()
|
|
75
|
+
self._heartbeat_stale_after = heartbeat_stale_after
|
|
58
76
|
|
|
59
77
|
self.logger = structlog.getLogger("opensmi.SubscriptionManager")
|
|
60
78
|
|
|
61
|
-
async def _create_subscription(self
|
|
62
|
-
self._ua_subscription = await
|
|
79
|
+
async def _create_subscription(self) -> None:
|
|
80
|
+
self._ua_subscription = await self._ua_client.create_subscription(
|
|
81
|
+
period=self._publishing_interval_ms, handler=self
|
|
82
|
+
)
|
|
63
83
|
self.logger.info("Created subscription!", parameters=self._ua_subscription.parameters)
|
|
64
84
|
|
|
65
|
-
async def init(self
|
|
66
|
-
self.
|
|
67
|
-
self._ua_client = ua_client
|
|
68
|
-
await self._create_subscription(ua_client)
|
|
85
|
+
async def init(self) -> None:
|
|
86
|
+
await self._create_subscription()
|
|
69
87
|
|
|
70
88
|
# subscribe to a node that always changes reliably, for example the current time of the server
|
|
71
89
|
# this is done to prevent the subscription from timing out
|
|
72
|
-
current_time_node =
|
|
90
|
+
current_time_node = self._ua_client.get_node(ua.object_ids.ObjectIds.Server_ServerStatus_CurrentTime)
|
|
73
91
|
await self.subscribe_data_change(self, current_time_node) # pyright: ignore[reportArgumentType]
|
|
74
92
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
93
|
+
self._last_heartbeat = time.monotonic()
|
|
94
|
+
self._heartbeat_task = asyncio.create_task(self._heartbeat_loop(), name="heartbeat_task")
|
|
95
|
+
|
|
96
|
+
async def _renew_subscriptions(self) -> None:
|
|
97
|
+
self.logger.info(f"Trying to renew {self.no_of_monitored_items} subscriptions...")
|
|
98
|
+
old_data_subscription_map = self._data_subscription_map.copy()
|
|
99
|
+
old_event_subscription_map = self._event_subscription_map.copy()
|
|
100
|
+
|
|
101
|
+
await self.clear_subscriptions()
|
|
102
|
+
while True:
|
|
103
|
+
try:
|
|
104
|
+
await self._create_subscription()
|
|
105
|
+
# add all old data change subscriptions back
|
|
106
|
+
for node_id, handlers in old_data_subscription_map.items():
|
|
107
|
+
for handler in handlers:
|
|
108
|
+
await self.subscribe_data_change(handler=handler, nodes=[self._ua_client.get_node(node_id)])
|
|
109
|
+
|
|
110
|
+
# add all old event subscriptions back
|
|
111
|
+
for node_id, handlers in old_event_subscription_map.items():
|
|
112
|
+
for handler in handlers:
|
|
113
|
+
await self.subscribe_event(handler=handler, source_node=node_id)
|
|
114
|
+
|
|
115
|
+
self.logger.info("Successfully renewed subscriptions")
|
|
116
|
+
break
|
|
117
|
+
except Exception as err:
|
|
118
|
+
self.logger.warning("Could not renew subscriptions!", reason=err)
|
|
119
|
+
await asyncio.sleep(1)
|
|
92
120
|
|
|
93
121
|
async def clear_subscriptions(self) -> None:
|
|
94
122
|
self.logger.info(f"Clearing {self.no_of_monitored_items} subscriptions...")
|
|
@@ -160,11 +188,24 @@ class SubscriptionManager:
|
|
|
160
188
|
await self._ua_subscription.subscribe_events(sourcenode=source_node)
|
|
161
189
|
self._event_subscription_map[node_id].append(handler)
|
|
162
190
|
|
|
191
|
+
async def _heartbeat_loop(self) -> Never:
|
|
192
|
+
while True:
|
|
193
|
+
await asyncio.sleep(self._heartbeat_stale_after / 4)
|
|
194
|
+
try:
|
|
195
|
+
stale_for = time.monotonic() - self._last_heartbeat
|
|
196
|
+
if stale_for > self._heartbeat_stale_after:
|
|
197
|
+
self.logger.warning("Heartbeat stale, subscriptions presumed dead", stale_for=stale_for)
|
|
198
|
+
await self._renew_subscriptions()
|
|
199
|
+
except Exception as err:
|
|
200
|
+
self.logger.warning("Heartbeat check failed", reason=err)
|
|
201
|
+
|
|
163
202
|
###########################################
|
|
164
203
|
# asyncua callbacks
|
|
165
204
|
|
|
166
205
|
async def datachange_notification(self, node: Node, val: Any, data: DataChangeNotif) -> None:
|
|
167
206
|
"""Handle OPC UA data change notifications callback."""
|
|
207
|
+
self._last_heartbeat = time.monotonic()
|
|
208
|
+
|
|
168
209
|
try:
|
|
169
210
|
for handler in self._data_subscription_map[node.nodeid]: # list of handlers
|
|
170
211
|
if handler == self:
|
|
@@ -181,6 +222,8 @@ class SubscriptionManager:
|
|
|
181
222
|
|
|
182
223
|
async def event_notification(self, ua_event: UaEvent) -> None:
|
|
183
224
|
"""Handle OPC UA event notifications callback."""
|
|
225
|
+
self._last_heartbeat = time.monotonic()
|
|
226
|
+
|
|
184
227
|
# TODO(CaHa): ua_event.emitting_node is always i=2253 (=Server)
|
|
185
228
|
# might be an asyncua problem
|
|
186
229
|
try:
|
opensmi_core-0.2.1/PKG-INFO
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: OpenSMI-Core
|
|
3
|
-
Version: 0.2.1
|
|
4
|
-
Summary: Smart Machine Interface core functionality for server and client applications.
|
|
5
|
-
Author-email: Carsten Harms <Carsten.Harms@dfki.de>, Simon Jungbluth <Simon.Jungbluth@smartfactory.de>
|
|
6
|
-
Classifier: Development Status :: 4 - Beta
|
|
7
|
-
Classifier: Intended Audience :: Developers
|
|
8
|
-
Classifier: Intended Audience :: Information Technology
|
|
9
|
-
Classifier: Intended Audience :: Manufacturing
|
|
10
|
-
Classifier: Intended Audience :: Science/Research
|
|
11
|
-
Classifier: Programming Language :: Python :: 3
|
|
12
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.14
|
|
16
|
-
Classifier: Topic :: Communications
|
|
17
|
-
Classifier: Topic :: Scientific/Engineering
|
|
18
|
-
Classifier: Topic :: Scientific/Engineering :: Interface Engine/Protocol Translator
|
|
19
|
-
Classifier: Topic :: Software Development :: Embedded Systems
|
|
20
|
-
Classifier: Topic :: Software Development :: Libraries
|
|
21
|
-
Classifier: Typing :: Typed
|
|
22
|
-
Requires-Python: >=3.11
|
|
23
|
-
License-File: LICENSE
|
|
24
|
-
Requires-Dist: asyncua<3,>=2.0.1
|
|
25
|
-
Requires-Dist: structlog>=26
|
|
26
|
-
Requires-Dist: typing-extensions>=4.16.0
|
|
27
|
-
Provides-Extra: rich
|
|
28
|
-
Requires-Dist: rich>=15.0.0; extra == "rich"
|
|
29
|
-
Requires-Dist: colorama>=0.4; sys_platform == "win32" and extra == "rich"
|
|
30
|
-
Provides-Extra: json
|
|
31
|
-
Requires-Dist: orjson<4,>=3; extra == "json"
|
|
32
|
-
Dynamic: license-file
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: OpenSMI-Core
|
|
3
|
-
Version: 0.2.1
|
|
4
|
-
Summary: Smart Machine Interface core functionality for server and client applications.
|
|
5
|
-
Author-email: Carsten Harms <Carsten.Harms@dfki.de>, Simon Jungbluth <Simon.Jungbluth@smartfactory.de>
|
|
6
|
-
Classifier: Development Status :: 4 - Beta
|
|
7
|
-
Classifier: Intended Audience :: Developers
|
|
8
|
-
Classifier: Intended Audience :: Information Technology
|
|
9
|
-
Classifier: Intended Audience :: Manufacturing
|
|
10
|
-
Classifier: Intended Audience :: Science/Research
|
|
11
|
-
Classifier: Programming Language :: Python :: 3
|
|
12
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.14
|
|
16
|
-
Classifier: Topic :: Communications
|
|
17
|
-
Classifier: Topic :: Scientific/Engineering
|
|
18
|
-
Classifier: Topic :: Scientific/Engineering :: Interface Engine/Protocol Translator
|
|
19
|
-
Classifier: Topic :: Software Development :: Embedded Systems
|
|
20
|
-
Classifier: Topic :: Software Development :: Libraries
|
|
21
|
-
Classifier: Typing :: Typed
|
|
22
|
-
Requires-Python: >=3.11
|
|
23
|
-
License-File: LICENSE
|
|
24
|
-
Requires-Dist: asyncua<3,>=2.0.1
|
|
25
|
-
Requires-Dist: structlog>=26
|
|
26
|
-
Requires-Dist: typing-extensions>=4.16.0
|
|
27
|
-
Provides-Extra: rich
|
|
28
|
-
Requires-Dist: rich>=15.0.0; extra == "rich"
|
|
29
|
-
Requires-Dist: colorama>=0.4; sys_platform == "win32" and extra == "rich"
|
|
30
|
-
Provides-Extra: json
|
|
31
|
-
Requires-Dist: orjson<4,>=3; extra == "json"
|
|
32
|
-
Dynamic: license-file
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|