conson-xp 1.46.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.46.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/{conbus/actiontable/actiontable_download_state_machine.py → actiontable/download_state_machine.py} +13 -8
  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 +63 -29
  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 +46 -24
  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 +25 -30
  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.46.0.dist-info/RECORD +0 -211
  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.46.0.dist-info → conson_xp-1.47.0.dist-info}/WHEEL +0 -0
  178. {conson_xp-1.46.0.dist-info → conson_xp-1.47.0.dist-info}/entry_points.txt +0 -0
  179. {conson_xp-1.46.0.dist-info → conson_xp-1.47.0.dist-info}/licenses/LICENSE +0 -0
xp/term/protocol.py CHANGED
@@ -13,7 +13,8 @@ from xp.term.widgets.status_footer import StatusFooterWidget
13
13
 
14
14
 
15
15
  class ProtocolMonitorApp(App[None]):
16
- """Textual app for real-time protocol monitoring.
16
+ """
17
+ Textual app for real-time protocol monitoring.
17
18
 
18
19
  Displays live RX/TX telegram stream from Conbus server in an interactive
19
20
  terminal interface with keyboard shortcuts for control.
@@ -38,7 +39,8 @@ class ProtocolMonitorApp(App[None]):
38
39
  ]
39
40
 
40
41
  def __init__(self, protocol_service: ProtocolMonitorService) -> None:
41
- """Initialize the Protocol Monitor app.
42
+ """
43
+ Initialize the Protocol Monitor app.
42
44
 
43
45
  Args:
44
46
  protocol_service: ProtocolMonitorService for protocol operations.
@@ -50,7 +52,8 @@ class ProtocolMonitorApp(App[None]):
50
52
  self.footer_widget: Optional[StatusFooterWidget] = None
51
53
 
52
54
  def compose(self) -> ComposeResult:
53
- """Compose the app layout with widgets.
55
+ """
56
+ Compose the app layout with widgets.
54
57
 
55
58
  Yields:
56
59
  ProtocolLogWidget and Footer widgets.
@@ -71,7 +74,8 @@ class ProtocolMonitorApp(App[None]):
71
74
  yield self.footer_widget
72
75
 
73
76
  async def on_mount(self) -> None:
74
- """Initialize app after UI is mounted.
77
+ """
78
+ Initialize app after UI is mounted.
75
79
 
76
80
  Delays connection by 0.5s to let UI render first.
77
81
  """
@@ -82,7 +86,8 @@ class ProtocolMonitorApp(App[None]):
82
86
  self.protocol_service.connect()
83
87
 
84
88
  def action_toggle_connection(self) -> None:
85
- """Toggle connection on 'c' key press.
89
+ """
90
+ Toggle connection on 'c' key press.
86
91
 
87
92
  Connects if disconnected/failed, disconnects if connected/connecting.
88
93
  """
@@ -94,7 +99,8 @@ class ProtocolMonitorApp(App[None]):
94
99
  self.protocol_widget.clear_log()
95
100
 
96
101
  def on_key(self, event: Any) -> None:
97
- """Handle key press events for protocol keys.
102
+ """
103
+ Handle key press events for protocol keys.
98
104
 
99
105
  Args:
100
106
  event: Key press event from Textual.
xp/term/state.py CHANGED
@@ -11,7 +11,8 @@ from xp.term.widgets.status_footer import StatusFooterWidget
11
11
 
12
12
 
13
13
  class StateMonitorApp(App[None]):
14
- """Textual app for module state monitoring.
14
+ """
15
+ Textual app for module state monitoring.
15
16
 
16
17
  Displays module states from Conson configuration in an interactive
17
18
  terminal interface with real-time updates.
@@ -35,7 +36,8 @@ class StateMonitorApp(App[None]):
35
36
  ]
36
37
 
37
38
  def __init__(self, state_service: StateMonitorService) -> None:
38
- """Initialize the State Monitor app.
39
+ """
40
+ Initialize the State Monitor app.
39
41
 
40
42
  Args:
41
43
  state_service: StateMonitorService for module state operations.
