【发布时间】: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