"""Get the weather from an address using forecast.io."""
from __future__ import division
import dave.modules
import requests
import dave.config
import pickle
from urllib.parse import quote_plus
import arrow
from dave.models import Location
import socket
@dave.module.help("Syntax: weather [location]. Get the forecast in the specified location.")
@dave.module.command(["weather"], "?( .*)?$")
@dave.module.priority(dave.module.Priority.HIGHEST)
def weather(bot, args, sender, source):
location = args[0]
db_location = dave.config.session.query(Location).filter(Location.nick.ilike(sender)).first()
if not location:
if db_location:
location = db_location.location
else:
return
else:
location = location.strip()
if db_location:
db_location.location = location
else:
db_location = Location(nick=sender, location=location)
dave.config.session.add(db_location)
geocode = get_location(location)
if not geocode or not geocode["results"]:
return
formatted_address = get_address(geocode)
timezone = get_timezone(geocode)
weather = get_weather(geocode)
bot.reply(source, sender, u"{}: {}°C/{}°F (feels like {}°C/{}°F), {}. Wind: {}mph/{}km/h, humidity: {}% | Sun: {} - {} {}".format(
formatted_address,
int(round(weather["currently"]["temperature"])),
int(round(weather["currently"]["temperature"] * (9 / 5) + 32)),
int(round(weather["currently"]["apparentTemperature"])),
int(round(weather["currently"]["apparentTemperature"] * (9 / 5) + 32)),
weather["currently"]["summary"],
int(round(weather["currently"]["windSpeed"])),
int(round(weather["currently"]["windSpeed"] * 1.60934)),
int(round(weather["currently"]["humidity"] * 100)),
arrow.get(weather["daily"]["data"][0]["sunriseTime"]).to(timezone["zoneName"]).strftime("%H:%M").lower(),
arrow.get(weather["daily"]["data"][0]["sunsetTime"]).to(timezone["zoneName"]).strftime("%H:%M").lower(),
timezone["abbreviation"]
))
def get_location(location):
"""Get the lat/long of the location the user gave us."""
key = "location:{}".format(location.lower())
if not dave.config.redis.exists(key):
r = requests.get("https://maps.googleapis.com/maps/api/geocode/json?address={}&key={}".format(
quote_plus(location),
dave.config.config["api_keys"]["google_maps"]
))
geocode = r.json()
dave.config.redis.set(key, pickle.dumps(geocode))
else:
geocode = pickle.loads(dave.config.redis.get(key))
return geocode
def get_address(geocode):
"""Get a nicely formatted location to return."""
formatted_address = []
has_locality = False
for component in geocode["results"][0]["address_components"]:
if "locality" in component["types"]:
has_locality = True
formatted_address.append(component["short_name"])
if "country" in component["types"]:
formatted_address.append(component["short_name"])
if not has_locality:
for component in geocode["results"][0]["address_components"]:
if "postal_town" in component["types"]:
formatted_address.insert(0, component["short_name"])
if len(formatted_address) < 2:
formatted_address = [a["short_name"] for a in geocode["results"][0]["address_components"]]
return ", ".join(formatted_address)
def get_timezone(geocode):
"""Get the timezone of the location the user gave us"""
key = "timezone:{}_{}".format(geocode["results"][0]["geometry"]["location"]["lat"],
geocode["results"][0]["geometry"]["location"]["lng"])
if not dave.config.redis.exists(key):
r = requests.get("http://api.timezonedb.com/?key={}&lat={}&lng={}&format=json".format(
dave.config.config["api_keys"]["timezonedb"],
geocode["results"][0]["geometry"]["location"]["lat"],
geocode["results"][0]["geometry"]["location"]["lng"]
))
timezone = r.json()
dave.config.redis.set(key, pickle.dumps(timezone))
else:
timezone = pickle.loads(dave.config.redis.get(key))
return timezone
def get_weather(geocode):
"""Get the weather for the location the user gave us"""
key = "weather:{}_{}".format(geocode["results"][0]["geometry"]["location"]["lat"],
geocode["results"][0]["geometry"]["location"]["lng"])
if not dave.config.redis.exists(key):
r = requests.get("https://api.forecast.io/forecast/{}/{},{}?units=uk2".format(
dave.config.config["api_keys"]["forecast.io"],
geocode["results"][0]["geometry"]["location"]["lat"],
geocode["results"][0]["geometry"]["location"]["lng"]
))
json = r.json()
dave.config.redis.setex(key, 300, pickle.dumps(json))
else:
json = pickle.loads(dave.config.redis.get(key))
return json