Amazon Echo / Alexa Smart Home Example Flow

This flow demonstrates using the Alexa Smart Home Skill with a minimal lambda smart-home skill adapter to interface directly with node-red.

Unlike other approaches, this only relies on two components, Amazon and node-red; not a 3rd party service which you have to worry about being secure or going down.

You can then control a light (or anything in node-red, really) directly with phrases like:

"Alexa, turn on test light" "Alexa, dim test light to 10 percent"

Steps to get this up and running:

  1. Configure an Alexa Smart Home skill and use "Login with Amazon" for your account linking. See here & here

  2. Although it will work without it, for security, I HIGHLY recommend using SSL between your lambda skill adapter in step 3 below and node-red. If running node-red on a home server this would normally entail setting up dynamic DNS (desec.io is free and works well) and using LetsEncrypt to set up a certificate for your domain.

  3. Use the following python skill adapter in your Amazon lambda instance, and be sure to insert your node-red url endpoint in url = 'https://my_url/smarthome'. Credit to JonW who posted this skill adapter here which I only slightly modified.

"""
--------------------  REFERENCE MATERIALS  --------------------  
Smart Home Skill API Reference:
https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/smart-home-skill-api-reference
Python reference for url/http handling
https://docs.python.org/2/howto/urllib2.html
---------------------------------------------------------------  
"""
import json
import urllib
import urllib2
import logging

logger = logging.getLogger()
logger.setLevel(logging.INFO)

# ============================================================================
#   Default Handler for all function requests
# ============================================================================
def lambda_handler(event, context):

    # Set the request URL to host:port.
    url = 'https://my_url/smarthome'

    # Encode the request event data.
    data = json.dumps(event)

    # Perform the request with the event data.
    req = urllib2.Request(url, data)
    req.add_header('Content-Type' , 'application/json')


    # Create the response object.
    response = urllib2.urlopen(req)

    # Get the complete response page.
    the_page = str(response.read())

    # Load raw page data into JSON object.
    parsed_json = json.loads(the_page)

    # Log the event request, page response and json object.
    #logger.info('**  Context Request  ** = {}'.format(context)) 
    logger.info('**  Event Request  ** = {}'.format(event)) 
    logger.info('**  Page Response  ** = {}'.format(the_page)) 
    logger.info('**  Parsed JSON  ** = {}'.format(parsed_json)) 

    # Return value as a JSON object.
    return parsed_json
  1. Set up port forwarding on your firewall to accept and forward to the right internal host running node-red on your network.

  2. Paste in the node-red flow below and change e-mail address in the "verify email" node to your e-mail address associated with your linked Amazon account.

  3. In the Alexa mobile app, link your smart home skill with your Amazon account.

  4. In the Alexa mobile app, hit Discover Devices. If everything worked, you should see 2 new devices discovered: Test Light & Test Thermostat.

  5. You're done! Say "Alexa, turn on test light", and you should see a message in node red debug tab.

[{"id":"5a2248b8.76ba18","type":"tab","label":"alexa smart home"},{"id":"d8c878fa.c923b8","type":"http in","z":"5a2248b8.76ba18","name":"Echo request","url":"/smarthome","method":"post","swaggerDoc":"","x":75,"y":227.54074096679688,"wires":[["f2837818.d89118","557c2004.c3a75"]]},{"id":"9a1bb05f.d2e1d","type":"http response","z":"5a2248b8.76ba18","name":"","x":1624.0790710449219,"y":297.19420623779297,"wires":[]},{"id":"67446ad6.6005f4","type":"debug","z":"5a2248b8.76ba18","name":"","active":false,"console":"false","complete":"payload","x":541.7514038085938,"y":61.672271728515625,"wires":[]},{"id":"b7f0a6d5.e25498","type":"switch","z":"5a2248b8.76ba18","name":"check namespace","property":"req.body.header.namespace","propertyType":"msg","rules":[{"t":"eq","v":"Alexa.ConnectedHome.Discovery","vt":"str"},{"t":"eq","v":"Alexa.ConnectedHome.System","vt":"str"},{"t":"eq","v":"Alexa.ConnectedHome.Control","vt":"str"}],"checkall":"true","outputs":3,"x":525.8333435058594,"y":219.111083984375,"wires":[["8f8662f3.bc633"],["390b23f2.5ccdec"],["db82b2df.e7f6b"]]},{"id":"c21e0114.0174","type":"template","z":"5a2248b8.76ba18","name":"Discovery Response","field":"payload","fieldType":"msg","format":"json","syntax":"mustache","template":"{\n    \"header\": {\n    \"messageId\": \"{{_msgid}}\",\n    \"namespace\": \"Alexa.ConnectedHome.Discovery\",\n    \"name\": \"DiscoverAppliancesResponse\",\n    \"payloadVersion\": \"2\"\n    \n},\n    \"payload\": {\n    \"discoveredAppliances\": [\n        {\n            \"actions\": [\n                \"turnOn\",\n                \"turnOff\",\n                \"setPercentage\",\n                \"incrementPercentage\",\n                \"decrementPercentage\"\n            ],\n            \"additionalApplianceDetails\": {\n                \"extraDetail1\": \"optionalDetailForSkillAdapterToReferenceThisDevice\",\n                \"extraDetail2\": \"There can be multiple entries\",\n                \"extraDetail3\": \"but they should only be used for reference purposes.\",\n                \"extraDetail4\": \"This is not a suitable place to maintain current device state\"\n            },\n            \"applianceId\": \"testlight\",\n            \"friendlyName\": \"Test Light\",\n            \"friendlyDescription\": \"My test light in the office\",\n            \"isReachable\": true,\n            \"manufacturerName\": \"jonn26 inc.\",\n            \"modelName\": \"TESTDIMABLELIGHT01\",\n            \"version\": \"VER01\"\n        },\n        {\n            \"actions\": [\n                \"incrementTargetTemperature\",\n                \"decrementTargetTemperature\",\n                \"setTargetTemperature\"\n            ],\n            \"additionalApplianceDetails\": {},\n            \"applianceId\": \"thermostat\",\n            \"friendlyName\": \"Test Thermostat\",\n            \"friendlyDescription\": \"Test Thermostat in the livingroom\",\n            \"isReachable\": true,\n            \"manufacturerName\": \"jonn26 inc.\",\n            \"modelName\": \"TESTTHERMOSTAT01\",\n            \"version\": \"VER01\"\n        }\n    ]\n}\n}","x":1016.6665954589844,"y":164.66659545898438,"wires":[["9a1bb05f.d2e1d"]]},{"id":"f2837818.d89118","type":"http request","z":"5a2248b8.76ba18","name":"verify oauth token","method":"GET","ret":"obj","url":"https://api.amazon.com/user/profile?access_token={{req.body.payload.accessToken}}","tls":"","x":200.72222900390625,"y":295.55556297302246,"wires":[["f14aa09c.eba3d"]]},{"id":"390b23f2.5ccdec","type":"switch","z":"5a2248b8.76ba18","name":"HealthCheckRequest","property":"req.body.header.name","propertyType":"msg","rules":[{"t":"eq","v":"HealthCheckRequest","vt":"str"}],"checkall":"true","outputs":1,"x":753.2421569824219,"y":217.95311737060547,"wires":[["4069c1ff.5ce7c"]]},{"id":"4069c1ff.5ce7c","type":"template","z":"5a2248b8.76ba18","name":"HealthCheckResponse","field":"payload","fieldType":"msg","format":"json","syntax":"mustache","template":"{\n    \"header\": {\n        \"messageId\": \"{{_msgid}}\",\n        \"name\": \"HealthCheckResponse\",\n        \"namespace\": \"Alexa.ConnectedHome.System\",\n        \"payloadVersion\": \"2\"\n    },\n    \"payload\": {\n        \"description\": \"The system is currently healthy\",\n        \"isHealthy\": true\n    }\n}","x":1024.2421569824219,"y":217.13280487060547,"wires":[["9a1bb05f.d2e1d"]]},{"id":"8f8662f3.bc633","type":"switch","z":"5a2248b8.76ba18","name":"DiscoverAppliancesRequest","property":"req.body.header.name","propertyType":"msg","rules":[{"t":"eq","v":"DiscoverAppliancesRequest","vt":"str"}],"checkall":"true","outputs":1,"x":774.5077819824219,"y":164.52342224121094,"wires":[["c21e0114.0174"]]},{"id":"557c2004.c3a75","type":"debug","z":"5a2248b8.76ba18","name":"","active":false,"console":"false","complete":"req.body","x":299.7300262451172,"y":102.07900810241699,"wires":[]},{"id":"b513dbda.e8f538","type":"change","z":"5a2248b8.76ba18","name":"invalid oauth key return error 401","rules":[{"t":"set","p":"statusCode","pt":"msg","to":"401","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":603.2853698730469,"y":291.7456588745117,"wires":[["9a1bb05f.d2e1d"]]},{"id":"f14aa09c.eba3d","type":"switch","z":"5a2248b8.76ba18","name":"verify e-mail","property":"payload.email","propertyType":"msg","rules":[{"t":"eq","v":"your_email@gmail.com","vt":"str"},{"t":"else"}],"checkall":"true","outputs":2,"x":331.2421875,"y":219.9453125,"wires":[["b7f0a6d5.e25498","67446ad6.6005f4"],["b513dbda.e8f538","b7924711.cf6e28"]]},{"id":"b7924711.cf6e28","type":"debug","z":"5a2248b8.76ba18","name":"","active":false,"console":"false","complete":"false","x":528.1744689941406,"y":361.41231536865234,"wires":[]},{"id":"db82b2df.e7f6b","type":"switch","z":"5a2248b8.76ba18","name":"applianceid","property":"req.body.payload.appliance.applianceId","propertyType":"msg","rules":[{"t":"eq","v":"testlight","vt":"str"},{"t":"eq","v":"thermostat","vt":"str"}],"checkall":"true","outputs":2,"x":726.25,"y":522.9452972412109,"wires":[["e80d4cca.26651"],["e6ce36ad.83bff8"]]},{"id":"e80d4cca.26651","type":"change","z":"5a2248b8.76ba18","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"req.body.header.name","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":913.0198669433594,"y":484.92186737060547,"wires":[["912adbaa.b72ea8","c9328294.af43f"]]},{"id":"5358d664.c30898","type":"template","z":"5a2248b8.76ba18","name":"ControlResponse","field":"payload","fieldType":"msg","format":"json","syntax":"mustache","template":"{\n    \"header\": {\n        \"messageId\": \"{{_msgid}}\",\n        \"name\": \"{{payload}}\",\n        \"namespace\": \"Alexa.ConnectedHome.Control\",\n        \"payloadVersion\": \"2\"\n    },\n    \"payload\": {}\n}\n","x":1420.2421569824219,"y":485.63280487060547,"wires":[["9a1bb05f.d2e1d"]]},{"id":"912adbaa.b72ea8","type":"change","z":"5a2248b8.76ba18","name":"set confirmation","rules":[{"t":"change","p":"payload","pt":"msg","from":"TurnOnRequest","fromt":"str","to":"TurnOnConfirmation","tot":"str"},{"t":"change","p":"payload","pt":"msg","from":"TurnOffRequest","fromt":"str","to":"TurnOffConfirmation","tot":"str"},{"t":"change","p":"payload","pt":"msg","from":"SetPercentageRequest","fromt":"str","to":"SetPercentageConfirmation","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1150.1308288574219,"y":485.3108139038086,"wires":[["5358d664.c30898"]]},{"id":"c9328294.af43f","type":"switch","z":"5a2248b8.76ba18","name":"On / Off / Percentage","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"TurnOnRequest","vt":"str"},{"t":"eq","v":"TurnOffRequest","vt":"str"},{"t":"eq","v":"SetPercentageRequest","vt":"str"}],"checkall":"true","outputs":3,"x":1172.8333435058594,"y":408.66661834716797,"wires":[["799dd08f.61465"],["e29b098a.0459a8"],["e44bcb63.179558"]]},{"id":"e44bcb63.179558","type":"change","z":"5a2248b8.76ba18","name":"testlight percent","rules":[{"t":"set","p":"topic","pt":"msg","to":"testlight","tot":"str"},{"t":"set","p":"payload","pt":"msg","to":"req.body.payload.percentageState.value","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1411.3889083862305,"y":446.9999885559082,"wires":[["81b9eee3.07f19"]]},{"id":"799dd08f.61465","type":"change","z":"5a2248b8.76ba18","name":"testlight on","rules":[{"t":"set","p":"topic","pt":"msg","to":"testlight","tot":"str"},{"t":"set","p":"payload","pt":"msg","to":"on","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1402.6665954589844,"y":370.66661834716797,"wires":[["81b9eee3.07f19"]]},{"id":"e29b098a.0459a8","type":"change","z":"5a2248b8.76ba18","name":"testlight off","rules":[{"t":"set","p":"topic","pt":"msg","to":"testlight","tot":"str"},{"t":"set","p":"payload","pt":"msg","to":"off","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1401.1110534667969,"y":408.8888626098633,"wires":[["81b9eee3.07f19"]]},{"id":"45a19fe1.860a7","type":"comment","z":"5a2248b8.76ba18","name":"Edit DiscoveryResponse with your device names","info":"See the following for details on the fields:\n\nhttps://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/smart-home-skill-api-reference","x":1097.4812927246094,"y":128.6296157836914,"wires":[]},{"id":"81b9eee3.07f19","type":"debug","z":"5a2248b8.76ba18","name":"","active":true,"console":"false","complete":"false","x":1644.8149108886719,"y":409.2221908569336,"wires":[]},{"id":"f53f43e.60bc2c","type":"comment","z":"5a2248b8.76ba18","name":"ControlRequest","info":"","x":725.9258728027344,"y":479.4073715209961,"wires":[]},{"id":"9ce4cf8d.98065","type":"comment","z":"5a2248b8.76ba18","name":"Edit your e-mail address here","info":"This flow assumes you are using \"login with amazon\"\n\nedit the verify e-mail node with your amazon linked e-mail address.","x":342.0370635986328,"y":177.4074182510376,"wires":[]},{"id":"80541fe8.2412d","type":"comment","z":"5a2248b8.76ba18","name":"testlight","info":"","x":872.8334045410156,"y":450.99999237060547,"wires":[]},{"id":"e6ce36ad.83bff8","type":"change","z":"5a2248b8.76ba18","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"req.body.header.name","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":910.6665954589844,"y":563.6667098999023,"wires":[["50689281.9725ac"]]},{"id":"50689281.9725ac","type":"switch","z":"5a2248b8.76ba18","name":"Set / Incr / Decr","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"SetTargetTemperatureRequest","vt":"str"},{"t":"eq","v":"IncrementTargetTemperatureRequest","vt":"str"},{"t":"eq","v":"DecrementTargetTemperatureRequest","vt":"str"}],"checkall":"true","outputs":3,"x":1145.6665954589844,"y":612.6667098999023,"wires":[[],[],[]]},{"id":"730c62c8.6a736c","type":"comment","z":"5a2248b8.76ba18","name":"thermostat","info":"","x":881.6665954589844,"y":530.6667098999023,"wires":[]},{"id":"5553e653.c6d578","type":"comment","z":"5a2248b8.76ba18","name":"Thermostat Work-In-Progress","info":"","x":1155.8333435058594,"y":554.0000839233398,"wires":[]}]
jonn26

Flow Info

created 1 month, 1 week ago
updated 1 month ago

Node Types

Core
  • change (x7)
  • comment (x6)
  • debug (x4)
  • http in (x1)
  • http request (x1)
  • http response (x1)
  • switch (x7)
  • template (x3)
Other
  • tab (x1)

Tags

  • amazon
  • alexa
  • echo
  • smart
  • home
  • skill
Copy this flow JSON to your clipboard and then import into Node-RED using the Import From > Clipboard (Ctrl-I) menu option