weather: port weather to new style bot

This commit is contained in:
Brian S. Stephan 2015-05-15 21:22:14 -05:00
parent 80eca4781c
commit 41a7628c63
5 changed files with 263 additions and 0 deletions

View File

@ -127,6 +127,13 @@ IRCBOT_SSL = False
IRCBOT_IPV6 = False
# IRC module stuff
# weather
WEATHER_WEATHER_UNDERGROUND_API_KEY = None
# load local settings
try:

View File

View File

@ -0,0 +1,57 @@
import logging
from ircbot.lib import Plugin
from weather.lib import get_conditions_for_query, get_forecast_for_query
log = logging.getLogger('weather.ircplugin')
class Weather(Plugin):
"""Have IRC commands to do IRC things (join channels, quit, etc.)."""
def start(self):
"""Set up the handlers."""
self.connection.reactor.add_global_regex_handler('pubmsg', r'^!weather\s+(.*)$',
getattr(self, 'handle_weather'), -20)
self.connection.reactor.add_global_regex_handler('privmsg', r'^^!weather\s+(.*)$',
getattr(self, 'handle_weather'), -20)
super(Weather, self).start()
def stop(self):
"""Tear down handlers."""
self.connection.reactor.remove_global_regex_handler('pubmsg', getattr(self, 'handle_weather'))
self.connection.reactor.remove_global_regex_handler('privmsg', getattr(self, 'handle_weather'))
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)
plugin = Weather

199
dr_botzo/weather/lib.py Normal file
View File

@ -0,0 +1,199 @@
# coding: utf-8
from __future__ import unicode_literals
import json
import logging
import re
import urllib2
from django.conf import settings
wu_base_url = 'http://api.wunderground.com/api/{0:s}/'.format(settings.WEATHER_WEATHER_UNDERGROUND_API_KEY)
log = logging.getLogger('weather.lib')
def get_conditions_for_query(queryitems):
"""Make a wunderground conditions 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('conditions', query))
log.debug(u"calling %s", url)
json_resp = urllib2.urlopen(url)
condition_data = json.load(json_resp)
except IOError as e:
log.error("error while making conditions query")
log.exception(e)
raise
# 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(json.dumps(condition_data, sort_keys=True, indent=4))
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))
json_resp = urllib2.urlopen(url)
forecast_data = json.load(json_resp)
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(json.dumps(forecast_data, sort_keys=True, indent=4))
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'\\2', weather_str)

View File