我正在为Alexa Smart Home技能创建一个lambda函数来控制我的接收器。我正在使用亚马逊提供的样板代码示例代码,但我是节点的新手,我在等待我的回调设置响应方面遇到了很多麻烦。我一直在尝试操作,好像它们的总体结构在这里是正确的。
我可以调用它并且它执行POST请求就好了,但它总是返回null(Alexa不喜欢)。它没有在response.on('end'循环中记录任何内容。看起来它正好通过marantzAPI调用爆炸。我尝试在marantzAPI函数中使用回调(命令,回调),我最终得到了相同的结果我觉得有些东西我不会来这里。
这是lambda函数:
'use strict';
var http = require('http');
var qs = require('querystring');
/**
* We're not discovering our devices, we're just hardcoding them. Easy!
*/
const USER_DEVICES = [
{
applianceId: 'marantz-sr6010-shield',
manufacturerName: 'Marantz nVidia',
modelName: 'SR6010 Shield',
version: '1.0',
friendlyName: 'Shield',
friendlyDescription: 'nVidia Shield via Marantz SR6010',
isReachable: true,
actions: ['turnOn', 'turnOff'],
}
];
/**
* Utility functions
*/
function log(title, msg) {
console.log(`[${title}] ${msg}`);
}
/**
* Generate a unique message ID
*
* https://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript
* This isn't UUID V4 but it's good enough for what we're doing
*/
function generateMessageID() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
return v.toString(16);
});
}
/**
* Generate a response message
*
* @param {string} name - Directive name
* @param {Object} payload - Any special payload required for the response
* @returns {Object} Response object
*/
function generateResponse(name, payload) {
return {
header: {
messageId: generateMessageID(),
name: name,
namespace: 'Alexa.ConnectedHome.Control',
payloadVersion: '2',
},
payload: payload,
};
}
/**
* This is a lot easier when I'm just hard-coding my devices
*/
function getDevicesFromPartnerCloud() {
return USER_DEVICES;
}
/**
* The meat and potatoes, I'm butchering just the things I Need from the solid work done by Nathan Totten:
* https://github.com/ntotten/marantz-avr/blob/master/lib/avreciever.js
*/
function marantzAPI(commands, apiCallback) {
log('DEBUG', `MarantzAPI Invoked: ` + JSON.stringify(commands));
var postData = {};
// format commands for the Marantz POST (cmd0: cmd1: etc)
// note: may need to send commands one at a time??
for (var i=0; i<commands.length; i++) {
postData['cmd' + i] = commands[i];
}
log('DEBUG', `MarantzAPI POST Data: ` + qs.stringify(postData));
var serverError = function (e) {
log('Error', e.message);
apiCallback(generateResponse('UnexpectedInformationReceivedError', e.message));
};
var httpCallback = function(response) {
response.on('end', function () {
log('DEBUG', `API Request Complete`);
apiCallback(generateResponse('APIRequestComplete', postData));
});
response.on('error', serverError);
};
var apiRequest = http.request({
hostname: process.env.receiverIp,
path: '/MainZone/index.put.asp',
port: process.env.receiverPort,
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(qs.stringify(postData))
},
}, httpCallback);
apiRequest.on('error', serverError);
apiRequest.write(qs.stringify(postData));
apiRequest.end();
}
/**
* Main logic
*/
function handleDiscovery(request, callback) {
log('DEBUG', `Discovery Request: ${JSON.stringify(request)}`);
const userAccessToken = request.payload.accessToken.trim();
const response = {
header: {
messageId: generateMessageID(),
name: 'DiscoverAppliancesResponse',
namespace: 'Alexa.ConnectedHome.Discovery',
payloadVersion: '2',
},
payload: {
discoveredAppliances: getDevicesFromPartnerCloud(userAccessToken),
},
};
log('DEBUG', `Discovery Response: ${JSON.stringify(response)}`);
callback(null, response);
}
function handleControl(request, callback) {
log('DEBUG', `Control Request: ${JSON.stringify(request)}`);
const userAccessToken = request.payload.accessToken.trim();
const applianceId = request.payload.appliance.applianceId;
let response;
var commands = [];
switch (request.header.name) {
case 'TurnOnRequest':
// turn on the device
commands.push('PutZone_OnOff/ON');
// set the input
switch (applianceId) {
case 'marantz-sr6010-shield':
commands.push('PutZone_InputFunction/MPLAY');
break;
}
// I guess? Not even sure if it actually does all this.
commands.push('aspMainZone_WebUpdateStatus/');
marantzAPI(commands, function(response) {
callback(null, response);
});
break;
default: {
log('ERROR', `No supported directive name: ${request.header.name}`);
callback(null, generateResponse('UnsupportedOperationError', {}));
return;
}
}
// I think I need to remove these, because response is not set at execution time
// log('DEBUG', `Control Confirmation: ${JSON.stringify(response)}`);
// callback(null, response);
}
exports.handler = (request, context, callback) => {
switch (request.header.namespace) {
case 'Alexa.ConnectedHome.Discovery':
handleDiscovery(request, callback);
break;
case 'Alexa.ConnectedHome.Control':
handleControl(request, callback);
break;
default: {
const errorMessage = `No supported namespace: ${request.header.namespace}`;
log('ERROR', errorMessage);
callback(new Error(errorMessage));
}
}
};
答案 0 :(得分:0)
节点js环境默认情况下是异步环境,并且您的+-----------+-------------------------------------------+
| DATE_OUT | PERC |
+-----------+-------------------------------------------+
| 01-JAN-17 | .5161290322580645161290322580645161290323 |
| 01-FEB-17 | 1 |
| 01-MAR-17 | .0322580645161290322580645161290322580645 |
+-----------+-------------------------------------------+
方法异步执行,因此在执行此函数时,控件不会停在那里并继续执行下一个函数并最终执行{{ 1}}虽然previouse函数尚未完成,导致空白响应。这是我建议您访问This SO thread以获得详细说明和可能的解决方案的最合适的答案。
答案 1 :(得分:0)
我已经开始工作了。这是我更新的marantzAPI函数。看起来像response.on('数据'对于HTTP请求的成功至关重要?不知道。
function marantzAPI(commands, apiCallback) {
var postData = {};
// format commands for the Marantz POST (cmd0: cmd1: etc)
// note: may need to send commands one at a time??
for (var i=0; i<commands.length; i++) {
postData['cmd' + i] = commands[i];
}
log('DEBUG', `MarantzAPI Called w Data: ` + qs.stringify(postData));
var serverError = function (e) {
log('Error', e.message);
apiCallback(false, e.message);
};
var apiRequest = http.request({
hostname: process.env.receiverIp,
path: '/MainZone/index.put.asp',
port: process.env.receiverPort,
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(qs.stringify(postData))
},
}, function(response) {
response.setEncoding('utf8');
response.on('data', function (chunk) {
log('DEBUG', 'CHUNK RECEIVED');
});
response.on('end', function () {
log('DEBUG', `API Request Complete`);
apiCallback(true, '');
});
response.on('error', serverError);
});
apiRequest.on('error', serverError);
apiRequest.write(qs.stringify(postData));
apiRequest.end();
}