Home Assistant Unofficial Reference 2024.12.1
reload.py
Go to the documentation of this file.
1 """Class to reload platforms."""
2 
3 from __future__ import annotations
4 
5 import asyncio
6 from collections.abc import Iterable
7 import logging
8 from typing import Any, Literal, overload
9 
10 from homeassistant import config as conf_util
11 from homeassistant.const import SERVICE_RELOAD
12 from homeassistant.core import HomeAssistant, ServiceCall, callback
13 from homeassistant.exceptions import HomeAssistantError
14 from homeassistant.loader import async_get_integration
15 from homeassistant.setup import async_setup_component
16 
17 from .entity import Entity
18 from .entity_component import EntityComponent
19 from .entity_platform import EntityPlatform, async_get_platforms
20 from .service import async_register_admin_service
21 from .typing import ConfigType
22 
23 _LOGGER = logging.getLogger(__name__)
24 
25 PLATFORM_RESET_LOCK = "lock_async_reset_platform_{}"
26 
27 
29  hass: HomeAssistant, integration_domain: str, platform_domains: Iterable[str]
30 ) -> None:
31  """Reload an integration's platforms.
32 
33  The platform must support being re-setup.
34 
35  This functionality is only intended to be used for integrations that process
36  Home Assistant data and make this available to other integrations.
37 
38  Examples are template, stats, derivative, utility meter.
39  """
40  try:
41  unprocessed_conf = await conf_util.async_hass_config_yaml(hass)
42  except HomeAssistantError as err:
43  _LOGGER.error(err)
44  return
45 
46  tasks = [
47  _resetup_platform(hass, integration_domain, platform_domain, unprocessed_conf)
48  for platform_domain in platform_domains
49  ]
50 
51  await asyncio.gather(*tasks)
52 
53 
55  hass: HomeAssistant,
56  integration_domain: str,
57  platform_domain: str,
58  unprocessed_config: ConfigType,
59 ) -> None:
60  """Resetup a platform."""
61  integration = await async_get_integration(hass, platform_domain)
62 
63  conf = await conf_util.async_process_component_and_handle_errors(
64  hass, unprocessed_config, integration
65  )
66 
67  if not conf:
68  return
69 
70  root_config: dict[str, list[ConfigType]] = {platform_domain: []}
71  # Extract only the config for template, ignore the rest.
72  for p_type, p_config in conf_util.config_per_platform(conf, platform_domain):
73  if p_type != integration_domain:
74  continue
75 
76  root_config[platform_domain].append(p_config)
77 
78  component = await integration.async_get_component()
79 
80  if hasattr(component, "async_reset_platform"):
81  # If the integration has its own way to reset
82  # use this method.
83  async with hass.data.setdefault(
84  PLATFORM_RESET_LOCK.format(platform_domain), asyncio.Lock()
85  ):
86  await component.async_reset_platform(hass, integration_domain)
87  await component.async_setup(hass, root_config)
88  return
89 
90  # If it's an entity platform, we use the entity_platform
91  # async_reset method
93  hass, integration_domain, platform_domain
94  )
95  if platform:
96  await _async_reconfig_platform(platform, root_config[platform_domain])
97  return
98 
99  if not root_config[platform_domain]:
100  # No config for this platform
101  # and it's not loaded. Nothing to do.
102  return
103 
104  await _async_setup_platform(
105  hass, integration_domain, platform_domain, root_config[platform_domain]
106  )
107 
108 
110  hass: HomeAssistant,
111  integration_domain: str,
112  platform_domain: str,
113  platform_configs: list[dict[str, Any]],
114 ) -> None:
115  """Platform for the first time when new configuration is added."""
116  if platform_domain not in hass.data:
117  await async_setup_component(
118  hass, platform_domain, {platform_domain: platform_configs}
119  )
120  return
121 
122  entity_component: EntityComponent[Entity] = hass.data[platform_domain]
123  tasks = [
124  entity_component.async_setup_platform(integration_domain, p_config)
125  for p_config in platform_configs
126  ]
127  await asyncio.gather(*tasks)
128 
129 
131  platform: EntityPlatform, platform_configs: list[dict[str, Any]]
132 ) -> None:
133  """Reconfigure an already loaded platform."""
134  await platform.async_reset()
135  tasks = [platform.async_setup(p_config) for p_config in platform_configs]
136  await asyncio.gather(*tasks)
137 
138 
139 @overload
141  hass: HomeAssistant, integration_name: str
142 ) -> ConfigType | None: ...
143 
144 
145 @overload
147  hass: HomeAssistant,
148  integration_name: str,
149  *,
150  raise_on_failure: Literal[True],
151 ) -> ConfigType: ...
152 
153 
154 @overload
156  hass: HomeAssistant,
157  integration_name: str,
158  *,
159  raise_on_failure: Literal[False],
160 ) -> ConfigType | None: ...
161 
162 
164  hass: HomeAssistant, integration_name: str, *, raise_on_failure: bool = False
165 ) -> ConfigType | None:
166  """Fetch the latest yaml configuration for an integration."""
167  integration = await async_get_integration(hass, integration_name)
168  config = await conf_util.async_hass_config_yaml(hass)
169  return await conf_util.async_process_component_and_handle_errors(
170  hass, config, integration, raise_on_failure=raise_on_failure
171  )
172 
173 
174 @callback
176  hass: HomeAssistant, integration_name: str, integration_platform_name: str
177 ) -> EntityPlatform | None:
178  """Find an existing platform that is not a config entry."""
179  for integration_platform in async_get_platforms(hass, integration_name):
180  if integration_platform.config_entry is not None:
181  continue
182  if integration_platform.domain == integration_platform_name:
183  platform: EntityPlatform = integration_platform
184  return platform
185 
186  return None
187 
188 
190  hass: HomeAssistant, domain: str, platforms: Iterable[str]
191 ) -> None:
192  """Create the reload service for the domain."""
193  if hass.services.has_service(domain, SERVICE_RELOAD):
194  return
195 
196  async def _reload_config(call: ServiceCall) -> None:
197  """Reload the platforms."""
198  await async_reload_integration_platforms(hass, domain, platforms)
199  hass.bus.async_fire(f"event_{domain}_reloaded", context=call.context)
200 
201  async_register_admin_service(hass, domain, SERVICE_RELOAD, _reload_config)
202 
203 
205  hass: HomeAssistant, domain: str, platforms: Iterable[str]
206 ) -> None:
207  """Sync version of async_setup_reload_service."""
208  asyncio.run_coroutine_threadsafe(
209  async_setup_reload_service(hass, domain, platforms),
210  hass.loop,
211  ).result()
list[EntityPlatform] async_get_platforms(HomeAssistant hass, str integration_name)
None _resetup_platform(HomeAssistant hass, str integration_domain, str platform_domain, ConfigType unprocessed_config)
Definition: reload.py:59
None async_setup_reload_service(HomeAssistant hass, str domain, Iterable[str] platforms)
Definition: reload.py:191
None setup_reload_service(HomeAssistant hass, str domain, Iterable[str] platforms)
Definition: reload.py:206
None async_reload_integration_platforms(HomeAssistant hass, str integration_domain, Iterable[str] platform_domains)
Definition: reload.py:30
None _async_reconfig_platform(EntityPlatform platform, list[dict[str, Any]] platform_configs)
Definition: reload.py:132
EntityPlatform|None async_get_platform_without_config_entry(HomeAssistant hass, str integration_name, str integration_platform_name)
Definition: reload.py:177
ConfigType|None async_integration_yaml_config(HomeAssistant hass, str integration_name)
Definition: reload.py:142
None _async_setup_platform(HomeAssistant hass, str integration_domain, str platform_domain, list[dict[str, Any]] platform_configs)
Definition: reload.py:114
None async_register_admin_service(HomeAssistant hass, str domain, str service, Callable[[ServiceCall], Awaitable[None]|None] service_func, VolSchemaType schema=vol.Schema({}, extra=vol.PREVENT_EXTRA))
Definition: service.py:1121
Integration async_get_integration(HomeAssistant hass, str domain)
Definition: loader.py:1354
bool async_setup_component(core.HomeAssistant hass, str domain, ConfigType config)
Definition: setup.py:147