about summary refs log tree commit diff
path: root/weather.py
diff options
context:
space:
mode:
Diffstat (limited to 'weather.py')
-rwxr-xr-xweather.py70
1 files changed, 59 insertions, 11 deletions
diff --git a/weather.py b/weather.py
index 12ae7d6..638d14d 100755
--- a/weather.py
+++ b/weather.py
@@ -11,35 +11,83 @@ headers = {
     'accept': 'application/ld+json'
 }
 
+# SGR decorations / ANSI escape colors
+class term:
+    RESET = '\033[0m'
+    BOLD = '\033[1m'
+
 def handle_args():
     parser = ArgumentParser()
     parser.add_argument('lat', help='latitude')
     parser.add_argument('lon', help='longitude')
     return parser.parse_args()
 
-def print_alerts(zone): 
-    alerts = requests.get(base_url + f'/alerts/active/zone/{zone}',
-                          headers = headers).json()
-    print(alerts.get('title'))
-    print()
+def print_alerts(county, zone): 
+    # in some areas, alerts are not published for the zone but only for the county
+    # you can request both like this rather than making two requests
+    alerts = requests.get(base_url + f'/alerts/active?zone={county},{zone}',
+                          headers=headers).json()
+
+    # this title was cooler when we requested only one zone
+    # e.g. it would end with "for Holmes County (MSC051) MS"
+    # but now it's just "current watches, warnings, and advisories"
+    print(f'{term.BOLD}{alerts.get("title")}')
+    print(f'===================={term.RESET}')
     for alert in alerts.get('@graph'):
-        print(f'- {alert.get("headline")}')
+        print(f'{alert.get("headline")}')
         print(f'  Severity: {alert.get("severity")}')
-        print(f'  Expires: {alert.get("expires")}')
+        print(f'  Until: {alert.get("expires")}')
         print(f'{alert.get("description")}')
-        print()
+        # TODO description can be quite long
+        # short desc appears to be available as parameters.NWSheadline[0]
+        # and follow up with instruction when it exists
+        print('--------------------')
+
+        # many more cool fields available.
+        # verious datetimes: sent, effective, onset, expires, ends
+        # severity: Minor, Moderate, Severe, Extreme, Unknown
+        # certainty: Possible, Likely, Observed, Unknown
+        # urgency: Future, Expected, Immediate, Unknown
+        # messageType: Alert, Update
+                
+        # can construct the headline ourseves as f'{event} issued {sent} [until {end}] by {senderName}'
+
+def print_forecast(forecast_url):
+    # 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}')
+    for period in forecast.get('periods'):
+        # TODO parse isDaytime true/false to squish a day together
+        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")}')
 
 def main():
     args = handle_args()
 
     point = requests.get(base_url + f'/points/{args.lat},{args.lon}',
-                         headers = headers).json()
+                         headers=headers).json()
 
+    county = point.get('county').split('/')[-1]
     zone = point.get('forecastZone').split('/')[-1]
-    print_alerts(zone)
+    print_alerts(county, zone)
+
+    # TODO can hazardous weather outlook be gotten programatically?
 
     forecast_url = point.get('forecast')
-    # print_forecast(forecast_url)
+    print_forecast(forecast_url)
 
     # hourly_forecast_url = point.get('forecastHourly')