对 getThingShadow 的调用似乎没有在 lambda 函数中执行

call to getThingShadow does not seem to execute in lambda function

我正在开发一个 lambda alexa 技能处理程序,它与 aws IoT 中的事物影子集成在一起。我的问题是下面对 iotData.getThingShadow 的调用似乎没有执行。 None 的控制台消息是在回调函数中生成的,对象 objState 未被填充。这是代码片段。

   // get the shadow for the home-garage-door
    console.log('Getting thing shadow');

    iotData.getThingShadow(params, function(err, data) {
        console.log('Inside of getThingShadow callback');
        if (err){
            //Handle the error here
            console.log('Problem getting the thing shadow');
            console.log(err, err.stack);
            responseString = "I had trouble contacting the garage door, sorry";
        }
        else {
            console.log("Data back from shadow", JSON.stringify(data));
            payload = data.payload;
            objState = JSON.parse(payload);
        }
    });

    console.log('After getting the Shadow'); 

下面是我测试时生成的日志条目。有谁知道我可能做错了什么吗?

2018-01-14T22:55:15.564Z    fbdde171-f97d-11e7-bc0b-116e508011bd    Getting thing shadow
2018-01-14T22:55:16.127Z    fbdde171-f97d-11e7-bc0b-116e508011bd    After getting the Shadow
2018-01-14T22:55:16.165Z    fbdde171-f97d-11e7-bc0b-116e508011bd    objState: undefined

这是完整的代码。

/**
    Copyright 2014-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.

    Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance with the License. A copy of the License is located at

        http://aws.amazon.com/apache2.0/

    or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
*/

/**
 *
 */

/**
 * App ID for the skill
 */
 var APP_ID = 'amzn1.ask.skill.XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX'; 


/**
 * The AlexaSkill prototype and helper functions
 */
var AlexaSkill = require('./AlexaSkill');
var AWS = require('aws-sdk');

/**
 * GarageDoorIntentHandler is a child of AlexaSkill.
 * To read more about inheritance in JavaScript, see the link below.
 *
 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript#Inheritance
 */
var GarageDoorIntentHandler = function () {
    AlexaSkill.call(this, APP_ID);
};

// Extend AlexaSkill
GarageDoorIntentHandler.prototype = Object.create(AlexaSkill.prototype);
GarageDoorIntentHandler.prototype.constructor = GarageDoorIntentHandler;

GarageDoorIntentHandler.prototype.eventHandlers.onSessionStarted = function (sessionStartedRequest, session) {
    console.log("GarageDoorIntentHandler onSessionStarted requestId: " + sessionStartedRequest.requestId
        + ", sessionId: " + session.sessionId);
    // any initialization logic goes here
};

GarageDoorIntentHandler.prototype.eventHandlers.onLaunch = function (launchRequest, session, response) {
    console.log("GarageDoorIntentHandler onLaunch requestId: " + launchRequest.requestId + ", sessionId: " + session.sessionId);
    var speechOutput = "Welcome to the Automated Garage door for Alexa, you can say open the garage door or close the garage door";
    var repromptText = "You can say open or close the garage door";
    response.ask(speechOutput, repromptText);
};

GarageDoorIntentHandler.prototype.eventHandlers.onSessionEnded = function (sessionEndedRequest, session) {
    console.log("GarageDoorIntentHandler onSessionEnded requestId: " + sessionEndedRequest.requestId
        + ", sessionId: " + session.sessionId);
    // any cleanup logic goes here
};

