aiohomematic 2025.8.6__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.

Potentially problematic release.


This version of aiohomematic might be problematic. Click here for more details.

Files changed (77) hide show
  1. aiohomematic/__init__.py +47 -0
  2. aiohomematic/async_support.py +146 -0
  3. aiohomematic/caches/__init__.py +10 -0
  4. aiohomematic/caches/dynamic.py +554 -0
  5. aiohomematic/caches/persistent.py +459 -0
  6. aiohomematic/caches/visibility.py +774 -0
  7. aiohomematic/central/__init__.py +2034 -0
  8. aiohomematic/central/decorators.py +110 -0
  9. aiohomematic/central/xml_rpc_server.py +267 -0
  10. aiohomematic/client/__init__.py +1746 -0
  11. aiohomematic/client/json_rpc.py +1193 -0
  12. aiohomematic/client/xml_rpc.py +222 -0
  13. aiohomematic/const.py +795 -0
  14. aiohomematic/context.py +8 -0
  15. aiohomematic/converter.py +82 -0
  16. aiohomematic/decorators.py +188 -0
  17. aiohomematic/exceptions.py +145 -0
  18. aiohomematic/hmcli.py +159 -0
  19. aiohomematic/model/__init__.py +137 -0
  20. aiohomematic/model/calculated/__init__.py +65 -0
  21. aiohomematic/model/calculated/climate.py +230 -0
  22. aiohomematic/model/calculated/data_point.py +319 -0
  23. aiohomematic/model/calculated/operating_voltage_level.py +311 -0
  24. aiohomematic/model/calculated/support.py +174 -0
  25. aiohomematic/model/custom/__init__.py +175 -0
  26. aiohomematic/model/custom/climate.py +1334 -0
  27. aiohomematic/model/custom/const.py +146 -0
  28. aiohomematic/model/custom/cover.py +741 -0
  29. aiohomematic/model/custom/data_point.py +318 -0
  30. aiohomematic/model/custom/definition.py +861 -0
  31. aiohomematic/model/custom/light.py +1092 -0
  32. aiohomematic/model/custom/lock.py +389 -0
  33. aiohomematic/model/custom/siren.py +268 -0
  34. aiohomematic/model/custom/support.py +40 -0
  35. aiohomematic/model/custom/switch.py +172 -0
  36. aiohomematic/model/custom/valve.py +112 -0
  37. aiohomematic/model/data_point.py +1109 -0
  38. aiohomematic/model/decorators.py +173 -0
  39. aiohomematic/model/device.py +1347 -0
  40. aiohomematic/model/event.py +210 -0
  41. aiohomematic/model/generic/__init__.py +211 -0
  42. aiohomematic/model/generic/action.py +32 -0
  43. aiohomematic/model/generic/binary_sensor.py +28 -0
  44. aiohomematic/model/generic/button.py +25 -0
  45. aiohomematic/model/generic/data_point.py +162 -0
  46. aiohomematic/model/generic/number.py +73 -0
  47. aiohomematic/model/generic/select.py +36 -0
  48. aiohomematic/model/generic/sensor.py +72 -0
  49. aiohomematic/model/generic/switch.py +52 -0
  50. aiohomematic/model/generic/text.py +27 -0
  51. aiohomematic/model/hub/__init__.py +334 -0
  52. aiohomematic/model/hub/binary_sensor.py +22 -0
  53. aiohomematic/model/hub/button.py +26 -0
  54. aiohomematic/model/hub/data_point.py +332 -0
  55. aiohomematic/model/hub/number.py +37 -0
  56. aiohomematic/model/hub/select.py +47 -0
  57. aiohomematic/model/hub/sensor.py +35 -0
  58. aiohomematic/model/hub/switch.py +42 -0
  59. aiohomematic/model/hub/text.py +28 -0
  60. aiohomematic/model/support.py +599 -0
  61. aiohomematic/model/update.py +136 -0
  62. aiohomematic/py.typed +0 -0
  63. aiohomematic/rega_scripts/fetch_all_device_data.fn +75 -0
  64. aiohomematic/rega_scripts/get_program_descriptions.fn +30 -0
  65. aiohomematic/rega_scripts/get_serial.fn +44 -0
  66. aiohomematic/rega_scripts/get_system_variable_descriptions.fn +30 -0
  67. aiohomematic/rega_scripts/set_program_state.fn +12 -0
  68. aiohomematic/rega_scripts/set_system_variable.fn +15 -0
  69. aiohomematic/support.py +482 -0
  70. aiohomematic/validator.py +65 -0
  71. aiohomematic-2025.8.6.dist-info/METADATA +69 -0
  72. aiohomematic-2025.8.6.dist-info/RECORD +77 -0
  73. aiohomematic-2025.8.6.dist-info/WHEEL +5 -0
  74. aiohomematic-2025.8.6.dist-info/licenses/LICENSE +21 -0
  75. aiohomematic-2025.8.6.dist-info/top_level.txt +2 -0
  76. aiohomematic_support/__init__.py +1 -0
  77. aiohomematic_support/client_local.py +349 -0