@@ -46,7 +48,8 @@ class StateMonitorApp(App[None]):
46
48
  self.footer_widget: Optional[StatusFooterWidget] = None
47
49
 
48
50
  def compose(self) -> ComposeResult:
49
- """Compose the app layout with widgets.
51
+ """
52
+ Compose the app layout with widgets.
50
53
 
51
54
  Yields:
52
55
  ModulesListWidget and StatusFooterWidget.
@@ -62,10 +65,11 @@ class StateMonitorApp(App[None]):
62
65
  yield self.footer_widget
63
66
 
64
67
  async def on_mount(self) -> None:
65
- """Initialize app after UI is mounted.
68
+ """
69
+ Initialize app after UI is mounted.
66
70
 
67
- Delays connection by 0.5s to let UI render first.
68
- Sets up automatic screen refresh every second to update elapsed times.
71
+ Delays connection by 0.5s to let UI render first. Sets up automatic screen
72
+ refresh every second to update elapsed times.
69
73
  """
70
74
  import asyncio
71
75
 
@@ -82,7 +86,8 @@ class StateMonitorApp(App[None]):
82
86
  self.modules_widget.refresh_last_update_times()
83
87
 
84
88
  def action_toggle_connection(self) -> None:
85
- """Toggle connection on 'c' key press.
89
+ """
90
+ Toggle connection on 'c' key press.
86
91
 
87
92
  Connects if disconnected/failed, disconnects if connected/connecting.
88
93
  """
@@ -11,7 +11,8 @@ if TYPE_CHECKING:
11
11
 
12
12
 
13
13
  class HelpMenuWidget(Vertical):
14
- """Help menu widget displaying keyboard shortcuts and protocol keys.
14
+ """
15
+ Help menu widget displaying keyboard shortcuts and protocol keys.
15
16
 
16
17
  Displays a table of available keyboard shortcuts mapped to their
17
18
  corresponding protocol commands.
@@ -27,7 +28,8 @@ class HelpMenuWidget(Vertical):
27
28
  *args: Any,
28
29
  **kwargs: Any,
29
30
  ) -> None:
30
- """Initialize the Help Menu widget.
31
+ """
32
+ Initialize the Help Menu widget.
31
33
 
32
34
  Args:
33
35
  service: ProtocolMonitorService instance.
@@ -42,7 +44,8 @@ class HelpMenuWidget(Vertical):
42
44
  self.border_title = "Help menu"
43
45
 
44
46
  def compose(self) -> ComposeResult:
45
- """Compose the help menu layout.
47
+ """
48
+ Compose the help menu layout.
46
49
 
47
50
  Yields:
48
51
  DataTable widget with key mappings.
@@ -12,7 +12,8 @@ from xp.services.term.state_monitor_service import StateMonitorService
12
12
 
13
13
 
14
14
  class ModulesListWidget(Static):
15
- """Widget displaying module states in a data table.
15
+ """
16
+ Widget displaying module states in a data table.
16
17
 
17
18
  Shows module information with real-time updates from StateMonitorService.
18
19
  Table displays: name, serial_number, module_type, link_number, outputs, report, status, last_update.
@@ -28,7 +29,8 @@ class ModulesListWidget(Static):
28
29
  *args: Any,
29
30
  **kwargs: Any,
30
31
  ) -> None:
31
- """Initialize the Modules List widget.
32
+ """
33
+ Initialize the Modules List widget.
32
34
 
33
35
  Args:
34
36
  service: Optional StateMonitorService for signal subscriptions.
@@ -41,7 +43,8 @@ class ModulesListWidget(Static):
41
43
  self._row_keys: dict[str, Any] = {} # Map serial_number to row key
42
44
 
43
45
  def compose(self) -> ComposeResult:
44
- """Compose the widget layout.
46
+ """
47
+ Compose the widget layout.
45
48
 
46
49
  Yields:
47
50
  DataTable widget.
@@ -76,7 +79,8 @@ class ModulesListWidget(Static):
76
79
  self.service.on_module_state_changed.disconnect(self.update_module_state)
77
80
 
78
81
  def update_module_list(self, module_states: List[ModuleState]) -> None:
79
- """Update entire module list from service.
82
+ """
83
+ Update entire module list from service.
80
84
 
81
85
  Clears existing table and repopulates with all modules.
82
86
 
@@ -95,7 +99,8 @@ class ModulesListWidget(Static):
95
99
  self._add_module_row(module_state)
96
100
 
97
101
  def update_module_state(self, module_state: ModuleState) -> None:
98
- """Update individual module state in table.
102
+ """
103
+ Update individual module state in table.
99
104
 
100
105
  Updates existing row if module exists, otherwise adds new row.
101
106
 
@@ -133,7 +138,8 @@ class ModulesListWidget(Static):
133
138
  self._add_module_row(module_state)
134
139
 
135
140
  def _add_module_row(self, module_state: ModuleState) -> None:
136
- """Add a module row to the table.
141
+ """
142
+ Add a module row to the table.
137
143
 
138
144
  Args:
139
145
  module_state: Module state to add.
@@ -154,7 +160,8 @@ class ModulesListWidget(Static):
154
160
  self._row_keys[module_state.serial_number] = row_key
155
161
 
156
162
  def _format_outputs(self, outputs: str) -> str:
157
- """Format outputs for display.
163
+ """
164
+ Format outputs for display.
158
165
 
159
166
  Args:
160
167
  outputs: Raw output string.
@@ -165,7 +172,8 @@ class ModulesListWidget(Static):
165
172
  return outputs
166
173
 
167
174
  def _format_report(self, auto_report: bool) -> str:
168
- """Format auto-report status for display.
175
+ """
176
+ Format auto-report status for display.
169
177
 
170
178
  Args:
171
179
  auto_report: Auto-report boolean value.
@@ -176,7 +184,8 @@ class ModulesListWidget(Static):
176
184
  return "Y" if auto_report else "N"
177
185
 
178
186
  def _format_last_update(self, last_update: Optional[datetime]) -> str:
179
- """Format last update timestamp for display.
187
+ """
188
+ Format last update timestamp for display.
180
189
 
181
190
  Shows elapsed time in HH:MM:SS format or "--:--:--" if never updated.
182
191
 
@@ -200,7 +209,8 @@ class ModulesListWidget(Static):
200
209
  return f"{hours:02d}:{minutes:02d}:{seconds:02d}"
201
210
 
202
211
  def refresh_last_update_times(self) -> None:
203
- """Refresh only the last_update column for all modules.
212
+ """
213
+ Refresh only the last_update column for all modules.
204
214
 
205
215
  Updates the elapsed time display without querying the service.
206
216
  """
@@ -11,7 +11,8 @@ from xp.services.term.protocol_monitor_service import ProtocolMonitorService
11
11
 
12
12
 
13
13
  class ProtocolLogWidget(Widget):
14
- """Widget for displaying protocol telegram stream.
14
+ """
15
+ Widget for displaying protocol telegram stream.
15
16
 
16
17
  Displays live RX/TX telegram stream with color-coded direction markers
17
18
  via ProtocolMonitorService.
@@ -23,7 +24,8 @@ class ProtocolLogWidget(Widget):
23
24
  """
24
25
 
25
26
  def __init__(self, service: ProtocolMonitorService) -> None:
26
- """Initialize the Protocol Log widget.
27
+ """
28
+ Initialize the Protocol Log widget.
27
29
 
28
30
  Args:
29
31
  service: ProtocolMonitorService instance for protocol operations.
@@ -35,7 +37,8 @@ class ProtocolLogWidget(Widget):
35
37
  self.log_widget: Optional[RichLog] = None
36
38
 
37
39
  def compose(self) -> Any:
38
- """Compose the widget layout.
40
+ """
41
+ Compose the widget layout.
39
42
 
40
43
  Yields:
41
44
  RichLog widget for message display.
@@ -44,7 +47,8 @@ class ProtocolLogWidget(Widget):
44
47
  yield self.log_widget
45
48
 
46
49
  def on_mount(self) -> None:
47
- """Initialize widget when mounted.
50
+ """
51
+ Initialize widget when mounted.
48
52
 
49
53
  Connects to service signals for telegram display.