GarageDoorIntentHandler.prototype.intentHandlers = {

    // register custom intent handlers
    "moveDoorIntent": function (intent, session, response) {

        var responseString = ''; 
        var payload = {};
        var objState;

        var desiredDoorState = intent.slots.direction.value;

        var iotData = new AWS.IotData({endpoint: "XXXXXXXXXXXXXX.iot.us-east-1.amazonaws.com"});

        console.log('iotData: ' + JSON.stringify(iotData));

        var params = { "thingName" : "<My Thing Name Was Removed for Posting>" };


        console.log('Intent: ' + JSON.stringify(intent));

        // get the shadow for the home-garage-door
        console.log('Getting thing shadow');

        iotData.getThingShadow(params, function(err, data) {
            console.log('Inside of getThingShadow callback');
            if (err){
                //Handle the error here
                console.log('Problem getting the thing shadow');
                console.log(err, err.stack);
                responseString = "I had trouble contacting the garage door, sorry";
            }
            else {
                console.log("Data back from shadow", JSON.stringify(data));
                payload = data.payload;
                objState = JSON.parse(payload);
            }
        });

        console.log('After getting the Shadow');

        switch(desiredDoorState.toUpperCase()) {
            case 'OPEN':
                console.log('objState: ' + JSON.stringify(objState));
                switch (objState.state.reported.status.toUpperCase()) {
                    case 'OPEN': 
                        responseString = "I checked and the door is already open"; 
                        break;
                    case 'CLOSED':
                        responseString = "Ok, I am closing the garage door"; 
                        params.payload = buildObjectState('desired', 'doorActivated', true, 'string');
                        iotData.updateThingShadow(params, function(err, data) {
                            if (err){
                                //Handle the error here
                                console.log(err, err.stack);
                                responseString = "I had trouble doing that, sorry";
                            }
                            else {
                                responseString = "Ok, I opened the garage door";
                                console.log("Data back from shadow", data);
                            }
                        });
                }
                break;
            case 'CLOSE':
                break;
            default: 

        } // switch

        response.tellWithCard(responseString, "Open or Close the Garage Door", responseString);
    },

    "getDoorStateIntent": function (intent, session, response) {
        response.tellWithCard("You can say hello to me!", "You can say hello to me!");
    }
};


/**
*   Helper function to build the state object for the shadow document
**/

function buildObjectState (section, key, value, format) {

    var objState =  {state: {}};

    objState.state[section] = {};
    objState.state[section][key] = value;


    if (format === 'object') {
        return objState;
    } else if (format === 'string') {
        return JSON.stringify(objState);
    } else return; 

}

// Create the handler that responds to the Alexa Request.
exports.handler = function (event, context) {

    console.log('received an event'); 
    // Create an instance of the garageDoorIntentHandler.
    var garageDoorIntentHandler = new GarageDoorIntentHandler();
    garageDoorIntentHandler.execute(event, context);
};

在 Javascript 中,代码继续执行到下一行,而不等待异步函数调用完成。您的代码中的错误是因为您访问 objState 时它还没有值。

查看下面的评论以更好地理解它。

// This is called BEFORE iotData.getThingShadow()
console.log('Getting thing shadow');

iotData.getThingShadow(params, function(err, data) {
    console.log('Inside of getThingShadow callback');
    if (err) {
        //Handle the error here
        console.log('Problem getting the thing shadow');
        console.log(err, err.stack);
        responseString = "I had trouble contacting the garage door, sorry";
    } else {
        console.log("Data back from shadow", JSON.stringify(data));
        payload = data.payload;
        // This is populated AFTER iotData.getThingShadow() finishes
        objState = JSON.parse(payload);
        // This is where you put the code that you want to happen AFTER 
        // iotData.getThingShadow() finishes.
        console.log(objState)
    }
});

// This will execute without waiting for iotData.getThingShadow() to finish
console.log('After getting the Shadow');

// This will be undefined since iotData.getThingShadow() did NOT return 
// yet and objState has NOT been populated
console.log(objState)

因此,要修复它,请将您希望在 iotData.getThingShadow() 完成后发生的代码移到回调函数中。

您的 IOT 对象似乎嵌套在 Intent 中。

我会移动您的 IoT 影子并初始化为它们自己的影子

/Initialize Up Top of Script
AWS.config.region = process.env.IOT_REGION;
var IOT_Data = new AWS.IotData({endpoint: process.env.IOT_ENDPOINT});
var IOT_Thing = process.env.IOT_THING_NAME;

然后我使用辅助函数:

function getShadow(dataObj){
    IOT_Data.getThingShadow(dataObj, function (err, data) {
      if (err) console.log(err, err.stack); // an error occurred
      else     console.log(data);           // successful response
    })
}

您的 IOT 对象现在随处可用。我已经在多种技能中使用了这个设置,没有问题。