mirror of
https://github.com/home-assistant/core.git
synced 2025-07-20 03:37:07 +00:00
Fix entity and device selectors (#148580)
This commit is contained in:
parent
8bd51a7fd1
commit
3e0628cec2
@ -15,9 +15,10 @@ generate_data:
|
|||||||
required: false
|
required: false
|
||||||
selector:
|
selector:
|
||||||
entity:
|
entity:
|
||||||
domain: ai_task
|
filter:
|
||||||
supported_features:
|
domain: ai_task
|
||||||
- ai_task.AITaskEntityFeature.GENERATE_DATA
|
supported_features:
|
||||||
|
- ai_task.AITaskEntityFeature.GENERATE_DATA
|
||||||
structure:
|
structure:
|
||||||
advanced: true
|
advanced: true
|
||||||
required: false
|
required: false
|
||||||
|
@ -68,9 +68,10 @@ ask_question:
|
|||||||
required: true
|
required: true
|
||||||
selector:
|
selector:
|
||||||
entity:
|
entity:
|
||||||
domain: assist_satellite
|
filter:
|
||||||
supported_features:
|
domain: assist_satellite
|
||||||
- assist_satellite.AssistSatelliteEntityFeature.START_CONVERSATION
|
supported_features:
|
||||||
|
- assist_satellite.AssistSatelliteEntityFeature.START_CONVERSATION
|
||||||
question:
|
question:
|
||||||
required: false
|
required: false
|
||||||
example: "What kind of music would you like to play?"
|
example: "What kind of music would you like to play?"
|
||||||
|
@ -160,6 +160,22 @@ ENTITY_FILTER_SELECTOR_CONFIG_SCHEMA = vol.Schema(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Legacy entity selector config schema used directly under entity selectors
|
||||||
|
# is provided for backwards compatibility and remains feature frozen.
|
||||||
|
# New filtering features should be added under the `filter` key instead.
|
||||||
|
# https://github.com/home-assistant/frontend/pull/15302
|
||||||
|
LEGACY_ENTITY_SELECTOR_CONFIG_SCHEMA = vol.Schema(
|
||||||
|
{
|
||||||
|
# Integration that provided the entity
|
||||||
|
vol.Optional("integration"): str,
|
||||||
|
# Domain the entity belongs to
|
||||||
|
vol.Optional("domain"): vol.All(cv.ensure_list, [str]),
|
||||||
|
# Device class of the entity
|
||||||
|
vol.Optional("device_class"): vol.All(cv.ensure_list, [str]),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class EntityFilterSelectorConfig(TypedDict, total=False):
|
class EntityFilterSelectorConfig(TypedDict, total=False):
|
||||||
"""Class to represent a single entity selector config."""
|
"""Class to represent a single entity selector config."""
|
||||||
|
|
||||||
@ -179,10 +195,22 @@ DEVICE_FILTER_SELECTOR_CONFIG_SCHEMA = vol.Schema(
|
|||||||
vol.Optional("model"): str,
|
vol.Optional("model"): str,
|
||||||
# Model ID of device
|
# Model ID of device
|
||||||
vol.Optional("model_id"): str,
|
vol.Optional("model_id"): str,
|
||||||
# Device has to contain entities matching this selector
|
}
|
||||||
vol.Optional("entity"): vol.All(
|
)
|
||||||
cv.ensure_list, [ENTITY_FILTER_SELECTOR_CONFIG_SCHEMA]
|
|
||||||
),
|
|
||||||
|
# Legacy device selector config schema used directly under device selectors
|
||||||
|
# is provided for backwards compatibility and remains feature frozen.
|
||||||
|
# New filtering features should be added under the `filter` key instead.
|
||||||
|
# https://github.com/home-assistant/frontend/pull/15302
|
||||||
|
LEGACY_DEVICE_SELECTOR_CONFIG_SCHEMA = vol.Schema(
|
||||||
|
{
|
||||||
|
# Integration linked to it with a config entry
|
||||||
|
vol.Optional("integration"): str,
|
||||||
|
# Manufacturer of device
|
||||||
|
vol.Optional("manufacturer"): str,
|
||||||
|
# Model of device
|
||||||
|
vol.Optional("model"): str,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -714,9 +742,13 @@ class DeviceSelector(Selector[DeviceSelectorConfig]):
|
|||||||
selector_type = "device"
|
selector_type = "device"
|
||||||
|
|
||||||
CONFIG_SCHEMA = BASE_SELECTOR_CONFIG_SCHEMA.extend(
|
CONFIG_SCHEMA = BASE_SELECTOR_CONFIG_SCHEMA.extend(
|
||||||
DEVICE_FILTER_SELECTOR_CONFIG_SCHEMA.schema
|
LEGACY_DEVICE_SELECTOR_CONFIG_SCHEMA.schema
|
||||||
).extend(
|
).extend(
|
||||||
{
|
{
|
||||||
|
# Device has to contain entities matching this selector
|
||||||
|
vol.Optional("entity"): vol.All(
|
||||||
|
cv.ensure_list, [ENTITY_FILTER_SELECTOR_CONFIG_SCHEMA]
|
||||||
|
),
|
||||||
vol.Optional("multiple", default=False): cv.boolean,
|
vol.Optional("multiple", default=False): cv.boolean,
|
||||||
vol.Optional("filter"): vol.All(
|
vol.Optional("filter"): vol.All(
|
||||||
cv.ensure_list,
|
cv.ensure_list,
|
||||||
@ -794,7 +826,7 @@ class EntitySelector(Selector[EntitySelectorConfig]):
|
|||||||
selector_type = "entity"
|
selector_type = "entity"
|
||||||
|
|
||||||
CONFIG_SCHEMA = BASE_SELECTOR_CONFIG_SCHEMA.extend(
|
CONFIG_SCHEMA = BASE_SELECTOR_CONFIG_SCHEMA.extend(
|
||||||
ENTITY_FILTER_SELECTOR_CONFIG_SCHEMA.schema
|
LEGACY_ENTITY_SELECTOR_CONFIG_SCHEMA.schema
|
||||||
).extend(
|
).extend(
|
||||||
{
|
{
|
||||||
vol.Optional("exclude_entities"): [str],
|
vol.Optional("exclude_entities"): [str],
|
||||||
|
@ -88,7 +88,6 @@ def _test_selector(
|
|||||||
({"integration": "zha"}, ("abc123",), (None,)),
|
({"integration": "zha"}, ("abc123",), (None,)),
|
||||||
({"manufacturer": "mock-manuf"}, ("abc123",), (None,)),
|
({"manufacturer": "mock-manuf"}, ("abc123",), (None,)),
|
||||||
({"model": "mock-model"}, ("abc123",), (None,)),
|
({"model": "mock-model"}, ("abc123",), (None,)),
|
||||||
({"model_id": "mock-model_id"}, ("abc123",), (None,)),
|
|
||||||
({"manufacturer": "mock-manuf", "model": "mock-model"}, ("abc123",), (None,)),
|
({"manufacturer": "mock-manuf", "model": "mock-model"}, ("abc123",), (None,)),
|
||||||
(
|
(
|
||||||
{"integration": "zha", "manufacturer": "mock-manuf", "model": "mock-model"},
|
{"integration": "zha", "manufacturer": "mock-manuf", "model": "mock-model"},
|
||||||
@ -128,6 +127,7 @@ def _test_selector(
|
|||||||
"integration": "zha",
|
"integration": "zha",
|
||||||
"manufacturer": "mock-manuf",
|
"manufacturer": "mock-manuf",
|
||||||
"model": "mock-model",
|
"model": "mock-model",
|
||||||
|
"model_id": "mock-model_id",
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
("abc123",),
|
("abc123",),
|
||||||
@ -140,11 +140,13 @@ def _test_selector(
|
|||||||
"integration": "zha",
|
"integration": "zha",
|
||||||
"manufacturer": "mock-manuf",
|
"manufacturer": "mock-manuf",
|
||||||
"model": "mock-model",
|
"model": "mock-model",
|
||||||
|
"model_id": "mock-model_id",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"integration": "matter",
|
"integration": "matter",
|
||||||
"manufacturer": "other-mock-manuf",
|
"manufacturer": "other-mock-manuf",
|
||||||
"model": "other-mock-model",
|
"model": "other-mock-model",
|
||||||
|
"model_id": "other-mock-model_id",
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -158,6 +160,19 @@ def test_device_selector_schema(schema, valid_selections, invalid_selections) ->
|
|||||||
_test_selector("device", schema, valid_selections, invalid_selections)
|
_test_selector("device", schema, valid_selections, invalid_selections)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"schema",
|
||||||
|
[
|
||||||
|
# model_id should be used under the filter key
|
||||||
|
{"model_id": "mock-model_id"},
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_device_selector_schema_error(schema) -> None:
|
||||||
|
"""Test device selector."""
|
||||||
|
with pytest.raises(vol.Invalid):
|
||||||
|
selector.validate_selector({"device": schema})
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
("schema", "valid_selections", "invalid_selections"),
|
("schema", "valid_selections", "invalid_selections"),
|
||||||
[
|
[
|
||||||
@ -290,10 +305,12 @@ def test_entity_selector_schema(schema, valid_selections, invalid_selections) ->
|
|||||||
{"filter": [{"supported_features": ["light.FooEntityFeature.blah"]}]},
|
{"filter": [{"supported_features": ["light.FooEntityFeature.blah"]}]},
|
||||||
# Unknown feature enum member
|
# Unknown feature enum member
|
||||||
{"filter": [{"supported_features": ["light.LightEntityFeature.blah"]}]},
|
{"filter": [{"supported_features": ["light.LightEntityFeature.blah"]}]},
|
||||||
|
# supported_features should be used under the filter key
|
||||||
|
{"supported_features": ["light.LightEntityFeature.EFFECT"]},
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_entity_selector_schema_error(schema) -> None:
|
def test_entity_selector_schema_error(schema) -> None:
|
||||||
"""Test number selector."""
|
"""Test entity selector."""
|
||||||
with pytest.raises(vol.Invalid):
|
with pytest.raises(vol.Invalid):
|
||||||
selector.validate_selector({"entity": schema})
|
selector.validate_selector({"entity": schema})
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user