aiohomematic 2025.8.8__py3-none-any.whl → 2025.8.10__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 (71) hide show
  1. aiohomematic/__init__.py +15 -1
  2. aiohomematic/async_support.py +15 -2
  3. aiohomematic/caches/__init__.py +2 -0
  4. aiohomematic/caches/dynamic.py +2 -0
  5. aiohomematic/caches/persistent.py +29 -22
  6. aiohomematic/caches/visibility.py +277 -252
  7. aiohomematic/central/__init__.py +69 -49
  8. aiohomematic/central/decorators.py +60 -15
  9. aiohomematic/central/xml_rpc_server.py +15 -1
  10. aiohomematic/client/__init__.py +2 -0
  11. aiohomematic/client/_rpc_errors.py +81 -0
  12. aiohomematic/client/json_rpc.py +68 -19
  13. aiohomematic/client/xml_rpc.py +15 -8
  14. aiohomematic/const.py +145 -77
  15. aiohomematic/context.py +11 -1
  16. aiohomematic/converter.py +27 -1
  17. aiohomematic/decorators.py +88 -19
  18. aiohomematic/exceptions.py +19 -1
  19. aiohomematic/hmcli.py +13 -1
  20. aiohomematic/model/__init__.py +2 -0
  21. aiohomematic/model/calculated/__init__.py +2 -0
  22. aiohomematic/model/calculated/climate.py +2 -0
  23. aiohomematic/model/calculated/data_point.py +7 -1
  24. aiohomematic/model/calculated/operating_voltage_level.py +2 -0
  25. aiohomematic/model/calculated/support.py +2 -0
  26. aiohomematic/model/custom/__init__.py +2 -0
  27. aiohomematic/model/custom/climate.py +3 -1
  28. aiohomematic/model/custom/const.py +2 -0
  29. aiohomematic/model/custom/cover.py +30 -2
  30. aiohomematic/model/custom/data_point.py +6 -0
  31. aiohomematic/model/custom/definition.py +2 -0
  32. aiohomematic/model/custom/light.py +18 -10
  33. aiohomematic/model/custom/lock.py +2 -0
  34. aiohomematic/model/custom/siren.py +5 -2
  35. aiohomematic/model/custom/support.py +2 -0
  36. aiohomematic/model/custom/switch.py +2 -0
  37. aiohomematic/model/custom/valve.py +2 -0
  38. aiohomematic/model/data_point.py +30 -3
  39. aiohomematic/model/decorators.py +29 -8
  40. aiohomematic/model/device.py +9 -5
  41. aiohomematic/model/event.py +2 -0
  42. aiohomematic/model/generic/__init__.py +2 -0
  43. aiohomematic/model/generic/action.py +2 -0
  44. aiohomematic/model/generic/binary_sensor.py +2 -0
  45. aiohomematic/model/generic/button.py +2 -0
  46. aiohomematic/model/generic/data_point.py +4 -1
  47. aiohomematic/model/generic/number.py +4 -1
  48. aiohomematic/model/generic/select.py +4 -1
  49. aiohomematic/model/generic/sensor.py +2 -0
  50. aiohomematic/model/generic/switch.py +2 -0
  51. aiohomematic/model/generic/text.py +2 -0
  52. aiohomematic/model/hub/__init__.py +2 -0
  53. aiohomematic/model/hub/binary_sensor.py +2 -0
  54. aiohomematic/model/hub/button.py +2 -0
  55. aiohomematic/model/hub/data_point.py +6 -0
  56. aiohomematic/model/hub/number.py +2 -0
  57. aiohomematic/model/hub/select.py +2 -0
  58. aiohomematic/model/hub/sensor.py +2 -0
  59. aiohomematic/model/hub/switch.py +2 -0
  60. aiohomematic/model/hub/text.py +2 -0
  61. aiohomematic/model/support.py +26 -1
  62. aiohomematic/model/update.py +6 -0
  63. aiohomematic/support.py +175 -5
  64. aiohomematic/validator.py +49 -2
  65. aiohomematic-2025.8.10.dist-info/METADATA +124 -0
  66. aiohomematic-2025.8.10.dist-info/RECORD +78 -0
  67. {aiohomematic-2025.8.8.dist-info → aiohomematic-2025.8.10.dist-info}/licenses/LICENSE +1 -1
  68. aiohomematic-2025.8.8.dist-info/METADATA +0 -69
  69. aiohomematic-2025.8.8.dist-info/RECORD +0 -77
  70. {aiohomematic-2025.8.8.dist-info → aiohomematic-2025.8.10.dist-info}/WHEEL +0 -0
  71. {aiohomematic-2025.8.8.dist-info → aiohomematic-2025.8.10.dist-info}/top_level.txt +0 -0
