aiohomematic 2025.8.10__tar.gz → 2025.9.2__tar.gz
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.
Potentially problematic release.
This version of aiohomematic might be problematic. Click here for more details.
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/PKG-INFO +8 -5
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/README.md +7 -4
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/caches/dynamic.py +1 -6
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/central/__init__.py +35 -24
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/central/xml_rpc_server.py +1 -1
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/client/__init__.py +35 -29
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/client/json_rpc.py +44 -12
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/client/xml_rpc.py +53 -20
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/const.py +2 -2
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/decorators.py +66 -27
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/model/__init__.py +1 -1
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/model/calculated/__init__.py +1 -1
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/model/calculated/climate.py +1 -1
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/model/calculated/data_point.py +2 -2
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/model/calculated/operating_voltage_level.py +7 -21
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/model/calculated/support.py +20 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/model/custom/__init__.py +1 -1
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/model/custom/climate.py +18 -18
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/model/custom/cover.py +1 -1
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/model/custom/data_point.py +1 -1
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/model/custom/light.py +1 -1
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/model/custom/lock.py +1 -1
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/model/custom/siren.py +1 -1
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/model/custom/switch.py +1 -1
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/model/custom/valve.py +1 -1
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/model/data_point.py +18 -18
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/model/device.py +21 -20
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/model/event.py +3 -8
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/model/generic/__init__.py +1 -1
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/model/generic/binary_sensor.py +1 -1
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/model/generic/button.py +1 -1
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/model/generic/data_point.py +3 -5
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/model/generic/number.py +1 -1
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/model/generic/select.py +1 -1
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/model/generic/sensor.py +1 -1
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/model/generic/switch.py +4 -4
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/model/generic/text.py +1 -1
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/model/hub/binary_sensor.py +1 -1
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/model/hub/button.py +2 -2
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/model/hub/data_point.py +4 -7
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/model/hub/number.py +1 -1
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/model/hub/select.py +2 -2
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/model/hub/sensor.py +1 -1
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/model/hub/switch.py +3 -3
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/model/hub/text.py +1 -1
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/model/support.py +1 -40
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/model/update.py +5 -4
- aiohomematic-2025.9.2/aiohomematic/property_decorators.py +327 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/support.py +70 -85
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic.egg-info/PKG-INFO +8 -5
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic.egg-info/SOURCES.txt +1 -1
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic_support/client_local.py +5 -5
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/pyproject.toml +0 -2
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/tests/test_calculated_support.py +34 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/tests/test_central_pydevccu.py +11 -11
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/tests/test_decorator.py +23 -5
- aiohomematic-2025.8.10/aiohomematic/model/decorators.py +0 -194
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/LICENSE +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/__init__.py +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/async_support.py +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/caches/__init__.py +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/caches/persistent.py +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/caches/visibility.py +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/central/decorators.py +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/client/_rpc_errors.py +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/context.py +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/converter.py +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/exceptions.py +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/hmcli.py +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/model/custom/const.py +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/model/custom/definition.py +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/model/custom/support.py +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/model/generic/action.py +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/model/hub/__init__.py +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/py.typed +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/rega_scripts/fetch_all_device_data.fn +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/rega_scripts/get_program_descriptions.fn +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/rega_scripts/get_serial.fn +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/rega_scripts/get_system_variable_descriptions.fn +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/rega_scripts/set_program_state.fn +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/rega_scripts/set_system_variable.fn +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic/validator.py +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic.egg-info/dependency_links.txt +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic.egg-info/requires.txt +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic.egg-info/top_level.txt +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/aiohomematic_support/__init__.py +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/setup.cfg +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/tests/test_action.py +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/tests/test_binary_sensor.py +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/tests/test_button.py +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/tests/test_central.py +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/tests/test_climate.py +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/tests/test_cover.py +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/tests/test_device.py +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/tests/test_entity.py +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/tests/test_event.py +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/tests/test_json_rpc.py +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/tests/test_light.py +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/tests/test_lock.py +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/tests/test_number.py +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/tests/test_select.py +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/tests/test_sensor.py +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/tests/test_siren.py +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/tests/test_support.py +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/tests/test_switch.py +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/tests/test_text.py +0 -0
- {aiohomematic-2025.8.10 → aiohomematic-2025.9.2}/tests/test_valve.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: aiohomematic
|
|
3
|
-
Version: 2025.
|
|
3
|
+
Version: 2025.9.2
|
|
4
4
|
Summary: Homematic interface for Home Assistant running on Python 3.
|
|
5
5
|
Home-page: https://github.com/sukramj/aiohomematic
|
|
6
6
|
Author-email: SukramJ <sukramj@icloud.com>, Daniel Perna <danielperna84@gmail.com>
|
|
@@ -52,7 +52,7 @@ Unlike pyhomematic, which required manual device mappings, aiohomematic automati
|
|
|
52
52
|
Use the Home Assistant custom integration "Homematic(IP) Local", which is powered by aiohomematic.
|
|
53
53
|
|
|
54
54
|
1. Prerequisites
|
|
55
|
-
-
|
|
55
|
+
- Use latest version of Home Assistant.
|
|
56
56
|
- A CCU3, RaspberryMatic, or Homegear instance reachable from Home Assistant.
|
|
57
57
|
- For HomematicIP devices, ensure CCU firmware meets the minimum versions listed below.
|
|
58
58
|
2. Install the integration
|
|
@@ -60,11 +60,11 @@ Use the Home Assistant custom integration "Homematic(IP) Local", which is powere
|
|
|
60
60
|
- Follow the installation guide: https://github.com/sukramj/homematicip_local/wiki/Installation
|
|
61
61
|
3. Configure via Home Assistant UI
|
|
62
62
|
- In Home Assistant: Settings → Devices & Services → Add Integration → search for "Homematic(IP) Local".
|
|
63
|
-
- Enter the CCU/Homegear host (IP or hostname). If you use HTTPS on the CCU, enable
|
|
64
|
-
-
|
|
63
|
+
- Enter the CCU/Homegear host (IP or hostname). If you use HTTPS on the CCU, enable TLS and don't use verify if self‑signed.
|
|
64
|
+
- Always enter credentials.
|
|
65
65
|
- Choose which interfaces to enable (HM, HmIP, Virtual). Default ports are typically 2001 (HM), 2010 (HmIP), 9292 (Virtual).
|
|
66
66
|
4. Network callbacks
|
|
67
|
-
- The integration needs to receive XML‑RPC callbacks from the CCU. Make sure Home Assistant is reachable from the CCU (no NAT/firewall blocking).
|
|
67
|
+
- The integration needs to receive XML‑RPC callbacks from the CCU. Make sure Home Assistant is reachable from the CCU (no NAT/firewall blocking). Callbacks ar only required for special network setups.
|
|
68
68
|
5. Verify
|
|
69
69
|
- After setup, devices should appear under Devices & Services → Homematic(IP) Local. Discovery may take a few seconds after the first connection while paramsets are fetched and cached for faster restarts.
|
|
70
70
|
|
|
@@ -84,10 +84,12 @@ See details here: https://github.com/jens-maus/RaspberryMatic/issues/843. Other
|
|
|
84
84
|
- The public API of aiohomematic is explicitly defined via **all** in each module and subpackage.
|
|
85
85
|
- Backwards‑compatible imports should target these modules:
|
|
86
86
|
- aiohomematic.central: CentralUnit, CentralConfig and related schemas
|
|
87
|
+
- aiohomematic.central.event: display received events from the backend
|
|
87
88
|
- aiohomematic.client: Client, InterfaceConfig, create_client, get_client
|
|
88
89
|
- aiohomematic.model: device/data point abstractions (see subpackages for details)
|
|
89
90
|
- aiohomematic.exceptions: library exception types intended for consumers
|
|
90
91
|
- aiohomematic.const: constants and enums (stable subset; see module **all**)
|
|
92
|
+
- aiohomematic.performance: display some performance metrics (enabled when DEBUG is enabled)
|
|
91
93
|
- The top‑level package only exposes **version** to avoid import cycles and keep startup lean. Prefer importing from the specific submodules listed above.
|
|
92
94
|
|
|
93
95
|
Example:
|
|
@@ -109,6 +111,7 @@ Example:
|
|
|
109
111
|
|
|
110
112
|
- Changelog: [see](changelog.md) for release history and latest changes.
|
|
111
113
|
- Definition of calculated data points: [see](docs/calculated_data_points.md)
|
|
114
|
+
- Naming: [see](docs/naming.md) for how device, channel and data point names are created.
|
|
112
115
|
- Homematic(IP) Local integration: https://github.com/sukramj/homematicip_local
|
|
113
116
|
- Input select helper: [see](docs/input_select_helper.md) for an overview of how to use the input select helper.
|
|
114
117
|
- Troubleshooting with Home Assistant: [see](docs/homeassistant_troubleshooting.md) for common issues and how to debug them.
|
|
@@ -24,7 +24,7 @@ Unlike pyhomematic, which required manual device mappings, aiohomematic automati
|
|
|
24
24
|
Use the Home Assistant custom integration "Homematic(IP) Local", which is powered by aiohomematic.
|
|
25
25
|
|
|
26
26
|
1. Prerequisites
|
|
27
|
-
-
|
|
27
|
+
- Use latest version of Home Assistant.
|
|
28
28
|
- A CCU3, RaspberryMatic, or Homegear instance reachable from Home Assistant.
|
|
29
29
|
- For HomematicIP devices, ensure CCU firmware meets the minimum versions listed below.
|
|
30
30
|
2. Install the integration
|
|
@@ -32,11 +32,11 @@ Use the Home Assistant custom integration "Homematic(IP) Local", which is powere
|
|
|
32
32
|
- Follow the installation guide: https://github.com/sukramj/homematicip_local/wiki/Installation
|
|
33
33
|
3. Configure via Home Assistant UI
|
|
34
34
|
- In Home Assistant: Settings → Devices & Services → Add Integration → search for "Homematic(IP) Local".
|
|
35
|
-
- Enter the CCU/Homegear host (IP or hostname). If you use HTTPS on the CCU, enable
|
|
36
|
-
-
|
|
35
|
+
- Enter the CCU/Homegear host (IP or hostname). If you use HTTPS on the CCU, enable TLS and don't use verify if self‑signed.
|
|
36
|
+
- Always enter credentials.
|
|
37
37
|
- Choose which interfaces to enable (HM, HmIP, Virtual). Default ports are typically 2001 (HM), 2010 (HmIP), 9292 (Virtual).
|
|
38
38
|
4. Network callbacks
|
|
39
|
-
- The integration needs to receive XML‑RPC callbacks from the CCU. Make sure Home Assistant is reachable from the CCU (no NAT/firewall blocking).
|
|
39
|
+
- The integration needs to receive XML‑RPC callbacks from the CCU. Make sure Home Assistant is reachable from the CCU (no NAT/firewall blocking). Callbacks ar only required for special network setups.
|
|
40
40
|
5. Verify
|
|
41
41
|
- After setup, devices should appear under Devices & Services → Homematic(IP) Local. Discovery may take a few seconds after the first connection while paramsets are fetched and cached for faster restarts.
|
|
42
42
|
|
|
@@ -56,10 +56,12 @@ See details here: https://github.com/jens-maus/RaspberryMatic/issues/843. Other
|
|
|
56
56
|
- The public API of aiohomematic is explicitly defined via **all** in each module and subpackage.
|
|
57
57
|
- Backwards‑compatible imports should target these modules:
|
|
58
58
|
- aiohomematic.central: CentralUnit, CentralConfig and related schemas
|
|
59
|
+
- aiohomematic.central.event: display received events from the backend
|
|
59
60
|
- aiohomematic.client: Client, InterfaceConfig, create_client, get_client
|
|
60
61
|
- aiohomematic.model: device/data point abstractions (see subpackages for details)
|
|
61
62
|
- aiohomematic.exceptions: library exception types intended for consumers
|
|
62
63
|
- aiohomematic.const: constants and enums (stable subset; see module **all**)
|
|
64
|
+
- aiohomematic.performance: display some performance metrics (enabled when DEBUG is enabled)
|
|
63
65
|
- The top‑level package only exposes **version** to avoid import cycles and keep startup lean. Prefer importing from the specific submodules listed above.
|
|
64
66
|
|
|
65
67
|
Example:
|
|
@@ -81,6 +83,7 @@ Example:
|
|
|
81
83
|
|
|
82
84
|
- Changelog: [see](changelog.md) for release history and latest changes.
|
|
83
85
|
- Definition of calculated data points: [see](docs/calculated_data_points.md)
|
|
86
|
+
- Naming: [see](docs/naming.md) for how device, channel and data point names are created.
|
|
84
87
|
- Homematic(IP) Local integration: https://github.com/sukramj/homematicip_local
|
|
85
88
|
- Input select helper: [see](docs/input_select_helper.md) for an overview of how to use the input select helper.
|
|
86
89
|
- Troubleshooting with Home Assistant: [see](docs/homeassistant_troubleshooting.md) for common issues and how to debug them.
|
|
@@ -27,13 +27,11 @@ from collections.abc import Mapping
|
|
|
27
27
|
from datetime import datetime
|
|
28
28
|
import logging
|
|
29
29
|
from typing import Any, Final, cast
|
|
30
|
-
from urllib.parse import unquote
|
|
31
30
|
|
|
32
31
|
from aiohomematic import central as hmcu
|
|
33
32
|
from aiohomematic.const import (
|
|
34
33
|
DP_KEY_VALUE,
|
|
35
34
|
INIT_DATETIME,
|
|
36
|
-
ISO_8859_1,
|
|
37
35
|
LAST_COMMAND_SEND_STORE_TIMEOUT,
|
|
38
36
|
MAX_CACHE_AGE,
|
|
39
37
|
NO_CACHE_ENTRY,
|
|
@@ -312,10 +310,7 @@ class CentralDataCache:
|
|
|
312
310
|
|
|
313
311
|
def add_data(self, interface: Interface, all_device_data: Mapping[str, Any]) -> None:
|
|
314
312
|
"""Add data to cache."""
|
|
315
|
-
self._value_cache[interface] =
|
|
316
|
-
unquote(string=k, encoding=ISO_8859_1): unquote(string=v, encoding=ISO_8859_1) if isinstance(v, str) else v
|
|
317
|
-
for k, v in all_device_data.items()
|
|
318
|
-
}
|
|
313
|
+
self._value_cache[interface] = all_device_data
|
|
319
314
|
self._refreshed_at[interface] = datetime.now()
|
|
320
315
|
|
|
321
316
|
def get_data(
|
|
@@ -149,7 +149,6 @@ from aiohomematic.exceptions import (
|
|
|
149
149
|
from aiohomematic.model import create_data_points_and_events
|
|
150
150
|
from aiohomematic.model.custom import CustomDataPoint, create_custom_data_points
|
|
151
151
|
from aiohomematic.model.data_point import BaseParameterDataPoint, CallbackDataPoint
|
|
152
|
-
from aiohomematic.model.decorators import info_property
|
|
153
152
|
from aiohomematic.model.device import Channel, Device
|
|
154
153
|
from aiohomematic.model.event import GenericEvent
|
|
155
154
|
from aiohomematic.model.generic import GenericDataPoint
|
|
@@ -160,13 +159,21 @@ from aiohomematic.model.hub import (
|
|
|
160
159
|
Hub,
|
|
161
160
|
ProgramDpType,
|
|
162
161
|
)
|
|
163
|
-
from aiohomematic.
|
|
164
|
-
from aiohomematic.support import
|
|
162
|
+
from aiohomematic.property_decorators import info_property
|
|
163
|
+
from aiohomematic.support import (
|
|
164
|
+
LogContextMixin,
|
|
165
|
+
PayloadMixin,
|
|
166
|
+
check_config,
|
|
167
|
+
extract_exc_args,
|
|
168
|
+
get_channel_no,
|
|
169
|
+
get_device_address,
|
|
170
|
+
get_ip_addr,
|
|
171
|
+
)
|
|
165
172
|
|
|
166
173
|
__all__ = ["CentralConfig", "CentralUnit", "INTERFACE_EVENT_SCHEMA"]
|
|
167
174
|
|
|
168
175
|
_LOGGER: Final = logging.getLogger(__name__)
|
|
169
|
-
_LOGGER_EVENT: Final = logging.getLogger(f"{
|
|
176
|
+
_LOGGER_EVENT: Final = logging.getLogger(f"{__package__}.event")
|
|
170
177
|
|
|
171
178
|
# {central_name, central}
|
|
172
179
|
CENTRAL_INSTANCES: Final[dict[str, CentralUnit]] = {}
|
|
@@ -183,7 +190,7 @@ INTERFACE_EVENT_SCHEMA = vol.Schema(
|
|
|
183
190
|
)
|
|
184
191
|
|
|
185
192
|
|
|
186
|
-
class CentralUnit(PayloadMixin):
|
|
193
|
+
class CentralUnit(LogContextMixin, PayloadMixin):
|
|
187
194
|
"""Central unit that collects everything to handle communication from/to CCU/Homegear."""
|
|
188
195
|
|
|
189
196
|
def __init__(self, central_config: CentralConfig) -> None:
|
|
@@ -212,7 +219,7 @@ class CentralUnit(PayloadMixin):
|
|
|
212
219
|
# {interface_id, client}
|
|
213
220
|
self._clients: Final[dict[str, hmcl.Client]] = {}
|
|
214
221
|
self._data_point_key_event_subscriptions: Final[
|
|
215
|
-
dict[DataPointKey, list[Callable[[Any], Coroutine[Any, Any, None]]]]
|
|
222
|
+
dict[DataPointKey, list[Callable[[Any, datetime], Coroutine[Any, Any, None]]]]
|
|
216
223
|
] = {}
|
|
217
224
|
self._data_point_path_event_subscriptions: Final[dict[str, DataPointKey]] = {}
|
|
218
225
|
self._sysvar_data_point_event_subscriptions: Final[dict[str, Callable]] = {}
|
|
@@ -237,7 +244,7 @@ class CentralUnit(PayloadMixin):
|
|
|
237
244
|
self._hub: Hub = Hub(central=self)
|
|
238
245
|
self._version: str | None = None
|
|
239
246
|
# store last event received datetime by interface_id
|
|
240
|
-
self.
|
|
247
|
+
self._last_event_seen_for_interface: Final[dict[str, datetime]] = {}
|
|
241
248
|
self._xml_rpc_callback_ip: str = IP_ANY_V4
|
|
242
249
|
self._listen_ip_addr: str = IP_ANY_V4
|
|
243
250
|
self._listen_port: int = PORT_ANY
|
|
@@ -252,7 +259,7 @@ class CentralUnit(PayloadMixin):
|
|
|
252
259
|
"""Return the xml rpc server callback ip address."""
|
|
253
260
|
return self._xml_rpc_callback_ip
|
|
254
261
|
|
|
255
|
-
@info_property
|
|
262
|
+
@info_property(log_context=True)
|
|
256
263
|
def url(self) -> str:
|
|
257
264
|
"""Return the central url."""
|
|
258
265
|
return self._url
|
|
@@ -362,14 +369,14 @@ class CentralUnit(PayloadMixin):
|
|
|
362
369
|
"""Return the loop support."""
|
|
363
370
|
return self._looper
|
|
364
371
|
|
|
365
|
-
@info_property
|
|
372
|
+
@info_property(log_context=True)
|
|
366
373
|
def model(self) -> str | None:
|
|
367
374
|
"""Return the model of the backend."""
|
|
368
375
|
if not self._model and (client := self.primary_client):
|
|
369
376
|
self._model = client.model
|
|
370
377
|
return self._model
|
|
371
378
|
|
|
372
|
-
@info_property
|
|
379
|
+
@info_property(log_context=True)
|
|
373
380
|
def name(self) -> str:
|
|
374
381
|
"""Return the name of the backend."""
|
|
375
382
|
return self._config.name
|
|
@@ -1109,7 +1116,7 @@ class CentralUnit(PayloadMixin):
|
|
|
1109
1116
|
if not self.has_client(interface_id=interface_id):
|
|
1110
1117
|
return
|
|
1111
1118
|
|
|
1112
|
-
self.
|
|
1119
|
+
self.set_last_event_seen_for_interface(interface_id=interface_id)
|
|
1113
1120
|
# No need to check the response of a XmlRPC-PING
|
|
1114
1121
|
if parameter == Parameter.PONG:
|
|
1115
1122
|
if "#" in value:
|
|
@@ -1133,9 +1140,10 @@ class CentralUnit(PayloadMixin):
|
|
|
1133
1140
|
|
|
1134
1141
|
if dpk in self._data_point_key_event_subscriptions:
|
|
1135
1142
|
try:
|
|
1143
|
+
received_at = datetime.now()
|
|
1136
1144
|
for callback_handler in self._data_point_key_event_subscriptions[dpk]:
|
|
1137
1145
|
if callable(callback_handler):
|
|
1138
|
-
await callback_handler(value)
|
|
1146
|
+
await callback_handler(value, received_at)
|
|
1139
1147
|
except RuntimeError as rterr: # pragma: no cover
|
|
1140
1148
|
_LOGGER_EVENT.debug(
|
|
1141
1149
|
"EVENT: RuntimeError [%s]. Failed to call callback for: %s, %s, %s",
|
|
@@ -1184,7 +1192,10 @@ class CentralUnit(PayloadMixin):
|
|
|
1184
1192
|
try:
|
|
1185
1193
|
callback_handler = self._sysvar_data_point_event_subscriptions[state_path]
|
|
1186
1194
|
if callable(callback_handler):
|
|
1187
|
-
|
|
1195
|
+
received_at = datetime.now()
|
|
1196
|
+
self._looper.create_task(
|
|
1197
|
+
callback_handler(value, received_at), name=f"sysvar-data-point-event-{state_path}"
|
|
1198
|
+
)
|
|
1188
1199
|
except RuntimeError as rterr: # pragma: no cover
|
|
1189
1200
|
_LOGGER_EVENT.debug(
|
|
1190
1201
|
"EVENT: RuntimeError [%s]. Failed to call callback for: %s",
|
|
@@ -1207,7 +1218,7 @@ class CentralUnit(PayloadMixin):
|
|
|
1207
1218
|
|
|
1208
1219
|
def add_event_subscription(self, data_point: BaseParameterDataPoint) -> None:
|
|
1209
1220
|
"""Add data_point to central event subscription."""
|
|
1210
|
-
if isinstance(data_point,
|
|
1221
|
+
if isinstance(data_point, GenericDataPoint | GenericEvent) and (
|
|
1211
1222
|
data_point.is_readable or data_point.supports_events
|
|
1212
1223
|
):
|
|
1213
1224
|
if data_point.dpk not in self._data_point_key_event_subscriptions:
|
|
@@ -1219,13 +1230,13 @@ class CentralUnit(PayloadMixin):
|
|
|
1219
1230
|
):
|
|
1220
1231
|
self._data_point_path_event_subscriptions[data_point.state_path] = data_point.dpk
|
|
1221
1232
|
|
|
1222
|
-
@inspector
|
|
1233
|
+
@inspector
|
|
1223
1234
|
async def create_central_links(self) -> None:
|
|
1224
1235
|
"""Create a central links to support press events on all channels with click events."""
|
|
1225
1236
|
for device in self.devices:
|
|
1226
1237
|
await device.create_central_links()
|
|
1227
1238
|
|
|
1228
|
-
@inspector
|
|
1239
|
+
@inspector
|
|
1229
1240
|
async def remove_central_links(self) -> None:
|
|
1230
1241
|
"""Remove central links."""
|
|
1231
1242
|
for device in self.devices:
|
|
@@ -1248,19 +1259,19 @@ class CentralUnit(PayloadMixin):
|
|
|
1248
1259
|
|
|
1249
1260
|
def remove_event_subscription(self, data_point: BaseParameterDataPoint) -> None:
|
|
1250
1261
|
"""Remove event subscription from central collections."""
|
|
1251
|
-
if isinstance(data_point,
|
|
1262
|
+
if isinstance(data_point, GenericDataPoint | GenericEvent) and data_point.supports_events:
|
|
1252
1263
|
if data_point.dpk in self._data_point_key_event_subscriptions:
|
|
1253
1264
|
del self._data_point_key_event_subscriptions[data_point.dpk]
|
|
1254
1265
|
if data_point.state_path in self._data_point_path_event_subscriptions:
|
|
1255
1266
|
del self._data_point_path_event_subscriptions[data_point.state_path]
|
|
1256
1267
|
|
|
1257
|
-
def
|
|
1258
|
-
"""Return the last event
|
|
1259
|
-
return self.
|
|
1268
|
+
def get_last_event_seen_for_interface(self, interface_id: str) -> datetime | None:
|
|
1269
|
+
"""Return the last event seen for an interface."""
|
|
1270
|
+
return self._last_event_seen_for_interface.get(interface_id)
|
|
1260
1271
|
|
|
1261
|
-
def
|
|
1262
|
-
"""Set the last event
|
|
1263
|
-
self.
|
|
1272
|
+
def set_last_event_seen_for_interface(self, interface_id: str) -> None:
|
|
1273
|
+
"""Set the last event seen for an interface."""
|
|
1274
|
+
self._last_event_seen_for_interface[interface_id] = datetime.now()
|
|
1264
1275
|
|
|
1265
1276
|
async def execute_program(self, pid: str) -> bool:
|
|
1266
1277
|
"""Execute a program on CCU / Homegear."""
|
|
@@ -1703,7 +1714,7 @@ class _Scheduler(threading.Thread):
|
|
|
1703
1714
|
_LOGGER.debug("REFRESH_CLIENT_DATA: Loading data for %s", self._central.name)
|
|
1704
1715
|
for client in poll_clients:
|
|
1705
1716
|
await self._central.load_and_refresh_data_point_data(interface=client.interface)
|
|
1706
|
-
self._central.
|
|
1717
|
+
self._central.set_last_event_seen_for_interface(interface_id=client.interface_id)
|
|
1707
1718
|
|
|
1708
1719
|
@inspector(re_raise=False)
|
|
1709
1720
|
async def _refresh_sysvar_data(self) -> None:
|
|
@@ -57,7 +57,7 @@ class RPCFunctions:
|
|
|
57
57
|
action="error",
|
|
58
58
|
err=err,
|
|
59
59
|
level=logging.WARNING,
|
|
60
|
-
|
|
60
|
+
log_context={"interface_id": interface_id, "error_code": int(error_code)},
|
|
61
61
|
)
|
|
62
62
|
_LOGGER.warning(
|
|
63
63
|
"ERROR failed: interface_id = %s, error_code = %i, message = %s",
|
|
@@ -93,7 +93,9 @@ from aiohomematic.decorators import inspector, measure_execution_time
|
|
|
93
93
|
from aiohomematic.exceptions import BaseHomematicException, ClientException, NoConnectionException
|
|
94
94
|
from aiohomematic.model.device import Device
|
|
95
95
|
from aiohomematic.model.support import convert_value
|
|
96
|
+
from aiohomematic.property_decorators import info_property
|
|
96
97
|
from aiohomematic.support import (
|
|
98
|
+
LogContextMixin,
|
|
97
99
|
build_xml_rpc_headers,
|
|
98
100
|
build_xml_rpc_uri,
|
|
99
101
|
extract_exc_args,
|
|
@@ -124,7 +126,7 @@ _CCU_JSON_VALUE_TYPE: Final = {
|
|
|
124
126
|
}
|
|
125
127
|
|
|
126
128
|
|
|
127
|
-
class Client(ABC):
|
|
129
|
+
class Client(ABC, LogContextMixin):
|
|
128
130
|
"""Client object to access the backends via XML-RPC or JSON-RPC."""
|
|
129
131
|
|
|
130
132
|
def __init__(self, client_config: _ClientConfig) -> None:
|
|
@@ -144,6 +146,7 @@ class Client(ABC):
|
|
|
144
146
|
self._system_information: SystemInformation
|
|
145
147
|
self.modified_at: datetime = INIT_DATETIME
|
|
146
148
|
|
|
149
|
+
@inspector
|
|
147
150
|
async def init_client(self) -> None:
|
|
148
151
|
"""Init the client."""
|
|
149
152
|
self._system_information = await self._get_system_information()
|
|
@@ -168,7 +171,7 @@ class Client(ABC):
|
|
|
168
171
|
"""Return the interface of the client."""
|
|
169
172
|
return self._config.interface
|
|
170
173
|
|
|
171
|
-
@
|
|
174
|
+
@info_property(log_context=True)
|
|
172
175
|
def interface_id(self) -> str:
|
|
173
176
|
"""Return the interface id of the client."""
|
|
174
177
|
return self._config.interface_id
|
|
@@ -384,7 +387,9 @@ class Client(ABC):
|
|
|
384
387
|
"""Return if XmlRPC-Server is alive based on received events for this client."""
|
|
385
388
|
if not self.supports_ping_pong:
|
|
386
389
|
return True
|
|
387
|
-
if (
|
|
390
|
+
if (
|
|
391
|
+
last_events_dt := self.central.get_last_event_seen_for_interface(interface_id=self.interface_id)
|
|
392
|
+
) is not None:
|
|
388
393
|
if (seconds_since_last_event := (datetime.now() - last_events_dt).total_seconds()) > CALLBACK_WARN_INTERVAL:
|
|
389
394
|
if self._is_callback_alive:
|
|
390
395
|
self.central.fire_interface_event(
|
|
@@ -418,12 +423,12 @@ class Client(ABC):
|
|
|
418
423
|
"""Send ping to CCU to generate PONG event."""
|
|
419
424
|
|
|
420
425
|
@abstractmethod
|
|
421
|
-
@inspector
|
|
426
|
+
@inspector
|
|
422
427
|
async def execute_program(self, pid: str) -> bool:
|
|
423
428
|
"""Execute a program on CCU / Homegear."""
|
|
424
429
|
|
|
425
430
|
@abstractmethod
|
|
426
|
-
@inspector
|
|
431
|
+
@inspector
|
|
427
432
|
async def set_program_state(self, pid: str, state: bool) -> bool:
|
|
428
433
|
"""Set the program state on CCU / Homegear."""
|
|
429
434
|
|
|
@@ -433,12 +438,12 @@ class Client(ABC):
|
|
|
433
438
|
"""Set a system variable on CCU / Homegear."""
|
|
434
439
|
|
|
435
440
|
@abstractmethod
|
|
436
|
-
@inspector
|
|
441
|
+
@inspector
|
|
437
442
|
async def delete_system_variable(self, name: str) -> bool:
|
|
438
443
|
"""Delete a system variable from CCU / Homegear."""
|
|
439
444
|
|
|
440
445
|
@abstractmethod
|
|
441
|
-
@inspector
|
|
446
|
+
@inspector
|
|
442
447
|
async def get_system_variable(self, name: str) -> Any:
|
|
443
448
|
"""Get single system variable from CCU / Homegear."""
|
|
444
449
|
|
|
@@ -489,7 +494,7 @@ class Client(ABC):
|
|
|
489
494
|
_LOGGER.warning("GET_DEVICE_DESCRIPTIONS failed: %s [%s]", bhexc.name, extract_exc_args(exc=bhexc))
|
|
490
495
|
return None
|
|
491
496
|
|
|
492
|
-
@inspector
|
|
497
|
+
@inspector
|
|
493
498
|
async def add_link(self, sender_address: str, receiver_address: str, name: str, description: str) -> None:
|
|
494
499
|
"""Return a list of links."""
|
|
495
500
|
try:
|
|
@@ -499,7 +504,7 @@ class Client(ABC):
|
|
|
499
504
|
f"ADD_LINK failed with for: {sender_address}/{receiver_address}/{name}/{description}: {extract_exc_args(exc=bhexc)}"
|
|
500
505
|
) from bhexc
|
|
501
506
|
|
|
502
|
-
@inspector
|
|
507
|
+
@inspector
|
|
503
508
|
async def remove_link(self, sender_address: str, receiver_address: str) -> None:
|
|
504
509
|
"""Return a list of links."""
|
|
505
510
|
try:
|
|
@@ -509,7 +514,7 @@ class Client(ABC):
|
|
|
509
514
|
f"REMOVE_LINK failed with for: {sender_address}/{receiver_address}: {extract_exc_args(exc=bhexc)}"
|
|
510
515
|
) from bhexc
|
|
511
516
|
|
|
512
|
-
@inspector
|
|
517
|
+
@inspector
|
|
513
518
|
async def get_link_peers(self, address: str) -> tuple[str, ...] | None:
|
|
514
519
|
"""Return a list of link pers."""
|
|
515
520
|
try:
|
|
@@ -519,7 +524,7 @@ class Client(ABC):
|
|
|
519
524
|
f"GET_LINK_PEERS failed with for: {address}: {extract_exc_args(exc=bhexc)}"
|
|
520
525
|
) from bhexc
|
|
521
526
|
|
|
522
|
-
@inspector
|
|
527
|
+
@inspector
|
|
523
528
|
async def get_links(self, address: str, flags: int) -> dict[str, Any]:
|
|
524
529
|
"""Return a list of links."""
|
|
525
530
|
try:
|
|
@@ -527,7 +532,7 @@ class Client(ABC):
|
|
|
527
532
|
except BaseHomematicException as bhexc:
|
|
528
533
|
raise ClientException(f"GET_LINKS failed with for: {address}: {extract_exc_args(exc=bhexc)}") from bhexc
|
|
529
534
|
|
|
530
|
-
@inspector
|
|
535
|
+
@inspector
|
|
531
536
|
async def get_metadata(self, address: str, data_id: str) -> dict[str, Any]:
|
|
532
537
|
"""Return the metadata for an object."""
|
|
533
538
|
try:
|
|
@@ -537,7 +542,7 @@ class Client(ABC):
|
|
|
537
542
|
f"GET_METADATA failed with for: {address}/{data_id}: {extract_exc_args(exc=bhexc)}"
|
|
538
543
|
) from bhexc
|
|
539
544
|
|
|
540
|
-
@inspector
|
|
545
|
+
@inspector
|
|
541
546
|
async def set_metadata(self, address: str, data_id: str, value: dict[str, Any]) -> dict[str, Any]:
|
|
542
547
|
"""Write the metadata for an object."""
|
|
543
548
|
try:
|
|
@@ -694,7 +699,7 @@ class Client(ABC):
|
|
|
694
699
|
check_against_pd=check_against_pd,
|
|
695
700
|
)
|
|
696
701
|
|
|
697
|
-
@inspector
|
|
702
|
+
@inspector
|
|
698
703
|
async def get_paramset(
|
|
699
704
|
self,
|
|
700
705
|
address: str,
|
|
@@ -957,7 +962,7 @@ class Client(ABC):
|
|
|
957
962
|
)
|
|
958
963
|
return None
|
|
959
964
|
|
|
960
|
-
@inspector
|
|
965
|
+
@inspector
|
|
961
966
|
async def get_all_paramset_descriptions(
|
|
962
967
|
self, device_descriptions: tuple[DeviceDescription, ...]
|
|
963
968
|
) -> dict[str, dict[ParamsetKey, dict[str, ParameterData]]]:
|
|
@@ -967,7 +972,7 @@ class Client(ABC):
|
|
|
967
972
|
all_paramsets.update(await self.get_paramset_descriptions(device_description=device_description))
|
|
968
973
|
return all_paramsets
|
|
969
974
|
|
|
970
|
-
@inspector
|
|
975
|
+
@inspector
|
|
971
976
|
async def has_program_ids(self, channel_hmid: str) -> bool:
|
|
972
977
|
"""Return if a channel has program ids."""
|
|
973
978
|
return False
|
|
@@ -985,12 +990,12 @@ class Client(ABC):
|
|
|
985
990
|
)
|
|
986
991
|
return None
|
|
987
992
|
|
|
988
|
-
@inspector
|
|
993
|
+
@inspector
|
|
989
994
|
async def report_value_usage(self, address: str, value_id: str, ref_counter: int) -> bool:
|
|
990
995
|
"""Report value usage."""
|
|
991
996
|
return False
|
|
992
997
|
|
|
993
|
-
@inspector
|
|
998
|
+
@inspector
|
|
994
999
|
async def update_device_firmware(self, device_address: str) -> bool:
|
|
995
1000
|
"""Update the firmware of a homematic device."""
|
|
996
1001
|
if device := self.central.get_device(address=device_address):
|
|
@@ -1133,22 +1138,22 @@ class ClientCCU(Client):
|
|
|
1133
1138
|
self.modified_at = INIT_DATETIME
|
|
1134
1139
|
return False
|
|
1135
1140
|
|
|
1136
|
-
@inspector
|
|
1141
|
+
@inspector
|
|
1137
1142
|
async def execute_program(self, pid: str) -> bool:
|
|
1138
1143
|
"""Execute a program on CCU."""
|
|
1139
1144
|
return await self._json_rpc_client.execute_program(pid=pid)
|
|
1140
1145
|
|
|
1141
|
-
@inspector
|
|
1146
|
+
@inspector
|
|
1142
1147
|
async def set_program_state(self, pid: str, state: bool) -> bool:
|
|
1143
1148
|
"""Set the program state on CCU."""
|
|
1144
1149
|
return await self._json_rpc_client.set_program_state(pid=pid, state=state)
|
|
1145
1150
|
|
|
1146
|
-
@inspector
|
|
1151
|
+
@inspector
|
|
1147
1152
|
async def has_program_ids(self, channel_hmid: str) -> bool:
|
|
1148
1153
|
"""Return if a channel has program ids."""
|
|
1149
1154
|
return await self._json_rpc_client.has_program_ids(channel_hmid=channel_hmid)
|
|
1150
1155
|
|
|
1151
|
-
@inspector
|
|
1156
|
+
@inspector
|
|
1152
1157
|
async def report_value_usage(self, address: str, value_id: str, ref_counter: int) -> bool:
|
|
1153
1158
|
"""Report value usage."""
|
|
1154
1159
|
try:
|
|
@@ -1163,12 +1168,12 @@ class ClientCCU(Client):
|
|
|
1163
1168
|
"""Set a system variable on CCU / Homegear."""
|
|
1164
1169
|
return await self._json_rpc_client.set_system_variable(legacy_name=legacy_name, value=value)
|
|
1165
1170
|
|
|
1166
|
-
@inspector
|
|
1171
|
+
@inspector
|
|
1167
1172
|
async def delete_system_variable(self, name: str) -> bool:
|
|
1168
1173
|
"""Delete a system variable from CCU / Homegear."""
|
|
1169
1174
|
return await self._json_rpc_client.delete_system_variable(name=name)
|
|
1170
1175
|
|
|
1171
|
-
@inspector
|
|
1176
|
+
@inspector
|
|
1172
1177
|
async def get_system_variable(self, name: str) -> Any:
|
|
1173
1178
|
"""Get single system variable from CCU / Homegear."""
|
|
1174
1179
|
return await self._json_rpc_client.get_system_variable(name=name)
|
|
@@ -1217,6 +1222,7 @@ class ClientCCU(Client):
|
|
|
1217
1222
|
class ClientJsonCCU(ClientCCU):
|
|
1218
1223
|
"""Client implementation for CCU backend."""
|
|
1219
1224
|
|
|
1225
|
+
@inspector
|
|
1220
1226
|
async def init_client(self) -> None:
|
|
1221
1227
|
"""Init the client."""
|
|
1222
1228
|
self._system_information = await self._get_system_information()
|
|
@@ -1243,7 +1249,7 @@ class ClientJsonCCU(ClientCCU):
|
|
|
1243
1249
|
_LOGGER.warning("GET_DEVICE_DESCRIPTIONS failed: %s [%s]", bhexc.name, extract_exc_args(exc=bhexc))
|
|
1244
1250
|
return None
|
|
1245
1251
|
|
|
1246
|
-
@inspector
|
|
1252
|
+
@inspector
|
|
1247
1253
|
async def get_paramset(
|
|
1248
1254
|
self,
|
|
1249
1255
|
address: str,
|
|
@@ -1473,12 +1479,12 @@ class ClientHomegear(Client):
|
|
|
1473
1479
|
self.modified_at = INIT_DATETIME
|
|
1474
1480
|
return False
|
|
1475
1481
|
|
|
1476
|
-
@inspector
|
|
1482
|
+
@inspector
|
|
1477
1483
|
async def execute_program(self, pid: str) -> bool:
|
|
1478
1484
|
"""Execute a program on Homegear."""
|
|
1479
1485
|
return True
|
|
1480
1486
|
|
|
1481
|
-
@inspector
|
|
1487
|
+
@inspector
|
|
1482
1488
|
async def set_program_state(self, pid: str, state: bool) -> bool:
|
|
1483
1489
|
"""Set the program state on Homegear."""
|
|
1484
1490
|
return True
|
|
@@ -1489,13 +1495,13 @@ class ClientHomegear(Client):
|
|
|
1489
1495
|
await self._proxy.setSystemVariable(legacy_name, value)
|
|
1490
1496
|
return True
|
|
1491
1497
|
|
|
1492
|
-
@inspector
|
|
1498
|
+
@inspector
|
|
1493
1499
|
async def delete_system_variable(self, name: str) -> bool:
|
|
1494
1500
|
"""Delete a system variable from CCU / Homegear."""
|
|
1495
1501
|
await self._proxy.deleteSystemVariable(name)
|
|
1496
1502
|
return True
|
|
1497
1503
|
|
|
1498
|
-
@inspector
|
|
1504
|
+
@inspector
|
|
1499
1505
|
async def get_system_variable(self, name: str) -> Any:
|
|
1500
1506
|
"""Get single system variable from CCU / Homegear."""
|
|
1501
1507
|
return await self._proxy.getSystemVariable(name)
|