@@ -0,0 +1,172 @@
1
+ """Module for data points implemented using the switch category."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Mapping
6
+ from enum import StrEnum
7
+ import logging
8
+ from typing import Any, Final
9
+
10
+ from aiohomematic.const import DataPointCategory, Parameter
11
+ from aiohomematic.model import device as hmd
12
+ from aiohomematic.model.custom import definition as hmed
13
+ from aiohomematic.model.custom.const import DeviceProfile, Field
14
+ from aiohomematic.model.custom.data_point import CustomDataPoint
15
+ from aiohomematic.model.custom.support import CustomConfig, ExtendedConfig
16
+ from aiohomematic.model.data_point import CallParameterCollector, bind_collector
17
+ from aiohomematic.model.decorators import state_property
18
+ from aiohomematic.model.generic import DpAction, DpBinarySensor, DpSwitch
19
+
20
+ _LOGGER: Final = logging.getLogger(__name__)
21
+
22
+
23
+ class _StateChangeArg(StrEnum):
24
+ """Enum with switch state change arguments."""
25
+
26
+ OFF = "off"
27
+ ON = "on"
28
+
29
+
30
+ class CustomDpSwitch(CustomDataPoint):
31
+ """Class for HomeMatic switch data point."""
32
+
33
+ __slots__ = (
34
+ "_dp_group_state",
35
+ "_dp_on_time_value",
36
+ "_dp_state",
37
+ )
38
+
39
+ _category = DataPointCategory.SWITCH
40
+
41
+ def _init_data_point_fields(self) -> None:
42
+ """Init the data_point fields."""
43
+ super()._init_data_point_fields()
44
+ self._dp_state: DpSwitch = self._get_data_point(field=Field.STATE, data_point_type=DpSwitch)
45
+ self._dp_on_time_value: DpAction = self._get_data_point(field=Field.ON_TIME_VALUE, data_point_type=DpAction)
46
+ self._dp_group_state: DpBinarySensor = self._get_data_point(
47
+ field=Field.GROUP_STATE, data_point_type=DpBinarySensor
48
+ )
49
+
50
+ @property
51
+ def group_value(self) -> bool | None:
52
+ """Return the current group value of the switch."""
53
+ return self._dp_group_state.value
54
+
55
+ @state_property
56
+ def value(self) -> bool | None:
57
+ """Return the current channel value of the switch."""
58
+ return self._dp_state.value
59
+
60
+ @bind_collector()
61
+ async def turn_on(self, collector: CallParameterCollector | None = None, on_time: float | None = None) -> None:
62
+ """Turn the switch on."""
63
+ if on_time is not None:
64
+ self.set_timer_on_time(on_time=on_time)
65
+ if not self.is_state_change(on=True):
66
+ return
67
+
68
+ if (timer := self.get_and_start_timer()) is not None:
69
+ await self._dp_on_time_value.send_value(value=timer, collector=collector, do_validate=False)
70
+ await self._dp_state.turn_on(collector=collector)
71
+
72
+ @bind_collector()
73
+ async def turn_off(self, collector: CallParameterCollector | None = None) -> None:
74
+ """Turn the switch off."""
75
+ self.reset_timer_on_time()
76
+ if not self.is_state_change(off=True):
77
+ return
78
+ await self._dp_state.turn_off(collector=collector)
79
+
80
+ def is_state_change(self, **kwargs: Any) -> bool:
81
+ """Check if the state changes due to kwargs."""
82
+ if (on_time_running := self.timer_on_time_running) is not None and on_time_running is True:
83
+ return True
84
+ if self.timer_on_time is not None:
85
+ return True
86
+ if kwargs.get(_StateChangeArg.ON) is not None and self.value is not True:
87
+ return True
88
+ if kwargs.get(_StateChangeArg.OFF) is not None and self.value is not False:
89
+ return True
90
+ return super().is_state_change(**kwargs)
91
+
92
+
93
+ def make_ip_switch(
94
+ channel: hmd.Channel,
95
+ custom_config: CustomConfig,
96
+ ) -> None:
97
+ """Create HomematicIP switch data point."""
98
+ hmed.make_custom_data_point(
99
+ channel=channel,
100
+ data_point_class=CustomDpSwitch,
101
+ device_profile=DeviceProfile.IP_SWITCH,
102
+ custom_config=custom_config,
103
+ )
104
+
105
+
106
+ # Case for device model is not relevant.
107
+ # HomeBrew (HB-) devices are always listed as HM-.
108
+ DEVICES: Mapping[str, CustomConfig | tuple[CustomConfig, ...]] = {
109
+ "ELV-SH-BS2": CustomConfig(make_ce_func=make_ip_switch, channels=(4, 8)),
110
+ "ELV-SH-SW1-BAT": CustomConfig(make_ce_func=make_ip_switch, channels=(3,)),
111
+ "HmIP-BS2": CustomConfig(make_ce_func=make_ip_switch, channels=(4, 8)),
112
+ "HmIP-BSL": CustomConfig(make_ce_func=make_ip_switch, channels=(4,)),
113
+ "HmIP-BSM": CustomConfig(make_ce_func=make_ip_switch, channels=(4,)),
114
+ "HmIP-DRSI1": CustomConfig(
115
+ make_ce_func=make_ip_switch,
116
+ channels=(3,),
117
+ ),
118
+ "HmIP-DRSI4": CustomConfig(
119
+ make_ce_func=make_ip_switch,
120
+ channels=(6, 10, 14, 18),
121
+ ),
122
+ "HmIP-FSI": CustomConfig(make_ce_func=make_ip_switch, channels=(3,)),
123
+ "HmIP-FSM": CustomConfig(make_ce_func=make_ip_switch, channels=(2,)),
124
+ "HmIP-MOD-OC8": CustomConfig(make_ce_func=make_ip_switch, channels=(10, 14, 18, 22, 26, 30, 34, 38)),
125
+ "HmIP-PCBS": CustomConfig(make_ce_func=make_ip_switch, channels=(3,)),
126
+ "HmIP-PCBS-BAT": CustomConfig(make_ce_func=make_ip_switch, channels=(3,)),
127
+ "HmIP-PCBS2": CustomConfig(make_ce_func=make_ip_switch, channels=(4, 8)),
128
+ "HmIP-PS": CustomConfig(make_ce_func=make_ip_switch, channels=(3,)),
129
+ "HmIP-SCTH230": CustomConfig(make_ce_func=make_ip_switch, channels=(8,)),
130
+ "HmIP-SMO230": CustomConfig(
131
+ make_ce_func=make_ip_switch,
132
+ channels=(10,),
133
+ extended=ExtendedConfig(
134
+ additional_data_points={
135
+ 1: (
136
+ Parameter.ILLUMINATION,
137
+ Parameter.MOTION,
138
+ Parameter.MOTION_DETECTION_ACTIVE,
139
+ Parameter.RESET_MOTION,
140
+ ),
141
+ 2: (
142
+ Parameter.ILLUMINATION,
143
+ Parameter.MOTION,
144
+ Parameter.MOTION_DETECTION_ACTIVE,
145
+ Parameter.RESET_MOTION,
146
+ ),
147
+ 3: (
148
+ Parameter.ILLUMINATION,
149
+ Parameter.MOTION,
150
+ Parameter.MOTION_DETECTION_ACTIVE,
151
+ Parameter.RESET_MOTION,
152
+ ),
153
+ 4: (
154
+ Parameter.ILLUMINATION,
155
+ Parameter.MOTION,
156
+ Parameter.MOTION_DETECTION_ACTIVE,
157
+ Parameter.RESET_MOTION,
158
+ ),
159
+ }
160
+ ),
161
+ ),
162
+ "HmIP-USBSM": CustomConfig(make_ce_func=make_ip_switch, channels=(3,)),
163
+ "HmIP-WGC": CustomConfig(make_ce_func=make_ip_switch, channels=(3,)),
164
+ "HmIP-WGT": CustomConfig(make_ce_func=make_ip_switch, channels=(4,)),
165
+ "HmIP-WHS2": CustomConfig(make_ce_func=make_ip_switch, channels=(2, 6)),
166
+ "HmIPW-DRS": CustomConfig(
167
+ make_ce_func=make_ip_switch,
168
+ channels=(2, 6, 10, 14, 18, 22, 26, 30),
169
+ ),
170
+ "HmIPW-FIO6": CustomConfig(make_ce_func=make_ip_switch, channels=(8, 12, 16, 20, 24, 28)),
171
+ }
172
+ hmed.ALL_DEVICES[DataPointCategory.SWITCH] = DEVICES
@@ -0,0 +1,112 @@
1
+ """Module for data points implemented using the valve category."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Mapping
6
+ from enum import StrEnum
7
+ import logging
8
+ from typing import Any, Final
9
+
10
+ from aiohomematic.const import DataPointCategory
11
+ from aiohomematic.model import device as hmd
12
+ from aiohomematic.model.custom import definition as hmed
13
+ from aiohomematic.model.custom.const import DeviceProfile, Field
14
+ from aiohomematic.model.custom.data_point import CustomDataPoint
15
+ from aiohomematic.model.custom.support import CustomConfig
16
+ from aiohomematic.model.data_point import CallParameterCollector, bind_collector
17
+ from aiohomematic.model.decorators import state_property
18
+ from aiohomematic.model.generic import DpAction, DpBinarySensor, DpSwitch
19
+
20
+ _LOGGER: Final = logging.getLogger(__name__)
21
+
22
+
23
+ class _StateChangeArg(StrEnum):
24
+ """Enum with valve state change arguments."""
25
+
26
+ OFF = "off"
27
+ ON = "on"
28
+
29
+
30
+ class CustomDpIpIrrigationValve(CustomDataPoint):
31
+ """Class for HomeMatic irrigation valve data point."""
32
+
33
+ __slots__ = (
34
+ "_dp_group_state",
35
+ "_dp_on_time_value",
36
+ "_dp_state",
37
+ )
38
+
39
+ _category = DataPointCategory.VALVE
40
+
41
+ def _init_data_point_fields(self) -> None:
42
+ """Init the data_point fields."""
43
+ super()._init_data_point_fields()
44
+ self._dp_state: DpSwitch = self._get_data_point(field=Field.STATE, data_point_type=DpSwitch)
45
+ self._dp_on_time_value: DpAction = self._get_data_point(field=Field.ON_TIME_VALUE, data_point_type=DpAction)
46
+ self._dp_group_state: DpBinarySensor = self._get_data_point(
47
+ field=Field.GROUP_STATE, data_point_type=DpBinarySensor
48
+ )
49
+
50
+ @property
51
+ def group_value(self) -> bool | None:
52
+ """Return the current channel value of the valve."""
53
+ return self._dp_group_state.value
54
+
55
+ @state_property
56
+ def value(self) -> bool | None:
57
+ """Return the current value of the valve."""
58
+ return self._dp_state.value
59
+
60
+ @bind_collector()
61
+ async def open(self, collector: CallParameterCollector | None = None, on_time: float | None = None) -> None:
62
+ """Turn the valve on."""
63
+ if on_time is not None:
64
+ self.set_timer_on_time(on_time=on_time)
65
+ if not self.is_state_change(on=True):
66
+ return
67
+
68
+ if (timer := self.get_and_start_timer()) is not None:
69
+ await self._dp_on_time_value.send_value(value=timer, collector=collector, do_validate=False)
70
+ await self._dp_state.turn_on(collector=collector)
71
+
72
+ @bind_collector()
73
+ async def close(self, collector: CallParameterCollector | None = None) -> None:
74
+ """Turn the valve off."""
75
+ self.reset_timer_on_time()
76
+ if not self.is_state_change(off=True):
77
+ return
78
+ await self._dp_state.turn_off(collector=collector)
79
+
80
+ def is_state_change(self, **kwargs: Any) -> bool:
81
+ """Check if the state changes due to kwargs."""
82
+ if (on_time_running := self.timer_on_time_running) is not None and on_time_running is True:
83
+ return True
84
+ if self.timer_on_time is not None:
85
+ return True
86
+ if kwargs.get(_StateChangeArg.ON) is not None and self.value is not True:
87
+ return True
88
+ if kwargs.get(_StateChangeArg.OFF) is not None and self.value is not False:
89
+ return True
90
+ return super().is_state_change(**kwargs)
91
+
92
+
93
+ def make_ip_irrigation_valve(
94
+ channel: hmd.Channel,
95
+ custom_config: CustomConfig,
96
+ ) -> None:
97
+ """Create HomematicIP irrigation valve data point."""
98
+ hmed.make_custom_data_point(
99
+ channel=channel,
100
+ data_point_class=CustomDpIpIrrigationValve,
101
+ device_profile=DeviceProfile.IP_IRRIGATION_VALVE,
102
+ custom_config=custom_config,
103
+ )
104
+
105
+
106
+ # Case for device model is not relevant.
107
+ # HomeBrew (HB-) devices are always listed as HM-.
108
+ DEVICES: Mapping[str, CustomConfig | tuple[CustomConfig, ...]] = {
109
+ "ELV-SH-WSM": CustomConfig(make_ce_func=make_ip_irrigation_valve, channels=(4,)),
110
+ "HmIP-WSM": CustomConfig(make_ce_func=make_ip_irrigation_valve, channels=(4,)),
111
+ }
112
+ hmed.ALL_DEVICES[DataPointCategory.VALVE] = DEVICES