-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Display noteworthy weather conditions as a third line in event summar…
…ies. This is very quick and dirty. Right now we display the temperature if it is outside of the range 65‒85℉ / 18‒29℃, and any free-form forecast text that contains the words "rain" or "snow". A followup will extend this to include warnings and alerts (like "Winter Storm Warning: Heavy Mixed precipitation, Mixed Precipitation"). This should probably be displayed in groups in general, though, rather than just as additional weather exceptions (both because the information is more pressing and because alerts aren't really forecasted). See #80.
- Loading branch information
Showing
4 changed files
with
128 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
"""Quick utilities for geocoding an address and looking up its weather forecast.""" | ||
|
||
import logging | ||
import time | ||
import urllib.parse | ||
|
||
import googlemaps | ||
import requests | ||
|
||
from metabot.util import iso8601 | ||
from metabot.util import pickleutil | ||
|
||
try: | ||
_CLIENT_KEY = next(open('config/google_maps_apikey')).strip() | ||
except IOError: | ||
_CLIENT = None | ||
else: | ||
_CLIENT = googlemaps.Client(key=_CLIENT_KEY) | ||
_CACHEFILE = 'config/geoutil.pickle' | ||
_CACHE = pickleutil.load(_CACHEFILE) or {} | ||
_SHORTCACHE = {} | ||
|
||
|
||
def _save(): | ||
pickleutil.dump(_CACHEFILE, _CACHE) | ||
|
||
|
||
def geocode(address): | ||
"""Look up the given address in Google Maps.""" | ||
|
||
if 'geocode' not in _CACHE: | ||
_CACHE['geocode'] = {} | ||
if address not in _CACHE['geocode']: | ||
_CACHE['geocode'][address] = _CLIENT.geocode(address) | ||
_save() | ||
return _CACHE['geocode'][address] | ||
|
||
|
||
def _weatherfetch(url): | ||
url = urllib.parse.urljoin('https://api.weather.gov/', url) | ||
headers = { | ||
'user-agent': 'https://github.com/nmlorg/metabot', | ||
} | ||
logging.info('Fetching %r.', url) | ||
return requests.get(url, headers=headers).json() | ||
|
||
|
||
def weatherpoint(lat, lon): | ||
"""Map a latitude/longitude to a weather.gov gridpoint.""" | ||
|
||
# https://weather-gov.github.io/api/general-faqs#how-do-i-get-a-forecast-for-a-location-from-the-api | ||
lat = ('%.4f' % lat).rstrip('0') | ||
lon = ('%.4f' % lon).rstrip('0') | ||
key = '%s,%s' % (lat, lon) | ||
|
||
if 'weatherpoint' not in _CACHE: | ||
_CACHE['weatherpoint'] = {} | ||
if key not in _CACHE['weatherpoint']: | ||
_CACHE['weatherpoint'][key] = _weatherfetch('points/' + key) | ||
_save() | ||
return _CACHE['weatherpoint'][key] | ||
|
||
|
||
def hourlyforecast(lat, lon): | ||
"""Retrieve the hourly forecast for the given latitude/longitude.""" | ||
|
||
point = weatherpoint(lat, lon) | ||
if not point.get('properties'): | ||
return () | ||
now = time.time() | ||
url = point['properties']['forecastHourly'] | ||
last, ret = _SHORTCACHE.get(url) or (0, None) | ||
if last < now - 10 * 60: | ||
ret = _weatherfetch(url)['properties']['periods'] | ||
_SHORTCACHE[url] = (now, ret) | ||
return ret | ||
|
||
|
||
def lookup(address, now=None): | ||
"""Retrieve the forecasted weather conditions for the given address as of the given time.""" | ||
|
||
if _CLIENT is None: | ||
return | ||
if now is None: | ||
now = time.time() | ||
ret = {} | ||
geo = geocode(address) | ||
if not geo: | ||
return | ||
ret['lat'] = geo[0]['geometry']['location']['lat'] | ||
ret['lon'] = geo[0]['geometry']['location']['lng'] | ||
for period in hourlyforecast(ret['lat'], ret['lon']): | ||
start = iso8601.totimestamp(period['startTime']) | ||
end = iso8601.totimestamp(period['endTime']) | ||
if start <= now < end: | ||
ret['forecast'] = period | ||
break | ||
return ret |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,7 +3,7 @@ | |
|
||
setuptools.setup( | ||
name='metabot', | ||
version='0.3.16.4', | ||
version='0.3.17', | ||
author='Daniel Reed', | ||
author_email='[email protected]', | ||
description='Modularized, multi-account bot.', | ||
|
@@ -14,6 +14,7 @@ | |
package_data={'': ['*.html']}, | ||
python_requires='>=3.5', | ||
install_requires=[ | ||
'googlemaps', | ||
'ntelebot >= 0.3.4', | ||
'pytz', | ||
'PyYAML >= 5.1', | ||
|