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.
- aiohomematic/__init__.py +110 -0
- aiohomematic/_log_context_protocol.py +29 -0
- aiohomematic/api.py +410 -0
- aiohomematic/async_support.py +250 -0
- aiohomematic/backend_detection.py +462 -0
- aiohomematic/central/__init__.py +103 -0
- aiohomematic/central/async_rpc_server.py +760 -0
- aiohomematic/central/central_unit.py +1152 -0
- aiohomematic/central/config.py +463 -0
- aiohomematic/central/config_builder.py +772 -0
- aiohomematic/central/connection_state.py +160 -0
- aiohomematic/central/coordinators/__init__.py +38 -0
- aiohomematic/central/coordinators/cache.py +414 -0
- aiohomematic/central/coordinators/client.py +480 -0
- aiohomematic/central/coordinators/connection_recovery.py +1141 -0
- aiohomematic/central/coordinators/device.py +1166 -0
- aiohomematic/central/coordinators/event.py +514 -0
- aiohomematic/central/coordinators/hub.py +532 -0
- aiohomematic/central/decorators.py +184 -0
- aiohomematic/central/device_registry.py +229 -0
- aiohomematic/central/events/__init__.py +104 -0
- aiohomematic/central/events/bus.py +1392 -0
- aiohomematic/central/events/integration.py +424 -0
- aiohomematic/central/events/types.py +194 -0
- aiohomematic/central/health.py +762 -0
- aiohomematic/central/rpc_server.py +353 -0
- aiohomematic/central/scheduler.py +794 -0
- aiohomematic/central/state_machine.py +391 -0
- aiohomematic/client/__init__.py +203 -0
- aiohomematic/client/_rpc_errors.py +187 -0
- aiohomematic/client/backends/__init__.py +48 -0
- aiohomematic/client/backends/base.py +335 -0
- aiohomematic/client/backends/capabilities.py +138 -0
- aiohomematic/client/backends/ccu.py +487 -0
- aiohomematic/client/backends/factory.py +116 -0
- aiohomematic/client/backends/homegear.py +294 -0
- aiohomematic/client/backends/json_ccu.py +252 -0
- aiohomematic/client/backends/protocol.py +316 -0
- aiohomematic/client/ccu.py +1857 -0
- aiohomematic/client/circuit_breaker.py +459 -0
- aiohomematic/client/config.py +64 -0
- aiohomematic/client/handlers/__init__.py +40 -0
- aiohomematic/client/handlers/backup.py +157 -0
- aiohomematic/client/handlers/base.py +79 -0
- aiohomematic/client/handlers/device_ops.py +1085 -0
- aiohomematic/client/handlers/firmware.py +144 -0
- aiohomematic/client/handlers/link_mgmt.py +199 -0
- aiohomematic/client/handlers/metadata.py +436 -0
- aiohomematic/client/handlers/programs.py +144 -0
- aiohomematic/client/handlers/sysvars.py +100 -0
- aiohomematic/client/interface_client.py +1304 -0
- aiohomematic/client/json_rpc.py +2068 -0
- aiohomematic/client/request_coalescer.py +282 -0
- aiohomematic/client/rpc_proxy.py +629 -0
- aiohomematic/client/state_machine.py +324 -0
- aiohomematic/const.py +2207 -0
- aiohomematic/context.py +275 -0
- aiohomematic/converter.py +270 -0
- aiohomematic/decorators.py +390 -0
- aiohomematic/exceptions.py +185 -0
- aiohomematic/hmcli.py +997 -0
- aiohomematic/i18n.py +193 -0
- aiohomematic/interfaces/__init__.py +407 -0
- aiohomematic/interfaces/central.py +1067 -0
- aiohomematic/interfaces/client.py +1096 -0
- aiohomematic/interfaces/coordinators.py +63 -0
- aiohomematic/interfaces/model.py +1921 -0
- aiohomematic/interfaces/operations.py +217 -0
- aiohomematic/logging_context.py +134 -0
- aiohomematic/metrics/__init__.py +125 -0
- aiohomematic/metrics/_protocols.py +140 -0
- aiohomematic/metrics/aggregator.py +534 -0
- aiohomematic/metrics/dataclasses.py +489 -0
- aiohomematic/metrics/emitter.py +292 -0
- aiohomematic/metrics/events.py +183 -0
- aiohomematic/metrics/keys.py +300 -0
- aiohomematic/metrics/observer.py +563 -0
- aiohomematic/metrics/stats.py +172 -0
- aiohomematic/model/__init__.py +189 -0
- aiohomematic/model/availability.py +65 -0
- aiohomematic/model/calculated/__init__.py +89 -0
- aiohomematic/model/calculated/climate.py +276 -0
- aiohomematic/model/calculated/data_point.py +315 -0
- aiohomematic/model/calculated/field.py +147 -0
- aiohomematic/model/calculated/operating_voltage_level.py +286 -0
- aiohomematic/model/calculated/support.py +232 -0
- aiohomematic/model/custom/__init__.py +214 -0
- aiohomematic/model/custom/capabilities/__init__.py +67 -0
- aiohomematic/model/custom/capabilities/climate.py +41 -0
- aiohomematic/model/custom/capabilities/light.py +87 -0
- aiohomematic/model/custom/capabilities/lock.py +44 -0
- aiohomematic/model/custom/capabilities/siren.py +63 -0
- aiohomematic/model/custom/climate.py +1130 -0
- aiohomematic/model/custom/cover.py +722 -0
- aiohomematic/model/custom/data_point.py +360 -0
- aiohomematic/model/custom/definition.py +300 -0
- aiohomematic/model/custom/field.py +89 -0
- aiohomematic/model/custom/light.py +1174 -0
- aiohomematic/model/custom/lock.py +322 -0
- aiohomematic/model/custom/mixins.py +445 -0
- aiohomematic/model/custom/profile.py +945 -0
- aiohomematic/model/custom/registry.py +251 -0
- aiohomematic/model/custom/siren.py +462 -0
- aiohomematic/model/custom/switch.py +195 -0
- aiohomematic/model/custom/text_display.py +289 -0
- aiohomematic/model/custom/valve.py +78 -0
- aiohomematic/model/data_point.py +1416 -0
- aiohomematic/model/device.py +1840 -0
- aiohomematic/model/event.py +216 -0
- aiohomematic/model/generic/__init__.py +327 -0
- aiohomematic/model/generic/action.py +40 -0
- aiohomematic/model/generic/action_select.py +62 -0
- aiohomematic/model/generic/binary_sensor.py +30 -0
- aiohomematic/model/generic/button.py +31 -0
- aiohomematic/model/generic/data_point.py +177 -0
- aiohomematic/model/generic/dummy.py +150 -0
- aiohomematic/model/generic/number.py +76 -0
- aiohomematic/model/generic/select.py +56 -0
- aiohomematic/model/generic/sensor.py +76 -0
- aiohomematic/model/generic/switch.py +54 -0
- aiohomematic/model/generic/text.py +33 -0
- aiohomematic/model/hub/__init__.py +100 -0
- aiohomematic/model/hub/binary_sensor.py +24 -0
- aiohomematic/model/hub/button.py +28 -0
- aiohomematic/model/hub/connectivity.py +190 -0
- aiohomematic/model/hub/data_point.py +342 -0
- aiohomematic/model/hub/hub.py +864 -0
- aiohomematic/model/hub/inbox.py +135 -0
- aiohomematic/model/hub/install_mode.py +393 -0
- aiohomematic/model/hub/metrics.py +208 -0
- aiohomematic/model/hub/number.py +42 -0
- aiohomematic/model/hub/select.py +52 -0
- aiohomematic/model/hub/sensor.py +37 -0
- aiohomematic/model/hub/switch.py +43 -0
- aiohomematic/model/hub/text.py +30 -0
- aiohomematic/model/hub/update.py +221 -0
- aiohomematic/model/support.py +592 -0
- aiohomematic/model/update.py +140 -0
- aiohomematic/model/week_profile.py +1827 -0
- aiohomematic/property_decorators.py +719 -0
- aiohomematic/py.typed +0 -0
- aiohomematic/rega_scripts/accept_device_in_inbox.fn +51 -0
- aiohomematic/rega_scripts/create_backup_start.fn +28 -0
- aiohomematic/rega_scripts/create_backup_status.fn +89 -0
- aiohomematic/rega_scripts/fetch_all_device_data.fn +97 -0
- aiohomematic/rega_scripts/get_backend_info.fn +25 -0
- aiohomematic/rega_scripts/get_inbox_devices.fn +61 -0
- aiohomematic/rega_scripts/get_program_descriptions.fn +31 -0
- aiohomematic/rega_scripts/get_serial.fn +44 -0
- aiohomematic/rega_scripts/get_service_messages.fn +83 -0
- aiohomematic/rega_scripts/get_system_update_info.fn +39 -0
- aiohomematic/rega_scripts/get_system_variable_descriptions.fn +31 -0
- aiohomematic/rega_scripts/set_program_state.fn +17 -0
- aiohomematic/rega_scripts/set_system_variable.fn +19 -0
- aiohomematic/rega_scripts/trigger_firmware_update.fn +67 -0
- aiohomematic/schemas.py +256 -0
- aiohomematic/store/__init__.py +55 -0
- aiohomematic/store/dynamic/__init__.py +43 -0
- aiohomematic/store/dynamic/command.py +250 -0
- aiohomematic/store/dynamic/data.py +175 -0
- aiohomematic/store/dynamic/details.py +187 -0
- aiohomematic/store/dynamic/ping_pong.py +416 -0
- aiohomematic/store/persistent/__init__.py +71 -0
- aiohomematic/store/persistent/base.py +285 -0
- aiohomematic/store/persistent/device.py +233 -0
- aiohomematic/store/persistent/incident.py +380 -0
- aiohomematic/store/persistent/paramset.py +241 -0
- aiohomematic/store/persistent/session.py +556 -0
- aiohomematic/store/serialization.py +150 -0
- aiohomematic/store/storage.py +689 -0
- aiohomematic/store/types.py +526 -0
- aiohomematic/store/visibility/__init__.py +40 -0
- aiohomematic/store/visibility/parser.py +141 -0
- aiohomematic/store/visibility/registry.py +722 -0
- aiohomematic/store/visibility/rules.py +307 -0
- aiohomematic/strings.json +237 -0
- aiohomematic/support.py +706 -0
- aiohomematic/tracing.py +236 -0
- aiohomematic/translations/de.json +237 -0
- aiohomematic/translations/en.json +237 -0
- aiohomematic/type_aliases.py +51 -0
- aiohomematic/validator.py +128 -0
- aiohomematic-2026.1.29.dist-info/METADATA +296 -0
- aiohomematic-2026.1.29.dist-info/RECORD +188 -0
- aiohomematic-2026.1.29.dist-info/WHEEL +5 -0
- aiohomematic-2026.1.29.dist-info/entry_points.txt +2 -0
- aiohomematic-2026.1.29.dist-info/licenses/LICENSE +21 -0
- 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__ = ()
|