""" An inbound application that prompts the caller to enter a US Zipcode and then reads the weather for that location to the caller. It gets the weather forecast using the Yahoo query API. """ __uas_identify__ = "application" __uas_version__ = "1.0b3" import sys, os if sys.version > '3': import http.client else: import httplib from prosody.uas import Hangup, Error, ICanRun from urllib import quote import json # expand US state abbreviation to full name def us_state(abbreviation): return { 'AK': 'Alaska', 'AL': 'Alabama', 'AR': 'Arkansas', 'AS': 'American Samoa', 'AZ': 'Arizona', 'CA': 'California', 'CO': 'Colorado', 'CT': 'Connecticut', 'DC': 'District of Columbia', 'DE': 'Delaware', 'FL': 'Florida', 'GA': 'Georgia', 'GU': 'Guam', 'HI': 'Hawaii', 'IA': 'Iowa', 'ID': 'Idaho', 'IL': 'Illinois', 'IN': 'Indiana', 'KS': 'Kansas', 'KY': 'Kentucky', 'LA': 'Louisiana', 'MA': 'Massachusetts', 'MD': 'Maryland', 'ME': 'Maine', 'MI': 'Michigan', 'MN': 'Minnesota', 'MO': 'Missouri', 'MP': 'Northern Mariana Islands', 'MS': 'Mississippi', 'MT': 'Montana', 'NA': 'National', 'NC': 'North Carolina', 'ND': 'North Dakota', 'NE': 'Nebraska', 'NH': 'New Hampshire', 'NJ': 'New Jersey', 'NM': 'New Mexico', 'NV': 'Nevada', 'NY': 'New York', 'OH': 'Ohio', 'OK': 'Oklahoma', 'OR': 'Oregon', 'PA': 'Pennsylvania', 'PR': 'Puerto Rico', 'RI': 'Rhode Island', 'SC': 'South Carolina', 'SD': 'South Dakota', 'TN': 'Tennessee', 'TX': 'Texas', 'UT': 'Utah', 'VA': 'Virginia', 'VI': 'Virgin Islands', 'VT': 'Vermont', 'WA': 'Washington', 'WI': 'Wisconsin', 'WV': 'West Virginia', 'WY': 'Wyoming' }.get(abbreviation.strip(), abbreviation) def get_woeid(zip_code): # Get the "where on earth ID" from the zip code if sys.version > '3': http_connect = http.client.HTTPConnection("query.yahooapis.com") else: http_connect = httplib.HTTPConnection("query.yahooapis.com") query = quote('select woeid from geo.places(1) where text = "{0}"'.format(zip_code)) request = '/v1/public/yql?q={0}&format=json'.format(query) http_connect.request("GET", request) response = http_connect.getresponse() if response.status == 200: data = json.loads(response.read()) print("W: {0}".format(data["query"]["results"])) woeid = data["query"]["results"]["place"]["woeid"] return woeid else: return None def get_weather(woeid, my_log=None): if sys.version > '3': http_connect = http.client.HTTPConnection("query.yahooapis.com") else: http_connect = httplib.HTTPConnection("query.yahooapis.com") query = quote('select * from weather.forecast where woeid = {0}'.format(woeid)) request = '/v1/public/yql?q={0}&format=json'.format(query) http_connect.request("GET", request) response = http_connect.getresponse() if response.status == 200: data = json.loads(response.read()) results = data["query"]["results"]["channel"] country = results["location"]["country"] if country == "United States": region = us_state(results["location"]["region"]) else: region = country location = results["location"]["city"] + ", " + region forecasts = results["item"]["forecast"] high_f = float(forecasts[0]["high"]) high_c = int((high_f - 32.0) * 5.0/9.0) temp = "{0} Fahrenheit, {1} Celsius".format(high_f, high_c) weather = "{0}. Today's weather is {1}, with a high of {2}.".format(location, forecasts[0]["text"], temp) high_f = float(forecasts[1]["high"]) high_c = int((high_f - 32.0) * 5.0/9.0) temp = "{0} Fahrenheit, {1} Celsius".format(high_f, high_c) weather = weather + " Tomorrow will be {0}, with a high of {1}.".format(forecasts[1]["text"], temp) if my_log: my_log.info("{0}".format(weather)) print("{0}".format(weather)) return weather else: print("R: {0}".format(response.status)) return None def i_say(channel, to_say): cause = channel.FilePlayer.say(to_say, barge_in=True) if cause != channel.FilePlayer.Cause.NORMAL and cause != channel.FilePlayer.Cause.BARGEIN: raise Error("Say failed: cause is {0}".format(cause)) def main(channel, application_instance_id, file_man, my_log, application_parameters): my_log.info("Get US weather started") dtmf = "" try: channel.ring(2) channel.answer() i_say(channel, "Hello, please enter a five digit US zipcode, followed by the pound sign.") # use ICanRun to prevent accidental infinite loop i_can_run = ICanRun(channel) while i_can_run: dtmf = channel.DTMFDetector.get_digits(end='#*', seconds_predigits_timeout=30) cause = channel.DTMFDetector.cause() if cause == channel.DTMFDetector.Cause.END: dtmf = dtmf[:-1] # check results if len(dtmf) == 5: break channel.DTMFDetector.clear_digits() i_say(channel, "Five digits are required, please try again.") my_log.info("Zip code entered is {0}".format(dtmf)) woeid = get_woeid(dtmf) if not woeid: i_say(channel, "Sorry but I can't find a region for that zip code.") else: try: weather = get_weather(woeid, my_log) except: weather = "I cannot find the weather for that location." i_say(channel, weather) i_say(channel, "Thank you for calling, goodbye") channel.hang_up() my_log.info("Get weather completed") return 0 except Hangup as exc: my_log.info("Get weather completed with Hangup") return 0 except Error as exc: my_log.error("Get weather completed with Error exception! {0}".format(exc)) return -101 except Exception as exc: my_log.exception("Get weather completed with exception! {0}".format(exc)) return -102 finally: if channel.state() != channel.State.IDLE: channel.hang_up() w = get_woeid("MK10") c = get_weather(w)