【问题标题】:I can't send the state of my device to Alexa我无法将设备状态发送给 Alexa
【发布时间】:2021-11-02 16:20:20
【问题描述】:

我正在尝试将我的设备状态发送到 Alexa,但问题是它给了我一个错误 400,我什至使用邮递员进行了尝试,但我仍然无法从事件 uri 中获得积极响应。我什至不知道是否可以使用 AJAX 发送请求,或者我必须使用 aws-sdk 中的任何奇怪方法,因为我不太熟悉它,任何帮助将不胜感激!

index.js

'use strict';

const AWS = require('aws-sdk');
const axios = require('axios');
const {
    "v4": uuid
} = require('uuid');

AWS.config.update({
    region: 'eu-west-1'
});

let AlexaResponse = require("./alexa/skills/smarthome/AlexaResponse");


exports.handler = async function(event, context) {

    // Dump the request for logging - check the CloudWatch logs
    console.log("index.handler request  -----");
    console.log(JSON.stringify(event));

    if (context !== undefined) {
        console.log("index.handler context  -----");
        console.log(JSON.stringify(context));
    }

    // Validate we have an Alexa directive
    if (!('directive' in event)) {
        let aer = new AlexaResponse({
            "name": "ErrorResponse",
            "payload": {
                "type": "INVALID_DIRECTIVE",
                "message": "Missing key: directive, Is request a valid Alexa directive?"
            }
        });
        return sendResponse(aer.get());
    }

    // Check the payload version
    if (event.directive.header.payloadVersion !== "3") {
        let aer = new AlexaResponse({
            "name": "ErrorResponse",
            "payload": {
                "type": "INTERNAL_ERROR",
                "message": "This skill only supports Smart Home API version 3"
            }
        });
        return sendResponse(aer.get())
    }

    let namespace = ((event.directive || {}).header || {}).namespace;


    if (namespace.toLowerCase() === 'alexa.authorization') {

        let aar = new AlexaResponse({
            "namespace": "Alexa.Authorization",
            "name": "AcceptGrant.Response",
        });

        return sendResponse(aar.get());
    }


    if (namespace.toLowerCase() === 'alexa.discovery') {
        let adr = new AlexaResponse({
            "namespace": "Alexa.Discovery",
            "name": "Discover.Response"
        });
        let capability_alexa = adr.createPayloadEndpointCapability();
        let capability_alexa_powercontroller = adr.createPayloadEndpointCapability({
            "interface": "Alexa.PowerController",
            "supported": [{
                "name": "powerState"
            }]
        });

        adr.addPayloadEndpoint({
            "friendlyName": "Switch Demo",
            "endpointId": "switch-demo-01",
            "capabilities": [capability_alexa, capability_alexa_powercontroller]
        });

        return sendResponse(adr.get());
    }


    let power_state_value;
    let endpoint_id = event.directive.endpoint.endpointId;
    let token = event.directive.endpoint.scope.token;
    let correlationToken = event.directive.header.correlationToken;

    if (namespace.toLowerCase() === 'alexa.powercontroller') {
        power_state_value = "OFF";
        if (event.directive.header.name === "TurnOn")
            power_state_value = "ON";


        console.log(`TOKEN: ${token}`)
        console.log(`CORRELATION TOKEN: ${correlationToken}`)


        let ar = new AlexaResponse({
            "correlationToken": correlationToken,
            "token": token,
            "endpointId": endpoint_id
        });
        ar.addContextProperty({
            "namespace": "Alexa.PowerController",
            "name": "powerState",
            "value": power_state_value
        });

        // Check for an error when setting the state
        let state_set = sendDeviceState(endpoint_id, "powerState", power_state_value);

        if (!state_set) {
            return new AlexaResponse({
                "name": "ErrorResponse",
                "payload": {
                    "type": "ENDPOINT_UNREACHABLE",
                    "message": "Unable to reach endpoint database."
                }
            }).get();
        }
        return sendResponse(ar.get());
    }

    if (event.directive.header.name === 'ReportState') {
        console.log("Report State Axios Code")
        axios({
                method: 'POST',
                url: 'https://api.eu.amazonalexa.com/v3/events',
                data: {
                    "event": {
                        "header": {
                            "namespace": "Alexa",
                            "name": "StateReport",
                            "messageId": uuid(),
                            "correlationToken": correlationToken,
                            "payloadVersion": "3"
                        },
                        "endpoint": {
                            "scope": {
                                "type": "BearerToken",
                                "token": token,
                            },
                            "endpointId":endpoint_id,
                        },
                        "payload": {}
                    },
                    "context": {
                        "properties": [{
                            "namespace": "Alexa.PowerController",
                            "name": "powerState",
                            "value": power_state_value,
                            "timeOfSample": new Date().toISOString(),
                            "uncertaintyInMilliseconds": 0
                        }]
                    }
                }
            })
            .then(function(response) {
                console.log(response);
            });
    }


};




