diff --git a/custom_components/openei/__init__.py b/custom_components/openei/__init__.py index 6644b5b..431e4b2 100644 --- a/custom_components/openei/__init__.py +++ b/custom_components/openei/__init__.py @@ -83,6 +83,7 @@ def __init__(self, hass: HomeAssistant, config: ConfigEntry) -> None: self.hass = hass self.interval = timedelta(seconds=30) self._data = {} + self._rate_limit_count = 0 _LOGGER.debug("Data will be updated at the top of every hour.") @@ -100,11 +101,8 @@ async def _async_update_data(self) -> dict: async_call_later(self.hass, wait_seconds, self._async_refresh_data) try: self._data = await self.hass.async_add_executor_job( - get_sensors, self.hass, self._config + self.get_sensors, self.hass, self._config ) - except openeihttp.RateLimit: - _LOGGER.error("API Rate limit exceded, retrying later.") - self._data = {} except Exception as exception: raise UpdateFailed() from exception return self._data @@ -121,59 +119,68 @@ async def _async_refresh_data(self, data=None) -> None: async_call_later(self.hass, wait_seconds, self._async_refresh_data) try: self._data = await self.hass.async_add_executor_job( - get_sensors, self.hass, self._config + self.get_sensors, self.hass, self._config ) - except openeihttp.RateLimit: - _LOGGER.error("API Rate limit exceded, retrying later.") - self._data = {} except Exception as exception: raise UpdateFailed() from exception - -def get_sensors(hass, config) -> dict: - """Update sensor data.""" - api = config.data.get(CONF_API_KEY) - plan = config.data.get(CONF_PLAN) - meter = config.data.get(CONF_SENSOR) - reading = None - - if config.data.get(CONF_MANUAL_PLAN): - plan = config.data.get(CONF_MANUAL_PLAN) - - if meter: - _LOGGER.debug("Using meter data from sensor: %s", meter) - reading = hass.states.get(meter) - if not reading: - reading = None - _LOGGER.warning("Sensor: %s is not valid.", meter) - else: - reading = reading.state - - rate = openeihttp.Rates( - api=api, - plan=plan, - reading=reading, - ) - rate.update() - data = {} - - for sensor in SENSOR_TYPES: # pylint: disable=consider-using-dict-items - _sensor = {} - value = getattr(rate, SENSOR_TYPES[sensor].key) - if isinstance(value, tuple): - _sensor[sensor] = value[0] - _sensor[f"{sensor}_uom"] = value[1] - else: - _sensor[sensor] = getattr(rate, SENSOR_TYPES[sensor].key) - data.update(_sensor) - - for sensor in BINARY_SENSORS: # pylint: disable=consider-using-dict-items - _sensor = {} - _sensor[sensor] = getattr(rate, sensor) - data.update(_sensor) - - _LOGGER.debug("DEBUG: %s", data) - return data + def get_sensors(self) -> dict: + """Update sensor data.""" + api = self._config.data.get(CONF_API_KEY) + plan = self._config.data.get(CONF_PLAN) + meter = self._config.data.get(CONF_SENSOR) + reading = None + + if self._config.data.get(CONF_MANUAL_PLAN): + plan = self._config.data.get(CONF_MANUAL_PLAN) + + if meter: + _LOGGER.debug("Using meter data from sensor: %s", meter) + reading = self.hass.states.get(meter) + if not reading: + reading = None + _LOGGER.warning("Sensor: %s is not valid.", meter) + else: + reading = reading.state + + rate = openeihttp.Rates( + api=api, + plan=plan, + reading=reading, + ) + if self._rate_limit_count == 0: + try: + rate.update() + except openeihttp.RateLimit: + _LOGGER.error("API Rate limit exceded, retrying later.") + if self._data == {}: + # 3 hour retry if we have no data + self._rate_limit_count = 3 + else: + # 6 hour retry after rate limited + self._rate_limit_count = 6 + elif self._rate_limit_count > 0: + self._rate_limit_count -= 1 + + data = {} + + for sensor in SENSOR_TYPES: # pylint: disable=consider-using-dict-items + _sensor = {} + value = getattr(rate, SENSOR_TYPES[sensor].key) + if isinstance(value, tuple): + _sensor[sensor] = value[0] + _sensor[f"{sensor}_uom"] = value[1] + else: + _sensor[sensor] = getattr(rate, SENSOR_TYPES[sensor].key) + data.update(_sensor) + + for sensor in BINARY_SENSORS: # pylint: disable=consider-using-dict-items + _sensor = {} + _sensor[sensor] = getattr(rate, sensor) + data.update(_sensor) + + _LOGGER.debug("DEBUG: %s", data) + return data async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: