From 8962e93d3c77f6cb3ed7cbe1fc255282f0abf406 Mon Sep 17 00:00:00 2001 From: iou1name Date: Wed, 4 Dec 2019 18:39:19 -0500 Subject: [PATCH] rewrite weather.py to use openweathermap --- README.md | 2 +- config.template.py | 3 + modules/weather.py | 177 ++++++++++++--------------------------------- 3 files changed, 52 insertions(+), 130 deletions(-) diff --git a/README.md b/README.md index 1442b05..de0f0f3 100755 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ It's like Sopel, except rewritten from scratch using Twisted as a base and over ## Requirements Python 3.6+ 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 Fix the movie table diff --git a/config.template.py b/config.template.py index 98b90ca..c787b7c 100755 --- a/config.template.py +++ b/config.template.py @@ -31,3 +31,6 @@ exchangerate_api_key = 'password' """ Crypto """ coinlib_api_key = 'password' + +""" Weather """ +weather_api_key = 'password' diff --git a/modules/weather.py b/modules/weather.py index c663a92..f823ec2 100755 --- a/modules/weather.py +++ b/modules/weather.py @@ -3,142 +3,61 @@ The weather man. """ import requests -import xmltodict +import config from module import commands, example -URI = "https://query.yahooapis.com/v1/public/yql?{QUERY}" - -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 + ')' - +URI = "https://api.openweathermap.org/data/2.5/weather" @commands("weather") -@example('.weather London') +@example('.weather Hell') 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): return bot.reply("Weather where?") - location = trigger.group(2) - location = location.strip() - first_result = woeid_search(location) - woeid = None - if first_result is not None: - woeid = first_result.get('woeid') + location = trigger.group(3) + if location == '-m' or location == '--metric': + location = trigger.group(4) + units = 'metric' + else: + units = 'imperial' - if not woeid: - return bot.reply("I don't know where that is.") + params = { + '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'" - 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: - 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.msg(u'%s: %s, %s, %s, %s' % (location, cover, temp, humidity, wind)) + city = data.get('name') + country = data['sys']['country'] + sky = data['weather'][0]['main'] + temp = data['main']['temp'] + humidity = data['main']['humidity'] + wind = data['wind']['speed'] + degrees = data['wind']['deg'] + + msg = "[\x0304Weather\x03] " + msg += f"\x0310City\x03: \x0312{city}\x03, \x0312{country}\x03 | " + msg += f"\x0310Sky: \x0312{sky}\x03 | " + msg += f"\x0310Temp\x03: \x0308{temp}\u00B0" + 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)