Cache remote app list for vizio TVs (#89003)

This commit is contained in:
Raman Gupta 2023-03-15 15:42:23 -04:00 committed by GitHub
parent b43b2eb3cb
commit 7a267460d3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 47 additions and 32 deletions

View File

@ -15,6 +15,7 @@ from homeassistant.const import Platform
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers import config_validation as cv from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.storage import Store
from homeassistant.helpers.typing import ConfigType from homeassistant.helpers.typing import ConfigType
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator 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] CONF_APPS not in hass.data[DOMAIN]
and entry.data[CONF_DEVICE_CLASS] == MediaPlayerDeviceClass.TV and entry.data[CONF_DEVICE_CLASS] == MediaPlayerDeviceClass.TV
): ):
coordinator = VizioAppsDataUpdateCoordinator(hass) store: Store = Store(hass, 1, DOMAIN)
await coordinator.async_refresh() coordinator = VizioAppsDataUpdateCoordinator(hass, store)
await coordinator.async_config_entry_first_refresh()
hass.data[DOMAIN][CONF_APPS] = coordinator hass.data[DOMAIN][CONF_APPS] = coordinator
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) 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]]]): class VizioAppsDataUpdateCoordinator(DataUpdateCoordinator[list[dict[str, Any]]]):
"""Define an object to hold Vizio app config data.""" """Define an object to hold Vizio app config data."""
def __init__(self, hass: HomeAssistant) -> None: def __init__(self, hass: HomeAssistant, store: Store) -> None:
"""Initialize.""" """Initialize."""
super().__init__( super().__init__(
hass, hass,
@ -107,31 +109,40 @@ class VizioAppsDataUpdateCoordinator(DataUpdateCoordinator[list[dict[str, Any]]]
update_interval=timedelta(days=1), update_interval=timedelta(days=1),
update_method=self._async_update_data, update_method=self._async_update_data,
) )
self.data = APPS
self.fail_count = 0 self.fail_count = 0
self.fail_threshold = 10 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]]: async def _async_update_data(self) -> list[dict[str, Any]]:
"""Update data via library.""" """Update data via library."""
data = await gen_apps_list_from_url(session=async_get_clientsession(self.hass)) if data := await gen_apps_list_from_url(
if not data: session=async_get_clientsession(self.hass)
# 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. # Reset the fail count and threshold when the data is successfully retrieved
# This is here to prevent silent failures but to reduce repeat logs. self.fail_count = 0
if self.fail_count == self.fail_threshold: self.fail_threshold = 10
_LOGGER.warning( # Store the new data if it has changed so we have it for the next restart
( if data != self.data:
"Unable to retrieve the apps list from the external server " await self.store.async_save(data)
"for the last %s days" return data
), # For every failure, increase the fail count until we reach the threshold.
self.fail_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.
self.fail_count = 0 if self.fail_count == self.fail_threshold:
self.fail_threshold += 10 _LOGGER.warning(
else: (
self.fail_count += 1 "Unable to retrieve the apps list from the external server for the "
return self.data "last %s days"
# Reset the fail count and threshold when the data is successfully retrieved ),
self.fail_count = 0 self.fail_threshold,
self.fail_threshold = 10 )
return sorted(data, key=lambda app: app["name"]) self.fail_count = 0
self.fail_threshold += 10
else:
self.fail_count += 1
return self.data

View File

@ -137,7 +137,7 @@ class VizioDevice(MediaPlayerEntity):
device: VizioAsync, device: VizioAsync,
name: str, name: str,
device_class: MediaPlayerDeviceClass, device_class: MediaPlayerDeviceClass,
apps_coordinator: VizioAppsDataUpdateCoordinator, apps_coordinator: VizioAppsDataUpdateCoordinator | None,
) -> None: ) -> None:
"""Initialize Vizio device.""" """Initialize Vizio device."""
self._config_entry = config_entry 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 # Register callback for app list updates if device is a TV
@callback @callback
def apps_list_update(): def apps_list_update() -> None:
"""Update list of all apps.""" """Update list of all apps."""
if not self._apps_coordinator:
return
self._all_apps = self._apps_coordinator.data self._all_apps = self._apps_coordinator.data
self.async_write_ha_state() self.async_write_ha_state()
if self._attr_device_class == MediaPlayerDeviceClass.TV: self.async_on_remove(
self.async_on_remove( self._apps_coordinator.async_add_listener(apps_list_update)
self._apps_coordinator.async_add_listener(apps_list_update) )
)
@property @property
def source(self) -> str | None: def source(self) -> str | None: