1
votes

I'm trying to control my raspberry using Amazon Alexa, IoT and Lambda. What I got working so far:

  • Setting up raspberry as IoT device and being able to publish and subscribe to a topic (Testes using the IoT Client)
  • Setting up a test lambda node.js script
  • Setting up a test Alexa Skill that triggers an intent in my lambda script

Here's the intent handling in my node.js script:

switch(event.request.intent.name) {
      case "testone":
        var config = {};
        config.IOT_BROKER_ENDPOINT      = "restAPILinkFromIoT".toLowerCase();
        config.IOT_BROKER_REGION        = "us-east-1";

        //Loading AWS SDK libraries
        var AWS = require('aws-sdk');
        AWS.config.region = config.IOT_BROKER_REGION;
        var iotData = new AWS.IotData({endpoint: config.IOT_BROKER_ENDPOINT});
        var topic = "/test";
        var output = "test output without publish"
        var params = {
            topic: topic,
            payload: "foo bar baz",
            qos:0
        };
        iotData.publish(params, (err, data) => {
            if (!err){
               output = "publish without error"
                this.emit(':tell', tell);
            } else {
                output = err
            }
        });
        context.succeed(
              generateResponse(
                buildSpeechletResponse(output, true),
                {}
              )
            )
        break;
        ...

Basically the script should either return "publish without error" or the error message. The Problem it always returns "test output without publish". It seems like the publish function (or at least the callback function) is never triggered. I also don't see a message in the topic.

Am I doing something wrong?

Thanks in advance!

1

1 Answers

1
votes

This part:

   iotData.publish(params, (err, data) => {
        if (!err){
           output = "publish without error"
            this.emit(':tell', tell);
        } else {
            output = err
        }
    });

Is an asynchronous method call. The iotData.publish() method will return immediately. Then the anonymous callback function with the if(!err) ... code block will be executed at some future time once the asynchronous call completes.

That means that this part:

   context.succeed(
          generateResponse(
            buildSpeechletResponse(output, true),
            {}
          )
        )

Is being called before the IoT publish() call has completed, and before the output variable has anything assigned to it.

To fix this you could move your code into the callback itself:

   iotData.publish(params, (err, data) => {
        if (!err){
           context.succeed(generateResponse(
            buildSpeechletResponse("publish without error", true),
            {});
          )
        } else {
           context.succeed(generateResponse(
            buildSpeechletResponse(err, true),
            {});            
        }
    });

As a side note, I really don't recommend trying to learn NodeJS and AWS Lambda and IoT at the same time. I recommend going with Python if you need to learn a language at the same time you are learning Lambda and other AWS stuff because you don't have to deal with these asynchronous callback issues in Python.