50
54
  """
@@ -52,7 +56,8 @@ class ProtocolLogWidget(Widget):
52
56
  self.service.on_telegram_display.connect(self._on_telegram_display)
53
57
 
54
58
  def _on_telegram_display(self, event: TelegramDisplayEvent) -> None:
55
- """Handle telegram display event from service.
59
+ """
60
+ Handle telegram display event from service.
56
61
 
57
62
  Args:
58
63
  event: Telegram display event with direction and telegram data.
@@ -69,7 +74,8 @@ class ProtocolLogWidget(Widget):
69
74
  self.log_widget.clear()
70
75
 
71
76
  def on_unmount(self) -> None:
72
- """Clean up when widget unmounts.
77
+ """
78
+ Clean up when widget unmounts.
73
79
 
74
80
  Disconnects signals from service.
75
81
  """
@@ -12,7 +12,8 @@ from xp.services.term.state_monitor_service import StateMonitorService
12
12
 
13
13
 
14
14
  class StatusFooterWidget(Horizontal):
15
- """Footer widget with connection status indicator.
15
+ """
16
+ Footer widget with connection status indicator.
16
17
 
17
18
  Combines the Textual Footer with a status indicator dot that shows
18
19
  the current connection state. Subscribes directly to service signals.
@@ -29,7 +30,8 @@ class StatusFooterWidget(Horizontal):
29
30
  *args: Any,
30
31
  **kwargs: Any,
31
32
  ) -> None:
32
- """Initialize the Status Footer widget.
33
+ """
34
+ Initialize the Status Footer widget.
33
35
 
34
36
  Args:
35
37
  service: Optional ProtocolMonitorService or StateMonitorService for signal subscriptions.
@@ -42,7 +44,8 @@ class StatusFooterWidget(Horizontal):
42
44
  self.status_widget: Static = Static("○", id="status-line")
43
45
 
44
46
  def compose(self) -> ComposeResult:
45
- """Compose the footer layout.
47
+ """
48
+ Compose the footer layout.
46
49
 
47
50
  Yields:
48
51
  Footer and status indicator widgets.
@@ -64,7 +67,8 @@ class StatusFooterWidget(Horizontal):
64
67
  self.service.on_status_message.disconnect(self.update_message)
65
68
 
66
69
  def update_status(self, state: ConnectionState) -> None:
67
- """Update status indicator with connection state.
70
+ """
71
+ Update status indicator with connection state.
68
72
 
69
73
  Args:
70
74
  state: Current connection state (ConnectionState enum).
@@ -80,7 +84,8 @@ class StatusFooterWidget(Horizontal):
80
84
  self.status_widget.update(dot)
81
85
 
82
86
  def update_message(self, message: str) -> None:
83
- """Update status text with message.
87
+ """
88
+ Update status text with message.
84
89
 
85
90
  Args:
86
91
  message: Status message to display.
xp/utils/checksum.py CHANGED
@@ -1,4 +1,5 @@
1
- """Checksum utility functions for protocol interoperability.
1
+ """
2
+ Checksum utility functions for protocol interoperability.
2
3
 
3
4
  This module provides standard checksum calculation functions for protocol
4
5
  communication compatibility, including XOR checksum and IEEE 802.3 CRC32.
@@ -12,7 +13,8 @@ from xp.utils.serialization import nibble
12
13
 
13
14
 
14
15
  def calculate_checksum(buffer: str) -> str:
15
- """Calculate simple XOR checksum of a string buffer.
16
+ """
17
+ Calculate simple XOR checksum of a string buffer.
16
18
 
17
19
  Args:
18
20
  buffer: Input string to calculate checksum for
@@ -28,7 +30,8 @@ def calculate_checksum(buffer: str) -> str:
28
30
 
29
31
 
30
32
  def calculate_checksum32(buffer: bytes) -> str:
31
- """Calculate CRC32 checksum for protocol interoperability.
33
+ """
34
+ Calculate CRC32 checksum for protocol interoperability.
32
35
 
33
36
  Implements standard CRC32 algorithm using IEEE 802.3 polynomial 0xEDB88320
