conson-xp 1.45.0__py3-none-any.whl → 1.47.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.
Files changed (179) hide show
  1. {conson_xp-1.45.0.dist-info → conson_xp-1.47.0.dist-info}/METADATA +1 -1
  2. conson_xp-1.47.0.dist-info/RECORD +210 -0
  3. xp/__init__.py +3 -2
  4. xp/cli/commands/conbus/conbus.py +1 -1
  5. xp/cli/commands/conbus/conbus_actiontable_commands.py +33 -15
  6. xp/cli/commands/conbus/conbus_autoreport_commands.py +8 -4
  7. xp/cli/commands/conbus/conbus_blink_commands.py +20 -10
  8. xp/cli/commands/conbus/conbus_config_commands.py +2 -1
  9. xp/cli/commands/conbus/conbus_custom_commands.py +4 -2
  10. xp/cli/commands/conbus/conbus_datapoint_commands.py +10 -5
  11. xp/cli/commands/conbus/conbus_discover_commands.py +8 -4
  12. xp/cli/commands/conbus/conbus_event_commands.py +8 -4
  13. xp/cli/commands/conbus/conbus_export_commands.py +8 -4
  14. xp/cli/commands/conbus/conbus_lightlevel_commands.py +16 -8
  15. xp/cli/commands/conbus/conbus_linknumber_commands.py +8 -4
  16. xp/cli/commands/conbus/conbus_modulenumber_commands.py +8 -4
  17. xp/cli/commands/conbus/conbus_msactiontable_commands.py +78 -40
  18. xp/cli/commands/conbus/conbus_output_commands.py +16 -8
  19. xp/cli/commands/conbus/conbus_raw_commands.py +6 -3
  20. xp/cli/commands/conbus/conbus_receive_commands.py +6 -3
  21. xp/cli/commands/conbus/conbus_scan_commands.py +6 -3
  22. xp/cli/commands/file_commands.py +6 -3
  23. xp/cli/commands/homekit/homekit.py +4 -2
  24. xp/cli/commands/homekit/homekit_start_commands.py +2 -1
  25. xp/cli/commands/module_commands.py +8 -4
  26. xp/cli/commands/reverse_proxy_commands.py +8 -4
  27. xp/cli/commands/server/server_commands.py +6 -3
  28. xp/cli/commands/telegram/telegram_blink_commands.py +4 -2
  29. xp/cli/commands/telegram/telegram_checksum_commands.py +4 -2
  30. xp/cli/commands/telegram/telegram_discover_commands.py +2 -1
  31. xp/cli/commands/telegram/telegram_linknumber_commands.py +4 -2
  32. xp/cli/commands/telegram/telegram_parse_commands.py +4 -2
  33. xp/cli/commands/telegram/telegram_version_commands.py +2 -1
  34. xp/cli/commands/term/term_commands.py +4 -2
  35. xp/cli/main.py +2 -1
  36. xp/cli/utils/click_tree.py +6 -3
  37. xp/cli/utils/datapoint_type_choice.py +4 -2
  38. xp/cli/utils/decorators.py +42 -21
  39. xp/cli/utils/error_handlers.py +16 -8
  40. xp/cli/utils/formatters.py +22 -11
  41. xp/cli/utils/module_type_choice.py +4 -2
  42. xp/cli/utils/serial_number_type.py +4 -2
  43. xp/cli/utils/system_function_choice.py +4 -2
  44. xp/cli/utils/xp_module_type.py +4 -2
  45. xp/models/actiontable/actiontable.py +8 -8
  46. xp/models/actiontable/actiontable_type.py +20 -0
  47. xp/models/actiontable/msactiontable_xp20.py +8 -4
  48. xp/models/actiontable/msactiontable_xp24.py +12 -6
  49. xp/models/actiontable/msactiontable_xp33.py +20 -10
  50. xp/models/conbus/conbus.py +8 -4
  51. xp/models/conbus/conbus_autoreport.py +4 -2
  52. xp/models/conbus/conbus_blink.py +4 -2
  53. xp/models/conbus/conbus_client_config.py +6 -3
  54. xp/models/conbus/conbus_connection_status.py +4 -2
  55. xp/models/conbus/conbus_custom.py +4 -2
  56. xp/models/conbus/conbus_datapoint.py +4 -2
  57. xp/models/conbus/conbus_discover.py +6 -3
  58. xp/models/conbus/conbus_event_list.py +4 -2
  59. xp/models/conbus/conbus_event_raw.py +4 -2
  60. xp/models/conbus/conbus_export.py +2 -1
  61. xp/models/conbus/conbus_lightlevel.py +4 -2
  62. xp/models/conbus/conbus_linknumber.py +4 -2
  63. xp/models/conbus/conbus_logger_config.py +8 -4
  64. xp/models/conbus/conbus_output.py +4 -2
  65. xp/models/conbus/conbus_raw.py +4 -2
  66. xp/models/conbus/conbus_receive.py +4 -2
  67. xp/models/conbus/conbus_writeconfig.py +4 -2
  68. xp/models/config/conson_module_config.py +8 -4
  69. xp/models/homekit/homekit_accessory.py +4 -2
  70. xp/models/homekit/homekit_config.py +12 -6
  71. xp/models/log_entry.py +16 -8
  72. xp/models/protocol/conbus_protocol.py +36 -18
  73. xp/models/response.py +12 -8
  74. xp/models/telegram/action_type.py +4 -2
  75. xp/models/telegram/datapoint_type.py +4 -2
  76. xp/models/telegram/event_telegram.py +14 -7
  77. xp/models/telegram/event_type.py +2 -1
  78. xp/models/telegram/input_action_type.py +2 -1
  79. xp/models/telegram/input_type.py +2 -1
  80. xp/models/telegram/module_type.py +24 -12
  81. xp/models/telegram/module_type_code.py +2 -1
  82. xp/models/telegram/output_telegram.py +16 -10
  83. xp/models/telegram/reply_telegram.py +24 -13
  84. xp/models/telegram/system_function.py +6 -3
  85. xp/models/telegram/system_telegram.py +10 -6
  86. xp/models/telegram/telegram.py +2 -1
  87. xp/models/telegram/telegram_type.py +2 -1
  88. xp/models/telegram/timeparam_type.py +2 -1
  89. xp/models/term/connection_state.py +4 -2
  90. xp/models/term/module_state.py +2 -1
  91. xp/models/term/protocol_keys_config.py +6 -3
  92. xp/models/term/status_message.py +2 -1
  93. xp/models/term/telegram_display.py +2 -1
  94. xp/models/write_config_type.py +4 -2
  95. xp/services/actiontable/actiontable_serializer.py +34 -41
  96. xp/services/actiontable/download_state_machine.py +281 -0
  97. xp/services/actiontable/msactiontable_xp20_serializer.py +77 -49
  98. xp/services/actiontable/msactiontable_xp24_serializer.py +78 -53
  99. xp/services/actiontable/msactiontable_xp33_serializer.py +39 -9
  100. xp/services/actiontable/serializer_protocol.py +76 -0
  101. xp/services/conbus/actiontable/actiontable_download_service.py +134 -280
  102. xp/services/conbus/actiontable/actiontable_list_service.py +17 -4
  103. xp/services/conbus/actiontable/actiontable_show_service.py +10 -6
  104. xp/services/conbus/actiontable/actiontable_upload_service.py +17 -9
  105. xp/services/conbus/conbus_blink_all_service.py +16 -8
  106. xp/services/conbus/conbus_blink_service.py +14 -7
  107. xp/services/conbus/conbus_custom_service.py +16 -8
  108. xp/services/conbus/conbus_datapoint_queryall_service.py +18 -9
  109. xp/services/conbus/conbus_datapoint_service.py +18 -9
  110. xp/services/conbus/conbus_discover_service.py +24 -13
  111. xp/services/conbus/conbus_event_list_service.py +11 -7
  112. xp/services/conbus/conbus_event_raw_service.py +18 -10
  113. xp/services/conbus/conbus_export_service.py +28 -14
  114. xp/services/conbus/conbus_output_service.py +18 -10
  115. xp/services/conbus/conbus_raw_service.py +16 -8
  116. xp/services/conbus/conbus_receive_service.py +18 -10
  117. xp/services/conbus/conbus_scan_service.py +18 -10
  118. xp/services/conbus/msactiontable/msactiontable_upload_service.py +17 -9
  119. xp/services/conbus/write_config_service.py +18 -9
  120. xp/services/homekit/homekit_cache_service.py +12 -6
  121. xp/services/homekit/homekit_conbus_service.py +12 -6
  122. xp/services/homekit/homekit_config_validator.py +34 -17
  123. xp/services/homekit/homekit_conson_validator.py +18 -9
  124. xp/services/homekit/homekit_dimminglight.py +14 -7
  125. xp/services/homekit/homekit_dimminglight_service.py +14 -7
  126. xp/services/homekit/homekit_hap_service.py +18 -9
  127. xp/services/homekit/homekit_lightbulb.py +10 -5
  128. xp/services/homekit/homekit_lightbulb_service.py +10 -5
  129. xp/services/homekit/homekit_module_service.py +8 -4
  130. xp/services/homekit/homekit_outlet.py +14 -7
  131. xp/services/homekit/homekit_outlet_service.py +12 -6
  132. xp/services/homekit/homekit_service.py +24 -12
  133. xp/services/log_file_service.py +16 -8
  134. xp/services/module_type_service.py +10 -5
  135. xp/services/protocol/conbus_event_protocol.py +140 -21
  136. xp/services/protocol/conbus_protocol.py +36 -19
  137. xp/services/protocol/protocol_factory.py +12 -6
  138. xp/services/protocol/telegram_protocol.py +12 -6
  139. xp/services/reverse_proxy_service.py +26 -14
  140. xp/services/server/base_server_service.py +42 -23
  141. xp/services/server/client_buffer_manager.py +12 -7
  142. xp/services/server/cp20_server_service.py +10 -7
  143. xp/services/server/device_service_factory.py +12 -8
  144. xp/services/server/server_service.py +18 -11
  145. xp/services/server/xp130_server_service.py +11 -8
  146. xp/services/server/xp20_server_service.py +16 -10
  147. xp/services/server/xp230_server_service.py +10 -7
  148. xp/services/server/xp24_server_service.py +22 -13
  149. xp/services/server/xp33_server_service.py +44 -25
  150. xp/services/telegram/telegram_blink_service.py +14 -8
  151. xp/services/telegram/telegram_checksum_service.py +12 -7
  152. xp/services/telegram/telegram_datapoint_service.py +14 -9
  153. xp/services/telegram/telegram_discover_service.py +28 -15
  154. xp/services/telegram/telegram_link_number_service.py +18 -10
  155. xp/services/telegram/telegram_output_service.py +24 -12
  156. xp/services/telegram/telegram_service.py +22 -11
  157. xp/services/telegram/telegram_version_service.py +14 -8
  158. xp/services/term/protocol_monitor_service.py +30 -16
  159. xp/services/term/state_monitor_service.py +39 -21
  160. xp/term/protocol.py +12 -6
  161. xp/term/state.py +12 -7
  162. xp/term/widgets/help_menu.py +6 -3
  163. xp/term/widgets/modules_list.py +20 -10
  164. xp/term/widgets/protocol_log.py +12 -6
  165. xp/term/widgets/status_footer.py +10 -5
  166. xp/utils/checksum.py +6 -3
  167. xp/utils/dependencies.py +26 -31
  168. xp/utils/event_helper.py +6 -4
  169. xp/utils/logging.py +6 -3
  170. xp/utils/serialization.py +30 -16
  171. xp/utils/state_machine.py +16 -9
  172. xp/utils/time_utils.py +6 -3
  173. conson_xp-1.45.0.dist-info/RECORD +0 -210
  174. xp/services/conbus/msactiontable/msactiontable_download_service.py +0 -275
  175. xp/services/conbus/msactiontable/msactiontable_list_service.py +0 -100
  176. xp/services/conbus/msactiontable/msactiontable_show_service.py +0 -89
  177. {conson_xp-1.45.0.dist-info → conson_xp-1.47.0.dist-info}/WHEEL +0 -0
  178. {conson_xp-1.45.0.dist-info → conson_xp-1.47.0.dist-info}/entry_points.txt +0 -0
  179. {conson_xp-1.45.0.dist-info → conson_xp-1.47.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,4 +1,5 @@
1
- """Conbus Event Protocol for XP telegram communication.
1
+ """
2
+ Conbus Event Protocol for XP telegram communication.
2
3
 
3
4
  This module implements the Twisted protocol for Conbus communication.
4
5
  """
@@ -21,13 +22,21 @@ from xp.models import ConbusClientConfig, ModuleTypeCode
21
22
  from xp.models.protocol.conbus_protocol import (
22
23
  TelegramReceivedEvent,
23
24
  )
25
+ from xp.models.telegram.datapoint_type import DataPointType
26
+ from xp.models.telegram.reply_telegram import ReplyTelegram
24
27
  from xp.models.telegram.system_function import SystemFunction
25
28
  from xp.models.telegram.telegram_type import TelegramType
29
+ from xp.services import TelegramService
26
30
  from xp.utils import calculate_checksum
27
31
 
32
+ # Constants
33
+ NO_ERROR_CODE = "00"
34
+ CHUNK_HEADER_LENGTH = 2 # data_value format: 2-char counter + actiontable chunk
35
+
28
36
 
29
37
  class ConbusEventProtocol(protocol.Protocol, protocol.ClientFactory):
30
- """Twisted protocol for XP telegram communication.
38
+ """
39
+ Twisted protocol for XP telegram communication.
31
40
 
32
41
  Attributes:
33
42
  buffer: Buffer for incoming telegram data.
@@ -47,6 +56,10 @@ class ConbusEventProtocol(protocol.Protocol, protocol.ClientFactory):
47
56
  on_telegram_sent: Signal emitted when a telegram is sent.
48
57
  on_data_received: Signal emitted when data is received.
49
58
  on_telegram_received: Signal emitted when a telegram is received.
59
+ on_invalid_telegram_received: Signal emitted when invalid telegram received.
60
+ on_read_datapoint_received: Signal emitted when read datapoint reply received.
61
+ on_actiontable_chunk_received: Signal emitted when actiontable chunk received.
62
+ on_eof_received: Signal emitted when EOF telegram received.
50
63
  on_timeout: Signal emitted when timeout occurs.
51
64
  on_failed: Signal emitted when operation fails.
52
65
  on_start_reactor: Signal emitted when reactor starts.
@@ -68,6 +81,11 @@ class ConbusEventProtocol(protocol.Protocol, protocol.ClientFactory):
68
81
  on_telegram_sent: Signal = Signal(bytes)
69
82
  on_data_received: Signal = Signal(bytes)
70
83
  on_telegram_received: Signal = Signal(TelegramReceivedEvent)
84
+ on_invalid_telegram_received: Signal = Signal(TelegramReceivedEvent)
85
+ on_read_datapoint_received: Signal = Signal(ReplyTelegram)
86
+ on_actiontable_chunk_received: Signal = Signal(ReplyTelegram, str)
87
+ on_eof_received: Signal = Signal(ReplyTelegram)
88
+
71
89
  on_timeout: Signal = Signal()
72
90
  on_failed: Signal = Signal(str)
73
91
  on_start_reactor: Signal = Signal()
@@ -77,12 +95,15 @@ class ConbusEventProtocol(protocol.Protocol, protocol.ClientFactory):
77
95
  self,
78
96
  cli_config: ConbusClientConfig,
79
97
  reactor: PosixReactorBase,
98
+ telegram_service: TelegramService,
80
99
  ) -> None:
81
- """Initialize ConbusProtocol.
100
+ """
101
+ Initialize ConbusProtocol.
82
102
 
83
103
  Args:
84
104
  cli_config: Configuration for Conbus client connection.
85
105
  reactor: Twisted reactor for event handling.
106
+ telegram_service: Telegram service for parsing telegrams.
86
107
  """
87
108
  self.buffer = b""
88
109
  self.logger = logging.getLogger(__name__)
@@ -90,12 +111,14 @@ class ConbusEventProtocol(protocol.Protocol, protocol.ClientFactory):
90
111
  self._reactor = reactor
91
112
  self.timeout_seconds = self.cli_config.timeout
92
113
  self.timeout_call: Optional[DelayedCall] = None
114
+ self.telegram_service = telegram_service
93
115
 
94
116
  def connectionMade(self) -> None:
95
- """Handle connection established event.
117
+ """
118
+ Handle connection established event.
96
119
 
97
- Called when TCP connection is successfully established.
98
- Starts inactivity timeout monitoring.
120
+ Called when TCP connection is successfully established. Starts inactivity
121
+ timeout monitoring.
99
122
  """
100
123
  self.logger.debug("connectionMade")
101
124
  self.on_connection_made.emit()
@@ -104,7 +127,8 @@ class ConbusEventProtocol(protocol.Protocol, protocol.ClientFactory):
104
127
  self._reset_timeout()
105
128
 
106
129
  def wait(self, wait_timeout: Optional[float] = None) -> None:
107
- """Wait for incoming telegrams with optional timeout override.
130
+ """
131
+ Wait for incoming telegrams with optional timeout override.
108
132
 
109
133
  Args:
110
134
  wait_timeout: Optional timeout in seconds to override default.
@@ -114,7 +138,8 @@ class ConbusEventProtocol(protocol.Protocol, protocol.ClientFactory):
114
138
  self._reset_timeout()
115
139
 
116
140
  def dataReceived(self, data: bytes) -> None:
117
- """Handle received data from TCP connection.
141
+ """
142
+ Handle received data from TCP connection.
118
143
 
119
144
  Parses incoming telegram frames and dispatches events.
120
145
 
@@ -171,10 +196,51 @@ class ConbusEventProtocol(protocol.Protocol, protocol.ClientFactory):
171
196
  checksum=checksum,
172
197
  checksum_valid=checksum_valid,
173
198
  )
174
- self.on_telegram_received.emit(telegram_received)
199
+ self.emit_telegram_received(telegram_received)
200
+
201
+ def emit_telegram_received(self, telegram_received: TelegramReceivedEvent) -> None:
202
+ """
203
+ Handle telegram received event.
204
+
205
+ Args:
206
+ telegram_received: The telegram received event.
207
+ """
208
+ self.logger.debug(f"Received {telegram_received}")
209
+ self.on_telegram_received.emit(telegram_received)
210
+
211
+ # Filter invalid telegrams
212
+ if not telegram_received.checksum_valid:
213
+ self.logger.debug("Filtered: invalid checksum")
214
+ self.on_invalid_telegram_received.emit(telegram_received)
215
+ return
216
+
217
+ if telegram_received.telegram_type != TelegramType.REPLY.value:
218
+ self.logger.debug(
219
+ f"Filtered: not a reply (got {telegram_received.telegram_type})"
220
+ )
221
+ self.on_invalid_telegram_received.emit(telegram_received)
222
+ return
223
+
224
+ reply_telegram = self.telegram_service.parse_reply_telegram(
225
+ telegram_received.frame
226
+ )
227
+
228
+ if reply_telegram.system_function == SystemFunction.READ_DATAPOINT:
229
+ self.on_read_datapoint_received.emit(reply_telegram)
230
+ return
231
+
232
+ if reply_telegram.system_function == SystemFunction.ACTIONTABLE:
233
+ actiontable_chunk = reply_telegram.data_value[CHUNK_HEADER_LENGTH:]
234
+ self.on_actiontable_chunk_received.emit(reply_telegram, actiontable_chunk)
235
+ return
236
+
237
+ if reply_telegram.system_function == SystemFunction.EOF:
238
+ self.on_eof_received.emit(reply_telegram)
239
+ return
175
240
 
176
241
  def sendFrame(self, data: bytes) -> None:
177
- """Send telegram frame.
242
+ """
243
+ Send telegram frame.
178
244
 
179
245
  Args:
180
246
  data: Raw telegram payload (without checksum/framing).
@@ -203,7 +269,8 @@ class ConbusEventProtocol(protocol.Protocol, protocol.ClientFactory):
203
269
  system_function: SystemFunction,
204
270
  data_value: str,
205
271
  ) -> None:
206
- """Send telegram with specified parameters.
272
+ """
273
+ Send telegram with specified parameters.
207
274
 
208
275
  Args:
209
276
  telegram_type: Type of telegram to send.
@@ -222,7 +289,8 @@ class ConbusEventProtocol(protocol.Protocol, protocol.ClientFactory):
222
289
  def send_event_telegram(
223
290
  self, module_type_code: ModuleTypeCode, link_number: int, input_number: int
224
291
  ) -> None:
225
- """Send telegram with specified parameters.
292
+ """
293
+ Send telegram with specified parameters.
226
294
 
227
295
  Args:
228
296
  module_type_code: Type code of module.
@@ -235,7 +303,8 @@ class ConbusEventProtocol(protocol.Protocol, protocol.ClientFactory):
235
303
  self.send_raw_telegram(payload)
236
304
 
237
305
  def send_raw_telegram(self, payload: str) -> None:
238
- """Send telegram with specified parameters.
306
+ """
307
+ Send telegram with specified parameters.
239
308
 
240
309
  Args:
241
310
  payload: Telegram to send.
@@ -243,6 +312,48 @@ class ConbusEventProtocol(protocol.Protocol, protocol.ClientFactory):
243
312
  self.telegram_queue.put_nowait(payload.encode())
244
313
  self.call_later(0.0, self.start_queue_manager)
245
314
 
315
+ def send_error_status_query(self, serial_number: str) -> None:
316
+ """
317
+ Send error status query telegram.
318
+
319
+ Args:
320
+ serial_number: Device serial number.
321
+ """
322
+ self.send_telegram(
323
+ telegram_type=TelegramType.SYSTEM,
324
+ serial_number=serial_number,
325
+ system_function=SystemFunction.READ_DATAPOINT,
326
+ data_value=DataPointType.MODULE_ERROR_CODE.value,
327
+ )
328
+
329
+ def send_download_request(self, serial_number: str) -> None:
330
+ """
331
+ Send download request telegram.
332
+
333
+ Args:
334
+ serial_number: Device serial number.
335
+ """
336
+ self.send_telegram(
337
+ telegram_type=TelegramType.SYSTEM,
338
+ serial_number=serial_number,
339
+ system_function=SystemFunction.DOWNLOAD_ACTIONTABLE,
340
+ data_value=NO_ERROR_CODE,
341
+ )
342
+
343
+ def send_ack(self, serial_number: str) -> None:
344
+ """
345
+ Send ACK telegram.
346
+
347
+ Args:
348
+ serial_number: Device serial number.
349
+ """
350
+ self.send_telegram(
351
+ telegram_type=TelegramType.SYSTEM,
352
+ serial_number=serial_number,
353
+ system_function=SystemFunction.ACK,
354
+ data_value=NO_ERROR_CODE,
355
+ )
356
+
246
357
  def call_later(
247
358
  self,
248
359
  delay: float,
@@ -250,7 +361,8 @@ class ConbusEventProtocol(protocol.Protocol, protocol.ClientFactory):
250
361
  *args: object,
251
362
  **kw: object,
252
363
  ) -> DelayedCall:
253
- """Schedule a callable to be called later.
364
+ """
365
+ Schedule a callable to be called later.
254
366
 
255
367
  Args:
256
368
  delay: Delay in seconds before calling.
@@ -264,7 +376,8 @@ class ConbusEventProtocol(protocol.Protocol, protocol.ClientFactory):
264
376
  return self._reactor.callLater(delay, callable_action, *args, **kw)
265
377
 
266
378
  def buildProtocol(self, addr: IAddress) -> protocol.Protocol:
267
- """Build protocol instance for connection.
379
+ """
380
+ Build protocol instance for connection.
268
381
 
269
382
  Args:
270
383
  addr: Address of the connection.
@@ -276,7 +389,8 @@ class ConbusEventProtocol(protocol.Protocol, protocol.ClientFactory):
276
389
  return self
277
390
 
278
391
  def clientConnectionFailed(self, connector: IConnector, reason: Failure) -> None:
279
- """Handle client connection failure.
392
+ """
393
+ Handle client connection failure.
280
394
 
281
395
  Args:
282
396
  connector: Connection connector instance.
@@ -288,7 +402,8 @@ class ConbusEventProtocol(protocol.Protocol, protocol.ClientFactory):
288
402
  self._cancel_timeout()
289
403
 
290
404
  def clientConnectionLost(self, connector: IConnector, reason: Failure) -> None:
291
- """Handle client connection lost event.
405
+ """
406
+ Handle client connection lost event.
292
407
 
293
408
  Args:
294
409
  connector: Connection connector instance.
@@ -304,7 +419,8 @@ class ConbusEventProtocol(protocol.Protocol, protocol.ClientFactory):
304
419
  self.on_timeout.emit()
305
420
 
306
421
  def connection_failed(self, reason: Failure) -> None:
307
- """Handle connection failure.
422
+ """
423
+ Handle connection failure.
308
424
 
309
425
  Args:
310
426
  reason: Failure reason details.
@@ -339,7 +455,8 @@ class ConbusEventProtocol(protocol.Protocol, protocol.ClientFactory):
339
455
  self.logger.debug(f"Reactor stop failed (likely already stopped): {e}")
340
456
 
341
457
  def connect(self) -> None:
342
- """Connect to TCP server.
458
+ """
459
+ Connect to TCP server.
343
460
 
344
461
  Automatically detects and integrates with running asyncio event loop if present.
345
462
  """
@@ -397,7 +514,8 @@ class ConbusEventProtocol(protocol.Protocol, protocol.ClientFactory):
397
514
  self.call_later(later, self.process_telegram_queue)
398
515
 
399
516
  def set_event_loop(self, event_loop: asyncio.AbstractEventLoop) -> None:
400
- """Change the event loop.
517
+ """
518
+ Change the event loop.
401
519
 
402
520
  Args:
403
521
  event_loop: the event loop instance.
@@ -414,7 +532,8 @@ class ConbusEventProtocol(protocol.Protocol, protocol.ClientFactory):
414
532
  self.logger.info("Set reactor to running state")
415
533
 
416
534
  def __enter__(self) -> "ConbusEventProtocol":
417
- """Enter context manager.
535
+ """
536
+ Enter context manager.
418
537
 
419
538
  Returns:
420
539
  Self for context management.
@@ -1,4 +1,5 @@
1
- """Conbus Protocol for XP telegram communication.
1
+ """
2
+ Conbus Protocol for XP telegram communication.
2
3
 
3
4
  This module implements the Twisted protocol for Conbus communication.
4
5
  """
@@ -22,7 +23,8 @@ from xp.utils import calculate_checksum
22
23
 
23
24
 
24
25
  class ConbusProtocol(protocol.Protocol, protocol.ClientFactory):
25
- """Twisted protocol for XP telegram communication.
26
+ """
27
+ Twisted protocol for XP telegram communication.
26
28
 
27
29
  Attributes:
28
30
  buffer: Buffer for incoming telegram data.
@@ -40,7 +42,8 @@ class ConbusProtocol(protocol.Protocol, protocol.ClientFactory):
40
42
  cli_config: ConbusClientConfig,
41
43
  reactor: PosixReactorBase,
42
44
  ) -> None:
43
- """Initialize ConbusProtocol.
45
+ """
46
+ Initialize ConbusProtocol.
44
47
 
45
48
  Args:
46
49
  cli_config: Configuration for Conbus client connection.
@@ -54,10 +57,11 @@ class ConbusProtocol(protocol.Protocol, protocol.ClientFactory):
54
57
  self.timeout_call: Optional[DelayedCall] = None
55
58
 
56
59
  def connectionMade(self) -> None:
57
- """Handle connection established event.
60
+ """
61
+ Handle connection established event.
58
62
 
59
- Called when TCP connection is successfully established.
60
- Starts inactivity timeout monitoring.
63
+ Called when TCP connection is successfully established. Starts inactivity
64
+ timeout monitoring.
61
65
  """
62
66
  self.logger.debug("connectionMade")
63
67
  self.connection_established()
@@ -65,7 +69,8 @@ class ConbusProtocol(protocol.Protocol, protocol.ClientFactory):
65
69
  self._reset_timeout()
66
70
 
67
71
  def dataReceived(self, data: bytes) -> None:
68
- """Handle received data from TCP connection.
72
+ """
73
+ Handle received data from TCP connection.
69
74
 
70
75
  Parses incoming telegram frames and dispatches events.
71
76
 
@@ -124,7 +129,8 @@ class ConbusProtocol(protocol.Protocol, protocol.ClientFactory):
124
129
  self.telegram_received(telegram_received)
125
130
 
126
131
  def sendFrame(self, data: bytes) -> None:
127
- """Send telegram frame.
132
+ """
133
+ Send telegram frame.
128
134
 
129
135
  Args:
130
136
  data: Raw telegram payload (without checksum/framing).
@@ -153,7 +159,8 @@ class ConbusProtocol(protocol.Protocol, protocol.ClientFactory):
153
159
  system_function: SystemFunction,
154
160
  data_value: str,
155
161
  ) -> None:
