aiohomematic 2025.10.7__py3-none-any.whl → 2025.10.9__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 (73) hide show
  1. aiohomematic/__init__.py +3 -3
  2. aiohomematic/async_support.py +1 -1
  3. aiohomematic/central/__init__.py +59 -31
  4. aiohomematic/central/decorators.py +1 -1
  5. aiohomematic/central/rpc_server.py +1 -1
  6. aiohomematic/client/__init__.py +19 -13
  7. aiohomematic/client/_rpc_errors.py +1 -1
  8. aiohomematic/client/json_rpc.py +29 -3
  9. aiohomematic/client/rpc_proxy.py +20 -2
  10. aiohomematic/const.py +25 -6
  11. aiohomematic/context.py +1 -1
  12. aiohomematic/converter.py +1 -1
  13. aiohomematic/decorators.py +1 -1
  14. aiohomematic/exceptions.py +1 -1
  15. aiohomematic/hmcli.py +1 -1
  16. aiohomematic/model/__init__.py +1 -1
  17. aiohomematic/model/calculated/__init__.py +21 -4
  18. aiohomematic/model/calculated/climate.py +59 -1
  19. aiohomematic/model/calculated/data_point.py +1 -1
  20. aiohomematic/model/calculated/operating_voltage_level.py +1 -1
  21. aiohomematic/model/calculated/support.py +41 -3
  22. aiohomematic/model/custom/__init__.py +1 -1
  23. aiohomematic/model/custom/climate.py +7 -4
  24. aiohomematic/model/custom/const.py +1 -1
  25. aiohomematic/model/custom/cover.py +1 -1
  26. aiohomematic/model/custom/data_point.py +1 -1
  27. aiohomematic/model/custom/definition.py +1 -1
  28. aiohomematic/model/custom/light.py +1 -1
  29. aiohomematic/model/custom/lock.py +1 -1
  30. aiohomematic/model/custom/siren.py +1 -1
  31. aiohomematic/model/custom/support.py +1 -1
  32. aiohomematic/model/custom/switch.py +1 -1
  33. aiohomematic/model/custom/valve.py +1 -1
  34. aiohomematic/model/data_point.py +3 -2
  35. aiohomematic/model/device.py +10 -13
  36. aiohomematic/model/event.py +1 -1
  37. aiohomematic/model/generic/__init__.py +1 -1
  38. aiohomematic/model/generic/action.py +1 -1
  39. aiohomematic/model/generic/binary_sensor.py +1 -1
  40. aiohomematic/model/generic/button.py +1 -1
  41. aiohomematic/model/generic/data_point.py +1 -1
  42. aiohomematic/model/generic/number.py +1 -1
  43. aiohomematic/model/generic/select.py +1 -1
  44. aiohomematic/model/generic/sensor.py +1 -1
  45. aiohomematic/model/generic/switch.py +1 -1
  46. aiohomematic/model/generic/text.py +1 -1
  47. aiohomematic/model/hub/__init__.py +1 -1
  48. aiohomematic/model/hub/binary_sensor.py +1 -1
  49. aiohomematic/model/hub/button.py +1 -1
  50. aiohomematic/model/hub/data_point.py +1 -1
  51. aiohomematic/model/hub/number.py +1 -1
  52. aiohomematic/model/hub/select.py +1 -1
  53. aiohomematic/model/hub/sensor.py +1 -1
  54. aiohomematic/model/hub/switch.py +1 -1
  55. aiohomematic/model/hub/text.py +1 -1
  56. aiohomematic/model/support.py +1 -1
  57. aiohomematic/model/update.py +1 -1
  58. aiohomematic/property_decorators.py +2 -2
  59. aiohomematic/store/__init__.py +34 -0
  60. aiohomematic/{caches → store}/dynamic.py +4 -4
  61. aiohomematic/store/persistent.py +933 -0
  62. aiohomematic/{caches → store}/visibility.py +4 -4
  63. aiohomematic/support.py +20 -17
  64. aiohomematic/validator.py +1 -1
  65. {aiohomematic-2025.10.7.dist-info → aiohomematic-2025.10.9.dist-info}/METADATA +1 -1
  66. aiohomematic-2025.10.9.dist-info/RECORD +78 -0
  67. aiohomematic_support/client_local.py +2 -2
  68. aiohomematic/caches/__init__.py +0 -12
  69. aiohomematic/caches/persistent.py +0 -478
  70. aiohomematic-2025.10.7.dist-info/RECORD +0 -78
  71. {aiohomematic-2025.10.7.dist-info → aiohomematic-2025.10.9.dist-info}/WHEEL +0 -0
  72. {aiohomematic-2025.10.7.dist-info → aiohomematic-2025.10.9.dist-info}/licenses/LICENSE +0 -0
  73. {aiohomematic-2025.10.7.dist-info → aiohomematic-2025.10.9.dist-info}/top_level.txt +0 -0
aiohomematic/const.py CHANGED
@@ -1,5 +1,5 @@
1
1
  # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2021-2025 Daniel Perna, SukramJ
2
+ # Copyright (c) 2021-2025
3
3
  """
4
4
  Constants used by aiohomematic.
5
5
 
@@ -19,7 +19,7 @@ import sys
19
19
  from types import MappingProxyType
20
20
  from typing import Any, Final, NamedTuple, Required, TypeAlias, TypedDict
21
21
 
22
- VERSION: Final = "2025.10.7"
22
+ VERSION: Final = "2025.10.9"
23
23
 
24
24
  # Detect test speedup mode via environment
25
25
  _TEST_SPEEDUP: Final = (
@@ -27,7 +27,7 @@ _TEST_SPEEDUP: Final = (
27
27
  )
28
28
 
29
29
  # default
30
- DEFAULT_STORAGE_FOLDER: Final = "aiohomematic_storage"
30
+ DEFAULT_STORAGE_DIRECTORY: Final = "aiohomematic_storage"
31
31
  DEFAULT_CUSTOM_ID: Final = "custom_id"
32
32
  DEFAULT_DELAY_NEW_DEVICE_CREATION: Final = False
33
33
  DEFAULT_ENABLE_DEVICE_FIRMWARE_CHECK: Final = False
@@ -49,6 +49,12 @@ DEFAULT_UN_IGNORES: Final[frozenset[str]] = frozenset()
49
49
  DEFAULT_USE_GROUP_CHANNEL_FOR_COVER_STATE: Final = True
50
50
  DEFAULT_VERIFY_TLS: Final = False
51
51
 
52
+ MANU_TEMP_CUSTOM_ID: Final = "manu_temp"
53
+ INTERNAL_CUSTOM_IDS: Final[tuple[str, ...]] = (
54
+ DEFAULT_CUSTOM_ID,
55
+ MANU_TEMP_CUSTOM_ID,
56
+ )
57
+
52
58
  # Default encoding for json service calls, persistent cache
53
59
  UTF_8: Final = "utf-8"
54
60
  # Default encoding for xmlrpc service calls and script files
@@ -82,7 +88,7 @@ SYSVAR_ENABLE_DEFAULT: Final[frozenset[str]] = ALWAYS_ENABLE_SYSVARS_BY_ID
82
88
 
83
89
  ADDRESS_SEPARATOR: Final = ":"
84
90
  BLOCK_LOG_TIMEOUT: Final = 60
85
- CACHE_PATH: Final = "cache"
91
+ CONTENT_PATH: Final = "cache"
86
92
  CONF_PASSWORD: Final = "password"
87
93
  CONF_USERNAME: Final = "username"
88
94
 
@@ -94,8 +100,12 @@ DEVICE_FIRMWARE_CHECK_INTERVAL: Final = 21600 # 6h
94
100
  DEVICE_FIRMWARE_DELIVERING_CHECK_INTERVAL: Final = 3600 # 1h
95
101
  DEVICE_FIRMWARE_UPDATING_CHECK_INTERVAL: Final = 300 # 5m
96
102
  DUMMY_SERIAL: Final = "SN0815"
97
- FILE_DEVICES: Final = "homematic_devices.json"
98
- FILE_PARAMSETS: Final = "homematic_paramsets.json"
103
+ FILE_DEVICES: Final = "homematic_devices"
104
+ FILE_PARAMSETS: Final = "homematic_paramsets"
105
+ FILE_SESSION_RECORDER: Final = "homematic_session_recorder"
106
+ FILE_NAME_TS_PATTERN: Final = "%Y%m%d_%H%M%S"
107
+ SUB_DIRECTORY_CACHE: Final = "cache"
108
+ SUB_DIRECTORY_SESSION: Final = "session"
99
109
  HUB_PATH: Final = "hub"
100
110
  IDENTIFIER_SEPARATOR: Final = "@"
101
111
  INIT_DATETIME: Final = datetime.strptime("01.01.1970 00:00:00", DATETIME_FORMAT)
@@ -179,6 +189,8 @@ class CalulatedParameter(StrEnum):
179
189
 
180
190
  APPARENT_TEMPERATURE = "APPARENT_TEMPERATURE"
181
191
  DEW_POINT = "DEW_POINT"
192
+ DEW_POINT_SPREAD = "DEW_POINT_SPREAD"
193
+ ENTHALPY = "ENTHALPY"
182
194
  FROST_POINT = "FROST_POINT"
183
195
  OPERATING_VOLTAGE_LEVEL = "OPERATING_VOLTAGE_LEVEL"
184
196
  VAPOR_CONCENTRATION = "VAPOR_CONCENTRATION"
@@ -497,6 +509,13 @@ class RegaScript(StrEnum):
497
509
  SET_SYSTEM_VARIABLE: Final = "set_system_variable.fn"
498
510
 
499
511
 
512
+ class RPCType(StrEnum):
513
+ """Enum with Homematic rpc types."""
514
+
515
+ XML_RPC = "xmlrpc"
516
+ JSON_RPC = "jsonrpc"
517
+
518
+
500
519
  class Interface(StrEnum):
501
520
  """Enum with Homematic interfaces."""
502
521
 
aiohomematic/context.py CHANGED
@@ -1,5 +1,5 @@
1
1
  # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2021-2025 Daniel Perna, SukramJ
2
+ # Copyright (c) 2021-2025
3
3
  """
