The Haaska Super Thread

Yes mine was incorrect and fixing it fixed my issue… yours seems fine… so might be a different issue.

Did you add the Alexa skill from the app or from http://alexa.amazon.com/ ?

And if yes how is the skill marked (the icon)? it should say something like devES or devGB or devUS

Did you add the Alexa skill from the app or from http://alexa.amazon.com/ ?

I added from website https://alexa.amazon.es

And if yes how is the skill marked (the icon)?

Yes, icon appears with devES

imagen

There is a way to test or debug if lambda works with the skill? or something similar to check where can be the problem?
thanks

You definetly don’t have the same issue I had as my skill was getting created in the wrong region whilst yours is in the correct region.

In AWS there is a service called cloudwatch and it will create logs every time the lambda function is called. You can try and attempt to “discover devices” and see if new logs appear which would indicate if lambda ran or not

I’m a new HA user. 3 days up and running on a Pi4. I have gotten through all of the steps and I’m at the testing phase getting the following error:

{
“errorMessage”: “404 Client Error: Not Found for url: https://XXXXXX.duckdns.org/api/alexa/smart_home”,
“errorType”: “HTTPError”,
“stackTrace”: [
[
“/var/task/haaska.py”,
111,
“event_handler”,
“return ha.post(‘alexa/smart_home’, event, wait=True)”
],
[
“/var/task/haaska.py”,
66,
“post”,
“r.raise_for_status()”
],
[
“/var/task/requests/models.py”,
940,
“raise_for_status”,
“raise HTTPError(http_error_msg, response=self)”
]
]
}

I did mask out my URL, and I am port forwarding 443 external to 8123. I’m able to open https://XXXXXX.duckdns.org without any issue.

Any ideas?

Ok… I’m a little embarrassed over here. In the initial instructions after adding:

api:

alexa:
  smart_home:

to my config.yaml file I tested the config, but forgot to restart HASS. Oops. Did that and I’m now all set.

Hi to everyone,

After continue trubleshooting my problem, i’m watching logs from Cloudwatch and from amazon skill developer.
I think that i have configured correctly the links between both systems, but in logs i can’t see that the skill call to my lambda function.

These are my logs amazon skill developer:

imagen

Inside of them in the Directive: SpeechSynthesizer.Speak I can see that there is a hacer and then a payload part.

{
“header”: {
“namespace”: “SpeechSynthesizer”,
“name”: “Speak”,
“messageId”: “7a37c530-b8b7-4485-xxxx-xxxxxxx”,
“dialogRequestId”: “1229fe5b-ff98-41f1-xxxx-xxxxxx”,
“keys”: {
“isBlocking”: true,
“channel”: “audio”
}
},
“payload”: {
“caption”: “Iniciando detección. Esto tardará unos momentos. Enciende ahora tus nuevos dispositivos y ponlos en modo detección si es necesario.”,
“url”: “https://tinytts-eu-west-1.amazon.com/3/89203f66-58ec-xxxx-xxxx-xxxxxxx-95b8e6/14/16xxxxxx/ca0e2xxxxxxxxxxx/resource.mp3”,
“format”: “AUDIO_MPEG”,
“token”: “amzn1.as-ct.v1.HomeAutomation#ACRI#HomeAutomation.StartDiscovery.aec40220-xxxx-xxxx-xxxx-e751xxxxx”,
“ssml”: “<prosody volume="x-loud">Iniciando detección. Esto tardará unos momentos. Enciende ahora tus nuevos dispositivos y ponlos en modo detección si es necesario.Discovery.GenericDiscoveryStartedHomeAutomationes_ESdefault8926c5a3-9fb7-xxxx-xxx-xxxxxxxxx51”
}
}

Please can tell me soneone if try to use testing of skill in amazon developer, the skill in the payload, appear their info about lambda?

In cloudwatch logs i only see this:

imagen

There is no much info inside…

thanks

thanks

is it possible to use haaska to pass camera streams to echo devices with a screen?

When Testing the Lambda function and I am getting an error

START RequestId: 4aee404f-5dec-4cec-ba02-caa762579de6 Version: $LATEST
[ERROR] Runtime.ImportModuleError: Unable to import module 'lambda_function': No module named 'lambda_function'END RequestId: 4aee404f-5dec-4cec-ba02-caa762579de6
REPORT RequestId: 4aee404f-5dec-4cec-ba02-caa762579de6	Duration: 1.57 ms	Billed Duration: 2 ms	Memory Size: 128 MB	Max Memory Used: 52 MB	Init Duration: 121.83 ms	

