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,144 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2021-2026
|
|
3
|
+
"""
|
|
4
|
+
Firmware handler.
|
|
5
|
+
|
|
6
|
+
Handles device and system firmware update operations.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import logging
|
|
12
|
+
from typing import TYPE_CHECKING, Final
|
|
13
|
+
|
|
14
|
+
from aiohomematic import i18n
|
|
15
|
+
from aiohomematic.client.handlers.base import BaseHandler
|
|
16
|
+
from aiohomematic.const import ProductGroup
|
|
17
|
+
from aiohomematic.decorators import inspector
|
|
18
|
+
from aiohomematic.exceptions import BaseHomematicException, ClientException
|
|
19
|
+
from aiohomematic.interfaces import FirmwareOperationsProtocol
|
|
20
|
+
from aiohomematic.property_decorators import DelegatedProperty
|
|
21
|
+
from aiohomematic.support import extract_exc_args
|
|
22
|
+
|
|
23
|
+
if TYPE_CHECKING:
|
|
24
|
+
from aiohomematic.client import AioJsonRpcAioHttpClient, BaseRpcProxy
|
|
25
|
+
from aiohomematic.const import Interface
|
|
26
|
+
from aiohomematic.interfaces import ClientDependenciesProtocol
|
|
27
|
+
|
|
28
|
+
_LOGGER: Final = logging.getLogger(__name__)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class FirmwareHandler(BaseHandler, FirmwareOperationsProtocol):
|
|
32
|
+
"""
|
|
33
|
+
Handler for firmware update operations.
|
|
34
|
+
|
|
35
|
+
Implements FirmwareOperationsProtocol protocol for ISP-compliant client operations.
|
|
36
|
+
|
|
37
|
+
Handles:
|
|
38
|
+
- Updating device firmware
|
|
39
|
+
- Triggering system firmware updates
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
__slots__ = (
|
|
43
|
+
"_has_device_firmware_update",
|
|
44
|
+
"_has_firmware_update_trigger",
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
def __init__(
|
|
48
|
+
self,
|
|
49
|
+
*,
|
|
50
|
+
client_deps: ClientDependenciesProtocol,
|
|
51
|
+
interface: Interface,
|
|
52
|
+
interface_id: str,
|
|
53
|
+
json_rpc_client: AioJsonRpcAioHttpClient,
|
|
54
|
+
proxy: BaseRpcProxy,
|
|
55
|
+
proxy_read: BaseRpcProxy,
|
|
56
|
+
has_device_firmware_update: bool,
|
|
57
|
+
has_firmware_update_trigger: bool,
|
|
58
|
+
) -> None:
|
|
59
|
+
"""Initialize the firmware handler."""
|
|
60
|
+
super().__init__(
|
|
61
|
+
client_deps=client_deps,
|
|
62
|
+
interface=interface,
|
|
63
|
+
interface_id=interface_id,
|
|
64
|
+
json_rpc_client=json_rpc_client,
|
|
65
|
+
proxy=proxy,
|
|
66
|
+
proxy_read=proxy_read,
|
|
67
|
+
)
|
|
68
|
+
self._has_device_firmware_update: Final = has_device_firmware_update
|
|
69
|
+
self._has_firmware_update_trigger: Final = has_firmware_update_trigger
|
|
70
|
+
|
|
71
|
+
has_device_firmware_update: Final = DelegatedProperty[bool](path="_has_device_firmware_update")
|
|
72
|
+
has_firmware_update_trigger: Final = DelegatedProperty[bool](path="_has_firmware_update_trigger")
|
|
73
|
+
|
|
74
|
+
@inspector(re_raise=False)
|
|
75
|
+
async def trigger_firmware_update(self) -> bool:
|
|
76
|
+
"""
|
|
77
|
+
Trigger the CCU system firmware update process.
|
|
78
|
+
|
|
79
|
+
Initiates the CCU's own firmware update (not device firmware). The CCU
|
|
80
|
+
will download and install available system updates.
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
True if the update was triggered successfully, False if unsupported.
|
|
84
|
+
|
|
85
|
+
"""
|
|
86
|
+
if not self._has_firmware_update_trigger:
|
|
87
|
+
_LOGGER.debug("TRIGGER_FIRMWARE_UPDATE: Not supported by client for %s", self._interface_id)
|
|
88
|
+
return False
|
|
89
|
+
|
|
90
|
+
return await self._json_rpc_client.trigger_firmware_update()
|
|
91
|
+
|
|
92
|
+
@inspector
|
|
93
|
+
async def update_device_firmware(self, *, device_address: str) -> bool:
|
|
94
|
+
"""
|
|
95
|
+
Update firmware on a single Homematic device.
|
|
96
|
+
|
|
97
|
+
Uses installFirmware() for HmIP/HmIPW devices and updateFirmware() for
|
|
98
|
+
BidCos devices. The device must have a firmware update available.
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
device_address: Device address (e.g., "VCU0000001").
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
True if the update was initiated successfully, False if device not
|
|
105
|
+
found or update unsupported.
|
|
106
|
+
|
|
107
|
+
Raises:
|
|
108
|
+
ClientException: If the RPC call fails.
|
|
109
|
+
|
|
110
|
+
"""
|
|
111
|
+
if not self._has_device_firmware_update:
|
|
112
|
+
_LOGGER.debug("UPDATE_DEVICE_FIRMWARE: Not supported by client for %s", self._interface_id)
|
|
113
|
+
return False
|
|
114
|
+
|
|
115
|
+
if device := self._client_deps.device_coordinator.get_device(address=device_address):
|
|
116
|
+
_LOGGER.info(
|
|
117
|
+
i18n.tr(
|
|
118
|
+
key="log.client.update_device_firmware.try",
|
|
119
|
+
device_address=device_address,
|
|
120
|
+
)
|
|
121
|
+
)
|
|
122
|
+
try:
|
|
123
|
+
update_result = (
|
|
124
|
+
await self._proxy.installFirmware(device_address)
|
|
125
|
+
if device.product_group in (ProductGroup.HMIPW, ProductGroup.HMIP)
|
|
126
|
+
else await self._proxy.updateFirmware(device_address)
|
|
127
|
+
)
|
|
128
|
+
result = bool(update_result) if isinstance(update_result, bool) else bool(update_result[0])
|
|
129
|
+
_LOGGER.info(
|
|
130
|
+
i18n.tr(
|
|
131
|
+
key="log.client.update_device_firmware.result",
|
|
132
|
+
device_address=device_address,
|
|
133
|
+
result=("success" if result else "failed"),
|
|
134
|
+
)
|
|
135
|
+
)
|
|
136
|
+
except BaseHomematicException as bhexc:
|
|
137
|
+
raise ClientException(
|
|
138
|
+
i18n.tr(
|
|
139
|
+
key="exception.client.update_device_firmware.failed",
|
|
140
|
+
reason=extract_exc_args(exc=bhexc),
|
|
141
|
+
)
|
|
142
|
+
) from bhexc
|
|
143
|
+
return result
|
|
144
|
+
return False
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2021-2026
|
|
3
|
+
"""
|
|
4
|
+
Link management handler.
|
|
5
|
+
|
|
6
|
+
Handles device linking operations.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import logging
|
|
12
|
+
from typing import TYPE_CHECKING, Any, Final, cast
|
|
13
|
+
|
|
14
|
+
from aiohomematic import i18n
|
|
15
|
+
from aiohomematic.client.handlers.base import BaseHandler
|
|
16
|
+
from aiohomematic.decorators import inspector
|
|
17
|
+
from aiohomematic.exceptions import BaseHomematicException, ClientException
|
|
18
|
+
from aiohomematic.interfaces import LinkOperationsProtocol
|
|
19
|
+
from aiohomematic.property_decorators import DelegatedProperty
|
|
20
|
+
from aiohomematic.support import extract_exc_args
|
|
21
|
+
|
|
22
|
+
if TYPE_CHECKING:
|
|
23
|
+
from aiohomematic.client import AioJsonRpcAioHttpClient, BaseRpcProxy
|
|
24
|
+
from aiohomematic.const import Interface
|
|
25
|
+
from aiohomematic.interfaces import ClientDependenciesProtocol
|
|
26
|
+
|
|
27
|
+
_LOGGER: Final = logging.getLogger(__name__)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class LinkHandler(BaseHandler, LinkOperationsProtocol):
|
|
31
|
+
"""
|
|
32
|
+
Handler for device linking operations.
|
|
33
|
+
|
|
34
|
+
Implements LinkOperationsProtocol protocol for ISP-compliant client operations.
|
|
35
|
+
|
|
36
|
+
Handles:
|
|
37
|
+
- Adding links between devices
|
|
38
|
+
- Removing links between devices
|
|
39
|
+
- Querying link information and peers
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
__slots__ = ("_has_linking",)
|
|
43
|
+
|
|
44
|
+
def __init__(
|
|
45
|
+
self,
|
|
46
|
+
*,
|
|
47
|
+
client_deps: ClientDependenciesProtocol,
|
|
48
|
+
interface: Interface,
|
|
49
|
+
interface_id: str,
|
|
50
|
+
json_rpc_client: AioJsonRpcAioHttpClient,
|
|
51
|
+
proxy: BaseRpcProxy,
|
|
52
|
+
proxy_read: BaseRpcProxy,
|
|
53
|
+
has_linking: bool,
|
|
54
|
+
) -> None:
|
|
55
|
+
"""Initialize the link management handler."""
|
|
56
|
+
super().__init__(
|
|
57
|
+
client_deps=client_deps,
|
|
58
|
+
interface=interface,
|
|
59
|
+
interface_id=interface_id,
|
|
60
|
+
json_rpc_client=json_rpc_client,
|
|
61
|
+
proxy=proxy,
|
|
62
|
+
proxy_read=proxy_read,
|
|
63
|
+
)
|
|
64
|
+
self._has_linking: Final = has_linking
|
|
65
|
+
|
|
66
|
+
has_linking: Final = DelegatedProperty[bool](path="_has_linking")
|
|
67
|
+
|
|
68
|
+
@inspector
|
|
69
|
+
async def add_link(
|
|
70
|
+
self,
|
|
71
|
+
*,
|
|
72
|
+
sender_address: str,
|
|
73
|
+
receiver_address: str,
|
|
74
|
+
name: str,
|
|
75
|
+
description: str,
|
|
76
|
+
) -> None:
|
|
77
|
+
"""
|
|
78
|
+
Create a direct link between two device channels.
|
|
79
|
+
|
|
80
|
+
Direct links allow devices to communicate without the CCU. The sender
|
|
81
|
+
triggers actions on the receiver (e.g., a button press turning on a light).
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
sender_address: Source channel address (e.g., "VCU0000001:1").
|
|
85
|
+
receiver_address: Target channel address (e.g., "VCU0000002:1").
|
|
86
|
+
name: User-defined link name.
|
|
87
|
+
description: User-defined link description.
|
|
88
|
+
|
|
89
|
+
Raises:
|
|
90
|
+
ClientException: If the RPC call fails.
|
|
91
|
+
|
|
92
|
+
"""
|
|
93
|
+
if not self._has_linking:
|
|
94
|
+
_LOGGER.debug("ADD_LINK: Not supported by client for %s", self._interface_id)
|
|
95
|
+
return
|
|
96
|
+
|
|
97
|
+
try:
|
|
98
|
+
await self._proxy.addLink(sender_address, receiver_address, name, description)
|
|
99
|
+
except BaseHomematicException as bhexc:
|
|
100
|
+
raise ClientException(
|
|
101
|
+
i18n.tr(
|
|
102
|
+
key="exception.client.add_link.failed",
|
|
103
|
+
sender=sender_address,
|
|
104
|
+
receiver=receiver_address,
|
|
105
|
+
name=name,
|
|
106
|
+
description=description,
|
|
107
|
+
reason=extract_exc_args(exc=bhexc),
|
|
108
|
+
)
|
|
109
|
+
) from bhexc
|
|
110
|
+
|
|
111
|
+
@inspector
|
|
112
|
+
async def get_link_peers(self, *, address: str) -> tuple[str, ...]:
|
|
113
|
+
"""
|
|
114
|
+
Return addresses of all channels linked to the given address.
|
|
115
|
+
|
|
116
|
+
Args:
|
|
117
|
+
address: Channel address to query (e.g., "VCU0000001:1").
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
Tuple of peer channel addresses that are linked to this channel.
|
|
121
|
+
|
|
122
|
+
Raises:
|
|
123
|
+
ClientException: If the RPC call fails.
|
|
124
|
+
|
|
125
|
+
"""
|
|
126
|
+
if not self._has_linking:
|
|
127
|
+
_LOGGER.debug("GET_LINK_PEERS: Not supported by client for %s", self._interface_id)
|
|
128
|
+
return ()
|
|
129
|
+
|
|
130
|
+
try:
|
|
131
|
+
return tuple(links) if (links := await self._proxy.getLinkPeers(address)) else ()
|
|
132
|
+
except BaseHomematicException as bhexc:
|
|
133
|
+
raise ClientException(
|
|
134
|
+
i18n.tr(
|
|
135
|
+
key="exception.client.get_link_peers.failed",
|
|
136
|
+
address=address,
|
|
137
|
+
reason=extract_exc_args(exc=bhexc),
|
|
138
|
+
)
|
|
139
|
+
) from bhexc
|
|
140
|
+
|
|
141
|
+
@inspector
|
|
142
|
+
async def get_links(self, *, address: str, flags: int) -> dict[str, Any]:
|
|
143
|
+
"""
|
|
144
|
+
Return detailed link information for a channel.
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
address: Channel address to query (e.g., "VCU0000001:1").
|
|
148
|
+
flags: Bitmask controlling returned information (backend-specific).
|
|
149
|
+
|
|
150
|
+
Returns:
|
|
151
|
+
Dict containing link details including sender, receiver, and paramsets.
|
|
152
|
+
|
|
153
|
+
Raises:
|
|
154
|
+
ClientException: If the RPC call fails.
|
|
155
|
+
|
|
156
|
+
"""
|
|
157
|
+
if not self._has_linking:
|
|
158
|
+
_LOGGER.debug("GET_LINKS: Not supported by client for %s", self._interface_id)
|
|
159
|
+
return {}
|
|
160
|
+
|
|
161
|
+
try:
|
|
162
|
+
return cast(dict[str, Any], await self._proxy.getLinks(address, flags))
|
|
163
|
+
except BaseHomematicException as bhexc:
|
|
164
|
+
raise ClientException(
|
|
165
|
+
i18n.tr(
|
|
166
|
+
key="exception.client.get_links.failed",
|
|
167
|
+
address=address,
|
|
168
|
+
reason=extract_exc_args(exc=bhexc),
|
|
169
|
+
)
|
|
170
|
+
) from bhexc
|
|
171
|
+
|
|
172
|
+
@inspector
|
|
173
|
+
async def remove_link(self, *, sender_address: str, receiver_address: str) -> None:
|
|
174
|
+
"""
|
|
175
|
+
Remove a direct link between two device channels.
|
|
176
|
+
|
|
177
|
+
Args:
|
|
178
|
+
sender_address: Source channel address (e.g., "VCU0000001:1").
|
|
179
|
+
receiver_address: Target channel address (e.g., "VCU0000002:1").
|
|
180
|
+
|
|
181
|
+
Raises:
|
|
182
|
+
ClientException: If the RPC call fails.
|
|
183
|
+
|
|
184
|
+
"""
|
|
185
|
+
if not self._has_linking:
|
|
186
|
+
_LOGGER.debug("REMOVE_LINK: Not supported by client for %s", self._interface_id)
|
|
187
|
+
return
|
|
188
|
+
|
|
189
|
+
try:
|
|
190
|
+
await self._proxy.removeLink(sender_address, receiver_address)
|
|
191
|
+
except BaseHomematicException as bhexc:
|
|
192
|
+
raise ClientException(
|
|
193
|
+
i18n.tr(
|
|
194
|
+
key="exception.client.remove_link.failed",
|
|
195
|
+
sender=sender_address,
|
|
196
|
+
receiver=receiver_address,
|
|
197
|
+
reason=extract_exc_args(exc=bhexc),
|
|
198
|
+
)
|
|
199
|
+
) from bhexc
|