4
4
  Collection of context variables.
5
5
 
aiohomematic/converter.py CHANGED
@@ -1,5 +1,5 @@
1
1
  # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2021-2025 Daniel Perna, SukramJ
2
+ # Copyright (c) 2021-2025
3
3
  """
4
4
  Converters used by aiohomematic.
5
5
 
@@ -1,5 +1,5 @@
1
1
  # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2021-2025 Daniel Perna, SukramJ
2
+ # Copyright (c) 2021-2025
3
3
  """
4
4
  Common Decorators used within aiohomematic.
5
5
 
@@ -1,5 +1,5 @@
1
1
  # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2021-2025 Daniel Perna, SukramJ
2
+ # Copyright (c) 2021-2025
3
3
  """
4
4
  Module for AioHomematicExceptions.
5
5
 
aiohomematic/hmcli.py CHANGED
@@ -1,5 +1,5 @@
1
1
  # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2021-2025 Daniel Perna, SukramJ
2
+ # Copyright (c) 2021-2025
3
3
  #!/usr/bin/python3
4
4
  """
5
5
  Commandline tool to query Homematic hubs via XML-RPC.
@@ -1,5 +1,5 @@
1
1
  # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2021-2025 Daniel Perna, SukramJ
2
+ # Copyright (c) 2021-2025
3
3
  """
4
4
  Data point and event model for AioHomematic.
5
5
 
@@ -1,5 +1,5 @@
1
1
  # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2021-2025 Daniel Perna, SukramJ
2
+ # Copyright (c) 2021-2025
3
3
  """
4
4
  Calculated (derived) data points for AioHomematic.
5
5
 
@@ -24,7 +24,7 @@ Factory:
24
24
  normal read-only data points.
25
25
 
26
26
  Modules/classes:
27
- - ApparentTemperature, DewPoint, FrostPoint, VaporConcentration: Climate-related
27
+ - ApparentTemperature, DewPoint, DewPointSpread, Enthalphy, FrostPoint, VaporConcentration: Climate-related
28
28
  sensors implemented in climate.py using well-known formulas (see
29
29
  aiohomematic.model.calculated.support for details and references).
30
30
  - OperatingVoltageLevel: Interprets battery/voltage values and exposes a human
@@ -41,7 +41,14 @@ from typing import Final
41
41
 
42
42
  from aiohomematic.decorators import inspector
43
43
  from aiohomematic.model import device as hmd
