dr.botzo/dr_botzo/weather/lib.py

200 lines
7.4 KiB
Python
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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)