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