44
- from aiohomematic.model.calculated.climate import ApparentTemperature, DewPoint, FrostPoint, VaporConcentration
44
+ from aiohomematic.model.calculated.climate import (
45
+ ApparentTemperature,
46
+ DewPoint,
47
+ DewPointSpread,
48
+ Enthalpy,
49
+ FrostPoint,
50
+ VaporConcentration,
51
+ )
45
52
  from aiohomematic.model.calculated.data_point import CalculatedDataPoint
46
53
  from aiohomematic.model.calculated.operating_voltage_level import OperatingVoltageLevel
47
54
 
@@ -49,13 +56,23 @@ __all__ = [
49
56
  "ApparentTemperature",
50
57
  "CalculatedDataPoint",
51
58
  "DewPoint",
59
+ "DewPointSpread",
60
+ "Enthalpy",
52
61
  "FrostPoint",
53
62
  "OperatingVoltageLevel",
54
63
  "VaporConcentration",
55
64
  "create_calculated_data_points",
56
65
  ]
57
66
 
58
- _CALCULATED_DATA_POINTS: Final = (ApparentTemperature, DewPoint, FrostPoint, OperatingVoltageLevel, VaporConcentration)
67
+ _CALCULATED_DATA_POINTS: Final = (
68
+ ApparentTemperature,
69
+ DewPoint,
70
+ DewPointSpread,
71
+ Enthalpy,
72
+ FrostPoint,
73
+ OperatingVoltageLevel,
74
+ VaporConcentration,
75
+ )
59
76
  _LOGGER: Final = logging.getLogger(__name__)
60
77
 
61
78
 
@@ -1,5 +1,5 @@
1
1
  # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2021-2025 Daniel Perna, SukramJ
2
+ # Copyright (c) 2021-2025
3
3
  """Module for calculating the apparent temperature in the sensor category."""
4
4
 
5
5
  from __future__ import annotations
@@ -13,6 +13,8 @@ from aiohomematic.model.calculated.data_point import CalculatedDataPoint
13
13
  from aiohomematic.model.calculated.support import (
14
14
  calculate_apparent_temperature,
15
15
  calculate_dew_point,
16
+ calculate_dew_point_spread,
17
+ calculate_enthalpy,
16
18
  calculate_frost_point,
17
19
  calculate_vapor_concentration,
18
20
  )
@@ -141,6 +143,62 @@ class DewPoint(BaseClimateSensor):
141
143
  return None
142
144
 
143
145
 
146
+ class DewPointSpread(BaseClimateSensor):
147
+ """Implementation of a calculated sensor for dew point spread."""
148
+
149
+ __slots__ = ()
150
+
151
+ _calculated_parameter = CalulatedParameter.DEW_POINT_SPREAD
152
+
153
+ def __init__(self, *, channel: hmd.Channel) -> None:
154
+ """Initialize the data point."""
155
+ super().__init__(channel=channel)
156
+ self._unit = "K"
157
+
158
+ @staticmethod
159
+ def is_relevant_for_model(*, channel: hmd.Channel) -> bool:
160
+ """Return if this calculated data point is relevant for the model."""
161
+ return _is_relevant_for_model_temperature_and_humidity(channel=channel)
162
+
163
+ @state_property
164
+ def value(self) -> float | None:
165
+ """Return the value."""
166
+ if self._dp_temperature.value is not None and self._dp_humidity.value is not None:
167
+ return calculate_dew_point_spread(
168
+ temperature=self._dp_temperature.value,
169
+ humidity=self._dp_humidity.value,
170
+ )
171
+ return None
172
+
173
+
174
+ class Enthalpy(BaseClimateSensor):
175
+ """Implementation of a calculated sensor for enthalpy."""
176
+
177
+ __slots__ = ()
178
+
179
+ _calculated_parameter = CalulatedParameter.ENTHALPY
180
+
181
+ def __init__(self, *, channel: hmd.Channel) -> None:
182
+ """Initialize the data point."""
183
+ super().__init__(channel=channel)
184
+ self._unit = "kJ/kg"
185
+
186
+ @staticmethod
187
+ def is_relevant_for_model(*, channel: hmd.Channel) -> bool:
188
+ """Return if this calculated data point is relevant for the model."""
189
+ return _is_relevant_for_model_temperature_and_humidity(channel=channel)
190
+
191
+ @state_property
192
+ def value(self) -> float | None:
193
+ """Return the value."""
194
+ if self._dp_temperature.value is not None and self._dp_humidity.value is not None:
195
+ return calculate_enthalpy(
196
+ temperature=self._dp_temperature.value,
197
+ humidity=self._dp_humidity.value,
198
+ )
199
+ return None
200
+
201
+
144
202
  class FrostPoint(BaseClimateSensor):
145
203
  """Implementation of a calculated sensor for frost point."""
146
204
 
@@ -1,5 +1,5 @@
1
1
  # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2021-2025 Daniel Perna, SukramJ
2
+ # Copyright (c) 2021-2025
3
3
  """Module with base class for calculated data points."""
4
4
 
5
5
  from __future__ import annotations
@@ -1,5 +1,5 @@
1
1
  # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2021-2025 Daniel Perna, SukramJ
2
+ # Copyright (c) 2021-2025
3
3
  """Module for calculating the operating voltage level in the sensor category."""
4
4
 
5
5
  from __future__ import annotations
@@ -1,5 +1,5 @@
1
1
  # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2021-2025 Daniel Perna, SukramJ
2
+ # Copyright (c) 2021-2025
3
3
  """
4
4
  A number of functions used to calculate values based on existing data.
5
5
 
@@ -16,9 +16,47 @@ from typing import Final
16
16
 
17
17
  from aiohomematic.support import extract_exc_args
18
18
 
19
+ _DEFAULT_PRESSURE_HPA: Final = 1013.25
19
20
  _LOGGER: Final = logging.getLogger(__name__)
20
21
 
21
22
 
23
+ def calculate_dew_point_spread(*, temperature: float, humidity: int) -> float | None:
24
+ """
25
+ Calculate the dew point spread.
26
+
27
+ Dew point spread = Difference between current air temperature and dew point.
28
+ Specifies the safety margin against condensation(K).
29
+ """
30
+ if dew_point := calculate_dew_point(temperature=temperature, humidity=humidity):
31
+ return round(temperature - dew_point, 2)
32
+ return None
33
+
34
+
35
+ def calculate_enthalpy(
36
+ *, temperature: float, humidity: int, pressure_hPa: float = _DEFAULT_PRESSURE_HPA
37
+ ) -> float | None:
38
+ """
39
+ Calculate the enthalpy based on temperature and humidity.
40
+
41
+ Calculates the specific enthalpy of humid air in kJ/kg (relative to dry air).
42
+ temperature: Air temperature in °C
43
+ humidity: Relative humidity in %
44
+ pressure_hPa: Air pressure (default: 1013.25 hPa)
45
+
46
+ """
47
+
48
+ # Saturation vapor pressure according to Magnus in hPa
49
+ e_s = 6.112 * math.exp((17.62 * temperature) / (243.12 + temperature))
50
+ e = humidity / 100.0 * e_s # aktueller Dampfdruck in hPa
51
+
52
+ # Mixing ratio (g water / kg dry air)
53
+ r = 622 * e / (pressure_hPa - e)
54
+
55
+ # Specific enthalpy (kJ/kg dry air)
56
+ h = 1.006 * temperature + r * (2501 + 1.86 * temperature) / 1000 # in kJ/kg
57
+ return round(h, 2)
58
+
59
+
22
60
  def _calculate_heat_index(*, temperature: float, humidity: int) -> float:
23
61
  """
24
62
  Calculate the Heat Index (feels like temperature) based on the NOAA equation.
@@ -158,10 +196,10 @@ def calculate_dew_point(*, temperature: float, humidity: int) -> float | None:
158
196
  def calculate_frost_point(*, temperature: float, humidity: int) -> float | None:
159
197
  """Calculate the frost point."""
160
198
  try:
161
- if (dewpoint := calculate_dew_point(temperature=temperature, humidity=humidity)) is None:
199
+ if (dew_point := calculate_dew_point(temperature=temperature, humidity=humidity)) is None:
162
200
  return None
163
201
  t = temperature + 273.15
164
- td = dewpoint + 273.15
202
+ td = dew_point + 273.15
165
203
 
166
204
  return round((td + (2671.02 / ((2954.61 / t) + 2.193665 * math.log(t) - 13.3448)) - t) - 273.15, 1)
167
205
  except ValueError as verr:
@@ -1,5 +1,5 @@
1
1
  # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2021-2025 Daniel Perna, SukramJ
