diff options
Diffstat (limited to 'cached')
| -rw-r--r-- | cached/weather_data.py | 78 | ||||
| -rw-r--r-- | cached/weather_forecast.py | 48 |
2 files changed, 62 insertions, 64 deletions
diff --git a/cached/weather_data.py b/cached/weather_data.py index 45b6e6e..7b86d02 100644 --- a/cached/weather_data.py +++ b/cached/weather_data.py @@ -1,12 +1,12 @@ #!/usr/bin/env python3 -from dataclasses import dataclass import datetime import json import logging import os -from typing import Any, List import urllib.request +from dataclasses import dataclass +from typing import Any, List from overrides import overrides @@ -27,32 +27,31 @@ cfg.add_argument( type=str, default=f'{os.environ["HOME"]}/cache/.weather_summary_cache', metavar='FILENAME', - help='File in which to cache weather data' + help='File in which to cache weather data', ) cfg.add_argument( '--weather_data_stalest_acceptable', type=argparse_utils.valid_duration, - default=datetime.timedelta(seconds=7200), # 2 hours + default=datetime.timedelta(seconds=7200), # 2 hours metavar='DURATION', - help='Maximum acceptable age of cached data. If zero, forces a refetch' + help='Maximum acceptable age of cached data. If zero, forces a refetch', ) @dataclass class WeatherData: - date: datetime.date # The date - high: float # The predicted high in F - low: float # The predicted low in F - precipitation_inches: float # Number of inches of precipitation / day - conditions: List[str] # Conditions per ~3h window - most_common_condition: str # The most common condition - icon: str # An icon to represent it + date: datetime.date # The date + high: float # The predicted high in F + low: float # The predicted low in F + precipitation_inches: float # Number of inches of precipitation / day + conditions: List[str] # Conditions per ~3h window + most_common_condition: str # The most common condition + icon: str # An icon to represent it [email protected]_autoloaded_singleton() [email protected]_autoloaded_singleton() # type: ignore class CachedWeatherData(persistent.Persistent): - def __init__(self, - weather_data = None): + def __init__(self, weather_data=None): if weather_data is not None: self.weather_data = weather_data return @@ -72,7 +71,7 @@ class CachedWeatherData(persistent.Persistent): "Sand": "🏜️", "Ash": "🌋", "Squall": "🌬", - "Tornado": "🌪️" + "Tornado": "🌪️", } now = datetime.datetime.now() dates = set() @@ -80,7 +79,7 @@ class CachedWeatherData(persistent.Persistent): lows = {} conditions = {} precip = {} - param = "id=5786882" # Bellevue, WA + param = "id=5786882" # Bellevue, WA key = "c0b160c49743622f62a9cd3cda0270b3" www = urllib.request.urlopen( f'http://api.openweathermap.org/data/2.5/weather?zip=98005,us&APPID={key}&units=imperial' @@ -107,13 +106,13 @@ class CachedWeatherData(persistent.Persistent): if dt == now.date() and now.hour > 18 and condition == 'Clear': icon = '🌙' self.weather_data[dt] = WeatherData( - date = dt, - high = float(parsed_json["main"]["temp_max"]), - low = float(parsed_json["main"]["temp_min"]), - precipitation_inches = p / 25.4, - conditions = [condition], - most_common_condition = condition, - icon = icon, + date=dt, + high=float(parsed_json["main"]["temp_max"]), + low=float(parsed_json["main"]["temp_min"]), + precipitation_inches=p / 25.4, + conditions=[condition], + most_common_condition=condition, + icon=icon, ) www = urllib.request.urlopen( @@ -134,9 +133,9 @@ class CachedWeatherData(persistent.Persistent): lows[dt] = None conditions[dt] = [] for temp in ( - data["main"]["temp"], - data['main']['temp_min'], - data['main']['temp_max'], + data["main"]["temp"], + data['main']['temp_min'], + data['main']['temp_max'], ): if highs[dt] is None or temp > highs[dt]: highs[dt] = temp @@ -160,10 +159,7 @@ class CachedWeatherData(persistent.Persistent): for dt in sorted(dates): if dt == today: high = highs.get(dt, None) - if ( - high is not None and - self.weather_data[today].high < high - ): + if high is not None and self.weather_data[today].high < high: self.weather_data[today].high = high continue most_common_condition = list_utils.most_common(conditions[dt]) @@ -171,23 +167,24 @@ class CachedWeatherData(persistent.Persistent): if dt == now.date() and now.hour > 18 and condition == 'Clear': icon = '🌙' self.weather_data[dt] = WeatherData( - date = dt, - high = highs[dt], - low = lows[dt], - precipitation_inches = precip[dt] / 25.4, - conditions = conditions[dt], - most_common_condition = most_common_condition, - icon = icon + date=dt, + high=highs[dt], + low=lows[dt], + precipitation_inches=precip[dt] / 25.4, + conditions=conditions[dt], + most_common_condition=most_common_condition, + icon=icon, ) @classmethod @overrides def load(cls) -> Any: if persistent.was_file_written_within_n_seconds( - config.config['weather_data_cachefile'], - config.config['weather_data_stalest_acceptable'].total_seconds(), + config.config['weather_data_cachefile'], + config.config['weather_data_stalest_acceptable'].total_seconds(), ): import pickle + with open(config.config['weather_data_cachefile'], 'rb') as rf: weather_data = pickle.load(rf) return cls(weather_data) @@ -196,6 +193,7 @@ class CachedWeatherData(persistent.Persistent): @overrides def save(self) -> bool: import pickle + with open(config.config['weather_data_cachefile'], 'wb') as wf: pickle.dump( self.weather_data, diff --git a/cached/weather_forecast.py b/cached/weather_forecast.py index b343938..58f53c3 100644 --- a/cached/weather_forecast.py +++ b/cached/weather_forecast.py @@ -1,60 +1,59 @@ #!/usr/bin/env python3 -from dataclasses import dataclass import datetime import logging import os -from typing import Any import urllib.request +from dataclasses import dataclass +from typing import Any import astral # type: ignore +import pytz from astral.sun import sun # type: ignore from bs4 import BeautifulSoup # type: ignore from overrides import overrides -import pytz import argparse_utils import config -import datetime_utils import dateparse.dateparse_utils as dp +import datetime_utils import persistent -import text_utils import smart_home.thermometers as temps - +import text_utils logger = logging.getLogger(__name__) cfg = config.add_commandline_args( f'Cached Weather Forecast ({__file__})', - 'Arguments controlling detailed weather rendering' + 'Arguments controlling detailed weather rendering', ) cfg.add_argument( '--weather_forecast_cachefile', type=str, default=f'{os.environ["HOME"]}/cache/.weather_forecast_cache', metavar='FILENAME', - help='File in which to cache weather data' + help='File in which to cache weather data', ) cfg.add_argument( '--weather_forecast_stalest_acceptable', type=argparse_utils.valid_duration, - default=datetime.timedelta(seconds=7200), # 2 hours + default=datetime.timedelta(seconds=7200), # 2 hours metavar='DURATION', - help='Maximum acceptable age of cached data. If zero, forces a refetch' + help='Maximum acceptable age of cached data. If zero, forces a refetch', ) @dataclass class WeatherForecast: - date: datetime.date # The date - sunrise: datetime.datetime # Sunrise datetime - sunset: datetime.datetime # Sunset datetime - description: str # Textual description of weather + date: datetime.date # The date + sunrise: datetime.datetime # Sunrise datetime + sunset: datetime.datetime # Sunset datetime + description: str # Textual description of weather [email protected]_autoloaded_singleton() [email protected]_autoloaded_singleton() # type: ignore class CachedDetailedWeatherForecast(persistent.Persistent): - def __init__(self, forecasts = None): + def __init__(self, forecasts=None): if forecasts is not None: self.forecasts = forecasts return @@ -82,8 +81,7 @@ class CachedDetailedWeatherForecast(persistent.Persistent): last_dt = now dt = now for (day, txt) in zip( - forecast.find_all('b'), - forecast.find_all(class_='col-sm-10 forecast-text') + forecast.find_all('b'), forecast.find_all(class_='col-sm-10 forecast-text') ): last_dt = dt try: @@ -112,20 +110,21 @@ class CachedDetailedWeatherForecast(persistent.Persistent): self.forecasts[dt.date()].description += '\n' + blurb else: self.forecasts[dt.date()] = WeatherForecast( - date = dt, - sunrise = sunrise, - sunset = sunset, - description = blurb, + date=dt, + sunrise=sunrise, + sunset=sunset, + description=blurb, ) @classmethod @overrides def load(cls) -> Any: if persistent.was_file_written_within_n_seconds( - config.config['weather_forecast_cachefile'], - config.config['weather_forecast_stalest_acceptable'].total_seconds(), + config.config['weather_forecast_cachefile'], + config.config['weather_forecast_stalest_acceptable'].total_seconds(), ): import pickle + with open(config.config['weather_forecast_cachefile'], 'rb') as rf: weather_data = pickle.load(rf) return cls(weather_data) @@ -134,6 +133,7 @@ class CachedDetailedWeatherForecast(persistent.Persistent): @overrides def save(self) -> bool: import pickle + with open(config.config['weather_forecast_cachefile'], 'wb') as wf: pickle.dump( self.forecasts, |
