2019-12-13 14:38:41 +00:00
|
|
|
"""Helpers to help with integration platforms."""
|
2021-04-20 15:40:41 +00:00
|
|
|
from __future__ import annotations
|
|
|
|
|
2019-12-13 14:38:41 +00:00
|
|
|
import asyncio
|
2021-09-29 14:32:11 +00:00
|
|
|
from collections.abc import Awaitable, Callable
|
2022-04-17 10:23:00 +00:00
|
|
|
from dataclasses import dataclass
|
2019-12-13 14:38:41 +00:00
|
|
|
import logging
|
2021-09-29 14:32:11 +00:00
|
|
|
from typing import Any
|
2019-12-13 14:38:41 +00:00
|
|
|
|
2022-01-10 16:10:46 +00:00
|
|
|
from homeassistant.const import EVENT_COMPONENT_LOADED
|
2019-12-13 14:38:41 +00:00
|
|
|
from homeassistant.core import Event, HomeAssistant
|
2020-06-25 01:14:50 +00:00
|
|
|
from homeassistant.loader import async_get_integration, bind_hass
|
2022-01-10 16:10:46 +00:00
|
|
|
from homeassistant.setup import ATTR_COMPONENT
|
2019-12-13 14:38:41 +00:00
|
|
|
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
2022-04-17 10:23:00 +00:00
|
|
|
DATA_INTEGRATION_PLATFORMS = "integration_platforms"
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
|
|
class IntegrationPlatform:
|
|
|
|
"""An integration platform."""
|
|
|
|
|
|
|
|
platform_name: str
|
|
|
|
process_platform: Callable[[HomeAssistant, str, Any], Awaitable[None]]
|
|
|
|
seen_components: set[str]
|
|
|
|
|
|
|
|
|
2022-04-18 06:59:31 +00:00
|
|
|
async def _async_process_single_integration_platform_component(
|
2022-04-17 10:23:00 +00:00
|
|
|
hass: HomeAssistant, component_name: str, integration_platform: IntegrationPlatform
|
|
|
|
) -> None:
|
|
|
|
"""Process a single integration platform."""
|
|
|
|
if component_name in integration_platform.seen_components:
|
|
|
|
return
|
|
|
|
integration_platform.seen_components.add(component_name)
|
|
|
|
|
|
|
|
integration = await async_get_integration(hass, component_name)
|
|
|
|
platform_name = integration_platform.platform_name
|
|
|
|
|
|
|
|
try:
|
|
|
|
platform = integration.get_platform(platform_name)
|
|
|
|
except ImportError as err:
|
|
|
|
if f"{component_name}.{platform_name}" not in str(err):
|
|
|
|
_LOGGER.exception(
|
|
|
|
"Unexpected error importing %s/%s.py",
|
|
|
|
component_name,
|
|
|
|
platform_name,
|
|
|
|
)
|
|
|
|
return
|
|
|
|
|
|
|
|
try:
|
|
|
|
await integration_platform.process_platform(hass, component_name, platform) # type: ignore[misc,operator] # https://github.com/python/mypy/issues/5485
|
|
|
|
except Exception: # pylint: disable=broad-except
|
|
|
|
_LOGGER.exception(
|
|
|
|
"Error processing platform %s.%s", component_name, platform_name
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2022-04-18 06:59:31 +00:00
|
|
|
async def async_process_integration_platform_for_component(
|
2022-04-17 10:23:00 +00:00
|
|
|
hass: HomeAssistant, component_name: str
|
|
|
|
) -> None:
|
2022-04-18 06:59:31 +00:00
|
|
|
"""Process integration platforms on demand for a component.
|
2022-04-17 10:23:00 +00:00
|
|
|
|
|
|
|
This function will load the integration platforms
|
|
|
|
for an integration instead of waiting for the EVENT_COMPONENT_LOADED
|
|
|
|
event to be fired for the integration.
|
|
|
|
|
|
|
|
When the integration will create entities before
|
|
|
|
it has finished setting up; call this function to ensure
|
|
|
|
that the integration platforms are loaded before the entities
|
|
|
|
are created.
|
|
|
|
"""
|
2022-04-18 05:45:52 +00:00
|
|
|
if DATA_INTEGRATION_PLATFORMS not in hass.data:
|
2022-04-21 20:02:52 +00:00
|
|
|
# There are no integration platforms loaded yet
|
2022-04-18 05:45:52 +00:00
|
|
|
return
|
2022-04-17 10:23:00 +00:00
|
|
|
integration_platforms: list[IntegrationPlatform] = hass.data[
|
|
|
|
DATA_INTEGRATION_PLATFORMS
|
|
|
|
]
|
|
|
|
await asyncio.gather(
|
|
|
|
*[
|
2022-04-18 06:59:31 +00:00
|
|
|
_async_process_single_integration_platform_component(
|
2022-04-17 10:23:00 +00:00
|
|
|
hass, component_name, integration_platform
|
|
|
|
)
|
|
|
|
for integration_platform in integration_platforms
|
|
|
|
]
|
|
|
|
)
|
2019-12-13 14:38:41 +00:00
|
|
|
|
|
|
|
|
|
|
|
@bind_hass
|
|
|
|
async def async_process_integration_platforms(
|
|
|
|
hass: HomeAssistant,
|
|
|
|
platform_name: str,
|
|
|
|
# Any = platform.
|
|
|
|
process_platform: Callable[[HomeAssistant, str, Any], Awaitable[None]],
|
|
|
|
) -> None:
|
|
|
|
"""Process a specific platform for all current and future loaded integrations."""
|
2022-04-17 10:23:00 +00:00
|
|
|
if DATA_INTEGRATION_PLATFORMS not in hass.data:
|
|
|
|
hass.data[DATA_INTEGRATION_PLATFORMS] = []
|
2019-12-13 14:38:41 +00:00
|
|
|
|
2022-04-17 10:23:00 +00:00
|
|
|
async def _async_component_loaded(event: Event) -> None:
|
|
|
|
"""Handle a new component loaded."""
|
|
|
|
comp = event.data[ATTR_COMPONENT]
|
|
|
|
if "." not in comp:
|
2022-04-18 06:59:31 +00:00
|
|
|
await async_process_integration_platform_for_component(hass, comp)
|
2019-12-13 14:38:41 +00:00
|
|
|
|
2022-04-17 10:23:00 +00:00
|
|
|
hass.bus.async_listen(EVENT_COMPONENT_LOADED, _async_component_loaded)
|
2019-12-13 14:38:41 +00:00
|
|
|
|
2022-04-17 10:23:00 +00:00
|
|
|
integration_platforms: list[IntegrationPlatform] = hass.data[
|
|
|
|
DATA_INTEGRATION_PLATFORMS
|
|
|
|
]
|
|
|
|
integration_platform = IntegrationPlatform(platform_name, process_platform, set())
|
|
|
|
integration_platforms.append(integration_platform)
|
|
|
|
if top_level_components := (
|
|
|
|
comp for comp in hass.config.components if "." not in comp
|
|
|
|
):
|
|
|
|
await asyncio.gather(
|
|
|
|
*[
|
2022-04-18 06:59:31 +00:00
|
|
|
_async_process_single_integration_platform_component(
|
2022-04-17 10:23:00 +00:00
|
|
|
hass, comp, integration_platform
|
|
|
|
)
|
|
|
|
for comp in top_level_components
|
|
|
|
]
|
|
|
|
)
|