Home Assistant Unofficial Reference 2024.12.1
switch.py
Go to the documentation of this file.
1 """Platform allowing several switches to be grouped into one switch."""
2 
3 from __future__ import annotations
4 
5 import logging
6 from typing import Any
7 
8 import voluptuous as vol
9 
11  DOMAIN as SWITCH_DOMAIN,
12  PLATFORM_SCHEMA as SWITCH_PLATFORM_SCHEMA,
13  SwitchEntity,
14 )
15 from homeassistant.config_entries import ConfigEntry
16 from homeassistant.const import (
17  ATTR_ENTITY_ID,
18  CONF_ENTITIES,
19  CONF_NAME,
20  CONF_UNIQUE_ID,
21  SERVICE_TURN_OFF,
22  SERVICE_TURN_ON,
23  STATE_ON,
24  STATE_UNAVAILABLE,
25  STATE_UNKNOWN,
26 )
27 from homeassistant.core import HomeAssistant, callback
28 from homeassistant.helpers import config_validation as cv, entity_registry as er
29 from homeassistant.helpers.entity_platform import AddEntitiesCallback
30 from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
31 
32 from .entity import GroupEntity
33 
34 DEFAULT_NAME = "Switch Group"
35 CONF_ALL = "all"
36 
37 # No limit on parallel updates to enable a group calling another group
38 PARALLEL_UPDATES = 0
39 
40 PLATFORM_SCHEMA = SWITCH_PLATFORM_SCHEMA.extend(
41  {
42  vol.Required(CONF_ENTITIES): cv.entities_domain(SWITCH_DOMAIN),
43  vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
44  vol.Optional(CONF_UNIQUE_ID): cv.string,
45  vol.Optional(CONF_ALL, default=False): cv.boolean,
46  }
47 )
48 
49 _LOGGER = logging.getLogger(__name__)
50 
51 
53  hass: HomeAssistant,
54  config: ConfigType,
55  async_add_entities: AddEntitiesCallback,
56  discovery_info: DiscoveryInfoType | None = None,
57 ) -> None:
58  """Set up the Switch Group platform."""
60  [
62  config.get(CONF_UNIQUE_ID),
63  config[CONF_NAME],
64  config[CONF_ENTITIES],
65  config.get(CONF_ALL, False),
66  )
67  ]
68  )
69 
70 
72  hass: HomeAssistant,
73  config_entry: ConfigEntry,
74  async_add_entities: AddEntitiesCallback,
75 ) -> None:
76  """Initialize Switch Group config entry."""
77  registry = er.async_get(hass)
78  entities = er.async_validate_entity_ids(
79  registry, config_entry.options[CONF_ENTITIES]
80  )
82  [
84  config_entry.entry_id,
85  config_entry.title,
86  entities,
87  config_entry.options.get(CONF_ALL),
88  )
89  ]
90  )
91 
92 
93 @callback
95  hass: HomeAssistant, name: str, validated_config: dict[str, Any]
96 ) -> SwitchGroup:
97  """Create a preview sensor."""
98  return SwitchGroup(
99  None,
100  name,
101  validated_config[CONF_ENTITIES],
102  validated_config.get(CONF_ALL, False),
103  )
104 
105 
107  """Representation of a switch group."""
108 
109  _attr_available = False
110  _attr_should_poll = False
111 
112  def __init__(
113  self,
114  unique_id: str | None,
115  name: str,
116  entity_ids: list[str],
117  mode: bool | None,
118  ) -> None:
119  """Initialize a switch group."""
120  self._entity_ids_entity_ids = entity_ids
121 
122  self._attr_name_attr_name = name
123  self._attr_extra_state_attributes_attr_extra_state_attributes = {ATTR_ENTITY_ID: entity_ids}
124  self._attr_unique_id_attr_unique_id = unique_id
125  self.modemode = any
126  if mode:
127  self.modemode = all
128 
129  async def async_turn_on(self, **kwargs: Any) -> None:
130  """Forward the turn_on command to all switches in the group."""
131  data = {ATTR_ENTITY_ID: self._entity_ids_entity_ids}
132  _LOGGER.debug("Forwarded turn_on command: %s", data)
133 
134  await self.hasshass.services.async_call(
135  SWITCH_DOMAIN,
136  SERVICE_TURN_ON,
137  data,
138  blocking=True,
139  context=self._context_context,
140  )
141 
142  async def async_turn_off(self, **kwargs: Any) -> None:
143  """Forward the turn_off command to all switches in the group."""
144  data = {ATTR_ENTITY_ID: self._entity_ids_entity_ids}
145  await self.hasshass.services.async_call(
146  SWITCH_DOMAIN,
147  SERVICE_TURN_OFF,
148  data,
149  blocking=True,
150  context=self._context_context,
151  )
152 
153  @callback
154  def async_update_group_state(self) -> None:
155  """Query all members and determine the switch group state."""
156  states = [
157  state.state
158  for entity_id in self._entity_ids_entity_ids
159  if (state := self.hasshass.states.get(entity_id)) is not None
160  ]
161 
162  valid_state = self.modemode(
163  state not in (STATE_UNKNOWN, STATE_UNAVAILABLE) for state in states
164  )
165 
166  if not valid_state:
167  # Set as unknown if any / all member is unknown or unavailable
168  self._attr_is_on_attr_is_on = None
169  else:
170  # Set as ON if any / all member is ON
171  self._attr_is_on_attr_is_on = self.modemode(state == STATE_ON for state in states)
172 
173  # Set group as unavailable if all members are unavailable or missing
174  self._attr_available_attr_available_attr_available = any(state != STATE_UNAVAILABLE for state in states)
None __init__(self, str|None unique_id, str name, list[str] entity_ids, bool|None mode)
Definition: switch.py:118
None async_setup_platform(HomeAssistant hass, ConfigType config, AddEntitiesCallback async_add_entities, DiscoveryInfoType|None discovery_info=None)
Definition: switch.py:57
None async_setup_entry(HomeAssistant hass, ConfigEntry config_entry, AddEntitiesCallback async_add_entities)
Definition: switch.py:75
SwitchGroup async_create_preview_switch(HomeAssistant hass, str name, dict[str, Any] validated_config)
Definition: switch.py:96