34
37
  for interoperability with XP protocol communications. This is a standard
xp/utils/dependencies.py CHANGED
@@ -51,15 +51,6 @@ from xp.services.conbus.conbus_output_service import ConbusOutputService
51
51
  from xp.services.conbus.conbus_raw_service import ConbusRawService
52
52
  from xp.services.conbus.conbus_receive_service import ConbusReceiveService
53
53
  from xp.services.conbus.conbus_scan_service import ConbusScanService
54
- from xp.services.conbus.msactiontable.msactiontable_download_service import (
55
- MsActionTableDownloadService,
56
- )
57
- from xp.services.conbus.msactiontable.msactiontable_list_service import (
58
- MsActionTableListService,
59
- )
60
- from xp.services.conbus.msactiontable.msactiontable_show_service import (
61
- MsActionTableShowService,
62
- )
63
54
  from xp.services.conbus.msactiontable.msactiontable_upload_service import (
64
55
  MsActionTableUploadService,
65
56
  )
@@ -100,8 +91,8 @@ class ServiceContainer:
100
91
  """
101
92
  Service container that manages dependency injection for all XP services.
102
93
 
103
- Uses the service dependency graph from Dependencies.dot to properly
104
- wire up all services with their dependencies.
94
+ Uses the service dependency graph from Dependencies.dot to properly wire up all
95
+ services with their dependencies.
105
96
  """
106
97
 
107
98
  def __init__(
@@ -327,6 +318,15 @@ class ServiceContainer:
327
318
  factory=lambda: ActionTableDownloadService(
328
319
  conbus_protocol=self.container.resolve(ConbusEventProtocol),
329
320
  actiontable_serializer=self.container.resolve(ActionTableSerializer),
321
+ msactiontable_serializer_xp20=self.container.resolve(
322
+ Xp20MsActionTableSerializer
323
+ ),
324
+ msactiontable_serializer_xp24=self.container.resolve(
325
+ Xp24MsActionTableSerializer
326
+ ),
327
+ msactiontable_serializer_xp33=self.container.resolve(
328
+ Xp33MsActionTableSerializer
329
+ ),
330
330
  ),
331
331
  scope=punq.Scope.singleton,
332
332
  )
@@ -373,13 +373,19 @@ class ServiceContainer:
373
373
  )
374
374
 
375
375
  self.container.register(
376
- MsActionTableDownloadService,
377
- factory=lambda: MsActionTableDownloadService(
376
+ ActionTableDownloadService,
377
+ factory=lambda: ActionTableDownloadService(
378
378
  conbus_protocol=self.container.resolve(ConbusEventProtocol),
379
- xp20ms_serializer=self.container.resolve(Xp20MsActionTableSerializer),
380
- xp24ms_serializer=self.container.resolve(Xp24MsActionTableSerializer),
381
- xp33ms_serializer=self.container.resolve(Xp33MsActionTableSerializer),
382
- telegram_service=self.container.resolve(TelegramService),
379
+ actiontable_serializer=self.container.resolve(ActionTableSerializer),
380
+ msactiontable_serializer_xp20=self.container.resolve(
381
+ Xp20MsActionTableSerializer
382
+ ),
383
+ msactiontable_serializer_xp24=self.container.resolve(
384
+ Xp24MsActionTableSerializer
385
+ ),
386
+ msactiontable_serializer_xp33=self.container.resolve(
387
+ Xp33MsActionTableSerializer
388
+ ),
383
389
  ),
384
390
  scope=punq.Scope.singleton,
385
391
  )
@@ -494,18 +500,6 @@ class ServiceContainer:
494
500
  scope=punq.Scope.singleton,
495
501
  )
496
502
 
497
- self.container.register(
498
- MsActionTableListService,
499
- factory=MsActionTableListService,
500
- scope=punq.Scope.singleton,
501
- )
502
-
503
- self.container.register(
504
- MsActionTableShowService,
505
- factory=MsActionTableShowService,
506
- scope=punq.Scope.singleton,
507
- )
508
-
509
503
  # Server services layer
