weather2.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. import requests
  2. import re
  3. from event import Event
  4. try:
  5. from basemodule import BaseModule
  6. except ImportError:
  7. from modules.basemodule import BaseModule
  8. class Weather2(BaseModule):
  9. def post_init(self):
  10. weather2 = Event('__.weather2__')
  11. weather2.define(msg_definition='^\.weather')
  12. weather2.subscribe(self)
  13. self.bot.register_event(weather2, self)
  14. self.api_key = "1fe31b3b4cfdab66"
  15. def api_request(self, location, channel):
  16. """location is a search string after the .weather command. This function
  17. will determine whether it is a zip code or a named location and return an
  18. appropriate API call"""
  19. #note for future: if wanted, add further detection of conditions or forecast searching
  20. query = None
  21. try:
  22. # test if is a zipcode or a single city name
  23. a = float(location.split()[0])
  24. if a and len(location.split()[0]) < 5:
  25. self.say(channel,"valid zipcode required, numbnuts")
  26. return None
  27. zipcode = re.match('[0-9]{5}', location)
  28. query = '/q/'+zipcode.string
  29. except ValueError: # it's a city name (or broken encoding on numbers or something)
  30. #create autocomplete search
  31. q = requests.get('http://autocomplete.wunderground.com/aq', params={'query':location})
  32. try:
  33. q.raise_for_status()
  34. except request.exceptions.HTTPError:
  35. self.say(channel, "Encountered an error contacting the WUnderground API")
  36. return None
  37. results = q.json()
  38. try:
  39. #attempt to grab the 'l' field from the first result
  40. #assuming it exists, this field will be what we use to search the conditions api
  41. query = results['RESULTS'][0]['l']
  42. except (IndexError, KeyError):
  43. #in case there were no results, let channel know
  44. self.say(channel, "No results found")
  45. return None
  46. if query:
  47. #return the full URL of the query we want to make
  48. return 'http://api.wunderground.com/api/'+self.api_key+'/conditions'+query+'.json'
  49. return None
  50. def get_conditions(self, query, channel):
  51. """given a fully formed query to the wundeground API, format an output string"""
  52. r = requests.get(query)
  53. try:
  54. r.raise_for_status()
  55. except requests.exceptions.HTTPError:
  56. self.say(channel, "Encountered an error contacting the WUnderground API")
  57. return
  58. weather = r.json()
  59. try:
  60. #grab the relevant data we want for formatting
  61. location = weather['current_observation']['display_location']['full']
  62. conditions = weather['current_observation']['weather']
  63. temp_f = str(weather['current_observation']['temp_f'])
  64. temp_c = str(weather['current_observation']['temp_c'])
  65. humidity = weather['current_observation']['relative_humidity']
  66. except KeyError:
  67. self.say(channel, "Unable to get weather data from results. Sorry.")
  68. return
  69. #return the formatted string of weather data
  70. return location + ': ' + conditions + ', ' + temp_f + 'F (' + temp_c + 'C). Humidity: ' + humidity
  71. def handle(self, event):
  72. #split the line beginning with .weather into 2 parts, the command and the search string
  73. weather_line = event.msg.split(None, 1)
  74. if len(weather_line) > 1:
  75. #if we're sure there's actually a search string, then continue
  76. query = self.api_request(weather_line[1], event.channel)
  77. if not query:
  78. return
  79. weather = self.get_conditions(query, event.channel)
  80. if not weather:
  81. return
  82. self.say(event.channel, weather)
  83. else:
  84. #chastise the user for being silly and not actually searching for a location
  85. self.say(event.channel, "It would help if you supplied an actual location to search for.")