Skip to content

Instantly share code, notes, and snippets.

@jamesbulpin
Created November 25, 2018 19:17
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jamesbulpin/8d75bae78232674c4b1ddab6d12196e8 to your computer and use it in GitHub Desktop.
Save jamesbulpin/8d75bae78232674c4b1ddab6d12196e8 to your computer and use it in GitHub Desktop.
Alexa skill handler for Cambridge bin collection query
# Set environment variable BIN_CALENDAR_URL to the specific ical calendar for your postcode
# https://refusecalendarapi.azurewebsites.net/calendar/ical/<id> where <id> can be found
# interactively using https://www.cambridge.gov.uk/check-when-your-bin-will-be-emptied
from urllib2 import urlopen
from datetime import datetime, timedelta
import os
from ask_sdk_core.skill_builder import SkillBuilder
from ask_sdk_core.dispatch_components import (
AbstractRequestHandler, AbstractExceptionHandler,
AbstractRequestInterceptor, AbstractResponseInterceptor)
from ask_sdk_core.utils import is_request_type, is_intent_name
from ask_sdk_core.handler_input import HandlerInput
from ask_sdk_model.ui import SimpleCard
from ask_sdk_model import Response
# Quick and dirty ical parsing to find the next occurrence of each
# type of collection. This avoids needing the full ical library
# which relies on strftime format strings that don't work on all
# platforms.
def get_next_dates(url):
# We're only interested in dates from today onwards. Set our threshold to
# this time yesterday so that the "all-day" (midnight) timestamp for
# today shows as in the future
threshold = datetime.now() - timedelta(1)
ical = urlopen(url).read().decode('iso-8859-1')
earliest = {}
current_date = None
current_item = None
for line in ical.splitlines():
if line.startswith("BEGIN:VEVENT"):
current_date = None
current_item = None
elif line.startswith("END:VEVENT"):
if current_date != None and current_item != None:
if current_date < threshold:
pass
elif earliest.has_key(current_item):
if current_date < earliest[current_item]:
earliest[current_item] = current_date
else:
earliest[current_item] = current_date
elif line.startswith("DTSTART;VALUE=DATE:"):
current_date = datetime.strptime(line.split(":")[1], "%Y%m%d")
elif line.startswith("SUMMARY:"):
current_item = line.split(":")[1]
return earliest
sb = SkillBuilder()
class BinDateIntentHandler(AbstractRequestHandler):
"""Handler for BinDateIntent."""
def can_handle(self, handler_input):
# type: (HandlerInput) -> bool
return is_intent_name("BinDateIntent")(handler_input)
def handle(self, handler_input):
# type: (HandlerInput) -> Response
try:
dates = get_next_dates(os.environ["BIN_CALENDAR_URL"])
slots = handler_input.request_envelope.request.intent.slots
if "BinColor" in slots:
color = slots["BinColor"].value
if color in ["green", "black", "blue"]:
item = color.title() + " Bin Collection"
if item in dates:
# Construct the response
resp = "The next " + item + " is "
if datetime.now().date() == dates[item].date():
resp = resp + "today"
elif (datetime.now() + timedelta(1)).date() == dates[item].date():
resp = resp + "tomorrow"
else:
delta_days = (dates[item].date() - datetime.now().date()).days
if delta_days < 7:
resp = resp + "this coming "
else:
resp = resp + "on "
resp = resp + dates[item].strftime("%A, %B") + " "
d = dates[item].strftime("%d").lstrip("0")
resp = resp + d
if d in ["1", "21", "31"]: resp = resp + "st"
if d in ["2", "22"]: resp = resp + "nd"
if d in ["3", "23"]: resp = resp + "rd"
handler_input.response_builder.speak(resp)
else:
handler_input.response_builder.speak("Sorry, I can't find the date for the " + item + " in the collection calendar.")
else:
handler_input.response_builder.speak("Sorry, I don't think that there are any " + color + " bin collections.")
else:
handler_input.response_builder.speak("Please specify which bin colour you'd like the schedule for.")
except:
handler_input.response_builder.speak("Sorry, something went wrong fetching the bin collection calendar.")
return handler_input.response_builder.response
sb.add_request_handler(BinDateIntentHandler())
# Handler name that is used on AWS lambda
lambda_handler = sb.lambda_handler()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment