conson-xp 1.18.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 (176) hide show
  1. conson_xp-1.18.0.dist-info/METADATA +412 -0
  2. conson_xp-1.18.0.dist-info/RECORD +176 -0
  3. conson_xp-1.18.0.dist-info/WHEEL +4 -0
  4. conson_xp-1.18.0.dist-info/entry_points.txt +5 -0
  5. conson_xp-1.18.0.dist-info/licenses/LICENSE +29 -0
  6. xp/__init__.py +9 -0
  7. xp/cli/__init__.py +5 -0
  8. xp/cli/__main__.py +6 -0
  9. xp/cli/commands/__init__.py +153 -0
  10. xp/cli/commands/conbus/__init__.py +25 -0
  11. xp/cli/commands/conbus/conbus.py +128 -0
  12. xp/cli/commands/conbus/conbus_actiontable_commands.py +233 -0
  13. xp/cli/commands/conbus/conbus_autoreport_commands.py +108 -0
  14. xp/cli/commands/conbus/conbus_blink_commands.py +163 -0
  15. xp/cli/commands/conbus/conbus_config_commands.py +29 -0
  16. xp/cli/commands/conbus/conbus_custom_commands.py +57 -0
  17. xp/cli/commands/conbus/conbus_datapoint_commands.py +113 -0
  18. xp/cli/commands/conbus/conbus_discover_commands.py +61 -0
  19. xp/cli/commands/conbus/conbus_event_commands.py +81 -0
  20. xp/cli/commands/conbus/conbus_lightlevel_commands.py +207 -0
  21. xp/cli/commands/conbus/conbus_linknumber_commands.py +102 -0
  22. xp/cli/commands/conbus/conbus_modulenumber_commands.py +104 -0
  23. xp/cli/commands/conbus/conbus_msactiontable_commands.py +94 -0
  24. xp/cli/commands/conbus/conbus_output_commands.py +163 -0
  25. xp/cli/commands/conbus/conbus_raw_commands.py +62 -0
  26. xp/cli/commands/conbus/conbus_receive_commands.py +59 -0
  27. xp/cli/commands/conbus/conbus_scan_commands.py +58 -0
  28. xp/cli/commands/file_commands.py +186 -0
  29. xp/cli/commands/homekit/__init__.py +3 -0
  30. xp/cli/commands/homekit/homekit.py +118 -0
  31. xp/cli/commands/homekit/homekit_start_commands.py +43 -0
  32. xp/cli/commands/module_commands.py +187 -0
  33. xp/cli/commands/reverse_proxy_commands.py +178 -0
  34. xp/cli/commands/server/__init__.py +3 -0
  35. xp/cli/commands/server/server_commands.py +135 -0
  36. xp/cli/commands/telegram/__init__.py +5 -0
  37. xp/cli/commands/telegram/telegram.py +41 -0
  38. xp/cli/commands/telegram/telegram_blink_commands.py +79 -0
  39. xp/cli/commands/telegram/telegram_checksum_commands.py +112 -0
  40. xp/cli/commands/telegram/telegram_discover_commands.py +41 -0
  41. xp/cli/commands/telegram/telegram_linknumber_commands.py +86 -0
  42. xp/cli/commands/telegram/telegram_parse_commands.py +75 -0
  43. xp/cli/commands/telegram/telegram_version_commands.py +52 -0
  44. xp/cli/main.py +87 -0
  45. xp/cli/utils/__init__.py +1 -0
  46. xp/cli/utils/click_tree.py +57 -0
  47. xp/cli/utils/datapoint_type_choice.py +57 -0
  48. xp/cli/utils/decorators.py +351 -0
  49. xp/cli/utils/error_handlers.py +201 -0
  50. xp/cli/utils/formatters.py +312 -0
  51. xp/cli/utils/module_type_choice.py +56 -0
  52. xp/cli/utils/serial_number_type.py +52 -0
  53. xp/cli/utils/system_function_choice.py +57 -0
  54. xp/cli/utils/xp_module_type.py +53 -0
  55. xp/connection/__init__.py +13 -0
  56. xp/connection/exceptions.py +22 -0
  57. xp/models/__init__.py +36 -0
  58. xp/models/actiontable/__init__.py +1 -0
  59. xp/models/actiontable/actiontable.py +43 -0
  60. xp/models/actiontable/msactiontable_xp20.py +53 -0
  61. xp/models/actiontable/msactiontable_xp24.py +58 -0
  62. xp/models/actiontable/msactiontable_xp33.py +65 -0
  63. xp/models/conbus/__init__.py +1 -0
  64. xp/models/conbus/conbus.py +87 -0
  65. xp/models/conbus/conbus_autoreport.py +67 -0
  66. xp/models/conbus/conbus_blink.py +80 -0
  67. xp/models/conbus/conbus_client_config.py +55 -0
  68. xp/models/conbus/conbus_connection_status.py +40 -0
  69. xp/models/conbus/conbus_custom.py +58 -0
  70. xp/models/conbus/conbus_datapoint.py +89 -0
  71. xp/models/conbus/conbus_discover.py +64 -0
  72. xp/models/conbus/conbus_event_raw.py +47 -0
  73. xp/models/conbus/conbus_lightlevel.py +52 -0
  74. xp/models/conbus/conbus_linknumber.py +54 -0
  75. xp/models/conbus/conbus_output.py +57 -0
  76. xp/models/conbus/conbus_raw.py +45 -0
  77. xp/models/conbus/conbus_receive.py +42 -0
  78. xp/models/conbus/conbus_writeconfig.py +60 -0
  79. xp/models/homekit/__init__.py +1 -0
  80. xp/models/homekit/homekit_accessory.py +35 -0
  81. xp/models/homekit/homekit_config.py +106 -0
  82. xp/models/homekit/homekit_conson_config.py +86 -0
  83. xp/models/log_entry.py +130 -0
  84. xp/models/protocol/__init__.py +1 -0
  85. xp/models/protocol/conbus_protocol.py +312 -0
  86. xp/models/response.py +42 -0
  87. xp/models/telegram/__init__.py +1 -0
  88. xp/models/telegram/action_type.py +31 -0
  89. xp/models/telegram/datapoint_type.py +82 -0
  90. xp/models/telegram/event_telegram.py +140 -0
  91. xp/models/telegram/event_type.py +15 -0
  92. xp/models/telegram/input_action_type.py +69 -0
  93. xp/models/telegram/input_type.py +17 -0
  94. xp/models/telegram/module_type.py +188 -0
  95. xp/models/telegram/module_type_code.py +205 -0
  96. xp/models/telegram/output_telegram.py +103 -0
  97. xp/models/telegram/reply_telegram.py +297 -0
  98. xp/models/telegram/system_function.py +116 -0
  99. xp/models/telegram/system_telegram.py +94 -0
  100. xp/models/telegram/telegram.py +28 -0
  101. xp/models/telegram/telegram_type.py +19 -0
  102. xp/models/telegram/timeparam_type.py +51 -0
  103. xp/models/write_config_type.py +33 -0
  104. xp/services/__init__.py +26 -0
  105. xp/services/actiontable/__init__.py +1 -0
  106. xp/services/actiontable/actiontable_serializer.py +273 -0
  107. xp/services/actiontable/msactiontable_serializer.py +7 -0
  108. xp/services/actiontable/msactiontable_xp20_serializer.py +169 -0
  109. xp/services/actiontable/msactiontable_xp24_serializer.py +120 -0
  110. xp/services/actiontable/msactiontable_xp33_serializer.py +239 -0
  111. xp/services/conbus/__init__.py +1 -0
  112. xp/services/conbus/actiontable/__init__.py +1 -0
  113. xp/services/conbus/actiontable/actiontable_download_service.py +158 -0
  114. xp/services/conbus/actiontable/actiontable_list_service.py +91 -0
  115. xp/services/conbus/actiontable/actiontable_show_service.py +89 -0
  116. xp/services/conbus/actiontable/actiontable_upload_service.py +211 -0
  117. xp/services/conbus/actiontable/msactiontable_service.py +232 -0
  118. xp/services/conbus/conbus_blink_all_service.py +181 -0
  119. xp/services/conbus/conbus_blink_service.py +158 -0
  120. xp/services/conbus/conbus_custom_service.py +156 -0
  121. xp/services/conbus/conbus_datapoint_queryall_service.py +182 -0
  122. xp/services/conbus/conbus_datapoint_service.py +170 -0
  123. xp/services/conbus/conbus_discover_service.py +312 -0
  124. xp/services/conbus/conbus_event_raw_service.py +181 -0
  125. xp/services/conbus/conbus_output_service.py +194 -0
  126. xp/services/conbus/conbus_raw_service.py +122 -0
  127. xp/services/conbus/conbus_receive_service.py +115 -0
  128. xp/services/conbus/conbus_scan_service.py +150 -0
  129. xp/services/conbus/write_config_service.py +194 -0
  130. xp/services/homekit/__init__.py +1 -0
  131. xp/services/homekit/homekit_cache_service.py +307 -0
  132. xp/services/homekit/homekit_conbus_service.py +93 -0
  133. xp/services/homekit/homekit_config_validator.py +310 -0
  134. xp/services/homekit/homekit_conson_validator.py +121 -0
  135. xp/services/homekit/homekit_dimminglight.py +182 -0
  136. xp/services/homekit/homekit_dimminglight_service.py +148 -0
  137. xp/services/homekit/homekit_hap_service.py +342 -0
  138. xp/services/homekit/homekit_lightbulb.py +120 -0
  139. xp/services/homekit/homekit_lightbulb_service.py +86 -0
  140. xp/services/homekit/homekit_module_service.py +56 -0
  141. xp/services/homekit/homekit_outlet.py +168 -0
  142. xp/services/homekit/homekit_outlet_service.py +121 -0
  143. xp/services/homekit/homekit_service.py +359 -0
  144. xp/services/log_file_service.py +309 -0
  145. xp/services/module_type_service.py +257 -0
  146. xp/services/protocol/__init__.py +21 -0
  147. xp/services/protocol/conbus_event_protocol.py +360 -0
  148. xp/services/protocol/conbus_protocol.py +318 -0
  149. xp/services/protocol/protocol_factory.py +78 -0
  150. xp/services/protocol/telegram_protocol.py +264 -0
  151. xp/services/reverse_proxy_service.py +435 -0
  152. xp/services/server/__init__.py +1 -0
  153. xp/services/server/base_server_service.py +366 -0
  154. xp/services/server/cp20_server_service.py +65 -0
  155. xp/services/server/device_service_factory.py +94 -0
  156. xp/services/server/server_service.py +428 -0
  157. xp/services/server/xp130_server_service.py +67 -0
  158. xp/services/server/xp20_server_service.py +92 -0
  159. xp/services/server/xp230_server_service.py +58 -0
  160. xp/services/server/xp24_server_service.py +245 -0
  161. xp/services/server/xp33_server_service.py +535 -0
  162. xp/services/telegram/__init__.py +1 -0
  163. xp/services/telegram/telegram_blink_service.py +138 -0
  164. xp/services/telegram/telegram_checksum_service.py +149 -0
  165. xp/services/telegram/telegram_datapoint_service.py +82 -0
  166. xp/services/telegram/telegram_discover_service.py +277 -0
  167. xp/services/telegram/telegram_link_number_service.py +216 -0
  168. xp/services/telegram/telegram_output_service.py +322 -0
  169. xp/services/telegram/telegram_service.py +380 -0
  170. xp/services/telegram/telegram_version_service.py +288 -0
  171. xp/utils/__init__.py +12 -0
  172. xp/utils/checksum.py +61 -0
  173. xp/utils/dependencies.py +531 -0
  174. xp/utils/event_helper.py +31 -0
  175. xp/utils/serialization.py +205 -0
  176. xp/utils/time_utils.py +134 -0
