async def test_integrations_only_once(hass):
    """Test that we load integrations only once."""
    int_1 = hass.async_create_task(
        loader.async_get_integration(hass, 'hue'))
    int_2 = hass.async_create_task(
        loader.async_get_integration(hass, 'hue'))

    assert await int_1 is await int_2
async def test_component_translation_path(hass):
    """Test the component translation file function."""
    assert await async_setup_component(
        hass,
        "switch",
        {"switch": [{"platform": "test"}, {"platform": "test_embedded"}]},
    )
    assert await async_setup_component(hass, "test_standalone", {"test_standalone"})
    assert await async_setup_component(hass, "test_package", {"test_package"})

    (
        int_test,
        int_test_embedded,
        int_test_standalone,
        int_test_package,
    ) = await asyncio.gather(
        async_get_integration(hass, "test"),
        async_get_integration(hass, "test_embedded"),
        async_get_integration(hass, "test_standalone"),
        async_get_integration(hass, "test_package"),
    )

    assert path.normpath(
        translation.component_translation_path("switch.test", "en", int_test)
    ) == path.normpath(
        hass.config.path("custom_components", "test", "translations", "switch.en.json")
    )

    assert path.normpath(
        translation.component_translation_path(
            "switch.test_embedded", "en", int_test_embedded
        )
    ) == path.normpath(
        hass.config.path(
            "custom_components", "test_embedded", "translations", "switch.en.json"
        )
    )

    assert (
        translation.component_translation_path(
            "test_standalone", "en", int_test_standalone
        )
        is None
    )

    assert path.normpath(
        translation.component_translation_path("test_package", "en", int_test_package)
    ) == path.normpath(
        hass.config.path("custom_components", "test_package", "translations", "en.json")
    )
Exemple #3
0
async def async_matching_config_entries(
        hass: HomeAssistant, type_filter: str | None,
        domain: str | None) -> list[dict[str, Any]]:
    """Return matching config entries by type and/or domain."""
    kwargs = {}
    if domain:
        kwargs["domain"] = domain
    entries = hass.config_entries.async_entries(**kwargs)

    if type_filter is None:
        return [entry_json(entry) for entry in entries]

    integrations = {}
    # Fetch all the integrations so we can check their type
    tasks = (async_get_integration(hass, domain)
             for domain in {entry.domain
                            for entry in entries})
    results = await asyncio.gather(*tasks, return_exceptions=True)
    for integration_or_exc in results:
        if isinstance(integration_or_exc, Integration):
            integrations[integration_or_exc.domain] = integration_or_exc
        elif not isinstance(integration_or_exc, IntegrationNotFound):
            raise integration_or_exc

    entries = [
        entry for entry in entries
        if (type_filter != "helper" and entry.domain not in integrations) or (
            entry.domain in integrations
            and integrations[entry.domain].integration_type == type_filter)
    ]

    return [entry_json(entry) for entry in entries]
    async def get(self, request):
        """List available config entries."""
        hass: HomeAssistant = request.app["hass"]

        kwargs = {}
        if "domain" in request.query:
            kwargs["domain"] = request.query["domain"]

        entries = hass.config_entries.async_entries(**kwargs)

        if "type" not in request.query:
            return self.json([entry_json(entry) for entry in entries])

        integrations = {}
        type_filter = request.query["type"]

        # Fetch all the integrations so we can check their type
        for integration in await asyncio.gather(
                *(loader.async_get_integration(hass, domain)
                  for domain in {entry.domain
                                 for entry in entries})):
            integrations[integration.domain] = integration

        entries = [
            entry for entry in entries
            if integrations[entry.domain].integration_type == type_filter
        ]

        return self.json([entry_json(entry) for entry in entries])
Exemple #5
0
async def handle_manifest_list(hass, connection, msg):
    """Handle integrations command."""
    loaded_integrations = async_get_loaded_integrations(hass)
    integrations = await asyncio.gather(*[
        async_get_integration(hass, domain) for domain in loaded_integrations
    ])
    connection.send_result(
        msg["id"], [integration.manifest for integration in integrations])
