diff --git a/homeassistant/helpers/selector.py b/homeassistant/helpers/selector.py index 5936aadf2cd0..268cc67e8490 100644 --- a/homeassistant/helpers/selector.py +++ b/homeassistant/helpers/selector.py @@ -245,6 +245,26 @@ class DeviceFilterSelectorConfig(TypedDict, total=False): model_id: str +ENTITY_WITH_DEVICE_FILTER_SELECTOR_CONFIG_SCHEMA = ( + ENTITY_FILTER_SELECTOR_CONFIG_SCHEMA.extend( + { + # Filter on properties of the device the entity belongs to + vol.Optional("device"): DEVICE_FILTER_SELECTOR_CONFIG_SCHEMA, + } + ) +) + + +class EntityWithDeviceFilterSelectorConfig(EntityFilterSelectorConfig, total=False): + """Class to represent an entity selector filter config. + + Adds device filtering on top of the shared entity filter, only used by + the entity selector. + """ + + device: DeviceFilterSelectorConfig + + class ActionSelectorConfig(BaseSelectorConfig): """Class to represent an action selector config.""" @@ -985,7 +1005,10 @@ class EntitySelectorConfig( include_entities: list[str] multiple: bool reorder: bool - filter: EntityFilterSelectorConfig | list[EntityFilterSelectorConfig] + filter: ( + EntityWithDeviceFilterSelectorConfig + | list[EntityWithDeviceFilterSelectorConfig] + ) @SELECTORS.register("entity") @@ -1004,7 +1027,7 @@ class EntitySelector(Selector[EntitySelectorConfig]): vol.Optional("reorder", default=False): cv.boolean, vol.Optional("filter"): vol.All( cv.ensure_list, - [ENTITY_FILTER_SELECTOR_CONFIG_SCHEMA], + [ENTITY_WITH_DEVICE_FILTER_SELECTOR_CONFIG_SCHEMA], ), } ), diff --git a/tests/helpers/test_selector.py b/tests/helpers/test_selector.py index 95bbaaad87fc..9d8a2e764487 100644 --- a/tests/helpers/test_selector.py +++ b/tests/helpers/test_selector.py @@ -300,6 +300,38 @@ def test_device_selector_schema_error(schema) -> None: ( { "filter": [ + { + "device": { + "manufacturer": "mock-manuf", + "model": "mock-model", + "model_id": "mock-model_id", + } + } + ] + }, + ("light.abc123", "blah.blah", FAKE_UUID), + (None,), + ), + ( + { + "filter": [ + { + "domain": "binary_sensor", + "device": { + "integration": "zha", + "manufacturer": "mock-manuf", + "model": "mock-model", + "model_id": "mock-model_id", + }, + }, + { + "device": { + "integration": "matter", + "manufacturer": "other-mock-manuf", + "model": "other-mock-model", + "model_id": "other-mock-model_id", + }, + }, {"unit_of_measurement": "baguette"}, ] }, @@ -341,6 +373,10 @@ def test_entity_selector_schema(schema, valid_selections, invalid_selections) -> {"unit_of_measurement": ["currywurst", "bratwurst"]}, # Invalid unit_of_measurement {"filter": [{"unit_of_measurement": 42}]}, + # Device properties must be grouped under the device key + {"filter": [{"manufacturer": "mock-manuf"}]}, + {"filter": [{"model": "mock-model"}]}, + {"filter": [{"model_id": "mock-model_id"}]}, # reorder can only be used when multiple is true {"reorder": True}, {"reorder": True, "multiple": False},