Control your X10 Devices with the Amazon Echo using the Smart Home Skill API

Amazon Dot X10

In a previous post you’ve learned how to control your X10 devices using the Amazon Echo and the IFTTT service. But now Amazon allows you to code a Smart Home Skill so you can say Alexa turn on the lights instead of Alexa trigger lights on. It’s more convenient! Let’s extend the work we’ve already done to write a Smart Home Skill to natively manage your X10 devices.

You will need the following:

  • You have to do everything in this post completely except for the IFTTT part (the last section).
  • An Amazon Developer account. It’s free.
  • An Amazon AWS account, because we need the Lambda Service. It’ll be free if you use your skill less than 1 million times a month, which is a lot. This is a requirement, not optional.
  • An Amazon Login account, completely free, to authenticate your skill.

Alright, let’s do this!

Smart Home Skills

The Smart Home Skills are a little different than the normal Alexa Skills. Your skill needs a special piece of code called a Skill Adapter. This code has to be written using the Lambda Function Service of Amazon, and you can choose to do it in  a few different languages. We will write it in JavaScript, more on that later. This function has to provide two basic services:

  • Discovery: This is the procedure that will be called when you say Alexa discover my devices. It should tell your web server to read the INI file and return a JSON string with all the devices you have configured.
  • Control: This is the main procedure to turn on/off things or to dim/brighten lights.

You already implemented the Control interface in the previous post, but you need to create an interface on your web server to do the discovery.

As you might have guessed we need to write a PHP script to return all the discovered devices. This is a very simple script that all it will do is to read your X10 INI file that you created in the previous post and return something like this:

[  
   {  
      "applianceId":"lights",
      "manufacturerName":"Scorpius",
      "modelName":"X10",
      "version":"1.0",
      "friendlyName":"lights",
      "friendlyDescription":"Master bedroom lights",
      "isReachable":true,
      "actions":[  
         "turnOn",
         "turnOff"
      ],
      "additionalApplianceDetails":{  
         "extraDetail1":"Test"
      }
   },
   {  
      "applianceId":"air_conditioner",
      "manufacturerName":"Scorpius",
      "modelName":"X10",
      "version":"1.0",
      "friendlyName":"air conditioner",
      "friendlyDescription":"Air Conditioner",
      "isReachable":true,
      "actions":[  
         "turnOn",
         "turnOff"
      ],
      "additionalApplianceDetails":{  
         "extraDetail1":"Test"
      }
   }
]

You will need to extend your INI file a little to add a name and a description, like this:

[lights]
code = a2
dim = 1
name = lights
description = Master bedroom lights

[air_conditioner]
code = a4
name = air conditioner
description = Air Conditioner

The script is so simple that needs no further explanation. You can find it here. Test it opening a URL like this:

http://echo.echoparklake.com/ifttt/discover.php

You have to change echo.echoparklake.com with the domain name of your web server, of course.

Amazon Developer Account

Next in our To-Do list is to create an Amazon Developer account. Once you’re logged in the Developer Console, click on the Alexa tab and then on Get Started under the Alexa Skills Kit option:

Alexa Skills Kit

Now click on Add a New Skill. The first thing you need to do is to change the Skill Type to Smart Home Skill API. Choose a name for your skill and click on Save. In a couple of seconds, it will refresh and show you the Application ID. Take note of this ID:

Amazon Developer Smart Home Skill

For now we are not going to go any further. We’ll go back to this when we have everything else.

Amazon Web Services (AWS) Account

Now you need to create an AWS account. After you have created your account and have logged in, click on AWS and select Lambda under the Compute section.

Click on Create a New Lambda Function and select Blank Function. Now you should be in the Configure Trigger section. Choose the Alexa Smart Home trigger and paste the Application ID you got from the Amazon Developer Portal. Click on Enable Trigger. It should look like this:

Amazon Lambda Function Setup

Click on Next.  Choose a name for your Lambda function, and a description. The runtime should be Node.js 4.3.

Now we need to write a JavaScript function to handle our X10 devices. We’re going to modify the Smart Home Skill Lambda function example a little. Copy this lambda function and paste it in the Code field. You have to modify it with your settings. You need to modify the options array in each function with your domain name and path of your web server PHP scripts:

var options = {
    hostname: 'echo.echoparklake.com',
    path: '/ifttt/discover.php',
    port: 80
};

Now configure the handler and role as follows:

Lambda Handler and Role

Click on Next and then Create Function. After that look at the top right of your screen and take note of the ARN it should be something like arn:aws:lambda:us-east-1:239411752002:function:myX10LambdaFunction. You will need it later.

Amazon Login Account

We need an Amazon Login account to be able to use OAuth authentication for the skill. After you create your account and are logged in, click on the Register New Application button.

Just fill the fields with some names for your application. Here’s an example:

Smart Home X10 Control Application

Click on the Save button.

Now click on Web Settings. Take a note of the Client ID, we’ll need it later.

Finish Configurations

Now we must go back to the Amazon Developer Console and edit our Smart Home Skill. Go to Configuration and in the Endpoint section, click on North America (assuming you created your Lambda function there) and paste the ARN of your Lambda function there.

The Authorization URL should be https://www.amazon.com/ap/oa since we are using the Amazon Login service.

Paste the Client ID from your Amazon Login application you just created in the previous step in the Client ID field.

Add your domain in the Domain List field. For instance, we would have to use echoparklake.com since that’s the domain we’ve been using as an example. In your case just type the domain name you have been using.

In the Scope field, type profile.

Smart Home Settings

Copy the Redirect URLs and paste them in the Amazon Login Web Settings section of your application:X10 Smart Home Skill Application Web Settings

Select Auth Code Grant in the Authorization Grant Type field.

The Access Token URI should be https://api.amazon.com/auth/o2/token. Paste the Client Secret from your Amazon Login application to the Client Secret field. The Client Authentication Scheme should be HTTP Basic Authentication.

Smart Home Settings

Click on Next and then enable it in the Test section so you can see the skill in the Alexa app.

Enabling and Testing the Skill

Go to the Alexa app (do it from a PC browser, not from your phone or tablet) and look for your skill in the Your Skills section and click on Enable. It should go to the Amazon Login website to ask for your login and password if you are not already logged in (you should be, though).

After that, the Alexa app should ask you to discover devices. You can also discover them by saying Alexa discover my devices. If everything went well you should see a list of all the devices you configured in your INI file. Now you can try to turn them on or off, for example saying Alexa turn on the lights.