Exemple #6
0
async def async_get_all_descriptions(
    hass: HomeAssistantType,
) -> Dict[str, Dict[str, Any]]:
    """Return descriptions (i.e. user documentation) for all service calls."""
    descriptions_cache = hass.data.setdefault(SERVICE_DESCRIPTION_CACHE, {})
    format_cache_key = "{}.{}".format
    services = hass.services.async_services()

    # See if there are new services not seen before.
    # Any service that we saw before already has an entry in description_cache.
    missing = set()
    for domain in services:
        for service in services[domain]:
            if format_cache_key(domain, service) not in descriptions_cache:
                missing.add(domain)
                break

    # Files we loaded for missing descriptions
    loaded = {}

    if missing:
        integrations = await gather_with_concurrency(
            MAX_LOAD_CONCURRENTLY,
            *(async_get_integration(hass, domain) for domain in missing),
        )

        contents = await hass.async_add_executor_job(
            _load_services_files, hass, integrations
        )

        for domain, content in zip(missing, contents):
            loaded[domain] = content

    # Build response
    descriptions: Dict[str, Dict[str, Any]] = {}
    for domain in services:
        descriptions[domain] = {}

        for service in services[domain]:
            cache_key = format_cache_key(domain, service)
            description = descriptions_cache.get(cache_key)

            # Cache missing descriptions
            if description is None:
                domain_yaml = loaded[domain]
                yaml_description = domain_yaml.get(service, {})  # type: ignore

                # Don't warn for missing services, because it triggers false
                # positives for things like scripts, that register as a service

                description = descriptions_cache[cache_key] = {
                    "description": yaml_description.get("description", ""),
                    "fields": yaml_description.get("fields", {}),
                }

            descriptions[domain][service] = description

    return descriptions
Exemple #7
0
async def handle_manifest_list(hass: HomeAssistant,
                               connection: ActiveConnection,
                               msg: dict[str, Any]) -> None:
    """Handle integrations command."""
    loaded_integrations = async_get_loaded_integrations(hass)
    integrations = await asyncio.gather(*(async_get_integration(hass, domain)
                                          for domain in loaded_integrations))
    connection.send_result(
        msg["id"], [integration.manifest for integration in integrations])
Exemple #8
0
async def _async_set_up_integrations(
    hass: core.HomeAssistant, config: dict[str, Any]
) -> None:
    """Set up all the integrations."""
    hass.data[DATA_SETUP_STARTED] = {}
    setup_time = hass.data[DATA_SETUP_TIME] = {}

    watch_task = asyncio.create_task(_async_watch_pending_setups(hass))

    domains_to_setup = _get_domains(hass, config)

    # Resolve all dependencies so we know all integrations
    # that will have to be loaded and start rightaway
    integration_cache: dict[str, loader.Integration] = {}
    to_resolve = domains_to_setup
    while to_resolve:
        old_to_resolve = to_resolve
        to_resolve = set()

        integrations_to_process = [
            int_or_exc
            for int_or_exc in await gather_with_concurrency(
                loader.MAX_LOAD_CONCURRENTLY,
                *(
                    loader.async_get_integration(hass, domain)
                    for domain in old_to_resolve
                ),
                return_exceptions=True,
            )
            if isinstance(int_or_exc, loader.Integration)
        ]
        resolve_dependencies_tasks = [
            itg.resolve_dependencies()
            for itg in integrations_to_process
            if not itg.all_dependencies_resolved
        ]

        if resolve_dependencies_tasks:
            await asyncio.gather(*resolve_dependencies_tasks)

        for itg in integrations_to_process:
            integration_cache[itg.domain] = itg

            for dep in itg.all_dependencies:
                if dep in domains_to_setup:
                    continue

                domains_to_setup.add(dep)
                to_resolve.add(dep)

    _LOGGER.info("Domains to be set up: %s", domains_to_setup)

    # Load logging as soon as possible
    if logging_domains := domains_to_setup & LOGGING_INTEGRATIONS:
        _LOGGER.info("Setting up logging: %s", logging_domains)
        await async_setup_multi_components(hass, logging_domains, config)
Exemple #9
0
async def handle_manifest_list(hass, connection, msg):
    """Handle integrations command."""
    integrations = await asyncio.gather(*[
        async_get_integration(hass, domain)
        for domain in hass.config.components
        # Filter out platforms.
        if "." not in domain
    ])
    connection.send_result(
        msg["id"], [integration.manifest for integration in integrations])
async def _async_name_to_type_map(hass: HomeAssistant) -> dict[str, str]:
    """Create a mapping of types of devices/entities HomeKit can support."""
    integrations = await asyncio.gather(
        *(async_get_integration(hass, domain) for domain in SUPPORTED_DOMAINS),
        return_exceptions=True,
    )
    name_to_type_map = {
        domain: domain
        if isinstance(integrations[idx], Exception) else integrations[idx].name
        for idx, domain in enumerate(SUPPORTED_DOMAINS)
    }
    return name_to_type_map
Exemple #11
0
async def async_get_component_strings(
    hass: HomeAssistant, language: str, components: set[str]
) -> dict[str, Any]:
    """Load translations."""
    domains = list({loaded.split(".")[-1] for loaded in components})
    integrations = dict(
        zip(
            domains,
            await gather_with_concurrency(
                MAX_LOAD_CONCURRENTLY,
                *(async_get_integration(hass, domain) for domain in domains),
            ),
        )
    )

    translations: dict[str, Any] = {}

    # Determine paths of missing components/platforms
    files_to_load = {}
    for loaded in components:
        parts = loaded.split(".")
        domain = parts[-1]
        integration = integrations[domain]

        path = component_translation_path(loaded, language, integration)
        # No translation available
        if path is None:
            translations[loaded] = {}
        else:
            files_to_load[loaded] = path

    if not files_to_load:
        return translations

    # Load files
    load_translations_job = hass.async_add_executor_job(
        load_translations_files, files_to_load
    )
    assert load_translations_job is not None
    loaded_translations = await load_translations_job

    # Translations that miss "title" will get integration put in.
    for loaded, loaded_translation in loaded_translations.items():
        if "." in loaded:
            continue

        if "title" not in loaded_translation:
            loaded_translation["title"] = integrations[loaded].name

    translations.update(loaded_translations)

    return translations
Exemple #12
0
async def get_custom_integrations(hass: HomeAssistant):
    """Return a list with custom integration info."""
    custom_integrations = []
    configured_integrations: List[Integration | IntegrationNotFound
                                  | BaseException] = await asyncio.gather(
                                      *[
                                          async_get_integration(hass, domain)
                                          for domain in
                                          async_get_loaded_integrations(hass)
                                      ],
                                      return_exceptions=True,
                                  )

    for integration in configured_integrations:
        if isinstance(integration, IntegrationNotFound):
            continue

        if isinstance(integration, BaseException):
            raise integration

        if integration.disabled or integration.is_built_in:
            continue

        custom_integrations.append({
            "domain":
            integration.domain,
            "name":
            integration.name,
            "documentation":
            integration.documentation,
            "version":
            integration.version,
            "codeowners":
            integration.manifest.get("codeowners"),
        })

    return custom_integrations
