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
|
@@ -6,18 +6,17 @@ and processing ACK/NAK responses.
|
|
|
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_output import ConbusOutputResponse
|
|
15
14
|
from xp.models.protocol.conbus_protocol import TelegramReceivedEvent
|
|
16
15
|
from xp.models.telegram.action_type import ActionType
|
|
17
16
|
from xp.models.telegram.output_telegram import OutputTelegram
|
|
18
17
|
from xp.models.telegram.system_function import SystemFunction
|
|
19
18
|
from xp.models.telegram.telegram_type import TelegramType
|
|
20
|
-
from xp.services.protocol import
|
|
19
|
+
from xp.services.protocol.conbus_event_protocol import ConbusEventProtocol
|
|
21
20
|
from xp.services.telegram.telegram_output_service import (
|
|
22
21
|
TelegramOutputService,
|
|
23
22
|
XPOutputError,
|
|
@@ -30,33 +29,47 @@ class ConbusOutputError(Exception):
|
|
|
30
29
|
pass
|
|
31
30
|
|
|
32
31
|
|
|
33
|
-
class ConbusOutputService
|
|
32
|
+
class ConbusOutputService:
|
|
34
33
|
"""
|
|
35
34
|
Service for sending action telegrams to Conbus module outputs.
|
|
36
35
|
|
|
37
36
|
Manages action telegram transmission (ON/OFF) and processes
|
|
38
37
|
ACK/NAK responses from modules.
|
|
38
|
+
|
|
39
|
+
Attributes:
|
|
40
|
+
conbus_protocol: Protocol instance for Conbus communication.
|
|
41
|
+
on_finish: Signal emitted when operation finishes (with result).
|
|
39
42
|
"""
|
|
40
43
|
|
|
44
|
+
conbus_protocol: ConbusEventProtocol
|
|
45
|
+
on_finish: Signal = Signal(ConbusOutputResponse)
|
|
46
|
+
|
|
41
47
|
def __init__(
|
|
42
48
|
self,
|
|
49
|
+
conbus_protocol: ConbusEventProtocol,
|
|
43
50
|
telegram_output_service: TelegramOutputService,
|
|
44
|
-
cli_config: ConbusClientConfig,
|
|
45
|
-
reactor: PosixReactorBase,
|
|
46
51
|
):
|
|
47
52
|
"""Initialize the Conbus output service.
|
|
48
53
|
|
|
49
54
|
Args:
|
|
55
|
+
conbus_protocol: ConbusEventProtocol for communication.
|
|
50
56
|
telegram_output_service: TelegramOutputService for telegram generation/parsing.
|
|
51
|
-
cli_config: Conbus client configuration.
|
|
52
|
-
reactor: Twisted reactor for async operations.
|
|
53
57
|
"""
|
|
54
|
-
|
|
58
|
+
self.conbus_protocol = conbus_protocol
|
|
55
59
|
self.telegram_output_service = telegram_output_service
|
|
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
|
+
# Initialize state
|
|
56
69
|
self.serial_number: str = ""
|
|
57
70
|
self.output_number: int = 0
|
|
58
71
|
self.action_type: ActionType = ActionType.ON_RELEASE
|
|
59
|
-
self.
|
|
72
|
+
self.output_state: str = ""
|
|
60
73
|
self.service_response: ConbusOutputResponse = ConbusOutputResponse(
|
|
61
74
|
success=False,
|
|
62
75
|
serial_number=self.serial_number,
|
|
@@ -68,7 +81,7 @@ class ConbusOutputService(ConbusProtocol):
|
|
|
68
81
|
# Set up logging
|
|
69
82
|
self.logger = logging.getLogger(__name__)
|
|
70
83
|
|
|
71
|
-
def
|
|
84
|
+
def connection_made(self) -> None:
|
|
72
85
|
"""Handle connection established event."""
|
|
73
86
|
self.logger.debug(
|
|
74
87
|
f"Connection established, sending action {self.action_type} to output {self.output_number}."
|
|
@@ -84,7 +97,7 @@ class ConbusOutputService(ConbusProtocol):
|
|
|
84
97
|
|
|
85
98
|
# Send F27D{output:02d}{action} telegram
|
|
86
99
|
# F27 = ACTION, D = data with output number and action type
|
|
87
|
-
self.send_telegram(
|
|
100
|
+
self.conbus_protocol.send_telegram(
|
|
88
101
|
telegram_type=TelegramType.SYSTEM,
|
|
89
102
|
serial_number=self.serial_number,
|
|
90
103
|
system_function=SystemFunction.ACTION,
|
|
@@ -148,8 +161,12 @@ class ConbusOutputService(ConbusProtocol):
|
|
|
148
161
|
self.service_response.output_number = self.output_number
|
|
149
162
|
self.service_response.action_type = self.action_type
|
|
150
163
|
self.service_response.output_telegram = output_telegram
|
|
151
|
-
|
|
152
|
-
|
|
164
|
+
self.on_finish.emit(self.service_response)
|
|
165
|
+
|
|
166
|
+
def timeout(self) -> None:
|
|
167
|
+
"""Handle timeout event."""
|
|
168
|
+
self.logger.debug("Timeout occurred")
|
|
169
|
+
self.failed("Timeout")
|
|
153
170
|
|
|
154
171
|
def failed(self, message: str) -> None:
|
|
155
172
|
"""Handle failed connection event.
|
|
@@ -164,15 +181,13 @@ class ConbusOutputService(ConbusProtocol):
|
|
|
164
181
|
self.service_response.output_number = self.output_number
|
|
165
182
|
self.service_response.action_type = self.action_type
|
|
166
183
|
self.service_response.error = message
|
|
167
|
-
|
|
168
|
-
self.finish_callback(self.service_response)
|
|
184
|
+
self.on_finish.emit(self.service_response)
|
|
169
185
|
|
|
170
186
|
def send_action(
|
|
171
187
|
self,
|
|
172
188
|
serial_number: str,
|
|
173
189
|
output_number: int,
|
|
174
190
|
action_type: ActionType,
|
|
175
|
-
finish_callback: Callable[[ConbusOutputResponse], None],
|
|
176
191
|
timeout_seconds: Optional[float] = None,
|
|
177
192
|
) -> None:
|
|
178
193
|
"""Send an action telegram to a module output.
|
|
@@ -181,14 +196,59 @@ class ConbusOutputService(ConbusProtocol):
|
|
|
181
196
|
serial_number: 10-digit module serial number.
|
|
182
197
|
output_number: Output number (0-99).
|
|
183
198
|
action_type: Action to perform (ON_RELEASE, OFF_PRESS, etc.).
|
|
184
|
-
finish_callback: Callback function to call when operation completes.
|
|
185
199
|
timeout_seconds: Optional timeout in seconds.
|
|
186
200
|
"""
|
|
187
201
|
self.logger.info("Starting send_action")
|
|
188
202
|
if timeout_seconds:
|
|
189
|
-
self.timeout_seconds = timeout_seconds
|
|
203
|
+
self.conbus_protocol.timeout_seconds = timeout_seconds
|
|
190
204
|
self.serial_number = serial_number
|
|
191
205
|
self.output_number = output_number
|
|
192
206
|
self.action_type = action_type
|
|
193
|
-
|
|
194
|
-
|
|
207
|
+
|
|
208
|
+
def set_timeout(self, timeout_seconds: float) -> None:
|
|
209
|
+
"""Set operation timeout.
|
|
210
|
+
|
|
211
|
+
Args:
|
|
212
|
+
timeout_seconds: Timeout in seconds.
|
|
213
|
+
"""
|
|
214
|
+
self.conbus_protocol.timeout_seconds = timeout_seconds
|
|
215
|
+
|
|
216
|
+
def start_reactor(self) -> None:
|
|
217
|
+
"""Start the reactor."""
|
|
218
|
+
self.conbus_protocol.start_reactor()
|
|
219
|
+
|
|
220
|
+
def stop_reactor(self) -> None:
|
|
221
|
+
"""Stop the reactor."""
|
|
222
|
+
self.conbus_protocol.stop_reactor()
|
|
223
|
+
|
|
224
|
+
def __enter__(self) -> "ConbusOutputService":
|
|
225
|
+
"""Enter context manager - reset state for singleton reuse.
|
|
226
|
+
|
|
227
|
+
Returns:
|
|
228
|
+
Self for context manager protocol.
|
|
229
|
+
"""
|
|
230
|
+
# Reset state for singleton reuse
|
|
231
|
+
self.service_response = ConbusOutputResponse(
|
|
232
|
+
success=False,
|
|
233
|
+
serial_number="",
|
|
234
|
+
output_number=0,
|
|
235
|
+
action_type=ActionType.ON_RELEASE,
|
|
236
|
+
timestamp=datetime.now(),
|
|
237
|
+
)
|
|
238
|
+
self.output_state = ""
|
|
239
|
+
return self
|
|
240
|
+
|
|
241
|
+
def __exit__(
|
|
242
|
+
self, _exc_type: Optional[type], _exc_val: Optional[Exception], _exc_tb: Any
|
|
243
|
+
) -> None:
|
|
244
|
+
"""Exit context manager and disconnect signals."""
|
|
245
|
+
# Disconnect protocol signals
|
|
246
|
+
self.conbus_protocol.on_connection_made.disconnect(self.connection_made)
|
|
247
|
+
self.conbus_protocol.on_telegram_sent.disconnect(self.telegram_sent)
|
|
248
|
+
self.conbus_protocol.on_telegram_received.disconnect(self.telegram_received)
|
|
249
|
+
self.conbus_protocol.on_timeout.disconnect(self.timeout)
|
|
250
|
+
self.conbus_protocol.on_failed.disconnect(self.failed)
|
|
251
|
+
# Disconnect service signals
|
|
252
|
+
self.on_finish.disconnect()
|
|
253
|
+
# Stop reactor
|
|
254
|
+
self.stop_reactor()
|
|
@@ -5,49 +5,61 @@ This service handles sending raw telegram strings without prior validation.
|
|
|
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_raw import ConbusRawResponse
|
|
14
13
|
from xp.models.protocol.conbus_protocol import TelegramReceivedEvent
|
|
15
|
-
from xp.services.protocol import
|
|
14
|
+
from xp.services.protocol.conbus_event_protocol import ConbusEventProtocol
|
|
16
15
|
|
|
17
16
|
|
|
18
|
-
class ConbusRawService
|
|
17
|
+
class ConbusRawService:
|
|
19
18
|
"""
|
|
20
19
|
Service for sending raw telegram sequences to Conbus modules.
|
|
21
20
|
|
|
22
|
-
Uses
|
|
21
|
+
Uses ConbusEventProtocol to provide raw telegram functionality
|
|
23
22
|
for sending arbitrary telegram strings without validation.
|
|
23
|
+
|
|
24
|
+
Attributes:
|
|
25
|
+
conbus_protocol: Protocol instance for Conbus communication.
|
|
26
|
+
on_progress: Signal emitted when telegram is received (with frame).
|
|
27
|
+
on_finish: Signal emitted when operation finishes (with result).
|
|
24
28
|
"""
|
|
25
29
|
|
|
30
|
+
conbus_protocol: ConbusEventProtocol
|
|
31
|
+
on_progress: Signal = Signal(str)
|
|
32
|
+
on_finish: Signal = Signal(ConbusRawResponse)
|
|
33
|
+
|
|
26
34
|
def __init__(
|
|
27
35
|
self,
|
|
28
|
-
|
|
29
|
-
reactor: PosixReactorBase,
|
|
36
|
+
conbus_protocol: ConbusEventProtocol,
|
|
30
37
|
) -> None:
|
|
31
38
|
"""Initialize the Conbus raw service.
|
|
32
39
|
|
|
33
40
|
Args:
|
|
34
|
-
|
|
35
|
-
reactor: Twisted reactor for event loop.
|
|
41
|
+
conbus_protocol: ConbusEventProtocol instance.
|
|
36
42
|
"""
|
|
37
|
-
|
|
43
|
+
self.conbus_protocol = conbus_protocol
|
|
44
|
+
|
|
45
|
+
# Connect protocol signals
|
|
46
|
+
self.conbus_protocol.on_connection_made.connect(self.connection_made)
|
|
47
|
+
self.conbus_protocol.on_telegram_sent.connect(self.telegram_sent)
|
|
48
|
+
self.conbus_protocol.on_telegram_received.connect(self.telegram_received)
|
|
49
|
+
self.conbus_protocol.on_timeout.connect(self.timeout)
|
|
50
|
+
self.conbus_protocol.on_failed.connect(self.failed)
|
|
51
|
+
|
|
38
52
|
self.raw_input: str = ""
|
|
39
|
-
self.progress_callback: Optional[Callable[[str], None]] = None
|
|
40
|
-
self.finish_callback: Optional[Callable[[ConbusRawResponse], None]] = None
|
|
41
53
|
self.service_response: ConbusRawResponse = ConbusRawResponse(
|
|
42
54
|
success=False,
|
|
43
55
|
)
|
|
44
56
|
# Set up logging
|
|
45
57
|
self.logger = logging.getLogger(__name__)
|
|
46
58
|
|
|
47
|
-
def
|
|
59
|
+
def connection_made(self) -> None:
|
|
48
60
|
"""Handle connection established event."""
|
|
49
61
|
self.logger.debug(f"Connection established, sending {self.raw_input}")
|
|
50
|
-
self.
|
|
62
|
+
self.conbus_protocol.send_raw_telegram(self.raw_input)
|
|
51
63
|
|
|
52
64
|
def telegram_sent(self, telegram_sent: str) -> None:
|
|
53
65
|
"""Handle telegram sent event.
|
|
@@ -71,19 +83,13 @@ class ConbusRawService(ConbusProtocol):
|
|
|
71
83
|
self.service_response.received_telegrams = []
|
|
72
84
|
self.service_response.received_telegrams.append(telegram_received.frame)
|
|
73
85
|
|
|
74
|
-
|
|
75
|
-
self.progress_callback(telegram_received.frame)
|
|
76
|
-
|
|
77
|
-
def timeout(self) -> bool:
|
|
78
|
-
"""Handle timeout event.
|
|
86
|
+
self.on_progress.emit(telegram_received.frame)
|
|
79
87
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
self.logger.debug(f"Timeout: {
|
|
84
|
-
|
|
85
|
-
self.finish_callback(self.service_response)
|
|
86
|
-
return False
|
|
88
|
+
def timeout(self) -> None:
|
|
89
|
+
"""Handle timeout event."""
|
|
90
|
+
timeout_seconds = self.conbus_protocol.timeout_seconds
|
|
91
|
+
self.logger.debug(f"Timeout: {timeout_seconds}s")
|
|
92
|
+
self.on_finish.emit(self.service_response)
|
|
87
93
|
|
|
88
94
|
def failed(self, message: str) -> None:
|
|
89
95
|
"""Handle failed connection event.
|
|
@@ -95,28 +101,63 @@ class ConbusRawService(ConbusProtocol):
|
|
|
95
101
|
self.service_response.success = False
|
|
96
102
|
self.service_response.timestamp = datetime.now()
|
|
97
103
|
self.service_response.error = message
|
|
98
|
-
|
|
99
|
-
self.finish_callback(self.service_response)
|
|
104
|
+
self.on_finish.emit(self.service_response)
|
|
100
105
|
|
|
101
106
|
def send_raw_telegram(
|
|
102
107
|
self,
|
|
103
108
|
raw_input: str,
|
|
104
|
-
progress_callback: Callable[[str], None],
|
|
105
|
-
finish_callback: Callable[[ConbusRawResponse], None],
|
|
106
109
|
timeout_seconds: Optional[float] = None,
|
|
107
110
|
) -> None:
|
|
108
111
|
"""Send a raw telegram string to the Conbus server.
|
|
109
112
|
|
|
110
113
|
Args:
|
|
111
114
|
raw_input: Raw telegram string to send.
|
|
112
|
-
progress_callback: Callback to handle progress updates.
|
|
113
|
-
finish_callback: Callback function to call when the operation is complete.
|
|
114
115
|
timeout_seconds: Timeout in seconds.
|
|
115
116
|
"""
|
|
116
117
|
self.logger.info("Starting send_raw_telegram")
|
|
117
118
|
if timeout_seconds:
|
|
118
|
-
self.timeout_seconds = timeout_seconds
|
|
119
|
-
self.progress_callback = progress_callback
|
|
120
|
-
self.finish_callback = finish_callback
|
|
119
|
+
self.conbus_protocol.timeout_seconds = timeout_seconds
|
|
121
120
|
self.raw_input = raw_input
|
|
122
|
-
|
|
121
|
+
|
|
122
|
+
def set_timeout(self, timeout_seconds: float) -> None:
|
|
123
|
+
"""Set operation timeout.
|
|
124
|
+
|
|
125
|
+
Args:
|
|
126
|
+
timeout_seconds: Timeout in seconds.
|
|
127
|
+
"""
|
|
128
|
+
self.conbus_protocol.timeout_seconds = timeout_seconds
|
|
129
|
+
|
|
130
|
+
def start_reactor(self) -> None:
|
|
131
|
+
"""Start the reactor."""
|
|
132
|
+
self.conbus_protocol.start_reactor()
|
|
133
|
+
|
|
134
|
+
def stop_reactor(self) -> None:
|
|
135
|
+
"""Stop the reactor."""
|
|
136
|
+
self.conbus_protocol.stop_reactor()
|
|
137
|
+
|
|
138
|
+
def __enter__(self) -> "ConbusRawService":
|
|
139
|
+
"""Enter context manager.
|
|
140
|
+
|
|
141
|
+
Returns:
|
|
142
|
+
Self for context manager protocol.
|
|
143
|
+
"""
|
|
144
|
+
# Reset state for singleton reuse
|
|
145
|
+
self.service_response = ConbusRawResponse(success=False)
|
|
146
|
+
self.raw_input = ""
|
|
147
|
+
return self
|
|
148
|
+
|
|
149
|
+
def __exit__(
|
|
150
|
+
self, _exc_type: Optional[type], _exc_val: Optional[Exception], _exc_tb: Any
|
|
151
|
+
) -> None:
|
|
152
|
+
"""Exit context manager and disconnect signals."""
|
|
153
|
+
# Disconnect protocol signals
|
|
154
|
+
self.conbus_protocol.on_connection_made.disconnect(self.connection_made)
|
|
155
|
+
self.conbus_protocol.on_telegram_sent.disconnect(self.telegram_sent)
|
|
156
|
+
self.conbus_protocol.on_telegram_received.disconnect(self.telegram_received)
|
|
157
|
+
self.conbus_protocol.on_timeout.disconnect(self.timeout)
|
|
158
|
+
self.conbus_protocol.on_failed.disconnect(self.failed)
|
|
159
|
+
# Disconnect service signals
|
|
160
|
+
self.on_progress.disconnect()
|
|
161
|
+
self.on_finish.disconnect()
|
|
162
|
+
# Stop reactor
|
|
163
|
+
self.stop_reactor()
|
|
@@ -6,43 +6,50 @@ telegrams to scan modules for all datapoints by function code.
|
|
|
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
|
|
14
|
-
ConbusClientConfig,
|
|
15
|
-
ConbusResponse,
|
|
16
|
-
)
|
|
13
|
+
from xp.models import ConbusResponse
|
|
17
14
|
from xp.models.protocol.conbus_protocol import TelegramReceivedEvent
|
|
18
|
-
from xp.services.protocol import
|
|
15
|
+
from xp.services.protocol.conbus_event_protocol import ConbusEventProtocol
|
|
19
16
|
|
|
20
17
|
|
|
21
|
-
class ConbusScanService
|
|
18
|
+
class ConbusScanService:
|
|
22
19
|
"""
|
|
23
20
|
Service for scanning modules for all datapoints by function code.
|
|
24
21
|
|
|
25
|
-
Uses
|
|
22
|
+
Uses ConbusEventProtocol to provide scan functionality for discovering
|
|
26
23
|
all available datapoints on a module.
|
|
24
|
+
|
|
25
|
+
Attributes:
|
|
26
|
+
conbus_protocol: Protocol instance for Conbus communication.
|
|
27
|
+
on_progress: Signal emitted when scan progress is made (with telegram frame).
|
|
28
|
+
on_finish: Signal emitted when scan finishes (with result).
|
|
27
29
|
"""
|
|
28
30
|
|
|
31
|
+
on_progress: Signal = Signal(str)
|
|
32
|
+
on_finish: Signal = Signal(ConbusResponse)
|
|
33
|
+
|
|
29
34
|
def __init__(
|
|
30
35
|
self,
|
|
31
|
-
|
|
32
|
-
reactor: PosixReactorBase,
|
|
36
|
+
conbus_protocol: ConbusEventProtocol,
|
|
33
37
|
) -> None:
|
|
34
38
|
"""Initialize the Conbus scan service.
|
|
35
39
|
|
|
36
40
|
Args:
|
|
37
|
-
|
|
38
|
-
reactor: Twisted reactor instance.
|
|
41
|
+
conbus_protocol: ConbusEventProtocol instance.
|
|
39
42
|
"""
|
|
40
|
-
|
|
43
|
+
self.conbus_protocol = conbus_protocol
|
|
44
|
+
self.conbus_protocol.on_connection_made.connect(self.connection_made)
|
|
45
|
+
self.conbus_protocol.on_telegram_sent.connect(self.telegram_sent)
|
|
46
|
+
self.conbus_protocol.on_telegram_received.connect(self.telegram_received)
|
|
47
|
+
self.conbus_protocol.on_timeout.connect(self.timeout)
|
|
48
|
+
self.conbus_protocol.on_failed.connect(self.failed)
|
|
49
|
+
|
|
41
50
|
self.serial_number: str = ""
|
|
42
51
|
self.function_code: str = ""
|
|
43
52
|
self.datapoint_value: int = -1
|
|
44
|
-
self.progress_callback: Optional[Callable[[str], None]] = None
|
|
45
|
-
self.finish_callback: Optional[Callable[[ConbusResponse], None]] = None
|
|
46
53
|
self.service_response: ConbusResponse = ConbusResponse(
|
|
47
54
|
success=False,
|
|
48
55
|
serial_number=self.serial_number,
|
|
@@ -53,8 +60,8 @@ class ConbusScanService(ConbusProtocol):
|
|
|
53
60
|
# Set up logging
|
|
54
61
|
self.logger = logging.getLogger(__name__)
|
|
55
62
|
|
|
56
|
-
def
|
|
57
|
-
"""Handle connection
|
|
63
|
+
def connection_made(self) -> None:
|
|
64
|
+
"""Handle connection made event."""
|
|
58
65
|
self.logger.debug("Connection established, starting scan")
|
|
59
66
|
self.scan_next_datacode()
|
|
60
67
|
|
|
@@ -66,14 +73,13 @@ class ConbusScanService(ConbusProtocol):
|
|
|
66
73
|
"""
|
|
67
74
|
self.datapoint_value += 1
|
|
68
75
|
if self.datapoint_value >= 100:
|
|
69
|
-
|
|
70
|
-
self.finish_callback(self.service_response)
|
|
76
|
+
self.on_finish.emit(self.service_response)
|
|
71
77
|
return False
|
|
72
78
|
|
|
73
79
|
self.logger.debug(f"Scanning next datacode: {self.datapoint_value:02d}")
|
|
74
80
|
data = f"{self.datapoint_value:02d}"
|
|
75
81
|
telegram_body = f"S{self.serial_number}F{self.function_code}D{data}"
|
|
76
|
-
self.sendFrame(telegram_body.encode())
|
|
82
|
+
self.conbus_protocol.sendFrame(telegram_body.encode())
|
|
77
83
|
return True
|
|
78
84
|
|
|
79
85
|
def telegram_sent(self, telegram_sent: str) -> None:
|
|
@@ -96,18 +102,13 @@ class ConbusScanService(ConbusProtocol):
|
|
|
96
102
|
self.service_response.received_telegrams = []
|
|
97
103
|
self.service_response.received_telegrams.append(telegram_received.frame)
|
|
98
104
|
|
|
99
|
-
|
|
100
|
-
self.progress_callback(telegram_received.frame)
|
|
101
|
-
|
|
102
|
-
def timeout(self) -> bool:
|
|
103
|
-
"""Handle timeout event by scanning next data code.
|
|
105
|
+
self.on_progress.emit(telegram_received.frame)
|
|
104
106
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
self.logger.debug(f"Timeout: {
|
|
109
|
-
|
|
110
|
-
return continue_scan
|
|
107
|
+
def timeout(self) -> None:
|
|
108
|
+
"""Handle timeout event by scanning next data code."""
|
|
109
|
+
timeout_seconds = self.conbus_protocol.timeout_seconds
|
|
110
|
+
self.logger.debug(f"Timeout: {timeout_seconds}s")
|
|
111
|
+
self.scan_next_datacode()
|
|
111
112
|
|
|
112
113
|
def failed(self, message: str) -> None:
|
|
113
114
|
"""Handle failed connection event.
|
|
@@ -119,15 +120,12 @@ class ConbusScanService(ConbusProtocol):
|
|
|
119
120
|
self.service_response.success = False
|
|
120
121
|
self.service_response.timestamp = datetime.now()
|
|
121
122
|
self.service_response.error = message
|
|
122
|
-
|
|
123
|
-
self.finish_callback(self.service_response)
|
|
123
|
+
self.on_finish.emit(self.service_response)
|
|
124
124
|
|
|
125
125
|
def scan_module(
|
|
126
126
|
self,
|
|
127
127
|
serial_number: str,
|
|
128
128
|
function_code: str,
|
|
129
|
-
progress_callback: Callable[[str], None],
|
|
130
|
-
finish_callback: Callable[[ConbusResponse], None],
|
|
131
129
|
timeout_seconds: float = 0.25,
|
|
132
130
|
) -> None:
|
|
133
131
|
"""Scan a module for all datapoints by function code.
|
|
@@ -135,16 +133,62 @@ class ConbusScanService(ConbusProtocol):
|
|
|
135
133
|
Args:
|
|
136
134
|
serial_number: 10-digit module serial number.
|
|
137
135
|
function_code: The function code to scan.
|
|
138
|
-
progress_callback: Callback to handle progress.
|
|
139
|
-
finish_callback: Callback function to call when the scan is complete.
|
|
140
136
|
timeout_seconds: Timeout in seconds.
|
|
141
137
|
"""
|
|
142
138
|
self.logger.info("Starting scan_module")
|
|
143
139
|
if timeout_seconds:
|
|
144
|
-
self.timeout_seconds = timeout_seconds
|
|
140
|
+
self.conbus_protocol.timeout_seconds = timeout_seconds
|
|
145
141
|
|
|
146
142
|
self.serial_number = serial_number
|
|
147
143
|
self.function_code = function_code
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
144
|
+
|
|
145
|
+
def set_timeout(self, timeout_seconds: float) -> None:
|
|
146
|
+
"""Set operation timeout.
|
|
147
|
+
|
|
148
|
+
Args:
|
|
149
|
+
timeout_seconds: Timeout in seconds.
|
|
150
|
+
"""
|
|
151
|
+
self.conbus_protocol.timeout_seconds = timeout_seconds
|
|
152
|
+
|
|
153
|
+
def start_reactor(self) -> None:
|
|
154
|
+
"""Start the reactor."""
|
|
155
|
+
self.conbus_protocol.start_reactor()
|
|
156
|
+
|
|
157
|
+
def stop_reactor(self) -> None:
|
|
158
|
+
"""Stop the reactor."""
|
|
159
|
+
self.conbus_protocol.stop_reactor()
|
|
160
|
+
|
|
161
|
+
def __enter__(self) -> "ConbusScanService":
|
|
162
|
+
"""Enter context manager - reset state for singleton reuse.
|
|
163
|
+
|
|
164
|
+
Returns:
|
|
165
|
+
Self for context manager protocol.
|
|
166
|
+
"""
|
|
167
|
+
# Reset state for singleton reuse
|
|
168
|
+
self.serial_number = ""
|
|
169
|
+
self.function_code = ""
|
|
170
|
+
self.datapoint_value = -1
|
|
171
|
+
self.service_response = ConbusResponse(
|
|
172
|
+
success=False,
|
|
173
|
+
serial_number="",
|
|
174
|
+
sent_telegrams=[],
|
|
175
|
+
received_telegrams=[],
|
|
176
|
+
timestamp=datetime.now(),
|
|
177
|
+
)
|
|
178
|
+
return self
|
|
179
|
+
|
|
180
|
+
def __exit__(
|
|
181
|
+
self, _exc_type: Optional[type], _exc_val: Optional[Exception], _exc_tb: Any
|
|
182
|
+
) -> None:
|
|
183
|
+
"""Exit context manager and disconnect signals."""
|
|
184
|
+
# Disconnect protocol signals
|
|
185
|
+
self.conbus_protocol.on_connection_made.disconnect(self.connection_made)
|
|
186
|
+
self.conbus_protocol.on_telegram_sent.disconnect(self.telegram_sent)
|
|
187
|
+
self.conbus_protocol.on_telegram_received.disconnect(self.telegram_received)
|
|
188
|
+
self.conbus_protocol.on_timeout.disconnect(self.timeout)
|
|
189
|
+
self.conbus_protocol.on_failed.disconnect(self.failed)
|
|
190
|
+
# Disconnect service signals
|
|
191
|
+
self.on_progress.disconnect()
|
|
192
|
+
self.on_finish.disconnect()
|
|
193
|
+
# Stop reactor
|
|
194
|
+
self.stop_reactor()
|