Add filter options to entity and device selectors (#87536)

* Add support for multiple device classes

* Add support for entity filter selector

* Add support for device filter selector

* Apply suggestions

* Fix wrong property name

* Update snapshot

---------

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
This commit is contained in:
Paul Bottein
2023-02-27 10:38:18 -05:00
committed by GitHub
co-authored by Paulus Schoutsen
parent ac70612ec5
commit e95944bf9f
3 changed files with 170 additions and 31 deletions
+47 -22
View File
@@ -79,27 +79,27 @@ class Selector(Generic[_T]):
return {"selector": {self.selector_type: self.config}}
SINGLE_ENTITY_SELECTOR_CONFIG_SCHEMA = vol.Schema(
ENTITY_FILTER_SELECTOR_CONFIG_SCHEMA = vol.Schema(
{
# Integration that provided the entity
vol.Optional("integration"): str,
# Domain the entity belongs to
vol.Optional("domain"): vol.Any(str, [str]),
vol.Optional("domain"): vol.All(cv.ensure_list, [str]),
# Device class of the entity
vol.Optional("device_class"): str,
vol.Optional("device_class"): vol.All(cv.ensure_list, [str]),
}
)
class SingleEntitySelectorConfig(TypedDict, total=False):
class EntityFilterSelectorConfig(TypedDict, total=False):
"""Class to represent a single entity selector config."""
integration: str
domain: str | list[str]
device_class: str
device_class: str | list[str]
SINGLE_DEVICE_SELECTOR_CONFIG_SCHEMA = vol.Schema(
DEVICE_FILTER_SELECTOR_CONFIG_SCHEMA = vol.Schema(
{
# Integration linked to it with a config entry
vol.Optional("integration"): str,
@@ -108,18 +108,21 @@ SINGLE_DEVICE_SELECTOR_CONFIG_SCHEMA = vol.Schema(
# Model of device
vol.Optional("model"): str,
# Device has to contain entities matching this selector
vol.Optional("entity"): SINGLE_ENTITY_SELECTOR_CONFIG_SCHEMA,
vol.Optional("entity"): vol.All(
cv.ensure_list, [ENTITY_FILTER_SELECTOR_CONFIG_SCHEMA]
),
}
)
class SingleDeviceSelectorConfig(TypedDict, total=False):
class DeviceFilterSelectorConfig(TypedDict, total=False):
"""Class to represent a single device selector config."""
integration: str
manufacturer: str
model: str
entity: SingleEntitySelectorConfig
entity: EntityFilterSelectorConfig | list[EntityFilterSelectorConfig]
filter: DeviceFilterSelectorConfig | list[DeviceFilterSelectorConfig]
class ActionSelectorConfig(TypedDict):
@@ -176,8 +179,8 @@ class AddonSelector(Selector[AddonSelectorConfig]):
class AreaSelectorConfig(TypedDict, total=False):
"""Class to represent an area selector config."""
entity: SingleEntitySelectorConfig
device: SingleDeviceSelectorConfig
entity: EntityFilterSelectorConfig | list[EntityFilterSelectorConfig]
device: DeviceFilterSelectorConfig | list[DeviceFilterSelectorConfig]
multiple: bool
@@ -189,8 +192,14 @@ class AreaSelector(Selector[AreaSelectorConfig]):
CONFIG_SCHEMA = vol.Schema(
{
vol.Optional("entity"): SINGLE_ENTITY_SELECTOR_CONFIG_SCHEMA,
vol.Optional("device"): SINGLE_DEVICE_SELECTOR_CONFIG_SCHEMA,
vol.Optional("entity"): vol.All(
cv.ensure_list,
[ENTITY_FILTER_SELECTOR_CONFIG_SCHEMA],
),
vol.Optional("device"): vol.All(
cv.ensure_list,
[DEVICE_FILTER_SELECTOR_CONFIG_SCHEMA],
),
vol.Optional("multiple", default=False): cv.boolean,
}
)
@@ -399,7 +408,7 @@ class DeviceSelectorConfig(TypedDict, total=False):
integration: str
manufacturer: str
model: str
entity: SingleEntitySelectorConfig
entity: EntityFilterSelectorConfig | list[EntityFilterSelectorConfig]
multiple: bool
@@ -409,8 +418,14 @@ class DeviceSelector(Selector[DeviceSelectorConfig]):
selector_type = "device"
CONFIG_SCHEMA = SINGLE_DEVICE_SELECTOR_CONFIG_SCHEMA.extend(
{vol.Optional("multiple", default=False): cv.boolean}
CONFIG_SCHEMA = DEVICE_FILTER_SELECTOR_CONFIG_SCHEMA.extend(
{
vol.Optional("multiple", default=False): cv.boolean,
vol.Optional("filter"): vol.All(
cv.ensure_list,
[DEVICE_FILTER_SELECTOR_CONFIG_SCHEMA],
),
},
)
def __init__(self, config: DeviceSelectorConfig | None = None) -> None:
@@ -457,7 +472,7 @@ class DurationSelector(Selector[DurationSelectorConfig]):
return cast(dict[str, float], data)
class EntitySelectorConfig(SingleEntitySelectorConfig, total=False):
class EntitySelectorConfig(EntityFilterSelectorConfig, total=False):
"""Class to represent an entity selector config."""
exclude_entities: list[str]
@@ -471,11 +486,15 @@ class EntitySelector(Selector[EntitySelectorConfig]):
selector_type = "entity"
CONFIG_SCHEMA = SINGLE_ENTITY_SELECTOR_CONFIG_SCHEMA.extend(
CONFIG_SCHEMA = ENTITY_FILTER_SELECTOR_CONFIG_SCHEMA.extend(
{
vol.Optional("exclude_entities"): [str],
vol.Optional("include_entities"): [str],
vol.Optional("multiple", default=False): cv.boolean,
vol.Optional("filter"): vol.All(
cv.ensure_list,
[ENTITY_FILTER_SELECTOR_CONFIG_SCHEMA],
),
}
)
@@ -784,8 +803,8 @@ class SelectSelector(Selector[SelectSelectorConfig]):
class TargetSelectorConfig(TypedDict, total=False):
"""Class to represent a target selector config."""
entity: SingleEntitySelectorConfig
device: SingleDeviceSelectorConfig
entity: EntityFilterSelectorConfig | list[EntityFilterSelectorConfig]
device: DeviceFilterSelectorConfig | list[DeviceFilterSelectorConfig]
class StateSelectorConfig(TypedDict, total=False):
@@ -832,8 +851,14 @@ class TargetSelector(Selector[TargetSelectorConfig]):
CONFIG_SCHEMA = vol.Schema(
{
vol.Optional("entity"): SINGLE_ENTITY_SELECTOR_CONFIG_SCHEMA,
vol.Optional("device"): SINGLE_DEVICE_SELECTOR_CONFIG_SCHEMA,
vol.Optional("entity"): vol.All(
cv.ensure_list,
[ENTITY_FILTER_SELECTOR_CONFIG_SCHEMA],
),
vol.Optional("device"): vol.All(
cv.ensure_list,
[DEVICE_FILTER_SELECTOR_CONFIG_SCHEMA],
),
}
)