weather: start rewriting weather plugin to use wttr.in
This commit is contained in:
parent
802072caed
commit
31758b80b6
@ -2,7 +2,7 @@ import logging
|
||||
|
||||
from ircbot.lib import Plugin
|
||||
|
||||
from weather.lib import get_conditions_for_query, get_forecast_for_query
|
||||
from weather.lib import weather_summary
|
||||
|
||||
|
||||
log = logging.getLogger('weather.ircplugin')
|
||||
@ -28,27 +28,12 @@ class Weather(Plugin):
|
||||
super(Weather, self).stop()
|
||||
|
||||
def handle_weather(self, connection, event, match):
|
||||
"""Handle IRC input for a weather queries."""
|
||||
|
||||
# see if there was a specific command given in the query, first
|
||||
query = match.group(1)
|
||||
queryitems = query.split(" ")
|
||||
if len(queryitems) <= 0:
|
||||
return
|
||||
|
||||
# search for commands
|
||||
if queryitems[0] == 'conditions':
|
||||
# current weather query
|
||||
results = get_conditions_for_query(queryitems[1:])
|
||||
return self.bot.reply(event, results)
|
||||
elif queryitems[0] == 'forecast':
|
||||
# forecast query
|
||||
results = get_forecast_for_query(queryitems[1:])
|
||||
return self.bot.reply(event, results)
|
||||
else:
|
||||
# assume they wanted current weather
|
||||
results = get_conditions_for_query(queryitems)
|
||||
return self.bot.reply(event, results)
|
||||
return self.bot.reply(event, weather_summary(queryitems[0]))
|
||||
|
||||
|
||||
plugin = Weather
|
||||
|
224
weather/lib.py
224
weather/lib.py
@ -1,196 +1,50 @@
|
||||
# coding: utf-8
|
||||
|
||||
"""Get results of weather queries."""
|
||||
import logging
|
||||
import re
|
||||
import requests
|
||||
|
||||
from django.conf import settings
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
wu_base_url = 'http://api.wunderground.com/api/{0:s}/'.format(settings.WEATHER_WEATHER_UNDERGROUND_API_KEY)
|
||||
log = logging.getLogger('weather.lib')
|
||||
def query_wttr_in(query):
|
||||
"""Hit the wttr.in JSON API with the provided query."""
|
||||
logger.info(f"about to query wttr.in with '{query}")
|
||||
response = requests.get('http://wttr.in/{query}?format=j1')
|
||||
response.raise_for_status()
|
||||
|
||||
weather_info = response.json()
|
||||
logger.debug(f"results: {weather_info}")
|
||||
return weather_info
|
||||
|
||||
|
||||
def get_conditions_for_query(queryitems):
|
||||
"""Make a wunderground conditions call, return as string."""
|
||||
def weather_summary(query):
|
||||
"""Create a more consumable version of the weather report."""
|
||||
weather_info = query_wttr_in(query)
|
||||
|
||||
# recombine the query into a string
|
||||
query = ' '.join(queryitems)
|
||||
query = query.replace(' ', '_')
|
||||
# get some common/nested stuff once now
|
||||
current = weather_info['current_condition'][0]
|
||||
weather_desc = current['weatherDesc'][0] if 'weatherDesc' in current else {}
|
||||
today_forecast = weather_info['weather'][0]
|
||||
tomorrow_forecast = weather_info['weather'][1]
|
||||
day_after_tomorrow_forecast = weather_info['weather'][2]
|
||||
|
||||
try:
|
||||
url = wu_base_url + ('{0:s}/q/{1:s}.json'.format('conditions', query))
|
||||
log.debug("calling %s", url)
|
||||
resp = requests.get(url)
|
||||
condition_data = resp.json()
|
||||
except IOError as e:
|
||||
log.error("error while making conditions query")
|
||||
log.exception(e)
|
||||
raise
|
||||
summary = {
|
||||
'location': query,
|
||||
'current': {
|
||||
'description': weather_desc.get('value'),
|
||||
'temp_C': f"{current.get('temp_C')}°C",
|
||||
'temp_F': f"{current.get('temp_F')}°F",
|
||||
'feels_like_temp_C': f"{current.get('FeelsLikeC')}°C",
|
||||
'feels_like_temp_F': f"{current.get('FeelsLikeF')}°F",
|
||||
'cloud_cover': f"{current.get('cloudcover')}%",
|
||||
'humidity': f"{current.get('humidity')}%",
|
||||
'precipitation': f"{current.get('precipMM')} mm",
|
||||
'visibility': f"{current.get('visibility')} mi",
|
||||
'wind_speed': f"{current.get('windspeedMiles')} MPH",
|
||||
'wind_direction': f"{current.get('winddir16Point')}",
|
||||
'pressure': f"{current.get('pressure')} mb",
|
||||
'uv_index': f"{current.get('uvIndex')}",
|
||||
},
|
||||
}
|
||||
|
||||
# condition data is loaded. the rest of this is obviously specific to
|
||||
# http://www.wunderground.com/weather/api/d/docs?d=data/conditions
|
||||
log.debug(condition_data)
|
||||
|
||||
try:
|
||||
# just see if we have current_observation data
|
||||
current = condition_data['current_observation']
|
||||
except KeyError as e:
|
||||
# ok, try to see if the ambiguous results stuff will help
|
||||
log.debug(e)
|
||||
log.debug("potentially ambiguous results, checking")
|
||||
try:
|
||||
results = condition_data['response']['results']
|
||||
reply = "Multiple results, try one of the following zmw codes:"
|
||||
for res in results[:-1]:
|
||||
q = res['l'].strip('/q/')
|
||||
reply += " {0:s} ({1:s}, {2:s}),".format(q, res['name'], res['country_name'])
|
||||
q = results[-1]['l'].strip('/q/')
|
||||
reply += " or {0:s} ({1:s}, {2:s}).".format(q, results[-1]['name'], results[-1]['country_name'])
|
||||
return reply
|
||||
except KeyError as e:
|
||||
# now we really know something is wrong
|
||||
log.error("error or bad query in conditions lookup")
|
||||
log.exception(e)
|
||||
return "No results."
|
||||
else:
|
||||
try:
|
||||
location = current['display_location']['full']
|
||||
reply = "Conditions for {0:s}: ".format(location)
|
||||
|
||||
weather_str = current['weather']
|
||||
if weather_str != '':
|
||||
reply += "{0:s}, ".format(weather_str)
|
||||
|
||||
temp_f = current['temp_f']
|
||||
temp_c = current['temp_c']
|
||||
temp_str = current['temperature_string']
|
||||
if temp_f != '' and temp_c != '':
|
||||
reply += "{0:.1f}°F ({1:.1f}°C)".format(temp_f, temp_c)
|
||||
elif temp_str != '':
|
||||
reply += "{0:s}".format(temp_str)
|
||||
|
||||
# append feels like if we have it
|
||||
feelslike_f = current['feelslike_f']
|
||||
feelslike_c = current['feelslike_c']
|
||||
feelslike_str = current['feelslike_string']
|
||||
if feelslike_f != '' and feelslike_c != '':
|
||||
reply += ", feels like {0:s}°F ({1:s}°C)".format(feelslike_f, feelslike_c)
|
||||
elif feelslike_str != '':
|
||||
reply += ", feels like {0:s}".format(feelslike_str)
|
||||
|
||||
# whether this is current or current + feelslike, terminate sentence
|
||||
reply += ". "
|
||||
|
||||
humidity_str = current['relative_humidity']
|
||||
if humidity_str != '':
|
||||
reply += "Humidity: {0:s}. ".format(humidity_str)
|
||||
|
||||
wind_str = current['wind_string']
|
||||
if wind_str != '':
|
||||
reply += "Wind: {0:s}. ".format(wind_str)
|
||||
|
||||
pressure_in = current['pressure_in']
|
||||
pressure_trend = current['pressure_trend']
|
||||
if pressure_in != '':
|
||||
reply += "Pressure: {0:s}\"".format(pressure_in)
|
||||
if pressure_trend != '':
|
||||
reply += " and {0:s}".format("dropping" if pressure_trend == '-' else "rising")
|
||||
reply += ". "
|
||||
|
||||
heat_index_str = current['heat_index_string']
|
||||
if heat_index_str != '' and heat_index_str != 'NA':
|
||||
reply += "Heat index: {0:s}. ".format(heat_index_str)
|
||||
|
||||
windchill_str = current['windchill_string']
|
||||
if windchill_str != '' and windchill_str != 'NA':
|
||||
reply += "Wind chill: {0:s}. ".format(windchill_str)
|
||||
|
||||
visibility_mi = current['visibility_mi']
|
||||
if visibility_mi != '':
|
||||
reply += "Visibility: {0:s} miles. ".format(visibility_mi)
|
||||
|
||||
precip_in = current['precip_today_in']
|
||||
if precip_in != '':
|
||||
reply += "Precipitation today: {0:s}\". ".format(precip_in)
|
||||
|
||||
observation_time = current['observation_time']
|
||||
if observation_time != '':
|
||||
reply += "{0:s}. ".format(observation_time)
|
||||
|
||||
return _prettify_weather_strings(reply.rstrip())
|
||||
except KeyError as e:
|
||||
log.error("error or unexpected results in conditions reply")
|
||||
log.exception(e)
|
||||
return "Error parsing results."
|
||||
|
||||
|
||||
def get_forecast_for_query(queryitems):
|
||||
"""Make a wunderground forecast call, return as string."""
|
||||
|
||||
# recombine the query into a string
|
||||
query = ' '.join(queryitems)
|
||||
query = query.replace(' ', '_')
|
||||
|
||||
try:
|
||||
url = wu_base_url + ('{0:s}/q/{1:s}.json'.format('forecast', query))
|
||||
resp = requests.get(url)
|
||||
forecast_data = resp.json()
|
||||
except IOError as e:
|
||||
log.error("error while making forecast query")
|
||||
log.exception(e)
|
||||
raise
|
||||
|
||||
# forecast data is loaded. the rest of this is obviously specific to
|
||||
# http://www.wunderground.com/weather/api/d/docs?d=data/forecast
|
||||
log.debug(forecast_data)
|
||||
|
||||
try:
|
||||
# just see if we have forecast data
|
||||
forecasts = forecast_data['forecast']['txt_forecast']
|
||||
except KeyError as e:
|
||||
# ok, try to see if the ambiguous results stuff will help
|
||||
log.debug(e)
|
||||
log.debug("potentially ambiguous results, checking")
|
||||
try:
|
||||
results = forecast_data['response']['results']
|
||||
reply = "Multiple results, try one of the following zmw codes:"
|
||||
for res in results[:-1]:
|
||||
q = res['l'].strip('/q/')
|
||||
reply += " {0:s} ({1:s}, {2:s}),".format(q, res['name'],
|
||||
res['country_name'])
|
||||
q = results[-1]['l'].strip('/q/')
|
||||
reply += " or {0:s} ({1:s}, {2:s}).".format(q, results[-1]['name'],
|
||||
results[-1]['country_name'])
|
||||
return reply
|
||||
except KeyError as e:
|
||||
# now we really know something is wrong
|
||||
log.error("error or bad query in forecast lookup")
|
||||
log.exception(e)
|
||||
return "No results."
|
||||
else:
|
||||
try:
|
||||
reply = "Forecast: "
|
||||
for forecast in forecasts['forecastday'][0:5]:
|
||||
reply += "{0:s}: {1:s} ".format(forecast['title'],
|
||||
forecast['fcttext'])
|
||||
|
||||
return _prettify_weather_strings(reply.rstrip())
|
||||
except KeyError as e:
|
||||
log.error("error or unexpected results in forecast reply")
|
||||
log.exception(e)
|
||||
return "Error parsing results."
|
||||
|
||||
|
||||
def _prettify_weather_strings(weather_str):
|
||||
"""
|
||||
Clean up output strings.
|
||||
|
||||
For example, turn 32F into 32°F in input string.
|
||||
|
||||
Input:
|
||||
weather_str --- the string to clean up
|
||||
|
||||
"""
|
||||
|
||||
return re.sub(r'(\d+)\s*([FC])', r'\1°\2', weather_str)
|
||||
return summary
|
||||
|
Loading…
Reference in New Issue
Block a user