aiohomematic 2026.1.29__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 (188) hide show
  1. aiohomematic/__init__.py +110 -0
  2. aiohomematic/_log_context_protocol.py +29 -0
  3. aiohomematic/api.py +410 -0
  4. aiohomematic/async_support.py +250 -0
  5. aiohomematic/backend_detection.py +462 -0
  6. aiohomematic/central/__init__.py +103 -0
  7. aiohomematic/central/async_rpc_server.py +760 -0
  8. aiohomematic/central/central_unit.py +1152 -0
  9. aiohomematic/central/config.py +463 -0
  10. aiohomematic/central/config_builder.py +772 -0
  11. aiohomematic/central/connection_state.py +160 -0
  12. aiohomematic/central/coordinators/__init__.py +38 -0
  13. aiohomematic/central/coordinators/cache.py +414 -0
  14. aiohomematic/central/coordinators/client.py +480 -0
  15. aiohomematic/central/coordinators/connection_recovery.py +1141 -0
  16. aiohomematic/central/coordinators/device.py +1166 -0
  17. aiohomematic/central/coordinators/event.py +514 -0
  18. aiohomematic/central/coordinators/hub.py +532 -0
  19. aiohomematic/central/decorators.py +184 -0
  20. aiohomematic/central/device_registry.py +229 -0
  21. aiohomematic/central/events/__init__.py +104 -0
  22. aiohomematic/central/events/bus.py +1392 -0
  23. aiohomematic/central/events/integration.py +424 -0
  24. aiohomematic/central/events/types.py +194 -0
  25. aiohomematic/central/health.py +762 -0
  26. aiohomematic/central/rpc_server.py +353 -0
  27. aiohomematic/central/scheduler.py +794 -0
  28. aiohomematic/central/state_machine.py +391 -0
  29. aiohomematic/client/__init__.py +203 -0
  30. aiohomematic/client/_rpc_errors.py +187 -0
  31. aiohomematic/client/backends/__init__.py +48 -0
  32. aiohomematic/client/backends/base.py +335 -0
  33. aiohomematic/client/backends/capabilities.py +138 -0
  34. aiohomematic/client/backends/ccu.py +487 -0
  35. aiohomematic/client/backends/factory.py +116 -0
  36. aiohomematic/client/backends/homegear.py +294 -0
  37. aiohomematic/client/backends/json_ccu.py +252 -0
  38. aiohomematic/client/backends/protocol.py +316 -0
  39. aiohomematic/client/ccu.py +1857 -0
  40. aiohomematic/client/circuit_breaker.py +459 -0
  41. aiohomematic/client/config.py +64 -0
  42. aiohomematic/client/handlers/__init__.py +40 -0
  43. aiohomematic/client/handlers/backup.py +157 -0
  44. aiohomematic/client/handlers/base.py +79 -0
  45. aiohomematic/client/handlers/device_ops.py +1085 -0
  46. aiohomematic/client/handlers/firmware.py +144 -0
  47. aiohomematic/client/handlers/link_mgmt.py +199 -0
  48. aiohomematic/client/handlers/metadata.py +436 -0
  49. aiohomematic/client/handlers/programs.py +144 -0
  50. aiohomematic/client/handlers/sysvars.py +100 -0
  51. aiohomematic/client/interface_client.py +1304 -0
  52. aiohomematic/client/json_rpc.py +2068 -0
  53. aiohomematic/client/request_coalescer.py +282 -0
  54. aiohomematic/client/rpc_proxy.py +629 -0
  55. aiohomematic/client/state_machine.py +324 -0
  56. aiohomematic/const.py +2207 -0
  57. aiohomematic/context.py +275 -0
  58. aiohomematic/converter.py +270 -0
  59. aiohomematic/decorators.py +390 -0
  60. aiohomematic/exceptions.py +185 -0
  61. aiohomematic/hmcli.py +997 -0
  62. aiohomematic/i18n.py +193 -0
  63. aiohomematic/interfaces/__init__.py +407 -0
  64. aiohomematic/interfaces/central.py +1067 -0
  65. aiohomematic/interfaces/client.py +1096 -0
  66. aiohomematic/interfaces/coordinators.py +63 -0
  67. aiohomematic/interfaces/model.py +1921 -0
  68. aiohomematic/interfaces/operations.py +217 -0
  69. aiohomematic/logging_context.py +134 -0
  70. aiohomematic/metrics/__init__.py +125 -0
  71. aiohomematic/metrics/_protocols.py +140 -0
  72. aiohomematic/metrics/aggregator.py +534 -0
  73. aiohomematic/metrics/dataclasses.py +489 -0
  74. aiohomematic/metrics/emitter.py +292 -0
  75. aiohomematic/metrics/events.py +183 -0
  76. aiohomematic/metrics/keys.py +300 -0
  77. aiohomematic/metrics/observer.py +563 -0
  78. aiohomematic/metrics/stats.py +172 -0
  79. aiohomematic/model/__init__.py +189 -0
  80. aiohomematic/model/availability.py +65 -0
  81. aiohomematic/model/calculated/__init__.py +89 -0
  82. aiohomematic/model/calculated/climate.py +276 -0
  83. aiohomematic/model/calculated/data_point.py +315 -0
  84. aiohomematic/model/calculated/field.py +147 -0
  85. aiohomematic/model/calculated/operating_voltage_level.py +286 -0
  86. aiohomematic/model/calculated/support.py +232 -0
  87. aiohomematic/model/custom/__init__.py +214 -0
  88. aiohomematic/model/custom/capabilities/__init__.py +67 -0
  89. aiohomematic/model/custom/capabilities/climate.py +41 -0
  90. aiohomematic/model/custom/capabilities/light.py +87 -0
  91. aiohomematic/model/custom/capabilities/lock.py +44 -0
  92. aiohomematic/model/custom/capabilities/siren.py +63 -0
  93. aiohomematic/model/custom/climate.py +1130 -0
  94. aiohomematic/model/custom/cover.py +722 -0
  95. aiohomematic/model/custom/data_point.py +360 -0
  96. aiohomematic/model/custom/definition.py +300 -0
  97. aiohomematic/model/custom/field.py +89 -0
  98. aiohomematic/model/custom/light.py +1174 -0
  99. aiohomematic/model/custom/lock.py +322 -0
  100. aiohomematic/model/custom/mixins.py +445 -0
  101. aiohomematic/model/custom/profile.py +945 -0
  102. aiohomematic/model/custom/registry.py +251 -0
  103. aiohomematic/model/custom/siren.py +462 -0
  104. aiohomematic/model/custom/switch.py +195 -0
  105. aiohomematic/model/custom/text_display.py +289 -0
  106. aiohomematic/model/custom/valve.py +78 -0
  107. aiohomematic/model/data_point.py +1416 -0
  108. aiohomematic/model/device.py +1840 -0
  109. aiohomematic/model/event.py +216 -0
  110. aiohomematic/model/generic/__init__.py +327 -0
  111. aiohomematic/model/generic/action.py +40 -0
  112. aiohomematic/model/generic/action_select.py +62 -0
  113. aiohomematic/model/generic/binary_sensor.py +30 -0
  114. aiohomematic/model/generic/button.py +31 -0
  115. aiohomematic/model/generic/data_point.py +177 -0
  116. aiohomematic/model/generic/dummy.py +150 -0
  117. aiohomematic/model/generic/number.py +76 -0
  118. aiohomematic/model/generic/select.py +56 -0
  119. aiohomematic/model/generic/sensor.py +76 -0
  120. aiohomematic/model/generic/switch.py +54 -0
  121. aiohomematic/model/generic/text.py +33 -0
  122. aiohomematic/model/hub/__init__.py +100 -0
  123. aiohomematic/model/hub/binary_sensor.py +24 -0
  124. aiohomematic/model/hub/button.py +28 -0
  125. aiohomematic/model/hub/connectivity.py +190 -0
  126. aiohomematic/model/hub/data_point.py +342 -0
  127. aiohomematic/model/hub/hub.py +864 -0
  128. aiohomematic/model/hub/inbox.py +135 -0
  129. aiohomematic/model/hub/install_mode.py +393 -0
  130. aiohomematic/model/hub/metrics.py +208 -0
  131. aiohomematic/model/hub/number.py +42 -0
  132. aiohomematic/model/hub/select.py +52 -0
  133. aiohomematic/model/hub/sensor.py +37 -0
  134. aiohomematic/model/hub/switch.py +43 -0
  135. aiohomematic/model/hub/text.py +30 -0
  136. aiohomematic/model/hub/update.py +221 -0
  137. aiohomematic/model/support.py +592 -0
  138. aiohomematic/model/update.py +140 -0
  139. aiohomematic/model/week_profile.py +1827 -0
  140. aiohomematic/property_decorators.py +719 -0
  141. aiohomematic/py.typed +0 -0
  142. aiohomematic/rega_scripts/accept_device_in_inbox.fn +51 -0
  143. aiohomematic/rega_scripts/create_backup_start.fn +28 -0
  144. aiohomematic/rega_scripts/create_backup_status.fn +89 -0
  145. aiohomematic/rega_scripts/fetch_all_device_data.fn +97 -0
  146. aiohomematic/rega_scripts/get_backend_info.fn +25 -0
  147. aiohomematic/rega_scripts/get_inbox_devices.fn +61 -0
  148. aiohomematic/rega_scripts/get_program_descriptions.fn +31 -0
  149. aiohomematic/rega_scripts/get_serial.fn +44 -0
  150. aiohomematic/rega_scripts/get_service_messages.fn +83 -0
  151. aiohomematic/rega_scripts/get_system_update_info.fn +39 -0
  152. aiohomematic/rega_scripts/get_system_variable_descriptions.fn +31 -0
  153. aiohomematic/rega_scripts/set_program_state.fn +17 -0
  154. aiohomematic/rega_scripts/set_system_variable.fn +19 -0
  155. aiohomematic/rega_scripts/trigger_firmware_update.fn +67 -0
  156. aiohomematic/schemas.py +256 -0
  157. aiohomematic/store/__init__.py +55 -0
  158. aiohomematic/store/dynamic/__init__.py +43 -0
  159. aiohomematic/store/dynamic/command.py +250 -0
  160. aiohomematic/store/dynamic/data.py +175 -0
  161. aiohomematic/store/dynamic/details.py +187 -0
  162. aiohomematic/store/dynamic/ping_pong.py +416 -0
  163. aiohomematic/store/persistent/__init__.py +71 -0
  164. aiohomematic/store/persistent/base.py +285 -0
  165. aiohomematic/store/persistent/device.py +233 -0
  166. aiohomematic/store/persistent/incident.py +380 -0
  167. aiohomematic/store/persistent/paramset.py +241 -0
  168. aiohomematic/store/persistent/session.py +556 -0
  169. aiohomematic/store/serialization.py +150 -0
  170. aiohomematic/store/storage.py +689 -0
  171. aiohomematic/store/types.py +526 -0
  172. aiohomematic/store/visibility/__init__.py +40 -0
  173. aiohomematic/store/visibility/parser.py +141 -0
  174. aiohomematic/store/visibility/registry.py +722 -0
  175. aiohomematic/store/visibility/rules.py +307 -0
  176. aiohomematic/strings.json +237 -0
  177. aiohomematic/support.py +706 -0
  178. aiohomematic/tracing.py +236 -0
  179. aiohomematic/translations/de.json +237 -0
  180. aiohomematic/translations/en.json +237 -0
  181. aiohomematic/type_aliases.py +51 -0
  182. aiohomematic/validator.py +128 -0
  183. aiohomematic-2026.1.29.dist-info/METADATA +296 -0
  184. aiohomematic-2026.1.29.dist-info/RECORD +188 -0
  185. aiohomematic-2026.1.29.dist-info/WHEEL +5 -0
  186. aiohomematic-2026.1.29.dist-info/entry_points.txt +2 -0
  187. aiohomematic-2026.1.29.dist-info/licenses/LICENSE +21 -0
  188. aiohomematic-2026.1.29.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1067 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2021-2026
