sopel/modules/weather.py

182 lines
6.0 KiB
Python
Raw Normal View History

2017-11-22 19:26:40 -05:00
# coding=utf-8
# Copyright 2008, Sean B. Palmer, inamidst.com
# Copyright 2012, Elsie Powell, embolalia.com
# Licensed under the Eiffel Forum License 2.
from __future__ import unicode_literals, absolute_import, print_function, division
from module import commands, example, NOLIMIT
import xmltodict, requests
def woeid_search(query):
"""
Find the first Where On Earth ID for the given query. Result is the etree
node for the result, so that location data can still be retrieved. Returns
None if there is no result, or the woeid field is empty.
"""
query = 'q=select * from geo.places where text="%s"' % query
body = requests.get('http://query.yahooapis.com/v1/public/yql?' + query).content
parsed = xmltodict.parse(body).get('query')
results = parsed.get('results')
if results is None or results.get('place') is None:
return None
if type(results.get('place')) is list:
return results.get('place')[0]
return results.get('place')
def get_cover(parsed):
try:
condition = parsed['channel']['item']['yweather:condition']
except KeyError:
return 'unknown'
text = condition['@text']
# code = int(condition['code'])
# TODO parse code to get those little icon thingies.
return text
def get_temp(parsed):
try:
condition = parsed['channel']['item']['yweather:condition']
temp = int(condition['@temp'])
except (KeyError, ValueError):
return 'unknown'
f = round((temp * 1.8) + 32, 2)
return (u'%d\u00B0C (%d\u00B0F)' % (temp, f))
def get_humidity(parsed):
try:
humidity = parsed['channel']['yweather:atmosphere']['@humidity']
except (KeyError, ValueError):
return 'unknown'
return "Humidity: %s%%" % humidity
def get_wind(parsed):
try:
wind_data = parsed['channel']['yweather:wind']
kph = float(wind_data['@speed'])
m_s = float(round(kph / 3.6, 1))
speed = int(round(kph / 1.852, 0))
degrees = int(wind_data['@direction'])
except (KeyError, ValueError):
return 'unknown'
if speed < 1:
description = 'Calm'
elif speed < 4:
description = 'Light air'
elif speed < 7:
description = 'Light breeze'
elif speed < 11:
description = 'Gentle breeze'
elif speed < 16:
description = 'Moderate breeze'
elif speed < 22:
description = 'Fresh breeze'
elif speed < 28:
description = 'Strong breeze'
elif speed < 34:
description = 'Near gale'
elif speed < 41:
description = 'Gale'
elif speed < 48:
description = 'Strong gale'
elif speed < 56:
description = 'Storm'
elif speed < 64:
description = 'Violent storm'
else:
description = 'Hurricane'
if (degrees <= 22.5) or (degrees > 337.5):
degrees = u'\u2193'
elif (degrees > 22.5) and (degrees <= 67.5):
degrees = u'\u2199'
elif (degrees > 67.5) and (degrees <= 112.5):
degrees = u'\u2190'
elif (degrees > 112.5) and (degrees <= 157.5):
degrees = u'\u2196'
elif (degrees > 157.5) and (degrees <= 202.5):
degrees = u'\u2191'
elif (degrees > 202.5) and (degrees <= 247.5):
degrees = u'\u2197'
elif (degrees > 247.5) and (degrees <= 292.5):
degrees = u'\u2192'
elif (degrees > 292.5) and (degrees <= 337.5):
degrees = u'\u2198'
return description + ' ' + str(m_s) + 'm/s (' + degrees + ')'
@commands('weather', 'wea')
@example('.weather London')
def weather(bot, trigger):
""".weather location - Show the weather at the given location."""
location = trigger.group(2)
woeid = ''
if not location:
woeid = bot.db.get_nick_value(trigger.nick, 'woeid')
if not woeid:
return bot.msg(trigger.sender, "I don't know where you live. " +
'Give me a location, like .weather London, or tell me where you live by saying .setlocation London, for example.')
else:
location = location.strip()
woeid = bot.db.get_nick_value(location, 'woeid')
if woeid is None:
first_result = woeid_search(location)
if first_result is not None:
woeid = first_result.get('woeid')
if not woeid:
return bot.reply("I don't know where that is.")
query = 'q=select * from weather.forecast where woeid="%s" and u=\'c\'' % woeid
body = requests.get('http://query.yahooapis.com/v1/public/yql?' + query).content
parsed = xmltodict.parse(body).get('query')
results = parsed.get('results')
if results is None:
return bot.reply("No forecast available. Try a more specific location.")
location = results.get('channel').get('title')
cover = get_cover(results)
temp = get_temp(results)
humidity = get_humidity(results)
wind = get_wind(results)
bot.say(u'%s: %s, %s, %s, %s' % (location, cover, temp, humidity, wind))
@commands('setlocation', 'setwoeid')
@example('.setlocation Columbus, OH')
def update_woeid(bot, trigger):
"""Set your default weather location."""
if not trigger.group(2):
bot.reply('Give me a location, like "Washington, DC" or "London".')
return NOLIMIT
first_result = woeid_search(trigger.group(2))
if first_result is None:
return bot.reply("I don't know where that is.")
woeid = first_result.get('woeid')
bot.db.set_nick_value(trigger.nick, 'woeid', woeid)
neighborhood = first_result.get('locality2') or ''
if neighborhood:
neighborhood = neighborhood.get('#text') + ', '
city = first_result.get('locality1') or ''
# This is to catch cases like 'Bawlf, Alberta' where the location is
# thought to be a "LocalAdmin" rather than a "Town"
if city:
city = city.get('#text')
else:
city = first_result.get('name')
state = first_result.get('admin1').get('#text') or ''
country = first_result.get('country').get('#text') or ''
bot.reply('I now have you at WOEID %s (%s%s, %s, %s)' %
(woeid, neighborhood, city, state, country))