Skip to content

Commit

Permalink
Add WeatherAPI.com weather provider
Browse files Browse the repository at this point in the history
  • Loading branch information
johnmaguire committed Jun 12, 2021
1 parent 7b39237 commit a1746df
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 45 deletions.
3 changes: 2 additions & 1 deletion plugins/weather/config.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{
"api_key": "7d00a4a07f7d55d9894aae06b0b473cb"
"provider": "weatherapi",
"api_key": "9dc48ecdcea74f9eae0135324211206"
}
147 changes: 103 additions & 44 deletions plugins/weather/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,33 @@

from cardinal.decorators import command, help

API_ENDPOINT = "https://api.openweathermap.org/data/2.5/weather"


class WeatherPlugin:
def __init__(self, cardinal, config=None):
self.logger = logging.getLogger(__name__)
self.db = cardinal.get_db('weather')

if config is None:
return

if 'api_key' in config:
self.api_key = config['api_key']
class Forecast:
def __init__(
self,
location,
condition,
temperature_f,
humidity,
winds_mph
):
self.location = location
self.condition = condition
self.temperature_f = temperature_f
self.temperature_c = (temperature_f - 32) * 5 // 9
self.humidity = humidity
self.winds_mph = winds_mph
self.winds_k = round(winds_mph * 1.609344, 2)


class OpenWeatherClient:
API_ENDPOINT = "https://api.openweathermap.org/data/2.5/weather"

def __init__(self, api_key):
self.api_key = api_key

@defer.inlineCallbacks
def _get_forecast(self, location):
def get_forecast(self, location) -> Forecast:
params = {
'q': location,
'appid': self.api_key,
Expand All @@ -31,11 +42,78 @@ def _get_forecast(self, location):

r = yield deferToThread(
requests.get,
API_ENDPOINT,
self.API_ENDPOINT,
params=params
)

return r.json()
return self.parse_forecast(r.json())

def parse_forecast(self, res):
location = "{}, {}".format(res['name'].strip(),
res['sys']['country'].strip())
condition = res['weather'][0]['main']
temperature = int(res['main']['temp'])
humidity = int(res['main']['humidity'])
winds = float(res['wind']['speed'])

return Forecast(location, condition, temperature, humidity, winds)


class WeatherAPIClient:
API_ENDPOINT = "https://api.weatherapi.com/v1/current.json"

def __init__(self, api_key):
self.api_key = api_key

@defer.inlineCallbacks
def get_forecast(self, location) -> Forecast:
params = {
'q': location,
'key': self.api_key,
}

r = yield deferToThread(
requests.get,
self.API_ENDPOINT,
params=params
)

return self.parse_forecast(r.json())

def parse_forecast(self, res):
location = res['location']['name']
if res['location']['region']:
location += ", {}, {}".format(res['location']['region'],
res['location']['country'])
else:
location += ", {}".format(res['location']['country'])

return Forecast(
location=location,
condition=res['current']['condition']['text'],
temperature_f=res['current']['temp_f'],
humidity=res['current']['humidity'],
winds_mph=res['current']['wind_mph'],
)


class WeatherPlugin:
def __init__(self, cardinal, config):
self.logger = logging.getLogger(__name__)
self.db = cardinal.get_db('weather')

if config is None:
config = {}

self.provider = config.get('provider', 'weatherapi')
self.api_key = config.get('api_key', None)

if self.provider == 'openweather':
self.client = OpenWeatherClient(self.api_key)
elif self.provider == 'weatherapi':
self.client = WeatherAPIClient(self.api_key)
else:
raise Exception(f"Unknown weather provider: {self.provider}")

@command('setw')
@help("Set your default weather location.")
Expand All @@ -49,9 +127,7 @@ def set_weather(self, cardinal, user, channel, msg):
return

try:
res = yield self._get_forecast(location)
location = "{}, {}".format(res['name'].strip(),
res['sys']['country'].strip())
res = yield self.client.get_forecast(location)
except Exception:
cardinal.sendMsg(channel, "Sorry, I can't find that location.")
self.logger.exception(
Expand All @@ -65,7 +141,7 @@ def set_weather(self, cardinal, user, channel, msg):
cardinal.sendMsg(channel, '{}: Your default weather location is now '
'set to {}. Next time you want the weather '
'at this location, just use .weather or .w!'
.format(user.nick, location))
.format(user.nick, res.location))

@command(['weather', 'w'])
@help("Retrieves the weather using the OpenWeatherMap API.")
Expand Down Expand Up @@ -94,41 +170,24 @@ def weather(self, cardinal, user, channel, msg):
return

try:
res = yield self._get_forecast(location)
res = yield self.client.get_forecast(location)
except Exception:
cardinal.sendMsg(channel, "Error fetching weather data.")
self.logger.exception(
"Error fetching forecast for location '{}'".format(location))
return

try:
self.logger.exception(
res
)
location = "{}, {}".format(res['name'].strip(),
res['sys']['country'].strip())
except KeyError:
cardinal.sendMsg(channel,
"Couldn't find weather data for your location: {}".format(location))
return

condition = res['weather'][0]['main']
temperature = int(res['main']['temp'])
temperature_c = (temperature - 32) * 5 // 9
humidity = int(res['main']['humidity'])
winds = float(res['wind']['speed'])
winds_k = round(winds * 1.609344, 2)
cardinal.sendMsg(
channel,
"[ {} | {} | Temp: {} °F ({} °C) | Humidity: {}% |"
" Winds: {} mph ({} km/h) ]".format(
location,
condition,
temperature,
temperature_c,
humidity,
winds,
winds_k)
res.location,
res.condition,
res.temperature_f,
res.temperature_c,
res.humidity,
res.winds_mph,
res.winds_k)
)


Expand Down

0 comments on commit a1746df

Please sign in to comment.