510
504
  self.container.register(
511
505
  ServerService,
@@ -629,7 +623,8 @@ class ServiceContainer:
629
623
  )
630
624
 
631
625
  def _load_protocol_keys(self) -> "ProtocolKeysConfig":
632
- """Load protocol keys from YAML config file.
626
+ """
627
+ Load protocol keys from YAML config file.
633
628
 
634
629
  Returns:
635
630
  ProtocolKeysConfig instance loaded from configuration path.
xp/utils/event_helper.py CHANGED
@@ -1,7 +1,8 @@
1
- """Event handling utilities for PyDispatcher integration.
1
+ """
2
+ Event handling utilities for PyDispatcher integration.
2
3
 
3
- This module provides clean, reusable utilities for handling PyDispatcher
4
- responses across all HomeKit accessory classes.
4
+ This module provides clean, reusable utilities for handling PyDispatcher responses
5
+ across all HomeKit accessory classes.
5
6
  """
6
7
 
7
8
  from typing import Any, Callable, List, Tuple
@@ -10,7 +11,8 @@ from typing import Any, Callable, List, Tuple
10
11
  def get_first_response(
11
12
  responses: List[Tuple[Callable, Any]], default: Any = None
12
13
  ) -> Any:
13
- """Extract the first non-None response from PyDispatcher responses.
14
+ """
15
+ Extract the first non-None response from PyDispatcher responses.
14
16
 
15
17
  Args:
16
18
  responses: List of (receiver_function, return_value) tuples from dispatcher.send()
xp/utils/logging.py CHANGED
@@ -11,7 +11,8 @@ class LoggerService:
11
11
  """Service for managing logging configuration and setup."""
12
12
 
13
13
  def __init__(self, logger_config: ConbusLoggerConfig):
14
- """Initialize LoggerService with configuration.
14
+ """
15
+ Initialize LoggerService with configuration.
15
16
 
16
17
  Args:
17
18
  logger_config: Logger configuration object.
@@ -44,7 +45,8 @@ class LoggerService:
44
45
  logging.getLogger(module).setLevel(self.logging_config.levels[module])
45
46
 
46
47
  def setup_console_logging(self, log_format: str, date_format: str) -> None:
47
- """Setup console logging with specified format.
48
+ """
49
+ Setup console logging with specified format.
48
50
 
49
51
  Args:
50
52
  log_format: Log message format string.
@@ -68,7 +70,8 @@ class LoggerService:
68
70
  root_logger.addHandler(handler)
69
71
 
70
72
  def setup_file_logging(self, log_format: str, date_format: str) -> None:
71
- """Setup file logging with rotation for term application.
73
+ """
74
+ Setup file logging with rotation for term application.
72
75
 
73
76
  Args:
74
77
  log_format: Log message format string.
xp/utils/serialization.py CHANGED
@@ -1,7 +1,8 @@
1
- """Binary serialization utility functions.
1
+ """
2
+ Binary serialization utility functions.
2
3
 
3
- This module provides common binary manipulation functions used across
4
- the XP protocol serializers for consistent data encoding/decoding.
4
+ This module provides common binary manipulation functions used across the XP protocol
5
+ serializers for consistent data encoding/decoding.
5
6
  """
6
7
 
7
8
  from typing import List
@@ -14,7 +15,8 @@ UPPER5 = 248 # 0xF8
14
15
 
15
16
 
16
17
  def de_bcd(byte_val: int) -> int:
17
- """Convert BCD byte to decimal.
18
+ """
19
+ Convert BCD byte to decimal.
18
20
 
19
21
  Args:
20
22
  byte_val: BCD encoded byte
@@ -26,7 +28,8 @@ def de_bcd(byte_val: int) -> int:
26
28
 
27
29
 
28
30
  def to_bcd(decimal_val: int) -> int:
29
- """Convert decimal to BCD byte.
31
+ """
32
+ Convert decimal to BCD byte.
30
33
 
31
34
  Args:
32
35
  decimal_val: Decimal value to convert
@@ -40,7 +43,8 @@ def to_bcd(decimal_val: int) -> int:
40
43
 
41
44
 
42
45
  def lower3(byte_val: int) -> int:
43
- """Extract lower 3 bits from byte.
46
+ """
47
+ Extract lower 3 bits from byte.
44
48
 
45
49
  Args:
46
50
  byte_val: Input byte
@@ -52,7 +56,8 @@ def lower3(byte_val: int) -> int:
52
56
 
53
57
 
54
58
  def upper5(byte_val: int) -> int:
55
- """Extract upper 5 bits from byte.
59
+ """
60
+ Extract upper 5 bits from byte.
56
61
 
57
62
  Args:
58
63
  byte_val: Input byte
@@ -64,7 +69,8 @@ def upper5(byte_val: int) -> int:
64
69
 
65
70
 
66
71
  def byte_to_bits(byte_value: int) -> List[bool]:
67
- """Convert a byte value to 8-bit boolean array.
72
+ """
73
+ Convert a byte value to 8-bit boolean array.
68
74
 
69
75
  Args:
70
76
  byte_value: Byte value to convert
@@ -76,7 +82,8 @@ def byte_to_bits(byte_value: int) -> List[bool]:
76
82
 
77
83
 
78
84
  def bits_to_byte(bits: List[bool]) -> int:
79
- """Convert boolean array to byte value.
85
+ """
86
+ Convert boolean array to byte value.
80
87
 
81
88
  Args:
82
89
  bits: List of boolean values representing bits
@@ -92,7 +99,8 @@ def bits_to_byte(bits: List[bool]) -> int:
92
99
 
93
100
 
94
101
  def highest_bit_set(value: int) -> int:
95
- """Remove the high bit (0x80) from a byte value.
102
+ """
103
+ Remove the high bit (0x80) from a byte value.
96
104
 
97
105
  Args:
98
106
  value: Byte value to process
@@ -104,7 +112,8 @@ def highest_bit_set(value: int) -> int:
104
112
 
105
113
 
106
114
  def remove_highest_bit(value: int) -> int:
107
- """Remove the high bit (0x80) from a byte value.
115
+ """
116
+ Remove the high bit (0x80) from a byte value.
108
117
 
109
118
  Args:
110
119
  value: Byte value to process
@@ -116,7 +125,8 @@ def remove_highest_bit(value: int) -> int:
116
125
 
117
126
 
118
127
  def byte_to_unsigned(byte_val: int) -> int:
119
- """Convert signed byte to unsigned integer.
128
+ """
129
+ Convert signed byte to unsigned integer.
120
130
 
121
131
  Args:
122
132
  byte_val: Byte value (can be negative)
@@ -130,7 +140,8 @@ def byte_to_unsigned(byte_val: int) -> int:
130
140
 
131
141
 
132
142
  def nibble(byte_val: int) -> str:
133
- """Convert byte value to two-character nibble representation.
143
+ """
144
+ Convert byte value to two-character nibble representation.
134
145
 
135
146
  Args:
136
147
  byte_val: Byte value (0-255)
@@ -144,7 +155,8 @@ def nibble(byte_val: int) -> str:
144
155
 
145
156
 
146
157
  def de_nibble(nibble_str: str) -> int:
147
- """Convert two-character nibble string to byte value.
158
+ """
159
+ Convert two-character nibble string to byte value.
148
160
 
149
161
  Based on pseudocode: A=0, B=1, C=2, ..., P=15
150
162
 
@@ -171,7 +183,8 @@ def de_nibble(nibble_str: str) -> int:
171
183
 
172
184
 
173
185
  def de_nibbles(str_val: str) -> bytearray:
174
- """Convert hex string with A-P encoding to list of integers.
186
+ """
187
+ Convert hex string with A-P encoding to list of integers.
175
188
 
176
189
  Based on pseudocode: A=0, B=1, C=2, ..., P=15
177
190
 
@@ -194,7 +207,8 @@ def de_nibbles(str_val: str) -> bytearray:
194
207
 
195
208
 
196
209
  def nibbles(data: bytes) -> str:
197
- """Convert bytes data to nibble string representation.
210
+ """
211
+ Convert bytes data to nibble string representation.
198
212
 
199
213
  Args:
200
214
  data: Bytes data to convert