diff --git a/homeassistant/components/vizio/__init__.py b/homeassistant/components/vizio/__init__.py index 9fc40c40c2b..d694f4b93f8 100644 --- a/homeassistant/components/vizio/__init__.py +++ b/homeassistant/components/vizio/__init__.py @@ -15,6 +15,7 @@ from homeassistant.const import Platform from homeassistant.core import HomeAssistant from homeassistant.helpers import config_validation as cv from homeassistant.helpers.aiohttp_client import async_get_clientsession +from homeassistant.helpers.storage import Store from homeassistant.helpers.typing import ConfigType from homeassistant.helpers.update_coordinator import DataUpdateCoordinator @@ -66,8 +67,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: CONF_APPS not in hass.data[DOMAIN] and entry.data[CONF_DEVICE_CLASS] == MediaPlayerDeviceClass.TV ): - coordinator = VizioAppsDataUpdateCoordinator(hass) - await coordinator.async_refresh() + store: Store = Store(hass, 1, DOMAIN) + coordinator = VizioAppsDataUpdateCoordinator(hass, store) + await coordinator.async_config_entry_first_refresh() hass.data[DOMAIN][CONF_APPS] = coordinator await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) @@ -98,7 +100,7 @@ async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> class VizioAppsDataUpdateCoordinator(DataUpdateCoordinator[list[dict[str, Any]]]): """Define an object to hold Vizio app config data.""" - def __init__(self, hass: HomeAssistant) -> None: + def __init__(self, hass: HomeAssistant, store: Store) -> None: """Initialize.""" super().__init__( hass, @@ -107,31 +109,40 @@ class VizioAppsDataUpdateCoordinator(DataUpdateCoordinator[list[dict[str, Any]]] update_interval=timedelta(days=1), update_method=self._async_update_data, ) - self.data = APPS self.fail_count = 0 self.fail_threshold = 10 + self.store = store + + async def async_config_entry_first_refresh(self) -> None: + """Refresh data for the first time when a config entry is setup.""" + self.data = await self.store.async_load() or APPS + await super().async_config_entry_first_refresh() async def _async_update_data(self) -> list[dict[str, Any]]: """Update data via library.""" - data = await gen_apps_list_from_url(session=async_get_clientsession(self.hass)) - if not data: - # For every failure, increase the fail count until we reach the threshold. - # We then log a warning, increase the threshold, and reset the fail count. - # This is here to prevent silent failures but to reduce repeat logs. - if self.fail_count == self.fail_threshold: - _LOGGER.warning( - ( - "Unable to retrieve the apps list from the external server " - "for the last %s days" - ), - self.fail_threshold, - ) - self.fail_count = 0 - self.fail_threshold += 10 - else: - self.fail_count += 1 - return self.data - # Reset the fail count and threshold when the data is successfully retrieved - self.fail_count = 0 - self.fail_threshold = 10 - return sorted(data, key=lambda app: app["name"]) + if data := await gen_apps_list_from_url( + session=async_get_clientsession(self.hass) + ): + # Reset the fail count and threshold when the data is successfully retrieved + self.fail_count = 0 + self.fail_threshold = 10 + # Store the new data if it has changed so we have it for the next restart + if data != self.data: + await self.store.async_save(data) + return data + # For every failure, increase the fail count until we reach the threshold. + # We then log a warning, increase the threshold, and reset the fail count. + # This is here to prevent silent failures but to reduce repeat logs. + if self.fail_count == self.fail_threshold: + _LOGGER.warning( + ( + "Unable to retrieve the apps list from the external server for the " + "last %s days" + ), + self.fail_threshold, + ) + self.fail_count = 0 + self.fail_threshold += 10 + else: + self.fail_count += 1 + return self.data diff --git a/homeassistant/components/vizio/media_player.py b/homeassistant/components/vizio/media_player.py index e1ca306ddf7..a989cea488f 100644 --- a/homeassistant/components/vizio/media_player.py +++ b/homeassistant/components/vizio/media_player.py @@ -137,7 +137,7 @@ class VizioDevice(MediaPlayerEntity): device: VizioAsync, name: str, device_class: MediaPlayerDeviceClass, - apps_coordinator: VizioAppsDataUpdateCoordinator, + apps_coordinator: VizioAppsDataUpdateCoordinator | None, ) -> None: """Initialize Vizio device.""" self._config_entry = config_entry @@ -330,17 +330,21 @@ class VizioDevice(MediaPlayerEntity): ) ) + if not self._apps_coordinator: + return + # Register callback for app list updates if device is a TV @callback - def apps_list_update(): + def apps_list_update() -> None: """Update list of all apps.""" + if not self._apps_coordinator: + return self._all_apps = self._apps_coordinator.data self.async_write_ha_state() - if self._attr_device_class == MediaPlayerDeviceClass.TV: - self.async_on_remove( - self._apps_coordinator.async_add_listener(apps_list_update) - ) + self.async_on_remove( + self._apps_coordinator.async_add_listener(apps_list_update) + ) @property def source(self) -> str | None: