disforw / goveelife

Home Assistant Govee integration using the newest API for ALL Govee WiFi devices
17 stars 2 forks source link

async_forward_entry_setup Warning for GoveeLife Integration #16

Closed PHolstein1 closed 1 month ago

PHolstein1 commented 1 month ago

I am encountering a warning related to the GoveeLife integration in Home Assistant. The warning indicates that async_forward_entry_setup is being called without being awaited, which will be deprecated in Home Assistant 2025.1. Here are the details:

Logger: homeassistant.helpers.frame Source: helpers/frame.py:151 First occurred: 12:20:04 PM (2 occurrences) Last logged: 12:20:04 PM

Detected code that calls async_forward_entry_setup for integration goveelife with title: GoveeLife and entry_id: 01J2ENQEW26DHRBYZ4YKBSB7NV, during setup without awaiting async_forward_entry_setup, which can cause the setup lock to be released before the setup is done. This will stop working in Home Assistant 2025.1. Please report this issue.

Steps to Reproduce:

1.  Install the GoveeLife integration.
2.  Observe the log for warnings during the setup process.

Expected behavior: The integration setup should await the async_forward_entry_setup call to ensure proper setup and prevent the release of the setup lock before completion.

Additional context: This issue needs to be resolved before Home Assistant 2025.1's deprecation, as it will cause the integration to stop working. Please let me know if any additional information is needed.

PHolstein1 commented 1 month ago

With the help of ChatGPT, we rewrote the init.py file and it works on my system:

"""Init for the Govee Life integration."""

from future import annotations from typing import Final import logging import asyncio

from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant from homeassistant.const import ( CONF_API_KEY, CONF_DEVICES, CONF_PARAMS, CONF_SCAN_INTERVAL, )

from .const import ( DOMAIN, CONF_COORDINATORS, FUNC_OPTION_UPDATES, SUPPORTED_PLATFORMS, ) from .entities import ( GoveeAPIUpdateCoordinator, ) from .services import ( async_registerService, async_service_SetPollInterval, ) from .utils import ( async_ProgrammingDebug, async_GoveeAPI_GETRequest, async_GoveeAPI_GetDeviceState, )

_LOGGER: Final = logging.getLogger(name)

async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Set up cloud resource from the config entry.""" _LOGGER.debug("Setting up config entry: %s", entry.entry_id)

try:
    _LOGGER.debug("%s - async_setup_entry: Creating data store: %s.%s ", entry.entry_id, DOMAIN, entry.entry_id)
    hass.data.setdefault(DOMAIN, {})
    hass.data[DOMAIN].setdefault(entry.entry_id, {})
    entry_data = hass.data[DOMAIN][entry.entry_id]
    entry_data[CONF_PARAMS] = entry.data
    entry_data[CONF_SCAN_INTERVAL] = None
except Exception as e:
    _LOGGER.error("%s - async_setup_entry: Creating data store failed: %s (%s.%s)", entry.entry_id, str(e), e.__class__.__module__, type(e).__name__)
    return False

try:
    _LOGGER.debug("%s - async_setup_entry: Receiving cloud devices..", entry.entry_id)
    api_devices = await async_GoveeAPI_GETRequest(hass, entry.entry_id, 'user/devices')
    if api_devices is None:
        return False
    entry_data[CONF_DEVICES] = api_devices
except Exception as e:
    _LOGGER.error("%s - async_setup_entry: Receiving cloud devices failed: %s (%s.%s)", entry.entry_id, str(e), e.__class__.__module__, type(e).__name__)
    return False 

try:
    _LOGGER.debug("%s - async_setup_entry: Creating update coordinators per device..", entry.entry_id)
    entry_data.setdefault(CONF_COORDINATORS, {})
    for device_cfg in api_devices:
        await async_GoveeAPI_GetDeviceState(hass, entry.entry_id, device_cfg)
        coordinator = GoveeAPIUpdateCoordinator(hass, entry.entry_id, device_cfg)
        d = device_cfg.get('device')
        entry_data[CONF_COORDINATORS][d] = coordinator            
except Exception as e:
    _LOGGER.error("%s - async_setup_entry: Creating update coordinators failed: %s (%s.%s)", entry.entry_id, str(e), e.__class__.__module__, type(e).__name__)
    return False 

try:
    _LOGGER.debug("%s - async_setup_entry: Register option updates listener: %s ", entry.entry_id, FUNC_OPTION_UPDATES)
    entry_data[FUNC_OPTION_UPDATES] = entry.add_update_listener(options_update_listener)
except Exception as e:
    _LOGGER.error("%s - async_setup_entry: Register option updates listener failed: %s (%s.%s)", entry.entry_id, str(e), e.__class__.__module__, type(e).__name__)
    return False

try:
    await hass.config_entries.async_forward_entry_setups(entry, SUPPORTED_PLATFORMS)
except Exception as e:
    _LOGGER.error("%s - async_setup_entry: Setup trigger for platform failed: %s (%s.%s)", entry.entry_id, str(e), e.__class__.__module__, type(e).__name__)
    return False

try:
    _LOGGER.debug("%s - async_setup_entry: register services", entry.entry_id)
    await async_registerService(hass, "set_poll_interval", async_service_SetPollInterval)
except Exception as e:
    _LOGGER.error("%s - async_setup_entry: register services failed: %s (%s.%s)", entry.entry_id, str(e), e.__class__.__module__, type(e).__name__)
    return False 

_LOGGER.debug("%s - async_setup_entry: Completed", entry.entry_id)
return True

async def options_update_listener(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Handle options update.""" _LOGGER.debug("Update options / reload config entry: %s", entry.entry_id) await hass.config_entries.async_reload(entry.entry_id)

async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Unload a config entry.""" try: _LOGGER.debug("Unloading config entry: %s", entry.entry_id) all_ok = True for platform in SUPPORTED_PLATFORMS: _LOGGER.debug("%s - async_unload_entry: unload platform: %s", entry.entry_id, platform) platform_ok = await hass.config_entries.async_forward_entry_unload(entry, platform) if not platform_ok: _LOGGER.error("%s - async_unload_entry: failed to unload: %s (%s)", entry.entry_id, platform, platform_ok) all_ok = platform_ok

    if all_ok:
        _LOGGER.debug("%s - async_unload_entry: Unload option updates listener: %s.%s ", entry.entry_id, FUNC_OPTION_UPDATES)
        hass.data[DOMAIN][entry.entry_id][FUNC_OPTION_UPDATES]()
        _LOGGER.debug("%s - async_unload_entry: Remove data store: %s.%s ", entry.entry_id, DOMAIN, entry.entry_id)
        hass.data[DOMAIN].pop(entry.entry_id)
    return all_ok
except Exception as e:
    _LOGGER.error("%s - async_unload_entry: Unload device failed: %s (%s.%s)", entry.entry_id, str(e), e.__class__.__module__, type(e).__name__)
    return False
disforw commented 1 month ago

Sorry, what version do you have installed?

PHolstein1 commented 1 month ago

It's version 0.0.1

disforw commented 1 month ago

Cleaned up in beta 2.9.6

PHolstein1 commented 1 month ago

I just tried the latest beta 2.9.8 and got errors:

This error originated from a custom integration.

Logger: custom_components.goveelife.switch Source: custom_components/goveelife/switch.py:60 integration: Govee Life (documentation) First occurred: 1:21:49 PM (2 occurrences) Last logged: 1:23:04 PM

01J2FSEH14GVKNTX4AW5R0778P - async_setup_entry switch: Setup device failed: 'GoveeLifeSwitch' object has no attribute '_api_id' (builtins.AttributeError)

and

This error originated from a custom integration.

Logger: custom_components.goveelife.climate Source: custom_components/goveelife/climate.py:52 integration: Govee Life (documentation) First occurred: 1:21:49 PM (2 occurrences) Last logged: 1:23:04 PM

01J2FSEH14GVKNTX4AW5R0778P - async_setup_entry climate: Failed to setup device: 'GoveeLifeClimate' object has no attribute '_api_id' (builtins.AttributeError)