async def _async_set_up_integrations(
        hass: core.HomeAssistant, config: Dict[str, Any]) -> None:
    """Set up all the integrations."""
    domains = _get_domains(hass, config)

    # Start up debuggers. Start these first in case they want to wait.
    debuggers = domains & DEBUGGER_INTEGRATIONS
    if debuggers:
        _LOGGER.debug("Starting up debuggers %s", debuggers)
        await asyncio.gather(*[
            async_setup_component(hass, domain, config)
            for domain in debuggers])
        domains -= DEBUGGER_INTEGRATIONS

    # Resolve all dependencies of all components so we can find the logging
    # and integrations that need faster initialization.
    resolved_domains_task = asyncio.gather(*[
        loader.async_component_dependencies(hass, domain)
        for domain in domains
    ], return_exceptions=True)

    # Set up core.
    _LOGGER.debug("Setting up %s", CORE_INTEGRATIONS)

    if not all(await asyncio.gather(*[
            async_setup_component(hass, domain, config)
            for domain in CORE_INTEGRATIONS
    ])):
        _LOGGER.error("Home Assistant core failed to initialize. "
                      "Further initialization aborted")
        return

    _LOGGER.debug("Home Assistant core initialized")

    # Finish resolving domains
    for dep_domains in await resolved_domains_task:
        # Result is either a set or an exception. We ignore exceptions
        # It will be properly handled during setup of the domain.
        if isinstance(dep_domains, set):
            domains.update(dep_domains)

    # setup components
    logging_domains = domains & LOGGING_INTEGRATIONS
    stage_1_domains = domains & STAGE_1_INTEGRATIONS
    stage_2_domains = domains - logging_domains - stage_1_domains

    if logging_domains:
        _LOGGER.info("Setting up %s", logging_domains)

        await asyncio.gather(*[
            async_setup_component(hass, domain, config)
            for domain in logging_domains
        ])

    # Kick off loading the registries. They don't need to be awaited.
    asyncio.gather(
        hass.helpers.device_registry.async_get_registry(),
        hass.helpers.entity_registry.async_get_registry(),
        hass.helpers.area_registry.async_get_registry())

    if stage_1_domains:
        await asyncio.gather(*[
            async_setup_component(hass, domain, config)
            for domain in stage_1_domains
        ])

    # Load all integrations
    after_dependencies = {}  # type: Dict[str, Set[str]]

    for int_or_exc in await asyncio.gather(*[
            loader.async_get_integration(hass, domain)
            for domain in stage_2_domains
    ], return_exceptions=True):
        # Exceptions are handled in async_setup_component.
        if (isinstance(int_or_exc, loader.Integration) and
                int_or_exc.after_dependencies):
            after_dependencies[int_or_exc.domain] = set(
                int_or_exc.after_dependencies
            )

    last_load = None
    while stage_2_domains:
        domains_to_load = set()

        for domain in stage_2_domains:
            after_deps = after_dependencies.get(domain)
            # Load if integration has no after_dependencies or they are
            # all loaded
            if (not after_deps or
                    not after_deps-hass.config.components):
                domains_to_load.add(domain)

        if not domains_to_load or domains_to_load == last_load:
            break

        _LOGGER.debug("Setting up %s", domains_to_load)

        await asyncio.gather(*[
            async_setup_component(hass, domain, config)
            for domain in domains_to_load
        ])

        last_load = domains_to_load
        stage_2_domains -= domains_to_load

    # These are stage 2 domains that never have their after_dependencies
    # satisfied.
    if stage_2_domains:
        _LOGGER.debug("Final set up: %s", stage_2_domains)

        await asyncio.gather(*[
            async_setup_component(hass, domain, config)
            for domain in stage_2_domains
        ])

    # Wrap up startup
    await hass.async_block_till_done()
