X-Git-Url: https://wannabe.guru.org/gitweb/?a=blobdiff_plain;f=weather_renderer.py;h=f10f1ceb7d132f0e92965e8368b60d404f63409b;hb=0113d4ae8b11e01b695cd15cdb2c317d887e0935;hp=e11703bd5cdc3980530ada67d0658226d43daa66;hpb=5e241dc47e497c547463cecc07946ea6882835a7;p=kiosk.git diff --git a/weather_renderer.py b/weather_renderer.py index e11703b..f10f1ce 100644 --- a/weather_renderer.py +++ b/weather_renderer.py @@ -1,27 +1,32 @@ +#!/usr/bin/env python3 + from datetime import datetime +import json +from typing import Dict, List +import urllib.request +import urllib.error +import urllib.parse + import file_writer import renderer -import json -import re -import secrets -import urllib.request, urllib.error, urllib.parse +import kiosk_secrets as secrets import random -class weather_renderer(renderer.debuggable_abstaining_renderer): +class weather_renderer(renderer.abstaining_renderer): """A renderer to fetch forecast from wunderground.""" - def __init__(self, name_to_timeout_dict, file_prefix): - super(weather_renderer, self).__init__(name_to_timeout_dict, False) + def __init__(self, name_to_timeout_dict: Dict[str, int], file_prefix: str) -> None: + super().__init__(name_to_timeout_dict) self.file_prefix = file_prefix - def debug_prefix(self): - return "weather(%s)" % (self.file_prefix) + def debug_prefix(self) -> str: + return f"weather({self.file_prefix})" - def periodic_render(self, key): + def periodic_render(self, key: str) -> bool: return self.fetch_weather() - def describe_time(self, index): + def describe_time(self, index: int) -> str: if index <= 1: return "overnight" elif index <= 3: @@ -31,7 +36,7 @@ class weather_renderer(renderer.debuggable_abstaining_renderer): else: return "evening" - def describe_wind(self, mph): + def describe_wind(self, mph: float) -> str: if mph <= 0.3: return "calm" elif mph <= 5.0: @@ -43,26 +48,27 @@ class weather_renderer(renderer.debuggable_abstaining_renderer): else: return "heavy" - def describe_magnitude(self, mm): - if mm < 2: + def describe_magnitude(self, mm: float) -> str: + if mm < 2.0: return "light" - elif mm < 10: + elif mm < 10.0: return "moderate" else: return "heavy" - def describe_precip(self, rain, snow): - if rain == 0 and snow == 0: + def describe_precip(self, rain: float, snow: float) -> str: + if rain == 0.0 and snow == 0.0: return "no precipitation" magnitude = rain + snow if rain > 0 and snow > 0: - return "a %s mix of rain and snow" % self.describe_magnitude(magnitude) + return f"a {self.describe_magnitude(magnitude)} mix of rain and snow" elif rain > 0: - return "%s rain" % self.describe_magnitude(magnitude) + return f"{self.describe_magnitude(magnitude)} rain" elif snow > 0: - return "%s snow" % self.describe_magnitude(magnitude) + return f"{self.describe_magnitude(magnitude)} snow" + return "rain" - def fix_caps(self, s): + def fix_caps(self, s: str) -> str: r = "" s = s.lower() for x in s.split("."): @@ -71,7 +77,9 @@ class weather_renderer(renderer.debuggable_abstaining_renderer): r = r.replace(". .", ".") return r - def pick_icon(self, conditions, rain, snow): + def pick_icon( + self, conditions: List[str], rain: List[float], snow: List[float] + ) -> str: # rain snow clouds sun # fog.gif # hazy.gif @@ -91,7 +99,7 @@ class weather_renderer(renderer.debuggable_abstaining_renderer): seen_snow = False cloud_count = 0 clear_count = 0 - total_snow = 0 + total_snow = 0.0 count = min(len(conditions), len(rain), len(snow)) for x in range(0, count): seen_rain = rain[x] > 0 @@ -127,7 +135,15 @@ class weather_renderer(renderer.debuggable_abstaining_renderer): return "partlysunny.gif" return "clear.gif" - def describe_weather(self, high, low, wind, conditions, rain, snow): + def describe_weather( + self, + high: float, + low: float, + wind: List[float], + conditions: List[str], + rain: List[float], + snow: List[float], + ) -> str: # High temp: 65 # Low temp: 44 # -onight------ -morning----- -afternoon-- -evening---- @@ -202,7 +218,7 @@ class weather_renderer(renderer.debuggable_abstaining_renderer): descr = self.fix_caps(descr) return descr - def fetch_weather(self): + def fetch_weather(self) -> bool: if self.file_prefix == "stevens": text_location = "Stevens Pass, WA" param = "lat=47.74&lon=-121.08" @@ -238,178 +254,178 @@ class weather_renderer(renderer.debuggable_abstaining_renderer): # "dt_txt":"2017-01-30 18:00:00" # }, # {"dt":1485810000,.... - f = file_writer.file_writer("weather-%s_3_10800.html" % self.file_prefix) - f.write( - """ -