@@ -1,3 +1,5 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2021-2025 Daniel Perna, SukramJ
1
3
  """
2
4
  Parameter visibility rules and cache for HomeMatic data points.
3
5
 
@@ -30,11 +32,11 @@ available on the CentralUnit and model descriptors.
30
32
  from __future__ import annotations
31
33
 
32
34
  from collections import defaultdict
33
- from collections.abc import Mapping
35
+ from collections.abc import Iterable, Mapping
34
36
  from functools import cache
35
37
  import logging
36
38
  import re
37
- from typing import Final
39
+ from typing import Final, TypeAlias
38
40
 
39
41
  from aiohomematic import central as hmcu, support as hms
40
42
  from aiohomematic.const import ADDRESS_SEPARATOR, CLICK_EVENTS, UN_IGNORE_WILDCARD, Parameter, ParamsetKey
@@ -43,7 +45,12 @@ from aiohomematic.model.custom import get_required_parameters
43
45
  from aiohomematic.support import element_matches_key
44
46
 
45
47
  _LOGGER: Final = logging.getLogger(__name__)
46
- _CACHE_KEY_TYPE = tuple[str, int, ParamsetKey, str]
48
+
49
+ # Readability type aliases for internal cache structures
50
+ TModelName: TypeAlias = str
51
+ TChannelNo: TypeAlias = int | None
52
+ TUnIgnoreChannelNo: TypeAlias = TChannelNo | str
53
+ TParameterName: TypeAlias = str
47
54
 
48
55
  # Define which additional parameters from MASTER paramset should be created as data_point.
49
56
  # By default these are also on the _HIDDEN_PARAMETERS, which prevents these data points
@@ -51,172 +58,174 @@ _CACHE_KEY_TYPE = tuple[str, int, ParamsetKey, str]
51
58
  # and not for general display.
52
59
  # {model: (channel_no, parameter)}
53
60
 
54
- _RELEVANT_MASTER_PARAMSETS_BY_CHANNEL: Final[Mapping[int | str | None, tuple[Parameter, ...]]] = {
55
- None: (Parameter.GLOBAL_BUTTON_LOCK, Parameter.LOW_BAT_LIMIT),
56
- 0: (Parameter.GLOBAL_BUTTON_LOCK, Parameter.LOW_BAT_LIMIT),
61
+ _RELEVANT_MASTER_PARAMSETS_BY_CHANNEL: Final[Mapping[TChannelNo, frozenset[Parameter]]] = {
62
+ None: frozenset({Parameter.GLOBAL_BUTTON_LOCK, Parameter.LOW_BAT_LIMIT}),
63
+ 0: frozenset({Parameter.GLOBAL_BUTTON_LOCK, Parameter.LOW_BAT_LIMIT}),
57
64
  }
58
65
 
59
- _CLIMATE_MASTER_PARAMETERS: Final[tuple[Parameter, ...]] = (
60
- Parameter.HEATING_VALVE_TYPE,
61
- Parameter.MIN_MAX_VALUE_NOT_RELEVANT_FOR_MANU_MODE,
62
- Parameter.OPTIMUM_START_STOP,
63
- Parameter.TEMPERATURE_MAXIMUM,
64
- Parameter.TEMPERATURE_MINIMUM,
65
- Parameter.TEMPERATURE_OFFSET,
66
- Parameter.WEEK_PROGRAM_POINTER,
66
+ _CLIMATE_MASTER_PARAMETERS: Final[frozenset[Parameter]] = frozenset(
67
+ {
68
+ Parameter.HEATING_VALVE_TYPE,
69
+ Parameter.MIN_MAX_VALUE_NOT_RELEVANT_FOR_MANU_MODE,
70
+ Parameter.OPTIMUM_START_STOP,
71
+ Parameter.TEMPERATURE_MAXIMUM,
72
+ Parameter.TEMPERATURE_MINIMUM,
73
+ Parameter.TEMPERATURE_OFFSET,
74
+ Parameter.WEEK_PROGRAM_POINTER,
75
+ }
67
76
  )
68
77
 
69
- _RELEVANT_MASTER_PARAMSETS_BY_DEVICE: Final[Mapping[str, tuple[tuple[int | None, ...], tuple[Parameter, ...]]]] = {
70
- "ALPHA-IP-RBG": ((1,), _CLIMATE_MASTER_PARAMETERS),
71
- "ELV-SH-TACO": ((2,), (Parameter.CHANNEL_OPERATION_MODE,)),
78
+ _RELEVANT_MASTER_PARAMSETS_BY_DEVICE: Final[Mapping[TModelName, tuple[frozenset[TChannelNo], frozenset[Parameter]]]] = {
79
+ "ALPHA-IP-RBG": (frozenset({1}), _CLIMATE_MASTER_PARAMETERS),
80
+ "ELV-SH-TACO": (frozenset({2}), frozenset({Parameter.CHANNEL_OPERATION_MODE})),
72
81
  "HM-CC-RT-DN": (
73
- (None,),
82
+ frozenset({None}),
74
83
  _CLIMATE_MASTER_PARAMETERS,
75
84
  ),
76
85
  "HM-CC-VG-1": (
77
- (None,),
86
+ frozenset({None}),
78
87
  _CLIMATE_MASTER_PARAMETERS,
79
88
  ),
80
89
  "HM-TC-IT-WM-W-EU": (
81
- (None,),
90
+ frozenset({None}),
82
91
  _CLIMATE_MASTER_PARAMETERS,
83
92
  ),
84
- "HmIP-BWTH": ((1, 8), _CLIMATE_MASTER_PARAMETERS),
93
+ "HmIP-BWTH": (frozenset({1, 8}), _CLIMATE_MASTER_PARAMETERS),
85
94
  "HmIP-DRBLI4": (
86
- (1, 2, 3, 4, 5, 6, 7, 8, 9, 13, 17, 21),
87
- (Parameter.CHANNEL_OPERATION_MODE,),
95
+ frozenset({1, 2, 3, 4, 5, 6, 7, 8, 9, 13, 17, 21}),
96
+ frozenset({Parameter.CHANNEL_OPERATION_MODE}),
88
97
  ),
89
- "HmIP-DRDI3": ((1, 2, 3), (Parameter.CHANNEL_OPERATION_MODE,)),
90
- "HmIP-DRSI1": ((1,), (Parameter.CHANNEL_OPERATION_MODE,)),
91
- "HmIP-DRSI4": ((1, 2, 3, 4), (Parameter.CHANNEL_OPERATION_MODE,)),
92
- "HmIP-DSD-PCB": ((1,), (Parameter.CHANNEL_OPERATION_MODE,)),
93
- "HmIP-FCI1": ((1,), (Parameter.CHANNEL_OPERATION_MODE,)),
94
- "HmIP-FCI6": (tuple(range(1, 7)), (Parameter.CHANNEL_OPERATION_MODE,)),
95
- "HmIP-FSI16": ((1,), (Parameter.CHANNEL_OPERATION_MODE,)),
96
- "HmIP-HEATING": ((1,), _CLIMATE_MASTER_PARAMETERS),
97
- "HmIP-MIO16-PCB": ((13, 14, 15, 16), (Parameter.CHANNEL_OPERATION_MODE,)),
98
- "HmIP-MOD-RC8": (tuple(range(1, 9)), (Parameter.CHANNEL_OPERATION_MODE,)),
99
- "HmIP-RGBW": ((0,), (Parameter.DEVICE_OPERATION_MODE,)),
100
- "HmIP-STH": ((1,), _CLIMATE_MASTER_PARAMETERS),
101
- "HmIP-WGT": ((8, 14), _CLIMATE_MASTER_PARAMETERS),
102
- "HmIP-WTH": ((1,), _CLIMATE_MASTER_PARAMETERS),
103
- "HmIP-eTRV": ((1,), _CLIMATE_MASTER_PARAMETERS),
104
- "HmIPW-DRBL4": ((1, 5, 9, 13), (Parameter.CHANNEL_OPERATION_MODE,)),
105
- "HmIPW-DRI16": (tuple(range(1, 17)), (Parameter.CHANNEL_OPERATION_MODE,)),
106
- "HmIPW-DRI32": (tuple(range(1, 33)), (Parameter.CHANNEL_OPERATION_MODE,)),
107
- "HmIPW-FIO6": (tuple(range(1, 7)), (Parameter.CHANNEL_OPERATION_MODE,)),
108
- "HmIPW-STH": ((1,), _CLIMATE_MASTER_PARAMETERS),
98
+ "HmIP-DRDI3": (frozenset({1, 2, 3}), frozenset({Parameter.CHANNEL_OPERATION_MODE})),
99
+ "HmIP-DRSI1": (frozenset({1}), frozenset({Parameter.CHANNEL_OPERATION_MODE})),
100
+ "HmIP-DRSI4": (frozenset({1, 2, 3, 4}), frozenset({Parameter.CHANNEL_OPERATION_MODE})),
101
+ "HmIP-DSD-PCB": (frozenset({1}), frozenset({Parameter.CHANNEL_OPERATION_MODE})),
102
+ "HmIP-FCI1": (frozenset({1}), frozenset({Parameter.CHANNEL_OPERATION_MODE})),
103
+ "HmIP-FCI6": (frozenset(range(1, 7)), frozenset({Parameter.CHANNEL_OPERATION_MODE})),
104
+ "HmIP-FSI16": (frozenset({1}), frozenset({Parameter.CHANNEL_OPERATION_MODE})),
105
+ "HmIP-HEATING": (frozenset({1}), _CLIMATE_MASTER_PARAMETERS),
106
+ "HmIP-MIO16-PCB": (frozenset({13, 14, 15, 16}), frozenset({Parameter.CHANNEL_OPERATION_MODE})),
107
+ "HmIP-MOD-RC8": (frozenset(range(1, 9)), frozenset({Parameter.CHANNEL_OPERATION_MODE})),
108
+ "HmIP-RGBW": (frozenset({0}), frozenset({Parameter.DEVICE_OPERATION_MODE})),
109
+ "HmIP-STH": (frozenset({1}), _CLIMATE_MASTER_PARAMETERS),
110
+ "HmIP-WGT": (frozenset({8, 14}), _CLIMATE_MASTER_PARAMETERS),
111
+ "HmIP-WTH": (frozenset({1}), _CLIMATE_MASTER_PARAMETERS),
112
+ "HmIP-eTRV": (frozenset({1}), _CLIMATE_MASTER_PARAMETERS),
113
+ "HmIPW-DRBL4": (frozenset({1, 5, 9, 13}), frozenset({Parameter.CHANNEL_OPERATION_MODE})),
114
+ "HmIPW-DRI16": (frozenset(range(1, 17)), frozenset({Parameter.CHANNEL_OPERATION_MODE})),
115
+ "HmIPW-DRI32": (frozenset(range(1, 33)), frozenset({Parameter.CHANNEL_OPERATION_MODE})),
116
+ "HmIPW-FIO6": (frozenset(range(1, 7)), frozenset({Parameter.CHANNEL_OPERATION_MODE})),
117
+ "HmIPW-STH": (frozenset({1}), _CLIMATE_MASTER_PARAMETERS),
109
118
  }
110
119
 
111
120
  # Ignore events for some devices
112
- _IGNORE_DEVICES_FOR_DATA_POINT_EVENTS: Final[Mapping[str, tuple[Parameter, ...]]] = {
121
+ _IGNORE_DEVICES_FOR_DATA_POINT_EVENTS: Final[Mapping[TModelName, frozenset[Parameter]]] = {
113
122
  "HmIP-PS": CLICK_EVENTS,
114
123
  }
115
124
 
116
- _IGNORE_DEVICES_FOR_DATA_POINT_EVENTS_LOWER: Final[dict[str, tuple[str, ...]]] = {
117
- model.lower(): tuple(event for event in events) for model, events in _IGNORE_DEVICES_FOR_DATA_POINT_EVENTS.items()
125
+ _IGNORE_DEVICES_FOR_DATA_POINT_EVENTS_LOWER: Final[Mapping[TModelName, frozenset[Parameter]]] = {
126
+ model.lower(): frozenset(events) for model, events in _IGNORE_DEVICES_FOR_DATA_POINT_EVENTS.items()
118
127
  }
119
128
 
120
129
  # data points that will be created, but should be hidden.
121
- _HIDDEN_PARAMETERS: Final[tuple[Parameter, ...]] = (
122
- Parameter.ACTIVITY_STATE,
123
- Parameter.CHANNEL_OPERATION_MODE,
124
- Parameter.CONFIG_PENDING,
125
- Parameter.DIRECTION,
126
- Parameter.ERROR,
127
- Parameter.HEATING_VALVE_TYPE,
128
- Parameter.LOW_BAT_LIMIT,
129
- Parameter.MIN_MAX_VALUE_NOT_RELEVANT_FOR_MANU_MODE,
130
- Parameter.OPTIMUM_START_STOP,
131
- Parameter.SECTION,
132
- Parameter.STICKY_UN_REACH,
133
- Parameter.TEMPERATURE_MAXIMUM,
134
- Parameter.TEMPERATURE_MINIMUM,
135
- Parameter.TEMPERATURE_OFFSET,
136
- Parameter.UN_REACH,
137
- Parameter.UPDATE_PENDING,
138
- Parameter.WORKING,
130
+ _HIDDEN_PARAMETERS: Final[frozenset[Parameter]] = frozenset(
131
+ {
132
+ Parameter.ACTIVITY_STATE,
133
+ Parameter.CHANNEL_OPERATION_MODE,
134
+ Parameter.CONFIG_PENDING,
135
+ Parameter.DIRECTION,
136
+ Parameter.ERROR,
137
+ Parameter.HEATING_VALVE_TYPE,
138
+ Parameter.LOW_BAT_LIMIT,
139
+ Parameter.MIN_MAX_VALUE_NOT_RELEVANT_FOR_MANU_MODE,
140
+ Parameter.OPTIMUM_START_STOP,
141
+ Parameter.SECTION,
142
+ Parameter.STICKY_UN_REACH,
143
+ Parameter.TEMPERATURE_MAXIMUM,
144
+ Parameter.TEMPERATURE_MINIMUM,
145
+ Parameter.TEMPERATURE_OFFSET,
146
+ Parameter.UN_REACH,
147
+ Parameter.UPDATE_PENDING,
148
+ Parameter.WORKING,
149
+ }
139
150
  )
140
- # Fast membership for hidden parameters
141
- _HIDDEN_PARAMETERS_SET: Final[set[Parameter]] = set(_HIDDEN_PARAMETERS)
142
151
 
143
152
  # Parameters within the VALUES paramset for which we don't create data points.
144
- _IGNORED_PARAMETERS: Final[tuple[str, ...]] = (
145
- "ACCESS_AUTHORIZATION",
146
- "ACOUSTIC_NOTIFICATION_SELECTION",
147
- "ADAPTION_DRIVE",
148
- "AES_KEY",
149
- "ALARM_COUNT",
150
- "ALL_LEDS",
151
- "ARROW_DOWN",
152
- "ARROW_UP",
153
- "BACKLIGHT",
154
- "BEEP",
155
- "BELL",
156
- "BLIND",
157
- "BOOST_STATE",
158
- "BOOST_TIME",
159
- "BOOT",
160
- "BULB",
161
- "CLEAR_ERROR",
162
- "CLEAR_WINDOW_OPEN_SYMBOL",
163
- "CLOCK",
164
- "CONTROL_DIFFERENTIAL_TEMPERATURE",
165
- "DATE_TIME_UNKNOWN",
166
- "DECISION_VALUE",
167
- "DEVICE_IN_BOOTLOADER",
168
- "DISPLAY_DATA_ALIGNMENT",
169
- "DISPLAY_DATA_BACKGROUND_COLOR",
170
- "DISPLAY_DATA_COMMIT",
171
- "DISPLAY_DATA_ICON",
172
- "DISPLAY_DATA_ID",
173
- "DISPLAY_DATA_STRING",
174
- "DISPLAY_DATA_TEXT_COLOR",
175
- "DOOR",
176
- "EXTERNAL_CLOCK",
177
- "FROST_PROTECTION",
178
- "HUMIDITY_LIMITER",
179
- "IDENTIFICATION_MODE_KEY_VISUAL",
180
- "IDENTIFICATION_MODE_LCD_BACKLIGHT",
181
- "INCLUSION_UNSUPPORTED_DEVICE",
182
- "INHIBIT",
183
- "INSTALL_MODE",
184
- "INTERVAL",
185
- "LEVEL_REAL",
186
- "OLD_LEVEL",
187
- "OVERFLOW",
188
- "OVERRUN",
189
- "PARTY_SET_POINT_TEMPERATURE",
190
- "PARTY_TEMPERATURE",
191
- "PARTY_TIME_END",
192
- "PARTY_TIME_START",
193
- "PHONE",
194
- "PROCESS",
195
- "QUICK_VETO_TIME",
196
- "RAMP_STOP",
197
- "RELOCK_DELAY",
198
- "SCENE",
199
- "SELF_CALIBRATION",
200
- "SERVICE_COUNT",
201
- "SET_SYMBOL_FOR_HEATING_PHASE",
202
- "SHADING_SPEED",
203
- "SHEV_POS",
204
- "SPEED",
205
- "STATE_UNCERTAIN",
206
- "SUBMIT",
207
- "SWITCH_POINT_OCCURED",
208
- "TEMPERATURE_LIMITER",
209
- "TEMPERATURE_OUT_OF_RANGE",
210
- "TEXT",
211
- "USER_COLOR",
212
- "USER_PROGRAM",
213
- "VALVE_ADAPTION",
214
- "WINDOW",
215
- "WIN_RELEASE",
216
- "WIN_RELEASE_ACT",
153
+ _IGNORED_PARAMETERS: Final[frozenset[TParameterName]] = frozenset(
154
+ {
155
+ "ACCESS_AUTHORIZATION",
156
+ "ACOUSTIC_NOTIFICATION_SELECTION",
157
+ "ADAPTION_DRIVE",
158
+ "AES_KEY",
159
+ "ALARM_COUNT",
160
+ "ALL_LEDS",
161
+ "ARROW_DOWN",
162
+ "ARROW_UP",
163
+ "BACKLIGHT",
164
+ "BEEP",
165
+ "BELL",
166
+ "BLIND",
167
+ "BOOST_STATE",
168
+ "BOOST_TIME",
169
+ "BOOT",
170
+ "BULB",
171
+ "CLEAR_ERROR",
172
+ "CLEAR_WINDOW_OPEN_SYMBOL",
173
+ "CLOCK",
174
+ "CONTROL_DIFFERENTIAL_TEMPERATURE",
175
+ "DATE_TIME_UNKNOWN",
176
+ "DECISION_VALUE",
177
+ "DEVICE_IN_BOOTLOADER",
178
+ "DISPLAY_DATA_ALIGNMENT",
179
+ "DISPLAY_DATA_BACKGROUND_COLOR",
180
+ "DISPLAY_DATA_COMMIT",
181
+ "DISPLAY_DATA_ICON",
182
+ "DISPLAY_DATA_ID",
183
+ "DISPLAY_DATA_STRING",
184
+ "DISPLAY_DATA_TEXT_COLOR",
185
+ "DOOR",
186
+ "EXTERNAL_CLOCK",
187
+ "FROST_PROTECTION",
188
+ "HUMIDITY_LIMITER",
189
+ "IDENTIFICATION_MODE_KEY_VISUAL",
190
+ "IDENTIFICATION_MODE_LCD_BACKLIGHT",
191
+ "INCLUSION_UNSUPPORTED_DEVICE",
192
+ "INHIBIT",
193
+ "INSTALL_MODE",
194
+ "INTERVAL",
195
+ "LEVEL_REAL",
196
+ "OLD_LEVEL",
197
+ "OVERFLOW",
198
+ "OVERRUN",
199
+ "PARTY_SET_POINT_TEMPERATURE",
200
+ "PARTY_TEMPERATURE",
201
+ "PARTY_TIME_END",
202
+ "PARTY_TIME_START",
203
+ "PHONE",
204
+ "PROCESS",
205
+ "QUICK_VETO_TIME",
206
+ "RAMP_STOP",
207
+ "RELOCK_DELAY",
208
+ "SCENE",
209
+ "SELF_CALIBRATION",
210
+ "SERVICE_COUNT",
211
+ "SET_SYMBOL_FOR_HEATING_PHASE",
212
+ "SHADING_SPEED",
213
+ "SHEV_POS",
214
+ "SPEED",
215
+ "STATE_UNCERTAIN",
216
+ "SUBMIT",
217
+ "SWITCH_POINT_OCCURED",
218
+ "TEMPERATURE_LIMITER",
219
+ "TEMPERATURE_OUT_OF_RANGE",
220
+ "TEXT",
221
+ "USER_COLOR",
222
+ "USER_PROGRAM",
223
+ "VALVE_ADAPTION",
224
+ "WINDOW",
225
+ "WIN_RELEASE",
226
+ "WIN_RELEASE_ACT",
227
+ }
217
228
  )
218
- # Fast membership for ignored VALUE parameters
219
- _IGNORED_PARAMETERS_SET: Final[set[str]] = set(_IGNORED_PARAMETERS)
220
229
 
221
230
 
222
231
  # Precompile Regex patterns for wildcard checks
@@ -228,31 +237,28 @@ _IGNORED_PARAMETERS_START_RE: Final = re.compile(
228
237
  )
229
238
 
230
239
 
231
- def _parameter_is_wildcard_ignored(parameter: str) -> bool:
240
+ def _parameter_is_wildcard_ignored(parameter: TParameterName) -> bool:
232
241
  """Check if a parameter matches common wildcard patterns."""
233
242
  return bool(_IGNORED_PARAMETERS_END_RE.match(parameter) or _IGNORED_PARAMETERS_START_RE.match(parameter))
234
243
 
235
244
 
236
245
  # Parameters within the paramsets for which we create data points.
237
- _UN_IGNORE_PARAMETERS_BY_DEVICE: Final[Mapping[str, tuple[Parameter, ...]]] = {
238
- "HmIP-DLD": (Parameter.ERROR_JAMMED,),
239
- "HmIP-SWSD": (Parameter.SMOKE_DETECTOR_ALARM_STATUS,),
240
- "HM-OU-LED16": (Parameter.LED_STATUS,),
241
- "HM-Sec-Win": (Parameter.DIRECTION, Parameter.WORKING, Parameter.ERROR, Parameter.STATUS),
242
- "HM-Sec-Key": (Parameter.DIRECTION, Parameter.ERROR),
243
- "HmIP-PCBS-BAT": (
244
- Parameter.OPERATING_VOLTAGE,
245
- Parameter.LOW_BAT,
246
- ), # To override ignore for HmIP-PCBS
246
+ _UN_IGNORE_PARAMETERS_BY_DEVICE: Final[Mapping[TModelName, frozenset[Parameter]]] = {
247
+ "HmIP-DLD": frozenset({Parameter.ERROR_JAMMED}),
248
+ "HmIP-SWSD": frozenset({Parameter.SMOKE_DETECTOR_ALARM_STATUS}),
249
+ "HM-OU-LED16": frozenset({Parameter.LED_STATUS}),
250
+ "HM-Sec-Win": frozenset({Parameter.DIRECTION, Parameter.WORKING, Parameter.ERROR, Parameter.STATUS}),
251
+ "HM-Sec-Key": frozenset({Parameter.DIRECTION, Parameter.ERROR}),
252
+ "HmIP-PCBS-BAT": frozenset({Parameter.OPERATING_VOLTAGE, Parameter.LOW_BAT}), # To override ignore for HmIP-PCBS
247
253
  }
248
254
 
249
- _UN_IGNORE_PARAMETERS_BY_MODEL_LOWER: Final[dict[str, tuple[str, ...]]] = {
250
- model.lower(): parameters for model, parameters in _UN_IGNORE_PARAMETERS_BY_DEVICE.items()
255
+ _UN_IGNORE_PARAMETERS_BY_MODEL_LOWER: Final[dict[TModelName, frozenset[Parameter]]] = {
256
+ model.lower(): frozenset(parameters) for model, parameters in _UN_IGNORE_PARAMETERS_BY_DEVICE.items()
251
257
  }
252
258
 
253
259
 
254
260
  @cache
255
- def _get_parameters_for_model_prefix(model_prefix: str | None) -> tuple[str, ...] | None:
261
+ def _get_parameters_for_model_prefix(model_prefix: str | None) -> frozenset[Parameter] | None:
256
262
  """Return the dict value by wildcard type."""
257
263
  if model_prefix is None:
258
264
  return None
@@ -264,59 +270,74 @@ def _get_parameters_for_model_prefix(model_prefix: str | None) -> tuple[str, ...
264
270
 
265
271
 
266
272
  # Parameters by device within the VALUES paramset for which we don't create data points.
267
- _IGNORE_PARAMETERS_BY_DEVICE: Final[Mapping[Parameter, tuple[str, ...]]] = {
268
- Parameter.CURRENT_ILLUMINATION: (
269
- "HmIP-SMI",
270
- "HmIP-SMO",
271
- "HmIP-SPI",
273
+ _IGNORE_PARAMETERS_BY_DEVICE: Final[Mapping[Parameter, frozenset[TModelName]]] = {
274
+ Parameter.CURRENT_ILLUMINATION: frozenset(
275
+ {
276
+ "HmIP-SMI",
277
+ "HmIP-SMO",
278
+ "HmIP-SPI",
279
+ }
272
280
  ),
273
- Parameter.LOWBAT: (
274
- "HM-LC-Sw1-DR",
275
- "HM-LC-Sw1-FM",
276
- "HM-LC-Sw1-PCB",
277
- "HM-LC-Sw1-Pl",
278
- "HM-LC-Sw1-Pl-DN-R1",
279
- "HM-LC-Sw1PBU-FM",
280
- "HM-LC-Sw2-FM",
281
- "HM-LC-Sw4-DR",
282
- "HM-SwI-3-FM",
281
+ Parameter.LOWBAT: frozenset(
282
+ {
283
+ "HM-LC-Sw1-DR",
284
+ "HM-LC-Sw1-FM",
285
+ "HM-LC-Sw1-PCB",
286
+ "HM-LC-Sw1-Pl",
287
+ "HM-LC-Sw1-Pl-DN-R1",
288
+ "HM-LC-Sw1PBU-FM",
289
+ "HM-LC-Sw2-FM",
290
+ "HM-LC-Sw4-DR",
291
+ "HM-SwI-3-FM",
292
+ }
283
293
  ),
284
- Parameter.LOW_BAT: ("HmIP-BWTH", "HmIP-PCBS"),
285
- Parameter.OPERATING_VOLTAGE: (
286
- "ELV-SH-BS2",
287
- "HmIP-BDT",
288
- "HmIP-BROLL",
289
- "HmIP-BS2",
290
- "HmIP-BSL",
291
- "HmIP-BSM",
292
- "HmIP-BWTH",
293
- "HmIP-DR",
294
- "HmIP-FDT",
295
- "HmIP-FROLL",
296
- "HmIP-FSM",
297
- "HmIP-MOD-OC8",
298
- "HmIP-PCBS",
299
- "HmIP-PDT",
300
- "HmIP-PMFS",
301
- "HmIP-PS",
302
- "HmIP-SFD",
303
- "HmIP-SMO230",
304
- "HmIP-WGT",
294
+ Parameter.LOW_BAT: frozenset({"HmIP-BWTH", "HmIP-PCBS"}),
295
+ Parameter.OPERATING_VOLTAGE: frozenset(
296
+ {
297
+ "ELV-SH-BS2",
298
+ "HmIP-BDT",
299
+ "HmIP-BROLL",
300
+ "HmIP-BS2",
301
+ "HmIP-BSL",
302
+ "HmIP-BSM",
303
+ "HmIP-BWTH",
304
+ "HmIP-DR",
305
+ "HmIP-FDT",
306
+ "HmIP-FROLL",
307
+ "HmIP-FSM",
308
+ "HmIP-MOD-OC8",
309
+ "HmIP-PCBS",
310
+ "HmIP-PDT",
311
+ "HmIP-PMFS",
312
+ "HmIP-PS",
313
+ "HmIP-SFD",
314
+ "HmIP-SMO230",
315
+ "HmIP-WGT",
316
+ }
305
317
  ),
306
- Parameter.VALVE_STATE: ("HmIPW-FALMOT-C12", "HmIP-FALMOT-C12"),
318
+ Parameter.VALVE_STATE: frozenset({"HmIPW-FALMOT-C12", "HmIP-FALMOT-C12"}),
307
319
  }
308
320
 
309
- _IGNORE_PARAMETERS_BY_DEVICE_LOWER: Final[dict[str, tuple[str, ...]]] = {
310
- parameter: tuple(model.lower() for model in s) for parameter, s in _IGNORE_PARAMETERS_BY_DEVICE.items()
321
+ _IGNORE_PARAMETERS_BY_DEVICE_LOWER: Final[dict[TParameterName, frozenset[TModelName]]] = {
322
+ parameter: frozenset(model.lower() for model in s) for parameter, s in _IGNORE_PARAMETERS_BY_DEVICE.items()
311
323
  }
312
324
 
313
325
  # Some devices have parameters on multiple channels,
314
326
  # but we want to use it only from a certain channel.
315
- _ACCEPT_PARAMETER_ONLY_ON_CHANNEL: Final[Mapping[str, int]] = {Parameter.LOWBAT: 0}
327
+ _ACCEPT_PARAMETER_ONLY_ON_CHANNEL: Final[Mapping[TParameterName, int]] = {Parameter.LOWBAT: 0}
316
328
 
317
329
 
318
330
  class ParameterVisibilityCache:
319
- """Cache for parameter visibility."""
331
+ """
332
+ Cache for parameter visibility.
333
+
334
+ The cache centralizes rules that determine whether a data point parameter is
335
+ created, ignored, un-ignored, or merely hidden for UI purposes. It combines
336
+ static rules (per-model/per-channel) with dynamic user-provided overrides and
337
+ memoizes decisions per (model/channel/paramset/parameter) to avoid repeated
338
+ computations during runtime. Behavior is unchanged; this class only clarifies
339
+ intent and structure through documentation and small naming improvements.
340
+ """
320
341
 
321
342
  __slots__ = (
322
343
  "_central",
@@ -342,36 +363,36 @@ class ParameterVisibilityCache:
342
363
  self._central = central
343
364
  self._storage_folder: Final = central.config.storage_folder
344
365
  self._required_parameters: Final = get_required_parameters()
345
- self._raw_un_ignores: Final[tuple[str, ...]] = central.config.un_ignore_list or ()
366
+ self._raw_un_ignores: Final[frozenset[str]] = central.config.un_ignore_list or frozenset()
346
367
 
347
368
  # un_ignore from custom un_ignore files
348
369
  # parameter
349
- self._custom_un_ignore_values_parameters: Final[set[str]] = set()
370
+ self._custom_un_ignore_values_parameters: Final[set[TParameterName]] = set()
350
371
 
351
- # model, channel_no, paramset_key, parameter
352
- self._custom_un_ignore_complex: Final[dict[str, dict[int | str | None, dict[str, set[str]]]]] = defaultdict(
353
- lambda: defaultdict(lambda: defaultdict(set))
354
- )
355
- self._ignore_custom_device_definition_models: Final[tuple[str, ...]] = (
372
+ # model -> channel_no -> paramset_key -> set(parameter)
373
+ self._custom_un_ignore_complex: Final[
374
+ dict[TModelName, dict[TUnIgnoreChannelNo, dict[ParamsetKey, set[TParameterName]]]]
375
+ ] = defaultdict(lambda: defaultdict(lambda: defaultdict(set)))
376
+ self._ignore_custom_device_definition_models: Final[frozenset[TModelName]] = (
356
377
  central.config.ignore_custom_device_definition_models
357
378
  )
358
379
 
359
380
  # model, channel_no, paramset_key, set[parameter]
360
381
  self._un_ignore_parameters_by_device_paramset_key: Final[
361
- dict[str, dict[int | None, dict[ParamsetKey, set[str]]]]
382
+ dict[TModelName, dict[TChannelNo, dict[ParamsetKey, set[TParameterName]]]]
362
383
  ] = defaultdict(lambda: defaultdict(lambda: defaultdict(set)))
363
384
 
364
385
  # model, channel_no
365
- self._relevant_master_paramsets_by_device: Final[dict[str, set[int | None]]] = defaultdict(set)
386
+ self._relevant_master_paramsets_by_device: Final[dict[TModelName, set[TChannelNo]]] = defaultdict(set)
366
387
  # Cache for resolving matching prefix key in _un_ignore_parameters_by_device_paramset_key
367
- self._un_ignore_prefix_cache: dict[str, str | None] = {}
388
+ self._un_ignore_prefix_cache: dict[TModelName, str | None] = {}
368
389
  # Cache for resolving matching prefix key in _relevant_master_paramsets_by_device
369
- self._relevant_prefix_cache: dict[str, str | None] = {}
390
+ self._relevant_prefix_cache: dict[TModelName, str | None] = {}
370
391
  # Per-instance memoization for repeated queries.
371
392
  # Key: (model_l, channel_no, paramset_key, parameter)
372
- self._param_ignored_cache: dict[tuple[str, int, ParamsetKey, str], bool] = {}
393
+ self._param_ignored_cache: dict[tuple[TModelName, TChannelNo, ParamsetKey, TParameterName], bool] = {}
373
394
  # Key: (model_l, channel_no, paramset_key, parameter, custom_only)
374
- self._param_un_ignored_cache: dict[tuple[str, int, ParamsetKey, str, bool], bool] = {}
395
+ self._param_un_ignored_cache: dict[tuple[TModelName, TChannelNo, ParamsetKey, TParameterName, bool], bool] = {}
375
396
  self._init()
376
397
 
377
398
  def _init(self) -> None:
@@ -383,7 +404,7 @@ class ParameterVisibilityCache:
383
404
  model_l = model.lower()
384
405
  channel_nos, parameters = channels_parameter
385
406
 
386
- def _add_channel(dt_l: str, params: tuple[Parameter, ...], ch_no: int | None) -> None:
407
+ def _add_channel(dt_l: str, params: frozenset[Parameter], ch_no: TChannelNo) -> None:
387
408
  self._relevant_master_paramsets_by_device[dt_l].add(ch_no)
388
409
  self._un_ignore_parameters_by_device_paramset_key[dt_l][ch_no][ParamsetKey.MASTER].update(params)
389
410
 
@@ -395,7 +416,17 @@ class ParameterVisibilityCache:
395
416
 
396
417
  self._process_un_ignore_entries(lines=self._raw_un_ignores)
397
418
 
398
- def model_is_ignored(self, model: str) -> bool:
419
+ def _resolve_prefix_key(
420
+ self, model_l: TModelName, mapping: Mapping[str, object], cache_dict: dict[TModelName, str | None]
421
+ ) -> str | None:
422
+ """Resolve and memoize the first key in mapping that prefixes model_l."""
423
+ dt_short_key = cache_dict.get(model_l)
424
+ if dt_short_key is None and model_l not in cache_dict:
425
+ dt_short_key = next((k for k in mapping if model_l.startswith(k)), None)
426
+ cache_dict[model_l] = dt_short_key
427
+ return dt_short_key
428
+
429
+ def model_is_ignored(self, model: TModelName) -> bool:
399
430
  """Check if a model should be ignored for custom data points."""
400
431
  return element_matches_key(
401
432
  search_elements=self._ignore_custom_device_definition_models,
@@ -406,13 +437,12 @@ class ParameterVisibilityCache:
406
437
  self,
407
438
  channel: hmd.Channel,
408
439
  paramset_key: ParamsetKey,
409
- parameter: str,
440
+ parameter: TParameterName,
410
441
  ) -> bool:
411
442
  """Check if parameter can be ignored."""
412
443
  model_l = channel.device.model.lower()
413
444
  # Fast path via per-instance memoization
414
- ch_no_key = channel.no if isinstance(channel.no, int) else (-1 if channel.no is None else channel.no)
415
- if (cache_key := (model_l, ch_no_key, paramset_key, parameter)) in self._param_ignored_cache:
445
+ if (cache_key := (model_l, channel.no, paramset_key, parameter)) in self._param_ignored_cache:
416
446
  return self._param_ignored_cache[cache_key]
417
447
 
418
448
  if paramset_key == ParamsetKey.VALUES:
@@ -425,7 +455,7 @@ class ParameterVisibilityCache:
425
455
 
426
456
  if (
427
457
  (
428
- (parameter in _IGNORED_PARAMETERS_SET or _parameter_is_wildcard_ignored(parameter=parameter))
458
+ (parameter in _IGNORED_PARAMETERS or _parameter_is_wildcard_ignored(parameter=parameter))
429
459
  and parameter not in self._required_parameters
430
460
  )
431
461
  or hms.element_matches_key(
@@ -454,14 +484,11 @@ class ParameterVisibilityCache:
454
484
  if parameter in self._custom_un_ignore_complex[model_l][channel.no][ParamsetKey.MASTER]:
455
485
  return False # pragma: no cover
456
486
 
457
- # Resolve matching device type prefix once and cache per model
458
- dt_short_key = self._un_ignore_prefix_cache.get(model_l)
459
- if dt_short_key is None and model_l not in self._un_ignore_prefix_cache:
460
- # Find first key that is a prefix of model_l
461
- dt_short_key = next(
462
- (k for k in self._un_ignore_parameters_by_device_paramset_key if model_l.startswith(k)), None
463
- )
464
- self._un_ignore_prefix_cache[model_l] = dt_short_key
487
+ dt_short_key = self._resolve_prefix_key(
488
+ model_l=model_l,
489
+ mapping=self._un_ignore_parameters_by_device_paramset_key,
490
+ cache_dict=self._un_ignore_prefix_cache,
491
+ )
465
492
  if (
466
493
  dt_short_key is not None
467
494
  and parameter
@@ -479,7 +506,7 @@ class ParameterVisibilityCache:
479
506
  self,
480
507
  channel: hmd.Channel,
481
508
  paramset_key: ParamsetKey,
482
- parameter: str,
509
+ parameter: TParameterName,
483
510
  custom_only: bool = False,
484
511
  ) -> bool:
485
512
  """
@@ -496,8 +523,7 @@ class ParameterVisibilityCache:
496
523
  # check if parameter is in custom_un_ignore with paramset_key
497
524
  model_l = channel.device.model.lower()
498
525
  # Fast path via per-instance memoization
499
- ch_no_key = channel.no if isinstance(channel.no, int) else (-1 if channel.no is None else channel.no)
500
- if (cache_key := (model_l, ch_no_key, paramset_key, parameter, custom_only)) in self._param_un_ignored_cache:
526
+ if (cache_key := (model_l, channel.no, paramset_key, parameter, custom_only)) in self._param_un_ignored_cache:
501
527
  return self._param_un_ignored_cache[cache_key]
502
528
 
503
529
  search_matrix = (
@@ -529,7 +555,7 @@ class ParameterVisibilityCache:
529
555
  self,
530
556
  channel: hmd.Channel,
531
557
  paramset_key: ParamsetKey,
532
- parameter: str,
558
+ parameter: TParameterName,
533
559
  custom_only: bool = False,
534
560
  ) -> bool:
535
561
  """
@@ -540,13 +566,11 @@ class ParameterVisibilityCache:
540
566
  """
541
567
  if not custom_only:
542
568
  model_l = channel.device.model.lower()
543
- # Resolve matching device type prefix once and cache per model
544
- dt_short_key = self._un_ignore_prefix_cache.get(model_l)
545
- if dt_short_key is None and model_l not in self._un_ignore_prefix_cache:
546
- dt_short_key = next(
547
- (k for k in self._un_ignore_parameters_by_device_paramset_key if model_l.startswith(k)), None
548
- )
549
- self._un_ignore_prefix_cache[model_l] = dt_short_key
569
+ dt_short_key = self._resolve_prefix_key(
570
+ model_l=model_l,
571
+ mapping=self._un_ignore_parameters_by_device_paramset_key,
572
+ cache_dict=self._un_ignore_prefix_cache,
573
+ )
550
574
 
