Beispiel #1
0
    async def async_unload(
            self,
            hass: HomeAssistant,
            *,
            integration: loader.Integration | None = None) -> bool:
        """Unload an entry.

        Returns if unload is possible and was successful.
        """
        if self.source == SOURCE_IGNORE:
            self.state = ENTRY_STATE_NOT_LOADED
            return True

        if integration is None:
            try:
                integration = await loader.async_get_integration(
                    hass, self.domain)
            except loader.IntegrationNotFound:
                # The integration was likely a custom_component
                # that was uninstalled, or an integration
                # that has been renamed without removing the config
                # entry.
                self.state = ENTRY_STATE_NOT_LOADED
                return True

        component = integration.get_component()

        if integration.domain == self.domain:
            if self.state in UNRECOVERABLE_STATES:
                return False

            if self.state != ENTRY_STATE_LOADED:
                if self._async_cancel_retry_setup is not None:
                    self._async_cancel_retry_setup()
                    self._async_cancel_retry_setup = None

                self.state = ENTRY_STATE_NOT_LOADED
                return True

        supports_unload = hasattr(component, "async_unload_entry")

        if not supports_unload:
            if integration.domain == self.domain:
                self.state = ENTRY_STATE_FAILED_UNLOAD
            return False

        try:
            result = await component.async_unload_entry(hass,
                                                        self)  # type: ignore

            assert isinstance(result, bool)

            # Only adjust state if we unloaded the component
            if result and integration.domain == self.domain:
                self.state = ENTRY_STATE_NOT_LOADED

            return result
        except Exception:  # pylint: disable=broad-except
            _LOGGER.exception("Error unloading entry %s for %s", self.title,
                              integration.domain)
            if integration.domain == self.domain:
                self.state = ENTRY_STATE_FAILED_UNLOAD
            return False
Beispiel #2
0
    async def async_setup(
        self,
        hass: HomeAssistant,
        *,
        integration: loader.Integration | None = None,
        tries: int = 0,
    ) -> None:
        """Set up an entry."""
        if self.source == SOURCE_IGNORE or self.disabled_by:
            return

        if integration is None:
            integration = await loader.async_get_integration(hass, self.domain)

        self.supports_unload = await support_entry_unload(hass, self.domain)

        try:
            component = integration.get_component()
        except ImportError as err:
            _LOGGER.error(
                "Error importing integration %s to set up %s configuration entry: %s",
                integration.domain,
                self.domain,
                err,
            )
            if self.domain == integration.domain:
                self.state = ENTRY_STATE_SETUP_ERROR
            return

        if self.domain == integration.domain:
            try:
                integration.get_platform("config_flow")
            except ImportError as err:
                _LOGGER.error(
                    "Error importing platform config_flow from integration %s to set up %s configuration entry: %s",
                    integration.domain,
                    self.domain,
                    err,
                )
                self.state = ENTRY_STATE_SETUP_ERROR
                return

            # Perform migration
            if not await self.async_migrate(hass):
                self.state = ENTRY_STATE_MIGRATION_ERROR
                return

        try:
            result = await component.async_setup_entry(hass,
                                                       self)  # type: ignore

            if not isinstance(result, bool):
                _LOGGER.error("%s.async_setup_entry did not return boolean",
                              integration.domain)
                result = False
        except ConfigEntryNotReady as ex:
            self.state = ENTRY_STATE_SETUP_RETRY
            wait_time = 2**min(tries, 4) * 5
            tries += 1
            message = str(ex)
            if not message and ex.__cause__:
                message = str(ex.__cause__)
            ready_message = f"ready yet: {message}" if message else "ready yet"
            if tries == 1:
                _LOGGER.warning(
                    "Config entry '%s' for %s integration not %s; Retrying in background",
                    self.title,
                    self.domain,
                    ready_message,
                )
            else:
                _LOGGER.debug(
                    "Config entry '%s' for %s integration not %s; Retrying in %d seconds",
                    self.title,
                    self.domain,
                    ready_message,
                    wait_time,
                )

            async def setup_again(*_: Any) -> None:
                """Run setup again."""
                self._async_cancel_retry_setup = None
                await self.async_setup(hass,
                                       integration=integration,
                                       tries=tries)

            if hass.state == CoreState.running:
                self._async_cancel_retry_setup = hass.helpers.event.async_call_later(
                    wait_time, setup_again)
            else:
                self._async_cancel_retry_setup = hass.bus.async_listen_once(
                    EVENT_HOMEASSISTANT_STARTED, setup_again)
            return
        except Exception:  # pylint: disable=broad-except
            _LOGGER.exception("Error setting up entry %s for %s", self.title,
                              integration.domain)
            result = False

        # Only store setup result as state if it was not forwarded.
        if self.domain != integration.domain:
            return

        if result:
            self.state = ENTRY_STATE_LOADED
        else:
            self.state = ENTRY_STATE_SETUP_ERROR