I have tried creating a Lambda function in both Python 3.6 and 3.8 though it shouldn’t matter. Everything else I believe I followed to a T.

Any Ideas?

I have been able to get this to work with Alexa on Firestick TV, but there is a bug/restriction in the code that only allows this work for port 443.

Yeah after I added the external_url internal_url and my Amazon region I was able to get my camera to work I am using port 443 so all good

Complete noob here, just starting to learn HA… when at the testing portion I get the error:
“errorMessage”: “HTTPConnectionPool(host=‘localhost’, port=8123): Max retries exceeded with url: /api/alexa/smart_home (Caused by NewConnectionError(’<urllib3.connection.HTTPConnection object at 0x7feeff01ccc0>: Failed to establish a new connection: [Errno 111] Connection refused’,))”,
“errorType”: “ConnectionError”,

Help? Please

Hi nah336.

Just sounds like you need to hit “Deploy” in the code box after editing the config file from the default localhost address (ensure you are in config, not the .sample).

1 Like

Hi,
ive got the following problem when i test in the aws:

START RequestId: 13bd53aa-4b60-45a0-9b0c-161b7d4d49e4 Version: $LATEST
Bad handler ‘haaska_event_handler’: not enough values to unpack (expected 2, got 1)

Is there anybody that can help me please…

Thanks a lot!!

Is it possible to set this up in such a way as to know WHO is speaking? Basically I want to create an alexa routine where I (and my wife) can say “I am going to bed” and alexa tells Home Assistant “Steve just said he is going to bed” and let HA flip the Steve’s in Bed boolean (and likewise for my wife).

Is that a doable thing with this?

1 Like

Steve,

I don’t know anything about Haaska, as I haven’t used it, but when a few of us were using EventGhost, we achieved it. I have pasted a modified AWS Lambda function here that might help you/others. This lambda function will return the session id, request id, spoken text, echo device id, and person id (if voice profiling is enabled). Currently, the way I use this, is I have a text helper entity created in HA. Then, by setting the values at the top of this Lambda function - an Alexa skill calls this lambda - and passes the information to the HA text helper entity. I would add that it would be trivial to change this to fire an event instead of updating an entity… I suppose having it fire an event would probably make more sense.

/**
 * EchoToHA - A custom Amazon Alexa Skill Kit that updates the state/attributes of a text helper entity in Home Assistant
 * v1.0(20210405)
 * 
 * Ryan Gerken (rdgerken@<googlesemailservice>.com)
 * 
 * Original Credits go to (from the EventGhost Project):
 * Brandon Simonsen (m19brandon.shop@<googlesemailservice>.com)
 * https://github.com/m19brandon/EchoToEventGhost
 * EventGhost Thread: http://www.eventghost.net/forum/viewtopic.php?f=2&t=7429
 */

// --------------- Variables that need to be set ----------------

var https = require('https');
var HA_ip = '<HOMEASSISTANTEXTERNALURL>';
var HA_Port = '<HOMEASSISTANTEXTERNALPORT>';
var HA_token = '<HOMEASSISTNATLONGLIVETOKEN>';
var HA_entityid = '<HOMEASSISTANTENTITYID>';

// Adding Security if you want.
//This ID is can be found under the Alexa tab on the amazon developer console page
//Goto https://developer.amazon.com/edw/home.html#/skills > Click 'View Skill ID'
//var Alexa_Skill_ID = 'amzn1.ask.skill.#';

var HA_uri = '';
var deviceId = '';
var personId = '';

// --------------- Main handler -----------------------