156
- """Send telegram with specified parameters.
162
+ """
163
+ Send telegram with specified parameters.
157
164
 
158
165
  Args:
159
166
  telegram_type: Type of telegram to send.
@@ -170,7 +177,8 @@ class ConbusProtocol(protocol.Protocol, protocol.ClientFactory):
170
177
  self.sendFrame(payload.encode())
171
178
 
172
179
  def buildProtocol(self, addr: IAddress) -> protocol.Protocol:
173
- """Build protocol instance for connection.
180
+ """
181
+ Build protocol instance for connection.
174
182
 
175
183
  Args:
176
184
  addr: Address of the connection.
@@ -182,7 +190,8 @@ class ConbusProtocol(protocol.Protocol, protocol.ClientFactory):
182
190
  return self
183
191
 
184
192
  def clientConnectionFailed(self, connector: IConnector, reason: Failure) -> None:
185
- """Handle client connection failure.
193
+ """
194
+ Handle client connection failure.
186
195
 
187
196
  Args:
188
197
  connector: Connection connector instance.
@@ -194,7 +203,8 @@ class ConbusProtocol(protocol.Protocol, protocol.ClientFactory):
194
203
  self._stop_reactor()
195
204
 
196
205
  def clientConnectionLost(self, connector: IConnector, reason: Failure) -> None:
197
- """Handle client connection lost event.
206
+ """
207
+ Handle client connection lost event.
198
208
 
199
209
  Args:
200
210
  connector: Connection connector instance.
@@ -206,7 +216,8 @@ class ConbusProtocol(protocol.Protocol, protocol.ClientFactory):
206
216
  self._stop_reactor()
207
217
 
208
218
  def timeout(self) -> bool:
209
- """Handle timeout event.
219
+ """
220
+ Handle timeout event.
210
221
 
211
222
  Returns:
212
223
  True to continue waiting for next timeout, False to stop.
@@ -216,7 +227,8 @@ class ConbusProtocol(protocol.Protocol, protocol.ClientFactory):
216
227
  return False
217
228
 
218
229
  def connection_failed(self, reason: Failure) -> None:
219
- """Handle connection failure.
230
+ """
231
+ Handle connection failure.
220
232
 
221
233
  Args:
222
234
  reason: Failure reason details.
@@ -262,7 +274,8 @@ class ConbusProtocol(protocol.Protocol, protocol.ClientFactory):
262
274
  self.reactor.run()
263
275
 
264
276
  def __enter__(self) -> "ConbusProtocol":
265
- """Enter context manager.
277
+ """
278
+ Enter context manager.
266
279
 
267
280
  Returns:
268
281
  Self for context management.
@@ -282,7 +295,8 @@ class ConbusProtocol(protocol.Protocol, protocol.ClientFactory):
282
295
  """Override methods."""
283
296
 
284
297
  def telegram_sent(self, telegram_sent: str) -> None:
285
- """Override callback when telegram has been sent.
298
+ """
299
+ Override callback when telegram has been sent.
286
300
 
287
301
  Args:
288
302
  telegram_sent: The telegram that was sent.
@@ -290,7 +304,8 @@ class ConbusProtocol(protocol.Protocol, protocol.ClientFactory):
290
304
  pass
291
305
 
292
306
  def telegram_received(self, telegram_received: TelegramReceivedEvent) -> None:
293
- """Override callback when telegram is received.
307
+ """
308
+ Override callback when telegram is received.
294
309
 
295
310
  Args:
296
311
  telegram_received: Event containing received telegram details.
@@ -302,7 +317,8 @@ class ConbusProtocol(protocol.Protocol, protocol.ClientFactory):
302
317
  pass
303
318
 
304
319
  def connection_lost(self, reason: Failure) -> None:
305
- """Override callback when connection is lost.
320
+ """
321
+ Override callback when connection is lost.
306
322
 
307
323
  Args:
308
324
  reason: Reason for connection loss.
