Today’s post comes from J. Michael Palermo IV, Sr. Evangelist at Amazon Alexa. You will learn how to respond to control directives in code to turn devices on or off, set temperature, and set percentages.
When you build a skill with the Smart Home Skill API, the ultimate goal is to control a device. That control can include turning a device on or off, setting a temperature, or setting a percentage, such as when you’re dimming a light bulb. This post will cover the general process of device control and teach the fundamentals by demonstrating control of the ‘on’ or ‘off’ state in code using Node.js.
This technical walkthrough is a continuation in a series of smart home skill posts focused on development. Please read and follow the instructions found below to reach parity.
Figure 1: Device control process
Once a customer has properly installed, configured, and discovered all smart home devices, verbal control commands can be issued to an Alexa-enabled device, such as the Amazon Echo. Consider what happens from a developer perspective when a control command is made, such as turning on a light.
Let’s examine each step above in more detail.
Not shown in the process is the confirmation response sent by the skill adapter back to the Smart Home Skill API. You will see this in code later in this post.
In a previous post covering device discovery, sample data including five devices was statically returned for testing purposes. As we continue where that post left off, find getAppliances function, and change the data for the device with an appliance ID of “sample-2” to have the value “Desk Light” for the “friendlyName” field as seen below.
Another item worth our consideration is the supported actions for the appliance. This data is determined based on what the device can actually do. Since this device is a light with dimming capabilities, five actions are listed. Now, we will focus on how to implement the “turnOn” and “turnOff” actions.
{ "applianceId": "sample-2", "manufacturerName": "Sample Manufacturer", "modelName": "Sample Dimmer", "version": "1", "friendlyName": "Desk Light", "friendlyDescription": "Dimmer by Sample Manufacturer", "isReachable": true, "actions": [ "turnOn", "turnOff", "setPercentage", "incrementPercentage", "decrementPercentage" ], "additionalApplianceDetails": { "extraDetail1": "This is a dimmer that is reachable } }
Once the skill adapter is saved, the next time the customer issues a device discovery command, the updated information will show in the Alexa app (see Figure 2). In this example, the device is named “Desk Light” which is also how the customer will verbally identify it.
Figure 2 : Sample devices returned with update to friendly name
When the Smart Home Skill API makes a request to your skill adapter, it is the responsibility of the developer to parse the incoming directive to determine what type of request it is. The major heavy lifting of this was already covered in this post. In that post, the following function was created to handle incoming requests matching “TurnOnRequest” for the name found in the header.
var handleControlTurnOn = function(event) { var header = createHeader(NAMESPACE_CONTROL,RESPONSE_TURN_ON); var payload = {}; return createDirective(header,payload); }// handleControlTurnOn
Let us explore what this function does without any modification. The first line in the function calls on a helper function named “createHeader” passing in values defined as constants a the top of the code file. This is the resulting value passed into the “header” variable.
{ "messageId": "bfd78356-f912-4de4-b398-bf589715024c", "namespace": "Alexa.ConnectedHome.Control", "name": "TurnOnConfirmation", "payloadVersion": "2" }
The second line of the function initializes an empty object for the payload variable as seen here.
{}
The third line returns the value from the helper function named “createDirective” which combines the values from the preceding lines as follows.
{ "header": { "messageId": "bfd78356-f912-4de4-b398-bf589715024c", "namespace": "Alexa.ConnectedHome.Control", "name": "TurnOnConfirmation", "payloadVersion": "2" }, "payload": {} }
The resulting output is a valid response to the Smart Home Skill API for turning a device on. While this is good, the function never called a device cloud to trigger a device to turn on. Because device cloud APIs will vary from one implementation to the next, add a new function to simulate a device cloud call as shown here.
var callDeviceCloud = function(event, command, commandValue) { // var accessToken = event.payload.accessToken; var deviceId = event.payload.appliance.applianceId; log(deviceId, command + " = " + commandValue); }// callDeviceCloud
The above function simulates a call to a device cloud. The first line is provided for reference because it shows how to acquire the access token needed for an actual call to API using the supported OAuth provider. Because this simulation is not requiring authentication, the line is commented out. If you replace the inner code with a call to requiring an access token, simply uncomment the line.
The next line of code obtains the value of the targeted device. The final line simply logs the device ID and passed in values for the “command” and “commandValue” arguments. To see how this will be called, modify the “handleControlTurnOn” function as seen here.
var handleControlTurnOn = function(event) { var header = createHeader(NAMESPACE_CONTROL,RESPONSE_TURN_ON); var payload = {}; callDeviceCloud(event,"state","on"); return createDirective(header,payload); }// handleControlTurnOn
The only change to the function is the call to “callDeviceCloud” function, which accepts the “event” argument passed down from the call stack, and the values for the “command” and “commandValue” parameters, “state” and “on”.
Using this approach, change the handleControlTurnOff function to resemble the following.
var handleControlTurnOff = function(event) { var header = createHeader(NAMESPACE_CONTROL,RESPONSE_TURN_OFF); callDeviceCloud(event,"state","off"); var payload = {}; return createDirective(header,payload); }// handleControlTurnOff
The only line that changed is the call to the “callDeviceCloud” function, with the third parameter indicating “off”.
To confirm your skill adapter is receiving and responding appropriately to device control requests, test the behavior in the AWS console. With your code updated to reflect the changes made in this post, click on the “Actions” button above your code and select “Configure test event.”
Figure 3 : Configure test event
Choose any sample event template from the dropdown menu as we're going to overwrite this with our own sample event. Replace the contents with the directive example shown here.
{ "header": { "messageId": "5d599a53-fe40-405f-b0ab-233611e2dc5c", "name": "TurnOnRequest", "namespace": "Alexa.ConnectedHome.Control", "payloadVersion": "2" }, "payload": { "accessToken": "acc355t0ken",| "appliance": { "additionalApplianceDetails": {}, "applianceId": "sample-2" } } }
Figure 4 : Log output for “on”
After clicking the “Save and test” button, you should get results in your “Log output” panel similar to what is shown here.
Note how the log reflects the target device found in the incoming directive and that its desired state should be “on”. Repeat the test process, but this time change the name in the header to use “TurnOffRequest” as seen here.
{ "header": { "messageId": "5d599a53-fe40-405f-b0ab-233611e2dc5c", "name": "TurnOffRequest", "namespace": "Alexa.ConnectedHome.Control", "payloadVersion": "2" }, "payload": { "accessToken": "acc355t0ken", "appliance": { "additionalApplianceDetails": {}, "applianceId": "sample-2" } } }
Once again, after clicking the “Save and test” button, you should get a result similar to this in your “Log output” panel.
Figure 5 : Log output for “off”
The device state now shows “off” based on the name in the directive header.
In this post, we covered how to control devices that support the actions of turning on or off. Although not calling an actual device cloud API, you simulated it by adding a function to access the target device and set its state to either on or off, based on the incoming directive request. You also learned how to test the features in the AWS console to confirm functionality.
In my next post, I will cover other control actions supported by the Smart Home Skill API. Stay tuned.