about summary refs log tree commit diff
path: root/meteor.py
diff options
context:
space:
mode:
authorStarfall <us@starfall.systems>2022-12-01 13:52:42 -0600
committerStarfall <us@starfall.systems>2022-12-01 13:52:42 -0600
commit1416ec325ac9a35aaa50cd1e7a77cd6112a8e5e0 (patch)
tree4d090c6f6fb9cbc0a9d1fe0fbd4720b86b4b6b9d /meteor.py
parentd528ba125fae31e3caa76471136fa0a821867884 (diff)
cache forecasts on filesystem
Diffstat (limited to 'meteor.py')
-rwxr-xr-xmeteor.py73
1 files changed, 40 insertions, 33 deletions
diff --git a/meteor.py b/meteor.py
index f19a834..fb3179c 100755
--- a/meteor.py
+++ b/meteor.py
@@ -1,6 +1,7 @@
 #!/usr/bin/env python3
 from argparse import ArgumentParser
 import requests
+import fscache as fs
 
 # doco is at https://www.weather.gov/documentation/services-web-api
 # openAPI spec is at https://api.weather.gov/openapi.json
@@ -53,35 +54,49 @@ def print_alerts(county, zone):
         # can construct the headline ourseves as f'{event} issued {sent} [until {end}] by {senderName}'
     print()
 
-def print_forecast(forecast_url):
+def print_forecast(point):
     # TODO pick up gridId AFC (AER/ALU), AFG, AJK, BOX< CAE, DLH, FSD, HGX, HNX, LIX, LWX, MAF, MFR, MLB, MRX, MTR, PIH and reduce gridX and gridY by 1 - known issue
 
-    forecast = requests.get(forecast_url, headers=headers).json()
-    # TODO retry on 500 - known issue
-    # TODO query param units=si
-    # TODO cache for like four hours per location, forecast doesn't change that frequently
-
-    # TODO replace the whole thing with /gridpoints/{point.gridId}/{gridX},{gridY} and create our own forecast
-    # there is lots more information there that would be useful
-    # probabilityOfPrecipitation is the neatest one that's not in .../forecast or .../forecast/hourly
-    # but there's also relativeHumidity, apparentTemperature (and, separately, windChill), skyCover, windGust
-    # downside, it appears to always convert the F/mph measurements into C/kph for no reason. e.g. all temps are measured in 9ths of C
-
-    print(f'{term.BOLD}forecast')
-    print(f'===================={term.RESET}')
-    periods = forecast.get('periods')
-    # print today and tonight in long format
-    for period in periods[:2]:
-        print(f'{term.BOLD}{period.get("name")}{term.RESET}:')
-        print(f'  {period.get("temperature")}°{period.get("temperatureUnit")}, wind {period.get("windSpeed")} {period.get("windDirection")}')
-        print(f'  {period.get("detailedForecast")}')
-    # print further forecasted periods in short format
-    for period in periods[2:]:
-        # TODO parse isDaytime true/false to squish a day together
-        print(f'{term.BOLD}{period.get("name").ljust(15)}{term.RESET}: {period.get("shortForecast")} - {period.get("temperature")}°{period.get("temperatureUnit")}, {period.get("windSpeed")} {period.get("windDirection")}')
+    cache_key = f'{point.get("gridId")}-{point.get("gridX")}-{point.get("gridY")}'
+
+    try: 
+        print(cache.read(cache_key))
+    except fs.CacheMiss:
+        forecast_url = point.get('forecast')
+        forecast = requests.get(forecast_url, headers=headers).json()
+        # TODO retry on 500 - known issue
+        # TODO query param units=si
+
+        # TODO replace the whole thing with /gridpoints/{point.gridId}/{gridX},{gridY} and create our own forecast
+        # there is lots more information there that would be useful
+        # probabilityOfPrecipitation is the neatest one that's not in .../forecast or .../forecast/hourly
+        # but there's also relativeHumidity, apparentTemperature (and, separately, windChill), skyCover, windGust
+        # downside, it appears to always convert the F/mph measurements into C/kph for no reason. e.g. all temps are measured in 9ths of C
+    
+        # TODO pick out location name from somewhere.
+        # city and state hide in point.relativeLocation.properties.city (and state)
+        # getting the county or zone's `name (id) state` is good too
+
+        buffer = f'{term.BOLD}forecast'
+        buffer += '\n' + f'===================={term.RESET}'
+        periods = forecast.get('periods')
+        # print today and tonight in long format
+        for period in periods[:2]:
+            buffer += '\n' + f'{term.BOLD}{period.get("name")}{term.RESET}:'
+            buffer += '\n' + f'  {period.get("temperature")}°{period.get("temperatureUnit")}, wind {period.get("windSpeed")} {period.get("windDirection")}'
+            buffer += '\n' + f'  {period.get("detailedForecast")}'
+        # print further forecasted periods in short format
+        for period in periods[2:]:
+            # TODO parse isDaytime true/false to squish a day together
+            buffer += '\n' + f'{term.BOLD}{period.get("name").ljust(15)}{term.RESET}: {period.get("shortForecast")} - {period.get("temperature")}°{period.get("temperatureUnit")}, {period.get("windSpeed")} {period.get("windDirection")}'
+
+        cache.write(cache_key, buffer)
+        print(buffer)
 
 def main():
     args = handle_args()
+    global cache
+    cache = fs.Cache('meteor.py')
 
     point = requests.get(base_url + f'/points/{args.lat},{args.lon}',
                          headers=headers).json()
@@ -90,17 +105,9 @@ def main():
     zone = point.get('forecastZone').split('/')[-1]
     print_alerts(county, zone)
 
-    # TODO pick out location name from somewhere.
-    # city and state hide in point.relativeLocation.properties.city (and state)
-    # getting the county or zone's `name (id) state` is good too
-
     # TODO can hazardous weather outlook be gotten programatically?
 
-
-    forecast_url = point.get('forecast')
-    print_forecast(forecast_url)
-
-    # hourly_forecast_url = point.get('forecastHourly')
+    print_forecast(point)
 
 if __name__ == '__main__':
     import sys