2
+ # Copyright (c) 2021-2025
3
3
  """
4
4
  Custom data points for AioHomematic.
5
5
 
@@ -1,5 +1,5 @@
1
1
  # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2021-2025 Daniel Perna, SukramJ
2
+ # Copyright (c) 2021-2025
3
3
  """Module for data points implemented using the climate category."""
4
4
 
5
5
  from __future__ import annotations
@@ -12,6 +12,7 @@ import logging
12
12
  from typing import Any, Final, cast
13
13
 
14
14
  from aiohomematic.const import (
15
+ MANU_TEMP_CUSTOM_ID,
15
16
  SCHEDULER_PROFILE_PATTERN,
16
17
  SCHEDULER_TIME_PATTERN,
17
18
  DataPointCategory,
@@ -233,7 +234,9 @@ class BaseCustomDpClimate(CustomDataPoint):
233
234
  field=Field.TEMPERATURE_MINIMUM, data_point_type=DpFloat
234
235
  )
235
236
  self._unregister_callbacks.append(
236
- self._dp_setpoint.register_data_point_updated_callback(cb=self._manu_temp_changed, custom_id="manu_temp")
237
+ self._dp_setpoint.register_data_point_updated_callback(
238
+ cb=self._manu_temp_changed, custom_id=MANU_TEMP_CUSTOM_ID
239
+ )
237
240
  )
238
241
 
239
242
  @abstractmethod
@@ -799,7 +802,7 @@ class CustomDpRfThermostat(BaseCustomDpClimate):
799
802
 
800
803
  self._unregister_callbacks.append(
801
804
  self._dp_control_mode.register_data_point_updated_callback(
802
- cb=self._manu_temp_changed, custom_id="manu_temp"
805
+ cb=self._manu_temp_changed, custom_id=MANU_TEMP_CUSTOM_ID
803
806
  )
804
807
  )
805
808
 
@@ -1044,7 +1047,7 @@ class CustomDpIpThermostat(BaseCustomDpClimate):
1044
1047
 
1045
1048
  self._unregister_callbacks.append(
1046
1049
  self._dp_set_point_mode.register_data_point_updated_callback(
1047
- cb=self._manu_temp_changed, custom_id="manu_temp"
1050
+ cb=self._manu_temp_changed, custom_id=MANU_TEMP_CUSTOM_ID
1048
1051
  )
1049
1052
  )
1050
1053
 
@@ -1,5 +1,5 @@
1
1
  # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2021-2025 Daniel Perna, SukramJ
2
+ # Copyright (c) 2021-2025
3
3
  """Constants used by aiohomematic custom data points."""
4
4
 
5
5
  from __future__ import annotations
@@ -1,5 +1,5 @@
1
1
  # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2021-2025 Daniel Perna, SukramJ
2
+ # Copyright (c) 2021-2025
3
3
  """Module for data points implemented using the cover category."""
4
4
 
5
5
  from __future__ import annotations
@@ -1,5 +1,5 @@
1
1
  # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2021-2025 Daniel Perna, SukramJ
2
+ # Copyright (c) 2021-2025
3
3
  """Module with base class for custom data points."""
4
4
 
5
5
  from __future__ import annotations
@@ -1,5 +1,5 @@
1
1
  # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2021-2025 Daniel Perna, SukramJ
2
+ # Copyright (c) 2021-2025
3
3
  """The module contains device descriptions for custom data points."""
4
4
 
5
5
  from __future__ import annotations
@@ -1,5 +1,5 @@
1
1
  # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2021-2025 Daniel Perna, SukramJ
2
+ # Copyright (c) 2021-2025
3
3
  """Module for data points implemented using the light category."""
4
4
 
5
5
  from __future__ import annotations
@@ -1,5 +1,5 @@
1
1
  # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2021-2025 Daniel Perna, SukramJ
2
+ # Copyright (c) 2021-2025
3
3
  """Module for data points implemented using the lock category."""
4
4
 
5
5
  from __future__ import annotations
@@ -1,5 +1,5 @@
1
1
  # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2021-2025 Daniel Perna, SukramJ
2
+ # Copyright (c) 2021-2025
3
3
  """Module for data points implemented using the siren category."""
4
4
 
5
5
  from __future__ import annotations
@@ -1,5 +1,5 @@
1
1
  # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2021-2025 Daniel Perna, SukramJ
2
+ # Copyright (c) 2021-2025
3
3
  """Support classes used by aiohomematic custom data points."""
4
4
 
5
5
  from __future__ import annotations
@@ -1,5 +1,5 @@
1
1
  # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2021-2025 Daniel Perna, SukramJ
2
+ # Copyright (c) 2021-2025
3
3
  """Module for data points implemented using the switch category."""
4
4
 
5
5
  from __future__ import annotations
@@ -1,5 +1,5 @@
1
1
  # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2021-2025 Daniel Perna, SukramJ
2
+ # Copyright (c) 2021-2025
3
3
  """Module for data points implemented using the valve category."""
4
4
 
5
5
  from __future__ import annotations
@@ -1,5 +1,5 @@
1
1
  # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2021-2025 Daniel Perna, SukramJ
2
+ # Copyright (c) 2021-2025
3
3
  """
4
4
  Core data point model for AioHomematic.
5
5
 
@@ -43,6 +43,7 @@ from aiohomematic.const import (
43
43
  DEFAULT_MULTIPLIER,
44
44
  DP_KEY_VALUE,
45
45
  INIT_DATETIME,
46
+ INTERNAL_CUSTOM_IDS,
46
47
  KEY_CHANNEL_OPERATION_MODE_VISIBILITY,
47
48
  KWARGS_ARG_CUSTOM_ID,
48
49
  KWARGS_ARG_DATA_POINT,
@@ -312,7 +313,7 @@ class CallbackDataPoint(ABC, LogContextMixin):
312
313
 
313
314
  def register_data_point_updated_callback(self, *, cb: Callable, custom_id: str) -> CALLBACK_TYPE:
314
315
  """Register data_point updated callback."""
315
- if custom_id != DEFAULT_CUSTOM_ID:
316
+ if custom_id not in INTERNAL_CUSTOM_IDS:
316
317
  if self._custom_id is not None and self._custom_id != custom_id:
317
318
  raise AioHomematicException(
318
319
  f"REGISTER_data_point_updated_CALLBACK failed: hm_data_point: {self.full_name} is already registered by {self._custom_id}"
@@ -1,5 +1,5 @@
1
1
  # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2021-2025 Daniel Perna, SukramJ
2
+ # Copyright (c) 2021-2025
3
3
  """
4
4
  Device and channel model for AioHomematic.
5
5
 
@@ -671,7 +671,7 @@ class Device(LogContextMixin, PayloadMixin):
671
671
  channel_address=channel_address,
672
672
  paramset_key=paramset_key,
673
673
  )
674
- await self._central.save_caches(save_paramset_descriptions=True)
674
+ await self._central.save_files(save_paramset_descriptions=True)
675
675
  for dp in self.generic_data_points:
676
676
  dp.update_parameter_data()
677
677
  self.fire_device_updated_callback()
@@ -1240,7 +1240,7 @@ class _ValueCache:
1240
1240
  *,
1241
1241
  dpk: DataPointKey,
1242
1242
  ) -> Any:
1243
- """Load data from caches."""
1243
+ """Load data from store."""
1244
1244
  # Try to get data from central cache
1245
1245
  if (
1246
1246
  dpk.paramset_key == ParamsetKey.VALUES
@@ -1269,14 +1269,14 @@ class _DefinitionExporter:
1269
1269
  "_device_address",
1270
1270
  "_interface_id",
1271
1271
  "_random_id",
1272
- "_storage_folder",
1272
+ "_storage_directory",
1273
1273
  )
1274
1274
 
1275
1275
  def __init__(self, *, device: Device) -> None:
1276
1276
  """Init the device exporter."""
1277
1277
  self._client: Final = device.client
1278
1278
  self._central: Final = device.client.central
1279
- self._storage_folder: Final = self._central.config.storage_folder
1279
+ self._storage_directory: Final = self._central.config.storage_directory
1280
1280
  self._interface_id: Final = device.interface_id
1281
1281
  self._device_address: Final = device.address
1282
1282
  self._random_id: Final[str] = f"VCU{int(random.randint(1000000, 9999999))}"
@@ -1315,14 +1315,14 @@ class _DefinitionExporter:
1315
1315
 
1316
1316
  # Save device_descriptions for device to file.
1317
1317
  await self._save(
1318
- file_dir=f"{self._storage_folder}/{DEVICE_DESCRIPTIONS_DIR}",
1318
+ directory=f"{self._storage_directory}/{DEVICE_DESCRIPTIONS_DIR}",
1319
1319
  filename=filename,
1320
1320
  data=anonymize_device_descriptions,
1321
1321
  )
1322
1322
 
1323
1323
  # Save device_descriptions for device to file.
1324
1324
  await self._save(
1325
- file_dir=f"{self._storage_folder}/{PARAMSET_DESCRIPTIONS_DIR}",
1325
+ directory=f"{self._storage_directory}/{PARAMSET_DESCRIPTIONS_DIR}",
1326
1326
  filename=filename,
1327
1327
  data=anonymize_paramset_descriptions,
1328
1328
  )
@@ -1332,16 +1332,13 @@ class _DefinitionExporter:
1332
1332
  address_parts[0] = self._random_id
1333
1333
  return ADDRESS_SEPARATOR.join(address_parts)
1334
1334
 
1335
- async def _save(self, *, file_dir: str, filename: str, data: Any) -> DataOperationResult:
1335
+ async def _save(self, *, directory: str, filename: str, data: Any) -> DataOperationResult:
1336
1336
  """Save file to disk."""
1337
1337
 
1338
1338
  def perform_save() -> DataOperationResult:
1339
- if not check_or_create_directory(directory=file_dir):
1339
+ if not check_or_create_directory(directory=directory):
1340
1340
  return DataOperationResult.NO_SAVE # pragma: no cover
1341
- with open(
1342
- file=os.path.join(file_dir, filename),
1343
- mode="wb",
1344
- ) as fptr:
1341
+ with open(file=os.path.join(directory, filename), mode="wb") as fptr:
1345
1342
  fptr.write(orjson.dumps(data, option=orjson.OPT_INDENT_2 | orjson.OPT_NON_STR_KEYS))
1346
1343
  return DataOperationResult.SAVE_SUCCESS
1347
1344
 
@@ -1,5 +1,5 @@
1
1
  # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2021-2025 Daniel Perna, SukramJ
2
+ # Copyright (c) 2021-2025
3
3
  """
4
4
  Event model for AioHomematic.
5
5
 
@@ -1,5 +1,5 @@
1
1
  # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2021-2025 Daniel Perna, SukramJ
2
+ # Copyright (c) 2021-2025
3
3
  """
4
4
  Generic data points for AioHomematic.
5
5
 
@@ -1,5 +1,5 @@
1
1
  # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2021-2025 Daniel Perna, SukramJ
2
+ # Copyright (c) 2021-2025
3
3
  """
4
4
  Module for action data points.
5
5
 
@@ -1,5 +1,5 @@
1
1
  # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2021-2025 Daniel Perna, SukramJ
2
+ # Copyright (c) 2021-2025
3
3
  """Module for data points implemented using the binary_sensor category."""
4
4
 
5
5
  from __future__ import annotations
@@ -1,5 +1,5 @@
1
1
  # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2021-2025 Daniel Perna, SukramJ
2
+ # Copyright (c) 2021-2025
3
3
  """Module for data points implemented using the button category."""
4
4
 
5
5
  from __future__ import annotations
@@ -1,5 +1,5 @@
1
1
  # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2021-2025 Daniel Perna, SukramJ
2
+ # Copyright (c) 2021-2025
3
3
  """Generic python representation of a backend parameter."""
4
4
 
5
5
  from __future__ import annotations
@@ -1,5 +1,5 @@
1
1
  # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2021-2025 Daniel Perna, SukramJ
2
+ # Copyright (c) 2021-2025
3
3
  """Module for data points implemented using the number category."""
4
4
 
5
5
  from __future__ import annotations
@@ -1,5 +1,5 @@
1
1
  # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2021-2025 Daniel Perna, SukramJ
2
+ # Copyright (c) 2021-2025
3
3
  """Module for data points implemented using the select category."""
4
4
 
5
5
  from __future__ import annotations
@@ -1,5 +1,5 @@
1
1
  # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2021-2025 Daniel Perna, SukramJ
2
+ # Copyright (c) 2021-2025
3
3
  """Module for data points implemented using the sensor category."""
4
4
 
5
5
  from __future__ import annotations