conson-xp 1.34.0__py3-none-any.whl → 1.36.0__py3-none-any.whl
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.
- {conson_xp-1.34.0.dist-info → conson_xp-1.36.0.dist-info}/METADATA +1 -1
- {conson_xp-1.34.0.dist-info → conson_xp-1.36.0.dist-info}/RECORD +31 -31
- xp/__init__.py +1 -1
- xp/cli/commands/conbus/conbus_actiontable_commands.py +34 -35
- xp/cli/commands/conbus/conbus_autoreport_commands.py +11 -10
- xp/cli/commands/conbus/conbus_custom_commands.py +6 -4
- xp/cli/commands/conbus/conbus_datapoint_commands.py +8 -6
- xp/cli/commands/conbus/conbus_lightlevel_commands.py +19 -16
- xp/cli/commands/conbus/conbus_linknumber_commands.py +7 -6
- xp/cli/commands/conbus/conbus_modulenumber_commands.py +7 -6
- xp/cli/commands/conbus/conbus_msactiontable_commands.py +7 -9
- xp/cli/commands/conbus/conbus_output_commands.py +9 -7
- xp/cli/commands/conbus/conbus_raw_commands.py +7 -2
- xp/cli/commands/conbus/conbus_scan_commands.py +4 -2
- xp/services/conbus/actiontable/actiontable_download_service.py +79 -37
- xp/services/conbus/actiontable/actiontable_list_service.py +17 -17
- xp/services/conbus/actiontable/actiontable_upload_service.py +78 -36
- xp/services/conbus/actiontable/msactiontable_service.py +88 -48
- xp/services/conbus/conbus_custom_service.py +81 -26
- xp/services/conbus/conbus_datapoint_queryall_service.py +90 -43
- xp/services/conbus/conbus_datapoint_service.py +76 -28
- xp/services/conbus/conbus_output_service.py +82 -22
- xp/services/conbus/conbus_raw_service.py +78 -37
- xp/services/conbus/conbus_scan_service.py +86 -42
- xp/services/conbus/write_config_service.py +76 -26
- xp/services/term/state_monitor_service.py +35 -15
- xp/term/widgets/modules_list.py +4 -2
- xp/utils/dependencies.py +10 -20
- {conson_xp-1.34.0.dist-info → conson_xp-1.36.0.dist-info}/WHEEL +0 -0
- {conson_xp-1.34.0.dist-info → conson_xp-1.36.0.dist-info}/entry_points.txt +0 -0
- {conson_xp-1.34.0.dist-info → conson_xp-1.36.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
"""Service for downloading XP24 action tables via Conbus protocol."""
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
|
-
from typing import
|
|
4
|
+
from typing import Any, Optional, Union
|
|
5
5
|
|
|
6
|
-
from
|
|
6
|
+
from psygnal import Signal
|
|
7
7
|
|
|
8
|
-
from xp.models import ConbusClientConfig
|
|
9
8
|
from xp.models.actiontable.msactiontable_xp20 import Xp20MsActionTable
|
|
10
9
|
from xp.models.actiontable.msactiontable_xp24 import Xp24MsActionTable
|
|
11
10
|
from xp.models.actiontable.msactiontable_xp33 import Xp33MsActionTable
|
|
@@ -21,7 +20,7 @@ from xp.services.actiontable.msactiontable_xp24_serializer import (
|
|
|
21
20
|
from xp.services.actiontable.msactiontable_xp33_serializer import (
|
|
22
21
|
Xp33MsActionTableSerializer,
|
|
23
22
|
)
|
|
24
|
-
from xp.services.protocol import
|
|
23
|
+
from xp.services.protocol.conbus_event_protocol import ConbusEventProtocol
|
|
25
24
|
from xp.services.telegram.telegram_service import TelegramService
|
|
26
25
|
|
|
27
26
|
|
|
@@ -31,34 +30,42 @@ class MsActionTableError(Exception):
|
|
|
31
30
|
pass
|
|
32
31
|
|
|
33
32
|
|
|
34
|
-
class MsActionTableService
|
|
33
|
+
class MsActionTableService:
|
|
35
34
|
"""
|
|
36
|
-
|
|
35
|
+
Service for downloading MS action tables via Conbus protocol.
|
|
37
36
|
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
Uses ConbusEventProtocol to download action tables from XP20, XP24, or XP33 modules.
|
|
38
|
+
Emits signals for progress updates, errors, and completion.
|
|
39
|
+
|
|
40
|
+
Attributes:
|
|
41
|
+
conbus_protocol: Protocol instance for Conbus communication.
|
|
42
|
+
on_progress: Signal emitted for progress updates (str).
|
|
43
|
+
on_error: Signal emitted for errors (str).
|
|
44
|
+
on_finish: Signal emitted when download completes (MsActionTable or None).
|
|
40
45
|
"""
|
|
41
46
|
|
|
47
|
+
on_progress: Signal = Signal(str)
|
|
48
|
+
on_error: Signal = Signal(str)
|
|
49
|
+
on_finish: Signal = Signal(object) # Union type for Xp20/24/33 or None
|
|
50
|
+
|
|
42
51
|
def __init__(
|
|
43
52
|
self,
|
|
44
|
-
|
|
45
|
-
reactor: PosixReactorBase,
|
|
53
|
+
conbus_protocol: ConbusEventProtocol,
|
|
46
54
|
xp20ms_serializer: Xp20MsActionTableSerializer,
|
|
47
55
|
xp24ms_serializer: Xp24MsActionTableSerializer,
|
|
48
56
|
xp33ms_serializer: Xp33MsActionTableSerializer,
|
|
49
57
|
telegram_service: TelegramService,
|
|
50
58
|
) -> None:
|
|
51
|
-
"""Initialize the
|
|
59
|
+
"""Initialize the MS action table service.
|
|
52
60
|
|
|
53
61
|
Args:
|
|
54
|
-
|
|
55
|
-
reactor: Twisted reactor instance.
|
|
62
|
+
conbus_protocol: ConbusEventProtocol instance.
|
|
56
63
|
xp20ms_serializer: XP20 MS action table serializer.
|
|
57
64
|
xp24ms_serializer: XP24 MS action table serializer.
|
|
58
65
|
xp33ms_serializer: XP33 MS action table serializer.
|
|
59
66
|
telegram_service: Telegram service for parsing.
|
|
60
67
|
"""
|
|
61
|
-
|
|
68
|
+
self.conbus_protocol = conbus_protocol
|
|
62
69
|
self.xp20ms_serializer = xp20ms_serializer
|
|
63
70
|
self.xp24ms_serializer = xp24ms_serializer
|
|
64
71
|
self.xp33ms_serializer = xp33ms_serializer
|
|
@@ -70,24 +77,23 @@ class MsActionTableService(ConbusProtocol):
|
|
|
70
77
|
self.telegram_service = telegram_service
|
|
71
78
|
self.serial_number: str = ""
|
|
72
79
|
self.xpmoduletype: str = ""
|
|
73
|
-
self.progress_callback: Optional[Callable[[str], None]] = None
|
|
74
|
-
self.error_callback: Optional[Callable[[str], None]] = None
|
|
75
|
-
self.finish_callback: Optional[
|
|
76
|
-
Callable[
|
|
77
|
-
[Union[Xp20MsActionTable, Xp24MsActionTable, Xp33MsActionTable, None]],
|
|
78
|
-
None,
|
|
79
|
-
]
|
|
80
|
-
] = None
|
|
81
80
|
self.msactiontable_data: list[str] = []
|
|
82
81
|
# Set up logging
|
|
83
82
|
self.logger = logging.getLogger(__name__)
|
|
84
83
|
|
|
85
|
-
|
|
86
|
-
|
|
84
|
+
# Connect protocol signals
|
|
85
|
+
self.conbus_protocol.on_connection_made.connect(self.connection_made)
|
|
86
|
+
self.conbus_protocol.on_telegram_sent.connect(self.telegram_sent)
|
|
87
|
+
self.conbus_protocol.on_telegram_received.connect(self.telegram_received)
|
|
88
|
+
self.conbus_protocol.on_timeout.connect(self.timeout)
|
|
89
|
+
self.conbus_protocol.on_failed.connect(self.failed)
|
|
90
|
+
|
|
91
|
+
def connection_made(self) -> None:
|
|
92
|
+
"""Handle connection made event."""
|
|
87
93
|
self.logger.debug(
|
|
88
94
|
"Connection established, sending download msactiontable telegram"
|
|
89
95
|
)
|
|
90
|
-
self.send_telegram(
|
|
96
|
+
self.conbus_protocol.send_telegram(
|
|
91
97
|
telegram_type=TelegramType.SYSTEM,
|
|
92
98
|
serial_number=self.serial_number,
|
|
93
99
|
system_function=SystemFunction.DOWNLOAD_MSACTIONTABLE,
|
|
@@ -143,10 +149,9 @@ class MsActionTableService(ConbusProtocol):
|
|
|
143
149
|
self.msactiontable_data.extend(
|
|
144
150
|
(reply_telegram.data, reply_telegram.data_value)
|
|
145
151
|
)
|
|
146
|
-
|
|
147
|
-
self.progress_callback(".")
|
|
152
|
+
self.on_progress.emit(".")
|
|
148
153
|
|
|
149
|
-
self.send_telegram(
|
|
154
|
+
self.conbus_protocol.send_telegram(
|
|
150
155
|
telegram_type=TelegramType.SYSTEM,
|
|
151
156
|
serial_number=self.serial_number,
|
|
152
157
|
system_function=SystemFunction.ACK,
|
|
@@ -164,6 +169,11 @@ class MsActionTableService(ConbusProtocol):
|
|
|
164
169
|
|
|
165
170
|
self.logger.debug("Invalid msactiontable response")
|
|
166
171
|
|
|
172
|
+
def timeout(self) -> None:
|
|
173
|
+
"""Handle timeout event."""
|
|
174
|
+
self.logger.debug("Timeout occurred")
|
|
175
|
+
self.failed("Timeout")
|
|
176
|
+
|
|
167
177
|
def failed(self, message: str) -> None:
|
|
168
178
|
"""Handle failed connection event.
|
|
169
179
|
|
|
@@ -171,9 +181,8 @@ class MsActionTableService(ConbusProtocol):
|
|
|
171
181
|
message: Failure message.
|
|
172
182
|
"""
|
|
173
183
|
self.logger.debug(f"Failed: {message}")
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
self._stop_reactor()
|
|
184
|
+
self.on_error.emit(message)
|
|
185
|
+
self.on_finish.emit(None)
|
|
177
186
|
|
|
178
187
|
def succeed(
|
|
179
188
|
self,
|
|
@@ -184,29 +193,19 @@ class MsActionTableService(ConbusProtocol):
|
|
|
184
193
|
Args:
|
|
185
194
|
msactiontable: result.
|
|
186
195
|
"""
|
|
187
|
-
|
|
188
|
-
self.finish_callback(msactiontable)
|
|
189
|
-
self._stop_reactor()
|
|
196
|
+
self.on_finish.emit(msactiontable)
|
|
190
197
|
|
|
191
198
|
def start(
|
|
192
199
|
self,
|
|
193
200
|
serial_number: str,
|
|
194
201
|
xpmoduletype: str,
|
|
195
|
-
progress_callback: Callable[[str], None],
|
|
196
|
-
error_callback: Callable[[str], None],
|
|
197
|
-
finish_callback: Callable[
|
|
198
|
-
[Union[Xp20MsActionTable, Xp24MsActionTable, Xp33MsActionTable, None]], None
|
|
199
|
-
],
|
|
200
202
|
timeout_seconds: Optional[float] = None,
|
|
201
203
|
) -> None:
|
|
202
|
-
"""
|
|
204
|
+
"""Setup download parameters.
|
|
203
205
|
|
|
204
206
|
Args:
|
|
205
207
|
serial_number: Module serial number.
|
|
206
208
|
xpmoduletype: XP module type (xp20, xp24, xp33).
|
|
207
|
-
progress_callback: Callback for progress updates.
|
|
208
|
-
error_callback: Callback for errors.
|
|
209
|
-
finish_callback: Callback when download completes.
|
|
210
209
|
timeout_seconds: Optional timeout in seconds.
|
|
211
210
|
|
|
212
211
|
Raises:
|
|
@@ -225,8 +224,49 @@ class MsActionTableService(ConbusProtocol):
|
|
|
225
224
|
raise MsActionTableError(f"Unsupported module type: {xpmoduletype}")
|
|
226
225
|
|
|
227
226
|
if timeout_seconds:
|
|
228
|
-
self.timeout_seconds = timeout_seconds
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
227
|
+
self.conbus_protocol.timeout_seconds = timeout_seconds
|
|
228
|
+
|
|
229
|
+
def set_timeout(self, timeout_seconds: float) -> None:
|
|
230
|
+
"""Set operation timeout.
|
|
231
|
+
|
|
232
|
+
Args:
|
|
233
|
+
timeout_seconds: Timeout in seconds.
|
|
234
|
+
"""
|
|
235
|
+
self.conbus_protocol.timeout_seconds = timeout_seconds
|
|
236
|
+
|
|
237
|
+
def start_reactor(self) -> None:
|
|
238
|
+
"""Start the reactor."""
|
|
239
|
+
self.conbus_protocol.start_reactor()
|
|
240
|
+
|
|
241
|
+
def stop_reactor(self) -> None:
|
|
242
|
+
"""Stop the reactor."""
|
|
243
|
+
self.conbus_protocol.stop_reactor()
|
|
244
|
+
|
|
245
|
+
def __enter__(self) -> "MsActionTableService":
|
|
246
|
+
"""Enter context manager.
|
|
247
|
+
|
|
248
|
+
Returns:
|
|
249
|
+
Self for context manager protocol.
|
|
250
|
+
"""
|
|
251
|
+
# Reset state for singleton reuse
|
|
252
|
+
self.msactiontable_data = []
|
|
253
|
+
self.serial_number = ""
|
|
254
|
+
self.xpmoduletype = ""
|
|
255
|
+
return self
|
|
256
|
+
|
|
257
|
+
def __exit__(
|
|
258
|
+
self, _exc_type: Optional[type], _exc_val: Optional[Exception], _exc_tb: Any
|
|
259
|
+
) -> None:
|
|
260
|
+
"""Exit context manager and disconnect signals."""
|
|
261
|
+
# Disconnect protocol signals
|
|
262
|
+
self.conbus_protocol.on_connection_made.disconnect(self.connection_made)
|
|
263
|
+
self.conbus_protocol.on_telegram_sent.disconnect(self.telegram_sent)
|
|
264
|
+
self.conbus_protocol.on_telegram_received.disconnect(self.telegram_received)
|
|
265
|
+
self.conbus_protocol.on_timeout.disconnect(self.timeout)
|
|
266
|
+
self.conbus_protocol.on_failed.disconnect(self.failed)
|
|
267
|
+
# Disconnect service signals
|
|
268
|
+
self.on_progress.disconnect()
|
|
269
|
+
self.on_error.disconnect()
|
|
270
|
+
self.on_finish.disconnect()
|
|
271
|
+
# Stop reactor
|
|
272
|
+
self.stop_reactor()
|
|
@@ -5,47 +5,49 @@ This service handles custom telegram operations for modules through Conbus teleg
|
|
|
5
5
|
|
|
6
6
|
import logging
|
|
7
7
|
from datetime import datetime
|
|
8
|
-
from typing import
|
|
8
|
+
from typing import Any, Optional
|
|
9
9
|
|
|
10
|
-
from
|
|
10
|
+
from psygnal import Signal
|
|
11
11
|
|
|
12
|
-
from xp.models import ConbusClientConfig
|
|
13
12
|
from xp.models.conbus.conbus_custom import ConbusCustomResponse
|
|
14
13
|
from xp.models.protocol.conbus_protocol import TelegramReceivedEvent
|
|
15
14
|
from xp.models.telegram.reply_telegram import ReplyTelegram
|
|
16
15
|
from xp.models.telegram.system_function import SystemFunction
|
|
17
16
|
from xp.models.telegram.telegram_type import TelegramType
|
|
18
|
-
from xp.services.protocol import
|
|
17
|
+
from xp.services.protocol.conbus_event_protocol import ConbusEventProtocol
|
|
19
18
|
from xp.services.telegram.telegram_service import TelegramService
|
|
20
19
|
|
|
21
20
|
|
|
22
|
-
class ConbusCustomService
|
|
23
|
-
"""
|
|
24
|
-
Service for sending custom telegrams to Conbus modules.
|
|
21
|
+
class ConbusCustomService:
|
|
22
|
+
"""Service for sending custom telegrams to Conbus modules.
|
|
25
23
|
|
|
26
|
-
Uses
|
|
24
|
+
Uses ConbusEventProtocol to provide custom telegram functionality
|
|
27
25
|
for sending arbitrary function codes and data to modules.
|
|
26
|
+
|
|
27
|
+
Attributes:
|
|
28
|
+
conbus_protocol: Protocol instance for Conbus communication.
|
|
29
|
+
telegram_service: Service for parsing telegrams.
|
|
30
|
+
on_finish: Signal emitted when custom operation completes (with response).
|
|
28
31
|
"""
|
|
29
32
|
|
|
33
|
+
on_finish: Signal = Signal(ConbusCustomResponse)
|
|
34
|
+
|
|
30
35
|
def __init__(
|
|
31
36
|
self,
|
|
37
|
+
conbus_protocol: ConbusEventProtocol,
|
|
32
38
|
telegram_service: TelegramService,
|
|
33
|
-
cli_config: ConbusClientConfig,
|
|
34
|
-
reactor: PosixReactorBase,
|
|
35
39
|
) -> None:
|
|
36
40
|
"""Initialize the Conbus custom service.
|
|
37
41
|
|
|
38
42
|
Args:
|
|
43
|
+
conbus_protocol: Protocol instance for Conbus communication.
|
|
39
44
|
telegram_service: Service for parsing telegrams.
|
|
40
|
-
cli_config: Configuration for Conbus client connection.
|
|
41
|
-
reactor: Twisted reactor for event loop.
|
|
42
45
|
"""
|
|
43
|
-
|
|
46
|
+
self.conbus_protocol = conbus_protocol
|
|
44
47
|
self.telegram_service = telegram_service
|
|
45
48
|
self.serial_number: str = ""
|
|
46
49
|
self.function_code: str = ""
|
|
47
50
|
self.data: str = ""
|
|
48
|
-
self.finish_callback: Optional[Callable[[ConbusCustomResponse], None]] = None
|
|
49
51
|
self.service_response: ConbusCustomResponse = ConbusCustomResponse(
|
|
50
52
|
success=False,
|
|
51
53
|
serial_number=self.serial_number,
|
|
@@ -54,7 +56,14 @@ class ConbusCustomService(ConbusProtocol):
|
|
|
54
56
|
# Set up logging
|
|
55
57
|
self.logger = logging.getLogger(__name__)
|
|
56
58
|
|
|
57
|
-
|
|
59
|
+
# Connect protocol signals
|
|
60
|
+
self.conbus_protocol.on_connection_made.connect(self.connection_made)
|
|
61
|
+
self.conbus_protocol.on_telegram_sent.connect(self.telegram_sent)
|
|
62
|
+
self.conbus_protocol.on_telegram_received.connect(self.telegram_received)
|
|
63
|
+
self.conbus_protocol.on_timeout.connect(self.timeout)
|
|
64
|
+
self.conbus_protocol.on_failed.connect(self.failed)
|
|
65
|
+
|
|
66
|
+
def connection_made(self) -> None:
|
|
58
67
|
"""Handle connection established event."""
|
|
59
68
|
self.logger.debug(
|
|
60
69
|
f"Connection established, sending custom telegram F{self.function_code}D{self.data}."
|
|
@@ -65,7 +74,7 @@ class ConbusCustomService(ConbusProtocol):
|
|
|
65
74
|
self.failed(f"Invalid function code {self.function_code}")
|
|
66
75
|
return
|
|
67
76
|
|
|
68
|
-
self.send_telegram(
|
|
77
|
+
self.conbus_protocol.send_telegram(
|
|
69
78
|
serial_number=self.serial_number,
|
|
70
79
|
telegram_type=TelegramType.SYSTEM,
|
|
71
80
|
system_function=system_function,
|
|
@@ -113,8 +122,13 @@ class ConbusCustomService(ConbusProtocol):
|
|
|
113
122
|
self.service_response.data = self.data
|
|
114
123
|
self.service_response.reply_telegram = reply_telegram
|
|
115
124
|
|
|
116
|
-
|
|
117
|
-
|
|
125
|
+
# Emit finish signal
|
|
126
|
+
self.on_finish.emit(self.service_response)
|
|
127
|
+
|
|
128
|
+
def timeout(self) -> None:
|
|
129
|
+
"""Handle timeout event."""
|
|
130
|
+
self.logger.debug("Timeout occurred")
|
|
131
|
+
self.failed("Timeout")
|
|
118
132
|
|
|
119
133
|
def failed(self, message: str) -> None:
|
|
120
134
|
"""Handle failed connection event.
|
|
@@ -126,15 +140,15 @@ class ConbusCustomService(ConbusProtocol):
|
|
|
126
140
|
self.service_response.success = False
|
|
127
141
|
self.service_response.timestamp = datetime.now()
|
|
128
142
|
self.service_response.error = message
|
|
129
|
-
|
|
130
|
-
|
|
143
|
+
|
|
144
|
+
# Emit finish signal
|
|
145
|
+
self.on_finish.emit(self.service_response)
|
|
131
146
|
|
|
132
147
|
def send_custom_telegram(
|
|
133
148
|
self,
|
|
134
149
|
serial_number: str,
|
|
135
150
|
function_code: str,
|
|
136
151
|
data: str,
|
|
137
|
-
finish_callback: Callable[[ConbusCustomResponse], None],
|
|
138
152
|
timeout_seconds: Optional[float] = None,
|
|
139
153
|
) -> None:
|
|
140
154
|
"""Send a custom telegram to a module.
|
|
@@ -143,14 +157,55 @@ class ConbusCustomService(ConbusProtocol):
|
|
|
143
157
|
serial_number: 10-digit module serial number.
|
|
144
158
|
function_code: Function code (e.g., "02", "17").
|
|
145
159
|
data: Data code (e.g., "E2", "AA").
|
|
146
|
-
finish_callback: Callback function to call when the reply is received.
|
|
147
160
|
timeout_seconds: Timeout in seconds.
|
|
148
161
|
"""
|
|
149
162
|
self.logger.info("Starting send_custom_telegram")
|
|
150
|
-
if timeout_seconds:
|
|
151
|
-
self.timeout_seconds = timeout_seconds
|
|
152
|
-
self.finish_callback = finish_callback
|
|
153
163
|
self.serial_number = serial_number
|
|
154
164
|
self.function_code = function_code
|
|
155
165
|
self.data = data
|
|
156
|
-
|
|
166
|
+
if timeout_seconds:
|
|
167
|
+
self.set_timeout(timeout_seconds)
|
|
168
|
+
|
|
169
|
+
def set_timeout(self, timeout_seconds: float) -> None:
|
|
170
|
+
"""Set operation timeout.
|
|
171
|
+
|
|
172
|
+
Args:
|
|
173
|
+
timeout_seconds: Timeout in seconds.
|
|
174
|
+
"""
|
|
175
|
+
self.conbus_protocol.timeout_seconds = timeout_seconds
|
|
176
|
+
|
|
177
|
+
def start_reactor(self) -> None:
|
|
178
|
+
"""Start the reactor."""
|
|
179
|
+
self.conbus_protocol.start_reactor()
|
|
180
|
+
|
|
181
|
+
def stop_reactor(self) -> None:
|
|
182
|
+
"""Stop the reactor."""
|
|
183
|
+
self.conbus_protocol.stop_reactor()
|
|
184
|
+
|
|
185
|
+
def __enter__(self) -> "ConbusCustomService":
|
|
186
|
+
"""Enter context manager - reset state for singleton reuse.
|
|
187
|
+
|
|
188
|
+
Returns:
|
|
189
|
+
Self for context manager protocol.
|
|
190
|
+
"""
|
|
191
|
+
# Reset state for singleton reuse
|
|
192
|
+
self.service_response = ConbusCustomResponse(success=False)
|
|
193
|
+
self.serial_number = ""
|
|
194
|
+
self.function_code = ""
|
|
195
|
+
self.data = ""
|
|
196
|
+
return self
|
|
197
|
+
|
|
198
|
+
def __exit__(
|
|
199
|
+
self, _exc_type: Optional[type], _exc_val: Optional[Exception], _exc_tb: Any
|
|
200
|
+
) -> None:
|
|
201
|
+
"""Exit context manager and disconnect signals."""
|
|
202
|
+
# Disconnect protocol signals
|
|
203
|
+
self.conbus_protocol.on_connection_made.disconnect(self.connection_made)
|
|
204
|
+
self.conbus_protocol.on_telegram_sent.disconnect(self.telegram_sent)
|
|
205
|
+
self.conbus_protocol.on_telegram_received.disconnect(self.telegram_received)
|
|
206
|
+
self.conbus_protocol.on_timeout.disconnect(self.timeout)
|
|
207
|
+
self.conbus_protocol.on_failed.disconnect(self.failed)
|
|
208
|
+
# Disconnect service signals
|
|
209
|
+
self.on_finish.disconnect()
|
|
210
|
+
# Stop reactor
|
|
211
|
+
self.stop_reactor()
|
|
@@ -5,46 +5,58 @@ This module provides service for querying all datapoint types from a module.
|
|
|
5
5
|
|
|
6
6
|
import logging
|
|
7
7
|
from datetime import datetime
|
|
8
|
-
from typing import
|
|
8
|
+
from typing import Any, Optional
|
|
9
9
|
|
|
10
|
-
from
|
|
10
|
+
from psygnal import Signal
|
|
11
11
|
|
|
12
|
-
from xp.models import
|
|
12
|
+
from xp.models import ConbusDatapointResponse
|
|
13
13
|
from xp.models.protocol.conbus_protocol import TelegramReceivedEvent
|
|
14
14
|
from xp.models.telegram.datapoint_type import DataPointType
|
|
15
15
|
from xp.models.telegram.reply_telegram import ReplyTelegram
|
|
16
16
|
from xp.models.telegram.system_function import SystemFunction
|
|
17
17
|
from xp.models.telegram.telegram_type import TelegramType
|
|
18
18
|
from xp.services import TelegramService
|
|
19
|
-
from xp.services.protocol import
|
|
19
|
+
from xp.services.protocol.conbus_event_protocol import ConbusEventProtocol
|
|
20
20
|
|
|
21
21
|
|
|
22
|
-
class ConbusDatapointQueryAllService
|
|
23
|
-
"""
|
|
24
|
-
Utility service for querying all datapoints from a module.
|
|
22
|
+
class ConbusDatapointQueryAllService:
|
|
23
|
+
"""Utility service for querying all datapoints from a module.
|
|
25
24
|
|
|
26
25
|
This service orchestrates multiple ConbusDatapointService calls to query
|
|
27
26
|
all available datapoint types sequentially.
|
|
27
|
+
|
|
28
|
+
Attributes:
|
|
29
|
+
conbus_protocol: ConbusEventProtocol for protocol communication.
|
|
30
|
+
telegram_service: TelegramService for dependency injection.
|
|
31
|
+
on_progress: Signal emitted for each datapoint response received.
|
|
32
|
+
on_finish: Signal emitted when all datapoints queried (with response).
|
|
28
33
|
"""
|
|
29
34
|
|
|
35
|
+
on_progress: Signal = Signal(ReplyTelegram)
|
|
36
|
+
on_finish: Signal = Signal(ConbusDatapointResponse)
|
|
37
|
+
|
|
30
38
|
def __init__(
|
|
31
39
|
self,
|
|
40
|
+
conbus_protocol: ConbusEventProtocol,
|
|
32
41
|
telegram_service: TelegramService,
|
|
33
|
-
cli_config: ConbusClientConfig,
|
|
34
|
-
reactor: PosixReactorBase,
|
|
35
42
|
) -> None:
|
|
36
43
|
"""Initialize the query all service.
|
|
37
44
|
|
|
38
45
|
Args:
|
|
46
|
+
conbus_protocol: ConbusEventProtocol for protocol communication.
|
|
39
47
|
telegram_service: TelegramService for dependency injection.
|
|
40
|
-
cli_config: ConbusClientConfig for connection settings.
|
|
41
|
-
reactor: PosixReactorBase for async operations.
|
|
42
48
|
"""
|
|
43
|
-
|
|
49
|
+
self.conbus_protocol = conbus_protocol
|
|
44
50
|
self.telegram_service = telegram_service
|
|
51
|
+
|
|
52
|
+
# Connect protocol signals
|
|
53
|
+
self.conbus_protocol.on_connection_made.connect(self.connection_made)
|
|
54
|
+
self.conbus_protocol.on_telegram_sent.connect(self.telegram_sent)
|
|
55
|
+
self.conbus_protocol.on_telegram_received.connect(self.telegram_received)
|
|
56
|
+
self.conbus_protocol.on_timeout.connect(self.timeout)
|
|
57
|
+
self.conbus_protocol.on_failed.connect(self.failed)
|
|
58
|
+
|
|
45
59
|
self.serial_number: str = ""
|
|
46
|
-
self.finish_callback: Optional[Callable[[ConbusDatapointResponse], None]] = None
|
|
47
|
-
self.progress_callback: Optional[Callable[[ReplyTelegram], None]] = None
|
|
48
60
|
self.service_response: ConbusDatapointResponse = ConbusDatapointResponse(
|
|
49
61
|
success=False,
|
|
50
62
|
serial_number=self.serial_number,
|
|
@@ -55,7 +67,7 @@ class ConbusDatapointQueryAllService(ConbusProtocol):
|
|
|
55
67
|
# Set up logging
|
|
56
68
|
self.logger = logging.getLogger(__name__)
|
|
57
69
|
|
|
58
|
-
def
|
|
70
|
+
def connection_made(self) -> None:
|
|
59
71
|
"""Handle connection established event."""
|
|
60
72
|
self.logger.debug("Connection established, querying datapoints.")
|
|
61
73
|
self.next_datapoint()
|
|
@@ -75,7 +87,7 @@ class ConbusDatapointQueryAllService(ConbusProtocol):
|
|
|
75
87
|
datapoint_type = DataPointType(datapoint_type_code)
|
|
76
88
|
|
|
77
89
|
self.logger.debug(f"Datapoint: {datapoint_type}")
|
|
78
|
-
self.send_telegram(
|
|
90
|
+
self.conbus_protocol.send_telegram(
|
|
79
91
|
telegram_type=TelegramType.SYSTEM,
|
|
80
92
|
serial_number=self.serial_number,
|
|
81
93
|
system_function=SystemFunction.READ_DATAPOINT,
|
|
@@ -84,24 +96,19 @@ class ConbusDatapointQueryAllService(ConbusProtocol):
|
|
|
84
96
|
self.current_index += 1
|
|
85
97
|
return True
|
|
86
98
|
|
|
87
|
-
def timeout(self) ->
|
|
88
|
-
"""Handle timeout event by querying next datapoint.
|
|
89
|
-
|
|
90
|
-
Returns:
|
|
91
|
-
True to continue, False to stop the reactor.
|
|
92
|
-
"""
|
|
99
|
+
def timeout(self) -> None:
|
|
100
|
+
"""Handle timeout event by querying next datapoint."""
|
|
93
101
|
self.logger.debug("Timeout, querying next datapoint")
|
|
94
102
|
query_next_datapoint = self.next_datapoint()
|
|
95
103
|
if not query_next_datapoint:
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
return True
|
|
104
|
+
self.logger.debug("Received all datapoints telegram")
|
|
105
|
+
self.service_response.success = True
|
|
106
|
+
self.service_response.timestamp = datetime.now()
|
|
107
|
+
self.service_response.serial_number = self.serial_number
|
|
108
|
+
self.service_response.system_function = SystemFunction.READ_DATAPOINT
|
|
109
|
+
|
|
110
|
+
# Emit finish signal
|
|
111
|
+
self.on_finish.emit(self.service_response)
|
|
105
112
|
|
|
106
113
|
def telegram_sent(self, telegram_sent: str) -> None:
|
|
107
114
|
"""Handle telegram sent event.
|
|
@@ -142,8 +149,7 @@ class ConbusDatapointQueryAllService(ConbusProtocol):
|
|
|
142
149
|
return
|
|
143
150
|
|
|
144
151
|
self.logger.debug("Received a datapoint telegram")
|
|
145
|
-
|
|
146
|
-
self.progress_callback(datapoint_telegram)
|
|
152
|
+
self.on_progress.emit(datapoint_telegram)
|
|
147
153
|
|
|
148
154
|
def failed(self, message: str) -> None:
|
|
149
155
|
"""Handle failed connection event.
|
|
@@ -155,28 +161,69 @@ class ConbusDatapointQueryAllService(ConbusProtocol):
|
|
|
155
161
|
self.service_response.success = False
|
|
156
162
|
self.service_response.timestamp = datetime.now()
|
|
157
163
|
self.service_response.error = message
|
|
158
|
-
|
|
159
|
-
|
|
164
|
+
|
|
165
|
+
# Emit finish signal
|
|
166
|
+
self.on_finish.emit(self.service_response)
|
|
160
167
|
|
|
161
168
|
def query_all_datapoints(
|
|
162
169
|
self,
|
|
163
170
|
serial_number: str,
|
|
164
|
-
finish_callback: Callable[[ConbusDatapointResponse], None],
|
|
165
|
-
progress_callback: Callable[[ReplyTelegram], None],
|
|
166
171
|
timeout_seconds: Optional[float] = None,
|
|
167
172
|
) -> None:
|
|
168
173
|
"""Query all datapoints from a module.
|
|
169
174
|
|
|
170
175
|
Args:
|
|
171
176
|
serial_number: 10-digit module serial number.
|
|
172
|
-
finish_callback: Callback function to call when all datapoints are received.
|
|
173
|
-
progress_callback: Callback function to call when each datapoint is received.
|
|
174
177
|
timeout_seconds: Timeout in seconds.
|
|
175
178
|
"""
|
|
176
179
|
self.logger.info("Starting query_all_datapoints")
|
|
177
180
|
if timeout_seconds:
|
|
178
|
-
self.timeout_seconds = timeout_seconds
|
|
179
|
-
self.finish_callback = finish_callback
|
|
180
|
-
self.progress_callback = progress_callback
|
|
181
|
+
self.conbus_protocol.timeout_seconds = timeout_seconds
|
|
181
182
|
self.serial_number = serial_number
|
|
182
|
-
|
|
183
|
+
|
|
184
|
+
def set_timeout(self, timeout_seconds: float) -> None:
|
|
185
|
+
"""Set operation timeout.
|
|
186
|
+
|
|
187
|
+
Args:
|
|
188
|
+
timeout_seconds: Timeout in seconds.
|
|
189
|
+
"""
|
|
190
|
+
self.conbus_protocol.timeout_seconds = timeout_seconds
|
|
191
|
+
|
|
192
|
+
def start_reactor(self) -> None:
|
|
193
|
+
"""Start the reactor."""
|
|
194
|
+
self.conbus_protocol.start_reactor()
|
|
195
|
+
|
|
196
|
+
def stop_reactor(self) -> None:
|
|
197
|
+
"""Stop the reactor."""
|
|
198
|
+
self.conbus_protocol.stop_reactor()
|
|
199
|
+
|
|
200
|
+
def __enter__(self) -> "ConbusDatapointQueryAllService":
|
|
201
|
+
"""Enter context manager - reset state for singleton reuse.
|
|
202
|
+
|
|
203
|
+
Returns:
|
|
204
|
+
Self for context manager protocol.
|
|
205
|
+
"""
|
|
206
|
+
# Reset state for singleton reuse
|
|
207
|
+
self.service_response = ConbusDatapointResponse(
|
|
208
|
+
success=False,
|
|
209
|
+
serial_number="",
|
|
210
|
+
)
|
|
211
|
+
self.datapoint_types = list(DataPointType)
|
|
212
|
+
self.current_index = 0
|
|
213
|
+
self.serial_number = ""
|
|
214
|
+
return self
|
|
215
|
+
|
|
216
|
+
def __exit__(
|
|
217
|
+
self, _exc_type: Optional[type], _exc_val: Optional[Exception], _exc_tb: Any
|
|
218
|
+
) -> None:
|
|
219
|
+
"""Exit context manager - cleanup signals and reactor."""
|
|
220
|
+
# Disconnect protocol signals
|
|
221
|
+
self.conbus_protocol.on_connection_made.disconnect(self.connection_made)
|
|
222
|
+
self.conbus_protocol.on_telegram_sent.disconnect(self.telegram_sent)
|
|
223
|
+
self.conbus_protocol.on_telegram_received.disconnect(self.telegram_received)
|
|
224
|
+
self.conbus_protocol.on_timeout.disconnect(self.timeout)
|
|
225
|
+
self.conbus_protocol.on_failed.disconnect(self.failed)
|
|
226
|
+
# Disconnect service signals
|
|
227
|
+
self.on_progress.disconnect()
|
|
228
|
+
# Stop reactor
|
|
229
|
+
self.stop_reactor()
|