3 from dataclasses import dataclass
7 from typing import List
16 cfg = config.add_commandline_args(
17 f'Cached Weather Data List ({__file__})',
18 'Arguments controlling cached weather data',
21 '--weather_data_cachefile',
23 default=f'{os.environ["HOME"]}/.weather_summary_cache',
25 help='File in which to cache weather data'
28 '--weather_data_stalest_acceptable',
29 type=argparse_utils.valid_duration,
30 default=datetime.timedelta(seconds=7200), # 2 hours
32 help='Maximum acceptable age of cached data. If zero, forces a refetch'
38 date: datetime.date # The date
39 high: float # The predicted high in F
40 low: float # The predicted low in F
41 conditions: List[str] # Conditions per ~3h window
42 most_common_condition: str # The most common condition
43 icon: str # An icon to represent it
46 @persistent.persistent_autoloaded_singleton()
47 class CachedWeatherData(persistent.Persistent):
50 if weather_data is not None:
51 self.weather_data = weather_data
53 self.weather_data = {}
71 now = datetime.datetime.now()
76 param = "id=5786882" # Bellevue, WA
77 key = "c0b160c49743622f62a9cd3cda0270b3"
78 www = urllib.request.urlopen(
79 f'http://api.openweathermap.org/data/2.5/weather?zip=98005,us&APPID={key}&units=imperial'
83 parsed_json = json.loads(response)
84 dt = datetime.datetime.fromtimestamp(parsed_json["dt"]).date()
86 condition = parsed_json["weather"][0]["main"]
87 icon = icon_by_condition.get(condition, '?')
88 if dt == now.date() and now.hour > 18 and condition == 'Clear':
90 self.weather_data[dt] = WeatherData(
92 high = float(parsed_json["main"]["temp_max"]),
93 low = float(parsed_json["main"]["temp_min"]),
94 conditions = [condition],
95 most_common_condition = condition,
99 www = urllib.request.urlopen(
100 f"http://api.openweathermap.org/data/2.5/forecast?{param}&APPID={key}&units=imperial"
102 response = www.read()
104 parsed_json = json.loads(response)
105 count = parsed_json["cnt"]
106 for x in range(count):
107 data = parsed_json["list"][x]
108 dt = datetime.datetime.strptime(data['dt_txt'], '%Y-%m-%d %H:%M:%S')
115 temp = data["main"]["temp"]
116 if highs[dt] is None or temp > highs[dt]:
118 if lows[dt] is None or temp < lows[dt]:
120 cond = data["weather"][0]["main"]
121 conditions[dt].append(cond)
123 today = datetime_utils.now_pacific().date()
124 for dt in sorted(dates):
126 high = highs.get(dt, None)
129 self.weather_data[today].high < high
131 self.weather_data[today].high = high
133 most_common_condition = list_utils.most_common_item(conditions[dt])
134 icon = icon_by_condition.get(most_common_condition, '?')
135 if dt == now.date() and now.hour > 18 and condition == 'Clear':
137 self.weather_data[dt] = WeatherData(
141 conditions = conditions[dt],
142 most_common_condition = most_common_condition,
148 if persistent.was_file_written_within_n_seconds(
149 config.config['weather_data_cachefile'],
150 config.config['weather_data_stalest_acceptable'].total_seconds(),
153 with open(config.config['weather_data_cachefile'], 'rb') as rf:
154 weather_data = pickle.load(rf)
155 return cls(weather_data)
160 with open(config.config['weather_data_cachefile'], 'wb') as wf:
164 pickle.HIGHEST_PROTOCOL,