#!/usr/bin/env python3 """ The weather man. """ import requests import xmltodict 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 + ')' @commands("weather") @example('.weather London') def weather(bot, trigger): """.weather location - Show the weather at the given location.""" 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') if not woeid: return bot.reply("I don't know where that is.") 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))