Exemple #14
0
async def _async_set_up_integrations(
    hass: core.HomeAssistant, config: Dict[str, Any]
) -> None:
    """Set up all the integrations."""

    async def async_setup_multi_components(domains: Set[str]) -> None:
        """Set up multiple domains. Log on failure."""
        futures = {
            domain: hass.async_create_task(async_setup_component(hass, domain, config))
            for domain in domains
        }
        await asyncio.wait(futures.values())
        errors = [domain for domain in domains if futures[domain].exception()]
        for domain in errors:
            exception = futures[domain].exception()
            _LOGGER.error(
                "Error setting up integration %s - received exception",
                domain,
                exc_info=(type(exception), exception, exception.__traceback__),
            )

    domains = _get_domains(hass, config)

    # Start up debuggers. Start these first in case they want to wait.
    debuggers = domains & DEBUGGER_INTEGRATIONS
    if debuggers:
        _LOGGER.debug("Starting up debuggers %s", debuggers)
        await async_setup_multi_components(debuggers)
        domains -= DEBUGGER_INTEGRATIONS

    # Resolve all dependencies of all components so we can find the logging
    # and integrations that need faster initialization.
    resolved_domains_task = asyncio.gather(
        *(loader.async_component_dependencies(hass, domain) for domain in domains),
        return_exceptions=True,
    )

    # Finish resolving domains
    for dep_domains in await resolved_domains_task:
        # Result is either a set or an exception. We ignore exceptions
        # It will be properly handled during setup of the domain.
        if isinstance(dep_domains, set):
            domains.update(dep_domains)

    # setup components
    logging_domains = domains & LOGGING_INTEGRATIONS
    stage_1_domains = domains & STAGE_1_INTEGRATIONS
    stage_2_domains = domains - logging_domains - stage_1_domains

    if logging_domains:
        _LOGGER.info("Setting up %s", logging_domains)

        await async_setup_multi_components(logging_domains)

    # Kick off loading the registries. They don't need to be awaited.
    asyncio.gather(
        hass.helpers.device_registry.async_get_registry(),
        hass.helpers.entity_registry.async_get_registry(),
        hass.helpers.area_registry.async_get_registry(),
    )

    if stage_1_domains:
        await async_setup_multi_components(stage_1_domains)

    # Load all integrations
    after_dependencies: Dict[str, Set[str]] = {}

    for int_or_exc in await asyncio.gather(
        *(loader.async_get_integration(hass, domain) for domain in stage_2_domains),
        return_exceptions=True,
    ):
        # Exceptions are handled in async_setup_component.
        if isinstance(int_or_exc, loader.Integration) and int_or_exc.after_dependencies:
            after_dependencies[int_or_exc.domain] = set(int_or_exc.after_dependencies)

    last_load = None
    while stage_2_domains:
        domains_to_load = set()

        for domain in stage_2_domains:
            after_deps = after_dependencies.get(domain)
            # Load if integration has no after_dependencies or they are
            # all loaded
            if not after_deps or not after_deps - hass.config.components:
                domains_to_load.add(domain)

        if not domains_to_load or domains_to_load == last_load:
            break

        _LOGGER.debug("Setting up %s", domains_to_load)

        await async_setup_multi_components(domains_to_load)

        last_load = domains_to_load
        stage_2_domains -= domains_to_load

    # These are stage 2 domains that never have their after_dependencies
    # satisfied.
    if stage_2_domains:
        _LOGGER.debug("Final set up: %s", stage_2_domains)

        await async_setup_multi_components(stage_2_domains)

    # Wrap up startup
    await hass.async_block_till_done()