function sendResponse(response) {
    // TODO Validate the response
    console.log("index.handler response -----");
    console.log(JSON.stringify(response));
    return response
}




function sendDeviceState(endpoint_id, state, value) {
    let dynamodb = new AWS.DynamoDB({
        apiVersion: '2012-08-10'
    });

    let key = state + "Value";
    let attribute_obj = {};
    attribute_obj[key] = {
        "Action": "PUT",
        "Value": {
            "S": value
        }
    };

    let request = dynamodb.updateItem({
        TableName: "SampleSmartHome",
        Key: {
            "ItemId": {
                "S": endpoint_id
            }
        },
        AttributeUpdates: attribute_obj,
        ReturnValues: "UPDATED_NEW"
    });

    console.log("index.sendDeviceState request -----");
    console.log(request);

    let response = request.send();

    console.log("index.sendDeviceState response -----");
    console.log(response);
    return true;
}

AlexaResponse.js

'use strict';

const {
    "v4": uuid
} = require('uuid');
const axios = require('axios');

/**
 * Helper class to generate an AlexaResponse.
 * @class
 */
class AlexaResponse {

    /**
     * Check a value for validity or return a default.
     * @param value The value being checked
     * @param defaultValue A default value if the passed value is not valid
     * @returns {*} The passed value if valid otherwise the default value.
     */
    checkValue(value, defaultValue) {

        if (value === undefined || value === {} || value === "")
            return defaultValue;

        return value;
    }

    /**
     * Constructor for an Alexa Response.
     * @constructor
     * @param opts Contains initialization options for the response
     */
    constructor(opts) {

        if (opts === undefined)
            opts = {};

        if (opts.context !== undefined)
            this.context = this.checkValue(opts.context, undefined);

        if (opts.event !== undefined)
            this.event = this.checkValue(opts.event, undefined);
        else
            this.event = {
                "header": {
                    "namespace": this.checkValue(opts.namespace, "Alexa"),
                    "name": this.checkValue(opts.name, "Response"),
                    "messageId": this.checkValue(opts.messageId, uuid()),
                    "correlationToken": this.checkValue(opts.correlationToken, undefined),
                    "payloadVersion": this.checkValue(opts.payloadVersion, "3")
                },
                "endpoint": {
                    "scope": {
                        "type": "BearerToken",
                        "token": this.checkValue(opts.token, "INVALID"),
                    },
                    "endpointId": this.checkValue(opts.endpointId, "INVALID")
                },
                "payload": this.checkValue(opts.payload, {})
            };

        // No endpoint in an AcceptGrant or Discover request
        if (this.event.header.name === "AcceptGrant.Response" || this.event.header.name === "Discover.Response")
            delete this.event.endpoint;

    }

    /**
     * Add a property to the context.
     * @param opts Contains options for the property.
     */
    addContextProperty(opts) {

        if (this.context === undefined)
            this.context = {
                properties: []
            };

        this.context.properties.push(this.createContextProperty(opts));
    }