551
575
  # check if parameter is in _RELEVANT_MASTER_PARAMSETS_BY_DEVICE
552
576
  if (
@@ -564,7 +588,7 @@ class ParameterVisibilityCache:
564
588
  )
565
589
 
566
590
  def should_skip_parameter(
567
- self, channel: hmd.Channel, paramset_key: ParamsetKey, parameter: str, parameter_is_un_ignored: bool
591
+ self, channel: hmd.Channel, paramset_key: ParamsetKey, parameter: TParameterName, parameter_is_un_ignored: bool
568
592
  ) -> bool:
569
593
  """Determine if a parameter should be skipped."""
570
594
  if self.parameter_is_ignored(
@@ -587,7 +611,7 @@ class ParameterVisibilityCache:
587
611
 
588
612
  return paramset_key == ParamsetKey.MASTER and not parameter_is_un_ignored
589
613
 
590
- def _process_un_ignore_entries(self, lines: tuple[str, ...]) -> None:
614
+ def _process_un_ignore_entries(self, lines: Iterable[str]) -> None:
591
615
  """Batch process un_ignore entries into cache."""
592
616
  for line in lines:
593
617
  # ignore empty line
@@ -610,17 +634,19 @@ class ParameterVisibilityCache:
610
634
  line,
611
635
  )
