rewrite weather.py to use openweathermap

This commit is contained in:
iou1name 2019-12-04 18:39:19 -05:00
parent 743a3a2d34
commit 8962e93d3c
3 changed files with 52 additions and 130 deletions

View File

@ -4,7 +4,7 @@ It's like Sopel, except rewritten from scratch using Twisted as a base and over
## Requirements ## Requirements
Python 3.6+ Python 3.6+
System packages: `enchant` System packages: `enchant`
Python packages: `twisted python-dateutil requests bs4 wolframalpha pyenchant emoji Pillow xml2dict ipython numpy numpngw` Python packages: `twisted python-dateutil requests bs4 wolframalpha pyenchant emoji pillow ipython numpy numpngw`
## TODO ## TODO
Fix the movie table Fix the movie table

View File

@ -31,3 +31,6 @@ exchangerate_api_key = 'password'
""" Crypto """ """ Crypto """
coinlib_api_key = 'password' coinlib_api_key = 'password'
""" Weather """
weather_api_key = 'password'

View File

@ -3,142 +3,61 @@
The weather man. The weather man.
""" """
import requests import requests
import xmltodict
import config
from module import commands, example from module import commands, example
URI = "https://query.yahooapis.com/v1/public/yql?{QUERY}" URI = "https://api.openweathermap.org/data/2.5/weather"
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 = f'q=select * from geo.places where text="{query}"'
res = requests.get(URI.format(**{"QUERY": query}), verify=True)
body = res.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") @commands("weather")
@example('.weather London') @example('.weather Hell')
def weather(bot, trigger): def weather(bot, trigger):
""".weather location - Show the weather at the given location.""" """
Show the weather at the given location.
-m, --metric - uses metric units instead of imperial.
"""
if not trigger.group(2): if not trigger.group(2):
return bot.reply("Weather where?") return bot.reply("Weather where?")
location = trigger.group(2) location = trigger.group(3)
location = location.strip() if location == '-m' or location == '--metric':
first_result = woeid_search(location) location = trigger.group(4)
woeid = None units = 'metric'
if first_result is not None: else:
woeid = first_result.get('woeid') units = 'imperial'
if not woeid: params = {
return bot.reply("I don't know where that is.") 'q': location,
'appid': config.weather_api_key,
'units': units
}
res = requests.get(URI, params=params, verify=True)
data = res.json()
if data['cod'] == 404:
return bot.reply("City not found. Try a different query.")
query =f"q=select * from weather.forecast where woeid=\"{woeid}\" and u='c'" city = data.get('name')
res = requests.get(URI.format(**{"QUERY": query}), verify=True) country = data['sys']['country']
body = res.content sky = data['weather'][0]['main']
parsed = xmltodict.parse(body).get('query') temp = data['main']['temp']
results = parsed.get('results') humidity = data['main']['humidity']
if results is None: wind = data['wind']['speed']
return bot.reply("No forecast available. Try a more specific location.") degrees = data['wind']['deg']
location = results.get('channel').get('title')
cover = get_cover(results) msg = "[\x0304Weather\x03] "
temp = get_temp(results) msg += f"\x0310City\x03: \x0312{city}\x03, \x0312{country}\x03 | "
humidity = get_humidity(results) msg += f"\x0310Sky: \x0312{sky}\x03 | "
wind = get_wind(results) msg += f"\x0310Temp\x03: \x0308{temp}\u00B0"
bot.msg(u'%s: %s, %s, %s, %s' % (location, cover, temp, humidity, wind)) if units == 'imperial':
msg += "F\x03 | "
else:
msg += "C\x03 | "
msg += f"\x0310Humidity\x03: \x0308{humidity}%\x03 | "
msg += f"\x0310Wind\x03: \x0308{wind}"
if units == 'imperial':
msg += "mph"
else:
msg += "m/s"
if degrees:
msg += f"\x03 (\x0308{degrees}\u00B0\x03)"
bot.msg(msg)