// Route the incoming request based on type (LaunchRequest, IntentRequest,
// etc.) The JSON body of the request is provided in the event parameter.
exports.handler = function (event, context) {
    console.log(event);
    try {
        console.log('event.session.application.applicationId=' + event.session.application.applicationId);
        /**
        * Adding Security if you want.
        * Uncomment this if statement and populate with your skill's application ID to
        * prevent someone else from configuring a skill that sends requests to this function.
        */
        /*
        if (event.session.application.applicationId !== Alexa_Skill_ID) {
            console.log('Check the Alexa_Skill_ID value, it did not match')
            console.log('event.session.application.applicationId=' + event.session.application.applicationId);
            console.log('versus');
            console.log('Alexa_Skill_ID=' + Alexa_Skill_ID);
            context.fail('Invalid Application ID');
        }
        */

        // get the deviceId if present
        try {
            deviceId="";
            if( typeof event.context.System.device.deviceId !== 'undefined' ) {
                deviceId = event.context.System.device.deviceId;
                console.log('deviceId='+deviceId);
            } else {
                console.log('deviceId not found');
            }
        } 
        catch (err) {
            console.log('deviceId not found');
        }
        
        // get the personId if present
        try {
            personId="";
            if( typeof event.context.System.person.personId !== 'undefined' ) {
                personId = event.context.System.person.personId;
                console.log('personId='+personId);
            } else {
                console.log('personId not found');
            }
        } 
        catch (err) {
            console.log('personId not found');
        }
        
        if (event.session.new) {
            onSessionStarted({requestId: event.request.requestId}, event.session);
        }
        if (event.request.type === 'IntentRequest') {
            onIntent(event.request,
                     event.session,
                     function callback(sessionAttributes, speechletResponse) {
                         context.succeed(buildResponse(sessionAttributes, speechletResponse));
                     });
        } else if (event.request.type === 'SessionEndedRequest') {
            onSessionEnded(event.request, event.session);
            context.succeed();
        }
    } catch (e) {
        context.fail('Exception: ' + e);
    }
};

// --------------- Helpers that build all of the responses -----------------------
function buildSpeechletResponse(title, output, repromptText, shouldEndSession) {
    return {
        outputSpeech: {
            type: 'PlainText',
            text: output
        },
        card: {
            type: 'Simple',
            title: 'Echo To HA - ' + title,
            content: output
        },
        reprompt: {
            outputSpeech: {
                type: 'PlainText',
                text: repromptText
            }
        },
        shouldEndSession: shouldEndSession
    };
}

function buildResponse(sessionAttributes, speechletResponse) {
    return {
        version: '1.0',
        sessionAttributes: sessionAttributes,
        response: speechletResponse
    };
}

// --------------- Events -----------------------

/**
 * Called when the session starts.
 */
function onSessionStarted(sessionStartedRequest, session) {
    console.log('onSessionStarted requestId=' + sessionStartedRequest.requestId + ', sessionId=' + session.sessionId);
}

/**
 * Called when the user specifies an intent for this skill.
 */
function onIntent(intentRequest, session, callback) {
    console.log('onIntent requestId=' + intentRequest.requestId + ', sessionId=' + session.sessionId);

    var intent = intentRequest.intent;
    //var intentName = intentRequest.intent.name;
        
    // Whatever the Intent is, pass it straight through to Home Assistant
    callEchoToHA(intent,intentRequest.requestId,session,callback);
}

/**
 * Called when the user ends the session.
 * Is not called when the skill returns shouldEndSession=true.
 */
function onSessionEnded(sessionEndedRequest, session) {
    console.log('onSessionEnded requestId=' + sessionEndedRequest.requestId + ', sessionId=' + session.sessionId);
    // Add cleanup logic here
}

// --------------- Functions that control the skill's behavior -----------------------

/**
 * Determines if a session should end based on string search in EG response
 */
function Get_shouldEndSession(string, def)
{
    var end = def;
    if(string.indexOf('EndSession: ') > -1) {
        var lines = string.split('\n');
        for(var i = 0;i < lines.length;i++){
            if(lines[i].indexOf('EndSession: ') > -1) {
                var es = lines[i].split('EndSession:')[1].trim();
                if (es === 'yes') {
                    end = true;
                }
                if (es === 'no') {
                    end = false;
                }
            }
        }
    }
    return end;
}

/**
 * This is the main function, this is what sends the intent to HA and then
 * determine what to do based on the response HA's response
 */

function callEchoToHA(intent,requestId,session,callback)
{
    this.cb = callback;
    var cardTitle = 'Home Automation';
    var shouldEndSession = true;
    console.log('SessionEnd='+shouldEndSession.toString());

    var speechOutput = '';
    var repromptText = 'I could not understand, please try again';
    
    //Pull the spoken text and format
    var actionSlot = intent.slots.Action;
    var setAction = actionSlot.value.toLowerCase();
    var setActionURI = require('querystring').escape(setAction);
    console.log('callEchoToHA - Intent name = ' + intent.name);
    console.log('callEchoToHA - Intent = ' + setAction);
    console.log('callEchoToHA - Intent = ' + setActionURI);

    HA_uri = '/api/states/' + HA_entityid;
    console.log('Full URI: ' + HA_uri);
    //Build body for the POST data to Home Assistant
    var postbody = '{"state": "' + decodeURIComponent(setActionURI) + '","attributes": {"Session": "' + session.sessionId + '","Request": "' + requestId + '","Device": "' + deviceId + '","Person": "' + personId + '"}}';
    sendToHA(HA_uri,postbody,function(body) {
        var ha_results = body;
        if (ha_results != 'Error') {
            console.log('Success Body: ' + ha_results);
            //Parse the Body results from HA, if the command was unknown we will reprompt
            if((ha_results.indexOf('intent: UNKNOWN') > -1)||(ha_results.indexOf('cmd is unknown:') > -1)) {
                console.log('callEchoToHA - Results were a unknown command, we will reprompt');
                speechOutput = 'Sorry but I did not understand, ' +setAction + ', please try again';
                shouldEndSession = Get_shouldEndSession(ha_results,shouldEndSession);
            } else {
                console.log('callEchoToHA - Results were a known command, all is good');
                //Return speech to Alexa not currently implemented-always drops to Else below
                if(ha_results.indexOf('Return Msg: ') > -1) {
                    var lines = ha_results.split('\n');
                    for(var ix = 0;ix < lines.length;ix++){
                        if(lines[ix].indexOf('Return Msg: ') > -1) {
                            var rtn_msg = lines[ix].split('Msg:')[1].trim();
                            if (rtn_msg !== '') {
                                setAction = rtn_msg;
                                shouldEndSession = Get_shouldEndSession(ha_results,shouldEndSession);
                            }
                        }
                    }
                    speechOutput = setAction;
                } else {
                    speechOutput = 'Got it, working on the command, '+setAction;
                    shouldEndSession = Get_shouldEndSession(ha_results,shouldEndSession);
                }
            }
        } else {
            console.log('callEchoToHA - Error, Home Assistant response error');
            speechOutput = 'Error, Home Assistant response error';
        }
    console.log('SessionEnd='+shouldEndSession.toString());
    this.cb({},buildSpeechletResponse(cardTitle, speechOutput, repromptText, shouldEndSession));
    }.bind(this));
}

/**
 * Reusable function that handle the post to Home Assistant
 */
function sendToHA(uri,postdata,cb) {
// Options included where we should send the request to with or without basic auth
    HA_uri = uri;
    var post_options = '';
    post_options = {
        host: HA_ip,
        port: HA_Port,
        path: HA_uri,
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            'Authorization': 'Bearer ' + HA_token
        }
    };
    
    console.log('sendToHA - Sending request to ' + post_options.host + ':' + post_options.port + post_options.path);
    // Set up the post request
    var body='';
    var reqPost =  https.request(post_options, function(res) {
        console.log("statusCode: ", res.statusCode);
        res.setEncoding('utf8');
        res.on('data', function (chunk) {
            body += chunk;
        });
        res.on('end', function () {
           console.log("Result", body.toString());
           cb(body);
        });
        res.on('error', function () {
          console.log("Result Error", body.toString());
        });
    });
    console.log('sendToHA - Posting:', postdata);
    reqPost.write(postdata);
    reqPost.end();
}
// --------------- End ----------------
1 Like

I’m very interested in determining who is speaking too.

I just discovered Haaska searching for this very topic. I’m not entire sure how it works, but I’m assuming the Alexa integration would have to support this extra metadata too. Can someone more knowledgable than me comment?

Hello,

I also try to get alexa to run.
I followed the instructions (some buttons seem to be named differently now). Unfortunately, the test does not work for me:

{
  "errorMessage": "Unable to import module 'lambda_function'"
}

I have now tried to implement it a second time exactly according to the instructions and get the same error … can someone help me?

1 Like

I have the same issue. Can someone help?

Okay, so Imma flip the script: I want to temporarily DEACTIVATE Haaska. (I know, right?)

Basically, I have had to kill the port forward for a bit due to some overly-paranoid complaints around the house about it creating a security risk, and I want to deactivate things TEMPORARILY and see how well I can get by without it.

Is it as easy as commenting out the alexa: block in configuration.yaml?

(Also, on the AWS side, I don’t see an obvious way to temporarily put a process on hold, but I’m not sure that matters if I deactivate things on the local side. True?)

Hi everyone, is anyone else having issues with their Haaska connection in the last week?

None of my devices were responding when I tried to call them via Alexa. I noticed Alexa wasn’t discovering any new devices.

I’ve since gone back to double check AWS and I’m getting significant issues. The haaska lambda tests fail with weird errors.

I then tried reuploading the Haaska config zip file and AWS errors out saying to check you are using a supported browser. I’ve tried this in both chrome and firefox.

Does this sound more like an AWS problem than Haaska?