Support readonly selectors in config_flows (#129456)

* Allow disabled selectors in config flows. Show hidden options for history_stats.

* fix tests

* use optional instead of required

* rename flag to readonly

* rename to read_only

* Update to use read_only field as part of selector definition

* lint fix

* Fix test

* All selectors
This commit is contained in:
karwosts 2025-05-23 08:05:43 -07:00 committed by GitHub
parent 83ec45e4fc
commit 7af731694f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 123 additions and 74 deletions

View File

@ -18,6 +18,7 @@ from homeassistant.helpers.selector import (
DurationSelector,
DurationSelectorConfig,
EntitySelector,
EntitySelectorConfig,
SelectSelector,
SelectSelectorConfig,
SelectSelectorMode,
@ -66,6 +67,20 @@ DATA_SCHEMA_SETUP = vol.Schema(
)
DATA_SCHEMA_OPTIONS = vol.Schema(
{
vol.Optional(CONF_ENTITY_ID): EntitySelector(
EntitySelectorConfig(read_only=True)
),
vol.Optional(CONF_STATE): TextSelector(
TextSelectorConfig(multiple=True, read_only=True)
),
vol.Optional(CONF_TYPE): SelectSelector(
SelectSelectorConfig(
options=CONF_TYPE_KEYS,
mode=SelectSelectorMode.DROPDOWN,
translation_key=CONF_TYPE,
read_only=True,
)
),
vol.Optional(CONF_START): TemplateSelector(),
vol.Optional(CONF_END): TemplateSelector(),
vol.Optional(CONF_DURATION): DurationSelector(

View File

@ -26,11 +26,17 @@
"options": {
"description": "Read the documentation for further details on how to configure the history stats sensor using these options.",
"data": {
"entity_id": "[%key:component::history_stats::config::step::user::data::entity_id%]",
"state": "[%key:component::history_stats::config::step::user::data::state%]",
"type": "[%key:component::history_stats::config::step::user::data::type%]",
"start": "Start",
"end": "End",
"duration": "Duration"
},
"data_description": {
"entity_id": "[%key:component::history_stats::config::step::user::data_description::entity_id%]",
"state": "[%key:component::history_stats::config::step::user::data_description::state%]",
"type": "[%key:component::history_stats::config::step::user::data_description::type%]",
"start": "When to start the measure (timestamp or datetime). Can be a template.",
"end": "When to stop the measure (timestamp or datetime). Can be a template",
"duration": "Duration of the measure."
@ -49,11 +55,17 @@
"init": {
"description": "[%key:component::history_stats::config::step::options::description%]",
"data": {
"entity_id": "[%key:component::history_stats::config::step::user::data::entity_id%]",
"state": "[%key:component::history_stats::config::step::user::data::state%]",
"type": "[%key:component::history_stats::config::step::user::data::type%]",
"start": "[%key:component::history_stats::config::step::options::data::start%]",
"end": "[%key:component::history_stats::config::step::options::data::end%]",
"duration": "[%key:component::history_stats::config::step::options::data::duration%]"
},
"data_description": {
"entity_id": "[%key:component::history_stats::config::step::user::data_description::entity_id%]",
"state": "[%key:component::history_stats::config::step::user::data_description::state%]",
"type": "[%key:component::history_stats::config::step::user::data_description::type%]",
"start": "[%key:component::history_stats::config::step::options::data_description::start%]",
"end": "[%key:component::history_stats::config::step::options::data_description::end%]",
"duration": "[%key:component::history_stats::config::step::options::data_description::duration%]"

View File

@ -214,6 +214,11 @@ class SchemaCommonFlowHandler:
and key.description.get("advanced")
and not self._handler.show_advanced_options
)
and not (
# don't remove read_only keys
isinstance(data_schema.schema[key], selector.Selector)
and data_schema.schema[key].config.get("read_only")
)
):
# Key not present, delete keys old value (if present) too
values.pop(key.schema, None)

View File

@ -131,6 +131,19 @@ def _validate_supported_features(supported_features: int | list[str]) -> int:
return feature_mask
BASE_SELECTOR_CONFIG_SCHEMA = vol.Schema(
{
vol.Optional("read_only"): bool,
}
)
class BaseSelectorConfig(TypedDict, total=False):
"""Class to common options of all selectors."""
read_only: bool
ENTITY_FILTER_SELECTOR_CONFIG_SCHEMA = vol.Schema(
{
# Integration that provided the entity
@ -183,7 +196,7 @@ class DeviceFilterSelectorConfig(TypedDict, total=False):
model_id: str
class ActionSelectorConfig(TypedDict):
class ActionSelectorConfig(BaseSelectorConfig):
"""Class to represent an action selector config."""
@ -193,7 +206,7 @@ class ActionSelector(Selector[ActionSelectorConfig]):
selector_type = "action"
CONFIG_SCHEMA = vol.Schema({})
CONFIG_SCHEMA = BASE_SELECTOR_CONFIG_SCHEMA
def __init__(self, config: ActionSelectorConfig | None = None) -> None:
"""Instantiate a selector."""
@ -204,7 +217,7 @@ class ActionSelector(Selector[ActionSelectorConfig]):
return data
class AddonSelectorConfig(TypedDict, total=False):
class AddonSelectorConfig(BaseSelectorConfig, total=False):
"""Class to represent an addon selector config."""
name: str
@ -217,7 +230,7 @@ class AddonSelector(Selector[AddonSelectorConfig]):
selector_type = "addon"
CONFIG_SCHEMA = vol.Schema(
CONFIG_SCHEMA = BASE_SELECTOR_CONFIG_SCHEMA.extend(
{
vol.Optional("name"): str,
vol.Optional("slug"): str,
@ -234,7 +247,7 @@ class AddonSelector(Selector[AddonSelectorConfig]):
return addon
class AreaSelectorConfig(TypedDict, total=False):
class AreaSelectorConfig(BaseSelectorConfig, total=False):
"""Class to represent an area selector config."""
entity: EntityFilterSelectorConfig | list[EntityFilterSelectorConfig]
@ -248,7 +261,7 @@ class AreaSelector(Selector[AreaSelectorConfig]):
selector_type = "area"
CONFIG_SCHEMA = vol.Schema(
CONFIG_SCHEMA = BASE_SELECTOR_CONFIG_SCHEMA.extend(
{
vol.Optional("entity"): vol.All(
cv.ensure_list,
@ -276,7 +289,7 @@ class AreaSelector(Selector[AreaSelectorConfig]):
return [vol.Schema(str)(val) for val in data]
class AssistPipelineSelectorConfig(TypedDict, total=False):
class AssistPipelineSelectorConfig(BaseSelectorConfig, total=False):
"""Class to represent an assist pipeline selector config."""
@ -286,7 +299,7 @@ class AssistPipelineSelector(Selector[AssistPipelineSelectorConfig]):
selector_type = "assist_pipeline"
CONFIG_SCHEMA = vol.Schema({})
CONFIG_SCHEMA = BASE_SELECTOR_CONFIG_SCHEMA
def __init__(self, config: AssistPipelineSelectorConfig | None = None) -> None:
"""Instantiate a selector."""
@ -298,7 +311,7 @@ class AssistPipelineSelector(Selector[AssistPipelineSelectorConfig]):
return pipeline
class AttributeSelectorConfig(TypedDict, total=False):
class AttributeSelectorConfig(BaseSelectorConfig, total=False):
"""Class to represent an attribute selector config."""
entity_id: Required[str]
@ -311,7 +324,7 @@ class AttributeSelector(Selector[AttributeSelectorConfig]):
selector_type = "attribute"
CONFIG_SCHEMA = vol.Schema(
CONFIG_SCHEMA = BASE_SELECTOR_CONFIG_SCHEMA.extend(
{
vol.Required("entity_id"): cv.entity_id,
# hide_attributes is used to hide attributes in the frontend.
@ -330,7 +343,7 @@ class AttributeSelector(Selector[AttributeSelectorConfig]):
return attribute
class BackupLocationSelectorConfig(TypedDict, total=False):
class BackupLocationSelectorConfig(BaseSelectorConfig, total=False):
"""Class to represent a backup location selector config."""
@ -340,7 +353,7 @@ class BackupLocationSelector(Selector[BackupLocationSelectorConfig]):
selector_type = "backup_location"
CONFIG_SCHEMA = vol.Schema({})
CONFIG_SCHEMA = BASE_SELECTOR_CONFIG_SCHEMA
def __init__(self, config: BackupLocationSelectorConfig | None = None) -> None:
"""Instantiate a selector."""
@ -352,7 +365,7 @@ class BackupLocationSelector(Selector[BackupLocationSelectorConfig]):
return name
class BooleanSelectorConfig(TypedDict):
class BooleanSelectorConfig(BaseSelectorConfig):
"""Class to represent a boolean selector config."""
@ -362,7 +375,7 @@ class BooleanSelector(Selector[BooleanSelectorConfig]):
selector_type = "boolean"
CONFIG_SCHEMA = vol.Schema({})
CONFIG_SCHEMA = BASE_SELECTOR_CONFIG_SCHEMA
def __init__(self, config: BooleanSelectorConfig | None = None) -> None:
"""Instantiate a selector."""
@ -374,7 +387,7 @@ class BooleanSelector(Selector[BooleanSelectorConfig]):
return value
class ColorRGBSelectorConfig(TypedDict):
class ColorRGBSelectorConfig(BaseSelectorConfig):
"""Class to represent a color RGB selector config."""
@ -384,7 +397,7 @@ class ColorRGBSelector(Selector[ColorRGBSelectorConfig]):
selector_type = "color_rgb"
CONFIG_SCHEMA = vol.Schema({})
CONFIG_SCHEMA = BASE_SELECTOR_CONFIG_SCHEMA
def __init__(self, config: ColorRGBSelectorConfig | None = None) -> None:
"""Instantiate a selector."""
@ -396,7 +409,7 @@ class ColorRGBSelector(Selector[ColorRGBSelectorConfig]):
return value
class ColorTempSelectorConfig(TypedDict, total=False):
class ColorTempSelectorConfig(BaseSelectorConfig, total=False):
"""Class to represent a color temp selector config."""
unit: ColorTempSelectorUnit
@ -419,7 +432,7 @@ class ColorTempSelector(Selector[ColorTempSelectorConfig]):
selector_type = "color_temp"
CONFIG_SCHEMA = vol.Schema(
CONFIG_SCHEMA = BASE_SELECTOR_CONFIG_SCHEMA.extend(
{
vol.Optional("unit", default=ColorTempSelectorUnit.MIRED): vol.All(
vol.Coerce(ColorTempSelectorUnit), lambda val: val.value
@ -456,7 +469,7 @@ class ColorTempSelector(Selector[ColorTempSelectorConfig]):
return value
class ConditionSelectorConfig(TypedDict):
class ConditionSelectorConfig(BaseSelectorConfig):
"""Class to represent an condition selector config."""
@ -466,7 +479,7 @@ class ConditionSelector(Selector[ConditionSelectorConfig]):
selector_type = "condition"
CONFIG_SCHEMA = vol.Schema({})
CONFIG_SCHEMA = BASE_SELECTOR_CONFIG_SCHEMA
def __init__(self, config: ConditionSelectorConfig | None = None) -> None:
"""Instantiate a selector."""
@ -477,7 +490,7 @@ class ConditionSelector(Selector[ConditionSelectorConfig]):
return vol.Schema(cv.CONDITIONS_SCHEMA)(data)
class ConfigEntrySelectorConfig(TypedDict, total=False):
class ConfigEntrySelectorConfig(BaseSelectorConfig, total=False):
"""Class to represent a config entry selector config."""
integration: str
@ -489,7 +502,7 @@ class ConfigEntrySelector(Selector[ConfigEntrySelectorConfig]):
selector_type = "config_entry"
CONFIG_SCHEMA = vol.Schema(
CONFIG_SCHEMA = BASE_SELECTOR_CONFIG_SCHEMA.extend(
{
vol.Optional("integration"): str,
}
@ -505,7 +518,7 @@ class ConfigEntrySelector(Selector[ConfigEntrySelectorConfig]):
return config
class ConstantSelectorConfig(TypedDict, total=False):
class ConstantSelectorConfig(BaseSelectorConfig, total=False):
"""Class to represent a constant selector config."""
label: str
@ -519,7 +532,7 @@ class ConstantSelector(Selector[ConstantSelectorConfig]):
selector_type = "constant"
CONFIG_SCHEMA = vol.Schema(
CONFIG_SCHEMA = BASE_SELECTOR_CONFIG_SCHEMA.extend(
{
vol.Optional("label"): str,
vol.Optional("translation_key"): cv.string,
@ -546,7 +559,7 @@ class QrErrorCorrectionLevel(StrEnum):
HIGH = "high"
class QrCodeSelectorConfig(TypedDict, total=False):
class QrCodeSelectorConfig(BaseSelectorConfig, total=False):
"""Class to represent a QR code selector config."""
data: str
@ -560,7 +573,7 @@ class QrCodeSelector(Selector[QrCodeSelectorConfig]):
selector_type = "qr_code"
CONFIG_SCHEMA = vol.Schema(
CONFIG_SCHEMA = BASE_SELECTOR_CONFIG_SCHEMA.extend(
{
vol.Required("data"): str,
vol.Optional("scale"): int,
@ -580,7 +593,7 @@ class QrCodeSelector(Selector[QrCodeSelectorConfig]):
return self.config["data"]
class ConversationAgentSelectorConfig(TypedDict, total=False):
class ConversationAgentSelectorConfig(BaseSelectorConfig, total=False):
"""Class to represent a conversation agent selector config."""
language: str
@ -592,7 +605,7 @@ class ConversationAgentSelector(Selector[ConversationAgentSelectorConfig]):
selector_type = "conversation_agent"
CONFIG_SCHEMA = vol.Schema(
CONFIG_SCHEMA = BASE_SELECTOR_CONFIG_SCHEMA.extend(
{
vol.Optional("language"): str,
}
@ -608,7 +621,7 @@ class ConversationAgentSelector(Selector[ConversationAgentSelectorConfig]):
return agent
class CountrySelectorConfig(TypedDict, total=False):
class CountrySelectorConfig(BaseSelectorConfig, total=False):
"""Class to represent a country selector config."""
countries: list[str]
@ -621,7 +634,7 @@ class CountrySelector(Selector[CountrySelectorConfig]):
selector_type = "country"
CONFIG_SCHEMA = vol.Schema(
CONFIG_SCHEMA = BASE_SELECTOR_CONFIG_SCHEMA.extend(
{
vol.Optional("countries"): [str],
vol.Optional("no_sort", default=False): cv.boolean,
@ -642,7 +655,7 @@ class CountrySelector(Selector[CountrySelectorConfig]):
return country
class DateSelectorConfig(TypedDict):
class DateSelectorConfig(BaseSelectorConfig):
"""Class to represent a date selector config."""
@ -652,7 +665,7 @@ class DateSelector(Selector[DateSelectorConfig]):
selector_type = "date"
CONFIG_SCHEMA = vol.Schema({})
CONFIG_SCHEMA = BASE_SELECTOR_CONFIG_SCHEMA
def __init__(self, config: DateSelectorConfig | None = None) -> None:
"""Instantiate a selector."""
@ -664,7 +677,7 @@ class DateSelector(Selector[DateSelectorConfig]):
return data
class DateTimeSelectorConfig(TypedDict):
class DateTimeSelectorConfig(BaseSelectorConfig):
"""Class to represent a date time selector config."""
@ -674,7 +687,7 @@ class DateTimeSelector(Selector[DateTimeSelectorConfig]):
selector_type = "datetime"
CONFIG_SCHEMA = vol.Schema({})
CONFIG_SCHEMA = BASE_SELECTOR_CONFIG_SCHEMA
def __init__(self, config: DateTimeSelectorConfig | None = None) -> None:
"""Instantiate a selector."""
@ -686,7 +699,7 @@ class DateTimeSelector(Selector[DateTimeSelectorConfig]):
return data
class DeviceSelectorConfig(DeviceFilterSelectorConfig, total=False):
class DeviceSelectorConfig(BaseSelectorConfig, DeviceFilterSelectorConfig, total=False):
"""Class to represent a device selector config."""
entity: EntityFilterSelectorConfig | list[EntityFilterSelectorConfig]
@ -700,7 +713,9 @@ class DeviceSelector(Selector[DeviceSelectorConfig]):
selector_type = "device"
CONFIG_SCHEMA = DEVICE_FILTER_SELECTOR_CONFIG_SCHEMA.extend(
CONFIG_SCHEMA = BASE_SELECTOR_CONFIG_SCHEMA.extend(
DEVICE_FILTER_SELECTOR_CONFIG_SCHEMA.schema
).extend(
{
vol.Optional("multiple", default=False): cv.boolean,
vol.Optional("filter"): vol.All(
@ -724,7 +739,7 @@ class DeviceSelector(Selector[DeviceSelectorConfig]):
return [vol.Schema(str)(val) for val in data]
class DurationSelectorConfig(TypedDict, total=False):
class DurationSelectorConfig(BaseSelectorConfig, total=False):
"""Class to represent a duration selector config."""
enable_day: bool
@ -738,7 +753,7 @@ class DurationSelector(Selector[DurationSelectorConfig]):
selector_type = "duration"
CONFIG_SCHEMA = vol.Schema(
CONFIG_SCHEMA = BASE_SELECTOR_CONFIG_SCHEMA.extend(
{
# Enable day field in frontend. A selection with `days` set is allowed
# even if `enable_day` is not set
@ -763,7 +778,7 @@ class DurationSelector(Selector[DurationSelectorConfig]):
return cast(dict[str, float], data)
class EntitySelectorConfig(EntityFilterSelectorConfig, total=False):
class EntitySelectorConfig(BaseSelectorConfig, EntityFilterSelectorConfig, total=False):
"""Class to represent an entity selector config."""
exclude_entities: list[str]
@ -778,7 +793,9 @@ class EntitySelector(Selector[EntitySelectorConfig]):
selector_type = "entity"
CONFIG_SCHEMA = ENTITY_FILTER_SELECTOR_CONFIG_SCHEMA.extend(
CONFIG_SCHEMA = BASE_SELECTOR_CONFIG_SCHEMA.extend(
ENTITY_FILTER_SELECTOR_CONFIG_SCHEMA.schema
).extend(
{
vol.Optional("exclude_entities"): [str],
vol.Optional("include_entities"): [str],
@ -824,7 +841,7 @@ class EntitySelector(Selector[EntitySelectorConfig]):
return cast(list, vol.Schema([validate])(data)) # Output is a list
class FloorSelectorConfig(TypedDict, total=False):
class FloorSelectorConfig(BaseSelectorConfig, total=False):
"""Class to represent an floor selector config."""
entity: EntityFilterSelectorConfig | list[EntityFilterSelectorConfig]
@ -838,7 +855,7 @@ class FloorSelector(Selector[FloorSelectorConfig]):
selector_type = "floor"
CONFIG_SCHEMA = vol.Schema(
CONFIG_SCHEMA = BASE_SELECTOR_CONFIG_SCHEMA.extend(
{
vol.Optional("entity"): vol.All(
cv.ensure_list,
@ -866,7 +883,7 @@ class FloorSelector(Selector[FloorSelectorConfig]):
return [vol.Schema(str)(val) for val in data]
class IconSelectorConfig(TypedDict, total=False):
class IconSelectorConfig(BaseSelectorConfig, total=False):
"""Class to represent an icon selector config."""
placeholder: str
@ -878,7 +895,7 @@ class IconSelector(Selector[IconSelectorConfig]):
selector_type = "icon"
CONFIG_SCHEMA = vol.Schema(
CONFIG_SCHEMA = BASE_SELECTOR_CONFIG_SCHEMA.extend(
{vol.Optional("placeholder"): str}
# Frontend also has a fallbackPath option, this is not used by core
)
@ -893,7 +910,7 @@ class IconSelector(Selector[IconSelectorConfig]):
return icon
class LabelSelectorConfig(TypedDict, total=False):
class LabelSelectorConfig(BaseSelectorConfig, total=False):
"""Class to represent a label selector config."""
multiple: bool
@ -905,7 +922,7 @@ class LabelSelector(Selector[LabelSelectorConfig]):
selector_type = "label"
CONFIG_SCHEMA = vol.Schema(
CONFIG_SCHEMA = BASE_SELECTOR_CONFIG_SCHEMA.extend(
{
vol.Optional("multiple", default=False): cv.boolean,
}
@ -925,7 +942,7 @@ class LabelSelector(Selector[LabelSelectorConfig]):
return [vol.Schema(str)(val) for val in data]
class LanguageSelectorConfig(TypedDict, total=False):
class LanguageSelectorConfig(BaseSelectorConfig, total=False):
"""Class to represent an language selector config."""
languages: list[str]
@ -939,7 +956,7 @@ class LanguageSelector(Selector[LanguageSelectorConfig]):
selector_type = "language"
CONFIG_SCHEMA = vol.Schema(
CONFIG_SCHEMA = BASE_SELECTOR_CONFIG_SCHEMA.extend(
{
vol.Optional("languages"): [str],
vol.Optional("native_name", default=False): cv.boolean,
@ -959,7 +976,7 @@ class LanguageSelector(Selector[LanguageSelectorConfig]):
return language
class LocationSelectorConfig(TypedDict, total=False):
class LocationSelectorConfig(BaseSelectorConfig, total=False):
"""Class to represent a location selector config."""
radius: bool
@ -972,7 +989,7 @@ class LocationSelector(Selector[LocationSelectorConfig]):
selector_type = "location"
CONFIG_SCHEMA = vol.Schema(
CONFIG_SCHEMA = BASE_SELECTOR_CONFIG_SCHEMA.extend(
{vol.Optional("radius"): bool, vol.Optional("icon"): str}
)
DATA_SCHEMA = vol.Schema(
@ -993,7 +1010,7 @@ class LocationSelector(Selector[LocationSelectorConfig]):
return location
class MediaSelectorConfig(TypedDict):
class MediaSelectorConfig(BaseSelectorConfig):
"""Class to represent a media selector config."""
@ -1003,7 +1020,7 @@ class MediaSelector(Selector[MediaSelectorConfig]):
selector_type = "media"
CONFIG_SCHEMA = vol.Schema({})
CONFIG_SCHEMA = BASE_SELECTOR_CONFIG_SCHEMA
DATA_SCHEMA = vol.Schema(
{
# Although marked as optional in frontend, this field is required
@ -1026,7 +1043,7 @@ class MediaSelector(Selector[MediaSelectorConfig]):
return media
class NumberSelectorConfig(TypedDict, total=False):
class NumberSelectorConfig(BaseSelectorConfig, total=False):
"""Class to represent a number selector config."""
min: float
@ -1061,7 +1078,7 @@ class NumberSelector(Selector[NumberSelectorConfig]):
selector_type = "number"
CONFIG_SCHEMA = vol.All(
vol.Schema(
BASE_SELECTOR_CONFIG_SCHEMA.extend(
{
vol.Optional("min"): vol.Coerce(float),
vol.Optional("max"): vol.Coerce(float),
@ -1096,7 +1113,7 @@ class NumberSelector(Selector[NumberSelectorConfig]):
return value
class ObjectSelectorConfig(TypedDict):
class ObjectSelectorConfig(BaseSelectorConfig):
"""Class to represent an object selector config."""
@ -1106,7 +1123,7 @@ class ObjectSelector(Selector[ObjectSelectorConfig]):
selector_type = "object"
CONFIG_SCHEMA = vol.Schema({})
CONFIG_SCHEMA = BASE_SELECTOR_CONFIG_SCHEMA
def __init__(self, config: ObjectSelectorConfig | None = None) -> None:
"""Instantiate a selector."""
@ -1142,7 +1159,7 @@ class SelectSelectorMode(StrEnum):
DROPDOWN = "dropdown"
class SelectSelectorConfig(TypedDict, total=False):
class SelectSelectorConfig(BaseSelectorConfig, total=False):
"""Class to represent a select selector config."""
options: Required[Sequence[SelectOptionDict] | Sequence[str]]
@ -1159,7 +1176,7 @@ class SelectSelector(Selector[SelectSelectorConfig]):
selector_type = "select"
CONFIG_SCHEMA = vol.Schema(
CONFIG_SCHEMA = BASE_SELECTOR_CONFIG_SCHEMA.extend(
{
vol.Required("options"): vol.All(vol.Any([str], [select_option])),
vol.Optional("multiple", default=False): cv.boolean,
@ -1199,14 +1216,14 @@ class SelectSelector(Selector[SelectSelectorConfig]):
return [parent_schema(vol.Schema(str)(val)) for val in data]
class TargetSelectorConfig(TypedDict, total=False):
class TargetSelectorConfig(BaseSelectorConfig, total=False):
"""Class to represent a target selector config."""
entity: EntityFilterSelectorConfig | list[EntityFilterSelectorConfig]
device: DeviceFilterSelectorConfig | list[DeviceFilterSelectorConfig]
class StateSelectorConfig(TypedDict, total=False):
class StateSelectorConfig(BaseSelectorConfig, total=False):
"""Class to represent an state selector config."""
entity_id: Required[str]
@ -1218,7 +1235,7 @@ class StateSelector(Selector[StateSelectorConfig]):
selector_type = "state"
CONFIG_SCHEMA = vol.Schema(
CONFIG_SCHEMA = BASE_SELECTOR_CONFIG_SCHEMA.extend(
{
vol.Required("entity_id"): cv.entity_id,
# The attribute to filter on, is currently deliberately not
@ -1248,7 +1265,7 @@ class TargetSelector(Selector[TargetSelectorConfig]):
selector_type = "target"
CONFIG_SCHEMA = vol.Schema(
CONFIG_SCHEMA = BASE_SELECTOR_CONFIG_SCHEMA.extend(
{
vol.Optional("entity"): vol.All(
cv.ensure_list,
@ -1273,7 +1290,7 @@ class TargetSelector(Selector[TargetSelectorConfig]):
return target
class TemplateSelectorConfig(TypedDict):
class TemplateSelectorConfig(BaseSelectorConfig):
"""Class to represent an template selector config."""
@ -1283,7 +1300,7 @@ class TemplateSelector(Selector[TemplateSelectorConfig]):
selector_type = "template"
CONFIG_SCHEMA = vol.Schema({})
CONFIG_SCHEMA = BASE_SELECTOR_CONFIG_SCHEMA
def __init__(self, config: TemplateSelectorConfig | None = None) -> None:
"""Instantiate a selector."""
@ -1295,7 +1312,7 @@ class TemplateSelector(Selector[TemplateSelectorConfig]):
return template.template
class TextSelectorConfig(TypedDict, total=False):
class TextSelectorConfig(BaseSelectorConfig, total=False):
"""Class to represent a text selector config."""
multiline: bool
@ -1330,7 +1347,7 @@ class TextSelector(Selector[TextSelectorConfig]):
selector_type = "text"
CONFIG_SCHEMA = vol.Schema(
CONFIG_SCHEMA = BASE_SELECTOR_CONFIG_SCHEMA.extend(
{
vol.Optional("multiline", default=False): bool,
vol.Optional("prefix"): str,
@ -1359,7 +1376,7 @@ class TextSelector(Selector[TextSelectorConfig]):
return [vol.Schema(str)(val) for val in data]
class ThemeSelectorConfig(TypedDict):
class ThemeSelectorConfig(BaseSelectorConfig):
"""Class to represent a theme selector config."""
@ -1369,7 +1386,7 @@ class ThemeSelector(Selector[ThemeSelectorConfig]):
selector_type = "theme"
CONFIG_SCHEMA = vol.Schema(
CONFIG_SCHEMA = BASE_SELECTOR_CONFIG_SCHEMA.extend(
{
vol.Optional("include_default", default=False): cv.boolean,
}
@ -1385,7 +1402,7 @@ class ThemeSelector(Selector[ThemeSelectorConfig]):
return theme
class TimeSelectorConfig(TypedDict):
class TimeSelectorConfig(BaseSelectorConfig):
"""Class to represent a time selector config."""
@ -1395,7 +1412,7 @@ class TimeSelector(Selector[TimeSelectorConfig]):
selector_type = "time"
CONFIG_SCHEMA = vol.Schema({})
CONFIG_SCHEMA = BASE_SELECTOR_CONFIG_SCHEMA
def __init__(self, config: TimeSelectorConfig | None = None) -> None:
"""Instantiate a selector."""
@ -1407,7 +1424,7 @@ class TimeSelector(Selector[TimeSelectorConfig]):
return cast(str, data)
class TriggerSelectorConfig(TypedDict):
class TriggerSelectorConfig(BaseSelectorConfig):
"""Class to represent an trigger selector config."""
@ -1417,7 +1434,7 @@ class TriggerSelector(Selector[TriggerSelectorConfig]):
selector_type = "trigger"
CONFIG_SCHEMA = vol.Schema({})
CONFIG_SCHEMA = BASE_SELECTOR_CONFIG_SCHEMA
def __init__(self, config: TriggerSelectorConfig | None = None) -> None:
"""Instantiate a selector."""
@ -1428,7 +1445,7 @@ class TriggerSelector(Selector[TriggerSelectorConfig]):
return vol.Schema(cv.TRIGGER_SCHEMA)(data)
class FileSelectorConfig(TypedDict):
class FileSelectorConfig(BaseSelectorConfig):
"""Class to represent a file selector config."""
accept: str # required
@ -1440,7 +1457,7 @@ class FileSelector(Selector[FileSelectorConfig]):
selector_type = "file"
CONFIG_SCHEMA = vol.Schema(
CONFIG_SCHEMA = BASE_SELECTOR_CONFIG_SCHEMA.extend(
{
# https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#accept
vol.Required("accept"): str,