megakid / ha_octopus_intelligent

Apache License 2.0
86 stars 10 forks source link

Prevent duplicate Octopus API call on integration load #39

Closed pdcastro closed 4 months ago

pdcastro commented 4 months ago

While working on other PRs, I observed (through debug logging) that the Octopus GraphQL API (async_get_combined_state) was called twice — one call right after the other — when the integration was loaded, e.g. when HASS was restarted.

The first call is a result of the call to async_config_entry_first_refresh() on the following line: https://github.com/megakid/ha_octopus_intelligent/blob/v1.6.3/custom_components/octopus_intelligent/__init__.py#L59

The second call is a result of each platform (binary sensor, sensor, switch, select) calling async_add_entities(..., True), where the True argument is short for update_before_add=True, which triggers a call chain that eventually results in calls to async_request_refresh() on the DataUpdateCoordinator: https://github.com/home-assistant/core/blob/2024.2.5/homeassistant/helpers/update_coordinator.py#L521

This in turn calls _debounced_refresh.async_call(): https://github.com/home-assistant/core/blob/2024.2.5/homeassistant/helpers/update_coordinator.py#L263

Which is a “debounced” call, meaning that, if multiple calls are made in a short period of time (I think it was a 10-second interval), only one call gets made. This way, the 4 calls from the 4 platforms (binary sensor, sensor, switch, select) get combined in a single call, which is made straight away. However, the call triggered by async_config_entry_first_refresh() is not subject to debouncing, so the Octopus API is hit twice.

The API call triggered by async_config_entry_first_refresh() is guaranteed to happen before the calls triggered by async_add_entities(..., True) because the latter are triggered by async_forward_entry_setup() on the following line: https://github.com/megakid/ha_octopus_intelligent/blob/v1.6.3/custom_components/octopus_intelligent/__init__.py#L65

They appear in the code in this order:

    await octopus_system.async_config_entry_first_refresh()        

    for component in PLATFORMS:
        hass.async_create_task(
            hass.config_entries.async_forward_entry_setup(entry, component))

Therefore, the conclusion is that there is no need for the platforms to request update_before_add=True and they could use a False argument instead: async_add_entities(..., False). This saves an unnecessary, duplicate call to the Octopus API whenever Home Assistant restarts. Obviously I tested it to confirm that it works.

It’s not much, but the Octopus API sometimes suffers from load issues and takes 30+ seconds to reply to a query, indeed the subject of @megakid’s commit 9f45e59 / release v1.6.3 and issues like #30 and #31, so I reckon it’s worth it. Also, for developers like me who frequently restart HASS to test stuff, it feels reassuring that my Octopus account won’t be rate-limited or suspended because of duplicate calls.