conson-xp 1.33.0__py3-none-any.whl → 1.35.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.33.0.dist-info → conson_xp-1.35.0.dist-info}/METADATA +1 -1
- {conson_xp-1.33.0.dist-info → conson_xp-1.35.0.dist-info}/RECORD +32 -32
- 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_blink_commands.py +20 -6
- 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_blink_all_service.py +89 -35
- xp/services/conbus/conbus_blink_service.py +82 -24
- 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/utils/dependencies.py +12 -24
- {conson_xp-1.33.0.dist-info → conson_xp-1.35.0.dist-info}/WHEEL +0 -0
- {conson_xp-1.33.0.dist-info → conson_xp-1.35.0.dist-info}/entry_points.txt +0 -0
- {conson_xp-1.33.0.dist-info → conson_xp-1.35.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()
|
|
@@ -6,46 +6,48 @@ blink/unblink telegrams to all discovered modules on the network.
|
|
|
6
6
|
|
|
7
7
|
import logging
|
|
8
8
|
from datetime import datetime
|
|
9
|
-
from typing import
|
|
9
|
+
from typing import Any, Optional
|
|
10
10
|
|
|
11
|
-
from
|
|
11
|
+
from psygnal import Signal
|
|
12
12
|
|
|
13
|
-
from xp.models import ConbusClientConfig
|
|
14
13
|
from xp.models.conbus.conbus_blink import ConbusBlinkResponse
|
|
15
14
|
from xp.models.protocol.conbus_protocol import TelegramReceivedEvent
|
|
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 ConbusBlinkAllService
|
|
21
|
+
class ConbusBlinkAllService:
|
|
23
22
|
"""
|
|
24
23
|
Service for blinking all modules on Conbus servers.
|
|
25
24
|
|
|
26
|
-
Uses
|
|
25
|
+
Uses ConbusEventProtocol to provide blink/unblink functionality
|
|
27
26
|
for all discovered modules on the network.
|
|
27
|
+
|
|
28
|
+
Attributes:
|
|
29
|
+
on_progress: Signal emitted during blink operation progress (with message).
|
|
30
|
+
on_finish: Signal emitted when blink operation completes (with response).
|
|
28
31
|
"""
|
|
29
32
|
|
|
33
|
+
on_progress: Signal = Signal(str)
|
|
34
|
+
on_finish: Signal = Signal(ConbusBlinkResponse)
|
|
35
|
+
|
|
30
36
|
def __init__(
|
|
31
37
|
self,
|
|
38
|
+
conbus_protocol: ConbusEventProtocol,
|
|
32
39
|
telegram_service: TelegramService,
|
|
33
|
-
cli_config: ConbusClientConfig,
|
|
34
|
-
reactor: PosixReactorBase,
|
|
35
40
|
) -> None:
|
|
36
41
|
"""Initialize the Conbus blink all service.
|
|
37
42
|
|
|
38
43
|
Args:
|
|
44
|
+
conbus_protocol: ConbusEventProtocol instance for communication.
|
|
39
45
|
telegram_service: Service for parsing telegrams.
|
|
40
|
-
cli_config: Configuration for Conbus client connection.
|
|
41
|
-
reactor: Twisted reactor for event loop.
|
|
42
46
|
"""
|
|
43
|
-
|
|
47
|
+
self.conbus_protocol = conbus_protocol
|
|
44
48
|
self.telegram_service = telegram_service
|
|
45
49
|
self.serial_number: str = ""
|
|
46
50
|
self.on_or_off = "none"
|
|
47
|
-
self.progress_callback: Optional[Callable[[str], None]] = None
|
|
48
|
-
self.finish_callback: Optional[Callable[[ConbusBlinkResponse], None]] = None
|
|
49
51
|
self.service_response: ConbusBlinkResponse = ConbusBlinkResponse(
|
|
50
52
|
success=False,
|
|
51
53
|
serial_number=self.serial_number,
|
|
@@ -56,17 +58,23 @@ class ConbusBlinkAllService(ConbusProtocol):
|
|
|
56
58
|
# Set up logging
|
|
57
59
|
self.logger = logging.getLogger(__name__)
|
|
58
60
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
+
# Connect protocol signals
|
|
62
|
+
self.conbus_protocol.on_connection_made.connect(self.connection_made)
|
|
63
|
+
self.conbus_protocol.on_telegram_sent.connect(self.telegram_sent)
|
|
64
|
+
self.conbus_protocol.on_telegram_received.connect(self.telegram_received)
|
|
65
|
+
self.conbus_protocol.on_timeout.connect(self.timeout)
|
|
66
|
+
self.conbus_protocol.on_failed.connect(self.failed)
|
|
67
|
+
|
|
68
|
+
def connection_made(self) -> None:
|
|
69
|
+
"""Handle connection made event."""
|
|
61
70
|
self.logger.debug("Connection established, send discover telegram.")
|
|
62
|
-
self.send_telegram(
|
|
71
|
+
self.conbus_protocol.send_telegram(
|
|
63
72
|
telegram_type=TelegramType.SYSTEM,
|
|
64
73
|
serial_number="0000000000",
|
|
65
74
|
system_function=SystemFunction.DISCOVERY,
|
|
66
75
|
data_value="00",
|
|
67
76
|
)
|
|
68
|
-
|
|
69
|
-
self.progress_callback(".")
|
|
77
|
+
self.on_progress.emit(".")
|
|
70
78
|
|
|
71
79
|
def send_blink(self, serial_number: str) -> None:
|
|
72
80
|
"""Send blink or unblink telegram to a discovered module.
|
|
@@ -81,7 +89,7 @@ class ConbusBlinkAllService(ConbusProtocol):
|
|
|
81
89
|
if self.on_or_off.lower() == "on":
|
|
82
90
|
system_function = SystemFunction.BLINK
|
|
83
91
|
|
|
84
|
-
self.send_telegram(
|
|
92
|
+
self.conbus_protocol.send_telegram(
|
|
85
93
|
telegram_type=TelegramType.SYSTEM,
|
|
86
94
|
serial_number=serial_number,
|
|
87
95
|
system_function=system_function,
|
|
@@ -90,8 +98,7 @@ class ConbusBlinkAllService(ConbusProtocol):
|
|
|
90
98
|
self.service_response.system_function = system_function
|
|
91
99
|
self.service_response.operation = self.on_or_off
|
|
92
100
|
|
|
93
|
-
|
|
94
|
-
self.progress_callback(".")
|
|
101
|
+
self.on_progress.emit(".")
|
|
95
102
|
|
|
96
103
|
def telegram_sent(self, telegram_sent: str) -> None:
|
|
97
104
|
"""Handle telegram sent event.
|
|
@@ -129,8 +136,7 @@ class ConbusBlinkAllService(ConbusProtocol):
|
|
|
129
136
|
):
|
|
130
137
|
self.logger.debug("Received discovery response")
|
|
131
138
|
self.send_blink(reply_telegram.serial_number)
|
|
132
|
-
|
|
133
|
-
self.progress_callback(".")
|
|
139
|
+
self.on_progress.emit(".")
|
|
134
140
|
return
|
|
135
141
|
|
|
136
142
|
if reply_telegram and reply_telegram.system_function in (
|
|
@@ -138,12 +144,18 @@ class ConbusBlinkAllService(ConbusProtocol):
|
|
|
138
144
|
SystemFunction.UNBLINK,
|
|
139
145
|
):
|
|
140
146
|
self.logger.debug("Received blink response")
|
|
141
|
-
|
|
142
|
-
self.progress_callback(".")
|
|
147
|
+
self.on_progress.emit(".")
|
|
143
148
|
return
|
|
144
149
|
|
|
145
150
|
self.logger.debug("Received unexpected response")
|
|
146
151
|
|
|
152
|
+
def timeout(self) -> None:
|
|
153
|
+
"""Handle timeout event to stop operation."""
|
|
154
|
+
self.logger.info("Blink all operation timeout")
|
|
155
|
+
self.service_response.success = False
|
|
156
|
+
self.service_response.error = "Blink all operation timeout"
|
|
157
|
+
self.on_finish.emit(self.service_response)
|
|
158
|
+
|
|
147
159
|
def failed(self, message: str) -> None:
|
|
148
160
|
"""Handle failed connection event.
|
|
149
161
|
|
|
@@ -154,28 +166,70 @@ class ConbusBlinkAllService(ConbusProtocol):
|
|
|
154
166
|
self.service_response.success = False
|
|
155
167
|
self.service_response.timestamp = datetime.now()
|
|
156
168
|
self.service_response.error = message
|
|
157
|
-
|
|
158
|
-
self.finish_callback(self.service_response)
|
|
169
|
+
self.on_finish.emit(self.service_response)
|
|
159
170
|
|
|
160
171
|
def send_blink_all_telegram(
|
|
161
172
|
self,
|
|
162
173
|
on_or_off: str,
|
|
163
|
-
progress_callback: Callable[[str], None],
|
|
164
|
-
finish_callback: Callable[[ConbusBlinkResponse], None],
|
|
165
174
|
timeout_seconds: Optional[float] = None,
|
|
166
175
|
) -> None:
|
|
167
176
|
"""Send blink command to all discovered modules.
|
|
168
177
|
|
|
169
178
|
Args:
|
|
170
179
|
on_or_off: "on" to blink or "off" to unblink all devices.
|
|
171
|
-
progress_callback: Callback function to call with progress updates.
|
|
172
|
-
finish_callback: Callback function to call when the operation completes.
|
|
173
180
|
timeout_seconds: Timeout in seconds.
|
|
174
181
|
"""
|
|
175
182
|
self.logger.info("Starting send_blink_all_telegram")
|
|
176
183
|
if timeout_seconds:
|
|
177
|
-
self.timeout_seconds = timeout_seconds
|
|
178
|
-
self.progress_callback = progress_callback
|
|
179
|
-
self.finish_callback = finish_callback
|
|
184
|
+
self.conbus_protocol.timeout_seconds = timeout_seconds
|
|
180
185
|
self.on_or_off = on_or_off
|
|
181
|
-
|
|
186
|
+
# Caller invokes start_reactor()
|
|
187
|
+
|
|
188
|
+
def set_timeout(self, timeout_seconds: float) -> None:
|
|
189
|
+
"""Set operation timeout.
|
|
190
|
+
|
|
191
|
+
Args:
|
|
192
|
+
timeout_seconds: Timeout in seconds.
|
|
193
|
+
"""
|
|
194
|
+
self.conbus_protocol.timeout_seconds = timeout_seconds
|
|
195
|
+
|
|
196
|
+
def start_reactor(self) -> None:
|
|
197
|
+
"""Start the reactor."""
|
|
198
|
+
self.conbus_protocol.start_reactor()
|
|
199
|
+
|
|
200
|
+
def stop_reactor(self) -> None:
|
|
201
|
+
"""Stop the reactor."""
|
|
202
|
+
self.conbus_protocol.stop_reactor()
|
|
203
|
+
|
|
204
|
+
def __enter__(self) -> "ConbusBlinkAllService":
|
|
205
|
+
"""Enter context manager - reset state for singleton reuse.
|
|
206
|
+
|
|
207
|
+
Returns:
|
|
208
|
+
Self for context manager protocol.
|
|
209
|
+
"""
|
|
210
|
+
# Reset state for singleton reuse
|
|
211
|
+
self.service_response = ConbusBlinkResponse(
|
|
212
|
+
success=False,
|
|
213
|
+
serial_number="",
|
|
214
|
+
system_function=SystemFunction.NONE,
|
|
215
|
+
operation="none",
|
|
216
|
+
)
|
|
217
|
+
self.serial_number = ""
|
|
218
|
+
self.on_or_off = "none"
|
|
219
|
+
return self
|
|
220
|
+
|
|
221
|
+
def __exit__(
|
|
222
|
+
self, _exc_type: Optional[type], _exc_val: Optional[Exception], _exc_tb: Any
|
|
223
|
+
) -> None:
|
|
224
|
+
"""Exit context manager - cleanup signals and reactor."""
|
|
225
|
+
# Disconnect protocol signals
|
|
226
|
+
self.conbus_protocol.on_connection_made.disconnect(self.connection_made)
|
|
227
|
+
self.conbus_protocol.on_telegram_sent.disconnect(self.telegram_sent)
|
|
228
|
+
self.conbus_protocol.on_telegram_received.disconnect(self.telegram_received)
|
|
229
|
+
self.conbus_protocol.on_timeout.disconnect(self.timeout)
|
|
230
|
+
self.conbus_protocol.on_failed.disconnect(self.failed)
|
|
231
|
+
# Disconnect service signals
|
|
232
|
+
self.on_progress.disconnect()
|
|
233
|
+
self.on_finish.disconnect()
|
|
234
|
+
# Stop reactor
|
|
235
|
+
self.stop_reactor()
|
|
@@ -6,45 +6,46 @@ blink/unblink telegrams to control module LED indicators.
|
|
|
6
6
|
|
|
7
7
|
import logging
|
|
8
8
|
from datetime import datetime
|
|
9
|
-
from typing import
|
|
9
|
+
from typing import Any, Optional
|
|
10
10
|
|
|
11
|
-
from
|
|
11
|
+
from psygnal import Signal
|
|
12
12
|
|
|
13
|
-
from xp.models import ConbusClientConfig
|
|
14
13
|
from xp.models.conbus.conbus_blink import ConbusBlinkResponse
|
|
15
14
|
from xp.models.protocol.conbus_protocol import TelegramReceivedEvent
|
|
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 ConbusBlinkService
|
|
21
|
+
class ConbusBlinkService:
|
|
23
22
|
"""
|
|
24
23
|
Service for blinking module LEDs on Conbus servers.
|
|
25
24
|
|
|
26
|
-
Uses
|
|
25
|
+
Uses ConbusEventProtocol to provide blink/unblink functionality
|
|
27
26
|
for controlling module LED indicators.
|
|
27
|
+
|
|
28
|
+
Attributes:
|
|
29
|
+
on_finish: Signal emitted when blink operation completes (with response).
|
|
28
30
|
"""
|
|
29
31
|
|
|
32
|
+
on_finish: Signal = Signal(ConbusBlinkResponse)
|
|
33
|
+
|
|
30
34
|
def __init__(
|
|
31
35
|
self,
|
|
36
|
+
conbus_protocol: ConbusEventProtocol,
|
|
32
37
|
telegram_service: TelegramService,
|
|
33
|
-
cli_config: ConbusClientConfig,
|
|
34
|
-
reactor: PosixReactorBase,
|
|
35
38
|
) -> None:
|
|
36
39
|
"""Initialize the Conbus blink service.
|
|
37
40
|
|
|
38
41
|
Args:
|
|
42
|
+
conbus_protocol: ConbusEventProtocol instance for communication.
|
|
39
43
|
telegram_service: Service for parsing telegrams.
|
|
40
|
-
cli_config: Configuration for Conbus client connection.
|
|
41
|
-
reactor: Twisted reactor for event loop.
|
|
42
44
|
"""
|
|
43
|
-
|
|
45
|
+
self.conbus_protocol = conbus_protocol
|
|
44
46
|
self.telegram_service = telegram_service
|
|
45
47
|
self.serial_number: str = ""
|
|
46
48
|
self.on_or_off = "none"
|
|
47
|
-
self.finish_callback: Optional[Callable[[ConbusBlinkResponse], None]] = None
|
|
48
49
|
self.service_response: ConbusBlinkResponse = ConbusBlinkResponse(
|
|
49
50
|
success=False,
|
|
50
51
|
serial_number=self.serial_number,
|
|
@@ -55,15 +56,22 @@ class ConbusBlinkService(ConbusProtocol):
|
|
|
55
56
|
# Set up logging
|
|
56
57
|
self.logger = logging.getLogger(__name__)
|
|
57
58
|
|
|
58
|
-
|
|
59
|
-
|
|
59
|
+
# Connect 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:
|
|
67
|
+
"""Handle connection made event."""
|
|
60
68
|
self.logger.debug("Connection established, sending blink command.")
|
|
61
69
|
# Blink is 05, Unblink is 06
|
|
62
70
|
system_function = SystemFunction.UNBLINK
|
|
63
71
|
if self.on_or_off.lower() == "on":
|
|
64
72
|
system_function = SystemFunction.BLINK
|
|
65
73
|
|
|
66
|
-
self.send_telegram(
|
|
74
|
+
self.conbus_protocol.send_telegram(
|
|
67
75
|
telegram_type=TelegramType.SYSTEM,
|
|
68
76
|
serial_number=self.serial_number,
|
|
69
77
|
system_function=system_function,
|
|
@@ -113,8 +121,14 @@ class ConbusBlinkService(ConbusProtocol):
|
|
|
113
121
|
self.service_response.serial_number = self.serial_number
|
|
114
122
|
self.service_response.reply_telegram = reply_telegram
|
|
115
123
|
|
|
116
|
-
|
|
117
|
-
|
|
124
|
+
self.on_finish.emit(self.service_response)
|
|
125
|
+
|
|
126
|
+
def timeout(self) -> None:
|
|
127
|
+
"""Handle timeout event to stop operation."""
|
|
128
|
+
self.logger.info("Blink operation timeout")
|
|
129
|
+
self.service_response.success = False
|
|
130
|
+
self.service_response.error = "Blink operation timeout"
|
|
131
|
+
self.on_finish.emit(self.service_response)
|
|
118
132
|
|
|
119
133
|
def failed(self, message: str) -> None:
|
|
120
134
|
"""Handle failed connection event.
|
|
@@ -126,14 +140,12 @@ class ConbusBlinkService(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
|
-
self.finish_callback(self.service_response)
|
|
143
|
+
self.on_finish.emit(self.service_response)
|
|
131
144
|
|
|
132
145
|
def send_blink_telegram(
|
|
133
146
|
self,
|
|
134
147
|
serial_number: str,
|
|
135
148
|
on_or_off: str,
|
|
136
|
-
finish_callback: Callable[[ConbusBlinkResponse], None],
|
|
137
149
|
timeout_seconds: Optional[float] = None,
|
|
138
150
|
) -> None:
|
|
139
151
|
r"""Send blink command to start blinking module LED.
|
|
@@ -141,7 +153,6 @@ class ConbusBlinkService(ConbusProtocol):
|
|
|
141
153
|
Args:
|
|
142
154
|
serial_number: 10-digit module serial number.
|
|
143
155
|
on_or_off: "on" to blink or "off" to unblink.
|
|
144
|
-
finish_callback: Callback function to call when the reply is received.
|
|
145
156
|
timeout_seconds: Timeout in seconds.
|
|
146
157
|
|
|
147
158
|
Examples:
|
|
@@ -151,8 +162,55 @@ class ConbusBlinkService(ConbusProtocol):
|
|
|
151
162
|
"""
|
|
152
163
|
self.logger.info("Starting send_blink_telegram")
|
|
153
164
|
if timeout_seconds:
|
|
154
|
-
self.timeout_seconds = timeout_seconds
|
|
155
|
-
self.finish_callback = finish_callback
|
|
165
|
+
self.conbus_protocol.timeout_seconds = timeout_seconds
|
|
156
166
|
self.serial_number = serial_number
|
|
157
167
|
self.on_or_off = on_or_off
|
|
158
|
-
|
|
168
|
+
# Caller invokes start_reactor()
|
|
169
|
+
|
|
170
|
+
def set_timeout(self, timeout_seconds: float) -> None:
|
|
171
|
+
"""Set operation timeout.
|
|
172
|
+
|
|
173
|
+
Args:
|
|
174
|
+
timeout_seconds: Timeout in seconds.
|
|
175
|
+
"""
|
|
176
|
+
self.conbus_protocol.timeout_seconds = timeout_seconds
|
|
177
|
+
|
|
178
|
+
def start_reactor(self) -> None:
|
|
179
|
+
"""Start the reactor."""
|
|
180
|
+
self.conbus_protocol.start_reactor()
|
|
181
|
+
|
|
182
|
+
def stop_reactor(self) -> None:
|
|
183
|
+
"""Stop the reactor."""
|
|
184
|
+
self.conbus_protocol.stop_reactor()
|
|
185
|
+
|
|
186
|
+
def __enter__(self) -> "ConbusBlinkService":
|
|
187
|
+
"""Enter context manager - reset state for singleton reuse.
|
|
188
|
+
|
|
189
|
+
Returns:
|
|
190
|
+
Self for context manager protocol.
|
|
191
|
+
"""
|
|
192
|
+
# Reset state for singleton reuse
|
|
193
|
+
self.service_response = ConbusBlinkResponse(
|
|
194
|
+
success=False,
|
|
195
|
+
serial_number="",
|
|
196
|
+
system_function=SystemFunction.NONE,
|
|
197
|
+
operation="none",
|
|
198
|
+
)
|
|
199
|
+
self.serial_number = ""
|
|
200
|
+
self.on_or_off = "none"
|
|
201
|
+
return self
|
|
202
|
+
|
|
203
|
+
def __exit__(
|
|
204
|
+
self, _exc_type: Optional[type], _exc_val: Optional[Exception], _exc_tb: Any
|
|
205
|
+
) -> None:
|
|
206
|
+
"""Exit context manager - cleanup signals and reactor."""
|
|
207
|
+
# Disconnect protocol signals
|
|
208
|
+
self.conbus_protocol.on_connection_made.disconnect(self.connection_made)
|
|
209
|
+
self.conbus_protocol.on_telegram_sent.disconnect(self.telegram_sent)
|
|
210
|
+
self.conbus_protocol.on_telegram_received.disconnect(self.telegram_received)
|
|
211
|
+
self.conbus_protocol.on_timeout.disconnect(self.timeout)
|
|
212
|
+
self.conbus_protocol.on_failed.disconnect(self.failed)
|
|
213
|
+
# Disconnect service signals
|
|
214
|
+
self.on_finish.disconnect()
|
|
215
|
+
# Stop reactor
|
|
216
|
+
self.stop_reactor()
|