Home Assistant Unofficial Reference 2024.12.1
selector.py
Go to the documentation of this file.
1 """Selectors for Home Assistant."""
2 
3 from __future__ import annotations
4 
5 from collections.abc import Callable, Mapping, Sequence
6 from enum import StrEnum
7 from functools import cache
8 import importlib
9 from typing import Any, Literal, Required, TypedDict, cast
10 from uuid import UUID
11 
12 import voluptuous as vol
13 
14 from homeassistant.const import CONF_MODE, CONF_UNIT_OF_MEASUREMENT
15 from homeassistant.core import split_entity_id, valid_entity_id
16 from homeassistant.generated.countries import COUNTRIES
17 from homeassistant.util import decorator
18 from homeassistant.util.yaml import dumper
19 
20 from . import config_validation as cv
21 
22 SELECTORS: decorator.Registry[str, type[Selector]] = decorator.Registry()
23 
24 
25 def _get_selector_class(config: Any) -> type[Selector]:
26  """Get selector class type."""
27  if not isinstance(config, dict):
28  raise vol.Invalid("Expected a dictionary")
29 
30  if len(config) != 1:
31  raise vol.Invalid(f"Only one type can be specified. Found {', '.join(config)}")
32 
33  selector_type: str = list(config)[0]
34 
35  if (selector_class := SELECTORS.get(selector_type)) is None:
36  raise vol.Invalid(f"Unknown selector type {selector_type} found")
37 
38  return selector_class
39 
40 
41 def selector(config: Any) -> Selector:
42  """Instantiate a selector."""
43  selector_class = _get_selector_class(config)
44  selector_type = list(config)[0]
45 
46  return selector_class(config[selector_type])
47 
48 
49 def validate_selector(config: Any) -> dict:
50  """Validate a selector."""
51  selector_class = _get_selector_class(config)
52  selector_type = list(config)[0]
53 
54  # Selectors can be empty
55  if config[selector_type] is None:
56  return {selector_type: {}}
57 
58  return {
59  selector_type: cast(dict, selector_class.CONFIG_SCHEMA(config[selector_type]))
60  }
61 
62 
63 class Selector[_T: Mapping[str, Any]]:
64  """Base class for selectors."""
65 
66  CONFIG_SCHEMA: Callable
67  config: _T
68  selector_type: str
69 
70  def __init__(self, config: Mapping[str, Any] | None = None) -> None:
71  """Instantiate a selector."""
72  # Selectors can be empty
73  if config is None:
74  config = {}
75 
76  self.config = self.CONFIG_SCHEMA(config)
77 
78  def __eq__(self, other: object) -> bool:
79  """Check equality."""
80  if not isinstance(other, Selector):
81  return NotImplemented
82 
83  return self.selector_type == other.selector_type and self.config == other.config
84 
85  def serialize(self) -> dict[str, dict[str, _T]]:
86  """Serialize Selector for voluptuous_serialize."""
87  return {"selector": {self.selector_type: self.config}}
88 
89 
90 @cache
91 def _entity_feature_flag(domain: str, enum_name: str, feature_name: str) -> int:
92  """Return a cached lookup of an entity feature enum.
93 
94  This will import a module from disk and is run from an executor when
95  loading the services schema files.
96  """
97  module = importlib.import_module(f"homeassistant.components.{domain}")
98  enum = getattr(module, enum_name)
99  feature = getattr(enum, feature_name)
100  return cast(int, feature.value)
101 
102 
103 def _validate_supported_feature(supported_feature: str) -> int:
104  """Validate a supported feature and resolve an enum string to its value."""
105 
106  try:
107  domain, enum, feature = supported_feature.split(".", 2)
108  except ValueError as exc:
109  raise vol.Invalid(
110  f"Invalid supported feature '{supported_feature}', expected "
111  "<domain>.<enum>.<member>"
112  ) from exc
113 
114  try:
115  return _entity_feature_flag(domain, enum, feature)
116  except (ModuleNotFoundError, AttributeError) as exc:
117  raise vol.Invalid(f"Unknown supported feature '{supported_feature}'") from exc
118 
119 
120 def _validate_supported_features(supported_features: int | list[str]) -> int:
121  """Validate a supported feature and resolve an enum string to its value."""
122 
123  if isinstance(supported_features, int):
124  return supported_features
125 
126  feature_mask = 0
127 
128  for supported_feature in supported_features:
129  feature_mask |= _validate_supported_feature(supported_feature)
130 
131  return feature_mask
132 
133 
134 ENTITY_FILTER_SELECTOR_CONFIG_SCHEMA = vol.Schema(
135  {
136  # Integration that provided the entity
137  vol.Optional("integration"): str,
138  # Domain the entity belongs to
139  vol.Optional("domain"): vol.All(cv.ensure_list, [str]),
140  # Device class of the entity
141  vol.Optional("device_class"): vol.All(cv.ensure_list, [str]),
142  # Features supported by the entity
143  vol.Optional("supported_features"): [
144  vol.All(cv.ensure_list, [str], _validate_supported_features)
145  ],
146  }
147 )
148 
149 
150 class EntityFilterSelectorConfig(TypedDict, total=False):
151  """Class to represent a single entity selector config."""
152 
153  integration: str
154  domain: str | list[str]
155  device_class: str | list[str]
156  supported_features: list[str]
157 
158 
159 DEVICE_FILTER_SELECTOR_CONFIG_SCHEMA = vol.Schema(
160  {
161  # Integration linked to it with a config entry
162  vol.Optional("integration"): str,
163  # Manufacturer of device
164  vol.Optional("manufacturer"): str,
165  # Model of device
166  vol.Optional("model"): str,
167  # Device has to contain entities matching this selector
168  vol.Optional("entity"): vol.All(
169  cv.ensure_list, [ENTITY_FILTER_SELECTOR_CONFIG_SCHEMA]
170  ),
171  }
172 )
173 
174 
175 class DeviceFilterSelectorConfig(TypedDict, total=False):
176  """Class to represent a single device selector config."""
177 
178  integration: str
179  manufacturer: str
180  model: str
181 
182 
183 class ActionSelectorConfig(TypedDict):
184  """Class to represent an action selector config."""
185 
186 
187 @SELECTORS.register("action")
188 class ActionSelector(Selector[ActionSelectorConfig]):
189  """Selector of an action sequence (script syntax)."""
190 
191  selector_type = "action"
192 
193  CONFIG_SCHEMA = vol.Schema({})
194 
195  def __init__(self, config: ActionSelectorConfig | None = None) -> None:
196  """Instantiate a selector."""
197  super().__init__(config)
198 
199  def __call__(self, data: Any) -> Any:
200  """Validate the passed selection."""
201  return data
202 
203 
204 class AddonSelectorConfig(TypedDict, total=False):
205  """Class to represent an addon selector config."""
206 
207  name: str
208  slug: str
209 
210 
211 @SELECTORS.register("addon")
212 class AddonSelector(Selector[AddonSelectorConfig]):
213  """Selector of a add-on."""
214 
215  selector_type = "addon"
216 
217  CONFIG_SCHEMA = vol.Schema(
218  {
219  vol.Optional("name"): str,
220  vol.Optional("slug"): str,
221  }
222  )
223 
224  def __init__(self, config: AddonSelectorConfig | None = None) -> None:
225  """Instantiate a selector."""
226  super().__init__(config)
227 
228  def __call__(self, data: Any) -> str:
229  """Validate the passed selection."""
230  addon: str = vol.Schema(str)(data)
231  return addon
232 
233 
234 class AreaSelectorConfig(TypedDict, total=False):
235  """Class to represent an area selector config."""
236 
237  entity: EntityFilterSelectorConfig | list[EntityFilterSelectorConfig]
238  device: DeviceFilterSelectorConfig | list[DeviceFilterSelectorConfig]
239  multiple: bool
240 
241 
242 @SELECTORS.register("area")
243 class AreaSelector(Selector[AreaSelectorConfig]):
244  """Selector of a single or list of areas."""
245 
246  selector_type = "area"
247 
248  CONFIG_SCHEMA = vol.Schema(
249  {
250  vol.Optional("entity"): vol.All(
251  cv.ensure_list,
252  [ENTITY_FILTER_SELECTOR_CONFIG_SCHEMA],
253  ),
254  vol.Optional("device"): vol.All(
255  cv.ensure_list,
256  [DEVICE_FILTER_SELECTOR_CONFIG_SCHEMA],
257  ),
258  vol.Optional("multiple", default=False): cv.boolean,
259  }
260  )
261 
262  def __init__(self, config: AreaSelectorConfig | None = None) -> None:
263  """Instantiate a selector."""
264  super().__init__(config)
265 
266  def __call__(self, data: Any) -> str | list[str]:
267  """Validate the passed selection."""
268  if not self.config["multiple"]:
269  area_id: str = vol.Schema(str)(data)
270  return area_id
271  if not isinstance(data, list):
272  raise vol.Invalid("Value should be a list")
273  return [vol.Schema(str)(val) for val in data]
274 
275 
276 class AssistPipelineSelectorConfig(TypedDict, total=False):
277  """Class to represent an assist pipeline selector config."""
278 
279 
280 @SELECTORS.register("assist_pipeline")
281 class AssistPipelineSelector(Selector[AssistPipelineSelectorConfig]):
282  """Selector for an assist pipeline."""
283 
284  selector_type = "assist_pipeline"
285 
286  CONFIG_SCHEMA = vol.Schema({})
287 
288  def __init__(self, config: AssistPipelineSelectorConfig | None = None) -> None:
289  """Instantiate a selector."""
290  super().__init__(config)
291 
292  def __call__(self, data: Any) -> str:
293  """Validate the passed selection."""
294  pipeline: str = vol.Schema(str)(data)
295  return pipeline
296 
297 
298 class AttributeSelectorConfig(TypedDict, total=False):
299  """Class to represent an attribute selector config."""
300 
301  entity_id: Required[str]
302  hide_attributes: list[str]
303 
304 
305 @SELECTORS.register("attribute")
306 class AttributeSelector(Selector[AttributeSelectorConfig]):
307  """Selector for an entity attribute."""
308 
309  selector_type = "attribute"
310 
311  CONFIG_SCHEMA = vol.Schema(
312  {
313  vol.Required("entity_id"): cv.entity_id,
314  # hide_attributes is used to hide attributes in the frontend.
315  # A hidden attribute can still be provided manually.
316  vol.Optional("hide_attributes"): [str],
317  }
318  )
319 
320  def __init__(self, config: AttributeSelectorConfig) -> None:
321  """Instantiate a selector."""
322  super().__init__(config)
323 
324  def __call__(self, data: Any) -> str:
325  """Validate the passed selection."""
326  attribute: str = vol.Schema(str)(data)
327  return attribute
328 
329 
330 class BackupLocationSelectorConfig(TypedDict, total=False):
331  """Class to represent a backup location selector config."""
332 
333 
334 @SELECTORS.register("backup_location")
335 class BackupLocationSelector(Selector[BackupLocationSelectorConfig]):
336  """Selector of a backup location."""
337 
338  selector_type = "backup_location"
339 
340  CONFIG_SCHEMA = vol.Schema({})
341 
342  def __init__(self, config: BackupLocationSelectorConfig | None = None) -> None:
343  """Instantiate a selector."""
344  super().__init__(config)
345 
346  def __call__(self, data: Any) -> str:
347  """Validate the passed selection."""
348  name: str = vol.Match(r"^(?:\/backup|\w+)$")(data)
349  return name
350 
351 
352 class BooleanSelectorConfig(TypedDict):
353  """Class to represent a boolean selector config."""
354 
355 
356 @SELECTORS.register("boolean")
357 class BooleanSelector(Selector[BooleanSelectorConfig]):
358  """Selector of a boolean value."""
359 
360  selector_type = "boolean"
361 
362  CONFIG_SCHEMA = vol.Schema({})
363 
364  def __init__(self, config: BooleanSelectorConfig | None = None) -> None:
365  """Instantiate a selector."""
366  super().__init__(config)
367 
368  def __call__(self, data: Any) -> bool:
369  """Validate the passed selection."""
370  value: bool = vol.Coerce(bool)(data)
371  return value
372 
373 
374 class ColorRGBSelectorConfig(TypedDict):
375  """Class to represent a color RGB selector config."""
376 
377 
378 @SELECTORS.register("color_rgb")
379 class ColorRGBSelector(Selector[ColorRGBSelectorConfig]):
380  """Selector of an RGB color value."""
381 
382  selector_type = "color_rgb"
383 
384  CONFIG_SCHEMA = vol.Schema({})
385 
386  def __init__(self, config: ColorRGBSelectorConfig | None = None) -> None:
387  """Instantiate a selector."""
388  super().__init__(config)
389 
390  def __call__(self, data: Any) -> list[int]:
391  """Validate the passed selection."""
392  value: list[int] = vol.All(list, vol.ExactSequence((cv.byte,) * 3))(data)
393  return value
394 
395 
396 class ColorTempSelectorConfig(TypedDict, total=False):
397  """Class to represent a color temp selector config."""
398 
399  unit: ColorTempSelectorUnit
400  min: int
401  max: int
402  max_mireds: int
403  min_mireds: int
404 
405 
406 class ColorTempSelectorUnit(StrEnum):
407  """Possible units for a color temperature selector."""
408 
409  KELVIN = "kelvin"
410  MIRED = "mired"
411 
412 
413 @SELECTORS.register("color_temp")
414 class ColorTempSelector(Selector[ColorTempSelectorConfig]):
415  """Selector of an color temperature."""
416 
417  selector_type = "color_temp"
418 
419  CONFIG_SCHEMA = vol.Schema(
420  {
421  vol.Optional("unit", default=ColorTempSelectorUnit.MIRED): vol.All(
422  vol.Coerce(ColorTempSelectorUnit), lambda val: val.value
423  ),
424  vol.Optional("min"): vol.Coerce(int),
425  vol.Optional("max"): vol.Coerce(int),
426  vol.Optional("max_mireds"): vol.Coerce(int),
427  vol.Optional("min_mireds"): vol.Coerce(int),
428  }
429  )
430 
431  def __init__(self, config: ColorTempSelectorConfig | None = None) -> None:
432  """Instantiate a selector."""
433  super().__init__(config)
434 
435  def __call__(self, data: Any) -> int:
436  """Validate the passed selection."""
437  range_min = self.config.get("min")
438  range_max = self.config.get("max")
439 
440  if range_min is None:
441  range_min = self.config.get("min_mireds")
442 
443  if range_max is None:
444  range_max = self.config.get("max_mireds")
445 
446  value: int = vol.All(
447  vol.Coerce(float),
448  vol.Range(
449  min=range_min,
450  max=range_max,
451  ),
452  )(data)
453  return value
454 
455 
456 class ConditionSelectorConfig(TypedDict):
457  """Class to represent an condition selector config."""
458 
459 
460 @SELECTORS.register("condition")
461 class ConditionSelector(Selector[ConditionSelectorConfig]):
462  """Selector of an condition sequence (script syntax)."""
463 
464  selector_type = "condition"
465 
466  CONFIG_SCHEMA = vol.Schema({})
467 
468  def __init__(self, config: ConditionSelectorConfig | None = None) -> None:
469  """Instantiate a selector."""
470  super().__init__(config)
471 
472  def __call__(self, data: Any) -> Any:
473  """Validate the passed selection."""
474  return vol.Schema(cv.CONDITIONS_SCHEMA)(data)
475 
476 
477 class ConfigEntrySelectorConfig(TypedDict, total=False):
478  """Class to represent a config entry selector config."""
479 
480  integration: str
481 
482 
483 @SELECTORS.register("config_entry")
484 class ConfigEntrySelector(Selector[ConfigEntrySelectorConfig]):
485  """Selector of a config entry."""
486 
487  selector_type = "config_entry"
488 
489  CONFIG_SCHEMA = vol.Schema(
490  {
491  vol.Optional("integration"): str,
492  }
493  )
494 
495  def __init__(self, config: ConfigEntrySelectorConfig | None = None) -> None:
496  """Instantiate a selector."""
497  super().__init__(config)
498 
499  def __call__(self, data: Any) -> str:
500  """Validate the passed selection."""
501  config: str = vol.Schema(str)(data)
502  return config
503 
504 
505 class ConstantSelectorConfig(TypedDict, total=False):
506  """Class to represent a constant selector config."""
507 
508  label: str
509  translation_key: str
510  value: str | int | bool
511 
512 
513 @SELECTORS.register("constant")
514 class ConstantSelector(Selector[ConstantSelectorConfig]):
515  """Constant selector."""
516 
517  selector_type = "constant"
518 
519  CONFIG_SCHEMA = vol.Schema(
520  {
521  vol.Optional("label"): str,
522  vol.Optional("translation_key"): cv.string,
523  vol.Required("value"): vol.Any(str, int, bool),
524  }
525  )
526 
527  def __init__(self, config: ConstantSelectorConfig) -> None:
528  """Instantiate a selector."""
529  super().__init__(config)
530 
531  def __call__(self, data: Any) -> Any:
532  """Validate the passed selection."""
533  vol.Schema(self.config["value"])(data)
534  return self.config["value"]
535 
536 
537 class QrErrorCorrectionLevel(StrEnum):
538  """Possible error correction levels for QR code selector."""
539 
540  LOW = "low"
541  MEDIUM = "medium"
542  QUARTILE = "quartile"
543  HIGH = "high"
544 
545 
546 class QrCodeSelectorConfig(TypedDict, total=False):
547  """Class to represent a QR code selector config."""
548 
549  data: str
550  scale: int
551  error_correction_level: QrErrorCorrectionLevel
552 
553 
554 @SELECTORS.register("qr_code")
555 class QrCodeSelector(Selector[QrCodeSelectorConfig]):
556  """QR code selector."""
557 
558  selector_type = "qr_code"
559 
560  CONFIG_SCHEMA = vol.Schema(
561  {
562  vol.Required("data"): str,
563  vol.Optional("scale"): int,
564  vol.Optional("error_correction_level"): vol.All(
565  vol.Coerce(QrErrorCorrectionLevel), lambda val: val.value
566  ),
567  }
568  )
569 
570  def __init__(self, config: QrCodeSelectorConfig) -> None:
571  """Instantiate a selector."""
572  super().__init__(config)
573 
574  def __call__(self, data: Any) -> Any:
575  """Validate the passed selection."""
576  vol.Schema(vol.Any(str, None))(data)
577  return self.config["data"]
578 
579 
580 class ConversationAgentSelectorConfig(TypedDict, total=False):
581  """Class to represent a conversation agent selector config."""
582 
583  language: str
584 
585 
586 @SELECTORS.register("conversation_agent")
587 class ConversationAgentSelector(Selector[ConversationAgentSelectorConfig]):
588  """Selector for a conversation agent."""
589 
590  selector_type = "conversation_agent"
591 
592  CONFIG_SCHEMA = vol.Schema(
593  {
594  vol.Optional("language"): str,
595  }
596  )
597 
598  def __init__(self, config: ConversationAgentSelectorConfig | None = None) -> None:
599  """Instantiate a selector."""
600  super().__init__(config)
601 
602  def __call__(self, data: Any) -> str:
603  """Validate the passed selection."""
604  agent: str = vol.Schema(str)(data)
605  return agent
606 
607 
608 class CountrySelectorConfig(TypedDict, total=False):
609  """Class to represent a country selector config."""
610 
611  countries: list[str]
612  no_sort: bool
613 
614 
615 @SELECTORS.register("country")
616 class CountrySelector(Selector[CountrySelectorConfig]):
617  """Selector for a single-choice country select."""
618 
619  selector_type = "country"
620 
621  CONFIG_SCHEMA = vol.Schema(
622  {
623  vol.Optional("countries"): [str],
624  vol.Optional("no_sort", default=False): cv.boolean,
625  }
626  )
627 
628  def __init__(self, config: CountrySelectorConfig | None = None) -> None:
629  """Instantiate a selector."""
630  super().__init__(config)
631 
632  def __call__(self, data: Any) -> Any:
633  """Validate the passed selection."""
634  country: str = vol.Schema(str)(data)
635  if "countries" in self.config and (
636  country not in self.config["countries"] or country not in COUNTRIES
637  ):
638  raise vol.Invalid(f"Value {country} is not a valid option")
639  return country
640 
641 
642 class DateSelectorConfig(TypedDict):
643  """Class to represent a date selector config."""
644 
645 
646 @SELECTORS.register("date")
647 class DateSelector(Selector[DateSelectorConfig]):
648  """Selector of a date."""
649 
650  selector_type = "date"
651 
652  CONFIG_SCHEMA = vol.Schema({})
653 
654  def __init__(self, config: DateSelectorConfig | None = None) -> None:
655  """Instantiate a selector."""
656  super().__init__(config)
657 
658  def __call__(self, data: Any) -> Any:
659  """Validate the passed selection."""
660  cv.date(data)
661  return data
662 
663 
664 class DateTimeSelectorConfig(TypedDict):
665  """Class to represent a date time selector config."""
666 
667 
668 @SELECTORS.register("datetime")
669 class DateTimeSelector(Selector[DateTimeSelectorConfig]):
670  """Selector of a datetime."""
671 
672  selector_type = "datetime"
673 
674  CONFIG_SCHEMA = vol.Schema({})
675 
676  def __init__(self, config: DateTimeSelectorConfig | None = None) -> None:
677  """Instantiate a selector."""
678  super().__init__(config)
679 
680  def __call__(self, data: Any) -> Any:
681  """Validate the passed selection."""
682  cv.datetime(data)
683  return data
684 
685 
687  """Class to represent a device selector config."""
688 
689  entity: EntityFilterSelectorConfig | list[EntityFilterSelectorConfig]
690  multiple: bool
691  filter: DeviceFilterSelectorConfig | list[DeviceFilterSelectorConfig]
692 
693 
694 @SELECTORS.register("device")
695 class DeviceSelector(Selector[DeviceSelectorConfig]):
696  """Selector of a single or list of devices."""
697 
698  selector_type = "device"
699 
700  CONFIG_SCHEMA = DEVICE_FILTER_SELECTOR_CONFIG_SCHEMA.extend(
701  {
702  vol.Optional("multiple", default=False): cv.boolean,
703  vol.Optional("filter"): vol.All(
704  cv.ensure_list,
705  [DEVICE_FILTER_SELECTOR_CONFIG_SCHEMA],
706  ),
707  },
708  )
709 
710  def __init__(self, config: DeviceSelectorConfig | None = None) -> None:
711  """Instantiate a selector."""
712  super().__init__(config)
713 
714  def __call__(self, data: Any) -> str | list[str]:
715  """Validate the passed selection."""
716  if not self.config["multiple"]:
717  device_id: str = vol.Schema(str)(data)
718  return device_id
719  if not isinstance(data, list):
720  raise vol.Invalid("Value should be a list")
721  return [vol.Schema(str)(val) for val in data]
722 
723 
724 class DurationSelectorConfig(TypedDict, total=False):
725  """Class to represent a duration selector config."""
726 
727  enable_day: bool
728  enable_millisecond: bool
729  allow_negative: bool
730 
731 
732 @SELECTORS.register("duration")
733 class DurationSelector(Selector[DurationSelectorConfig]):
734  """Selector for a duration."""
735 
736  selector_type = "duration"
737 
738  CONFIG_SCHEMA = vol.Schema(
739  {
740  # Enable day field in frontend. A selection with `days` set is allowed
741  # even if `enable_day` is not set
742  vol.Optional("enable_day"): cv.boolean,
743  # Enable millisecond field in frontend.
744  vol.Optional("enable_millisecond"): cv.boolean,
745  # Allow negative durations. Will default to False in HA Core 2025.6.0.
746  vol.Optional("allow_negative"): cv.boolean,
747  }
748  )
749 
750  def __init__(self, config: DurationSelectorConfig | None = None) -> None:
751  """Instantiate a selector."""
752  super().__init__(config)
753 
754  def __call__(self, data: Any) -> dict[str, float]:
755  """Validate the passed selection."""
756  if self.config.get("allow_negative", True):
757  cv.time_period_dict(data)
758  else:
759  cv.positive_time_period_dict(data)
760  return cast(dict[str, float], data)
761 
762 
764  """Class to represent an entity selector config."""
765 
766  exclude_entities: list[str]
767  include_entities: list[str]
768  multiple: bool
769  filter: EntityFilterSelectorConfig | list[EntityFilterSelectorConfig]
770 
771 
772 @SELECTORS.register("entity")
773 class EntitySelector(Selector[EntitySelectorConfig]):
774  """Selector of a single or list of entities."""
775 
776  selector_type = "entity"
777 
778  CONFIG_SCHEMA = ENTITY_FILTER_SELECTOR_CONFIG_SCHEMA.extend(
779  {
780  vol.Optional("exclude_entities"): [str],
781  vol.Optional("include_entities"): [str],
782  vol.Optional("multiple", default=False): cv.boolean,
783  vol.Optional("filter"): vol.All(
784  cv.ensure_list,
785  [ENTITY_FILTER_SELECTOR_CONFIG_SCHEMA],
786  ),
787  }
788  )
789 
790  def __init__(self, config: EntitySelectorConfig | None = None) -> None:
791  """Instantiate a selector."""
792  super().__init__(config)
793 
794  def __call__(self, data: Any) -> str | list[str]:
795  """Validate the passed selection."""
796 
797  include_entities = self.config.get("include_entities")
798  exclude_entities = self.config.get("exclude_entities")
799 
800  def validate(e_or_u: str) -> str:
801  e_or_u = cv.entity_id_or_uuid(e_or_u)
802  if not valid_entity_id(e_or_u):
803  return e_or_u
804  if allowed_domains := cv.ensure_list(self.config.get("domain")):
805  domain = split_entity_id(e_or_u)[0]
806  if domain not in allowed_domains:
807  raise vol.Invalid(
808  f"Entity {e_or_u} belongs to domain {domain}, "
809  f"expected {allowed_domains}"
810  )
811  if include_entities:
812  vol.In(include_entities)(e_or_u)
813  if exclude_entities:
814  vol.NotIn(exclude_entities)(e_or_u)
815  return e_or_u
816 
817  if not self.config["multiple"]:
818  return validate(data)
819  if not isinstance(data, list):
820  raise vol.Invalid("Value should be a list")
821  return cast(list, vol.Schema([validate])(data)) # Output is a list
822 
823 
824 class FloorSelectorConfig(TypedDict, total=False):
825  """Class to represent an floor selector config."""
826 
827  entity: EntityFilterSelectorConfig | list[EntityFilterSelectorConfig]
828  device: DeviceFilterSelectorConfig | list[DeviceFilterSelectorConfig]
829  multiple: bool
830 
831 
832 @SELECTORS.register("floor")
833 class FloorSelector(Selector[FloorSelectorConfig]):
834  """Selector of a single or list of floors."""
835 
836  selector_type = "floor"
837 
838  CONFIG_SCHEMA = vol.Schema(
839  {
840  vol.Optional("entity"): vol.All(
841  cv.ensure_list,
842  [ENTITY_FILTER_SELECTOR_CONFIG_SCHEMA],
843  ),
844  vol.Optional("device"): vol.All(
845  cv.ensure_list,
846  [DEVICE_FILTER_SELECTOR_CONFIG_SCHEMA],
847  ),
848  vol.Optional("multiple", default=False): cv.boolean,
849  }
850  )
851 
852  def __init__(self, config: FloorSelectorConfig | None = None) -> None:
853  """Instantiate a selector."""
854  super().__init__(config)
855 
856  def __call__(self, data: Any) -> str | list[str]:
857  """Validate the passed selection."""
858  if not self.config["multiple"]:
859  floor_id: str = vol.Schema(str)(data)
860  return floor_id
861  if not isinstance(data, list):
862  raise vol.Invalid("Value should be a list")
863  return [vol.Schema(str)(val) for val in data]
864 
865 
866 class IconSelectorConfig(TypedDict, total=False):
867  """Class to represent an icon selector config."""
868 
869  placeholder: str
870 
871 
872 @SELECTORS.register("icon")
873 class IconSelector(Selector[IconSelectorConfig]):
874  """Selector for an icon."""
875 
876  selector_type = "icon"
877 
878  CONFIG_SCHEMA = vol.Schema(
879  {vol.Optional("placeholder"): str}
880  # Frontend also has a fallbackPath option, this is not used by core
881  )
882 
883  def __init__(self, config: IconSelectorConfig | None = None) -> None:
884  """Instantiate a selector."""
885  super().__init__(config)
886 
887  def __call__(self, data: Any) -> str:
888  """Validate the passed selection."""
889  icon: str = vol.Schema(str)(data)
890  return icon
891 
892 
893 class LabelSelectorConfig(TypedDict, total=False):
894  """Class to represent a label selector config."""
895 
896  multiple: bool
897 
898 
899 @SELECTORS.register("label")
900 class LabelSelector(Selector[LabelSelectorConfig]):
901  """Selector of a single or list of labels."""
902 
903  selector_type = "label"
904 
905  CONFIG_SCHEMA = vol.Schema(
906  {
907  vol.Optional("multiple", default=False): cv.boolean,
908  }
909  )
910 
911  def __init__(self, config: LabelSelectorConfig | None = None) -> None:
912  """Instantiate a selector."""
913  super().__init__(config)
914 
915  def __call__(self, data: Any) -> str | list[str]:
916  """Validate the passed selection."""
917  if not self.config["multiple"]:
918  label_id: str = vol.Schema(str)(data)
919  return label_id
920  if not isinstance(data, list):
921  raise vol.Invalid("Value should be a list")
922  return [vol.Schema(str)(val) for val in data]
923 
924 
925 class LanguageSelectorConfig(TypedDict, total=False):
926  """Class to represent an language selector config."""
927 
928  languages: list[str]
929  native_name: bool
930  no_sort: bool
931 
932 
933 @SELECTORS.register("language")
934 class LanguageSelector(Selector[LanguageSelectorConfig]):
935  """Selector for an language."""
936 
937  selector_type = "language"
938 
939  CONFIG_SCHEMA = vol.Schema(
940  {
941  vol.Optional("languages"): [str],
942  vol.Optional("native_name", default=False): cv.boolean,
943  vol.Optional("no_sort", default=False): cv.boolean,
944  }
945  )
946 
947  def __init__(self, config: LanguageSelectorConfig | None = None) -> None:
948  """Instantiate a selector."""
949  super().__init__(config)
950 
951  def __call__(self, data: Any) -> str:
952  """Validate the passed selection."""
953  language: str = vol.Schema(str)(data)
954  if "languages" in self.config and language not in self.config["languages"]:
955  raise vol.Invalid(f"Value {language} is not a valid option")
956  return language
957 
958 
959 class LocationSelectorConfig(TypedDict, total=False):
960  """Class to represent a location selector config."""
961 
962  radius: bool
963  icon: str
964 
965 
966 @SELECTORS.register("location")
967 class LocationSelector(Selector[LocationSelectorConfig]):
968  """Selector for a location."""
969 
970  selector_type = "location"
971 
972  CONFIG_SCHEMA = vol.Schema(
973  {vol.Optional("radius"): bool, vol.Optional("icon"): str}
974  )
975  DATA_SCHEMA = vol.Schema(
976  {
977  vol.Required("latitude"): vol.Coerce(float),
978  vol.Required("longitude"): vol.Coerce(float),
979  vol.Optional("radius"): vol.Coerce(float),
980  }
981  )
982 
983  def __init__(self, config: LocationSelectorConfig | None = None) -> None:
984  """Instantiate a selector."""
985  super().__init__(config)
986 
987  def __call__(self, data: Any) -> dict[str, float]:
988  """Validate the passed selection."""
989  location: dict[str, float] = self.DATA_SCHEMADATA_SCHEMA(data)
990  return location
991 
992 
993 class MediaSelectorConfig(TypedDict):
994  """Class to represent a media selector config."""
995 
996 
997 @SELECTORS.register("media")
998 class MediaSelector(Selector[MediaSelectorConfig]):
999  """Selector for media."""
1000 
1001  selector_type = "media"
1002 
1003  CONFIG_SCHEMA = vol.Schema({})
1004  DATA_SCHEMA = vol.Schema(
1005  {
1006  # Although marked as optional in frontend, this field is required
1007  vol.Required("entity_id"): cv.entity_id_or_uuid,
1008  # Although marked as optional in frontend, this field is required
1009  vol.Required("media_content_id"): str,
1010  # Although marked as optional in frontend, this field is required
1011  vol.Required("media_content_type"): str,
1012  vol.Remove("metadata"): dict,
1013  }
1014  )
1015 
1016  def __init__(self, config: MediaSelectorConfig | None = None) -> None:
1017  """Instantiate a selector."""
1018  super().__init__(config)
1019 
1020  def __call__(self, data: Any) -> dict[str, float]:
1021  """Validate the passed selection."""
1022  media: dict[str, float] = self.DATA_SCHEMADATA_SCHEMA(data)
1023  return media
1024 
1025 
1026 class NumberSelectorConfig(TypedDict, total=False):
1027  """Class to represent a number selector config."""
1028 
1029  min: float
1030  max: float
1031  step: float | Literal["any"]
1032  unit_of_measurement: str
1033  mode: NumberSelectorMode
1034 
1035 
1036 class NumberSelectorMode(StrEnum):
1037  """Possible modes for a number selector."""
1038 
1039  BOX = "box"
1040  SLIDER = "slider"
1041 
1042 
1043 def validate_slider(data: Any) -> Any:
1044  """Validate configuration."""
1045  if data["mode"] == "box":
1046  return data
1047 
1048  if "min" not in data or "max" not in data:
1049  raise vol.Invalid("min and max are required in slider mode")
1050 
1051  return data
1052 
1053 
1054 @SELECTORS.register("number")
1055 class NumberSelector(Selector[NumberSelectorConfig]):
1056  """Selector of a numeric value."""
1057 
1058  selector_type = "number"
1059 
1060  CONFIG_SCHEMA = vol.All(
1061  vol.Schema(
1062  {
1063  vol.Optional("min"): vol.Coerce(float),
1064  vol.Optional("max"): vol.Coerce(float),
1065  # Controls slider steps, and up/down keyboard binding for the box
1066  # user input is not rounded
1067  vol.Optional("step", default=1): vol.Any(
1068  "any", vol.All(vol.Coerce(float), vol.Range(min=1e-3))
1069  ),
1070  vol.Optional(CONF_UNIT_OF_MEASUREMENT): str,
1071  vol.Optional(CONF_MODE, default=NumberSelectorMode.SLIDER): vol.All(
1072  vol.Coerce(NumberSelectorMode), lambda val: val.value
1073  ),
1074  }
1075  ),
1076  validate_slider,
1077  )
1078 
1079  def __init__(self, config: NumberSelectorConfig | None = None) -> None:
1080  """Instantiate a selector."""
1081  super().__init__(config)
1082 
1083  def __call__(self, data: Any) -> float:
1084  """Validate the passed selection."""
1085  value: float = vol.Coerce(float)(data)
1086 
1087  if "min" in self.config and value < self.config["min"]:
1088  raise vol.Invalid(f"Value {value} is too small")
1089 
1090  if "max" in self.config and value > self.config["max"]:
1091  raise vol.Invalid(f"Value {value} is too large")
1092 
1093  return value
1094 
1095 
1096 class ObjectSelectorConfig(TypedDict):
1097  """Class to represent an object selector config."""
1098 
1099 
1100 @SELECTORS.register("object")
1101 class ObjectSelector(Selector[ObjectSelectorConfig]):
1102  """Selector for an arbitrary object."""
1103 
1104  selector_type = "object"
1105 
1106  CONFIG_SCHEMA = vol.Schema({})
1107 
1108  def __init__(self, config: ObjectSelectorConfig | None = None) -> None:
1109  """Instantiate a selector."""
1110  super().__init__(config)
1111 
1112  def __call__(self, data: Any) -> Any:
1113  """Validate the passed selection."""
1114  return data
1115 
1116 
1117 select_option = vol.All(
1118  dict,
1119  vol.Schema(
1120  {
1121  vol.Required("value"): str,
1122  vol.Required("label"): str,
1123  }
1124  ),
1125 )
1126 
1127 
1128 class SelectOptionDict(TypedDict):
1129  """Class to represent a select option dict."""
1130 
1131  value: str
1132  label: str
1133 
1134 
1135 class SelectSelectorMode(StrEnum):
1136  """Possible modes for a number selector."""
1137 
1138  LIST = "list"
1139  DROPDOWN = "dropdown"
1140 
1141 
1142 class SelectSelectorConfig(TypedDict, total=False):
1143  """Class to represent a select selector config."""
1144 
1145  options: Required[Sequence[SelectOptionDict] | Sequence[str]]
1146  multiple: bool
1147  custom_value: bool
1148  mode: SelectSelectorMode
1149  translation_key: str
1150  sort: bool
1151 
1152 
1153 @SELECTORS.register("select")
1154 class SelectSelector(Selector[SelectSelectorConfig]):
1155  """Selector for an single-choice input select."""
1156 
1157  selector_type = "select"
1158 
1159  CONFIG_SCHEMA = vol.Schema(
1160  {
1161  vol.Required("options"): vol.All(vol.Any([str], [select_option])),
1162  vol.Optional("multiple", default=False): cv.boolean,
1163  vol.Optional("custom_value", default=False): cv.boolean,
1164  vol.Optional("mode"): vol.All(
1165  vol.Coerce(SelectSelectorMode), lambda val: val.value
1166  ),
1167  vol.Optional("translation_key"): cv.string,
1168  vol.Optional("sort", default=False): cv.boolean,
1169  }
1170  )
1171 
1172  def __init__(self, config: SelectSelectorConfig) -> None:
1173  """Instantiate a selector."""
1174  super().__init__(config)
1175 
1176  def __call__(self, data: Any) -> Any:
1177  """Validate the passed selection."""
1178  options: Sequence[str] = []
1179  if config_options := self.config["options"]:
1180  if isinstance(config_options[0], str):
1181  options = cast(Sequence[str], config_options)
1182  else:
1183  options = [
1184  option["value"]
1185  for option in cast(Sequence[SelectOptionDict], config_options)
1186  ]
1187 
1188  parent_schema: vol.In | vol.Any = vol.In(options)
1189  if self.config["custom_value"]:
1190  parent_schema = vol.Any(parent_schema, str)
1191 
1192  if not self.config["multiple"]:
1193  return parent_schema(vol.Schema(str)(data))
1194  if not isinstance(data, list):
1195  raise vol.Invalid("Value should be a list")
1196  return [parent_schema(vol.Schema(str)(val)) for val in data]
1197 
1198 
1199 class TargetSelectorConfig(TypedDict, total=False):
1200  """Class to represent a target selector config."""
1201 
1202  entity: EntityFilterSelectorConfig | list[EntityFilterSelectorConfig]
1203  device: DeviceFilterSelectorConfig | list[DeviceFilterSelectorConfig]
1204 
1205 
1206 class StateSelectorConfig(TypedDict, total=False):
1207  """Class to represent an state selector config."""
1208 
1209  entity_id: Required[str]
1210 
1211 
1212 @SELECTORS.register("state")
1213 class StateSelector(Selector[StateSelectorConfig]):
1214  """Selector for an entity state."""
1215 
1216  selector_type = "state"
1217 
1218  CONFIG_SCHEMA = vol.Schema(
1219  {
1220  vol.Required("entity_id"): cv.entity_id,
1221  # The attribute to filter on, is currently deliberately not
1222  # configurable/exposed. We are considering separating state
1223  # selectors into two types: one for state and one for attribute.
1224  # Limiting the public use, prevents breaking changes in the future.
1225  # vol.Optional("attribute"): str,
1226  }
1227  )
1228 
1229  def __init__(self, config: StateSelectorConfig) -> None:
1230  """Instantiate a selector."""
1231  super().__init__(config)
1232 
1233  def __call__(self, data: Any) -> str:
1234  """Validate the passed selection."""
1235  state: str = vol.Schema(str)(data)
1236  return state
1237 
1238 
1239 @SELECTORS.register("target")
1240 class TargetSelector(Selector[TargetSelectorConfig]):
1241  """Selector of a target value (area ID, device ID, entity ID etc).
1242 
1243  Value should follow cv.TARGET_SERVICE_FIELDS format.
1244  """
1245 
1246  selector_type = "target"
1247 
1248  CONFIG_SCHEMA = vol.Schema(
1249  {
1250  vol.Optional("entity"): vol.All(
1251  cv.ensure_list,
1252  [ENTITY_FILTER_SELECTOR_CONFIG_SCHEMA],
1253  ),
1254  vol.Optional("device"): vol.All(
1255  cv.ensure_list,
1256  [DEVICE_FILTER_SELECTOR_CONFIG_SCHEMA],
1257  ),
1258  }
1259  )
1260 
1261  TARGET_SELECTION_SCHEMA = vol.Schema(cv.TARGET_SERVICE_FIELDS)
1262 
1263  def __init__(self, config: TargetSelectorConfig | None = None) -> None:
1264  """Instantiate a selector."""
1265  super().__init__(config)
1266 
1267  def __call__(self, data: Any) -> dict[str, list[str]]:
1268  """Validate the passed selection."""
1269  target: dict[str, list[str]] = self.TARGET_SELECTION_SCHEMATARGET_SELECTION_SCHEMA(data)
1270  return target
1271 
1272 
1273 class TemplateSelectorConfig(TypedDict):
1274  """Class to represent an template selector config."""
1275 
1276 
1277 @SELECTORS.register("template")
1278 class TemplateSelector(Selector[TemplateSelectorConfig]):
1279  """Selector for an template."""
1280 
1281  selector_type = "template"
1282 
1283  CONFIG_SCHEMA = vol.Schema({})
1284 
1285  def __init__(self, config: TemplateSelectorConfig | None = None) -> None:
1286  """Instantiate a selector."""
1287  super().__init__(config)
1288 
1289  def __call__(self, data: Any) -> str:
1290  """Validate the passed selection."""
1291  template = cv.template(data)
1292  return template.template
1293 
1294 
1295 class TextSelectorConfig(TypedDict, total=False):
1296  """Class to represent a text selector config."""
1297 
1298  multiline: bool
1299  prefix: str
1300  suffix: str
1301  type: TextSelectorType
1302  autocomplete: str
1303  multiple: bool
1304 
1305 
1306 class TextSelectorType(StrEnum):
1307  """Enum for text selector types."""
1308 
1309  COLOR = "color"
1310  DATE = "date"
1311  DATETIME_LOCAL = "datetime-local"
1312  EMAIL = "email"
1313  MONTH = "month"
1314  NUMBER = "number"
1315  PASSWORD = "password"
1316  SEARCH = "search"
1317  TEL = "tel"
1318  TEXT = "text"
1319  TIME = "time"
1320  URL = "url"
1321  WEEK = "week"
1322 
1323 
1324 @SELECTORS.register("text")
1325 class TextSelector(Selector[TextSelectorConfig]):
1326  """Selector for a multi-line text string."""
1327 
1328  selector_type = "text"
1329 
1330  CONFIG_SCHEMA = vol.Schema(
1331  {
1332  vol.Optional("multiline", default=False): bool,
1333  vol.Optional("prefix"): str,
1334  vol.Optional("suffix"): str,
1335  # The "type" controls the input field in the browser, the resulting
1336  # data can be any string so we don't validate it.
1337  vol.Optional("type"): vol.All(
1338  vol.Coerce(TextSelectorType), lambda val: val.value
1339  ),
1340  vol.Optional("autocomplete"): str,
1341  vol.Optional("multiple", default=False): bool,
1342  }
1343  )
1344 
1345  def __init__(self, config: TextSelectorConfig | None = None) -> None:
1346  """Instantiate a selector."""
1347  super().__init__(config)
1348 
1349  def __call__(self, data: Any) -> str | list[str]:
1350  """Validate the passed selection."""
1351  if not self.config["multiple"]:
1352  text: str = vol.Schema(str)(data)
1353  return text
1354  if not isinstance(data, list):
1355  raise vol.Invalid("Value should be a list")
1356  return [vol.Schema(str)(val) for val in data]
1357 
1358 
1359 class ThemeSelectorConfig(TypedDict):
1360  """Class to represent a theme selector config."""
1361 
1362 
1363 @SELECTORS.register("theme")
1364 class ThemeSelector(Selector[ThemeSelectorConfig]):
1365  """Selector for an theme."""
1366 
1367  selector_type = "theme"
1368 
1369  CONFIG_SCHEMA = vol.Schema(
1370  {
1371  vol.Optional("include_default", default=False): cv.boolean,
1372  }
1373  )
1374 
1375  def __init__(self, config: ThemeSelectorConfig | None = None) -> None:
1376  """Instantiate a selector."""
1377  super().__init__(config)
1378 
1379  def __call__(self, data: Any) -> str:
1380  """Validate the passed selection."""
1381  theme: str = vol.Schema(str)(data)
1382  return theme
1383 
1384 
1385 class TimeSelectorConfig(TypedDict):
1386  """Class to represent a time selector config."""
1387 
1388 
1389 @SELECTORS.register("time")
1390 class TimeSelector(Selector[TimeSelectorConfig]):
1391  """Selector of a time value."""
1392 
1393  selector_type = "time"
1394 
1395  CONFIG_SCHEMA = vol.Schema({})
1396 
1397  def __init__(self, config: TimeSelectorConfig | None = None) -> None:
1398  """Instantiate a selector."""
1399  super().__init__(config)
1400 
1401  def __call__(self, data: Any) -> str:
1402  """Validate the passed selection."""
1403  cv.time(data)
1404  return cast(str, data)
1405 
1406 
1407 class TriggerSelectorConfig(TypedDict):
1408  """Class to represent an trigger selector config."""
1409 
1410 
1411 @SELECTORS.register("trigger")
1412 class TriggerSelector(Selector[TriggerSelectorConfig]):
1413  """Selector of a trigger sequence (script syntax)."""
1414 
1415  selector_type = "trigger"
1416 
1417  CONFIG_SCHEMA = vol.Schema({})
1418 
1419  def __init__(self, config: TriggerSelectorConfig | None = None) -> None:
1420  """Instantiate a selector."""
1421  super().__init__(config)
1422 
1423  def __call__(self, data: Any) -> Any:
1424  """Validate the passed selection."""
1425  return vol.Schema(cv.TRIGGER_SCHEMA)(data)
1426 
1427 
1428 class FileSelectorConfig(TypedDict):
1429  """Class to represent a file selector config."""
1430 
1431  accept: str # required
1432 
1433 
1434 @SELECTORS.register("file")
1435 class FileSelector(Selector[FileSelectorConfig]):
1436  """Selector of a file."""
1437 
1438  selector_type = "file"
1439 
1440  CONFIG_SCHEMA = vol.Schema(
1441  {
1442  # https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#accept
1443  vol.Required("accept"): str,
1444  }
1445  )
1446 
1447  def __init__(self, config: FileSelectorConfig) -> None:
1448  """Instantiate a selector."""
1449  super().__init__(config)
1450 
1451  def __call__(self, data: Any) -> str:
1452  """Validate the passed selection."""
1453  if not isinstance(data, str):
1454  raise vol.Invalid("Value should be a string")
1455 
1456  UUID(data)
1457 
1458  return data
1459 
1460 
1461 dumper.add_representer(
1462  Selector,
1463  lambda dumper, value: dumper.represent_odict(
1464  dumper, "tag:yaml.org,2002:map", value.serialize()
1465  ),
1466 )
None __init__(self, ActionSelectorConfig|None config=None)
Definition: selector.py:195
None __init__(self, AddonSelectorConfig|None config=None)
Definition: selector.py:224
None __init__(self, AreaSelectorConfig|None config=None)
Definition: selector.py:262
str|list[str] __call__(self, Any data)
Definition: selector.py:266
None __init__(self, AssistPipelineSelectorConfig|None config=None)
Definition: selector.py:288
None __init__(self, AttributeSelectorConfig config)
Definition: selector.py:320
None __init__(self, BackupLocationSelectorConfig|None config=None)
Definition: selector.py:342
None __init__(self, BooleanSelectorConfig|None config=None)
Definition: selector.py:364
None __init__(self, ColorRGBSelectorConfig|None config=None)
Definition: selector.py:386
None __init__(self, ColorTempSelectorConfig|None config=None)
Definition: selector.py:431
None __init__(self, ConditionSelectorConfig|None config=None)
Definition: selector.py:468
None __init__(self, ConfigEntrySelectorConfig|None config=None)
Definition: selector.py:495
None __init__(self, ConstantSelectorConfig config)
Definition: selector.py:527
None __init__(self, ConversationAgentSelectorConfig|None config=None)
Definition: selector.py:598
None __init__(self, CountrySelectorConfig|None config=None)
Definition: selector.py:628
None __init__(self, DateSelectorConfig|None config=None)
Definition: selector.py:654
None __init__(self, DateTimeSelectorConfig|None config=None)
Definition: selector.py:676
str|list[str] __call__(self, Any data)
Definition: selector.py:714
None __init__(self, DeviceSelectorConfig|None config=None)
Definition: selector.py:710
None __init__(self, DurationSelectorConfig|None config=None)
Definition: selector.py:750
dict[str, float] __call__(self, Any data)
Definition: selector.py:754
None __init__(self, EntitySelectorConfig|None config=None)
Definition: selector.py:790
str|list[str] __call__(self, Any data)
Definition: selector.py:794
None __init__(self, FileSelectorConfig config)
Definition: selector.py:1447
str|list[str] __call__(self, Any data)
Definition: selector.py:856
None __init__(self, FloorSelectorConfig|None config=None)
Definition: selector.py:852
None __init__(self, IconSelectorConfig|None config=None)
Definition: selector.py:883
str|list[str] __call__(self, Any data)
Definition: selector.py:915
None __init__(self, LabelSelectorConfig|None config=None)
Definition: selector.py:911
None __init__(self, LanguageSelectorConfig|None config=None)
Definition: selector.py:947
dict[str, float] __call__(self, Any data)
Definition: selector.py:987
None __init__(self, LocationSelectorConfig|None config=None)
Definition: selector.py:983
None __init__(self, MediaSelectorConfig|None config=None)
Definition: selector.py:1016
dict[str, float] __call__(self, Any data)
Definition: selector.py:1020
None __init__(self, NumberSelectorConfig|None config=None)
Definition: selector.py:1079
None __init__(self, ObjectSelectorConfig|None config=None)
Definition: selector.py:1108
None __init__(self, QrCodeSelectorConfig config)
Definition: selector.py:570
None __init__(self, SelectSelectorConfig config)
Definition: selector.py:1172
None __init__(self, StateSelectorConfig config)
Definition: selector.py:1229
dict[str, list[str]] __call__(self, Any data)
Definition: selector.py:1267
None __init__(self, TargetSelectorConfig|None config=None)
Definition: selector.py:1263
None __init__(self, TemplateSelectorConfig|None config=None)
Definition: selector.py:1285
None __init__(self, ThemeSelectorConfig|None config=None)
Definition: selector.py:1375
None __init__(self, TimeSelectorConfig|None config=None)
Definition: selector.py:1397
None __init__(self, TriggerSelectorConfig|None config=None)
Definition: selector.py:1419
web.Response get(self, web.Request request, str config_key)
Definition: view.py:88
dict[str, Any] validate(SchemaCommonFlowHandler handler, dict[str, Any] user_input)
Definition: config_flow.py:27
bool valid_entity_id(str entity_id)
Definition: core.py:235
tuple[str, str] split_entity_id(str entity_id)
Definition: core.py:214
int _validate_supported_features(int|list[str] supported_features)
Definition: selector.py:120
Selector selector(Any config)
Definition: selector.py:41
None __init__(self, Mapping[str, Any]|None config=None)
Definition: selector.py:70
int _entity_feature_flag(str domain, str enum_name, str feature_name)
Definition: selector.py:91
dict validate_selector(Any config)
Definition: selector.py:49
bool __eq__(self, object other)
Definition: selector.py:78
type[Selector] _get_selector_class(Any config)
Definition: selector.py:25
int _validate_supported_feature(str supported_feature)
Definition: selector.py:103
dict[str, dict[str, _T]] serialize(self)
Definition: selector.py:85