Cache remote app list for vizio TVs (#89003)
This commit is contained in:
parent
b43b2eb3cb
commit
7a267460d3
2 changed files with 47 additions and 32 deletions
homeassistant/components/vizio
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Add table
Reference in a new issue