diff --git a/homeassistant/components/esphome/dashboard.py b/homeassistant/components/esphome/dashboard.py index b618e012d986..f7788d014074 100644 --- a/homeassistant/components/esphome/dashboard.py +++ b/homeassistant/components/esphome/dashboard.py @@ -61,21 +61,25 @@ class ESPHomeDashboardManager: if not (data := self._data) or not (info := data.get("info")): return if is_hassio(self._hass): - from homeassistant.components.hassio import get_addons_info # noqa: PLC0415 + from homeassistant.components.hassio import ( # noqa: PLC0415 + HassioNotReadyError, + get_addons_info, + ) - # This may raise HassioNotReadyError if Supervisor was unreachable - # during setup of the Supervisor integration. That will fail setup - # of this integration. However there is no better option at this time - # since we need to know if the addon is installed from Supervisor to - # correctly setup this integration and we can't raise ConfigEntryNotReady - # to trigger a retry from async_setup. - addons = get_addons_info(self._hass) - if info["addon_slug"] not in addons: - # The addon is not installed anymore, but it make come back - # so we don't want to remove the dashboard, but for now - # we don't want to use it. - _LOGGER.debug("Addon %s is no longer installed", info["addon_slug"]) - return + try: + addons = get_addons_info(self._hass) + except HassioNotReadyError: + # Supervisor was unreachable during its own setup, so we cannot + # tell if the addon is installed. Restore the dashboard anyway, + # a stale one only fails to refresh. + _LOGGER.debug("Supervisor is not ready, skipping addon check") + else: + if info["addon_slug"] not in addons: + # The addon is not installed anymore, but it make come back + # so we don't want to remove the dashboard, but for now + # we don't want to use it. + _LOGGER.debug("Addon %s is no longer installed", info["addon_slug"]) + return await self.async_set_dashboard_info( info["addon_slug"], info["host"], info["port"] diff --git a/tests/components/esphome/test_dashboard.py b/tests/components/esphome/test_dashboard.py index 9887dfd2783b..e98e65fa71f1 100644 --- a/tests/components/esphome/test_dashboard.py +++ b/tests/components/esphome/test_dashboard.py @@ -7,6 +7,7 @@ from aioesphomeapi import APIClient, DeviceInfo, InvalidEncryptionKeyAPIError import pytest from homeassistant.components.esphome import CONF_NOISE_PSK, DOMAIN, dashboard +from homeassistant.components.hassio import HassioNotReadyError from homeassistant.config_entries import ConfigEntryState from homeassistant.core import HomeAssistant from homeassistant.data_entry_flow import FlowResultType @@ -110,6 +111,35 @@ async def test_restore_dashboard_storage_skipped_if_addon_uninstalled( assert not mock_dashboard_api.called +@pytest.mark.usefixtures("hassio_stubs") +async def test_restore_dashboard_storage_if_supervisor_not_ready( + hass: HomeAssistant, + hass_storage: dict[str, Any], +) -> None: + """Restore the dashboard, without failing setup, if Supervisor is not ready.""" + hass_storage[dashboard.STORAGE_KEY] = { + "version": dashboard.STORAGE_VERSION, + "minor_version": dashboard.STORAGE_VERSION, + "key": dashboard.STORAGE_KEY, + "data": {"info": {"addon_slug": "test-slug", "host": "new-host", "port": 6052}}, + } + with ( + patch( + "homeassistant.components.esphome.coordinator.ESPHomeDashboardAPI" + ) as mock_dashboard_api, + patch( + "homeassistant.components.esphome.dashboard.is_hassio", return_value=True + ), + patch( + "homeassistant.components.hassio.get_addons_info", + side_effect=HassioNotReadyError, + ), + ): + assert await async_setup_component(hass, DOMAIN, {}) + await hass.async_block_till_done() + assert mock_dashboard_api.mock_calls[0][1][0] == "http://new-host:6052" + + async def test_setup_dashboard_fails( hass: HomeAssistant, hass_storage: dict[str, Any],