Repository: home-assistant/core
File: homeassistant/components/fritzbox/coordinator.py (Python)

Code before:
            password=self.config_entry.data[CONF_PASSWORD],
        )

        try:
            await self.hass.async_add_executor_job(self.fritz.login)
        except RequestConnectionError as err:
            raise ConfigEntryNotReady from err
        except LoginError as err:
            raise ConfigEntryAuthFailed from err

        self.has_templates = await self.hass.async_add_executor_job(
            self.fritz.has_templates
        )
        LOGGER.debug("enable smarthome templates: %s", self.has_templates)

        try:
            self.has_triggers = await self.hass.async_add_executor_job(
                self.fritz.has_triggers
            )
        except HTTPError:
            # Fritz!OS < 7.39 just don't have this api endpoint
            # so we need to fetch the HTTPError here and assume no triggers
            self.has_triggers = False
        LOGGER.debug("enable smarthome triggers: %s", self.has_triggers)

        self.configuration_url = self.fritz.get_prefixed_host()

        await self.async_config_entry_first_refresh()
        self.cleanup_removed_devices(self.data)

    def cleanup_removed_devices(self, data: FritzboxCoordinatorData) -> None:
        """Cleanup entity and device registry from removed devices."""
        available_ains = list(data.devices) + list(data.templates)
        entity_reg = er.async_get(self.hass)
        for entity in er.async_entries_for_config_entry(
            entity_reg, self.config_entry.entry_id
        ):
            if entity.unique_id.split("_")[0] not in available_ains:
                LOGGER.debug("Removing obsolete entity entry %s", entity.entity_id)
                entity_reg.async_remove(entity.entity_id)

        available_main_ains = [
            ain
            for ain, dev in (data.devices | data.templates | data.triggers).items()
            if dev.device_and_unit_id[1] is None
        ]
        device_reg = dr.async_get(self.hass)
        identifiers = {(DOMAIN, ain) for ain in available_main_ains}
        for device in dr.async_entries_for_config_entry(
            device_reg, self.config_entry.entry_id
        ):

Review comment (suggestion):
the `get_prefixed_host()` method has been replaced by the `base_url` property in https://github.com/hthiery/python-fritzhome/pull/126

Code after:
            password=self.config_entry.data[CONF_PASSWORD],
        )

        try:
            await self.hass.async_add_executor_job(self.fritz.login)
        except RequestConnectionError as err:
            raise ConfigEntryNotReady from err
        except LoginError as err:
            raise ConfigEntryAuthFailed from err

        self.has_templates = await self.hass.async_add_executor_job(
            self.fritz.has_templates
        )
        LOGGER.debug("enable smarthome templates: %s", self.has_templates)

        try:
            self.has_triggers = await self.hass.async_add_executor_job(
                self.fritz.has_triggers
            )
        except HTTPError:
            # Fritz!OS < 7.39 just don't have this api endpoint
            # so we need to fetch the HTTPError here and assume no triggers
            self.has_triggers = False
        LOGGER.debug("enable smarthome triggers: %s", self.has_triggers)

        self.configuration_url = self.fritz.base_url

        await self.async_config_entry_first_refresh()
        self.cleanup_removed_devices(self.data)

    def cleanup_removed_devices(self, data: FritzboxCoordinatorData) -> None:
        """Cleanup entity and device registry from removed devices."""
        available_ains = list(data.devices) + list(data.templates)
        entity_reg = er.async_get(self.hass)
        for entity in er.async_entries_for_config_entry(
            entity_reg, self.config_entry.entry_id
        ):
            if entity.unique_id.split("_")[0] not in available_ains:
                LOGGER.debug("Removing obsolete entity entry %s", entity.entity_id)
                entity_reg.async_remove(entity.entity_id)

        available_main_ains = [
            ain
            for ain, dev in (data.devices | data.templates | data.triggers).items()
            if dev.device_and_unit_id[1] is None
        ]
        device_reg = dr.async_get(self.hass)
        identifiers = {(DOMAIN, ain) for ain in available_main_ains}
        for device in dr.async_entries_for_config_entry(
            device_reg, self.config_entry.entry_id
        ):