xp/utils/checksum.py ADDED
@@ -0,0 +1,61 @@
1
+ """Checksum utility functions for protocol interoperability.
2
+
3
+ This module provides standard checksum calculation functions for protocol
4
+ communication compatibility, including XOR checksum and IEEE 802.3 CRC32.
5
+ Implemented for interoperability purposes under fair use provisions.
6
+
7
+ Copyright (c) 2025 ld
8
+ Licensed under MIT License - see LICENSE file for details.
9
+ """
10
+
11
+ from xp.utils.serialization import nibble
12
+
13
+
14
+ def calculate_checksum(buffer: str) -> str:
15
+ """Calculate simple XOR checksum of a string buffer.
16
+
17
+ Args:
18
+ buffer: Input string to calculate checksum for
19
+
20
+ Returns:
21
+ Two-character checksum string in nibble format
22
+ """
23
+ cc = 0
24
+ for char in buffer:
25
+ cc ^= ord(char)
26
+
27
+ return nibble(cc & 0xFF)
28
+
29
+
30
+ def calculate_checksum32(buffer: bytes) -> str:
31
+ """Calculate CRC32 checksum for protocol interoperability.
32
+
33
+ Implements standard CRC32 algorithm using IEEE 802.3 polynomial 0xEDB88320
34
+ for interoperability with XP protocol communications. This is a standard
35
+ algorithm implementation for protocol compatibility purposes.
36
+
37
+ Args:
38
+ buffer: Byte array to calculate checksum for
39
+
40
+ Returns:
41
+ Eight-character checksum string in nibble format
42
+ """
43
+ nibble_result = ""
44
+ crc = 0xFFFFFFFF # Initialize to -1 (all bits set)
45
+
46
+ for byte in buffer:
47
+ crc ^= byte
48
+ for _ in range(8):
49
+ if crc & 1:
50
+ crc = (crc >> 1) ^ 0xEDB88320
51
+ else:
52
+ crc = crc >> 1
53
+
54
+ crc ^= 0xFFFFFFFF # Final XOR
55
+
56
+ # Convert to nibble format (4 bytes, little-endian)
57
+ for _ in range(4):
58
+ nibble_result = nibble(crc & 0xFF) + nibble_result
59
+ crc >>= 8
60
+
61
+ return nibble_result
@@ -0,0 +1,531 @@
1
+ """Dependency injection container for XP services."""
2
+
3
+ import punq
4
+ from bubus import EventBus
5
+ from twisted.internet import asyncioreactor
6
+ from twisted.internet.interfaces import IConnector
7
+ from twisted.internet.posixbase import PosixReactorBase
8
+
9
+ from xp.models import ConbusClientConfig
10
+ from xp.models.homekit.homekit_config import HomekitConfig
11
+ from xp.models.homekit.homekit_conson_config import ConsonModuleListConfig
12
+ from xp.services.actiontable.actiontable_serializer import ActionTableSerializer
13
+ from xp.services.actiontable.msactiontable_serializer import MsActionTableSerializer
14
+ from xp.services.actiontable.msactiontable_xp20_serializer import (
15
+ Xp20MsActionTableSerializer,
16
+ )
17
+ from xp.services.actiontable.msactiontable_xp24_serializer import (
18
+ Xp24MsActionTableSerializer,
19
+ )
20
+ from xp.services.actiontable.msactiontable_xp33_serializer import (
21
+ Xp33MsActionTableSerializer,
22
+ )
23
+ from xp.services.conbus.actiontable.actiontable_download_service import (
24
+ ActionTableService,
25
+ )
26
+ from xp.services.conbus.actiontable.actiontable_list_service import (
27
+ ActionTableListService,
28
+ )
29
+ from xp.services.conbus.actiontable.actiontable_show_service import (
30
+ ActionTableShowService,
31
+ )
32
+ from xp.services.conbus.actiontable.actiontable_upload_service import (
33
+ ActionTableUploadService,
34
+ )
35
+ from xp.services.conbus.actiontable.msactiontable_service import MsActionTableService
36
+ from xp.services.conbus.conbus_blink_all_service import ConbusBlinkAllService
37
+ from xp.services.conbus.conbus_blink_service import ConbusBlinkService
38
+ from xp.services.conbus.conbus_custom_service import ConbusCustomService
39
+ from xp.services.conbus.conbus_datapoint_queryall_service import (
40
+ ConbusDatapointQueryAllService,
41
+ )
42
+ from xp.services.conbus.conbus_datapoint_service import (
43
+ ConbusDatapointService,
44
+ )
45
+ from xp.services.conbus.conbus_discover_service import ConbusDiscoverService
46
+ from xp.services.conbus.conbus_event_raw_service import ConbusEventRawService
47
+ from xp.services.conbus.conbus_output_service import ConbusOutputService
48
+ from xp.services.conbus.conbus_raw_service import ConbusRawService
49
+ from xp.services.conbus.conbus_receive_service import ConbusReceiveService
50
+ from xp.services.conbus.conbus_scan_service import ConbusScanService
51
+ from xp.services.conbus.write_config_service import WriteConfigService
52
+ from xp.services.homekit.homekit_cache_service import HomeKitCacheService
53
+ from xp.services.homekit.homekit_conbus_service import HomeKitConbusService
54
+ from xp.services.homekit.homekit_dimminglight_service import HomeKitDimmingLightService
55
+ from xp.services.homekit.homekit_hap_service import HomekitHapService
56
+ from xp.services.homekit.homekit_lightbulb_service import HomeKitLightbulbService
57
+ from xp.services.homekit.homekit_module_service import HomekitModuleService
58
+ from xp.services.homekit.homekit_outlet_service import HomeKitOutletService
59
+ from xp.services.homekit.homekit_service import HomeKitService
60
+ from xp.services.log_file_service import LogFileService
61
+ from xp.services.module_type_service import ModuleTypeService
62
+ from xp.services.protocol import ConbusEventProtocol
63
+ from xp.services.protocol.protocol_factory import TelegramFactory
64
+ from xp.services.protocol.telegram_protocol import TelegramProtocol
65
+ from xp.services.reverse_proxy_service import ReverseProxyService
66
+ from xp.services.server.device_service_factory import DeviceServiceFactory
67
+ from xp.services.server.server_service import ServerService
68
+ from xp.services.telegram.telegram_blink_service import TelegramBlinkService
69
+ from xp.services.telegram.telegram_datapoint_service import TelegramDatapointService
70
+ from xp.services.telegram.telegram_discover_service import TelegramDiscoverService
71
+ from xp.services.telegram.telegram_link_number_service import LinkNumberService
72
+ from xp.services.telegram.telegram_output_service import TelegramOutputService
73
+ from xp.services.telegram.telegram_service import TelegramService
74
+
75
+ asyncioreactor.install()
76
+ from twisted.internet import reactor # noqa: E402
77
+
78
+
79
+ class ServiceContainer:
80
+ """
81
+ Service container that manages dependency injection for all XP services.
82
+
83
+ Uses the service dependency graph from Dependencies.dot to properly
84
+ wire up all services with their dependencies.
85
+ """
86
+
87
+ def __init__(
88
+ self,
89
+ config_path: str = "cli.yml",
90
+ homekit_config_path: str = "homekit.yml",
91
+ conson_config_path: str = "conson.yml",
92
+ server_port: int = 10001,
93
+ reverse_proxy_port: int = 10001,
94
+ ):
95
+ """
96
+ Initialize the service container.
97
+
98
+ Args:
99
+ config_path: Path to the Conbus CLI configuration file
100
+ homekit_config_path: Path to the HomeKit configuration file
101
+ conson_config_path: Path to the Conson configuration file
102
+ server_port: Port for the server service
103
+ reverse_proxy_port: Port for the reverse proxy service
104
+ """
105
+ self.container = punq.Container()
106
+ self._config_path = config_path
107
+ self._homekit_config_path = homekit_config_path
108
+ self._conson_config_path = conson_config_path
109
+ self._server_port = server_port
110
+ self._reverse_proxy_port = reverse_proxy_port
111
+
112
+ self._register_services()
113
+
114
+ def _register_services(self) -> None:
115
+ """Register all services in the container based on dependency graph."""
116
+ # ConbusClientConfig
117
+ self.container.register(
118
+ ConbusClientConfig,
119
+ factory=lambda: ConbusClientConfig.from_yaml(self._config_path),
120
+ scope=punq.Scope.singleton,
121
+ )
122
+
123
+ # Telegram services layer
124
+ self.container.register(TelegramService, scope=punq.Scope.singleton)
125
+ self.container.register(
126
+ TelegramOutputService,
127
+ factory=lambda: TelegramOutputService(
128
+ telegram_service=self.container.resolve(TelegramService),
129
+ ),
130
+ scope=punq.Scope.singleton,
131
+ )
132
+ self.container.register(TelegramDiscoverService, scope=punq.Scope.singleton)
133
+ self.container.register(TelegramBlinkService, scope=punq.Scope.singleton)
134
+ self.container.register(TelegramDatapointService, scope=punq.Scope.singleton)
135
+ self.container.register(LinkNumberService, scope=punq.Scope.singleton)
136
+
137
+ # Conbus services layer
138
+ self.container.register(
139
+ ConbusDatapointService,
140
+ factory=lambda: ConbusDatapointService(
141
+ telegram_service=self.container.resolve(TelegramService),
142
+ cli_config=self.container.resolve(ConbusClientConfig),
143
+ reactor=self.container.resolve(PosixReactorBase),
144
+ ),
145
+ scope=punq.Scope.singleton,
146
+ )
147
+
148
+ self.container.register(
149
+ ConbusDatapointQueryAllService,
150
+ factory=lambda: ConbusDatapointQueryAllService(
151
+ telegram_service=self.container.resolve(TelegramService),
152
+ cli_config=self.container.resolve(ConbusClientConfig),
153
+ reactor=self.container.resolve(PosixReactorBase),
154
+ ),
155
+ scope=punq.Scope.singleton,
156
+ )
157
+
158
+ self.container.register(
159
+ ConbusScanService,
160
+ factory=lambda: ConbusScanService(
161
+ cli_config=self.container.resolve(ConbusClientConfig),
162
+ reactor=self.container.resolve(PosixReactorBase),
163
+ ),
164
+ scope=punq.Scope.singleton,
165
+ )
166
+
167
+ self.container.register(
168
+ ConbusEventProtocol,
169
+ factory=lambda: ConbusEventProtocol(
170
+ cli_config=self.container.resolve(ConbusClientConfig),
171
+ reactor=self.container.resolve(PosixReactorBase),
172
+ ),
173
+ scope=punq.Scope.singleton,
174
+ )
175
+
176
+ self.container.register(
177
+ ConbusDiscoverService,
178
+ factory=lambda: ConbusDiscoverService(
179
+ conbus_protocol=self.container.resolve(ConbusEventProtocol)
180
+ ),
181
+ scope=punq.Scope.singleton,
182
+ )
183
+
184
+ self.container.register(
185
+ ConbusEventRawService,
186
+ factory=lambda: ConbusEventRawService(
187
+ conbus_protocol=self.container.resolve(ConbusEventProtocol)
188
+ ),
189
+ scope=punq.Scope.singleton,
190
+ )
191
+
192
+ self.container.register(
193
+ ConbusBlinkService,
194
+ factory=lambda: ConbusBlinkService(
195
+ cli_config=self.container.resolve(ConbusClientConfig),
196
+ reactor=self.container.resolve(PosixReactorBase),
197
+ telegram_service=self.container.resolve(TelegramService),
198
+ ),
199
+ scope=punq.Scope.singleton,
200
+ )
201
+
202
+ self.container.register(
203
+ ConbusBlinkAllService,
204
+ factory=lambda: ConbusBlinkAllService(
205
+ cli_config=self.container.resolve(ConbusClientConfig),
206
+ reactor=self.container.resolve(PosixReactorBase),
207
+ telegram_service=self.container.resolve(TelegramService),
208
+ ),
209
+ scope=punq.Scope.singleton,
210
+ )
211
+
212
+ self.container.register(
213
+ ConbusOutputService,
214
+ factory=lambda: ConbusOutputService(
215
+ telegram_output_service=self.container.resolve(TelegramOutputService),
216
+ cli_config=self.container.resolve(ConbusClientConfig),
217
+ reactor=self.container.resolve(PosixReactorBase),
218
+ ),
219
+ scope=punq.Scope.singleton,
220
+ )
221
+
222
+ self.container.register(
223
+ WriteConfigService,
224
+ factory=lambda: WriteConfigService(
225
+ telegram_service=self.container.resolve(TelegramService),
226
+ cli_config=self.container.resolve(ConbusClientConfig),
227
+ reactor=self.container.resolve(PosixReactorBase),
228
+ ),
229
+ scope=punq.Scope.singleton,
230
+ )
231
+
232
+ self.container.register(
233
+ ActionTableSerializer,
234
+ factory=lambda: ActionTableSerializer,
235
+ scope=punq.Scope.singleton,
236
+ )
237
+
238
+ self.container.register(
239
+ ActionTableService,
240
+ factory=lambda: ActionTableService(
241
+ cli_config=self.container.resolve(ConbusClientConfig),
242
+ reactor=self.container.resolve(PosixReactorBase),
243
+ actiontable_serializer=self.container.resolve(ActionTableSerializer),
244
+ telegram_service=self.container.resolve(TelegramService),
245
+ ),
246
+ scope=punq.Scope.singleton,
247
+ )
248
+
249
+ self.container.register(
250
+ ActionTableUploadService,
251
+ factory=lambda: ActionTableUploadService(
252
+ cli_config=self.container.resolve(ConbusClientConfig),
253
+ reactor=self.container.resolve(PosixReactorBase),
254
+ actiontable_serializer=self.container.resolve(ActionTableSerializer),
255
+ telegram_service=self.container.resolve(TelegramService),
256
+ conson_config=self.container.resolve(ConsonModuleListConfig),
257
+ ),
258
+ scope=punq.Scope.singleton,
259
+ )
260
+
261
+ self.container.register(
262
+ ActionTableListService,
263
+ factory=ActionTableListService,
264
+ scope=punq.Scope.singleton,
265
+ )
266
+
267
+ self.container.register(
268
+ ActionTableShowService,
269
+ factory=ActionTableShowService,
270
+ scope=punq.Scope.singleton,
271
+ )
272
+
273
+ self.container.register(
274
+ Xp20MsActionTableSerializer,
275
+ factory=lambda: Xp20MsActionTableSerializer,
276
+ scope=punq.Scope.singleton,
277
+ )
278
+
279
+ self.container.register(
280
+ Xp24MsActionTableSerializer,
281
+ factory=lambda: Xp24MsActionTableSerializer,
282
+ scope=punq.Scope.singleton,
283
+ )
284
+
285
+ self.container.register(
286
+ Xp33MsActionTableSerializer,
287
+ factory=lambda: Xp33MsActionTableSerializer,
288
+ scope=punq.Scope.singleton,
289
+ )
290
+
291
+ self.container.register(
292
+ MsActionTableService,
293
+ factory=lambda: MsActionTableService(
294
+ cli_config=self.container.resolve(ConbusClientConfig),
295
+ reactor=self.container.resolve(PosixReactorBase),
296
+ xp20ms_serializer=self.container.resolve(Xp20MsActionTableSerializer),
297
+ xp24ms_serializer=self.container.resolve(Xp24MsActionTableSerializer),
298
+ xp33ms_serializer=self.container.resolve(Xp33MsActionTableSerializer),
299
+ telegram_service=self.container.resolve(TelegramService),
300
+ ),
301
+ scope=punq.Scope.singleton,
302
+ )
303
+
304
+ self.container.register(
305
+ ConbusCustomService,
306
+ factory=lambda: ConbusCustomService(
307
+ telegram_service=self.container.resolve(TelegramService),
308
+ cli_config=self.container.resolve(ConbusClientConfig),
309
+ reactor=self.container.resolve(PosixReactorBase),
310
+ ),
311
+ scope=punq.Scope.singleton,
312
+ )
313
+
314
+ self.container.register(
315
+ ConbusRawService,
316
+ factory=lambda: ConbusRawService(
317
+ cli_config=self.container.resolve(ConbusClientConfig),
318
+ reactor=self.container.resolve(PosixReactorBase),
319
+ ),
320
+ scope=punq.Scope.singleton,
321
+ )
322
+
323
+ self.container.register(
324
+ ConbusReceiveService,
325
+ factory=lambda: ConbusReceiveService(
326
+ cli_config=self.container.resolve(ConbusClientConfig),
327
+ reactor=self.container.resolve(PosixReactorBase),
328
+ ),
329
+ scope=punq.Scope.singleton,
330
+ )
331
+
332
+ # HomeKit conson config
333
+ self.container.register(
334
+ ConsonModuleListConfig,
335
+ factory=lambda: ConsonModuleListConfig.from_yaml(self._conson_config_path),
336
+ scope=punq.Scope.singleton,
337
+ )
338
+
339
+ # HomeKit services layer
340
+ self.container.register(
341
+ HomekitModuleService,
342
+ factory=lambda: HomekitModuleService(
343
+ conson_modules_config=self.container.resolve(ConsonModuleListConfig),
344
+ ),
345
+ scope=punq.Scope.singleton,
346
+ )
347
+
348
+ # Create event bus
349
+ self.container.register(
350
+ EventBus,
351
+ factory=lambda: EventBus(max_history_size=500),
352
+ scope=punq.Scope.singleton,
353
+ )
354
+
355
+ # HomeKit conson config
356
+ self.container.register(
357
+ HomekitConfig,
358
+ factory=lambda: HomekitConfig.from_yaml(self._homekit_config_path),
359
+ scope=punq.Scope.singleton,
360
+ )
361
+
362
+ self.container.register(
363
+ HomekitHapService,
364
+ factory=lambda: HomekitHapService(
365
+ homekit_config=self.container.resolve(HomekitConfig),
366
+ module_service=self.container.resolve(HomekitModuleService),
367
+ event_bus=self.container.resolve(EventBus),
368
+ ),
369
+ scope=punq.Scope.singleton,
370
+ )
371
+
372
+ # Log file services layer
373
+ self.container.register(
374
+ LogFileService,
375
+ factory=lambda: LogFileService(
376
+ telegram_service=self.container.resolve(TelegramService),
377
+ ),
378
+ scope=punq.Scope.singleton,
379
+ )
380
+
381
+ # Module type services layer
382
+ self.container.register(ModuleTypeService, scope=punq.Scope.singleton)
383
+
384
+ # MsActionTable serializers
385
+ self.container.register(MsActionTableSerializer, scope=punq.Scope.singleton)
386
+ self.container.register(Xp20MsActionTableSerializer, scope=punq.Scope.singleton)
387
+ self.container.register(Xp24MsActionTableSerializer, scope=punq.Scope.singleton)
388
+ self.container.register(Xp33MsActionTableSerializer, scope=punq.Scope.singleton)
389
+
390
+ # Device service factory
391
+ self.container.register(
392
+ DeviceServiceFactory,
393
+ factory=lambda: DeviceServiceFactory(
394
+ xp20ms_serializer=self.container.resolve(Xp20MsActionTableSerializer),
395
+ xp24ms_serializer=self.container.resolve(Xp24MsActionTableSerializer),
396
+ xp33ms_serializer=self.container.resolve(Xp33MsActionTableSerializer),
397
+ ms_serializer=self.container.resolve(MsActionTableSerializer),
398
+ ),
399
+ scope=punq.Scope.singleton,
400
+ )
401
+
402
+ # Server services layer
403
+ self.container.register(
404
+ ServerService,
405
+ factory=lambda: ServerService(
406
+ telegram_service=self.container.resolve(TelegramService),
407
+ discover_service=self.container.resolve(TelegramDiscoverService),
408
+ device_factory=self.container.resolve(DeviceServiceFactory),
409
+ config_path="server.yml",
410
+ port=self._server_port,
411
+ ),
412
+ scope=punq.Scope.singleton,
413
+ )
414
+
415
+ # Other services
416
+ self.container.register(
417
+ ReverseProxyService,
418
+ factory=lambda: ReverseProxyService(
419
+ cli_config=self.container.resolve(ConbusClientConfig),
420
+ listen_port=self._reverse_proxy_port,
421
+ ),
422
+ scope=punq.Scope.singleton,
423
+ )
424
+
425
+ # Create protocol with built-in debouncing
426
+ self.container.register(
427
+ TelegramProtocol,
428
+ factory=lambda: TelegramProtocol(
429
+ event_bus=self.container.resolve(EventBus),
430
+ debounce_ms=50,
431
+ ),
432
+ scope=punq.Scope.singleton,
433
+ )
434
+
435
+ self.container.register(
436
+ IConnector,
437
+ factory=lambda: reactor,
438
+ scope=punq.Scope.singleton,
439
+ )
440
+
441
+ self.container.register(
442
+ TelegramFactory,
443
+ factory=lambda: TelegramFactory(
444
+ event_bus=self.container.resolve(EventBus),
445
+ telegram_protocol=self.container.resolve(TelegramProtocol),
446
+ connector=self.container.resolve(IConnector),
447
+ ),
448
+ scope=punq.Scope.singleton,
449
+ )
450
+
451
+ self.container.register(
452
+ PosixReactorBase,
453
+ factory=lambda: reactor,
454
+ scope=punq.Scope.singleton,
455
+ )
456
+
457
+ self.container.register(
458
+ HomeKitLightbulbService,
459
+ factory=lambda: HomeKitLightbulbService(
460
+ event_bus=self.container.resolve(EventBus),
461
+ ),
462
+ scope=punq.Scope.singleton,
463
+ )
464
+
465
+ self.container.register(
466
+ HomeKitOutletService,
467
+ factory=lambda: HomeKitOutletService(
468
+ event_bus=self.container.resolve(EventBus),
469
+ ),
470
+ scope=punq.Scope.singleton,
471
+ )
472
+
473
+ self.container.register(
474
+ HomeKitDimmingLightService,
475
+ factory=lambda: HomeKitDimmingLightService(
476
+ event_bus=self.container.resolve(EventBus),
477
+ ),
478
+ scope=punq.Scope.singleton,
479
+ )
480
+
481
+ # Cache service must be registered BEFORE HomeKitConbusService
482
+ # so it intercepts ReadDatapointEvent first
483
+ self.container.register(
484
+ HomeKitCacheService,
485
+ factory=lambda: HomeKitCacheService(
486
+ event_bus=self.container.resolve(EventBus),
487
+ ),
488
+ scope=punq.Scope.singleton,
489
+ )
490
+
491
+ self.container.register(
492
+ HomeKitConbusService,
493
+ factory=lambda: HomeKitConbusService(
494
+ event_bus=self.container.resolve(EventBus),
495
+ telegram_protocol=self.container.resolve(TelegramProtocol),
496
+ ),
497
+ scope=punq.Scope.singleton,
498
+ )
499
+
500
+ self.container.register(
501
+ TelegramService,
502
+ factory=TelegramService,
503
+ scope=punq.Scope.singleton,
504
+ )
505
+
506
+ self.container.register(
507
+ HomeKitService,
508
+ factory=lambda: HomeKitService(
509
+ cli_config=self.container.resolve(ConbusClientConfig),
510
+ event_bus=self.container.resolve(EventBus),
511
+ telegram_factory=self.container.resolve(TelegramFactory),
512
+ reactor=self.container.resolve(PosixReactorBase),
513
+ lightbulb_service=self.container.resolve(HomeKitLightbulbService),
514
+ outlet_service=self.container.resolve(HomeKitOutletService),
515
+ dimminglight_service=self.container.resolve(HomeKitDimmingLightService),
516
+ cache_service=self.container.resolve(HomeKitCacheService),
517
+ conbus_service=self.container.resolve(HomeKitConbusService),
518
+ module_factory=self.container.resolve(HomekitHapService),
519
+ telegram_service=self.container.resolve(TelegramService),
520
+ ),
521
+ scope=punq.Scope.singleton,
522
+ )
523
+
524
+ def get_container(self) -> punq.Container:
525
+ """
526
+ Get the configured container with all services registered.
527
+
528
+ Returns:
529
+ punq.Container: The configured dependency injection container
530
+ """
531
+ return self.container
@@ -0,0 +1,31 @@
1
+ """Event handling utilities for PyDispatcher integration.
2
+
3
+ This module provides clean, reusable utilities for handling PyDispatcher
4
+ responses across all HomeKit accessory classes.
5
+ """
6
+
7
+ from typing import Any, Callable, List, Tuple
8
+
9
+
10
+ def get_first_response(
11
+ responses: List[Tuple[Callable, Any]], default: Any = None
12
+ ) -> Any:
13
+ """Extract the first non-None response from PyDispatcher responses.
14
+
15
+ Args:
16
+ responses: List of (receiver_function, return_value) tuples from dispatcher.send()
17
+ default: Value to return if no valid responses found
18
+
19
+ Returns:
20
+ First non-None response value, or default if none found
21
+
22
+ Examples:
23
+ >>> responses = [(<func1>, None), (<func2>, True), (<func3>, False)]
24
+ >>> get_first_response(responses)
25
+ True
26
+
27
+ >>> responses = [(<func1>, None), (<func2>, None)]
28
+ >>> get_first_response(responses, default=False)
29
+ False
30
+ """
31
+ return next((r[1] for r in responses if r[1] is not None), default)