Home Assistant Unofficial Reference 2024.12.1
switch.py
Go to the documentation of this file.
1 """Support for switches which integrates with other components."""
2 
3 from __future__ import annotations
4 
5 from typing import Any
6 
7 import voluptuous as vol
8 
10  ENTITY_ID_FORMAT,
11  PLATFORM_SCHEMA as SWITCH_PLATFORM_SCHEMA,
12  SwitchEntity,
13 )
14 from homeassistant.config_entries import ConfigEntry
15 from homeassistant.const import (
16  ATTR_ENTITY_ID,
17  ATTR_FRIENDLY_NAME,
18  CONF_DEVICE_ID,
19  CONF_NAME,
20  CONF_SWITCHES,
21  CONF_UNIQUE_ID,
22  CONF_VALUE_TEMPLATE,
23  STATE_OFF,
24  STATE_ON,
25 )
26 from homeassistant.core import HomeAssistant, callback
27 from homeassistant.exceptions import TemplateError
28 from homeassistant.helpers import config_validation as cv, selector
29 from homeassistant.helpers.device import async_device_info_to_link_from_device_id
30 from homeassistant.helpers.entity import async_generate_entity_id
31 from homeassistant.helpers.entity_platform import AddEntitiesCallback
32 from homeassistant.helpers.restore_state import RestoreEntity
33 from homeassistant.helpers.script import Script
34 from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
35 
36 from .const import CONF_TURN_OFF, CONF_TURN_ON, DOMAIN
37 from .template_entity import (
38  TEMPLATE_ENTITY_COMMON_SCHEMA_LEGACY,
39  TemplateEntity,
40  rewrite_common_legacy_to_modern_conf,
41 )
42 
43 _VALID_STATES = [STATE_ON, STATE_OFF, "true", "false"]
44 
45 SWITCH_SCHEMA = vol.All(
46  cv.deprecated(ATTR_ENTITY_ID),
47  vol.Schema(
48  {
49  vol.Optional(CONF_VALUE_TEMPLATE): cv.template,
50  vol.Required(CONF_TURN_ON): cv.SCRIPT_SCHEMA,
51  vol.Required(CONF_TURN_OFF): cv.SCRIPT_SCHEMA,
52  vol.Optional(ATTR_FRIENDLY_NAME): cv.string,
53  vol.Optional(ATTR_ENTITY_ID): cv.entity_ids,
54  vol.Optional(CONF_UNIQUE_ID): cv.string,
55  }
56  ).extend(TEMPLATE_ENTITY_COMMON_SCHEMA_LEGACY.schema),
57 )
58 
59 PLATFORM_SCHEMA = SWITCH_PLATFORM_SCHEMA.extend(
60  {vol.Required(CONF_SWITCHES): cv.schema_with_slug_keys(SWITCH_SCHEMA)}
61 )
62 
63 SWITCH_CONFIG_SCHEMA = vol.Schema(
64  {
65  vol.Required(CONF_NAME): cv.template,
66  vol.Optional(CONF_VALUE_TEMPLATE): cv.template,
67  vol.Optional(CONF_TURN_ON): cv.SCRIPT_SCHEMA,
68  vol.Optional(CONF_TURN_OFF): cv.SCRIPT_SCHEMA,
69  vol.Optional(CONF_DEVICE_ID): selector.DeviceSelector(),
70  }
71 )
72 
73 
74 async def _async_create_entities(hass, config):
75  """Create the Template switches."""
76  switches = []
77 
78  for object_id, entity_config in config[CONF_SWITCHES].items():
79  entity_config = rewrite_common_legacy_to_modern_conf(hass, entity_config)
80  unique_id = entity_config.get(CONF_UNIQUE_ID)
81 
82  switches.append(
84  hass,
85  object_id,
86  entity_config,
87  unique_id,
88  )
89  )
90 
91  return switches
92 
93 
95  hass: HomeAssistant,
96  config: ConfigType,
97  async_add_entities: AddEntitiesCallback,
98  discovery_info: DiscoveryInfoType | None = None,
99 ) -> None:
100  """Set up the template switches."""
101  async_add_entities(await _async_create_entities(hass, config))
102 
103 
105  hass: HomeAssistant,
106  config_entry: ConfigEntry,
107  async_add_entities: AddEntitiesCallback,
108 ) -> None:
109  """Initialize config entry."""
110  _options = dict(config_entry.options)
111  _options.pop("template_type")
112  validated_config = SWITCH_CONFIG_SCHEMA(_options)
114  [SwitchTemplate(hass, None, validated_config, config_entry.entry_id)]
115  )
116 
117 
118 @callback
120  hass: HomeAssistant, name: str, config: dict[str, Any]
121 ) -> SwitchTemplate:
122  """Create a preview switch."""
123  validated_config = SWITCH_CONFIG_SCHEMA(config | {CONF_NAME: name})
124  return SwitchTemplate(hass, None, validated_config, None)
125 
126 
128  """Representation of a Template switch."""
129 
130  _attr_should_poll = False
131 
132  def __init__(
133  self,
134  hass,
135  object_id,
136  config,
137  unique_id,
138  ):
139  """Initialize the Template switch."""
140  super().__init__(
141  hass, config=config, fallback_name=object_id, unique_id=unique_id
142  )
143  if object_id is not None:
145  ENTITY_ID_FORMAT, object_id, hass=hass
146  )
147  friendly_name = self._attr_name_attr_name
148  self._template_template = config.get(CONF_VALUE_TEMPLATE)
149  self._on_script_on_script = (
150  Script(hass, config.get(CONF_TURN_ON), friendly_name, DOMAIN)
151  if config.get(CONF_TURN_ON) is not None
152  else None
153  )
154  self._off_script_off_script = (
155  Script(hass, config.get(CONF_TURN_OFF), friendly_name, DOMAIN)
156  if config.get(CONF_TURN_OFF) is not None
157  else None
158  )
159  self._state_state: bool | None = False
160  self._attr_assumed_state_attr_assumed_state = self._template_template is None
162  hass,
163  config.get(CONF_DEVICE_ID),
164  )
165 
166  @callback
167  def _update_state(self, result):
168  super()._update_state(result)
169  if isinstance(result, TemplateError):
170  self._state_state = None
171  return
172 
173  if isinstance(result, bool):
174  self._state_state = result
175  return
176 
177  if isinstance(result, str):
178  self._state_state = result.lower() in ("true", STATE_ON)
179  return
180 
181  self._state_state = False
182 
183  async def async_added_to_hass(self) -> None:
184  """Register callbacks."""
185  if self._template_template is None:
186  # restore state after startup
187  await super().async_added_to_hass()
188  if state := await self.async_get_last_stateasync_get_last_state():
189  self._state_state = state.state == STATE_ON
190  await super().async_added_to_hass()
191 
192  @callback
193  def _async_setup_templates(self) -> None:
194  """Set up templates."""
195  if self._template_template is not None:
196  self.add_template_attributeadd_template_attribute(
197  "_state", self._template_template, None, self._update_state_update_state_update_state
198  )
199 
200  super()._async_setup_templates()
201 
202  @property
203  def is_on(self) -> bool | None:
204  """Return true if device is on."""
205  return self._state_state
206 
207  async def async_turn_on(self, **kwargs: Any) -> None:
208  """Fire the on action."""
209  if self._on_script_on_script:
210  await self.async_run_scriptasync_run_script(self._on_script_on_script, context=self._context_context)
211  if self._template_template is None:
212  self._state_state = True
213  self.async_write_ha_stateasync_write_ha_state()
214 
215  async def async_turn_off(self, **kwargs: Any) -> None:
216  """Fire the off action."""
217  if self._off_script_off_script:
218  await self.async_run_scriptasync_run_script(self._off_script_off_script, context=self._context_context)
219  if self._template_template is None:
220  self._state_state = False
221  self.async_write_ha_stateasync_write_ha_state()
def __init__(self, hass, object_id, config, unique_id)
Definition: switch.py:138
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)
def _async_create_entities(hass, config)
Definition: switch.py:74
None async_setup_entry(HomeAssistant hass, ConfigEntry config_entry, AddEntitiesCallback async_add_entities)
Definition: switch.py:108
SwitchTemplate async_create_preview_switch(HomeAssistant hass, str name, dict[str, Any] config)
Definition: switch.py:121
None async_setup_platform(HomeAssistant hass, ConfigType config, AddEntitiesCallback async_add_entities, DiscoveryInfoType|None discovery_info=None)
Definition: switch.py:99
dict[str, Any] rewrite_common_legacy_to_modern_conf(HomeAssistant hass, dict[str, Any] entity_cfg, dict[str, str]|None extra_legacy_fields=None)
dr.DeviceInfo|None async_device_info_to_link_from_device_id(HomeAssistant hass, str|None device_id)
Definition: device.py:44
str async_generate_entity_id(str entity_id_format, str|None name, Iterable[str]|None current_ids=None, HomeAssistant|None hass=None)
Definition: entity.py:119