Exemple #15
0
    async def send_analytics(self, _=None) -> None:
        """Send analytics."""
        supervisor_info = None
        operating_system_info = {}

        if not self.onboarded or not self.preferences.get(ATTR_BASE, False):
            LOGGER.debug("Nothing to submit")
            return

        if self._data.get(ATTR_UUID) is None:
            self._data[ATTR_UUID] = uuid.uuid4().hex
            await self._store.async_save(self._data)

        if self.supervisor:
            supervisor_info = hassio.get_supervisor_info(self.hass)
            operating_system_info = hassio.get_os_info(self.hass)

        system_info = await async_get_system_info(self.hass)
        integrations = []
        custom_integrations = []
        addons = []
        payload: dict = {
            ATTR_UUID: self.uuid,
            ATTR_VERSION: HA_VERSION,
            ATTR_INSTALLATION_TYPE: system_info[ATTR_INSTALLATION_TYPE],
        }

        if supervisor_info is not None:
            payload[ATTR_SUPERVISOR] = {
                ATTR_HEALTHY: supervisor_info[ATTR_HEALTHY],
                ATTR_SUPPORTED: supervisor_info[ATTR_SUPPORTED],
                ATTR_ARCH: supervisor_info[ATTR_ARCH],
            }

        if operating_system_info.get(ATTR_BOARD) is not None:
            payload[ATTR_OPERATING_SYSTEM] = {
                ATTR_BOARD: operating_system_info[ATTR_BOARD],
                ATTR_VERSION: operating_system_info[ATTR_VERSION],
            }

        if self.preferences.get(ATTR_USAGE, False) or self.preferences.get(
            ATTR_STATISTICS, False
        ):
            configured_integrations = await asyncio.gather(
                *(
                    async_get_integration(self.hass, domain)
                    for domain in async_get_loaded_integrations(self.hass)
                ),
                return_exceptions=True,
            )

            for integration in configured_integrations:
                if isinstance(integration, IntegrationNotFound):
                    continue

                if isinstance(integration, BaseException):
                    raise integration

                if integration.disabled:
                    continue

                if not integration.is_built_in:
                    custom_integrations.append(
                        {
                            ATTR_DOMAIN: integration.domain,
                            ATTR_VERSION: integration.version,
                        }
                    )
                    continue

                integrations.append(integration.domain)

            if supervisor_info is not None:
                installed_addons = await asyncio.gather(
                    *(
                        hassio.async_get_addon_info(self.hass, addon[ATTR_SLUG])
                        for addon in supervisor_info[ATTR_ADDONS]
                    )
                )
                for addon in installed_addons:
                    addons.append(
                        {
                            ATTR_SLUG: addon[ATTR_SLUG],
                            ATTR_PROTECTED: addon[ATTR_PROTECTED],
                            ATTR_VERSION: addon[ATTR_VERSION],
                            ATTR_AUTO_UPDATE: addon[ATTR_AUTO_UPDATE],
                        }
                    )

        if self.preferences.get(ATTR_USAGE, False):
            payload[ATTR_INTEGRATIONS] = integrations
            payload[ATTR_CUSTOM_INTEGRATIONS] = custom_integrations
            if supervisor_info is not None:
                payload[ATTR_ADDONS] = addons

        if self.preferences.get(ATTR_STATISTICS, False):
            payload[ATTR_STATE_COUNT] = len(self.hass.states.async_all())
            payload[ATTR_AUTOMATION_COUNT] = len(
                self.hass.states.async_all(AUTOMATION_DOMAIN)
            )
            payload[ATTR_INTEGRATION_COUNT] = len(integrations)
            if supervisor_info is not None:
                payload[ATTR_ADDON_COUNT] = len(addons)
            payload[ATTR_USER_COUNT] = len(
                [
                    user
                    for user in await self.hass.auth.async_get_users()
                    if not user.system_generated
                ]
            )

        try:
            with async_timeout.timeout(30):
                response = await self.session.post(self.endpoint, json=payload)
                if response.status == 200:
                    LOGGER.info(
                        (
                            "Submitted analytics to Home Assistant servers. "
                            "Information submitted includes %s"
                        ),
                        payload,
                    )
                else:
                    LOGGER.warning(
                        "Sending analytics failed with statuscode %s from %s",
                        response.status,
                        self.endpoint,
                    )
        except asyncio.TimeoutError:
            LOGGER.error("Timeout sending analytics to %s", ANALYTICS_ENDPOINT_URL)
        except aiohttp.ClientError as err:
            LOGGER.error(
                "Error sending analytics to %s: %r", ANALYTICS_ENDPOINT_URL, err
            )