Weather at %s:

+ with file_writer.file_writer("weather-%s_3_10800.html" % self.file_prefix) as f: + f.write( + f""" +

Weather at {text_location}:


- - """ - % text_location - ) - count = parsed_json["cnt"] - - ts = {} - highs = {} - lows = {} - wind = {} - conditions = {} - rain = {} - snow = {} - for x in range(0, count): - data = parsed_json["list"][x] - dt = data["dt_txt"] # 2019-10-07 18:00:00 - date = dt.split(" ")[0] - time = dt.split(" ")[1] - wind[date] = [] - conditions[date] = [] - highs[date] = -99999 - lows[date] = +99999 - rain[date] = [] - snow[date] = [] - ts[date] = 0 - - for x in range(0, count): - data = parsed_json["list"][x] - dt = data["dt_txt"] # 2019-10-07 18:00:00 - date = dt.split(" ")[0] - time = dt.split(" ")[1] - _ = data["dt"] - if _ > ts[date]: - ts[date] = _ - temp = data["main"]["temp"] - if highs[date] < temp: - highs[date] = temp - if temp < lows[date]: - lows[date] = temp - wind[date].append(data["wind"]["speed"]) - conditions[date].append(data["weather"][0]["main"]) - if "rain" in data and "3h" in data["rain"]: - rain[date].append(data["rain"]["3h"]) - else: - rain[date].append(0) - if "snow" in data and "3h" in data["snow"]: - snow[date].append(data["snow"]["3h"]) - else: - snow[date].append(0) - - # {u'clouds': {u'all': 0}, - # u'sys': {u'pod': u'd'}, - # u'dt_txt': u'2019-10-09 21:00:00', - # u'weather': [ - # {u'main': u'Clear', - # u'id': 800, - # u'icon': u'01d', - # u'description': u'clear sky'} - # ], - # u'dt': 1570654800, - # u'main': { - # u'temp_kf': 0, - # u'temp': 54.74, - # u'grnd_level': 1018.95, - # u'temp_max': 54.74, - # u'sea_level': 1026.46, - # u'humidity': 37, - # u'pressure': 1026.46, - # u'temp_min': 54.74 - # }, - # u'wind': {u'speed': 6.31, u'deg': 10.09}} - - # Next 5 half-days - # for x in xrange(0, 5): - # fcast = parsed_json['forecast']['txt_forecast']['forecastday'][x] - # text = fcast['fcttext'] - # text = re.subn(r' ([0-9]+)F', r' \1°F', text)[0] - # f.write('' % text) - # f.write('

%s

') - # f.close() - # return True - - # f.write("\n") - days_seen = {} - for date in sorted(highs.keys()): - today = datetime.fromtimestamp(ts[date]) - formatted_date = today.strftime("%a %e %b") - if formatted_date in days_seen: - continue - days_seen[formatted_date] = True - num_days = len(list(days_seen.keys())) - - days_seen = {} - for date in sorted(highs.keys()): - precip = 0.0 - for _ in rain[date]: - precip += _ - for _ in snow[date]: - precip += _ - - today = datetime.fromtimestamp(ts[date]) - formatted_date = today.strftime("%a %e %b") - if formatted_date in days_seen: - continue - days_seen[formatted_date] = True - f.write('\n' + % self.describe_weather( + highs[date], + lows[date], + wind[date], + conditions[date], + rain[date], + snow[date], + ) + ) + f.write("
\n' % (100 / num_days)) - f.write("\n") - - # Date - f.write( - " \n" +
" - + formatted_date - + "
+ """ ) + count = parsed_json["cnt"] + + ts = {} + highs = {} + lows = {} + wind: Dict[str, List[float]] = {} + conditions: Dict[str, List[str]] = {} + rain: Dict[str, List[float]] = {} + snow: Dict[str, List[float]] = {} + for x in range(0, count): + data = parsed_json["list"][x] + dt = data["dt_txt"] # 2019-10-07 18:00:00 + date = dt.split(" ")[0] + time = dt.split(" ")[1] + wind[date] = [] + conditions[date] = [] + highs[date] = -99999 + lows[date] = +99999 + rain[date] = [] + snow[date] = [] + ts[date] = 0 + + for x in range(0, count): + data = parsed_json["list"][x] + dt = data["dt_txt"] # 2019-10-07 18:00:00 + date = dt.split(" ")[0] + time = dt.split(" ")[1] + _ = data["dt"] + if _ > ts[date]: + ts[date] = _ + temp = data["main"]["temp"] + if highs[date] < temp: + highs[date] = temp + if temp < lows[date]: + lows[date] = temp + wind[date].append(data["wind"]["speed"]) + conditions[date].append(data["weather"][0]["main"]) + if "rain" in data and "3h" in data["rain"]: + rain[date].append(data["rain"]["3h"]) + else: + rain[date].append(0) + if "snow" in data and "3h" in data["snow"]: + snow[date].append(data["snow"]["3h"]) + else: + snow[date].append(0) + + # {u'clouds': {u'all': 0}, + # u'sys': {u'pod': u'd'}, + # u'dt_txt': u'2019-10-09 21:00:00', + # u'weather': [ + # {u'main': u'Clear', + # u'id': 800, + # u'icon': u'01d', + # u'description': u'clear sky'} + # ], + # u'dt': 1570654800, + # u'main': { + # u'temp_kf': 0, + # u'temp': 54.74, + # u'grnd_level': 1018.95, + # u'temp_max': 54.74, + # u'sea_level': 1026.46, + # u'humidity': 37, + # u'pressure': 1026.46, + # u'temp_min': 54.74 + # }, + # u'wind': {u'speed': 6.31, u'deg': 10.09}} + + # Next 5 half-days + # for x in xrange(0, 5): + # fcast = parsed_json['forecast']['txt_forecast']['forecastday'][x] + # text = fcast['fcttext'] + # text = re.subn(r' ([0-9]+)F', r' \1°F', text)[0] + # f.write('' % text) + # f.write('

%s

') + # f.close() + # return True + + # f.write("\n") + days_seen = {} + for date in sorted(highs.keys()): + today = datetime.fromtimestamp(ts[date]) + formatted_date = today.strftime("%a %e %b") + if formatted_date in days_seen: + continue + days_seen[formatted_date] = True + num_days = len(list(days_seen.keys())) + + days_seen = {} + for date in sorted(highs.keys()): + precip = 0.0 + for _ in rain[date]: + precip += _ + for _ in snow[date]: + precip += _ + + today = datetime.fromtimestamp(ts[date]) + formatted_date = today.strftime("%a %e %b") + if formatted_date in days_seen: + continue + days_seen[formatted_date] = True + f.write( + '\n") - f.write("
\n' % (100 / num_days) + ) + f.write("\n") - # Icon - f.write( - ' \n' - % self.pick_icon(conditions[date], rain[date], snow[date]) - ) + # Date + f.write( + " \n" + ) - # Low temp - color = "#000099" - if lows[date] <= 32.5: - color = "#009999" - f.write( - ' \n' - % (color, int(lows[date])) - ) + # Icon + f.write( + ' \n' + % self.pick_icon(conditions[date], rain[date], snow[date]) + ) - # Total precip - precip *= 0.0393701 - if precip > 0.025: + # Low temp + color = "#000099" + if lows[date] <= 32.5: + color = "#009999" f.write( - ' \n' - % precip + ' \n' + % (color, int(lows[date])) ) - else: - f.write(" \n") - # High temp - color = "#800000" - if highs[date] >= 80: - color = "#AA0000" - f.write( - ' \n' - % (color, int(highs[date])) - ) + # Total precip + precip *= 0.0393701 + if precip > 0.025: + f.write( + ' \n' + % precip + ) + else: + f.write(" \n") - # Text "description" - f.write( - '\n' - % self.describe_weather( - highs[date], - lows[date], - wind[date], - conditions[date], - rain[date], - snow[date], + # High temp + color = "#800000" + if highs[date] >= 80: + color = "#AA0000" + f.write( + ' \n' + % (color, int(highs[date])) ) - ) - f.write("
" + + formatted_date + + "
%d°F  
%3.1f"
%d°F     %d°F
%3.1f"
 
%s
  %d°F
\n
") + + # Text "description" + f.write( + '
%s
\n\n") + f.write("
") return True -# x = weather_renderer({"Stevens": 1000}, -# "stevens") +# x = weather_renderer({"Stevens": 1000}, "stevens") # x.periodic_render("Stevens")