3
+ """
4
+ Central unit protocol interfaces.
5
+
6
+ This module defines protocol interfaces for CentralUnit operations,
7
+ allowing components to depend on central functionality without coupling
8
+ to the full CentralUnit implementation.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ from abc import abstractmethod
14
+ from collections.abc import Mapping
15
+ from typing import TYPE_CHECKING, Any, Protocol, Unpack, runtime_checkable
16
+
17
+ from aiohttp import ClientSession
18
+
19
+ from aiohomematic.const import (
20
+ BackupData,
21
+ CentralState,
22
+ ClientState,
23
+ DescriptionMarker,
24
+ DeviceFirmwareState,
25
+ DeviceTriggerEventType,
26
+ EventData,
27
+ FailureReason,
28
+ Interface,
29
+ OptionalSettings,
30
+ ParamsetKey,
31
+ ScheduleTimerConfig,
32
+ SystemEventType,
33
+ SystemInformation,
34
+ TimeoutConfig,
35
+ )
36
+ from aiohomematic.metrics._protocols import DeviceProviderForMetricsProtocol, HubDataPointManagerForMetricsProtocol
37
+
38
+ if TYPE_CHECKING:
39
+ from aiohomematic.central.coordinators import (
40
+ ClientCoordinator,
41
+ DeviceCoordinator,
42
+ EventCoordinator,
43
+ SystemEventArgs,
44
+ )
45
+ from aiohomematic.central.events import EventBus
46
+ from aiohomematic.client import InterfaceConfig
47
+ from aiohomematic.interfaces import (
48
+ CallbackDataPointProtocol,
49
+ ChannelProtocol,
50
+ GenericDataPointProtocolAny,
51
+ GenericSysvarDataPointProtocol,
52
+ )
53
+ from aiohomematic.metrics import MetricsObserver
54
+ from aiohomematic.model.hub import ProgramDpType
55
+ from aiohomematic.store import StorageFactoryProtocol
56
+
57
+
58
+ @runtime_checkable
59
+ class CentralConfigProtocol(Protocol):
60
+ """
61
+ Protocol for CentralConfig interface.
62
+
63
+ This protocol defines the configuration interface required by CentralUnit,
64
+ enabling dependency inversion to eliminate circular imports between
65
+ config.py and central_unit.py.
66
+
67
+ Implemented by CentralConfig.
68
+ """
69
+
70
+ @property
71
+ @abstractmethod
72
+ def callback_host(self) -> str | None:
73
+ """Return the callback host address."""
74
+
75
+ @property
76
+ @abstractmethod
77
+ def callback_port_xml_rpc(self) -> int | None:
78
+ """Return the callback port for XML-RPC."""
79
+
80
+ @property
81
+ @abstractmethod
82
+ def central_id(self) -> str:
83
+ """Return the central ID."""
84
+
85
+ @property
86
+ @abstractmethod
87
+ def client_session(self) -> ClientSession | None:
88
+ """Return the aiohttp client session."""
89
+
90
+ @property
91
+ @abstractmethod
92
+ def connection_check_port(self) -> int:
93
+ """Return the connection check port."""
94
+
95
+ @property
96
+ @abstractmethod
97
+ def default_callback_port_xml_rpc(self) -> int:
98
+ """Return the default callback port for XML-RPC."""
99
+
100
+ @property
101
+ @abstractmethod
102
+ def delay_new_device_creation(self) -> bool:
103
+ """Return if new device creation should be delayed."""
104
+
105
+ @property
106
+ @abstractmethod
107
+ def enable_device_firmware_check(self) -> bool:
108
+ """Return if device firmware check is enabled."""
109
+
110
+ @property
111
+ @abstractmethod
112
+ def enable_program_scan(self) -> bool:
113
+ """Return if program scanning is enabled."""
114
+
115
+ @property
116
+ @abstractmethod
117
+ def enable_sysvar_scan(self) -> bool:
118
+ """Return if system variable scanning is enabled."""
119
+
120
+ @property
121
+ @abstractmethod
122
+ def enable_xml_rpc_server(self) -> bool:
123
+ """Return if XML-RPC server should be enabled."""
124
+
125
+ @property
126
+ @abstractmethod
127
+ def enabled_interface_configs(self) -> frozenset[InterfaceConfig]:
128
+ """Return the enabled interface configurations."""
129
+
130
+ @property
131
+ @abstractmethod
132
+ def host(self) -> str:
133
+ """Return the host address."""
134
+
135
+ @property
136
+ @abstractmethod
137
+ def ignore_custom_device_definition_models(self) -> frozenset[str]:
138
+ """Return the set of device models to ignore for custom definitions."""
139
+
140
+ @property
141
+ @abstractmethod
142
+ def interfaces_requiring_periodic_refresh(self) -> frozenset[Interface]:
143
+ """Return the set of interfaces requiring periodic refresh."""
144
+
145
+ @property
146
+ @abstractmethod
147
+ def listen_ip_addr(self) -> str | None:
148
+ """Return the listen IP address."""
149
+
150
+ @property
151
+ @abstractmethod
152
+ def listen_port_xml_rpc(self) -> int | None:
153
+ """Return the listen port for XML-RPC."""
154
+
155
+ @property
156
+ @abstractmethod
157
+ def locale(self) -> str:
158
+ """Return the locale setting."""
159
+
160
+ @property
161
+ @abstractmethod
162
+ def max_read_workers(self) -> int:
163
+ """Return the maximum number of read workers."""
164
+
165
+ @property
166
+ @abstractmethod
167
+ def name(self) -> str:
168
+ """Return the central name."""
169
+
170
+ @property
171
+ @abstractmethod
172
+ def optional_settings(self) -> frozenset[OptionalSettings | str]:
173
+ """Return the optional settings."""
174
+
175
+ @property
176
+ @abstractmethod
177
+ def password(self) -> str:
178
+ """Return the password."""
179
+
180
+ @property
181
+ @abstractmethod
182
+ def program_markers(self) -> tuple[DescriptionMarker | str, ...]:
183
+ """Return the program markers for filtering."""
184
+
185
+ @property
186
+ @abstractmethod
187
+ def schedule_timer_config(self) -> ScheduleTimerConfig:
188
+ """Return the schedule timer configuration."""
189
+
190
+ @property
191
+ @abstractmethod
192
+ def session_recorder_randomize_output(self) -> bool:
193
+ """Return if session recorder should randomize output."""
194
+
195
+ @property
196
+ @abstractmethod
197
+ def session_recorder_start(self) -> bool:
198
+ """Return if session recorder should start."""
199
+
200
+ @property
201
+ @abstractmethod
202
+ def session_recorder_start_for_seconds(self) -> int:
203
+ """Return the session recorder start duration in seconds."""
204
+
205
+ @property
206
+ @abstractmethod
207
+ def start_direct(self) -> bool:
208
+ """Return if direct start mode is enabled."""
209
+
210
+ @property
211
+ @abstractmethod
212
+ def storage_directory(self) -> str:
213
+ """Return the storage directory path."""
214
+
215
+ @property
216
+ @abstractmethod
217
+ def storage_factory(self) -> StorageFactoryProtocol | None:
218
+ """Return the storage factory."""
219
+
220
+ @property
221
+ @abstractmethod
222
+ def sysvar_markers(self) -> tuple[DescriptionMarker | str, ...]:
223
+ """Return the system variable markers for filtering."""
224
+
225
+ @property
226
+ @abstractmethod
227
+ def timeout_config(self) -> TimeoutConfig:
228
+ """Return the timeout configuration."""
229
+
230
+ @property
231
+ @abstractmethod
232
+ def tls(self) -> bool:
233
+ """Return if TLS is enabled."""
234
+
235
+ @property
236
+ @abstractmethod
237
+ def un_ignore_list(self) -> frozenset[str]:
238
+ """Return the un-ignore list."""
239
+
240
+ @property
241
+ @abstractmethod
242
+ def use_caches(self) -> bool:
243
+ """Return if caches should be used."""
244
+
245
+ @property
246
+ @abstractmethod
247
+ def use_group_channel_for_cover_state(self) -> bool:
248
+ """Return if group channel should be used for cover state."""
249
+
250
+ @property
251
+ @abstractmethod
252
+ def username(self) -> str:
253
+ """Return the username."""
254
+
255
+ @property
256
+ @abstractmethod
257
+ def verify_tls(self) -> bool:
258
+ """Return if TLS verification is enabled."""
259
+
260
+ @abstractmethod
261
+ def create_central_url(self) -> str:
262
+ """Create and return the central URL."""
263
+
264
+
265
+ @runtime_checkable
266
+ class CentralInfoProtocol(Protocol):
267
+ """
268
+ Protocol for accessing central system information.
269
+
270
+ Implemented by CentralUnit.
271
+ """
272
+
273
+ @property
274
+ @abstractmethod
275
+ def available(self) -> bool:
276
+ """Check if central is available."""
277
+
278
+ @property
279
+ @abstractmethod
280
+ def info_payload(self) -> Mapping[str, Any]:
281
+ """Return the info payload."""
282
+
283
+ @property
284
+ @abstractmethod
285
+ def model(self) -> str | None:
286
+ """Get backend model."""
287
+
288
+ @property
289
+ @abstractmethod
290
+ def name(self) -> str:
291
+ """Get central name."""
292
+
293
+ @property
294
+ @abstractmethod
295
+ def state(self) -> CentralState:
296
+ """Return the current central state from the state machine."""
297
+
298
+
299
+ @runtime_checkable
300
+ class CentralUnitStateProviderProtocol(Protocol):
301
+ """
302
+ Protocol for accessing central unit state.
303
+
304
+ Implemented by CentralUnit.
305
+ """
306
+
307
+ @property
308
+ @abstractmethod
309
+ def state(self) -> CentralState:
310
+ """Get current central state."""
311
+
312
+
313
+ @runtime_checkable
314
+ class ConfigProviderProtocol(Protocol):
315
+ """
316
+ Protocol for accessing configuration.
317
+
318
+ Implemented by CentralUnit.
319
+ """
320
+
321
+ @property
322
+ @abstractmethod
323
+ def config(self) -> CentralConfigProtocol:
324
+ """Get central configuration."""
325
+
326
+
327
+ @runtime_checkable
328
+ class SystemInfoProviderProtocol(Protocol):
329
+ """
330
+ Protocol for accessing system information.
331
+
332
+ Implemented by CentralUnit.
333
+ """
334
+
335
+ @property
336
+ @abstractmethod
337
+ def system_information(self) -> SystemInformation:
338
+ """Get system information."""
339
+
340
+
341
+ @runtime_checkable
342
+ class BackupProviderProtocol(Protocol):
343
+ """
344
+ Protocol for backup operations.
345
+
346
+ Implemented by CentralUnit.
347
+ """
348
+
349
+ @abstractmethod
350
+ async def create_backup_and_download(self) -> BackupData | None:
351
+ """Create a backup on the CCU and download it."""
352
+
353
+
354
+ @runtime_checkable
355
+ class DeviceManagementProtocol(Protocol):
356
+ """
357
+ Protocol for device management operations.
358
+
359
+ Provides methods for managing devices on the CCU including
360
+ accepting inbox devices, renaming devices/channels, and install mode.
361
+ Implemented by CentralUnit.
362
+ """
363
+
364
+ @abstractmethod
365
+ async def accept_device_in_inbox(self, *, device_address: str) -> bool:
366
+ """Accept a device from the CCU inbox."""
367
+
368
+ @abstractmethod
369
+ async def get_install_mode(self) -> int:
370
+ """Return the remaining time in install mode."""
371
+
372
+ @abstractmethod
373
+ async def rename_device(self, *, device_address: str, name: str, include_channels: bool = False) -> bool:
374
+ """Rename a device on the CCU."""
375
+
376
+ @abstractmethod
377
+ async def set_install_mode(
378
+ self,
379
+ *,
380
+ on: bool = True,
381
+ time: int = 60,
382
+ mode: int = 1,
383
+ device_address: str | None = None,
384
+ ) -> bool:
385
+ """
386
+ Set the install mode on the backend.
387
+
388
+ Args:
389
+ on: Enable or disable install mode.
390
+ time: Duration in seconds (default 60).
391
+ mode: Mode 1=normal, 2=set all ROAMING devices into install mode.
392
+ device_address: Optional device address to limit pairing.
393
+
394
+ Returns:
395
+ True if successful.
396
+
397
+ """
398
+
399
+
400
+ @runtime_checkable
401
+ class EventBusProviderProtocol(Protocol):
402
+ """
403
+ Protocol for accessing event bus.
404
+
405
+ Implemented by CentralUnit.
406
+ """
407
+
408
+ @property
409
+ @abstractmethod
410
+ def event_bus(self) -> EventBus:
411
+ """Get event bus instance."""
412
+
413
+
414
+ @runtime_checkable
415
+ class EventPublisherProtocol(Protocol):
416
+ """
417
+ Protocol for publishing events to the system.
418
+
419
+ Implemented by EventCoordinator.
420
+ """
421
+
422
+ @abstractmethod
423
+ def publish_device_trigger_event(self, *, trigger_type: DeviceTriggerEventType, event_data: EventData) -> None:
424
+ """Publish a Homematic event."""
425
+
426
+ @abstractmethod
427
+ def publish_system_event(self, *, system_event: SystemEventType, **kwargs: Unpack[SystemEventArgs]) -> None:
428
+ """Publish a backend system event."""
429
+
430
+
431
+ @runtime_checkable
432
+ class DataPointProviderProtocol(Protocol):
433
+ """
434
+ Protocol for accessing data points.
435
+
436
+ Implemented by CentralUnit.
437
+ """
438
+
439
+ @abstractmethod
440
+ def get_data_point_by_custom_id(self, *, custom_id: str) -> CallbackDataPointProtocol | None:
441
+ """Return Homematic data_point by custom_id."""
442
+
443
+ @abstractmethod
444
+ def get_readable_generic_data_points(
445
+ self,
446
+ *,
447
+ paramset_key: ParamsetKey | None = None,
448
+ interface: Interface | None = None,
449
+ ) -> tuple[GenericDataPointProtocolAny, ...]:
450
+ """Get readable generic data points."""
451
+
452
+
453
+ @runtime_checkable
454
+ class DeviceProviderProtocol(DeviceProviderForMetricsProtocol, Protocol):
455
+ """
456
+ Protocol for accessing devices.
457
+
458
+ Extends DeviceProviderForMetricsProtocol with additional properties.
459
+ Implemented by CentralUnit.
460
+ """
461
+
462
+ @property
463
+ @abstractmethod
464
+ def interfaces(self) -> frozenset[Interface]:
465
+ """Get all interfaces."""
466
+
467
+
468
+ @runtime_checkable
469
+ class ChannelLookupProtocol(Protocol):
470
+ """
471
+ Protocol for looking up channels.
472
+
473
+ Implemented by CentralUnit.
474
+ """
475
+
476
+ @abstractmethod
477
+ def get_channel(self, *, channel_address: str) -> ChannelProtocol | None:
478
+ """Get channel by address."""
479
+
480
+ @abstractmethod
481
+ def identify_channel(self, *, text: str) -> ChannelProtocol | None:
482
+ """Identify a channel within a text string."""
483
+
484
+
485
+ @runtime_checkable
486
+ class FileOperationsProtocol(Protocol):
487
+ """
488
+ Protocol for file save operations.
489
+
490
+ Implemented by CentralUnit.
491
+ """
492
+
493
+ @abstractmethod
494
+ async def save_files(
495
+ self, *, save_device_descriptions: bool = False, save_paramset_descriptions: bool = False
496
+ ) -> None:
497
+ """Save persistent files to disk."""
498
+
499
+
500
+ @runtime_checkable
501
+ class FirmwareDataRefresherProtocol(Protocol):
502
+ """
503
+ Protocol for refreshing firmware data.
504
+
505
+ Implemented by DeviceCoordinator.
506
+ """
507
+
508
+ @abstractmethod
509
+ async def refresh_firmware_data(self, *, device_address: str | None = None) -> None:
510
+ """Refresh device firmware data."""
511
+
512
+ @abstractmethod
513
+ async def refresh_firmware_data_by_state(
514
+ self,
515
+ *,
516
+ device_firmware_states: tuple[DeviceFirmwareState, ...],
517
+ ) -> None:
518
+ """Refresh device firmware data for devices in specific states."""
519
+
520
+
521
+ class DeviceDataRefresherProtocol(Protocol):
522
+ """
523
+ Protocol for refreshing device data.
524
+
525
+ Implemented by CentralUnit.
526
+ """
527
+
528
+ @abstractmethod
529
+ async def load_and_refresh_data_point_data(self, *, interface: Interface) -> None:
530
+ """Load and refresh data point data for an interface."""
531
+
532
+
533
+ @runtime_checkable
534
+ class DataCacheProviderProtocol(Protocol):
535
+ """
536
+ Protocol for accessing data cache.
537
+
538
+ Implemented by CentralDataCache.
539
+ """
540
+
541
+ @abstractmethod
542
+ def get_data(self, *, interface: Interface, channel_address: str, parameter: str) -> Any:
543
+ """Get cached data for a parameter."""
544
+
545
+
546
+ @runtime_checkable
547
+ class HubFetchOperationsProtocol(Protocol):
548
+ """
549
+ Base protocol for hub fetch operations.
550
+
551
+ Defines the common fetch methods shared between HubDataFetcherProtocol and HubProtocol.
552
+ This eliminates duplication of fetch method signatures.
553
+ """
554
+
555
+ @abstractmethod
556
+ def fetch_connectivity_data(self, *, scheduled: bool) -> None:
557
+ """Refresh connectivity binary sensors with current values."""
558
+
559
+ @abstractmethod
560
+ async def fetch_inbox_data(self, *, scheduled: bool) -> None:
561
+ """Fetch inbox data from the backend."""
562
+
563
+ @abstractmethod
564
+ def fetch_metrics_data(self, *, scheduled: bool) -> None:
565
+ """Refresh metrics hub sensors with current values."""
566
+
567
+ @abstractmethod
568
+ async def fetch_program_data(self, *, scheduled: bool) -> None:
569
+ """Fetch program data from the backend."""
570
+
571
+ @abstractmethod
572
+ async def fetch_system_update_data(self, *, scheduled: bool) -> None:
573
+ """Fetch system update data from the backend."""
574
+
575
+ @abstractmethod
576
+ async def fetch_sysvar_data(self, *, scheduled: bool) -> None:
577
+ """Fetch system variable data from the backend."""
578
+
579
+
580
+ @runtime_checkable
581
+ class HubDataFetcherProtocol(HubFetchOperationsProtocol, Protocol):
582
+ """
583
+ Protocol for fetching hub data.
584
+
585
+ Extends HubFetchOperationsProtocol with program execution and state management.
586
+ Implemented by HubCoordinator.
587
+ """
588
+
589
+ @abstractmethod
590
+ async def execute_program(self, *, pid: str) -> bool:
591
+ """Execute a program on the backend."""
592
+
593
+ @abstractmethod
594
+ async def set_program_state(self, *, pid: str, state: bool) -> bool:
595
+ """Set program state on the backend."""
596
+
597
+
598
+ @runtime_checkable
599
+ class HubDataPointManagerProtocol(HubDataPointManagerForMetricsProtocol, Protocol):
600
+ """
601
+ Protocol for managing hub-level data points (programs/sysvars).
602
+
603
+ Extends HubDataPointManagerForMetricsProtocol with management methods.
604
+ Implemented by CentralUnit.
605
+ """
606
+
607
+ @abstractmethod
608
+ def add_program_data_point(self, *, program_dp: ProgramDpType) -> None:
609
+ """Add a program data point."""
610
+
611
+ @abstractmethod
612
+ def add_sysvar_data_point(self, *, sysvar_data_point: GenericSysvarDataPointProtocol) -> None:
613
+ """Add a system variable data point."""
614
+
615
+ @abstractmethod
616
+ def get_program_data_point(self, *, pid: str) -> ProgramDpType | None:
617
+ """Get a program data point by ID."""
618
+
619
+ @abstractmethod
620
+ def get_sysvar_data_point(self, *, vid: str) -> GenericSysvarDataPointProtocol | None:
621
+ """Get a system variable data point by ID."""
622
+
623
+ @abstractmethod
624
+ def remove_program_button(self, *, pid: str) -> None:
625
+ """Remove a program button."""
626
+
627
+ @abstractmethod
628
+ def remove_sysvar_data_point(self, *, vid: str) -> None:
629
+ """Remove a system variable data point."""
630
+
631
+
632
+ @runtime_checkable
633
+ class EventSubscriptionManagerProtocol(Protocol):
634
+ """
635
+ Protocol for managing event subscriptions.
636
+
637
+ Implemented by EventCoordinator.
638
+ """
639
+
640
+ @abstractmethod
641
+ def add_data_point_subscription(self, *, data_point: Any) -> None:
642
+ """Add an event subscription for a data point."""
643
+
644
+
645
+ @runtime_checkable
646
+ class RpcServerCentralProtocol(Protocol):
647
+ """
648
+ Protocol for CentralUnit operations required by RpcServer.
649
+
650
+ This protocol defines the minimal interface needed by the XML-RPC server
651
+ to interact with a central unit, avoiding direct coupling to CentralUnit.
652
+
653
+ Implemented by CentralUnit.
654
+ """
655
+
656
+ @property
657
+ @abstractmethod
658
+ def client_coordinator(self) -> ClientCoordinator:
659
+ """Return the client coordinator."""
660
+
661
+ @property
662
+ @abstractmethod
663
+ def device_coordinator(self) -> DeviceCoordinator:
664
+ """Return the device coordinator."""
665
+
666
+ @property
667
+ @abstractmethod
668
+ def event_coordinator(self) -> EventCoordinator:
669
+ """Return the event coordinator."""
670
+
671
+ @property
672
+ @abstractmethod
673
+ def name(self) -> str:
674
+ """Return the central name."""
675
+
676
+
677
+ @runtime_checkable
678
+ class RpcServerTaskSchedulerProtocol(Protocol):
679
+ """
680
+ Protocol for task scheduling in RpcServer context.
681
+
682
+ This protocol provides a way to schedule async tasks from the synchronous
683
+ XML-RPC callbacks without coupling to the full CentralUnit.
684
+
685
+ Implemented by CentralUnit.looper or a dedicated task scheduler.
686
+ """
687
+
688
+ @abstractmethod
689
+ def create_task(
690
+ self,
691
+ *,
692
+ target: Any,
693
+ name: str,
694
+ ) -> None:
695
+ """Create and schedule an async task."""
696
+
697
+
698
+ # =============================================================================
699
+ # Central State Machine Protocol
700
+ # =============================================================================
701
+
702
+
703
+ @runtime_checkable
704
+ class CentralStateMachineProtocol(Protocol):
705
+ """
706
+ Protocol for the central state machine.
707
+
708
+ Provides access to the overall system state and state transitions.
709
+ Implemented by CentralStateMachine.
710
+ """
711
+
712
+ @property
713
+ @abstractmethod
714
+ def degraded_interfaces(self) -> Mapping[str, FailureReason]:
715
+ """Return the interfaces that are degraded with their failure reasons."""
716
+
717
+ @property
718
+ @abstractmethod
719
+ def failure_interface_id(self) -> str | None:
720
+ """Return the interface ID that caused the failure, if applicable."""
721
+
722
+ @property
723
+ @abstractmethod
724
+ def failure_message(self) -> str:
725
+ """Return human-readable failure message."""
726
+
727
+ @property
728
+ @abstractmethod
729
+ def failure_reason(self) -> FailureReason:
730
+ """Return the reason for the failed state."""
731
+
732
+ @property
733
+ @abstractmethod
734
+ def is_degraded(self) -> bool:
735
+ """Return True if system is in degraded state."""
736
+
737
+ @property
738
+ @abstractmethod
739
+ def is_failed(self) -> bool:
740
+ """Return True if system is in failed state."""
741
+
742
+ @property
743
+ @abstractmethod
744
+ def is_operational(self) -> bool:
745
+ """Return True if system is operational (RUNNING or DEGRADED)."""
746
+
747
+ @property
748
+ @abstractmethod
749
+ def is_recovering(self) -> bool:
750
+ """Return True if recovery is in progress."""
751
+
752
+ @property
753
+ @abstractmethod
754
+ def is_running(self) -> bool:
755
+ """Return True if system is fully running."""
756
+
757
+ @property
758
+ @abstractmethod
759
+ def is_stopped(self) -> bool:
760
+ """Return True if system is stopped."""
761
+
762
+ @property
763
+ @abstractmethod
764
+ def state(self) -> CentralState:
765
+ """Return the current state."""
766
+
767
+ @abstractmethod
768
+ def can_transition_to(self, *, target: CentralState) -> bool:
769
+ """Check if transition to target state is valid."""
770
+
771
+ @abstractmethod
772
+ def transition_to(
773
+ self,
774
+ *,
775
+ target: CentralState,
776
+ reason: str = "",
777
+ force: bool = False,
778
+ failure_reason: FailureReason = FailureReason.NONE,
779
+ failure_interface_id: str | None = None,
780
+ degraded_interfaces: Mapping[str, FailureReason] | None = None,
781
+ ) -> None:
782
+ """Transition to a new state."""
783
+
784
+
785
+ @runtime_checkable
786
+ class CentralStateMachineProviderProtocol(Protocol):
787
+ """
788
+ Protocol for accessing the central state machine.
789
+
790
+ Implemented by CentralUnit.
791
+ """
792
+
793
+ @property
794
+ @abstractmethod
795
+ def central_state_machine(self) -> CentralStateMachineProtocol:
796
+ """Return the central state machine."""
797
+
798
+
799
+ # =============================================================================
800
+ # Health Tracking Protocols
801
+ # =============================================================================
802
+
803
+
804
+ @runtime_checkable
805
+ class ConnectionHealthProtocol(Protocol):
806
+ """
807
+ Protocol for per-client connection health.
808
+
809
+ Implemented by ConnectionHealth.
810
+ """
811
+
812
+ @property
813
+ @abstractmethod
814
+ def client_state(self) -> ClientState:
815
+ """Return the client state."""
816
+
817
+ @property
818
+ @abstractmethod
819
+ def health_score(self) -> float:
820
+ """Calculate a numeric health score (0.0 - 1.0)."""
821
+
822
+ @property
823
+ @abstractmethod
824
+ def interface(self) -> Interface:
825
+ """Return the interface type."""
826
+
827
+ @property
828
+ @abstractmethod
829
+ def interface_id(self) -> str:
830
+ """Return the interface ID."""
831
+
832
+ @property
833
+ @abstractmethod
834
+ def is_available(self) -> bool:
835
+ """Check if client is available for operations."""
836
+
837
+ @property
838
+ @abstractmethod
839
+ def is_connected(self) -> bool:
840
+ """Check if client is in connected state."""
841
+
842
+ @property
843
+ @abstractmethod
844
+ def is_degraded(self) -> bool:
845
+ """Check if client is in degraded state."""
846
+
847
+ @property
848
+ @abstractmethod
849
+ def is_failed(self) -> bool:
850
+ """Check if client is in failed state."""
851
+
852
+
853
+ @runtime_checkable
854
+ class CentralHealthProtocol(Protocol):
855
+ """
856
+ Protocol for aggregated central health.
857
+
858
+ Implemented by CentralHealth.
859
+ """
860
+
861
+ @property
862
+ @abstractmethod
863
+ def all_clients_healthy(self) -> bool:
864
+ """Check if all clients are fully healthy."""
865
+
866
+ @property
867
+ @abstractmethod
868
+ def any_client_healthy(self) -> bool:
869
+ """Check if at least one client is healthy."""
870
+
871
+ @property
872
+ @abstractmethod
873
+ def degraded_clients(self) -> list[str]:
874
+ """Return list of interface IDs with degraded health."""
875
+
876
+ @property
877
+ @abstractmethod
878
+ def failed_clients(self) -> list[str]:
879
+ """Return list of interface IDs that have failed."""
880
+
881
+ @property
882
+ @abstractmethod
883
+ def healthy_clients(self) -> list[str]:
884
+ """Return list of healthy interface IDs."""
885
+
886
+ @property
887
+ @abstractmethod
888
+ def overall_health_score(self) -> float:
889
+ """Calculate weighted average health score across all clients."""
890
+
891
+ @property
892
+ @abstractmethod
893
+ def primary_client_healthy(self) -> bool:
894
+ """Check if the primary client is healthy."""
895
+
896
+ @property
897
+ @abstractmethod
898
+ def state(self) -> CentralState:
899
+ """Return current central state."""
900
+
901
+ @abstractmethod
902
+ def get_client_health(self, *, interface_id: str) -> ConnectionHealthProtocol | None:
903
+ """Get health for a specific client."""
904
+
905
+ @abstractmethod
906
+ def should_be_degraded(self) -> bool:
907
+ """Determine if central should be in DEGRADED state."""
908
+
909
+ @abstractmethod
910
+ def should_be_running(self) -> bool:
911
+ """Determine if central should be in RUNNING state."""
912
+
913
+
914
+ @runtime_checkable
915
+ class HealthTrackerProtocol(Protocol):
916
+ """
917
+ Protocol for the health tracker.
918
+
919
+ Implemented by HealthTracker.
920
+ """
921
+
922
+ @property
923
+ @abstractmethod
924
+ def health(self) -> CentralHealthProtocol:
925
+ """Return the aggregated central health."""
926
+
927
+ @abstractmethod
928
+ def get_client_health(self, *, interface_id: str) -> ConnectionHealthProtocol | None:
929
+ """Get health for a specific client."""
930
+
931
+ @abstractmethod
932
+ def record_event_received(self, *, interface_id: str) -> None:
933
+ """Record that an event was received for an interface."""
934
+
935
+ @abstractmethod
936
+ def record_failed_request(self, *, interface_id: str) -> None:
937
+ """Record a failed RPC request for an interface."""
938
+
939
+ @abstractmethod
940
+ def record_successful_request(self, *, interface_id: str) -> None:
941
+ """Record a successful RPC request for an interface."""
942
+
943
+ @abstractmethod
944
+ def register_client(self, *, interface_id: str, interface: Interface) -> ConnectionHealthProtocol:
945
+ """Register a client for health tracking."""
946
+
947
+ @abstractmethod
948
+ def set_primary_interface(self, *, interface: Interface) -> None:
949
+ """Set the primary interface for health tracking."""
950
+
951
+ @abstractmethod
952
+ def unregister_client(self, *, interface_id: str) -> None:
953
+ """Unregister a client from health tracking."""
954
+
955
+
956
+ @runtime_checkable
957
+ class HealthProviderProtocol(Protocol):
958
+ """
959
+ Protocol for accessing the health tracker.
960
+
961
+ Implemented by CentralUnit.
962
+ """
963
+
964
+ @property
965
+ @abstractmethod
966
+ def health_tracker(self) -> HealthTrackerProtocol:
967
+ """Return the health tracker."""
968
+
969
+
970
+ @runtime_checkable
971
+ class MetricsProviderProtocol(Protocol):
972
+ """
973
+ Protocol for accessing the metrics observer.
974
+
975
+ Implemented by CentralUnit.
976
+ """
977
+
978
+ @property
979
+ @abstractmethod
980
+ def metrics(self) -> MetricsObserver:
981
+ """Return the metrics observer."""
982
+
983
+
984
+ # =============================================================================
985
+ # CentralProtocol Composite
986
+ # =============================================================================
987
+
988
+ # Import protocols from other interface modules for CentralProtocol composition.
989
+ # These imports are placed here (after all local protocols are defined) to avoid
990
+ # circular import issues while allowing proper inheritance.
991
+ from aiohomematic.interfaces.client import ( # noqa: E402
992
+ CallbackAddressProviderProtocol,
993
+ ClientDependenciesProtocol,
994
+ ClientFactoryProtocol,
995
+ ConnectionStateProviderProtocol,
996
+ JsonRpcClientProviderProtocol,
997
+ )
998
+ from aiohomematic.interfaces.coordinators import CoordinatorProviderProtocol # noqa: E402
999
+
1000
+
1001
+ @runtime_checkable
1002
+ class CentralProtocol(
1003
+ # From interfaces/central.py (this module)
1004
+ BackupProviderProtocol,
1005
+ CentralInfoProtocol,
1006
+ CentralUnitStateProviderProtocol,
1007
+ ConfigProviderProtocol,
1008
+ DataPointProviderProtocol,
1009
+ DeviceDataRefresherProtocol,
1010
+ DeviceProviderProtocol,
1011
+ EventBusProviderProtocol,
1012
+ FileOperationsProtocol,
1013
+ SystemInfoProviderProtocol,
1014
+ # From interfaces/client.py
1015
+ CallbackAddressProviderProtocol,
1016
+ ClientDependenciesProtocol,
1017
+ ClientFactoryProtocol,
1018
+ ConnectionStateProviderProtocol,
1019
+ JsonRpcClientProviderProtocol,
1020
+ # From interfaces/coordinators.py
1021
+ CoordinatorProviderProtocol,
1022
+ Protocol,
1023
+ ):
1024
+ """
1025
+ Composite protocol for CentralUnit.
1026
+
1027
+ Combines all sub-protocols that CentralUnit implements, providing a single
1028
+ protocol for complete central unit access while maintaining the ability to
1029
+ depend on specific sub-protocols when only partial functionality is needed.
1030
+
1031
+ Sub-protocols are organized into categories:
1032
+
1033
+ **Identity & Configuration:**
1034
+ - CentralInfoProtocol: Central system identification
1035
+ - CentralUnitStateProviderProtocol: Central unit lifecycle state
1036
+ - ConfigProviderProtocol: Configuration access
1037
+ - SystemInfoProviderProtocol: Backend system information
1038
+
1039
+ **Event System:**
1040
+ - EventBusProviderProtocol: Access to the central event bus
1041
+
1042
+ **Cache & Data Access:**
1043
+ - DataPointProviderProtocol: Find data points
1044
+ - DeviceProviderProtocol: Access device registry (internal use)
1045
+ - FileOperationsProtocol: File I/O operations
1046
+
1047
+ **Device Operations:**
1048
+ - DeviceDataRefresherProtocol: Refresh device data from backend
1049
+ - BackupProviderProtocol: Backup operations
1050
+
1051
+ **Hub Operations:**
1052
+ - HubDataFetcherProtocol: Fetch hub data
1053
+ - HubDataPointManagerProtocol: Manage hub data points
1054
+
1055
+ **Client Management (via CoordinatorProviderProtocol.client_coordinator):**
1056
+ - ClientFactoryProtocol: Create new client instances
1057
+ - ClientDependenciesProtocol: Dependencies for clients
1058
+ - JsonRpcClientProviderProtocol: JSON-RPC client access
1059
+ - ConnectionStateProviderProtocol: Connection state information
1060
+ - CallbackAddressProviderProtocol: Callback address management
1061
+ - SessionRecorderProviderProtocol: Session recording access
1062
+
1063
+ **Coordinators:**
1064
+ - CoordinatorProviderProtocol: Access to coordinators (client_coordinator, event_coordinator, etc.)
1065
+ """
1066
+
1067
+ __slots__ = ()