    /**
     * Add an endpoint to the payload.
     * @param opts Contains options for the endpoint.
     */
    addPayloadEndpoint(opts) {

        if (this.event.payload.endpoints === undefined)
            this.event.payload.endpoints = [];

        this.event.payload.endpoints.push(this.createPayloadEndpoint(opts));
    }

    /**
     * Creates a property for the context.
     * @param opts Contains options for the property.
     */
    createContextProperty(opts) {
        return {
            'namespace': this.checkValue(opts.namespace, "Alexa.EndpointHealth"),
            'name': this.checkValue(opts.name, "connectivity"),
            'value': this.checkValue(opts.value, {
                "value": "OK"
            }),
            'timeOfSample': new Date().toISOString(),
            'uncertaintyInMilliseconds': this.checkValue(opts.uncertaintyInMilliseconds, 0)
        };
    }

    /**
     * Creates an endpoint for the payload.
     * @param opts Contains options for the endpoint.
     */
    createPayloadEndpoint(opts) {

        if (opts === undefined) opts = {};

        // Return the proper structure expected for the endpoint
        let endpoint = {
            "capabilities": this.checkValue(opts.capabilities, []),
            "description": this.checkValue(opts.description, "Sample Endpoint Description"),
            "displayCategories": this.checkValue(opts.displayCategories, ["SWITCH"]),
            "endpointId": this.checkValue(opts.endpointId, 'endpoint-001'),
            // "endpointId": this.checkValue(opts.endpointId, 'endpoint_' + (Math.floor(Math.random() * 90000) + 10000)),
            "friendlyName": this.checkValue(opts.friendlyName, "Sample Endpoint"),
            "manufacturerName": this.checkValue(opts.manufacturerName, "Sample Manufacturer")
        };

        if (opts.hasOwnProperty("cookie"))
            endpoint["cookie"] = this.checkValue('cookie', {});
        console.log(endpoint);
        return endpoint
    }

    /**
     * Creates a capability for an endpoint within the payload.
     * @param opts Contains options for the endpoint capability.
     */
    createPayloadEndpointCapability(opts) {

        if (opts === undefined) opts = {};

        let capability = {};
        capability['type'] = this.checkValue(opts.type, "AlexaInterface");
        capability['interface'] = this.checkValue(opts.interface, "Alexa");
        capability['version'] = this.checkValue(opts.version, "3");
        let supported = this.checkValue(opts.supported, false);
        if (supported) {
            capability['properties'] = {};
            capability['properties']['supported'] = supported;
            capability['properties']['proactivelyReported'] = this.checkValue(opts.proactivelyReported, false);
            capability['properties']['retrievable'] = this.checkValue(opts.retrievable, true);
        }
        return capability
    }

    /**
     * Get the composed Alexa Response.
     * @returns {AlexaResponse}
     */
    get() {
        return this;
    }
}

module.exports = AlexaResponse;

我在 Lambda 上遇到的错误

"Runtime.UnhandledPromiseRejection: Error: Request failed with status code 400",
        "    at process.<anonymous> (/var/runtime/index.js:35:15)",
        "    at process.emit (events.js:400:28)",
        "    at process.emit (domain.js:470:12)",
        "    at processPromiseRejections (internal/process/promises.js:245:33)",
        "    at processTicksAndRejections (internal/process/task_queues.js:96:32)"

【问题讨论】:

    标签: javascript aws-lambda alexa


    【解决方案1】:

    400 表示错误请求。所以你在你的 axios 调用中做错了什么。 您没有收到您的 axios 请求。如果你没有抓住它会返回一个承诺拒绝异常。

    还要研究 try - catch,await - 异步

    添加这个

    axios(...)
    .then(function(response) {
                    console.log(response);
                })
    .catch(function(error) {
                    console.log(error);
                })
    

    这应该会给你一个正确的错误响应。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-22
      • 2021-03-17
      • 2020-10-19
      • 1970-01-01
      • 1970-01-01
      • 2014-01-27
      相关资源
      最近更新 更多