# # Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. # These materials are licensed under the Amazon Software License in connection with the Alexa Gadgets Program. # The Agreement is available at https://aws.amazon.com/asl/. # See the Agreement for the specific terms and conditions of the Agreement. # Capitalized terms not defined in this file have the meanings given to them in the Agreement. # import logging.handlers import uuid from ask_sdk_core.skill_builder import CustomSkillBuilder from ask_sdk_core.api_client import DefaultApiClient from ask_sdk_core.utils import is_request_type, is_intent_name from ask_sdk_core.handler_input import HandlerInput from ask_sdk_core.serialize import DefaultSerializer from ask_sdk_model.interfaces.custom_interface_controller import ( StartEventHandlerDirective, EventFilter, Expiration, FilterMatchAction, StopEventHandlerDirective, SendDirectiveDirective, Header, Endpoint ) logger = logging.getLogger() logger.setLevel(logging.INFO) serializer = DefaultSerializer() skill_builder = CustomSkillBuilder(api_client=DefaultApiClient()) @skill_builder.request_handler(can_handle_func=is_request_type("LaunchRequest")) def launch_request_handler(handler_input: HandlerInput): logger.info("== Launch Intent ==") response_builder = handler_input.response_builder system = handler_input.request_envelope.context.system # Get connected gadget endpoint ID. endpoints = get_connected_endpoints(handler_input) logger.debug("Checking endpoint..") if not endpoints: logger.debug("No connected gadget endpoints available.") return (response_builder .speak("Smart mirror not found. Please try again after connecting your gadget.") .set_should_end_session(True) .response) endpoint_id = endpoints[0].endpoint_id # Store endpoint ID for using it to send custom directives later. logger.debug("Received endpoints. Storing Endpoint Id: %s", endpoint_id) session_attr = handler_input.attributes_manager.session_attributes session_attr['endpointId'] = endpoint_id return (response_builder .speak("Welcome to the smart mirror skill! Say help if you want any.") .set_should_end_session(False) .response) @skill_builder.request_handler(can_handle_func=is_intent_name("AMAZON.HelpIntent")) def help_intent_handler(handler_input: HandlerInput): logger.info("Received HelpIntent.") # Retrieve the stored gadget endpointId from the SessionAttributes. session_attr = handler_input.attributes_manager.session_attributes endpoint_id = session_attr['endpointId'] response_builder = handler_input.response_builder return (response_builder .speak("You can say rainbow, police, show clock, change color to green or stop") .set_should_end_session(False) .response) @skill_builder.request_handler(can_handle_func=is_intent_name("ShowColor")) def yes_intent_handler(handler_input: HandlerInput): logger.info("ShowColor received. Sending color to device.") color_slot = "Color" # Retrieve the stored gadget endpointId from the SessionAttributes. session_attr = handler_input.attributes_manager.session_attributes endpoint_id = session_attr['endpointId'] response_builder = handler_input.response_builder slots = handler_input.request_envelope.request.intent.slots if color_slot in slots: color = slots[color_slot].value (response_builder .speak(f'Alright. Lighting up in {color}') .add_directive(build_showcolor_directive(endpoint_id, color)) .set_should_end_session(True)) else: (response_builder .speak("Can you please repeat that?") .set_should_end_session(False)) return response_builder.response @skill_builder.request_handler(can_handle_func=is_intent_name("ShowRainbow")) def show_rainbow_intent_handler(handler_input: HandlerInput): logger.info("Received ShowRainbowIntent.") # Retrieve the stored gadget endpointId from the SessionAttributes. session_attr = handler_input.attributes_manager.session_attributes endpoint_id = session_attr['endpointId'] response_builder = handler_input.response_builder return (response_builder .speak("Alright. Starting Rainbow!") .add_directive(build_rainbow_directive(endpoint_id)) .set_should_end_session(True) .response) @skill_builder.request_handler(can_handle_func=is_intent_name("BlinkPolice")) def police_intent_handler(handler_input: HandlerInput): logger.info("Received BlinkPoliceIntent.") session_attr = handler_input.attributes_manager.session_attributes endpoint_id = session_attr['endpointId'] response_builder = handler_input.response_builder return (response_builder .speak("Wooooop wooooop!") .add_directive(build_police_directive(endpoint_id)) .set_should_end_session(True) .response) @skill_builder.request_handler(can_handle_func=is_intent_name("ShowClock")) def clock_intent_handler(handler_input: HandlerInput): logger.info("Received ShowClockIntent") # Retrieve the stored gadget endpointId from the SessionAttributes. session_attr = handler_input.attributes_manager.session_attributes endpoint_id = session_attr['endpointId'] response_builder = handler_input.response_builder return (response_builder .speak("Super! Showing clock!") .add_directive(build_clock_directive(endpoint_id)) .set_should_end_session(True) .response) @skill_builder.request_handler(can_handle_func=is_intent_name("MirrorMirror")) def clock_intent_handler(handler_input: HandlerInput): logger.info("Received MirrorMirrorIntent") # Retrieve the stored gadget endpointId from the SessionAttributes. session_attr = handler_input.attributes_manager.session_attributes endpoint_id = session_attr['endpointId'] slots = handler_input.request_envelope.request.intent.slots response_builder = handler_input.response_builder name = 'Zoran' if 'Name' in slots: name = slots['Name'].value return (response_builder .add_directive(build_rainbow_directive(endpoint_id)) .speak(f'It is you {name} of course') .set_should_end_session(True) .response) @skill_builder.request_handler(can_handle_func=is_request_type("CustomInterfaceController.Expired")) def custom_interface_expiration_handler(handler_input): logger.info("== Custom Event Expiration Input ==") request = handler_input.request_envelope.request response_builder = handler_input.response_builder session_attr = handler_input.attributes_manager.session_attributes endpoint_id = session_attr['endpointId'] # When the EventHandler expires, send StopLED directive to stop LED animation # and end skill session. return (response_builder .add_directive(build_stop_led_directive(endpoint_id)) .speak(request.expiration_payload['data']) .set_should_end_session(True) .response) @skill_builder.request_handler(can_handle_func=lambda handler_input: is_intent_name("AMAZON.CancelIntent")(handler_input) or is_intent_name("AMAZON.StopIntent")(handler_input)) def stop_and_cancel_intent_handler(handler_input): logger.info("Received a Stop or a Cancel Intent..") session_attr = handler_input.attributes_manager.session_attributes response_builder = handler_input.response_builder endpoint_id = session_attr['endpointId'] # When the user stops the skill, stop the EventHandler, # send StopLED directive to stop LED animation and end skill session. if 'token' in session_attr.keys(): logger.debug("Active session detected, sending stop EventHandlerDirective.") response_builder.add_directive(StopEventHandlerDirective(session_attr['token'])) return (response_builder .speak("Alright, see you later Alligator!") .add_directive(build_stop_led_directive(endpoint_id)) .set_should_end_session(True) .response) @skill_builder.request_handler(can_handle_func=is_request_type("SessionEndedRequest")) def session_ended_request_handler(handler_input): logger.info("Session ended with reason: " + handler_input.request_envelope.request.reason.to_str()) return handler_input.response_builder.response @skill_builder.exception_handler(can_handle_func=lambda i, e: True) def error_handler(handler_input, exception): logger.info("==Error==") logger.error(exception, exc_info=True) return (handler_input.response_builder .speak("I'm sorry, something went wrong!").response) @skill_builder.global_request_interceptor() def log_request(handler_input): # Log the request for debugging purposes. logger.info("==Request==\r" + str(serializer.serialize(handler_input.request_envelope))) @skill_builder.global_response_interceptor() def log_response(handler_input, response): # Log the response for debugging purposes. logger.info("==Response==\r" + str(serializer.serialize(response))) logger.info("==Session Attributes==\r" + str(serializer.serialize(handler_input.attributes_manager.session_attributes))) def get_connected_endpoints(handler_input: HandlerInput): return handler_input.service_client_factory.get_endpoint_enumeration_service().get_endpoints().endpoints def build_stop_led_directive(endpoint_id): return SendDirectiveDirective( header=Header(namespace='Custom.SmartMirror', name='StopLED'), endpoint=Endpoint(endpoint_id=endpoint_id), payload={} ) def build_rainbow_directive(endpoint_id): return SendDirectiveDirective( header=Header(namespace='Custom.SmartMirror', name='Rainbow'), endpoint=Endpoint(endpoint_id=endpoint_id), payload={} ) def build_showcolor_directive(endpoint_id, color): return SendDirectiveDirective( header=Header(namespace='Custom.SmartMirror', name='Color'), endpoint=Endpoint(endpoint_id=endpoint_id), payload={ 'color': color } ) def build_police_directive(endpoint_id): return SendDirectiveDirective( header=Header(namespace='Custom.SmartMirror', name='Police'), endpoint=Endpoint(endpoint_id=endpoint_id), payload={} ) def build_clock_directive(endpoint_id): return SendDirectiveDirective( header=Header(namespace='Custom.SmartMirror', name='Clock'), endpoint=Endpoint(endpoint_id=endpoint_id), payload={} ) def build_start_event_handler_directive(token, duration_ms, namespace, name, filter_match_action, expiration_payload): return StartEventHandlerDirective( token=token, event_filter=EventFilter( filter_expression={ 'and': [ {'==': [{'var': 'header.namespace'}, namespace]}, {'==': [{'var': 'header.name'}, name]} ] }, filter_match_action=filter_match_action ), expiration=Expiration( duration_in_milliseconds=duration_ms, expiration_payload=expiration_payload)) def build_stop_event_handler_directive(token): return StopEventHandlerDirective(token=token) lambda_handler = skill_builder.lambda_handler()