27 thoughts to “Control your X10 Devices with the Amazon Echo using the Smart Home Skill API”

  1. Thanks for the update. I’ve done all the steps, and I think I’m pretty close to having it working. A couple things… I discovered that when configuring triggers you can only find the Alexa Smart Home trigger if you’re using the US East (N. Virginia) region. Also, is there an easy way to debug errors? I’m pretty sure I have everything configured right, but CloudWatch shows me invocation errors for the lambda function, and I can see from my web server logs that discover.php is not running when the function executes. I can view it myself, and the output looks fine.

    1. I’m thinking it might be the lambda function timing out because DNS isn’t resolving my server. I only created the subdomain today, and while it resolves locally with my ISP, I tried from a couple of other machines (work, etc.) and it timed out with no response. I guess I just have to wait.

        1. Now I’m lost 🙂 Is it working?

          It’s a nightmare to debug since there’s a lot of components, but the Lambda Function section has a Test with several Alexa Smart Home Skill templates and also you can turn on CloudWatch.

          Also the first thing you have to be sure is that all your PHP scripts work by manually calling the URLs and looking at the JSON results and the log of your web server.

          1. Haha, sorry… Yes, everything works as you described, except you might want to remind readers to select US East (N. Virginia) before trying to configure the triggers.

            I was having trouble debugging the script. CloudWatch showed me there were errors each time the lambda script was invoked, but the logs were pretty useless. I initially thought my problem was that DNS hadn’t propagated, so the hostname wasn’t resolving. That assumption was false. The problem was actually that my ISP blocks incoming requests on port 80. So I changed my virtual server / NAT config to use a different port that wasn’t blocked, and then I modified the lambda script to use that port instead of 80.

            Anyway, all is well now. I am able to control my lights with Alexa. And I appreciate your articles and your helpful responses. Thanks!

  2. “Haha, sorry… Yes, everything works as you described, except you might want to remind readers to select US East (N. Virginia) before trying to configure the triggers…”

    You will find this option in a drop-down, on the “Configure Triggers” page. It is located in the upper right-hand corner, in between your account name & support drop-downs.

  3. ARRRGH! First, thanks for sharing your work! I successfully went through the first post fine. I’m able to control devices with IFTTT (I did go through all of the steps if that’s a problem). I’m able to reach my comparable http://echo.echoparklake.com/ifttt/discover.php in a browser (although the appearance of the response differs – mine is basically rows rather than a coded outline would appear). I followed through the Amazon steps and can’t figure out where I’m going wrong. I’ve tried deleting and recreating the Lambda function as well. I’ve noticed a couple things and hope you can help.

    First, my domain is echo.echopark.lake to your echo.echoparklake (i.e. with a period in the middle).
    When creating the lambda function, the only choice for role is service-role/lambda_basic_execution, rather than just lambda_basic_execution.
    I’m able to see my skill in Alexa (from by PC and ios device) and it prompts me for the Amazon password and says I’m linked.
    Although it doesn’t give me any error, in the metrics tab of “login with Amazon”, it shows 0 sign-in success and 0 consent granted.
    When I tried discovering devices after activating the skill, I get an error that “Discovery could not be completed. All of your Alexa devices are offline.”
    After deleting the first function and creating a second one from scratch, I’m only able to see graphs of CloudWatch metrics, but when I click to View logs in CloudWatch, I only see graphs and can’t read logs anymore. Under log groups, it says nothing is subscribed. (as best I recall, the logs of my first attempt mentioned something about “someaccesstoken” and maybe bad syntax). Invocation counts and invocation errors are identical.

    Sorry to be so long winded, but would greatly appreciate any help getting across the finish line. If there is more information I can provide, please let me know.

    Thanks!

    Here’s the log from my webserver:
    54.162.180.250 – – [16/Dec/2016:07:10:52 +0000] “GET /ifttt/discover.php HTTP/1.1” 200 2994 “-” “-”
    54.198.103.244 – – [16/Dec/2016:08:10:57 +0000] “GET /ifttt/discover.php HTTP/1.1” 200 2994 “-” “-”
    54.165.19.132 – – [16/Dec/2016:09:11:02 +0000] “GET /ifttt/discover.php HTTP/1.1” 200 2994 “-” “-”
    54.165.19.132 – – [16/Dec/2016:09:38:20 +0000] “GET /ifttt/discover.php HTTP/1.1” 200 2994 “-” “-”
    54.173.99.41 – – [16/Dec/2016:10:38:25 +0000] “GET /ifttt/discover.php HTTP/1.1” 200 2994 “-” “-”
    52.90.140.123 – – [16/Dec/2016:11:37:38 +0000] “GET /ifttt/discover.php HTTP/1.1” 200 2994 “-” “-”
    54.205.244.239 – – [16/Dec/2016:12:37:43 +0000] “GET /ifttt/discover.php HTTP/1.1” 200 2994 “-” “-”
    54.226.11.68 – – [16/Dec/2016:15:22:18 +0000] “GET /ifttt/discover.php HTTP/1.1” 200 2994 “-” “-”
    52.90.129.231 – – [16/Dec/2016:15:37:42 +0000] “GET /ifttt/index.php?action=on&device=pictures HTTP/1.1” 200 193 “-” “-”
    54.92.253.4 – – [16/Dec/2016:16:16:40 +0000] “GET /ifttt/discover.php HTTP/1.1” 200 2994 “-” “-”
    ###.###.###.### – – [16/Dec/2016:16:20:53 +0000] “GET /ifttt/discover.php HTTP/1.1” 200 679 “-” “Mozilla/5.0 (Windows NT 10.0; WOW64; rv:48.0) Gecko/20100101 Firefox/48.0”
    54.92.253.4 – – [16/Dec/2016:16:47:05 +0000] “GET /ifttt/discover.php HTTP/1.1” 200 2994 “-” “-”
    54.92.253.4 – – [16/Dec/2016:17:08:11 +0000] “GET /ifttt/discover.php HTTP/1.1” 200 2994 “-” “-”
    54.92.253.4 – – [16/Dec/2016:17:08:12 +0000] “GET /ifttt/discover.php HTTP/1.1” 200 2994 “-” “-”
    54.92.253.4 – – [16/Dec/2016:17:08:13 +0000] “GET /ifttt/discover.php HTTP/1.1” 200 2994 “-” “-”
    54.92.253.4 – – [16/Dec/2016:17:08:14 +0000] “GET /ifttt/discover.php HTTP/1.1” 200 2994 “-” “-”
    54.92.253.4 – – [16/Dec/2016:17:11:05 +0000] “GET /ifttt/discover.php HTTP/1.1” 200 2994 “-” “-”
    54.92.253.4 – – [16/Dec/2016:17:11:06 +0000] “GET /ifttt/discover.php HTTP/1.1” 200 2994 “-” “-”
    54.92.253.4 – – [16/Dec/2016:17:11:07 +0000] “GET /ifttt/discover.php HTTP/1.1” 200 2994 “-” “-”
    54.92.253.4 – – [16/Dec/2016:17:11:07 +0000] “GET /ifttt/discover.php HTTP/1.1” 200 2994 “-” “-”
    54.92.253.4 – – [16/Dec/2016:17:13:46 +0000] “GET /ifttt/discover.php HTTP/1.1” 200 2994 “-” “-“

    1. When you say “Alexa discover my devices” do you actually see the attempt in your Apache logs? Because if you do see it, then there must be something in your discover.php that makes a wrong JSON response or something, or maybe some parameter is missing.

      Now if you don’t even see anything in your Apache log (that is the Alexa service can’t contact your server) must be something else.

      I’m not sure reading your logs if those are actually attemps of discovery or you pressing the Test button for the Lambda Service. I can see those are Amazon IPs, but not sure doing what.

      It’s pretty easy to solve if Alexa actually contact your Apache Web Server when you ask the Echo to discover your devices. If that’s the case just show me the JSON and I will tell you what’s wrong with it.

      1. Well, then I think this might be good news. Just asked alexa (on my tap) to discover my devices twice. Two additiional entries went into the log.

        54.197.38.214 – – [17/Dec/2016:03:09:05 +0000] “GET /ifttt/discover.php HTTP/1.1” 200 2994 “-” “-”
        54.146.139.26 – – [17/Dec/2016:03:47:59 +0000] “GET /ifttt/discover.php HTTP/1.1” 200 2994 “-” “-”
        54.146.139.26 – – [17/Dec/2016:03:49:58 +0000] “GET /ifttt/discover.php HTTP/1.1” 200 2994 “-” “-”

        So, here’s the discovery.php — JSON.

        “Test”);
        $discover[$num++] = $applianceDiscovered;
        }
        }
        print json_encode($discover);
        ?>

        And here’s a sample of the frst response I see in my browser:

        [{“applianceId”:”front_room_lights”,”manufacturerName”:”Scorpius”,”modelName”:”X10″,”version”:”1.0″,”friendlyName”:”front room lights”,”friendlyDescription”:”lights in the front room”,”isReachable”:true,”actions”:[“turnOn”,”turnOff”],”additionalApplianceDetails”:{“extraDetail1″:”Test”}},

        Thanks again for the help!

        1. That one looks good, but maybe there’s some kind of syntax error or an invalid character in any of your devices. Why don’t you try with just one single device in your INI file and try to discover that one? If that works, then try to add one more each time to see if you can catch which one is failing.

          1. So, I deleted all after the front room lights, and used the Tap to discover my devices again. This hit the log:

            54.159.187.78 – – [17/Dec/2016:04:22:02 +0000] “GET /ifttt/discover.php HTTP/1.1” 200 509 “-” “-”

            Unfortunately, no new devices were found. Any other thoughts?

        2. Go to the Lambda skill and select Configure Test Event. Then paste this:

          {
          “header”: {
          “namespace”: “Alexa.ConnectedHome.Discovery”,
          “name”: “DiscoverAppliancesRequest”,
          “payloadVersion”: “2”,
          “messageId”: “messageId”
          },
          “payload”: {
          “accessToken”: “token”
          }
          }

          Change the template name to something like “Alexa Smart Home – Discovery” and then press Save & Test, and show the execution results. It should be something like this:

          {
          “header”: {
          “namespace”: “Alexa.ConnectedHome.Discovery”,
          “name”: “DiscoverAppliancesResponse”,
          “payloadVersion”: “2”
          },
          “payload”: {
          “discoveredAppliances”: [
          {
          “applianceId”: “lights”,
          “manufacturerName”: “Scorpius”,
          “modelName”: “X10”,
          “version”: “1.0”,
          “friendlyName”: “lights”,
          “friendlyDescription”: “Master bedroom lights”,
          “isReachable”: true,
          “actions”: [
          “turnOn”,
          “turnOff”
          ],
          “additionalApplianceDetails”: {
          “extraDetail1”: “Test”
          }
          }
          }
          }

  4. I pasted it in. It says at the top of the screen: “There is an error in your JSON event. Please correct it before saving.” The save and test buttons are greyed out, so continuing isn’t a choice. The 2 in payloadversion statement is in red.

    1. Oh well this blog changed all the double quotes to stylized ones and you can’t paste it from here. You have to replace all double quotes with new ones, not stylized, to make them work.

      Anyway it’s a simple JSON you should know what’s wrong just taking a look at it. Here it is anyway, remember to replace all the stylized double quotes with normal ones:

      {“header”:{“namespace”:”Alexa.ConnectedHome.Discovery”,”name”:”DiscoverAppliancesRequest”,”payloadVersion”:”2″,”messageId”:”messageId”},”payload”:{“accessToken”:”token”}}

  5. Sorry, should have known to run it through an editor.

    Test Result:
    {
    “errorMessage”: “RequestId: 811215d0-c481-11e6-8d82-31a3ee109d9a Process exited before completing request”
    }

    Log:

    START RequestId: 811215d0-c481-11e6-8d82-31a3ee109d9a Version: $LATEST
    2016-12-17T17:51:57.913Z 811215d0-c481-11e6-8d82-31a3ee109d9a Input { header:
    { namespace: ‘Alexa.ConnectedHome.Discovery’,
    name: ‘DiscoverAppliancesRequest’,
    payloadVersion: ‘2’,
    messageId: ‘messageId’ },
    payload: { accessToken: ‘token’ } }
    2016-12-17T17:51:58.433Z 811215d0-c481-11e6-8d82-31a3ee109d9a SyntaxError: Unexpected token <
    at Object.parse (native)
    at IncomingMessage. (/var/task/lambda_function.js:64:43)
    at emitNone (events.js:72:20)
    at IncomingMessage.emit (events.js:166:7)
    at endReadableNT (_stream_readable.js:905:12)
    at nextTickCallbackWith2Args (node.js:437:9)
    at process._tickDomainCallback (node.js:392:17)
    END RequestId: 811215d0-c481-11e6-8d82-31a3ee109d9a
    REPORT RequestId: 811215d0-c481-11e6-8d82-31a3ee109d9a Duration: 814.37 ms Billed Duration: 900 ms Memory Size: 128 MB Max Memory Used: 7 MB
    RequestId: 811215d0-c481-11e6-8d82-31a3ee109d9a Process exited before completing request

    1. Your Lambda function fails in the JSON.parse() (line 64 right?). That’s when it is trying to parse the JSON from your server. It says it has a “<" in the response, making your JSON invalid. You have to see carefully what your PHP is responding. Looks like your web server is sending the PHP file without executing it and then the JSON parse fails in the " < ?php " line because it is not a correct JSON response. Use a sniffer like tshark or tcpdump to see it exactly what your Web Server is sending back to Amazon, but that's where the problem is.

      1. Oh my gosh! Thanks so much for your help and patience. Embarrassing, but I’ll admit to someone following me into this screw up, it was this operator’s error the whole way. I had an HTML tag at the end of discovery.php. It wasn’t a problem viewing in a browser, but it obviously made everything else fail. Alexa just found my devices! Thanks so much!

        1. I’m glad I could help!!! You’ll see how convenient it is now without using IFTTT and natively speaking to the Echo to control your X10 devices.

          I never got to program the dim and bright functions, because I never use them, but eventually I will update this post links (Lambda function and discover.php) to support those actions. It’s pretty easy to do actually.

  6. Hey there, thank you for this informative post. I’ve setup my Christmas present, a new echo and believe I have followed everything correctly. However, I’m getting an error when performing the discovery. In Cloudwatch I see:

    2017-01-01T18:30:50.864Z 6b96bac2-d050-11e6-a34b-85cba5ff7389 SyntaxError: Unexpected token <
    at Object.parse (native)
    at IncomingMessage. (/var/task/lambda_function.js:64:43)
    at emitNone (events.js:72:20)
    at IncomingMessage.emit (events.js:166:7)
    at endReadableNT (_stream_readable.js:905:12)
    at nextTickCallbackWith2Args (node.js:437:9)
    at process._tickDomainCallback (node.js:392:17)

    I can access the discover.php page via a browser and it is resolving the items in x10.ini.

    Any help would be appreciated!

    Tommy

    1. I just saw the post above mine with a similar issue. Looking at my discover.php file I do not see an additional html tag. Other thoughts of what could be the culprit? I’m about as green as you could be when it comes to this 🙁

      1. Access the discover.php via browser and then select on “View Source” on your browser and read it to see if you see anything weird. If it says “Unexpected token <" it is because there's a '<' somewhere that shouldn't be there.

        1. Well, I couldn’t find an extra < in the file. I ended up whacking the build and starting over. Got it working now, thanks again for your write up and assistance!

  7. Can you assist me? I get a timeout after 10 seconds. It is the discovery of the devices.. No connection to my server is established.

    I tried http and https. Specified in the domain list with and without subdomain, everywhere the same behavior.
    What am I doing wrong? Calling the URL in the browser works fine, returns me the following:
    [{“applianceId”:”Cam”,”manufacturerName”:”Dan”,”modelName”:”TPLink”,”version”:”1.0″,”friendlyName”:”Cam LivingRoom”,”friendlyDescription”:”Cam in Living room”,”isReachable”:true,”actions”:[“turnOn”,”turnOff”]}]
    If I add this static in the code, the device will discovered… But then I have the same problems when switching on the device

    Any hints?
    Thank you!

    1. You have to test it from the Lambda Skill Test window to see what’s going on. See my previous comments about how to configure a test event for a discovery.

  8. The Lambda code no longer works because it is Version 2 Payload and AWS no longer allows you to create code using that version. Has anyone updated their code to support Alexa V3 messages? I’m clueless for what needs to be done as I am not a programmer, I just follow instructions.

Leave a Reply