Home Assistant Unofficial Reference 2024.12.1
__init__.py
Go to the documentation of this file.
1 """Allow users to set and activate scenes."""
2 
3 from __future__ import annotations
4 
5 import functools as ft
6 import importlib
7 import logging
8 from typing import Any, Final, final
9 
10 import voluptuous as vol
11 
12 from homeassistant.components.light import ATTR_TRANSITION
13 from homeassistant.config_entries import ConfigEntry
14 from homeassistant.const import CONF_PLATFORM, SERVICE_TURN_ON, STATE_UNAVAILABLE
15 from homeassistant.core import DOMAIN as HOMEASSISTANT_DOMAIN, HomeAssistant
16 from homeassistant.helpers.entity_component import EntityComponent
17 from homeassistant.helpers.restore_state import RestoreEntity
18 from homeassistant.helpers.typing import ConfigType
19 from homeassistant.util import dt as dt_util
20 from homeassistant.util.hass_dict import HassKey
21 
22 DOMAIN: Final = "scene"
23 DATA_COMPONENT: HassKey[EntityComponent[Scene]] = HassKey(DOMAIN)
24 STATES: Final = "states"
25 
26 
27 def _hass_domain_validator(config: dict[str, Any]) -> dict[str, Any]:
28  """Validate platform in config for homeassistant domain."""
29  if CONF_PLATFORM not in config:
30  config = {CONF_PLATFORM: HOMEASSISTANT_DOMAIN, STATES: config}
31 
32  return config
33 
34 
35 def _platform_validator(config: dict[str, Any]) -> dict[str, Any]:
36  """Validate it is a valid platform."""
37  platform_name = config[CONF_PLATFORM]
38  try:
39  platform = importlib.import_module(
40  f"homeassistant.components.{platform_name}.scene"
41  )
42  except ImportError:
43  raise vol.Invalid("Invalid platform specified") from None
44 
45  if not hasattr(platform, "PLATFORM_SCHEMA"):
46  return config
47 
48  return platform.PLATFORM_SCHEMA(config) # type: ignore[no-any-return]
49 
50 
51 PLATFORM_SCHEMA = vol.Schema(
52  vol.All(
53  _hass_domain_validator,
54  vol.Schema({vol.Required(CONF_PLATFORM): str}, extra=vol.ALLOW_EXTRA),
55  _platform_validator,
56  ),
57  extra=vol.ALLOW_EXTRA,
58 )
59 
60 # mypy: disallow-any-generics
61 
62 
63 async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
64  """Set up the scenes."""
65  component = hass.data[DATA_COMPONENT] = EntityComponent[Scene](
66  logging.getLogger(__name__), DOMAIN, hass
67  )
68 
69  await component.async_setup(config)
70  # Ensure Home Assistant platform always loaded.
71  hass.async_create_task(
72  component.async_setup_platform(
73  HOMEASSISTANT_DOMAIN, {"platform": HOMEASSISTANT_DOMAIN, STATES: []}
74  ),
75  eager_start=True,
76  )
77  component.async_register_entity_service(
78  SERVICE_TURN_ON,
79  {ATTR_TRANSITION: vol.All(vol.Coerce(float), vol.Clamp(min=0, max=6553))},
80  "_async_activate",
81  )
82 
83  return True
84 
85 
86 async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
87  """Set up a config entry."""
88  return await hass.data[DATA_COMPONENT].async_setup_entry(entry)
89 
90 
91 async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
92  """Unload a config entry."""
93  return await hass.data[DATA_COMPONENT].async_unload_entry(entry)
94 
95 
97  """A scene is a group of entities and the states we want them to be."""
98 
99  _attr_should_poll = False
100  __last_activated: str | None = None
101 
102  @property
103  @final
104  def state(self) -> str | None:
105  """Return the state of the scene."""
106  if self.__last_activated__last_activated is None:
107  return None
108  return self.__last_activated__last_activated
109 
110  @final
111  async def _async_activate(self, **kwargs: Any) -> None:
112  """Activate scene.
113 
114  Should not be overridden, handle setting last press timestamp.
115  """
116  self.__last_activated__last_activated = dt_util.utcnow().isoformat()
117  self.async_write_ha_stateasync_write_ha_state()
118  await self.async_activateasync_activate(**kwargs)
119 
120  async def async_internal_added_to_hass(self) -> None:
121  """Call when the scene is added to hass."""
122  await super().async_internal_added_to_hass()
123  state = await self.async_get_last_stateasync_get_last_state()
124  if (
125  state is not None
126  and state.state is not None
127  and state.state != STATE_UNAVAILABLE
128  ):
129  self.__last_activated__last_activated = state.state
130 
131  def activate(self, **kwargs: Any) -> None:
132  """Activate scene. Try to get entities into requested state."""
133  raise NotImplementedError
134 
135  async def async_activate(self, **kwargs: Any) -> None:
136  """Activate scene. Try to get entities into requested state."""
137  task = self.hasshass.async_add_executor_job(ft.partial(self.activateactivate, **kwargs))
138  if task:
139  await task
None activate(self, **Any kwargs)
Definition: __init__.py:131
None _async_activate(self, **Any kwargs)
Definition: __init__.py:111
None async_activate(self, **Any kwargs)
Definition: __init__.py:135
dict[str, Any] _platform_validator(dict[str, Any] config)
Definition: __init__.py:35
bool async_setup_entry(HomeAssistant hass, ConfigEntry entry)
Definition: __init__.py:86
dict[str, Any] _hass_domain_validator(dict[str, Any] config)
Definition: __init__.py:27
bool async_setup(HomeAssistant hass, ConfigType config)
Definition: __init__.py:63
bool async_unload_entry(HomeAssistant hass, ConfigEntry entry)
Definition: __init__.py:91