aiohomematic 2026.1.29__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.
- aiohomematic/__init__.py +110 -0
- aiohomematic/_log_context_protocol.py +29 -0
- aiohomematic/api.py +410 -0
- aiohomematic/async_support.py +250 -0
- aiohomematic/backend_detection.py +462 -0
- aiohomematic/central/__init__.py +103 -0
- aiohomematic/central/async_rpc_server.py +760 -0
- aiohomematic/central/central_unit.py +1152 -0
- aiohomematic/central/config.py +463 -0
- aiohomematic/central/config_builder.py +772 -0
- aiohomematic/central/connection_state.py +160 -0
- aiohomematic/central/coordinators/__init__.py +38 -0
- aiohomematic/central/coordinators/cache.py +414 -0
- aiohomematic/central/coordinators/client.py +480 -0
- aiohomematic/central/coordinators/connection_recovery.py +1141 -0
- aiohomematic/central/coordinators/device.py +1166 -0
- aiohomematic/central/coordinators/event.py +514 -0
- aiohomematic/central/coordinators/hub.py +532 -0
- aiohomematic/central/decorators.py +184 -0
- aiohomematic/central/device_registry.py +229 -0
- aiohomematic/central/events/__init__.py +104 -0
- aiohomematic/central/events/bus.py +1392 -0
- aiohomematic/central/events/integration.py +424 -0
- aiohomematic/central/events/types.py +194 -0
- aiohomematic/central/health.py +762 -0
- aiohomematic/central/rpc_server.py +353 -0
- aiohomematic/central/scheduler.py +794 -0
- aiohomematic/central/state_machine.py +391 -0
- aiohomematic/client/__init__.py +203 -0
- aiohomematic/client/_rpc_errors.py +187 -0
- aiohomematic/client/backends/__init__.py +48 -0
- aiohomematic/client/backends/base.py +335 -0
- aiohomematic/client/backends/capabilities.py +138 -0
- aiohomematic/client/backends/ccu.py +487 -0
- aiohomematic/client/backends/factory.py +116 -0
- aiohomematic/client/backends/homegear.py +294 -0
- aiohomematic/client/backends/json_ccu.py +252 -0
- aiohomematic/client/backends/protocol.py +316 -0
- aiohomematic/client/ccu.py +1857 -0
- aiohomematic/client/circuit_breaker.py +459 -0
- aiohomematic/client/config.py +64 -0
- aiohomematic/client/handlers/__init__.py +40 -0
- aiohomematic/client/handlers/backup.py +157 -0
- aiohomematic/client/handlers/base.py +79 -0
- aiohomematic/client/handlers/device_ops.py +1085 -0
- aiohomematic/client/handlers/firmware.py +144 -0
- aiohomematic/client/handlers/link_mgmt.py +199 -0
- aiohomematic/client/handlers/metadata.py +436 -0
- aiohomematic/client/handlers/programs.py +144 -0
- aiohomematic/client/handlers/sysvars.py +100 -0
- aiohomematic/client/interface_client.py +1304 -0
- aiohomematic/client/json_rpc.py +2068 -0
- aiohomematic/client/request_coalescer.py +282 -0
- aiohomematic/client/rpc_proxy.py +629 -0
- aiohomematic/client/state_machine.py +324 -0
- aiohomematic/const.py +2207 -0
- aiohomematic/context.py +275 -0
- aiohomematic/converter.py +270 -0
- aiohomematic/decorators.py +390 -0
- aiohomematic/exceptions.py +185 -0
- aiohomematic/hmcli.py +997 -0
- aiohomematic/i18n.py +193 -0
- aiohomematic/interfaces/__init__.py +407 -0
- aiohomematic/interfaces/central.py +1067 -0
- aiohomematic/interfaces/client.py +1096 -0
- aiohomematic/interfaces/coordinators.py +63 -0
- aiohomematic/interfaces/model.py +1921 -0
- aiohomematic/interfaces/operations.py +217 -0
- aiohomematic/logging_context.py +134 -0
- aiohomematic/metrics/__init__.py +125 -0
- aiohomematic/metrics/_protocols.py +140 -0
- aiohomematic/metrics/aggregator.py +534 -0
- aiohomematic/metrics/dataclasses.py +489 -0
- aiohomematic/metrics/emitter.py +292 -0
- aiohomematic/metrics/events.py +183 -0
- aiohomematic/metrics/keys.py +300 -0
- aiohomematic/metrics/observer.py +563 -0
- aiohomematic/metrics/stats.py +172 -0
- aiohomematic/model/__init__.py +189 -0
- aiohomematic/model/availability.py +65 -0
- aiohomematic/model/calculated/__init__.py +89 -0
- aiohomematic/model/calculated/climate.py +276 -0
- aiohomematic/model/calculated/data_point.py +315 -0
- aiohomematic/model/calculated/field.py +147 -0
- aiohomematic/model/calculated/operating_voltage_level.py +286 -0
- aiohomematic/model/calculated/support.py +232 -0
- aiohomematic/model/custom/__init__.py +214 -0
- aiohomematic/model/custom/capabilities/__init__.py +67 -0
- aiohomematic/model/custom/capabilities/climate.py +41 -0
- aiohomematic/model/custom/capabilities/light.py +87 -0
- aiohomematic/model/custom/capabilities/lock.py +44 -0
- aiohomematic/model/custom/capabilities/siren.py +63 -0
- aiohomematic/model/custom/climate.py +1130 -0
- aiohomematic/model/custom/cover.py +722 -0
- aiohomematic/model/custom/data_point.py +360 -0
- aiohomematic/model/custom/definition.py +300 -0
- aiohomematic/model/custom/field.py +89 -0
- aiohomematic/model/custom/light.py +1174 -0
- aiohomematic/model/custom/lock.py +322 -0
- aiohomematic/model/custom/mixins.py +445 -0
- aiohomematic/model/custom/profile.py +945 -0
- aiohomematic/model/custom/registry.py +251 -0
- aiohomematic/model/custom/siren.py +462 -0
- aiohomematic/model/custom/switch.py +195 -0
- aiohomematic/model/custom/text_display.py +289 -0
- aiohomematic/model/custom/valve.py +78 -0
- aiohomematic/model/data_point.py +1416 -0
- aiohomematic/model/device.py +1840 -0
- aiohomematic/model/event.py +216 -0
- aiohomematic/model/generic/__init__.py +327 -0
- aiohomematic/model/generic/action.py +40 -0
- aiohomematic/model/generic/action_select.py +62 -0
- aiohomematic/model/generic/binary_sensor.py +30 -0
- aiohomematic/model/generic/button.py +31 -0
- aiohomematic/model/generic/data_point.py +177 -0
- aiohomematic/model/generic/dummy.py +150 -0
- aiohomematic/model/generic/number.py +76 -0
- aiohomematic/model/generic/select.py +56 -0
- aiohomematic/model/generic/sensor.py +76 -0
- aiohomematic/model/generic/switch.py +54 -0
- aiohomematic/model/generic/text.py +33 -0
- aiohomematic/model/hub/__init__.py +100 -0
- aiohomematic/model/hub/binary_sensor.py +24 -0
- aiohomematic/model/hub/button.py +28 -0
- aiohomematic/model/hub/connectivity.py +190 -0
- aiohomematic/model/hub/data_point.py +342 -0
- aiohomematic/model/hub/hub.py +864 -0
- aiohomematic/model/hub/inbox.py +135 -0
- aiohomematic/model/hub/install_mode.py +393 -0
- aiohomematic/model/hub/metrics.py +208 -0
- aiohomematic/model/hub/number.py +42 -0
- aiohomematic/model/hub/select.py +52 -0
- aiohomematic/model/hub/sensor.py +37 -0
- aiohomematic/model/hub/switch.py +43 -0
- aiohomematic/model/hub/text.py +30 -0
- aiohomematic/model/hub/update.py +221 -0
- aiohomematic/model/support.py +592 -0
- aiohomematic/model/update.py +140 -0
- aiohomematic/model/week_profile.py +1827 -0
- aiohomematic/property_decorators.py +719 -0
- aiohomematic/py.typed +0 -0
- aiohomematic/rega_scripts/accept_device_in_inbox.fn +51 -0
- aiohomematic/rega_scripts/create_backup_start.fn +28 -0
- aiohomematic/rega_scripts/create_backup_status.fn +89 -0
- aiohomematic/rega_scripts/fetch_all_device_data.fn +97 -0
- aiohomematic/rega_scripts/get_backend_info.fn +25 -0
- aiohomematic/rega_scripts/get_inbox_devices.fn +61 -0
- aiohomematic/rega_scripts/get_program_descriptions.fn +31 -0
- aiohomematic/rega_scripts/get_serial.fn +44 -0
- aiohomematic/rega_scripts/get_service_messages.fn +83 -0
- aiohomematic/rega_scripts/get_system_update_info.fn +39 -0
- aiohomematic/rega_scripts/get_system_variable_descriptions.fn +31 -0
- aiohomematic/rega_scripts/set_program_state.fn +17 -0
- aiohomematic/rega_scripts/set_system_variable.fn +19 -0
- aiohomematic/rega_scripts/trigger_firmware_update.fn +67 -0
- aiohomematic/schemas.py +256 -0
- aiohomematic/store/__init__.py +55 -0
- aiohomematic/store/dynamic/__init__.py +43 -0
- aiohomematic/store/dynamic/command.py +250 -0
- aiohomematic/store/dynamic/data.py +175 -0
- aiohomematic/store/dynamic/details.py +187 -0
- aiohomematic/store/dynamic/ping_pong.py +416 -0
- aiohomematic/store/persistent/__init__.py +71 -0
- aiohomematic/store/persistent/base.py +285 -0
- aiohomematic/store/persistent/device.py +233 -0
- aiohomematic/store/persistent/incident.py +380 -0
- aiohomematic/store/persistent/paramset.py +241 -0
- aiohomematic/store/persistent/session.py +556 -0
- aiohomematic/store/serialization.py +150 -0
- aiohomematic/store/storage.py +689 -0
- aiohomematic/store/types.py +526 -0
- aiohomematic/store/visibility/__init__.py +40 -0
- aiohomematic/store/visibility/parser.py +141 -0
- aiohomematic/store/visibility/registry.py +722 -0
- aiohomematic/store/visibility/rules.py +307 -0
- aiohomematic/strings.json +237 -0
- aiohomematic/support.py +706 -0
- aiohomematic/tracing.py +236 -0
- aiohomematic/translations/de.json +237 -0
- aiohomematic/translations/en.json +237 -0
- aiohomematic/type_aliases.py +51 -0
- aiohomematic/validator.py +128 -0
- aiohomematic-2026.1.29.dist-info/METADATA +296 -0
- aiohomematic-2026.1.29.dist-info/RECORD +188 -0
- aiohomematic-2026.1.29.dist-info/WHEEL +5 -0
- aiohomematic-2026.1.29.dist-info/entry_points.txt +2 -0
- aiohomematic-2026.1.29.dist-info/licenses/LICENSE +21 -0
- aiohomematic-2026.1.29.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,722 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2021-2026
|
|
3
|
+
"""
|
|
4
|
+
Parameter visibility registry for Homematic data points.
|
|
5
|
+
|
|
6
|
+
This module provides the ParameterVisibilityRegistry class which determines whether
|
|
7
|
+
parameters should be created, shown, hidden, ignored, or un-ignored for channels
|
|
8
|
+
and devices. It consolidates rules from multiple sources and memoizes decisions
|
|
9
|
+
to avoid repeated computations.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
from collections.abc import Iterable
|
|
15
|
+
from functools import cache
|
|
16
|
+
import logging
|
|
17
|
+
from typing import TYPE_CHECKING, Final, NamedTuple
|
|
18
|
+
|
|
19
|
+
from aiohomematic import support as hms
|
|
20
|
+
from aiohomematic.const import UN_IGNORE_WILDCARD, ParamsetKey
|
|
21
|
+
from aiohomematic.interfaces import ParameterVisibilityProviderProtocol
|
|
22
|
+
from aiohomematic.model.custom import get_required_parameters
|
|
23
|
+
from aiohomematic.store.visibility.parser import ParsedUnIgnoreLine, UnIgnoreChannelNo, parse_un_ignore_line
|
|
24
|
+
from aiohomematic.store.visibility.rules import (
|
|
25
|
+
ACCEPT_PARAMETER_ONLY_ON_CHANNEL,
|
|
26
|
+
HIDDEN_PARAMETERS,
|
|
27
|
+
IGNORE_DEVICES_FOR_DATA_POINT_EVENTS_LOWER,
|
|
28
|
+
IGNORE_PARAMETERS_BY_DEVICE_LOWER,
|
|
29
|
+
IGNORED_PARAMETERS,
|
|
30
|
+
RELEVANT_MASTER_PARAMSETS_BY_CHANNEL,
|
|
31
|
+
RELEVANT_MASTER_PARAMSETS_BY_DEVICE,
|
|
32
|
+
UN_IGNORE_PARAMETERS_BY_MODEL_LOWER,
|
|
33
|
+
ChannelNo,
|
|
34
|
+
ModelName,
|
|
35
|
+
ParameterName,
|
|
36
|
+
parameter_is_wildcard_ignored,
|
|
37
|
+
)
|
|
38
|
+
from aiohomematic.support import element_matches_key
|
|
39
|
+
|
|
40
|
+
if TYPE_CHECKING:
|
|
41
|
+
from aiohomematic.interfaces import ChannelProtocol, ConfigProviderProtocol, EventBusProviderProtocol
|
|
42
|
+
|
|
43
|
+
_LOGGER: Final = logging.getLogger(__name__)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
# =============================================================================
|
|
47
|
+
# Typed Cache Keys
|
|
48
|
+
# =============================================================================
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class IgnoreCacheKey(NamedTuple):
|
|
52
|
+
"""Cache key for parameter_is_ignored lookups."""
|
|
53
|
+
|
|
54
|
+
model: ModelName
|
|
55
|
+
channel_no: ChannelNo
|
|
56
|
+
paramset_key: ParamsetKey
|
|
57
|
+
parameter: ParameterName
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class UnIgnoreCacheKey(NamedTuple):
|
|
61
|
+
"""Cache key for parameter_is_un_ignored lookups."""
|
|
62
|
+
|
|
63
|
+
model: ModelName
|
|
64
|
+
channel_no: ChannelNo
|
|
65
|
+
paramset_key: ParamsetKey
|
|
66
|
+
parameter: ParameterName
|
|
67
|
+
custom_only: bool
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
# =============================================================================
|
|
71
|
+
# Rule Container Classes
|
|
72
|
+
# =============================================================================
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class ChannelParamsetRules:
|
|
76
|
+
"""
|
|
77
|
+
Manage parameter rules indexed by (channel_no, paramset_key).
|
|
78
|
+
|
|
79
|
+
Replaces nested defaultdict structures with a cleaner interface.
|
|
80
|
+
"""
|
|
81
|
+
|
|
82
|
+
__slots__ = ("_data",)
|
|
83
|
+
|
|
84
|
+
def __init__(self) -> None:
|
|
85
|
+
"""Initialize empty rules container."""
|
|
86
|
+
self._data: dict[tuple[UnIgnoreChannelNo, ParamsetKey], set[ParameterName]] = {}
|
|
87
|
+
|
|
88
|
+
def add(
|
|
89
|
+
self,
|
|
90
|
+
*,
|
|
91
|
+
channel_no: UnIgnoreChannelNo,
|
|
92
|
+
paramset_key: ParamsetKey,
|
|
93
|
+
parameter: ParameterName,
|
|
94
|
+
) -> None:
|
|
95
|
+
"""Add a parameter to the rules for a channel/paramset combination."""
|
|
96
|
+
if (key := (channel_no, paramset_key)) not in self._data:
|
|
97
|
+
self._data[key] = set()
|
|
98
|
+
self._data[key].add(parameter)
|
|
99
|
+
|
|
100
|
+
def contains(
|
|
101
|
+
self,
|
|
102
|
+
*,
|
|
103
|
+
channel_no: UnIgnoreChannelNo,
|
|
104
|
+
paramset_key: ParamsetKey,
|
|
105
|
+
parameter: ParameterName,
|
|
106
|
+
) -> bool:
|
|
107
|
+
"""Check if a parameter exists in the rules for a channel/paramset combination."""
|
|
108
|
+
return parameter in self._data.get((channel_no, paramset_key), set())
|
|
109
|
+
|
|
110
|
+
def get_parameters(
|
|
111
|
+
self,
|
|
112
|
+
*,
|
|
113
|
+
channel_no: UnIgnoreChannelNo,
|
|
114
|
+
paramset_key: ParamsetKey,
|
|
115
|
+
) -> set[ParameterName]:
|
|
116
|
+
"""Return the set of parameters for a channel/paramset combination."""
|
|
117
|
+
return self._data.get((channel_no, paramset_key), set())
|
|
118
|
+
|
|
119
|
+
def update(
|
|
120
|
+
self,
|
|
121
|
+
*,
|
|
122
|
+
channel_no: UnIgnoreChannelNo,
|
|
123
|
+
paramset_key: ParamsetKey,
|
|
124
|
+
parameters: Iterable[ParameterName],
|
|
125
|
+
) -> None:
|
|
126
|
+
"""Add multiple parameters to the rules for a channel/paramset combination."""
|
|
127
|
+
if (key := (channel_no, paramset_key)) not in self._data:
|
|
128
|
+
self._data[key] = set()
|
|
129
|
+
self._data[key].update(parameters)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
class ModelRules:
|
|
133
|
+
"""
|
|
134
|
+
Manage parameter rules indexed by model name.
|
|
135
|
+
|
|
136
|
+
Each model has its own ChannelParamsetRules and a set of relevant channels.
|
|
137
|
+
"""
|
|
138
|
+
|
|
139
|
+
__slots__ = ("_channel_rules", "_relevant_channels")
|
|
140
|
+
|
|
141
|
+
def __init__(self) -> None:
|
|
142
|
+
"""Initialize empty model rules container."""
|
|
143
|
+
self._channel_rules: dict[ModelName, ChannelParamsetRules] = {}
|
|
144
|
+
self._relevant_channels: dict[ModelName, set[ChannelNo]] = {}
|
|
145
|
+
|
|
146
|
+
def add_parameter(
|
|
147
|
+
self,
|
|
148
|
+
*,
|
|
149
|
+
model: ModelName,
|
|
150
|
+
channel_no: UnIgnoreChannelNo,
|
|
151
|
+
paramset_key: ParamsetKey,
|
|
152
|
+
parameter: ParameterName,
|
|
153
|
+
) -> None:
|
|
154
|
+
"""Add a parameter rule for a model/channel/paramset combination."""
|
|
155
|
+
if model not in self._channel_rules:
|
|
156
|
+
self._channel_rules[model] = ChannelParamsetRules()
|
|
157
|
+
self._channel_rules[model].add(channel_no=channel_no, paramset_key=paramset_key, parameter=parameter)
|
|
158
|
+
|
|
159
|
+
def add_relevant_channel(self, *, model: ModelName, channel_no: ChannelNo) -> None:
|
|
160
|
+
"""Mark a channel as relevant for MASTER paramset fetching."""
|
|
161
|
+
if model not in self._relevant_channels:
|
|
162
|
+
self._relevant_channels[model] = set()
|
|
163
|
+
self._relevant_channels[model].add(channel_no)
|
|
164
|
+
|
|
165
|
+
def contains(
|
|
166
|
+
self,
|
|
167
|
+
*,
|
|
168
|
+
model: ModelName,
|
|
169
|
+
channel_no: UnIgnoreChannelNo,
|
|
170
|
+
paramset_key: ParamsetKey,
|
|
171
|
+
parameter: ParameterName,
|
|
172
|
+
) -> bool:
|
|
173
|
+
"""Check if a parameter exists in the rules."""
|
|
174
|
+
if model not in self._channel_rules:
|
|
175
|
+
return False
|
|
176
|
+
return self._channel_rules[model].contains(
|
|
177
|
+
channel_no=channel_no, paramset_key=paramset_key, parameter=parameter
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
def get_models(self) -> Iterable[ModelName]:
|
|
181
|
+
"""Return all model names with rules."""
|
|
182
|
+
return self._channel_rules.keys()
|
|
183
|
+
|
|
184
|
+
def get_relevant_channels(self, *, model: ModelName) -> set[ChannelNo]:
|
|
185
|
+
"""Return the set of relevant channels for a model."""
|
|
186
|
+
return self._relevant_channels.get(model, set())
|
|
187
|
+
|
|
188
|
+
def has_relevant_channel(self, *, model: ModelName, channel_no: ChannelNo) -> bool:
|
|
189
|
+
"""Check if a channel is relevant for a model."""
|
|
190
|
+
return channel_no in self._relevant_channels.get(model, set())
|
|
191
|
+
|
|
192
|
+
def update_parameters(
|
|
193
|
+
self,
|
|
194
|
+
*,
|
|
195
|
+
model: ModelName,
|
|
196
|
+
channel_no: UnIgnoreChannelNo,
|
|
197
|
+
paramset_key: ParamsetKey,
|
|
198
|
+
parameters: Iterable[ParameterName],
|
|
199
|
+
) -> None:
|
|
200
|
+
"""Add multiple parameter rules for a model/channel/paramset combination."""
|
|
201
|
+
if model not in self._channel_rules:
|
|
202
|
+
self._channel_rules[model] = ChannelParamsetRules()
|
|
203
|
+
self._channel_rules[model].update(channel_no=channel_no, paramset_key=paramset_key, parameters=parameters)
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
# =============================================================================
|
|
207
|
+
# Cached Helper Functions
|
|
208
|
+
# =============================================================================
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
@cache
|
|
212
|
+
def _get_parameters_for_model_prefix(*, model_prefix: str | None) -> frozenset[ParameterName] | None:
|
|
213
|
+
"""Return un-ignore parameters for a model by prefix match."""
|
|
214
|
+
if model_prefix is None:
|
|
215
|
+
return None
|
|
216
|
+
|
|
217
|
+
for model, parameters in UN_IGNORE_PARAMETERS_BY_MODEL_LOWER.items():
|
|
218
|
+
if model.startswith(model_prefix):
|
|
219
|
+
return parameters
|
|
220
|
+
return None
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
# =============================================================================
|
|
224
|
+
# Parameter Visibility Registry
|
|
225
|
+
# =============================================================================
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
class ParameterVisibilityRegistry(ParameterVisibilityProviderProtocol):
|
|
229
|
+
"""
|
|
230
|
+
Registry for parameter visibility decisions.
|
|
231
|
+
|
|
232
|
+
Centralizes rules that determine whether a data point parameter is created,
|
|
233
|
+
ignored, un-ignored, or merely hidden for UI purposes. Combines static rules
|
|
234
|
+
(per-model/per-channel) with dynamic user-provided overrides and memoizes
|
|
235
|
+
decisions per (model/channel/paramset/parameter) to avoid repeated computations.
|
|
236
|
+
"""
|
|
237
|
+
|
|
238
|
+
__slots__ = (
|
|
239
|
+
"_config_provider",
|
|
240
|
+
"_custom_un_ignore_rules",
|
|
241
|
+
"_custom_un_ignore_values_parameters",
|
|
242
|
+
"_device_un_ignore_rules",
|
|
243
|
+
"_ignore_custom_device_definition_models",
|
|
244
|
+
"_param_ignored_cache",
|
|
245
|
+
"_param_un_ignored_cache",
|
|
246
|
+
"_raw_un_ignores",
|
|
247
|
+
"_relevant_master_channels",
|
|
248
|
+
"_relevant_prefix_cache",
|
|
249
|
+
"_required_parameters",
|
|
250
|
+
"_storage_directory",
|
|
251
|
+
"_un_ignore_prefix_cache",
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
def __init__(
|
|
255
|
+
self,
|
|
256
|
+
*,
|
|
257
|
+
config_provider: ConfigProviderProtocol,
|
|
258
|
+
event_bus_provider: EventBusProviderProtocol | None = None, # Kept for compatibility, unused
|
|
259
|
+
) -> None:
|
|
260
|
+
"""Initialize the parameter visibility registry."""
|
|
261
|
+
self._config_provider: Final = config_provider
|
|
262
|
+
self._storage_directory: Final = config_provider.config.storage_directory
|
|
263
|
+
self._required_parameters: Final = get_required_parameters()
|
|
264
|
+
self._raw_un_ignores: Final[frozenset[str]] = config_provider.config.un_ignore_list or frozenset()
|
|
265
|
+
self._ignore_custom_device_definition_models: Final[frozenset[ModelName]] = (
|
|
266
|
+
config_provider.config.ignore_custom_device_definition_models
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
# Simple un-ignore: parameter names that apply to all VALUES paramsets
|
|
270
|
+
self._custom_un_ignore_values_parameters: Final[set[ParameterName]] = set()
|
|
271
|
+
|
|
272
|
+
# Complex un-ignore: model -> channel/paramset/parameter rules
|
|
273
|
+
self._custom_un_ignore_rules: Final[ModelRules] = ModelRules()
|
|
274
|
+
|
|
275
|
+
# Device-specific un-ignore rules from RELEVANT_MASTER_PARAMSETS_BY_DEVICE
|
|
276
|
+
self._device_un_ignore_rules: Final[ModelRules] = ModelRules()
|
|
277
|
+
|
|
278
|
+
# Channels that need MASTER paramset fetching
|
|
279
|
+
self._relevant_master_channels: Final[dict[ModelName, set[ChannelNo]]] = {}
|
|
280
|
+
|
|
281
|
+
# Prefix resolution caches
|
|
282
|
+
self._un_ignore_prefix_cache: dict[ModelName, str | None] = {}
|
|
283
|
+
self._relevant_prefix_cache: dict[ModelName, str | None] = {}
|
|
284
|
+
|
|
285
|
+
# Per-instance memoization caches
|
|
286
|
+
self._param_ignored_cache: dict[IgnoreCacheKey, bool] = {}
|
|
287
|
+
self._param_un_ignored_cache: dict[UnIgnoreCacheKey, bool] = {}
|
|
288
|
+
|
|
289
|
+
self._init()
|
|
290
|
+
|
|
291
|
+
@property
|
|
292
|
+
def size(self) -> int:
|
|
293
|
+
"""Return total size of memoization caches."""
|
|
294
|
+
return len(self._param_ignored_cache) + len(self._param_un_ignored_cache)
|
|
295
|
+
|
|
296
|
+
def clear_memoization_caches(self) -> None:
|
|
297
|
+
"""Clear the per-instance memoization caches to free memory."""
|
|
298
|
+
self._param_ignored_cache.clear()
|
|
299
|
+
self._param_un_ignored_cache.clear()
|
|
300
|
+
|
|
301
|
+
def invalidate_all_caches(self) -> None:
|
|
302
|
+
"""Invalidate all caches including prefix resolution caches."""
|
|
303
|
+
self.clear_memoization_caches()
|
|
304
|
+
self._un_ignore_prefix_cache.clear()
|
|
305
|
+
self._relevant_prefix_cache.clear()
|
|
306
|
+
|
|
307
|
+
def is_relevant_paramset(
|
|
308
|
+
self,
|
|
309
|
+
*,
|
|
310
|
+
channel: ChannelProtocol,
|
|
311
|
+
paramset_key: ParamsetKey,
|
|
312
|
+
) -> bool:
|
|
313
|
+
"""
|
|
314
|
+
Return if a paramset is relevant.
|
|
315
|
+
|
|
316
|
+
Required to load MASTER paramsets, which are not initialized by default.
|
|
317
|
+
"""
|
|
318
|
+
if paramset_key == ParamsetKey.VALUES:
|
|
319
|
+
return True
|
|
320
|
+
|
|
321
|
+
if paramset_key == ParamsetKey.MASTER:
|
|
322
|
+
if channel.no in RELEVANT_MASTER_PARAMSETS_BY_CHANNEL:
|
|
323
|
+
return True
|
|
324
|
+
|
|
325
|
+
model_l = channel.device.model.lower()
|
|
326
|
+
dt_short_key = self._resolve_prefix_key(
|
|
327
|
+
model_l=model_l,
|
|
328
|
+
models=self._relevant_master_channels.keys(),
|
|
329
|
+
cache_dict=self._relevant_prefix_cache,
|
|
330
|
+
)
|
|
331
|
+
if dt_short_key is not None:
|
|
332
|
+
return channel.no in self._relevant_master_channels.get(dt_short_key, set())
|
|
333
|
+
|
|
334
|
+
return False
|
|
335
|
+
|
|
336
|
+
def model_is_ignored(self, *, model: ModelName) -> bool:
|
|
337
|
+
"""Check if a model should be ignored for custom data points."""
|
|
338
|
+
return element_matches_key(
|
|
339
|
+
search_elements=self._ignore_custom_device_definition_models,
|
|
340
|
+
compare_with=model,
|
|
341
|
+
)
|
|
342
|
+
|
|
343
|
+
def parameter_is_hidden(
|
|
344
|
+
self,
|
|
345
|
+
*,
|
|
346
|
+
channel: ChannelProtocol,
|
|
347
|
+
paramset_key: ParamsetKey,
|
|
348
|
+
parameter: ParameterName,
|
|
349
|
+
) -> bool:
|
|
350
|
+
"""
|
|
351
|
+
Return if parameter should be hidden.
|
|
352
|
+
|
|
353
|
+
Hidden parameters are created but not displayed by default.
|
|
354
|
+
Returns False if the parameter is on an un-ignore list.
|
|
355
|
+
"""
|
|
356
|
+
return parameter in HIDDEN_PARAMETERS and not self._parameter_is_un_ignored(
|
|
357
|
+
channel=channel,
|
|
358
|
+
paramset_key=paramset_key,
|
|
359
|
+
parameter=parameter,
|
|
360
|
+
)
|
|
361
|
+
|
|
362
|
+
def parameter_is_ignored(
|
|
363
|
+
self,
|
|
364
|
+
*,
|
|
365
|
+
channel: ChannelProtocol,
|
|
366
|
+
paramset_key: ParamsetKey,
|
|
367
|
+
parameter: ParameterName,
|
|
368
|
+
) -> bool:
|
|
369
|
+
"""Check if parameter should be ignored (not created as data point)."""
|
|
370
|
+
model_l = channel.device.model.lower()
|
|
371
|
+
|
|
372
|
+
if (cache_key := IgnoreCacheKey(model_l, channel.no, paramset_key, parameter)) in self._param_ignored_cache:
|
|
373
|
+
return self._param_ignored_cache[cache_key]
|
|
374
|
+
|
|
375
|
+
result = self._check_parameter_is_ignored(
|
|
376
|
+
channel=channel,
|
|
377
|
+
paramset_key=paramset_key,
|
|
378
|
+
parameter=parameter,
|
|
379
|
+
model_l=model_l,
|
|
380
|
+
)
|
|
381
|
+
self._param_ignored_cache[cache_key] = result
|
|
382
|
+
return result
|
|
383
|
+
|
|
384
|
+
def parameter_is_un_ignored(
|
|
385
|
+
self,
|
|
386
|
+
*,
|
|
387
|
+
channel: ChannelProtocol,
|
|
388
|
+
paramset_key: ParamsetKey,
|
|
389
|
+
parameter: ParameterName,
|
|
390
|
+
custom_only: bool = False,
|
|
391
|
+
) -> bool:
|
|
392
|
+
"""
|
|
393
|
+
Return if parameter is on an un-ignore list.
|
|
394
|
+
|
|
395
|
+
Includes both device-specific rules from RELEVANT_MASTER_PARAMSETS_BY_DEVICE
|
|
396
|
+
and custom user-provided un-ignore rules.
|
|
397
|
+
"""
|
|
398
|
+
if not custom_only:
|
|
399
|
+
model_l = channel.device.model.lower()
|
|
400
|
+
dt_short_key = self._resolve_prefix_key(
|
|
401
|
+
model_l=model_l,
|
|
402
|
+
models=self._device_un_ignore_rules.get_models(),
|
|
403
|
+
cache_dict=self._un_ignore_prefix_cache,
|
|
404
|
+
)
|
|
405
|
+
|
|
406
|
+
if dt_short_key is not None and self._device_un_ignore_rules.contains(
|
|
407
|
+
model=dt_short_key,
|
|
408
|
+
channel_no=channel.no,
|
|
409
|
+
paramset_key=paramset_key,
|
|
410
|
+
parameter=parameter,
|
|
411
|
+
):
|
|
412
|
+
return True
|
|
413
|
+
|
|
414
|
+
return self._parameter_is_un_ignored(
|
|
415
|
+
channel=channel,
|
|
416
|
+
paramset_key=paramset_key,
|
|
417
|
+
parameter=parameter,
|
|
418
|
+
custom_only=custom_only,
|
|
419
|
+
)
|
|
420
|
+
|
|
421
|
+
def should_skip_parameter(
|
|
422
|
+
self,
|
|
423
|
+
*,
|
|
424
|
+
channel: ChannelProtocol,
|
|
425
|
+
paramset_key: ParamsetKey,
|
|
426
|
+
parameter: ParameterName,
|
|
427
|
+
parameter_is_un_ignored: bool,
|
|
428
|
+
) -> bool:
|
|
429
|
+
"""Determine if a parameter should be skipped during data point creation."""
|
|
430
|
+
if self.parameter_is_ignored(
|
|
431
|
+
channel=channel,
|
|
432
|
+
paramset_key=paramset_key,
|
|
433
|
+
parameter=parameter,
|
|
434
|
+
):
|
|
435
|
+
_LOGGER.debug(
|
|
436
|
+
"SHOULD_SKIP_PARAMETER: Ignoring parameter: %s [%s]",
|
|
437
|
+
parameter,
|
|
438
|
+
channel.address,
|
|
439
|
+
)
|
|
440
|
+
return True
|
|
441
|
+
|
|
442
|
+
if (
|
|
443
|
+
paramset_key == ParamsetKey.MASTER
|
|
444
|
+
and (parameters := RELEVANT_MASTER_PARAMSETS_BY_CHANNEL.get(channel.no)) is not None
|
|
445
|
+
and parameter in parameters
|
|
446
|
+
):
|
|
447
|
+
return False
|
|
448
|
+
|
|
449
|
+
return paramset_key == ParamsetKey.MASTER and not parameter_is_un_ignored
|
|
450
|
+
|
|
451
|
+
def _check_master_parameter_is_ignored(
|
|
452
|
+
self,
|
|
453
|
+
*,
|
|
454
|
+
channel: ChannelProtocol,
|
|
455
|
+
parameter: ParameterName,
|
|
456
|
+
model_l: ModelName,
|
|
457
|
+
) -> bool:
|
|
458
|
+
"""Check if a MASTER parameter should be ignored."""
|
|
459
|
+
# Check channel-level relevance
|
|
460
|
+
if (parameters := RELEVANT_MASTER_PARAMSETS_BY_CHANNEL.get(channel.no)) is not None and parameter in parameters:
|
|
461
|
+
return False
|
|
462
|
+
|
|
463
|
+
# Check custom un-ignore rules
|
|
464
|
+
if self._custom_un_ignore_rules.contains(
|
|
465
|
+
model=model_l,
|
|
466
|
+
channel_no=channel.no,
|
|
467
|
+
paramset_key=ParamsetKey.MASTER,
|
|
468
|
+
parameter=parameter,
|
|
469
|
+
):
|
|
470
|
+
return False
|
|
471
|
+
|
|
472
|
+
# Check device-specific rules
|
|
473
|
+
dt_short_key = self._resolve_prefix_key(
|
|
474
|
+
model_l=model_l,
|
|
475
|
+
models=self._device_un_ignore_rules.get_models(),
|
|
476
|
+
cache_dict=self._un_ignore_prefix_cache,
|
|
477
|
+
)
|
|
478
|
+
|
|
479
|
+
return dt_short_key is not None and not self._device_un_ignore_rules.contains(
|
|
480
|
+
model=dt_short_key,
|
|
481
|
+
channel_no=channel.no,
|
|
482
|
+
paramset_key=ParamsetKey.MASTER,
|
|
483
|
+
parameter=parameter,
|
|
484
|
+
)
|
|
485
|
+
|
|
486
|
+
def _check_parameter_is_ignored(
|
|
487
|
+
self,
|
|
488
|
+
*,
|
|
489
|
+
channel: ChannelProtocol,
|
|
490
|
+
paramset_key: ParamsetKey,
|
|
491
|
+
parameter: ParameterName,
|
|
492
|
+
model_l: ModelName,
|
|
493
|
+
) -> bool:
|
|
494
|
+
"""Check if a parameter is ignored based on paramset type."""
|
|
495
|
+
if paramset_key == ParamsetKey.VALUES:
|
|
496
|
+
return self._check_values_parameter_is_ignored(
|
|
497
|
+
channel=channel,
|
|
498
|
+
parameter=parameter,
|
|
499
|
+
model_l=model_l,
|
|
500
|
+
)
|
|
501
|
+
|
|
502
|
+
if paramset_key == ParamsetKey.MASTER:
|
|
503
|
+
return self._check_master_parameter_is_ignored(
|
|
504
|
+
channel=channel,
|
|
505
|
+
parameter=parameter,
|
|
506
|
+
model_l=model_l,
|
|
507
|
+
)
|
|
508
|
+
|
|
509
|
+
return False
|
|
510
|
+
|
|
511
|
+
def _check_parameter_is_un_ignored(
|
|
512
|
+
self,
|
|
513
|
+
*,
|
|
514
|
+
channel: ChannelProtocol,
|
|
515
|
+
paramset_key: ParamsetKey,
|
|
516
|
+
parameter: ParameterName,
|
|
517
|
+
model_l: ModelName,
|
|
518
|
+
custom_only: bool,
|
|
519
|
+
) -> bool:
|
|
520
|
+
"""Check if a parameter matches any un-ignore rule."""
|
|
521
|
+
# Build search matrix for wildcard matching
|
|
522
|
+
search_patterns: tuple[tuple[ModelName, UnIgnoreChannelNo], ...]
|
|
523
|
+
if paramset_key == ParamsetKey.VALUES:
|
|
524
|
+
search_patterns = (
|
|
525
|
+
(model_l, channel.no),
|
|
526
|
+
(model_l, UN_IGNORE_WILDCARD),
|
|
527
|
+
(UN_IGNORE_WILDCARD, channel.no),
|
|
528
|
+
(UN_IGNORE_WILDCARD, UN_IGNORE_WILDCARD),
|
|
529
|
+
)
|
|
530
|
+
else:
|
|
531
|
+
search_patterns = ((model_l, channel.no),)
|
|
532
|
+
|
|
533
|
+
# Check custom rules
|
|
534
|
+
for ml, cno in search_patterns:
|
|
535
|
+
if self._custom_un_ignore_rules.contains(
|
|
536
|
+
model=ml,
|
|
537
|
+
channel_no=cno,
|
|
538
|
+
paramset_key=paramset_key,
|
|
539
|
+
parameter=parameter,
|
|
540
|
+
):
|
|
541
|
+
return True
|
|
542
|
+
|
|
543
|
+
# Check predefined un-ignore parameters
|
|
544
|
+
if not custom_only:
|
|
545
|
+
un_ignore_parameters = _get_parameters_for_model_prefix(model_prefix=model_l)
|
|
546
|
+
if un_ignore_parameters and parameter in un_ignore_parameters:
|
|
547
|
+
return True
|
|
548
|
+
|
|
549
|
+
return False
|
|
550
|
+
|
|
551
|
+
def _check_values_parameter_is_ignored(
|
|
552
|
+
self,
|
|
553
|
+
*,
|
|
554
|
+
channel: ChannelProtocol,
|
|
555
|
+
parameter: ParameterName,
|
|
556
|
+
model_l: ModelName,
|
|
557
|
+
) -> bool:
|
|
558
|
+
"""Check if a VALUES parameter should be ignored."""
|
|
559
|
+
# Check if un-ignored first
|
|
560
|
+
if self.parameter_is_un_ignored(
|
|
561
|
+
channel=channel,
|
|
562
|
+
paramset_key=ParamsetKey.VALUES,
|
|
563
|
+
parameter=parameter,
|
|
564
|
+
):
|
|
565
|
+
return False
|
|
566
|
+
|
|
567
|
+
# Check static ignore lists
|
|
568
|
+
if (
|
|
569
|
+
parameter in IGNORED_PARAMETERS or parameter_is_wildcard_ignored(parameter=parameter)
|
|
570
|
+
) and parameter not in self._required_parameters:
|
|
571
|
+
return True
|
|
572
|
+
|
|
573
|
+
# Check device-specific ignore lists
|
|
574
|
+
if hms.element_matches_key(
|
|
575
|
+
search_elements=IGNORE_PARAMETERS_BY_DEVICE_LOWER.get(parameter, []),
|
|
576
|
+
compare_with=model_l,
|
|
577
|
+
):
|
|
578
|
+
return True
|
|
579
|
+
|
|
580
|
+
# Check event suppression
|
|
581
|
+
if hms.element_matches_key(
|
|
582
|
+
search_elements=IGNORE_DEVICES_FOR_DATA_POINT_EVENTS_LOWER,
|
|
583
|
+
compare_with=parameter,
|
|
584
|
+
search_key=model_l,
|
|
585
|
+
do_right_wildcard_search=False,
|
|
586
|
+
):
|
|
587
|
+
return True
|
|
588
|
+
|
|
589
|
+
# Check channel-specific parameter rules
|
|
590
|
+
accept_channel = ACCEPT_PARAMETER_ONLY_ON_CHANNEL.get(parameter)
|
|
591
|
+
return accept_channel is not None and accept_channel != channel.no
|
|
592
|
+
|
|
593
|
+
def _init(self) -> None:
|
|
594
|
+
"""Initialize the registry with static and configured rules."""
|
|
595
|
+
# Load device-specific rules from RELEVANT_MASTER_PARAMSETS_BY_DEVICE
|
|
596
|
+
for model, (channel_nos, parameters) in RELEVANT_MASTER_PARAMSETS_BY_DEVICE.items():
|
|
597
|
+
model_l = model.lower()
|
|
598
|
+
|
|
599
|
+
effective_channels = channel_nos if channel_nos else frozenset({None})
|
|
600
|
+
for channel_no in effective_channels:
|
|
601
|
+
# Track relevant channels for MASTER paramset fetching
|
|
602
|
+
if model_l not in self._relevant_master_channels:
|
|
603
|
+
self._relevant_master_channels[model_l] = set()
|
|
604
|
+
self._relevant_master_channels[model_l].add(channel_no)
|
|
605
|
+
|
|
606
|
+
# Add un-ignore rules
|
|
607
|
+
self._device_un_ignore_rules.update_parameters(
|
|
608
|
+
model=model_l,
|
|
609
|
+
channel_no=channel_no,
|
|
610
|
+
paramset_key=ParamsetKey.MASTER,
|
|
611
|
+
parameters=parameters,
|
|
612
|
+
)
|
|
613
|
+
|
|
614
|
+
# Process user-provided un-ignore entries
|
|
615
|
+
self._process_un_ignore_entries(lines=self._raw_un_ignores)
|
|
616
|
+
|
|
617
|
+
def _parameter_is_un_ignored(
|
|
618
|
+
self,
|
|
619
|
+
*,
|
|
620
|
+
channel: ChannelProtocol,
|
|
621
|
+
paramset_key: ParamsetKey,
|
|
622
|
+
parameter: ParameterName,
|
|
623
|
+
custom_only: bool = False,
|
|
624
|
+
) -> bool:
|
|
625
|
+
"""
|
|
626
|
+
Check if parameter is on a custom un-ignore list.
|
|
627
|
+
|
|
628
|
+
This can be either the user's un-ignore configuration or the
|
|
629
|
+
predefined UN_IGNORE_PARAMETERS_BY_DEVICE.
|
|
630
|
+
"""
|
|
631
|
+
# Fast path: simple VALUES parameter un-ignore
|
|
632
|
+
if paramset_key == ParamsetKey.VALUES and parameter in self._custom_un_ignore_values_parameters:
|
|
633
|
+
return True
|
|
634
|
+
|
|
635
|
+
model_l = channel.device.model.lower()
|
|
636
|
+
cache_key = UnIgnoreCacheKey(model_l, channel.no, paramset_key, parameter, custom_only)
|
|
637
|
+
|
|
638
|
+
if cache_key in self._param_un_ignored_cache:
|
|
639
|
+
return self._param_un_ignored_cache[cache_key]
|
|
640
|
+
|
|
641
|
+
result = self._check_parameter_is_un_ignored(
|
|
642
|
+
channel=channel,
|
|
643
|
+
paramset_key=paramset_key,
|
|
644
|
+
parameter=parameter,
|
|
645
|
+
model_l=model_l,
|
|
646
|
+
custom_only=custom_only,
|
|
647
|
+
)
|
|
648
|
+
self._param_un_ignored_cache[cache_key] = result
|
|
649
|
+
return result
|
|
650
|
+
|
|
651
|
+
def _process_complex_un_ignore_entry(self, *, parsed: ParsedUnIgnoreLine) -> None:
|
|
652
|
+
"""Process a complex un-ignore entry."""
|
|
653
|
+
entry = parsed.entry
|
|
654
|
+
assert entry is not None # noqa: S101
|
|
655
|
+
|
|
656
|
+
# Track MASTER channels for paramset fetching
|
|
657
|
+
if entry.paramset_key == ParamsetKey.MASTER and (isinstance(entry.channel_no, int) or entry.channel_no is None):
|
|
658
|
+
if entry.model not in self._relevant_master_channels:
|
|
659
|
+
self._relevant_master_channels[entry.model] = set()
|
|
660
|
+
self._relevant_master_channels[entry.model].add(entry.channel_no)
|
|
661
|
+
|
|
662
|
+
self._custom_un_ignore_rules.add_parameter(
|
|
663
|
+
model=entry.model,
|
|
664
|
+
channel_no=entry.channel_no,
|
|
665
|
+
paramset_key=entry.paramset_key,
|
|
666
|
+
parameter=entry.parameter,
|
|
667
|
+
)
|
|
668
|
+
|
|
669
|
+
def _process_un_ignore_entries(self, *, lines: Iterable[str]) -> None:
|
|
670
|
+
"""Process un-ignore configuration entries into the registry."""
|
|
671
|
+
for line in lines:
|
|
672
|
+
if not line.strip():
|
|
673
|
+
continue
|
|
674
|
+
|
|
675
|
+
parsed = parse_un_ignore_line(line=line)
|
|
676
|
+
|
|
677
|
+
if parsed.is_error:
|
|
678
|
+
_LOGGER.error( # i18n-log: ignore
|
|
679
|
+
"PROCESS_UN_IGNORE_ENTRY failed: %s",
|
|
680
|
+
parsed.error,
|
|
681
|
+
)
|
|
682
|
+
elif parsed.is_simple:
|
|
683
|
+
self._custom_un_ignore_values_parameters.add(parsed.simple_parameter) # type: ignore[arg-type]
|
|
684
|
+
elif parsed.is_complex:
|
|
685
|
+
self._process_complex_un_ignore_entry(parsed=parsed)
|
|
686
|
+
|
|
687
|
+
def _resolve_prefix_key(
|
|
688
|
+
self,
|
|
689
|
+
*,
|
|
690
|
+
model_l: ModelName,
|
|
691
|
+
models: Iterable[ModelName],
|
|
692
|
+
cache_dict: dict[ModelName, str | None],
|
|
693
|
+
) -> str | None:
|
|
694
|
+
"""Resolve and memoize the first model key that is a prefix of model_l."""
|
|
695
|
+
if model_l in cache_dict:
|
|
696
|
+
return cache_dict[model_l]
|
|
697
|
+
|
|
698
|
+
dt_short_key = next((k for k in models if model_l.startswith(k)), None)
|
|
699
|
+
cache_dict[model_l] = dt_short_key
|
|
700
|
+
return dt_short_key
|
|
701
|
+
|
|
702
|
+
|
|
703
|
+
# =============================================================================
|
|
704
|
+
# Validation Helper
|
|
705
|
+
# =============================================================================
|
|
706
|
+
|
|
707
|
+
|
|
708
|
+
def check_ignore_parameters_is_clean() -> bool:
|
|
709
|
+
"""Check if any required parameter is incorrectly in the ignored parameters list."""
|
|
710
|
+
un_ignore_parameters_by_device: list[str] = []
|
|
711
|
+
for params in UN_IGNORE_PARAMETERS_BY_MODEL_LOWER.values():
|
|
712
|
+
un_ignore_parameters_by_device.extend(params)
|
|
713
|
+
|
|
714
|
+
required = get_required_parameters()
|
|
715
|
+
conflicting = [
|
|
716
|
+
parameter
|
|
717
|
+
for parameter in required
|
|
718
|
+
if (parameter in IGNORED_PARAMETERS or parameter_is_wildcard_ignored(parameter=parameter))
|
|
719
|
+
and parameter not in un_ignore_parameters_by_device
|
|
720
|
+
]
|
|
721
|
+
|
|
722
|
+
return len(conflicting) == 0
|