@@ -310,7 +326,8 @@ class ConbusProtocol(protocol.Protocol, protocol.ClientFactory):
310
326
  pass
311
327
 
312
328
  def failed(self, message: str) -> None:
313
- """Override callback when connection failed.
329
+ """
330
+ Override callback when connection failed.
314
331
 
315
332
  Args:
316
333
  message: Error message describing the failure.
@@ -1,4 +1,5 @@
1
- """Protocol Factory for Twisted protocol creation.
1
+ """
2
+ Protocol Factory for Twisted protocol creation.
2
3
 
3
4
  This module provides factory classes for protocol instantiation.
4
5
  """
@@ -18,7 +19,8 @@ from xp.services.protocol import TelegramProtocol
18
19
 
19
20
 
20
21
  class TelegramFactory(protocol.ClientFactory):
21
- """Factory for creating Telegram protocol instances.
22
+ """
23
+ Factory for creating Telegram protocol instances.
22
24
 
23
25
  Attributes:
24
26
  event_bus: Event bus for dispatching protocol events.
@@ -33,7 +35,8 @@ class TelegramFactory(protocol.ClientFactory):
33
35
  telegram_protocol: TelegramProtocol,
34
36
  connector: IConnector,
35
37
  ) -> None:
36
- """Initialize TelegramFactory.
38
+ """
39
+ Initialize TelegramFactory.
37
40
 
38
41
  Args:
39
42
  event_bus: Event bus for protocol events.
@@ -46,7 +49,8 @@ class TelegramFactory(protocol.ClientFactory):
46
49
  self.logger = logging.getLogger(__name__)
47
50
 
48
51
  def buildProtocol(self, addr: IAddress) -> TelegramProtocol:
49
- """Build protocol instance for connection.
52
+ """
53
+ Build protocol instance for connection.
50
54
 
51
55
  Args:
52
56
  addr: Address of the connection.
@@ -58,7 +62,8 @@ class TelegramFactory(protocol.ClientFactory):
58
62
  return self.telegram_protocol
59
63
 
60
64
  def clientConnectionFailed(self, connector: IConnector, reason: Failure) -> None:
61
- """Handle connection failure event.
65
+ """
66
+ Handle connection failure event.
62
67
 
63
68
  Args:
64
69
  connector: Connection connector instance.
@@ -68,7 +73,8 @@ class TelegramFactory(protocol.ClientFactory):
68
73
  self.connector.stop()
69
74
 
70
75
  def clientConnectionLost(self, connector: IConnector, reason: Failure) -> None:
71
- """Handle connection lost event.
76
+ """
77
+ Handle connection lost event.
72
78
 
73
79
  Args:
74
80
  connector: Connection connector instance.
@@ -1,4 +1,5 @@
1
- """Telegram Protocol for XP telegram communication.
1
+ """
2
+ Telegram Protocol for XP telegram communication.
2
3
 
3
4
  This module provides the protocol implementation for telegram-based communication.
4
5
  """
