Quick Start

In here you’ll find a fast introduction to askhome and show you how to get a simple Smart Home Skill up and running.

Installation

Install askhome with pip:

$ pip install askhome

If you are deploying to AWS Lambda by uploading zips, install askhome to your directory with:

$ pip install askhome -t /path/to/project-dir

More on deployment later.

Defining Appliances

When a Smart Home Skill is installed on Amazon Echo, Alexa first needs to discover all available appliances with information about what actions they support. With askhome, you can define your device types by subclassing Appliance. Methods marked with the @Appliance.action decorator will be discoverable and called when the corresponding request comes in:

from askhome import Appliance

class Light(Appliance):
    @Appliance.action
    def turn_on(self, request):
        pass # Your logic for switching a light on here

    @Appliance.action
    def turn_off(self, request):
        pass # Your logic for switching a light, you guessed it, off here

Now that we’ve defined a light appliance type, lets fill our smart home with some:

from askhome import Smarthome

home = Smarthome()
home.add_appliance('light1', Light, name='Kitchen Light',
                   description='Turn me on when cutting vegetables.')

home.add_appliance('light2', Light, name='Bedroom Light',
                   model='Very Bright Light 8000')

We’ve added two lights with some additional info. For all details you can set, check the Smarthome.add_appliance method or the official DiscoverAppliancesResponse documentation.

All that’s left to do is expose a handler for our AWS Lambda instance (more on that in deployment):

lambda_handler = home.lambda_handler

And that’s it! We’ve got a fully functioning Smart Home Skill that controls our lights. It can be initialized with:

“Alexa, discover my devices.”

And then to control the lights:

“Alexa, turn on the kitchen light.”

Handling Requests

When the method wrapped with @Appliance.action gets called, it receives a Request object as argument. It has some basic useful attributes such as payload or name, but what’s special about it is that for every action type a specific Request subclass is passed. These subclasses have additional helpful attributes and a response method which simplifies the response creation. For instance a set_target_temperature action receives a request that can do this:

class Heater(Appliance):
    @Appliance.action
    def set_target_temperature(self, request):
        print request.temperature
        return request.response(request.temperature,
                                mode='HEAT',
                                previous_temperature=21.3,
                                previous_mode='AUTO')

If the action method doesn’t return anything (returns None), success is implied.

Actions Overview

Possible action methods and their corresponding Request types passed are:

Here is a sample usage of all possible actions:

from askhome.requests import *

class UltimateAppliance(Appliance):

    # The action_for decorator can mark a method for multiple actions
    @Appliance.action_for('turn_on', 'turn_off')
    def turn_on_off(self, request):
        # type: (Request) -> Optional[dict]
        pass # nothing special here

    @Appliance.action_for('set_percentage', 'increment_percentage',
                          'decrement_percentage')
    def control_percentage(self, request):
        # type: (PercentageRequest) -> Optional[dict]
        print request.percentage
        print request.delta_percentage

    @Appliance.action_for('set_target_temperature',
                          'increment_target_temperature',
                          'decrement_target_temperature')
    def control_temperature(self, request):
        # type: (ChangeTemperatureRequest) -> Optional[dict]
        print request.temperature
        print request.delta_temperature
        return request.response(22.8,
                                mode='HEAT',
                                previous_temperature=21.3,
                                previous_mode='AUTO')

    @Appliance.action
    def get_target_temperature(self, request):
        # type: (GetTargetTemperatureRequest) -> Optional[dict]
        return request.response(21.8,
                                cooling_temperature=20
                                heating_temperature=23,
                                mode='CUSTOM',
                                mode_name='mode name')

    @Appliance.action
    def get_temperature_reading(self, request):
        # type: (TemperatureReadingRequest) -> Optional[dict]
        return request.response(21.8, timestamp=datetime.now())

    @Appliance.action_for('set_lock_state', 'get_lock_state')
    def lock_state(self, request):
        # type: (LockStateRequest) -> Optional[dict]
        return request.response('LOCKED')

For further information about these actions see the official documentation.

Error Responses

If the user asked an invalid request or something goes wrong during the action execution, the Smart Home API offers plenty of possible error responses. To respond with an error, simply raise one of askhome’s exceptions, like this:

from askhome.exceptions import ValueOutOfRangeError

class Heater(Appliance):
    @Appliance.action
    def set_target_temperature(self, request):
        if request.temperature not in range(15, 25):
            raise ValueOutOfRangeError(15, 25)

All possible exceptions can be found here or at the official error messages documentation.

Deployment

Unlike the Custom Skills, Smart Home Skills have to be hosted on AWS Lambda instances. To create a skill and deploy it to Lambda, follow the official tutorial. When it comes to uploading your code, you have to package your libraries with it. You can do that with a local pip installation and then uploading a zip of your project with all its dependencies included.

Deploying with Zappa

Zappa is an awesome tool to deploy WSGI apps to Lambda. Smart Home Skills are not using the WSGI interface, but we can still use Zappa to automate our deployments. It also comes with advantages like precompiled python packages (such as pyOpenSSL) which would otherwise have to be compiled on AWS machines.

To use it, first create a virtualenv for your project:

$ virtualenv .venv
$ source .venv/Scripts/activate

Then install the required packages:

$ pip install Zappa askhome

Create a zappa_settings.yml configuration file for Zappa:

dev:
  s3_bucket: smart-home-skill-dev-deploy
  lambda_handler: main.lambda_handler # name of your file and exposed handler
  aws_region: us-east-1 # region has to match your Echo version
  timeout_seconds: 10
  memory_size: 128
  keep_warm: false
  touch: false # keep Zappa from sending WSGI requests to your skill

Finally, let Zappa do its work:

$ zappa deploy

That should create a Lambda function, but you still need to manually add the trigger and link the function to your skill as described in the official tutorial. After that your Echo should respond to your commands!


Next, you can go to the official Smart Home Skill API documentation for detailed request information or continue to Advanced Usage.