AWS Lambda Proxy Custom Alexa Skill when you don't have https

No idea mate.

I am getting the same error: “errorMessage”: "Exception: TypeError: Cannot read property ‘application’ of undefined”

Any help would be appreciated.

Hi guys,

apologies for the delay, I was traveling. Here’s my code, hope it helps.

"use strict"

var http = require('http');
var URLParser = require('url');

exports.handler = function (json, context) {
    try {
        // A list of URL's to call for each applicationId
        var handlers = {
            'appId':'url',
            'YOUR_SKILL_ID':'http://YOUR_HA_ADDRESS:8123/api/alexa?api_password=YOUR_PWD'
        };

        // Look up the url to call based on the appId
        var url = handlers[json.session.application.applicationId];
        if (!url) { context.fail("No url found for application id"); }
        var parts = URLParser.parse(url);

        var post_data = JSON.stringify(json);

        // An object of options to indicate where to post to
        var post_options = {
            host: parts.hostname,
            auth: parts.auth,
            port: (parts.port || 80),
            path: parts.path,
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'Content-Length': post_data.length
            }
        };
        // Initiate the request to the HTTP endpoint
        var req = http.request(post_options,function(res) {
            var body = "";
            // Data may be chunked
            res.on('data', function(chunk) {
                body += chunk;
            });
            res.on('end', function() {
                // When data is done, finish the request
                context.succeed(JSON.parse(body));
            });
        });
        req.on('error', function(e) {
            context.fail('problem with request: ' + e.message);
        });
        // Send the JSON data
        req.write(post_data);
        req.end();        
    } catch (e) {
        context.fail("Exception: " + e);
    }
};
1 Like

Hi thanks for the code.

Can I ask you what runtime are you using?

sure - Node JS 4.3.

Make sure your router redirects the request to the right port / IP address for your HASS server (accessible from outside network).

Hi I am getting this error:

{
  "errorMessage": "Exception: TypeError: Cannot read property 'application' of undefined"
}

Any idea what could be the problem?

Thanks.

Thanks. I have tested this and it works for custom skills. However, I can’t find a way to make it works for Flash Briefing skill. The Feed URL in Configuration cannot accept arn:aws:lambda:us-east-1:XXXXXXXXXXX:function:YYYYYYYYYY.

Please help.

If you goto AWS lambda -> functions -> <your_funcation> -> Test and you get the below error, I don’t think that is exactly a true error. I have another working lambda function that spits out the same message.

{
  "errorMessage": "Exception: TypeError: Cannot read property 'application' of undefined"
}

I’m getting this error when asking where a person is. Errors is from hass.

17-02-18 13:20:43 WARNING (MainThread) [homeassistant.core] Unable to find service notify/notify

I think something is missing in the config or the example is incomplete?

Update:
So I got the example working of where are we and where is [name]

I commented out action with “notify.notify”. I think the point of that is a notification example. Not literally notify.notify. Now to expand on it…

I am able to make it work using ‘http’, but how do we make this work with ‘https’ Home Assistant URL.

i am getting below avs lambda error while using ‘https’

The remote endpoint could not be called, or the response it returned was invalid.

var http = require('http');
var URLParser = require('url');

exports.handler = function (json, context) {
    try {
        // A list of URL's to call for each applicationId
        var handlers = {
            'appId':'url',
            'amzn1.ask.skill.xxxx-xxxx-xxxx-xxxx-xxx':'https://xxxx.duckdns.org/api/alexa?api_password=xxxx'
        };

        // Look up the url to call based on the appId
        var url = handlers[json.session.application.applicationId];
        if (!url) { context.fail("No url found for application id"); }
        var parts = URLParser.parse(url);

        var post_data = JSON.stringify(json);

        // An object of options to indicate where to post to
        var post_options = {
            host: parts.hostname,
            auth: parts.auth,
            port: (parts.port || 80),
            path: parts.path,
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'Content-Length': post_data.length
            }
        };
        // Initiate the request to the HTTP endpoint
        var req = http.request(post_options,function(res) {
            var body = "";
            // Data may be chunked
            res.on('data', function(chunk) {
                body += chunk;
            });
            res.on('end', function() {
                // When data is done, finish the request
                context.succeed(JSON.parse(body));
            });
        });
        req.on('error', function(e) {
            context.fail('problem with request: ' + e.message);
        });
        // Send the JSON data
        req.write(post_data);
        req.end();        
    } catch (e) {
        context.fail("Exception: " + e);
    }
};