612
636
 
613
- def _get_un_ignore_line_details(self, line: str) -> tuple[str, int | str | None, str, ParamsetKey] | str | None:
637
+ def _get_un_ignore_line_details(
638
+ self, line: str
639
+ ) -> tuple[TModelName, TUnIgnoreChannelNo, TParameterName, ParamsetKey] | str | None:
614
640
  """
615
641
  Check the format of the line for un_ignore file.
616
642
 
617
643
  model, channel_no, paramset_key, parameter
618
644
  """
619
645
 
620
- model: str | None = None
621
- channel_no: int | str | None = None
646
+ model: TModelName | None = None
647
+ channel_no: TUnIgnoreChannelNo = None
622
648
  paramset_key: ParamsetKey | None = None
623
- parameter: str | None = None
649
+ parameter: TParameterName | None = None
624
650
 
625
651
  if "@" in line:
626
652
  data = line.split("@")
@@ -687,10 +713,10 @@ class ParameterVisibilityCache:
687
713
 
688
714
  def _add_complex_un_ignore_entry(
689
715
  self,
690
- model: str,
691
- channel_no: int | str | None,
716
+ model: TModelName,
717
+ channel_no: TUnIgnoreChannelNo,
692
718
  paramset_key: ParamsetKey,
693
- parameter: str,
719
+ parameter: TParameterName,
694
720
  ) -> None:
695
721
  """Add line to un ignore cache."""
696
722
  if paramset_key == ParamsetKey.MASTER:
@@ -713,7 +739,7 @@ class ParameterVisibilityCache:
713
739
  self,
714
740
  channel: hmd.Channel,
715
741
  paramset_key: ParamsetKey,
716
- parameter: str,
742
+ parameter: TParameterName,
717
743
  ) -> bool:
718
744
  """
719
745
  Return if parameter should be hidden.
@@ -721,7 +747,7 @@ class ParameterVisibilityCache:
721
747
  This is required to determine the data_point usage.
722
748
  Return only hidden parameters, that are no defined in the un_ignore file.
723
749
  """
724
- return parameter in _HIDDEN_PARAMETERS_SET and not self._parameter_is_un_ignored(
750
+ return parameter in _HIDDEN_PARAMETERS and not self._parameter_is_un_ignored(
725
751
  channel=channel,
726
752
  paramset_key=paramset_key,
727
753
  parameter=parameter,
@@ -744,12 +770,11 @@ class ParameterVisibilityCache:
744
770
  return True
745
771
  model_l = channel.device.model.lower()
746
772
  # Resolve matching device type prefix once and cache per model
747
- dt_short_key = self._relevant_prefix_cache.get(model_l)
748
- if dt_short_key is None and model_l not in self._relevant_prefix_cache:
749
- dt_short_key = next(
750
- (k for k in self._relevant_master_paramsets_by_device if model_l.startswith(k)), None
751
- )
752
- self._relevant_prefix_cache[model_l] = dt_short_key
773
+ dt_short_key = self._resolve_prefix_key(
774
+ model_l=model_l,
775
+ mapping=self._relevant_master_paramsets_by_device,
776
+ cache_dict=self._relevant_prefix_cache,
777
+ )
753
778
  if dt_short_key is not None and channel.no in self._relevant_master_paramsets_by_device[dt_short_key]:
754
779
  return True
755
780
  return False
@@ -766,7 +791,7 @@ def check_ignore_parameters_is_clean() -> bool:
766
791
  [
767
792
  parameter
768
793
  for parameter in get_required_parameters()
769
- if (parameter in _IGNORED_PARAMETERS_SET or _parameter_is_wildcard_ignored(parameter=parameter))
794
+ if (parameter in _IGNORED_PARAMETERS or _parameter_is_wildcard_ignored(parameter=parameter))
770
795
  and parameter not in un_ignore_parameters_by_device
771
796
  ]
772
797
  )