diff options
author | Starfall <us@starfall.systems> | 2022-12-01 13:52:42 -0600 |
---|---|---|
committer | Starfall <us@starfall.systems> | 2022-12-01 13:52:42 -0600 |
commit | 1416ec325ac9a35aaa50cd1e7a77cd6112a8e5e0 (patch) | |
tree | 4d090c6f6fb9cbc0a9d1fe0fbd4720b86b4b6b9d /meteor.py | |
parent | d528ba125fae31e3caa76471136fa0a821867884 (diff) |
cache forecasts on filesystem
Diffstat (limited to 'meteor.py')
-rwxr-xr-x | meteor.py | 73 |
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 |