@@ -20,7 +21,8 @@ from xp.utils import calculate_checksum
20
21
 
21
22
 
22
23
  class TelegramProtocol(protocol.Protocol):
23
- """Twisted protocol for XP telegram communication with built-in debouncing.
24
+ """
25
+ Twisted protocol for XP telegram communication with built-in debouncing.
24
26
 
25
27
  Automatically deduplicates identical telegram frames sent within a
26
28
  configurable time window (default 50ms).
@@ -38,7 +40,8 @@ class TelegramProtocol(protocol.Protocol):
38
40
  event_bus: EventBus
39
41
 
40
42
  def __init__(self, event_bus: EventBus, debounce_ms: int = 50) -> None:
41
- """Initialize TelegramProtocol.
43
+ """
44
+ Initialize TelegramProtocol.
42
45
 
43
46
  Args:
44
47
  event_bus: Event bus for dispatching protocol events.
@@ -64,7 +67,8 @@ class TelegramProtocol(protocol.Protocol):
64
67
  self.logger.error(f"Error scheduling async handler: {e}", exc_info=True)
65
68
 
66
69
  def _on_task_done(self, task: asyncio.Task) -> None:
67
- """Handle async task completion.
70
+ """
71
+ Handle async task completion.
68
72
 
69
73
  Args:
70
74
  task: Completed async task.
@@ -92,7 +96,8 @@ class TelegramProtocol(protocol.Protocol):
92
96
  )
93
97
 
94
98
  def dataReceived(self, data: bytes) -> None:
95
- """Handle received data from Twisted.
99
+ """
100
+ Handle received data from Twisted.
96
101
 
97
102
  Args:
98
103
  data: Raw bytes received from connection.
@@ -164,7 +169,8 @@ class TelegramProtocol(protocol.Protocol):
164
169
  )
165
170
 
166
171
  def sendFrame(self, data: bytes) -> None:
167
- """Send telegram frame.
172
+ """
173
+ Send telegram frame.
168
174
 
169
175
  Args:
170
176
  data: Raw telegram payload (without checksum/framing).