about summary refs log tree commit diff
diff options
context:
space:
mode:
authorStarfall <us@starfall.systems>2022-12-12 14:27:43 -0600
committerStarfall <us@starfall.systems>2022-12-12 14:27:43 -0600
commitf7d69f5948f708388df81f76b62dcc11b857dea3 (patch)
treec07fb68d80e244bcdf1cbd0769d95db14587b64f
parent4e912789e44b68aeda7cd505ee63b5f7ca27e952 (diff)
add README.md
-rw-r--r--README.md44
-rw-r--r--fscache.py1
-rwxr-xr-xmeteor.py20
3 files changed, 44 insertions, 21 deletions
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..95e9bc3
--- /dev/null
+++ b/README.md
@@ -0,0 +1,44 @@
+meteor.py
+=========
+
+A simple script written in about 4 hours that gets the weather. wttr.in was giving somewhat inaccurate results and
+we found the [National Weather Service API](https://www.weather.gov/documentation/services-web-api) one day, so we
+figured that we ought as well spend a little bit of time and have some fun with it.
+
+Usage
+-----
+
+`meteor.py lat lon`
+
+`lat` and `lon` are the latitude & longitude of a particular point in the United States (e.g. 38.57 -121.48 is within Sacramento, California)
+
+TODO / Issues
+-------------
+
+- Geocoding would make this a little more usable. [NWS lists several potential services](https://weather-gov.github.io/api/general-faqs#geocoding)
+- Round decimals to 4 places ourselves to avoid errors
+- Cache responses appropriately (the API uses HTTP caching headers correctly, TBA if we want to drop in requests-cache or do it ourselves)
+- Use the /gridpoints/gridId/gridX,gridY endpoint to generate our own forecast with things like probabilityOfPrecipitation
+- Fancy output like wttr.in
+- Display the names of the zones (requires extra API calls - cacheable for a long duration, though)
+- Shorter alert descriptions (`parameters.NWSheadline[0]` instead of `description`)
+- Work around known issues in the NWS API:
+    - retry when gridpoints 500s
+    - reduce gridX and gridY by 1 for AFC (AER/ALU), AFG, AJK, BOX, CAE, DLH, FSD, HGX, HNX, LIX, LWX, MAF, MFR, MLB, MRX, MTR, PIH offices/gridIds
+- Gracefully handle cache keys that include '/'
+
+Reference
+---------
+
+- [National Weather Service API Documentation](https://www.weather.gov/documentation/services-web-api)
+- [NWS OpenAPI](https://api.weather.gov/openapi.json)
+
+License
+-------
+
+(c) 2022 Starfall. All rights reserved.
+
+- "It shall be permissible to make quotations from a work ... provided that their making is
+  compatible with fair practice." - Berne Convention
+- Information wants to be free.
+- Be gay, do crimes.
diff --git a/fscache.py b/fscache.py
index d52ff62..b6d164b 100644
--- a/fscache.py
+++ b/fscache.py
@@ -15,7 +15,6 @@ class Cache:
         self.cache_dir.mkdir(exist_ok=True)
 
     def write(self, key, value):
-        # TODO gracefully handle keys with '/' by creating directories or rewriting
         loc = self.cache_dir/key
         loc.write_text(value, errors='ignore')
 
diff --git a/meteor.py b/meteor.py
index 4e41a64..8b7ab2c 100755
--- a/meteor.py
+++ b/meteor.py
@@ -3,9 +3,6 @@ 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
-
 base_url = 'https://api.weather.gov'
 headers = {
     'user-agent': 'meteor.py/0.2 (us@starfall.systems)',
@@ -29,9 +26,6 @@ def print_alerts(county, zone):
     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'):
@@ -39,9 +33,6 @@ def print_alerts(county, zone):
         print(f'  {alert.get("severity")} - {alert.get("certainty")} - {alert.get("urgency")}')
         print(f'  Until: {alert.get("expires")}')
         print(f'{alert.get("description")}')
-        # 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.
@@ -55,8 +46,6 @@ def print_alerts(county, zone):
     print()
 
 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
-
     cache_key = f'{point.get("gridId")}-{point.get("gridX")},{point.get("gridY")}'
 
     try: 
@@ -64,14 +53,6 @@ def print_forecast(point):
     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
 
         buffer = f'{term.BOLD}forecast for {point.get("relativeLocation").get("city")}, {point.get("relativeLocation").get("state")} ({cache_key})'
         buffer += '\n' + f'===================={term.RESET}'
@@ -83,7 +64,6 @@ def print_forecast(point):
             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)