Exemple #16
0
async def _async_set_up_integrations(hass: core.HomeAssistant,
                                     config: Dict[str, Any]) -> None:
    """Set up all the integrations."""
    setup_started = hass.data[DATA_SETUP_STARTED] = {}
    domains_to_setup = _get_domains(hass, config)

    # Resolve all dependencies so we know all integrations
    # that will have to be loaded and start rightaway
    integration_cache: Dict[str, loader.Integration] = {}
    to_resolve = domains_to_setup
    while to_resolve:
        old_to_resolve = to_resolve
        to_resolve = set()

        integrations_to_process = [
            int_or_exc for int_or_exc in await gather_with_concurrency(
                loader.MAX_LOAD_CONCURRENTLY,
                *(loader.async_get_integration(hass, domain)
                  for domain in old_to_resolve),
                return_exceptions=True,
            ) if isinstance(int_or_exc, loader.Integration)
        ]
        resolve_dependencies_tasks = [
            itg.resolve_dependencies() for itg in integrations_to_process
            if not itg.all_dependencies_resolved
        ]

        if resolve_dependencies_tasks:
            await asyncio.gather(*resolve_dependencies_tasks)

        for itg in integrations_to_process:
            integration_cache[itg.domain] = itg

            for dep in itg.all_dependencies:
                if dep in domains_to_setup:
                    continue

                domains_to_setup.add(dep)
                to_resolve.add(dep)

    _LOGGER.info("Domains to be set up: %s", domains_to_setup)

    logging_domains = domains_to_setup & LOGGING_INTEGRATIONS

    # Load logging as soon as possible
    if logging_domains:
        _LOGGER.info("Setting up logging: %s", logging_domains)
        await async_setup_multi_components(hass, logging_domains, config,
                                           setup_started)

    # Start up debuggers. Start these first in case they want to wait.
    debuggers = domains_to_setup & DEBUGGER_INTEGRATIONS

    if debuggers:
        _LOGGER.debug("Setting up debuggers: %s", debuggers)
        await async_setup_multi_components(hass, debuggers, config,
                                           setup_started)

    # calculate what components to setup in what stage
    stage_1_domains = set()

    # Find all dependencies of any dependency of any stage 1 integration that
    # we plan on loading and promote them to stage 1
    deps_promotion = STAGE_1_INTEGRATIONS
    while deps_promotion:
        old_deps_promotion = deps_promotion
        deps_promotion = set()

        for domain in old_deps_promotion:
            if domain not in domains_to_setup or domain in stage_1_domains:
                continue

            stage_1_domains.add(domain)

            dep_itg = integration_cache.get(domain)

            if dep_itg is None:
                continue

            deps_promotion.update(dep_itg.all_dependencies)

    stage_2_domains = domains_to_setup - logging_domains - debuggers - stage_1_domains

    # Kick off loading the registries. They don't need to be awaited.
    asyncio.create_task(hass.helpers.device_registry.async_get_registry())
    asyncio.create_task(hass.helpers.entity_registry.async_get_registry())
    asyncio.create_task(hass.helpers.area_registry.async_get_registry())

    # Start setup
    if stage_1_domains:
        _LOGGER.info("Setting up stage 1: %s", stage_1_domains)
        try:
            async with hass.timeout.async_timeout(STAGE_1_TIMEOUT,
                                                  cool_down=COOLDOWN_TIME):
                await async_setup_multi_components(hass, stage_1_domains,
                                                   config, setup_started)
        except asyncio.TimeoutError:
            _LOGGER.warning("Setup timed out for stage 1 - moving forward")

    # Enables after dependencies
    async_set_domains_to_be_loaded(hass, stage_1_domains | stage_2_domains)

    if stage_2_domains:
        _LOGGER.info("Setting up stage 2: %s", stage_2_domains)
        try:
            async with hass.timeout.async_timeout(STAGE_2_TIMEOUT,
                                                  cool_down=COOLDOWN_TIME):
                await async_setup_multi_components(hass, stage_2_domains,
                                                   config, setup_started)
        except asyncio.TimeoutError:
            _LOGGER.warning("Setup timed out for stage 2 - moving forward")

    # Wrap up startup
    _LOGGER.debug("Waiting for startup to wrap up")
    try:
        async with hass.timeout.async_timeout(WRAP_UP_TIMEOUT,
                                              cool_down=COOLDOWN_TIME):
            await hass.async_block_till_done()
    except asyncio.TimeoutError:
        _LOGGER.warning("Setup timed out for bootstrap - moving forward")
Exemple #17
0
async def _async_set_up_integrations(hass: core.HomeAssistant,
                                     config: Dict[str, Any]) -> None:
    """Set up all the integrations."""
    domains = _get_domains(hass, config)

    # Start up debuggers. Start these first in case they want to wait.
    debuggers = domains & DEBUGGER_INTEGRATIONS
    if debuggers:
        _LOGGER.debug("Starting up debuggers %s", debuggers)
        await asyncio.gather(*[
            async_setup_component(hass, domain, config) for domain in debuggers
        ])
        domains -= DEBUGGER_INTEGRATIONS

    # Resolve all dependencies of all components so we can find the logging
    # and integrations that need faster initialization.
    resolved_domains_task = asyncio.gather(*[
        loader.async_component_dependencies(hass, domain) for domain in domains
    ],
                                           return_exceptions=True)

    # Set up core.
    _LOGGER.debug("Setting up %s", CORE_INTEGRATIONS)

    if not all(await asyncio.gather(*[
            async_setup_component(hass, domain, config)
            for domain in CORE_INTEGRATIONS
    ])):
        _LOGGER.error("Home Assistant core failed to initialize. "
                      "Further initialization aborted")
        return

    _LOGGER.debug("Home Assistant core initialized")

    # Finish resolving domains
    for dep_domains in await resolved_domains_task:
        # Result is either a set or an exception. We ignore exceptions
        # It will be properly handled during setup of the domain.
        if isinstance(dep_domains, set):
            domains.update(dep_domains)

    # setup components
    logging_domains = domains & LOGGING_INTEGRATIONS
    stage_1_domains = domains & STAGE_1_INTEGRATIONS
    stage_2_domains = domains - logging_domains - stage_1_domains

    if logging_domains:
        _LOGGER.info("Setting up %s", logging_domains)

        await asyncio.gather(*[
            async_setup_component(hass, domain, config)
            for domain in logging_domains
        ])

    # Kick off loading the registries. They don't need to be awaited.
    asyncio.gather(hass.helpers.device_registry.async_get_registry(),
                   hass.helpers.entity_registry.async_get_registry(),
                   hass.helpers.area_registry.async_get_registry())

    if stage_1_domains:
        await asyncio.gather(*[
            async_setup_component(hass, domain, config)
            for domain in stage_1_domains
        ])

    # Load all integrations
    after_dependencies = {}  # type: Dict[str, Set[str]]

    for int_or_exc in await asyncio.gather(*[
            loader.async_get_integration(hass, domain)
            for domain in stage_2_domains
    ],
                                           return_exceptions=True):
        # Exceptions are handled in async_setup_component.
        if (isinstance(int_or_exc, loader.Integration)
                and int_or_exc.after_dependencies):
            after_dependencies[int_or_exc.domain] = set(
                int_or_exc.after_dependencies)

    last_load = None
    while stage_2_domains:
        domains_to_load = set()

        for domain in stage_2_domains:
            after_deps = after_dependencies.get(domain)
            # Load if integration has no after_dependencies or they are
            # all loaded
            if (not after_deps or not after_deps - hass.config.components):
                domains_to_load.add(domain)

        if not domains_to_load or domains_to_load == last_load:
            break

        _LOGGER.debug("Setting up %s", domains_to_load)

        await asyncio.gather(*[
            async_setup_component(hass, domain, config)
            for domain in domains_to_load
        ])

        last_load = domains_to_load
        stage_2_domains -= domains_to_load

    # These are stage 2 domains that never have their after_dependencies
    # satisfied.
    if stage_2_domains:
        _LOGGER.debug("Final set up: %s", stage_2_domains)

        await asyncio.gather(*[
            async_setup_component(hass, domain, config)
            for domain in stage_2_domains
        ])

    # Wrap up startup
    await hass.async_block_till_done()