conson-xp 1.1.0__py3-none-any.whl → 1.3.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 (174) hide show
  1. {conson_xp-1.1.0.dist-info → conson_xp-1.3.0.dist-info}/METADATA +1 -5
  2. conson_xp-1.3.0.dist-info/RECORD +164 -0
  3. xp/__init__.py +4 -3
  4. xp/cli/__init__.py +1 -1
  5. xp/cli/commands/__init__.py +1 -2
  6. xp/cli/commands/conbus/conbus.py +9 -37
  7. xp/cli/commands/conbus/conbus_actiontable_commands.py +26 -4
  8. xp/cli/commands/conbus/conbus_autoreport_commands.py +58 -30
  9. xp/cli/commands/conbus/conbus_blink_commands.py +61 -29
  10. xp/cli/commands/conbus/conbus_config_commands.py +10 -5
  11. xp/cli/commands/conbus/conbus_custom_commands.py +16 -5
  12. xp/cli/commands/conbus/conbus_datapoint_commands.py +32 -10
  13. xp/cli/commands/conbus/conbus_discover_commands.py +20 -7
  14. xp/cli/commands/conbus/conbus_lightlevel_commands.py +114 -39
  15. xp/cli/commands/conbus/conbus_linknumber_commands.py +50 -25
  16. xp/cli/commands/conbus/conbus_msactiontable_commands.py +36 -5
  17. xp/cli/commands/conbus/conbus_output_commands.py +52 -14
  18. xp/cli/commands/conbus/conbus_raw_commands.py +17 -6
  19. xp/cli/commands/conbus/conbus_receive_commands.py +20 -10
  20. xp/cli/commands/conbus/conbus_scan_commands.py +17 -4
  21. xp/cli/commands/file_commands.py +35 -18
  22. xp/cli/commands/homekit/homekit.py +14 -8
  23. xp/cli/commands/homekit/homekit_start_commands.py +8 -6
  24. xp/cli/commands/module_commands.py +38 -23
  25. xp/cli/commands/reverse_proxy_commands.py +27 -19
  26. xp/cli/commands/server/server_commands.py +18 -18
  27. xp/cli/commands/telegram/telegram.py +4 -12
  28. xp/cli/commands/telegram/telegram_blink_commands.py +10 -8
  29. xp/cli/commands/telegram/telegram_checksum_commands.py +19 -8
  30. xp/cli/commands/telegram/telegram_discover_commands.py +2 -4
  31. xp/cli/commands/telegram/telegram_linknumber_commands.py +11 -8
  32. xp/cli/commands/telegram/telegram_parse_commands.py +10 -9
  33. xp/cli/commands/telegram/telegram_version_commands.py +8 -4
  34. xp/cli/main.py +5 -3
  35. xp/cli/utils/click_tree.py +23 -3
  36. xp/cli/utils/datapoint_type_choice.py +20 -0
  37. xp/cli/utils/decorators.py +165 -14
  38. xp/cli/utils/error_handlers.py +49 -18
  39. xp/cli/utils/formatters.py +95 -10
  40. xp/cli/utils/serial_number_type.py +18 -0
  41. xp/cli/utils/system_function_choice.py +20 -0
  42. xp/cli/utils/xp_module_type.py +20 -0
  43. xp/connection/__init__.py +1 -1
  44. xp/connection/exceptions.py +5 -5
  45. xp/models/__init__.py +1 -1
  46. xp/models/actiontable/__init__.py +1 -0
  47. xp/models/actiontable/actiontable.py +17 -1
  48. xp/models/actiontable/msactiontable_xp20.py +10 -0
  49. xp/models/actiontable/msactiontable_xp24.py +20 -3
  50. xp/models/actiontable/msactiontable_xp33.py +27 -4
  51. xp/models/conbus/__init__.py +1 -0
  52. xp/models/conbus/conbus.py +34 -4
  53. xp/models/conbus/conbus_autoreport.py +20 -2
  54. xp/models/conbus/conbus_blink.py +22 -2
  55. xp/models/conbus/conbus_client_config.py +22 -1
  56. xp/models/conbus/conbus_connection_status.py +16 -2
  57. xp/models/conbus/conbus_custom.py +21 -2
  58. xp/models/conbus/conbus_datapoint.py +25 -2
  59. xp/models/conbus/conbus_discover.py +18 -2
  60. xp/models/conbus/conbus_lightlevel.py +20 -2
  61. xp/models/conbus/conbus_linknumber.py +20 -2
  62. xp/models/conbus/conbus_output.py +22 -2
  63. xp/models/conbus/conbus_raw.py +17 -2
  64. xp/models/conbus/conbus_receive.py +16 -2
  65. xp/models/conbus/conbus_writeconfig.py +60 -0
  66. xp/models/homekit/__init__.py +1 -0
  67. xp/models/homekit/homekit_accessory.py +15 -1
  68. xp/models/homekit/homekit_config.py +52 -0
  69. xp/models/homekit/homekit_conson_config.py +32 -0
  70. xp/models/log_entry.py +49 -9
  71. xp/models/protocol/__init__.py +1 -0
  72. xp/models/protocol/conbus_protocol.py +130 -21
  73. xp/models/telegram/__init__.py +1 -0
  74. xp/models/telegram/action_type.py +16 -2
  75. xp/models/telegram/datapoint_type.py +36 -2
  76. xp/models/telegram/event_telegram.py +46 -10
  77. xp/models/telegram/event_type.py +8 -1
  78. xp/models/telegram/input_action_type.py +34 -2
  79. xp/models/telegram/input_type.py +9 -1
  80. xp/models/telegram/module_type.py +69 -19
  81. xp/models/telegram/module_type_code.py +43 -1
  82. xp/models/telegram/output_telegram.py +30 -6
  83. xp/models/telegram/reply_telegram.py +56 -11
  84. xp/models/telegram/system_function.py +35 -3
  85. xp/models/telegram/system_telegram.py +18 -4
  86. xp/models/telegram/telegram.py +12 -3
  87. xp/models/telegram/telegram_type.py +8 -1
  88. xp/models/telegram/timeparam_type.py +27 -0
  89. xp/models/write_config_type.py +17 -2
  90. xp/services/__init__.py +1 -1
  91. xp/services/conbus/__init__.py +1 -0
  92. xp/services/conbus/actiontable/__init__.py +1 -0
  93. xp/services/conbus/actiontable/actiontable_service.py +33 -2
  94. xp/services/conbus/actiontable/msactiontable_service.py +40 -3
  95. xp/services/conbus/actiontable/msactiontable_xp24_serializer.py +36 -4
  96. xp/services/conbus/actiontable/msactiontable_xp33_serializer.py +45 -5
  97. xp/services/conbus/conbus_blink_all_service.py +40 -21
  98. xp/services/conbus/conbus_blink_service.py +37 -13
  99. xp/services/conbus/conbus_custom_service.py +29 -13
  100. xp/services/conbus/conbus_datapoint_queryall_service.py +40 -16
  101. xp/services/conbus/conbus_datapoint_service.py +42 -18
  102. xp/services/conbus/conbus_discover_service.py +43 -7
  103. xp/services/conbus/conbus_output_service.py +33 -13
  104. xp/services/conbus/conbus_raw_service.py +36 -16
  105. xp/services/conbus/conbus_receive_service.py +38 -6
  106. xp/services/conbus/conbus_scan_service.py +44 -18
  107. xp/services/conbus/write_config_service.py +193 -0
  108. xp/services/homekit/__init__.py +1 -0
  109. xp/services/homekit/homekit_cache_service.py +31 -6
  110. xp/services/homekit/homekit_conbus_service.py +33 -2
  111. xp/services/homekit/homekit_config_validator.py +97 -15
  112. xp/services/homekit/homekit_conson_validator.py +51 -7
  113. xp/services/homekit/homekit_dimminglight.py +47 -1
  114. xp/services/homekit/homekit_dimminglight_service.py +35 -1
  115. xp/services/homekit/homekit_hap_service.py +71 -18
  116. xp/services/homekit/homekit_lightbulb.py +35 -1
  117. xp/services/homekit/homekit_lightbulb_service.py +30 -2
  118. xp/services/homekit/homekit_module_service.py +23 -1
  119. xp/services/homekit/homekit_outlet.py +47 -1
  120. xp/services/homekit/homekit_outlet_service.py +44 -2
  121. xp/services/homekit/homekit_service.py +113 -19
  122. xp/services/log_file_service.py +37 -41
  123. xp/services/module_type_service.py +26 -5
  124. xp/services/protocol/__init__.py +1 -1
  125. xp/services/protocol/conbus_protocol.py +110 -16
  126. xp/services/protocol/protocol_factory.py +40 -0
  127. xp/services/protocol/telegram_protocol.py +38 -7
  128. xp/services/reverse_proxy_service.py +79 -14
  129. xp/services/server/__init__.py +1 -0
  130. xp/services/server/base_server_service.py +102 -14
  131. xp/services/server/cp20_server_service.py +12 -4
  132. xp/services/server/server_service.py +26 -11
  133. xp/services/server/xp130_server_service.py +11 -3
  134. xp/services/server/xp20_server_service.py +11 -3
  135. xp/services/server/xp230_server_service.py +11 -3
  136. xp/services/server/xp24_server_service.py +33 -6
  137. xp/services/server/xp33_server_service.py +41 -8
  138. xp/services/telegram/__init__.py +1 -0
  139. xp/services/telegram/telegram_blink_service.py +19 -31
  140. xp/services/telegram/telegram_checksum_service.py +10 -10
  141. xp/services/telegram/telegram_datapoint_service.py +70 -0
  142. xp/services/telegram/telegram_discover_service.py +58 -29
  143. xp/services/telegram/telegram_link_number_service.py +27 -40
  144. xp/services/telegram/telegram_output_service.py +46 -49
  145. xp/services/telegram/telegram_service.py +41 -41
  146. xp/services/telegram/telegram_version_service.py +4 -2
  147. xp/utils/__init__.py +1 -1
  148. xp/utils/dependencies.py +4 -47
  149. xp/utils/serialization.py +6 -0
  150. xp/utils/time_utils.py +6 -11
  151. conson_xp-1.1.0.dist-info/RECORD +0 -181
  152. xp/api/__init__.py +0 -1
  153. xp/api/main.py +0 -110
  154. xp/api/models/__init__.py +0 -1
  155. xp/api/models/api.py +0 -20
  156. xp/api/models/discover.py +0 -21
  157. xp/api/routers/__init__.py +0 -17
  158. xp/api/routers/conbus.py +0 -5
  159. xp/api/routers/conbus_blink.py +0 -105
  160. xp/api/routers/conbus_custom.py +0 -63
  161. xp/api/routers/conbus_datapoint.py +0 -67
  162. xp/api/routers/conbus_output.py +0 -147
  163. xp/api/routers/errors.py +0 -37
  164. xp/cli/commands/api.py +0 -16
  165. xp/cli/commands/api_start_commands.py +0 -126
  166. xp/services/conbus/conbus_autoreport_get_service.py +0 -85
  167. xp/services/conbus/conbus_autoreport_set_service.py +0 -128
  168. xp/services/conbus/conbus_lightlevel_get_service.py +0 -101
  169. xp/services/conbus/conbus_lightlevel_set_service.py +0 -205
  170. xp/services/conbus/conbus_linknumber_get_service.py +0 -86
  171. xp/services/conbus/conbus_linknumber_set_service.py +0 -155
  172. {conson_xp-1.1.0.dist-info → conson_xp-1.3.0.dist-info}/WHEEL +0 -0
  173. {conson_xp-1.1.0.dist-info → conson_xp-1.3.0.dist-info}/entry_points.txt +0 -0
  174. {conson_xp-1.1.0.dist-info → conson_xp-1.3.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,3 +1,8 @@
1
+ """HomeKit Configuration Validator.
2
+
3
+ This module validates HomeKit configuration files for correctness and consistency.
4
+ """
5
+
1
6
  from contextlib import suppress
2
7
  from typing import List, Set
3
8
 
@@ -9,10 +14,19 @@ class HomekitConfigValidator:
9
14
  """Validates homekit.yml configuration file for HomeKit integration."""
10
15
 
11
16
  def __init__(self, config: HomekitConfig):
17
+ """Initialize the HomeKit config validator.
18
+
19
+ Args:
20
+ config: HomeKit configuration to validate.
21
+ """
12
22
  self.config = config
13
23
 
14
24
  def validate_unique_accessory_names(self) -> List[str]:
15
- """Validate that all accessory names are unique."""
25
+ """Validate that all accessory names are unique.
26
+
27
+ Returns:
28
+ List of validation error messages.
29
+ """
16
30
  names: Set[str] = set()
17
31
  errors = []
18
32
 
@@ -24,10 +38,19 @@ class HomekitConfigValidator:
24
38
  return errors
25
39
 
26
40
  def validate_service_types(self) -> List[str]:
27
- """Validate that service types are valid."""
41
+ """Validate that service types are valid.
42
+
43
+ Returns:
44
+ List of validation error messages.
45
+ """
28
46
  valid_services = {"lightbulb", "outlet", "dimminglight"}
29
47
  errors = [
30
- f"Invalid service type '{accessory.service}' for accessory '{accessory.name}'. Valid types: {', '.join(valid_services)}"
48
+ (
49
+ f"Invalid "
50
+ f"service type '{accessory.service}' "
51
+ f"for accessory '{accessory.name}'. "
52
+ f"Valid types: {', '.join(valid_services)}"
53
+ )
31
54
  for accessory in self.config.accessories
32
55
  if accessory.service not in valid_services
33
56
  ]
@@ -35,7 +58,11 @@ class HomekitConfigValidator:
35
58
  return errors
36
59
 
37
60
  def validate_output_numbers(self) -> List[str]:
38
- """Validate that output numbers are positive integers."""
61
+ """Validate that output numbers are positive integers.
62
+
63
+ Returns:
64
+ List of validation error messages.
65
+ """
39
66
  errors = [
40
67
  f"Invalid output number {accessory.output_number} for accessory '{accessory.name}'. Must be positive."
41
68
  for accessory in self.config.accessories
@@ -45,7 +72,11 @@ class HomekitConfigValidator:
45
72
  return errors
46
73
 
47
74
  def validate_unique_room_names(self) -> List[str]:
48
- """Validate that all room names are unique."""
75
+ """Validate that all room names are unique.
76
+
77
+ Returns:
78
+ List of validation error messages.
79
+ """
49
80
  names: Set[str] = set()
50
81
  errors = []
51
82
 
@@ -57,7 +88,11 @@ class HomekitConfigValidator:
57
88
  return errors
58
89
 
59
90
  def validate_room_accessory_references(self) -> List[str]:
60
- """Validate that all room accessories exist in accessories section."""
91
+ """Validate that all room accessories exist in accessories section.
92
+
93
+ Returns:
94
+ List of validation error messages.
95
+ """
61
96
  accessory_names = {acc.name for acc in self.config.accessories}
62
97
  errors = []
63
98
 
@@ -71,7 +106,11 @@ class HomekitConfigValidator:
71
106
  return errors
72
107
 
73
108
  def validate_no_orphaned_accessories(self) -> List[str]:
74
- """Validate that all accessories are assigned to at least one room."""
109
+ """Validate that all accessories are assigned to at least one room.
110
+
111
+ Returns:
112
+ List of validation error messages.
113
+ """
75
114
  assigned_accessories: Set[str] = set()
76
115
  for room in self.config.bridge.rooms:
77
116
  assigned_accessories.update(room.accessories)
@@ -85,7 +124,11 @@ class HomekitConfigValidator:
85
124
  return errors
86
125
 
87
126
  def validate_no_duplicate_accessory_assignments(self) -> List[str]:
88
- """Validate that accessories are not assigned to multiple rooms."""
127
+ """Validate that accessories are not assigned to multiple rooms.
128
+
129
+ Returns:
130
+ List of validation error messages.
131
+ """
89
132
  assigned_accessories: Set[str] = set()
90
133
  errors = []
91
134
 
@@ -100,7 +143,11 @@ class HomekitConfigValidator:
100
143
  return errors
101
144
 
102
145
  def validate_all(self) -> List[str]:
103
- """Run all validations and return combined errors."""
146
+ """Run all validations and return combined errors.
147
+
148
+ Returns:
149
+ List of all validation error messages.
150
+ """
104
151
  all_errors = []
105
152
  all_errors.extend(self.validate_unique_accessory_names())
106
153
  all_errors.extend(self.validate_service_types())
@@ -120,11 +167,21 @@ class CrossReferenceValidator:
120
167
  conson_validator: ConsonConfigValidator,
121
168
  homekit_validator: HomekitConfigValidator,
122
169
  ):
170
+ """Initialize the cross-reference validator.
171
+
172
+ Args:
173
+ conson_validator: Conson configuration validator.
174
+ homekit_validator: HomeKit configuration validator.
175
+ """
123
176
  self.conson_validator = conson_validator
124
177
  self.homekit_validator = homekit_validator
125
178
 
126
179
  def validate_serial_number_references(self) -> List[str]:
127
- """Validate that all accessory serial numbers exist in conson configuration."""
180
+ """Validate that all accessory serial numbers exist in conson configuration.
181
+
182
+ Returns:
183
+ List of validation error messages.
184
+ """
128
185
  conson_serials = self.conson_validator.get_all_serial_numbers()
129
186
  errors = [
130
187
  f"Accessory '{accessory.name}' references unknown serial number {accessory.serial_number}"
@@ -135,7 +192,11 @@ class CrossReferenceValidator:
135
192
  return errors
136
193
 
137
194
  def validate_output_capabilities(self) -> List[str]:
138
- """Validate that output numbers are within module capabilities."""
195
+ """Validate that output numbers are within module capabilities.
196
+
197
+ Returns:
198
+ List of validation error messages.
199
+ """
139
200
  errors = []
140
201
 
141
202
  for accessory in self.homekit_validator.config.accessories:
@@ -162,13 +223,20 @@ class CrossReferenceValidator:
162
223
 
163
224
  if accessory.output_number > max_outputs:
164
225
  errors.append(
165
- f"Accessory '{accessory.name}' output {accessory.output_number} exceeds module '{module.name}' ({module.module_type}) limit of {max_outputs}"
226
+ f"Accessory '{accessory.name}' "
227
+ f"output {accessory.output_number} "
228
+ f"exceeds module '{module.name}' ({module.module_type}) "
229
+ f"limit of {max_outputs}"
166
230
  )
167
231
 
168
232
  return errors
169
233
 
170
234
  def validate_all(self) -> List[str]:
171
- """Run all cross-reference validations and return combined errors."""
235
+ """Run all cross-reference validations and return combined errors.
236
+
237
+ Returns:
238
+ List of all cross-reference validation error messages.
239
+ """
172
240
  all_errors = []
173
241
  all_errors.extend(self.validate_serial_number_references())
174
242
  all_errors.extend(self.validate_output_capabilities())
@@ -179,6 +247,12 @@ class ConfigValidationService:
179
247
  """Main service for validating HomeKit configuration coherence."""
180
248
 
181
249
  def __init__(self, conson_config_path: str, homekit_config_path: str):
250
+ """Initialize the config validation service.
251
+
252
+ Args:
253
+ conson_config_path: Path to conson.yml configuration file.
254
+ homekit_config_path: Path to homekit.yml configuration file.
255
+ """
182
256
  from xp.models.homekit.homekit_config import HomekitConfig
183
257
  from xp.models.homekit.homekit_conson_config import ConsonModuleListConfig
184
258
 
@@ -192,7 +266,11 @@ class ConfigValidationService:
192
266
  )
193
267
 
194
268
  def validate_all(self) -> dict:
195
- """Run all validations and return organized results."""
269
+ """Run all validations and return organized results.
270
+
271
+ Returns:
272
+ Dictionary containing validation results and error counts.
273
+ """
196
274
  conson_errors = self.conson_validator.validate_all()
197
275
  homekit_errors = self.homekit_validator.validate_all()
198
276
  cross_errors = self.cross_validator.validate_all()
@@ -209,7 +287,11 @@ class ConfigValidationService:
209
287
  }
210
288
 
211
289
  def print_config_summary(self) -> str:
212
- """Generate a summary of the configuration."""
290
+ """Generate a summary of the configuration.
291
+
292
+ Returns:
293
+ String containing configuration summary.
294
+ """
213
295
  summary = [
214
296
  f"Conson Modules: {len(self.conson_config.root)}",
215
297
  f"HomeKit Accessories: {len(self.homekit_config.accessories)}",
@@ -1,3 +1,8 @@
1
+ """Conson Configuration Validator for HomeKit.
2
+
3
+ This module validates conson.yml configuration files for HomeKit integration.
4
+ """
5
+
1
6
  from typing import List, Set
2
7
 
3
8
  from xp.models.homekit.homekit_conson_config import (
@@ -10,10 +15,19 @@ class ConsonConfigValidator:
10
15
  """Validates conson.yml configuration file for HomeKit integration."""
11
16
 
12
17
  def __init__(self, config: ConsonModuleListConfig):
18
+ """Initialize the Conson config validator.
19
+
20
+ Args:
21
+ config: Conson module list configuration to validate.
22
+ """
13
23
  self.config = config
14
24
 
15
25
  def validate_unique_names(self) -> List[str]:
16
- """Validate that all module names are unique."""
26
+ """Validate that all module names are unique.
27
+
28
+ Returns:
29
+ List of validation error messages.
30
+ """
17
31
  names: Set[str] = set()
18
32
  errors = []
19
33
 
@@ -25,7 +39,11 @@ class ConsonConfigValidator:
25
39
  return errors
26
40
 
27
41
  def validate_unique_serial_numbers(self) -> List[str]:
28
- """Validate that all serial numbers are unique."""
42
+ """Validate that all serial numbers are unique.
43
+
44
+ Returns:
45
+ List of validation error messages.
46
+ """
29
47
  serials: Set[str] = set()
30
48
  errors = []
31
49
 
@@ -37,7 +55,11 @@ class ConsonConfigValidator:
37
55
  return errors
38
56
 
39
57
  def validate_module_type_codes(self) -> List[str]:
40
- """Validate module type code ranges."""
58
+ """Validate module type code ranges.
59
+
60
+ Returns:
61
+ List of validation error messages.
62
+ """
41
63
  errors = [
42
64
  f"Invalid module_type_code {module.module_type_code} for module {module.name}. Must be between 1 and 255."
43
65
  for module in self.config.root
@@ -47,7 +69,11 @@ class ConsonConfigValidator:
47
69
  return errors
48
70
 
49
71
  def validate_network_config(self) -> List[str]:
50
- """Validate IP/port configuration."""
72
+ """Validate IP/port configuration.
73
+
74
+ Returns:
75
+ List of validation error messages.
76
+ """
51
77
  errors = [
52
78
  f"Invalid conbus_port {module.conbus_port} for module {module.name}. Must be between 1 and 65535."
53
79
  for module in self.config.root
@@ -57,7 +83,11 @@ class ConsonConfigValidator:
57
83
  return errors
58
84
 
59
85
  def validate_all(self) -> List[str]:
60
- """Run all validations and return combined errors."""
86
+ """Run all validations and return combined errors.
87
+
88
+ Returns:
89
+ List of all validation error messages.
90
+ """
61
91
  all_errors = []
62
92
  all_errors.extend(self.validate_unique_names())
63
93
  all_errors.extend(self.validate_unique_serial_numbers())
@@ -66,12 +96,26 @@ class ConsonConfigValidator:
66
96
  return all_errors
67
97
 
68
98
  def get_module_by_serial(self, serial_number: str) -> ConsonModuleConfig:
69
- """Get module configuration by serial number."""
99
+ """Get module configuration by serial number.
100
+
101
+ Args:
102
+ serial_number: Serial number of the module to find.
103
+
104
+ Returns:
105
+ Module configuration for the specified serial number.
106
+
107
+ Raises:
108
+ ValueError: If module with serial number is not found.
109
+ """
70
110
  for module in self.config.root:
71
111
  if module.serial_number == serial_number:
72
112
  return module
73
113
  raise ValueError(f"Module with serial number {serial_number} not found")
74
114
 
75
115
  def get_all_serial_numbers(self) -> Set[str]:
76
- """Get all serial numbers from the configuration."""
116
+ """Get all serial numbers from the configuration.
117
+
118
+ Returns:
119
+ Set of all serial numbers in the configuration.
120
+ """
77
121
  return {module.serial_number for module in self.config.root}
@@ -1,3 +1,8 @@
1
+ """HomeKit Dimming Light Accessory.
2
+
3
+ This module provides a dimming light accessory for HomeKit integration.
4
+ """
5
+
1
6
  import logging
2
7
 
3
8
  from bubus import EventBus
@@ -16,7 +21,20 @@ from xp.models.protocol.conbus_protocol import (
16
21
 
17
22
 
18
23
  class DimmingLight(Accessory):
19
- """Fake lightbulb, logs what the client sets."""
24
+ """HomeKit dimming light accessory.
25
+
26
+ Attributes:
27
+ category: HomeKit category (CATEGORY_LIGHTBULB).
28
+ event_bus: Event bus for inter-service communication.
29
+ logger: Logger instance.
30
+ identifier: Unique identifier for the accessory.
31
+ accessory: Accessory configuration.
32
+ module: Module configuration.
33
+ is_on: Current on/off state.
34
+ brightness: Current brightness level (0-100).
35
+ char_on: On characteristic.
36
+ char_brightness: Brightness characteristic.
37
+ """
20
38
 
21
39
  category = CATEGORY_LIGHTBULB
22
40
  event_bus: EventBus
@@ -28,6 +46,14 @@ class DimmingLight(Accessory):
28
46
  accessory: HomekitAccessoryConfig,
29
47
  event_bus: EventBus,
30
48
  ):
49
+ """Initialize the dimming light accessory.
50
+
51
+ Args:
52
+ driver: HAP accessory driver.
53
+ module: Module configuration.
54
+ accessory: Accessory configuration.
55
+ event_bus: Event bus for inter-service communication.
56
+ """
31
57
  super().__init__(driver, accessory.description)
32
58
 
33
59
  self.logger = logging.getLogger(__name__)
@@ -76,6 +102,11 @@ class DimmingLight(Accessory):
76
102
  )
77
103
 
78
104
  def set_on(self, value: bool) -> None:
105
+ """Set the on/off state of the dimming light.
106
+
107
+ Args:
108
+ value: True to turn on, False to turn off.
109
+ """
79
110
  # Emit set event
80
111
  self.logger.debug(f"set_on {value}")
81
112
 
@@ -93,6 +124,11 @@ class DimmingLight(Accessory):
93
124
  )
94
125
 
95
126
  def get_on(self) -> bool:
127
+ """Get the on/off state of the dimming light.
128
+
129
+ Returns:
130
+ True if on, False if off.
131
+ """
96
132
  # Emit event and get response
97
133
  self.logger.debug("get_on")
98
134
 
@@ -108,6 +144,11 @@ class DimmingLight(Accessory):
108
144
  return self.is_on
109
145
 
110
146
  def set_brightness(self, value: int) -> None:
147
+ """Set the brightness level of the dimming light.
148
+
149
+ Args:
150
+ value: Brightness level (0-100).
151
+ """
111
152
  self.logger.debug(f"set_brightness {value}")
112
153
  self.brightness = value
113
154
 
@@ -122,6 +163,11 @@ class DimmingLight(Accessory):
122
163
  )
123
164
 
124
165
  def get_brightness(self) -> int:
166
+ """Get the brightness level of the dimming light.
167
+
168
+ Returns:
169
+ Current brightness level (0-100).
170
+ """
125
171
  self.logger.debug("get_brightness")
126
172
 
127
173
  # Dispatch event from HAP thread (thread-safe)
@@ -1,3 +1,8 @@
1
+ """HomeKit Dimming Light Service.
2
+
3
+ This module provides service implementation for dimming light accessories.
4
+ """
5
+
1
6
  import logging
2
7
 
3
8
  from bubus import EventBus
@@ -14,12 +19,21 @@ from xp.models.telegram.datapoint_type import DataPointType
14
19
 
15
20
 
16
21
  class HomeKitDimmingLightService:
17
- """Dimming light service for HomeKit"""
22
+ """Dimming light service for HomeKit.
23
+
24
+ Attributes:
25
+ event_bus: Event bus for inter-service communication.
26
+ logger: Logger instance.
27
+ """
18
28
 
19
29
  event_bus: EventBus
20
30
 
21
31
  def __init__(self, event_bus: EventBus) -> None:
32
+ """Initialize the dimming light service.
22
33
 
34
+ Args:
35
+ event_bus: Event bus instance.
36
+ """
23
37
  self.logger = logging.getLogger(__name__)
24
38
  self.event_bus = event_bus
25
39
 
@@ -34,6 +48,11 @@ class HomeKitDimmingLightService:
34
48
  )
35
49
 
36
50
  def handle_dimminglight_get_on(self, event: DimmingLightGetOnEvent) -> None:
51
+ """Handle dimming light get on event.
52
+
53
+ Args:
54
+ event: Dimming light get on event.
55
+ """
37
56
  self.logger.info(
38
57
  f"Getting dimming light state for serial {event.serial_number}, output {event.output_number}"
39
58
  )
@@ -48,6 +67,11 @@ class HomeKitDimmingLightService:
48
67
  self.logger.debug(f"Dispatched ReadDatapointEvent for {event.serial_number}")
49
68
 
50
69
  def handle_dimminglight_set_on(self, event: DimmingLightSetOnEvent) -> None:
70
+ """Handle dimming light set on event.
71
+
72
+ Args:
73
+ event: Dimming light set on event.
74
+ """
51
75
  brightness = event.brightness if event.value else 0
52
76
  self.logger.debug(
53
77
  f"Setting on light for "
@@ -74,6 +98,11 @@ class HomeKitDimmingLightService:
74
98
  def handle_dimminglight_set_brightness(
75
99
  self, event: DimmingLightSetBrightnessEvent
76
100
  ) -> None:
101
+ """Handle dimming light set brightness event.
102
+
103
+ Args:
104
+ event: Dimming light set brightness event.
105
+ """
77
106
  self.logger.info(
78
107
  f"Setting dimming light brightness"
79
108
  f"serial {event.serial_number}, "
@@ -97,6 +126,11 @@ class HomeKitDimmingLightService:
97
126
  def handle_dimminglight_get_brightness(
98
127
  self, event: DimmingLightGetBrightnessEvent
99
128
  ) -> None:
129
+ """Handle dimming light get brightness event.
130
+
131
+ Args:
132
+ event: Dimming light get brightness event.
133
+ """
100
134
  self.logger.info(
101
135
  f"Getting dimming light brightness "
102
136
  f"for serial {event.serial_number}, "
@@ -1,3 +1,8 @@
1
+ """HomeKit HAP Service for Apple HomeKit integration.
2
+
3
+ This module provides the main HAP (HomeKit Accessory Protocol) service.
4
+ """
5
+
1
6
  import logging
2
7
  import signal
3
8
  import threading
@@ -30,11 +35,20 @@ from xp.services.homekit.homekit_outlet import Outlet
30
35
 
31
36
 
32
37
  class HomekitHapService:
33
- """
34
- HomeKit services.
35
-
36
- Manages TCP socket connections, handles telegram generation and transmission,
37
- and processes server responses.
38
+ """HomeKit HAP service.
39
+
40
+ Manages HAP accessory protocol, handles bridge and accessory setup,
41
+ and processes HomeKit events for device state synchronization.
42
+
43
+ Attributes:
44
+ event_bus: Event bus for inter-service communication.
45
+ last_activity: Timestamp of last service activity.
46
+ logger: Logger instance.
47
+ config: HomeKit configuration.
48
+ accessory_registry: Registry of accessories by identifier.
49
+ module_registry: Registry of accessories by module key.
50
+ modules: Module service for module lookup.
51
+ driver: HAP accessory driver.
38
52
  """
39
53
 
40
54
  event_bus: EventBus
@@ -45,12 +59,12 @@ class HomekitHapService:
45
59
  module_service: HomekitModuleService,
46
60
  event_bus: EventBus,
47
61
  ):
48
- """Initialize the Conbus client send service
62
+ """Initialize the HomeKit HAP service.
49
63
 
50
64
  Args:
51
- homekit_config: Conson configuration file
52
- module_service: HomekitModuleService for dependency injection
53
- event_bus: EventBus for dependency injection
65
+ homekit_config: HomeKit configuration.
66
+ module_service: Module service for dependency injection.
67
+ event_bus: Event bus for dependency injection.
54
68
  """
55
69
  self.last_activity: Optional[datetime] = None
56
70
 
@@ -82,13 +96,13 @@ class HomekitHapService:
82
96
  self.driver: AccessoryDriver = driver
83
97
 
84
98
  async def async_start(self) -> None:
85
- """Get current client configuration"""
86
- self.logger.info("Loading accessories...")
99
+ """Start the HAP service asynchronously."""
100
+ self.logger.info("Loading accessories.")
87
101
  self.build_bridge()
88
102
  self.logger.info("Accessories loaded successfully")
89
103
 
90
104
  # Start HAP-python in a separate thread to avoid event loop conflicts
91
- self.logger.info("Starting HAP-python driver in separate thread...")
105
+ self.logger.info("Starting HAP-python driver in separate thread.")
92
106
  hap_thread = threading.Thread(
93
107
  target=self._run_driver_in_thread, daemon=True, name="HAP-Python"
94
108
  )
@@ -96,19 +110,26 @@ class HomekitHapService:
96
110
  self.logger.info("HAP-python driver thread started")
97
111
 
98
112
  def _run_driver_in_thread(self) -> None:
99
- """Run the HAP-python driver in a separate thread with its own event loop"""
113
+ """Run the HAP-python driver in a separate thread with its own event loop."""
100
114
  try:
101
- self.logger.info("HAP-python thread starting, creating new event loop...")
115
+ self.logger.info("HAP-python thread starting, creating new event loop.")
102
116
  # Create a new event loop for this thread
103
117
 
104
- self.logger.info("Starting HAP-python driver...")
118
+ self.logger.info("Starting HAP-python driver.")
105
119
  self.driver.start()
106
120
  self.logger.info("HAP-python driver started successfully")
107
121
  except Exception as e:
108
122
  self.logger.error(f"HAP-python driver error: {e}", exc_info=True)
109
123
 
110
124
  def handle_output_state_received(self, event: OutputStateReceivedEvent) -> str:
125
+ """Handle output state received event.
126
+
127
+ Args:
128
+ event: Output state received event.
111
129
 
130
+ Returns:
131
+ Data value from the event.
132
+ """
112
133
  self.logger.debug(f"Received OutputStateReceivedEvent {event}")
113
134
  output_number = 0
114
135
  for output in event.data_value[::-1]:
@@ -131,7 +152,14 @@ class HomekitHapService:
131
152
  return event.data_value
132
153
 
133
154
  def handle_light_level_received(self, event: LightLevelReceivedEvent) -> str:
155
+ """Handle light level received event.
156
+
157
+ Args:
158
+ event: Light level received event.
134
159
 
160
+ Returns:
161
+ Data value from the event.
162
+ """
135
163
  # Parse response format like "00:050,01:025,02:100"
136
164
  self.logger.debug("Received LightLevelReceivedEvent", extra={"event": event})
137
165
  output_number = 0
@@ -165,6 +193,7 @@ class HomekitHapService:
165
193
  return event.data_value
166
194
 
167
195
  def build_bridge(self) -> None:
196
+ """Build the HomeKit bridge with all configured accessories."""
168
197
  bridge_config = self.config.bridge
169
198
  bridge = Bridge(self.driver, bridge_config.name)
170
199
  bridge.set_info_service(
@@ -177,7 +206,12 @@ class HomekitHapService:
177
206
  self.driver.add_accessory(accessory=bridge)
178
207
 
179
208
  def add_room(self, bridge: Bridge, room: RoomConfig) -> None:
180
- """Call this method to get a Bridge instead of a standalone accessory."""
209
+ """Add a room with its accessories to the bridge.
210
+
211
+ Args:
212
+ bridge: HAP bridge instance.
213
+ room: Room configuration.
214
+ """
181
215
  temperature = TemperatureSensor(self.driver, room.name)
182
216
  bridge.add_accessory(temperature)
183
217
 
@@ -205,7 +239,14 @@ class HomekitHapService:
205
239
  def get_accessory(
206
240
  self, homekit_accessory: HomekitAccessoryConfig
207
241
  ) -> Union[LightBulb, Outlet, DimmingLight, None]:
208
- """Call this method to get a standalone Accessory."""
242
+ """Get an accessory instance from configuration.
243
+
244
+ Args:
245
+ homekit_accessory: HomeKit accessory configuration.
246
+
247
+ Returns:
248
+ Accessory instance or None if not found or invalid service type.
249
+ """
209
250
  module_config = self.modules.get_module_by_serial(
210
251
  homekit_accessory.serial_number
211
252
  )
@@ -241,12 +282,24 @@ class HomekitHapService:
241
282
  return None
242
283
 
243
284
  def get_accessory_by_name(self, name: str) -> Optional[HomekitAccessoryConfig]:
285
+ """Get an accessory configuration by name.
286
+
287
+ Args:
288
+ name: Name of the accessory to find.
289
+
290
+ Returns:
291
+ Accessory configuration if found, None otherwise.
292
+ """
244
293
  return next(
245
294
  (module for module in self.config.accessories if module.name == name), None
246
295
  )
247
296
 
248
297
  def handle_module_state_changed(self, event: ModuleStateChangedEvent) -> None:
249
- """Handle module state change by refreshing affected accessories"""
298
+ """Handle module state change by refreshing affected accessories.
299
+
300
+ Args:
301
+ event: Module state changed event.
302
+ """
250
303
  self.logger.debug(
251
304
  f"Module state changed: module_type={event.module_type_code}, "
252
305
  f"link={event.link_number}, input={event.input_number}"