diff --git a/py3status/modules/weather_owm.py b/py3status/modules/weather_owm.py index 8aa47dce02..d318e37975 100644 --- a/py3status/modules/weather_owm.py +++ b/py3status/modules/weather_owm.py @@ -261,11 +261,12 @@ """ import datetime +import json # API information OWM_CURR_ENDPOINT = "https://api.openweathermap.org/data/2.5/weather?" OWM_FUTURE_ENDPOINT = "https://api.openweathermap.org/data/2.5/forecast?" -OWM_ONECALL_ENDPOINT = "https://api.openweathermap.org/data/2.5/onecall?" +OWM_ONECALL_ENDPOINT = "https://api.openweathermap.org/data/3.0/onecall?exclude=alerts,minutely" IP_ENDPOINT = "http://geo.ultrabug.fr" # Paths of information to extract from JSON @@ -448,6 +449,18 @@ def post_config_hook(self): # Generate our icon array self.icons = self._get_icons() + # Implement safe-to-reload rate limit + cached_day = datetime.datetime.now(datetime.UTC).strftime("%Y%m%d") + self.cached_hits = json.loads( + self.py3.storage_get("cached_hits") or json.dumps({cached_day: 0}) + ) + self.cached_onecall_response = self.py3.storage_get("cached_onecall_response") + + # We want to make sure users to not exceed the request limit + # to 3.0 API and get billed while taking into account that + # OWM does refresh its API data every 10min anyway. + self.cache_timeout = max(600, self.cache_timeout) + # Verify the units configuration if self.unit_rain.lower() not in RAIN_UNITS: raise Exception("unit_rain is not recognized") @@ -817,6 +830,9 @@ def _format(self, current_wthr, fcsts, city, country): return self.py3.safe_format(self.format, today) def weather_owm(self): + # Prepare rate limit cache + cached_day = datetime.datetime.now(datetime.UTC).strftime("%Y%m%d") + cached_hits = self.cached_hits.get(cached_day, 0) # Get weather information loc_tz_info = self._get_loc_tz_info() text = "" @@ -840,9 +856,19 @@ def weather_owm(self): except Exception: raise Exception("no latitude/longitude found for your config") - # onecall = forecasts - onecall_api_params = {"lat": lat, "lon": lon} - onecall = self._get_onecall(onecall_api_params) + # onecall = forecasts rate limited + if cached_hits < 999: + onecall_api_params = {"lat": lat, "lon": lon} + onecall = self._get_onecall(onecall_api_params) + # update and store caches + self.cached_onecall_response = onecall + self.cached_hits[cached_day] = cached_hits + 1 + self.py3.storage_set("cached_onecall_response", onecall) + self.py3.storage_set( + "cached_hits", json.dumps({cached_day: self.cached_hits[cached_day]}) + ) + else: + onecall = self.cached_onecall_response onecall_daily = onecall["daily"] fcsts_days = self.forecast_days + 1