From 236debb455380d09a32f619736ac2daf45469e4b Mon Sep 17 00:00:00 2001 From: Penny Wood Date: Thu, 11 Jul 2019 02:15:42 +0800 Subject: [PATCH] Avoid flooding steam API (#23941) --- .../components/steam_online/sensor.py | 63 +++++++++++++++---- 1 file changed, 50 insertions(+), 13 deletions(-) diff --git a/homeassistant/components/steam_online/sensor.py b/homeassistant/components/steam_online/sensor.py index 1afeb2be4df..d01334b66f2 100644 --- a/homeassistant/components/steam_online/sensor.py +++ b/homeassistant/components/steam_online/sensor.py @@ -1,10 +1,13 @@ """Sensor for Steam account status.""" import logging +from datetime import timedelta import voluptuous as vol from homeassistant.components.sensor import PLATFORM_SCHEMA +from homeassistant.core import callback from homeassistant.helpers.entity import Entity +from homeassistant.helpers.event import async_track_time_interval from homeassistant.const import CONF_API_KEY import homeassistant.helpers.config_validation as cv @@ -28,6 +31,9 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.All(cv.ensure_list, [cv.string]), }) +APP_LIST_KEY = 'steam_online.app_list' +BASE_INTERVAL = timedelta(minutes=1) + def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Steam platform.""" @@ -35,21 +41,32 @@ def setup_platform(hass, config, add_entities, discovery_info=None): steamod.api.key.set(config.get(CONF_API_KEY)) # Initialize steammods app list before creating sensors # to benefit from internal caching of the list. - steam_app_list = steamod.apps.app_list() - add_entities( - [SteamSensor(account, - steamod, - steam_app_list) - for account in config.get(CONF_ACCOUNTS)], True) + hass.data[APP_LIST_KEY] = steamod.apps.app_list() + entities = [ + SteamSensor(account, steamod) + for account in config.get(CONF_ACCOUNTS)] + if not entities: + return + add_entities(entities, True) + + # Only one sensor update once every 60 seconds to avoid + # flooding steam and getting disconnected. + entity_next = 0 + @callback + def do_update(time): + nonlocal entity_next + entities[entity_next].async_schedule_update_ha_state(True) + entity_next = (entity_next + 1) % len(entities) + + async_track_time_interval(hass, do_update, BASE_INTERVAL) class SteamSensor(Entity): """A class for the Steam account.""" - def __init__(self, account, steamod, steam_app_list): + def __init__(self, account, steamod): """Initialize the sensor.""" self._steamod = steamod - self._steam_app_list = steam_app_list self._account = account self._profile = None self._game = self._state = self._name = self._avatar = None @@ -69,6 +86,11 @@ class SteamSensor(Entity): """Return the state of the sensor.""" return self._state + @property + def should_poll(self): + """Turn off polling, will do ourselves.""" + return False + def update(self): """Update device state.""" try: @@ -95,12 +117,27 @@ class SteamSensor(Entity): if game_extra_info: return game_extra_info - if game_id and game_id in self._steam_app_list: - # The app list always returns a tuple - # with the game id and the game name - return self._steam_app_list[game_id][1] + if not game_id: + return None - return None + app_list = self.hass.data[APP_LIST_KEY] + try: + _, res = app_list[game_id] + return res + except KeyError: + pass + + # Try reloading the app list, must be a new app + app_list = self._steamod.apps.app_list() + self.hass.data[APP_LIST_KEY] = app_list + try: + _, res = app_list[game_id] + return res + except KeyError: + pass + + _LOGGER.error("Unable to find name of app with ID=%s", game_id) + return repr(game_id) @property def device_state_attributes(self):