from datetime import datetime, timedelta, timezone import itertools import json import os import urllib.error import urllib.parse import urllib.request class DarkSkyAPI: def __init__(self, apikey=None, gps=None, opts={"lang": "fr", "units": "metric"}): self.apikey = apikey or os.environ["WEATHERAPIKEY"] self.baseurl = "https://api.openweathermap.org/data/3.0/onecall" self.default_gps = gps or ("GPS" in os.environ and os.environ["GPS"]) or "48.8127,2.3437" self.opts = opts self._cached_file = ".darksky-%s.cache" def get_weather(self, gps=None): if gps is None: gps = self.default_gps # Read the mod time statinfo = None try: statinfo = os.stat(self._cached_file % gps) except: pass if statinfo is None or datetime.fromtimestamp(statinfo.st_mtime, tz=timezone.utc) + timedelta(hours=1) < datetime.now(tz=timezone.utc): # Do the request and save it try: (lat,lon) = gps.split(",") with urllib.request.urlopen(self.baseurl + "?appid=" + str(self.apikey) + "&lat=" + str(lat) + "&lon=" + str(lon) + "&" + ("&".join([opt+"="+self.opts[opt] for opt in self.opts]))) as f: with open(self._cached_file % gps, 'wb') as fd: fd.write(f.read()) except ConnectionResetError: pass #except urllib.error.URLError: # pass # Retrieve cached data res = {} with open(self._cached_file % gps) as f: res = json.load(f) return res def get_icon(icon, night=False, current=False): # 200: Thunderstorm if icon < 300: if icon == 200 or icon == 201 or icon == 202: if not night: return "wi-day-thunderstorm.png" else: return "wi-night-thunderstorm.png" elif icon == 210 or icon == 211: return "wi-thunderstorm.png" elif icon == 212 or icon == 221: return "wi-lightning.png" elif icon == 230 or icon == 231 or icon == 232: if not night: return "wi-day-storm-showers.png" else: return "wi-night-storm-showers.png" else: return "wi-thunderstorm.png" # 300: Drizzle elif icon < 400: if icon < 311: if not night: return "wi-day-showers.png" else: return "wi-night-showers.png" else: return "wi-showers.png" # 500: Rain elif icon < 600: if icon == 500: if not night: return "wi-day-rain.png" else: return "wi-night-rain.png" if icon < 510: return "wi-rain.png" elif icon < 520: if current: return "wi-hail.png" elif not night: return "wi-day-hail.png" else: return "wi-night-hail.png" elif icon == 520: if not night: return "wi-day-showers.png" else: return "wi-night-showers.png" elif icon > 520: return "wi-showers.png" else: return "wi-rain.png" # 600: Snow elif icon < 700: if icon == 600: if not night: return "wi-day-snow.png" else: return "wi-night-alt-snow.png" elif icon < 610: return "wi-snow.png" elif icon < 620: if current: return "wi-sleet.png" if not night: return "wi-day-sleet.png" else: return "wi-night-alt-sleet.png" elif icon == 620: if not night: return "wi-day-snow-wind.png" else: return "wi-night-snow-wind.png" elif icon < 630: return "wi-snow-wind.png" else: return "wi-snow.png" # Atmosphere elif icon < 800: if icon == 701: if not night: return "wi-day-haze.png" else: return "wi-night-fog.png" elif icon < 720: return "wi-smoke.png" elif icon < 730: if not night: return "wi-day-haze.png" else: return "wi-night-fog.png" elif icon < 740: return "wi-dust.png" elif icon < 750: if not night: return "wi-day-fog.png" else: return "wi-night-fog.png" elif icon == 751: return "wi-sandstorm.png" elif icon < 762: return "wi-dust.png" elif icon == 762: return "wi-volcano.png" elif icon == 771: return "wi-strong-wind.png" elif icon == 781: return "wi-tornado.png" # 800: Clear if icon == 800: if not night: return "wi-day-sunny.png" else: return "wi-night-clear.png" # 800: Clouds elif icon == 801: if not night: return "wi-day-sunny-overcast.png" else: return "wi-night-alt-partly-cloudy.png" elif icon == 802: if not night: return "wi-day-cloudy.png" else: return "wi-night-alt-cloudy.png" elif icon == 804: return "wi-cloudy.png" elif icon < 900: return "wi-cloud.png" return "wi-alien.png" def get_moon_icon(self, day=0): thisdayweather = list(itertools.islice(self.get_daily(), 1))[0] moon_phase = thisdayweather["moon_phase"] if moon_phase < 0.035: return "wi-moon-alt-new.png" elif moon_phase < 0.071: return "wi-moon-alt-waxing-crescent-1.png" elif moon_phase < 0.107: return "wi-moon-alt-waxing-crescent-2.png" elif moon_phase < 0.142: return "wi-moon-alt-waxing-crescent-3.png" elif moon_phase < 0.178: return "wi-moon-alt-waxing-crescent-4.png" elif moon_phase < 0.214: return "wi-moon-alt-waxing-crescent-5.png" elif moon_phase < 0.25: return "wi-moon-alt-waxing-crescent-6.png" elif moon_phase < 0.285: return "wi-moon-alt-first-quarter.png" elif moon_phase < 0.321: return "wi-moon-alt-waxing-gibbous-1.png" elif moon_phase < 0.357: return "wi-moon-alt-waxing-gibbous-2.png" elif moon_phase < 0.392: return "wi-moon-alt-waxing-gibbous-3.png" elif moon_phase < 0.428: return "wi-moon-alt-waxing-gibbous-4.png" elif moon_phase < 0.464: return "wi-moon-alt-waxing-gibbous-5.png" elif moon_phase < 0.5: return "wi-moon-alt-waxing-gibbous-6.png" elif moon_phase < 0.535: return "wi-moon-alt-full.png" elif moon_phase < 0.571: return "wi-moon-alt-waning-gibbous-1.png" elif moon_phase < 0.607: return "wi-moon-alt-waning-gibbous-2.png" elif moon_phase < 0.642: return "wi-moon-alt-waning-gibbous-3.png" elif moon_phase < 0.678: return "wi-moon-alt-waning-gibbous-4.png" elif moon_phase < 0.714: return "wi-moon-alt-waning-gibbous-5.png" elif moon_phase < 0.75: return "wi-moon-alt-waning-gibbous-6.png" elif moon_phase < 0.785: return "wi-moon-alt-third-quarter.png" elif moon_phase < 0.821: return "wi-moon-alt-waning-crescent-1.png" elif moon_phase < 0.857: return "wi-moon-alt-waning-crescent-2.png" elif moon_phase < 0.892: return "wi-moon-alt-waning-crescent-3.png" elif moon_phase < 0.928: return "wi-moon-alt-waning-crescent-4.png" elif moon_phase < 0.964: return "wi-moon-alt-waning-crescent-5.png" else: return "wi-moon-alt-waning-crescent-6.png" def get_currently(self, *args, **kwargs): cur = self.get_weather(*args, **kwargs)["current"] cur["is_day"] = True return cur def get_hourly(self, *args, **kwargs): return self.get_weather(*args, **kwargs)["hourly"] def get_daily(self, *args, **kwargs): for d in self.get_weather(*args, **kwargs)["daily"]: d["date"] = datetime.fromtimestamp(d["dt"]) yield d def has_alerts(self, *args, **kwargs): return "alerts" in self.get_weather(*args, **kwargs) and len(self.get_weather(*args, **kwargs)["alerts"]) > 0 def get_alerts(self, *args, **kwargs): w = self.get_weather(*args, **kwargs) if "alerts" in w: return w["alerts"] return [] def read_timestamp(self, timestamp, *args, **kwargs): wth = self.get_weather(*args, **kwargs) tz = timezone(timedelta(seconds=wth["timezone_offset"]), wth["timezone"]) return datetime.fromtimestamp(timestamp, tz=tz) WeatherAPI = DarkSkyAPI if __name__ == '__main__': dsa = DarkSkyAPI() print(dsa.get_currently())