Home Assistant Unofficial Reference 2024.12.1
select.py
Go to the documentation of this file.
1 """Support for selects which integrates with other components."""
2 
3 from __future__ import annotations
4 
5 import logging
6 from typing import Any
7 
8 import voluptuous as vol
9 
11  ATTR_OPTION,
12  ATTR_OPTIONS,
13  DOMAIN as SELECT_DOMAIN,
14  SelectEntity,
15 )
16 from homeassistant.config_entries import ConfigEntry
17 from homeassistant.const import (
18  CONF_DEVICE_ID,
19  CONF_NAME,
20  CONF_OPTIMISTIC,
21  CONF_STATE,
22  CONF_UNIQUE_ID,
23 )
24 from homeassistant.core import HomeAssistant, callback
25 from homeassistant.helpers import config_validation as cv, selector
26 from homeassistant.helpers.device import async_device_info_to_link_from_device_id
27 from homeassistant.helpers.entity_platform import AddEntitiesCallback
28 from homeassistant.helpers.script import Script
29 from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
30 
31 from . import TriggerUpdateCoordinator
32 from .const import DOMAIN
33 from .template_entity import (
34  TEMPLATE_ENTITY_AVAILABILITY_SCHEMA,
35  TEMPLATE_ENTITY_ICON_SCHEMA,
36  TemplateEntity,
37 )
38 from .trigger_entity import TriggerEntity
39 
40 _LOGGER = logging.getLogger(__name__)
41 
42 CONF_OPTIONS = "options"
43 CONF_SELECT_OPTION = "select_option"
44 
45 DEFAULT_NAME = "Template Select"
46 DEFAULT_OPTIMISTIC = False
47 
48 SELECT_SCHEMA = (
49  vol.Schema(
50  {
51  vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.template,
52  vol.Required(CONF_STATE): cv.template,
53  vol.Required(CONF_SELECT_OPTION): cv.SCRIPT_SCHEMA,
54  vol.Required(ATTR_OPTIONS): cv.template,
55  vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean,
56  vol.Optional(CONF_UNIQUE_ID): cv.string,
57  }
58  )
59  .extend(TEMPLATE_ENTITY_AVAILABILITY_SCHEMA.schema)
60  .extend(TEMPLATE_ENTITY_ICON_SCHEMA.schema)
61 )
62 
63 
64 SELECT_CONFIG_SCHEMA = vol.Schema(
65  {
66  vol.Required(CONF_NAME): cv.template,
67  vol.Required(CONF_STATE): cv.template,
68  vol.Required(CONF_OPTIONS): cv.template,
69  vol.Optional(CONF_SELECT_OPTION): cv.SCRIPT_SCHEMA,
70  vol.Optional(CONF_DEVICE_ID): selector.DeviceSelector(),
71  }
72 )
73 
74 
76  hass: HomeAssistant, definitions: list[dict[str, Any]], unique_id_prefix: str | None
77 ) -> list[TemplateSelect]:
78  """Create the Template select."""
79  entities = []
80  for definition in definitions:
81  unique_id = definition.get(CONF_UNIQUE_ID)
82  if unique_id and unique_id_prefix:
83  unique_id = f"{unique_id_prefix}-{unique_id}"
84  entities.append(TemplateSelect(hass, definition, unique_id))
85  return entities
86 
87 
89  hass: HomeAssistant,
90  config: ConfigType,
91  async_add_entities: AddEntitiesCallback,
92  discovery_info: DiscoveryInfoType | None = None,
93 ) -> None:
94  """Set up the template select."""
95  if discovery_info is None:
96  _LOGGER.warning(
97  "Template select entities can only be configured under template:"
98  )
99  return
100 
101  if "coordinator" in discovery_info:
103  TriggerSelectEntity(hass, discovery_info["coordinator"], config)
104  for config in discovery_info["entities"]
105  )
106  return
107 
110  hass, discovery_info["entities"], discovery_info["unique_id"]
111  )
112  )
113 
114 
116  hass: HomeAssistant,
117  config_entry: ConfigEntry,
118  async_add_entities: AddEntitiesCallback,
119 ) -> None:
120  """Initialize config entry."""
121  _options = dict(config_entry.options)
122  _options.pop("template_type")
123  validated_config = SELECT_CONFIG_SCHEMA(_options)
124  async_add_entities([TemplateSelect(hass, validated_config, config_entry.entry_id)])
125 
126 
128  """Representation of a template select."""
129 
130  _attr_should_poll = False
131 
132  def __init__(
133  self,
134  hass: HomeAssistant,
135  config: dict[str, Any],
136  unique_id: str | None,
137  ) -> None:
138  """Initialize the select."""
139  super().__init__(hass, config=config, unique_id=unique_id)
140  assert self._attr_name_attr_name is not None
141  self._value_template_value_template = config[CONF_STATE]
142  if (selection_option := config.get(CONF_SELECT_OPTION)) is not None:
143  self._command_select_option_command_select_option = Script(
144  hass, selection_option, self._attr_name_attr_name, DOMAIN
145  )
146  self._options_template_options_template = config[ATTR_OPTIONS]
147  self._attr_assumed_state_attr_assumed_state = self._optimistic_optimistic = config.get(CONF_OPTIMISTIC, False)
148  self._attr_options_attr_options = []
149  self._attr_current_option_attr_current_option = None
151  hass,
152  config.get(CONF_DEVICE_ID),
153  )
154 
155  @callback
156  def _async_setup_templates(self) -> None:
157  """Set up templates."""
158  self.add_template_attributeadd_template_attribute(
159  "_attr_current_option",
160  self._value_template_value_template,
161  validator=cv.string,
162  none_on_template_error=True,
163  )
164  self.add_template_attributeadd_template_attribute(
165  "_attr_options",
166  self._options_template_options_template,
167  validator=vol.All(cv.ensure_list, [cv.string]),
168  none_on_template_error=True,
169  )
170  super()._async_setup_templates()
171 
172  async def async_select_option(self, option: str) -> None:
173  """Change the selected option."""
174  if self._optimistic_optimistic:
175  self._attr_current_option_attr_current_option = option
176  self.async_write_ha_stateasync_write_ha_state()
177  if self._command_select_option_command_select_option:
178  await self.async_run_scriptasync_run_script(
179  self._command_select_option_command_select_option,
180  run_variables={ATTR_OPTION: option},
181  context=self._context_context,
182  )
183 
184 
186  """Select entity based on trigger data."""
187 
188  domain = SELECT_DOMAIN
189  extra_template_keys = (CONF_STATE,)
190  extra_template_keys_complex = (ATTR_OPTIONS,)
191 
192  def __init__(
193  self,
194  hass: HomeAssistant,
195  coordinator: TriggerUpdateCoordinator,
196  config: dict,
197  ) -> None:
198  """Initialize the entity."""
199  super().__init__(hass, coordinator, config)
200  self._command_select_option_command_select_option = Script(
201  hass,
202  config[CONF_SELECT_OPTION],
203  self._rendered.get(CONF_NAME, DEFAULT_NAME),
204  DOMAIN,
205  )
206 
207  @property
208  def current_option(self) -> str | None:
209  """Return the currently selected option."""
210  return self._rendered.get(CONF_STATE)
211 
212  @property
213  def options(self) -> list[str]:
214  """Return the list of available options."""
215  return self._rendered.get(ATTR_OPTIONS, [])
216 
217  async def async_select_option(self, option: str) -> None:
218  """Change the selected option."""
219  if self._config[CONF_OPTIMISTIC]:
220  self._attr_current_option_attr_current_option = option
221  self.async_write_ha_stateasync_write_ha_state()
222  await self._command_select_option_command_select_option.async_run(
223  {ATTR_OPTION: option}, context=self._context_context
224  )
None __init__(self, HomeAssistant hass, dict[str, Any] config, str|None unique_id)
Definition: select.py:137
None __init__(self, HomeAssistant hass, TriggerUpdateCoordinator coordinator, dict config)
Definition: select.py:197
None async_run_script(self, Script script, *_VarsType|None run_variables=None, Context|None context=None)
None add_template_attribute(self, str attribute, Template template, Callable[[Any], Any]|None validator=None, Callable[[Any], None]|None on_update=None, bool none_on_template_error=False)
web.Response get(self, web.Request request, str config_key)
Definition: view.py:88
None async_setup_platform(HomeAssistant hass, ConfigType config, AddEntitiesCallback async_add_entities, DiscoveryInfoType|None discovery_info=None)
Definition: select.py:93
list[TemplateSelect] _async_create_entities(HomeAssistant hass, list[dict[str, Any]] definitions, str|None unique_id_prefix)
Definition: select.py:77
None async_setup_entry(HomeAssistant hass, ConfigEntry config_entry, AddEntitiesCallback async_add_entities)
Definition: select.py:119
dr.DeviceInfo|None async_device_info_to_link_from_device_id(HomeAssistant hass, str|None device_id)
Definition: device.py:44