I got it working by changing ‘http’ to ‘https’ and port to 443.

var https = require('https');
var URLParser = require('url');

exports.handler = function (json, context) {
    try {
        // A list of URL's to call for each applicationId
        var handlers = {
            'appId':'url',
            'amzn1.ask.skill.xxxx-xxxx-xxxx-xxxx-xxxx':'https://xxxx.duckdns.org/api/alexa?api_password=xxxx'
        };

        // Look up the url to call based on the appId
        var url = handlers[json.session.application.applicationId];
        if (!url) { context.fail("No url found for application id"); }
        var parts = URLParser.parse(url);

        var post_data = JSON.stringify(json);

        // An object of options to indicate where to post to
        var post_options = {
            host: parts.hostname,
            auth: parts.auth,
            port: (parts.port || 443),
            path: parts.path,
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'Content-Length': post_data.length
            }
        };
        // Initiate the request to the HTTPS endpoint
        var req = https.request(post_options,function(res) {
            var body = "";
            // Data may be chunked
            res.on('data', function(chunk) {
                body += chunk;
            });
            res.on('end', function() {
                // When data is done, finish the request
                context.succeed(JSON.parse(body));
            });
        });
        req.on('error', function(e) {
            context.fail('problem with request: ' + e.message);
        });
        // Send the JSON data
        req.write(post_data);
        req.end();        
    } catch (e) {
        context.fail("Exception: " + e);
    }
};

This requires that you have set up SSL and have a signed certificate, I suppose? (In that case, you can also use Home Assistant’s Alexa component directly (see here), right?)

Do you know what the securtiy implications of this approach are? I would think that anyone who could intercept the HTTP request could read your password (since that’s somewhere in the URL that is sent unencrypted), which seems to make it very insecure, but I’m not an expert, so I hope someone can explain why I’m wrong here.

No. It does not require SSL (as the thread title states). I think the security implications are relatively clear when not using SSL. I also think other options require port 443 but I’m not sure so this solution may have that advantage as well.

Thanks for the reply. My question about needing SSL was actually meant for @hareeshmu’s approach, so I edited my question to make that clearer. (Sorry, it wasn’t so clear before. I don’t understand why it is not showing up as a reply to his comment.)

Regarding the security of not using SSL: so I am right in saying that the password is sent in plain text when not using SSL? Then it would be nice to warn people about that.

I dont have any Echo device, I’m using the software Alexa AVS Service
So, I believe HA Alexa built-in component will not work with AVS Service. Hence chose the custom skill method.
I am running HA in SSL using LetsEncrypt certificates.

Has anyone tried setting this up using ngork?

Hi all
kinda new here and trying to set up an alexaPi I have all the amazon stuff done or at least a lot of little green checks so now I am here on the page and was using the script from the top page and scrolled down read that it didn’t work and I should use the one in the middle of the page can I get some help on what I need to use for my Lambda code

Thanks Dale

Are you able to make it work, In which part you are having issues?

Hi,

I’m trying to set this up following the Guide in the first post.
This is my first AWS contact, so bear with me.

I selected “alexa-skills-kit-color-expert” and got to this point, but there’s no “Alexa Skills Kit” available in the dropdown menu. I only get those:

API Gateway
AWS IoT
CloudFront
CloudWatch Events - Schedule
CloudWatch Logs
CodeCommit
Cognito Sync Trigger
DynamoDB
Kinesis
S3
SNS

Did I select something wrong at one point? Or which one do I chose?

TIA,
Sebastian

EDIT: I figured it out. Apparently Alexa Skills Kit is not available in every data center.

I saw above how to do this with https. Not sure if it’s so people can stay on 8123 but set the above code to 443 so Amazon will accept it. That said, the instructions do not seem to flow with the current environment at Amazon. Anyone know an updated way to implement this?

Also looks like this uses an API password method which I understand isn’t supported anymore.