AWS Lambda cannot publish to IoT topic properly - node.js

I have written Lambda function using JavaScript, which responses to my voice and turns on the LED on my Raspberry.
But I have a problem with publishing its state to my thing topic. While Alexa responses correct ("Turning on" if Im asking to turn it on and "Turning off" if asking to off), my topic doesn't always get the state changes. Some times it gets data and sometime it doesn't and after few more invocations it gets data in bulk, and I cant even get the logic of creating a sequence of data in that bulk.
var AWS = require('aws-sdk');
var config = {};
config.IOT_BROKER_ENDPOINT = "xxxxxx.iot.us-east-1.amazonaws.com";
config.IOT_BROKER_REGION = "us-east-1";
config.IOT_THING_NAME = "raspberry";
var iotData = new AWS.IotData({endpoint: config.IOT_BROKER_ENDPOINT});
var topic = 'LED';
exports.handler = function (event, context) {
...
...
function updatePowerState (intent, session, callback) {
var speechOutput = '';
var newValue = '';
var repromptText = '';
const cardTitle = 'Power';
var sessionAttributes = {};
const shouldEndSession = true;
var value = intent.slots.PowerState.value;
if(value == 'on' || value == 'off') {
newValue = value.toUpperCase();
speechOutput = 'Turning your lamp ' + value;
updateShadow(newValue);
} else {
speechOutput = 'I didnt understand you. Please, repeat your request.';
}
callback(sessionAttributes, buildSpeechletResponse(cardTitle, speechOutput, repromptText, shouldEndSession));
}
function updateShadow(newValue) {
let payload = {
state: {
desired: {
power_state: newValue
}
}
};
var JSON_payload = JSON.stringify(payload);
var updates = {
topic: topic,
payload: JSON_payload,
qos: 0
};
iotData.publish(updates, (err, data) => {
if(err) {
console.log(err);
}
else {
console.log('Success!');
}
});
}
Do you have any ideas about its causes? Thank you!

Async methods like iotData.publish cause problems into AWS Lambda, because you request a execution and the lambda function ends soon without waiting for the response and processing the request.
Another problem could be your permissions.

var AWS = require('aws-sdk');
var iotdata = new AWS.IotData({endpoint: 'iotCoreEndpoint.iot.us-east-1.amazonaws.com'});
exports.handler = async (event) => {
var params = {
topic: 'topic/topicName',
payload: JSON.stringify(event.body),
qos: 0
};
await iotdata.publish(params).promise()
};
Just make sure to add the required permissions or you can attach the following policy to your lambda role: AWSIoTWirelessFullPublishAccess

Related

AWS lambda sending sns message to phone number

I have a lambda function running node.js The function makes database calls and sends a text message via sns. It has the following structure
the functions -> index.js file looks like this
async function sendTextMessage(message, phoneNumber) {
try {
console.log("hitSendFunction");
const sns = new AWS.SNS();
const params = {
Message: message,
MessageStructure: "string",
PhoneNumber: phoneNumber
};
//remember phone number must have +1 before it.
return await sns.publish(params).promise();
} catch (error) {
console.log(error);
}
}
module.exports = {
sendTextMessage
};
that function is than called in the main index.js file:
const database = require("./db");
const { sendTextMessage } = require("./functions");
const AWS = require("aws-sdk");
AWS.config.region = "us-east-1";
exports.handler = async function (event, context) {
try {
console.log("hit");
const result = await database.query("call getTicker()");
const data = result[0][0];
const currentProjectEndDate = new Date(
data.currentProjectEndDate
).getTime();
const now = new Date().getTime();
console.log("data.currentProjectEndDate", data.currentProjectEndDate);
const runningHot =
data.jobsInQueue > 0 && currentProjectEndDate <= now && data.textSent < 1;
if (runningHot) {
const numbers = ["+1435994****"];
for (let i = 0; i < numbers.length; i++) {
let number = numbers[i];
console.log("number", number);
let messageResult = await sendTextMessage(
"The CE Bot is running hot from lambda",
number
);
console.log("messageResult", messageResult);
}
await database.query("call insertIntoTextSent()");
console.log("yes");
}
} catch (error) {
console.log("this was the error", error);
}
The database calls work correctly but the textMessage function just hangs and times out. The lambda function has the following permissions attached to it:
Finally even though I do not think it is needed as the db code is working here is what the db -> index.js file looks like:
const mysql = require("mysql");
const util = require("util");
const awsConfig = {
host: process.env.RDS_HOST,
user: process.env.RDS_USER,
password: process.env.RDS_PASSWORD,
database: process.env.RDS_DATABASE
};
const connection = mysql.createConnection(awsConfig);
connection.query = util.promisify(connection.query.bind(connection));
connection.end = util.promisify(connection.end.bind(connection));
module.exports = connection;
I am not quite sure where I am going wrong here. Can someone point me in the right direction?
You can just send it via sms in sns just type in the phone number

AWS Sdk response not showing in Lambda Function

I am working on lambda function and creating a method for AWS-SDK historical metric report using node, js. The method is running successful but in response showing nothing. Have a look at the response.
Here is my code
function getKeyByValue(object, value) {
return Object.keys(object).find(key =>
object[key] === value);
}
exports.handler = async (event) => {
const AWS = require('aws-sdk');
var connect = new AWS.Connect({ apiVersion: '2017-08-08' });
let queueARN = event.queueARN || null;
const connectInstanceId = process.env.instanceID;
let flag =0, nextToken = null;
let queueARNsObject = {}, queueARNsArray=[], queueTypeObject={},listQueuesResult;
console.log('At line 12 entring do while loop....')
do{
console.log('How many times do I stay here???')
let listQueuesParams = {
InstanceId: connectInstanceId, /* required */
QueueTypes: [
"STANDARD",
],
NextToken: nextToken,
};
let listQueuesPromise = connect.listQueues(listQueuesParams).promise();
listQueuesResult = await listQueuesPromise;
// console.log(listQueuesResult);
listQueuesResult.QueueSummaryList.forEach(queue => {
if(queueARN != null){
if (queue.Arn == queueARN){
queueARNsArray = [queue.Arn];
queueARNsObject[queue.Name]= queue.Arn;
queueTypeObject[queue.QueueType]= queue.Arn;
flag = 1;
return;
}
}else{
queueARNsObject[queue.Name]= queue.Arn;
queueTypeObject[queue.QueueType]= queue.Arn;
queueARNsArray.push(queue.Arn);
nextToken = listQueuesResult.NextToken;
}
});
}while (flag=0 && nextToken != null);
const HistoricalMetrics = [
{
Name : "CONTACTS_HANDLED",
Unit : "COUNT",
Statistic : "SUM"
},
{
Name : "CONTACTS_ABANDONED",
Unit : "COUNT",
Statistic : "SUM"
},
];
// Metrics params
var getHistoricalMetricsParams = {
InstanceId: connectInstanceId,
StartTime: 1593099900,
EndTime: 1593129300,
Filters: {
Channels: ["VOICE"],
Queues: queueARNsArray
},
HistoricalMetrics: HistoricalMetrics,
Groupings: ["QUEUE"]
};
// console.log(getHistoricalMetricsParams);
// get current metrics by queues
var getHistoricalMetricsPromise = connect
.getMetricData(getHistoricalMetricsParams)
.promise();
var getHistoricalMetricsResult = await getHistoricalMetricsPromise;
console.log("historical metrics",getHistoricalMetricsResult);
// console.log("current |||||||| 1 metrics:", JSON.stringify(getCurrentMetricsResult));
let queueMetricsArray = [];
if(getHistoricalMetricsResult.MetricResults.length){
getHistoricalMetricsResult.MetricResults.forEach(queue => {
let queueMetrics = {
"Queue_Name" : getKeyByValue(queueARNsObject ,queue.Dimensions.Queue.Arn),
"CallsHandled": queue.Collections[0].Value,
"CallsAbanoded": queue.Collections[1].Value,
}
queueMetricsArray.push(queueMetrics);
console.log("TYPE||||", getKeyByValue(queueTypeObject ,queue.Dimensions.Queue.Arn))
});
}
const response = {
responseCode: 200,
metricResults: queueMetricsArray
};
return response;
};
I don't have any idea why it is not showing anything. if anyone of you knows please help me to fix it Thanks. I don't know what is Missing I've almost checked everything but I didn't get anything.
There are a few general areas you can look at:
Specify the region.
AWS.Connect({ apiVersion: '2017-08-08', region:'xxxxx' });
use Await directly with listQueues method
let listQueuesPromise = await connect.listQueues(listQueuesParams).promise();
Check Permissions - make sure there is sufficient authority
Lambda Configuration - increase timeout and memory size
PS: What did console log listQueuesPromise return?

my node.js code work unstable in aws-lambda, Sometimes it works fine, sometimes skipping the data persistence that piece of code

The data center uploads a csv file to our S3 bucket every five minutes, which triggers my lambda function to read the file and save the data to DynamoDB. But the code that performs data persistence is not stable, sometimes it will be executed, and sometimes it will be skipped completely. This makes me very confused. Here is my code.
var AWS = require('aws-sdk');
var csvtojson = require('csvtojson');
var encoding = require('text-encoding');
AWS.config.update({
accessKeyId: '********',
secretAccessKey: '**********',
region: 'us-west-2',
sslEnabled:false
});
var s3 = new AWS.S3();
var ddb = new AWS.DynamoDB({apiVersion: '2012-08-10'});
exports.handler = async (event) => {
try {
console.log(event);
console.log(event['Records'][0]['s3']['object']['key']);
//get the file name
let key = event['Records'][0]['s3']['object']['key'];
let date = `${key}`.slice(24,36);
console.log(date);
let getObject = {Bucket: 'saas-status-mockup-data', Key: `${key}`};
//get the object
let response = await s3.getObject(getObject).promise();
//transfer to csv
let csvFile= new encoding.TextDecoder("utf-8").decode(response.Body);
//transfer to json
let res = await csvtojson().fromString(csvFile);
console.log(res);
await res.map(async(item,key) => {
console.log(item);
let putParams = {};
if(item.FARM=="SMAX Internal production Functionalities"){
putParams.TableName = 'InternalProductionDb';
} else if(item.FARM=="SMAX Trial Major Functionalities"){
putParams.TableName = 'TrialMajorDb';
} else {
console.error(item);
}
putParams.Item = {
'Date' : {
S:`${date}${item.BUSINESS_PROCESS}`
},
'StatusId':{
S:`${date}${item.BUSINESS_PROCESS}`
},
'BusinessProcess':{
S:`${item.BUSINESS_PROCESS}`
},
'Status':{
S:`${item.STATUS}`
}
};
console.log(putParams);
//put data to dynamoDB, But sometimes this code sometimes does not execute.
let putRes = await ddb.putItem(putParams).promise();
console.dir(putRes);
});
}
catch(error){
console.error(error);
return error;
}
};
Array.map() returns an array not a Promise so you cannot await it (e.g. await res.map() in your code).
First, you should collect a list of promises and the use Promise.all() to wait for all of them.
exports.handler = async (event) => {
try {
console.log(event);
console.log(event['Records'][0]['s3']['object']['key']);
//get the file name
let key = event['Records'][0]['s3']['object']['key'];
let date = `${key}`.slice(24,36);
console.log(date);
let getObject = {Bucket: 'saas-status-mockup-data', Key: `${key}`};
//get the object
let response = await s3.getObject(getObject).promise();
//transfer to csv
let csvFile= new encoding.TextDecoder("utf-8").decode(response.Body);
//transfer to json
let res = await csvtojson().fromString(csvFile);
console.log(res);
// Construct the list of promises.
const promises = res.map((item, key) => {
console.log(item);
let putParams = {};
if(item.FARM=="SMAX Internal production Functionalities"){
putParams.TableName = 'InternalProductionDb';
} else if(item.FARM=="SMAX Trial Major Functionalities"){
putParams.TableName = 'TrialMajorDb';
} else {
console.error(item);
}
putParams.Item = {
'Date' : {
S:`${date}${item.BUSINESS_PROCESS}`
},
'StatusId':{
S:`${date}${item.BUSINESS_PROCESS}`
},
'BusinessProcess':{
S:`${item.BUSINESS_PROCESS}`
},
'Status':{
S:`${item.STATUS}`
}
};
console.log(putParams);
//put data to dynamoDB, But sometimes this code sometimes does not execute.
return ddb.putItem(putParams).promise();
});
// Wait for all promises to finish.
return Promise.all(promises)
}
catch(error){
console.error(error);
return error;
}
};

alexa implement CanFulfillIntentRequest in node.js

Alexa has released CanFulfillIntentRequest feature or Name-free Interaction for custom skills recently. I am trying to implement it in my existing skill which uses alexa-sdk. Please find my code below:
'use strict';
const Alexa = require('alexa-sdk');
var handlers = {
'LaunchRequest': function() {
var speechOutput = "You can ask me to read out quotes from Steve Jobs";
var repromptText = "Sorry I didnt understand";
this.emit(':tell', speechOutput, repromptText);
},
'RandomQuote': function() {
let data = getQuoteFunction();
const author = data[0];
const quote = data[1];
let cardTitle = "Quotation from author";
let cardContent = "Actual quote";
let speechOutput = "Actual quote";
// Speak out the output along with card information
this.emit(':tellWithCard', speechOutput, cardTitle, cardContent);
}
}
exports.handler = function (event, context, callback) {
const alexa = Alexa.handler(event, context, callback);
alexa.registerHandlers(handlers);
alexa.execute();
};
Do we need to add handler for CanFulfillIntentRequest, the way I did for other handlers ? for example:
var handlers = {
'LaunchRequest': function() {
},
'RandomQuote': function() {
},
'CanFulfillIntentRequest': function() {
//code to handle
}
}
Is this feature only available in ASK SDK v2 for Node.js ? Can we implement it in skill developed using alexa-sdk. Could anyone please let me know ?
Thanks

Alexa skill which can read Facebook posts using AWS Lambda, Node.js and the Alexa Skills Kit

I am developing an Alexa skill using AWS Lambda, Node.js and the Alexa Skills Kit.I am using a forked from skill-sample-nodejs-fact project & successfully deployed & tested the sample fact project .Now I am trying to modify that code to read posts on some Facebook feeds.First I tried to develop some node application which can read posts & it was successful.Please find below code for your reference.I used fb module -
https://www.npmjs.com/package/fb
const FB = require('fb');
FB.setAccessToken('abc');
const query='cnninternational/posts';
FB.api(query, function (res) {
if(!res || res.error) {
console.log(!res ? 'error occurred' : res.error);
return;
}
console.log(res);
});
Next, I tried to integrate above code block into the lambda function.Unfortunately, I was unable, to read Facebook posts using these codes.Please find those code blocks in the below panel .Also, I checked cloudwatch logs as well.I can see the "GetNewsIntent", but I didn't see "fb-init" , "fb-error" or "fb-exit"entries in logs.Surprisingly, no error in logs as well.I would much appreciate it if someone can help to solve that issue.
'use strict';
const Alexa = require('alexa-sdk');
const FB = require('fb');
const APP_ID = 'abc';
const SKILL_NAME = 'test';
const GET_FACT_MESSAGE = "Here's your news: ";
const STOP_MESSAGE = 'Goodbye!';
exports.handler = function(event, context, callback) {
var alexa = Alexa.handler(event, context);
alexa.appId = APP_ID;
alexa.registerHandlers(handlers);
alexa.execute();
};
const handlers = {
'LaunchRequest': function () {
this.emit('GetNewsIntent');
},
'GetNewsIntent': function () {
console.log('GetNewsIntent');
const speechOutput = GET_FACT_MESSAGE;
const query='cnninternational/posts';
FB.setAccessToken('abc');
FB.api(query, function (res) {
console.log('fb-init');
if(!res || res.error) {
console.log(!res ? 'error occurred' : res.error);
console.log('fb-error');
return;
}
console.log(res);
speechOutput = speechOutput + res;
console.log('fb-exit');
});
this.response.cardRenderer(SKILL_NAME, speechOutput);
this.response.speak(speechOutput);
this.emit(':responseReady');
},
'AMAZON.StopIntent': function () {
this.response.speak(STOP_MESSAGE);
this.emit(':responseReady');
},
};
Have you implemented account linking? You should be using event.session.user.accessToken for the parameter to setAccessToken().
I have removed this.response.cardRenderer , this.response.speak & changed the code bit.It's working fine now.Please find the below code snippet which can be used to read posts on the BBC Facebook page.
var accessToken = '';
exports.handler = function(event, context, callback) {
var alexa = Alexa.handler(event, context);
alexa.appId = APP_ID;
alexa.registerHandlers(handlers);
alexa.execute();
};
const handlers = {
'NewSession': function() {
var welcomeMessage = "Welcome to Athena";
welcomeMessage = welcomeMessage +"<break time=\"1s\"/>"+ "<audio src='https://s3.amazonaws.com/my-ssml-samples/Flourish.mp3' />"+"<break time=\"1s\"/>";
welcomeMessage += HELP_MESSAGE;
accessToken = this.event.session.user.accessToken;
if (accessToken) {
FB.setAccessToken(accessToken);
this.emit(':ask', welcomeMessage, HELP_REPROMPT);
}
else {
// If we don't have an access token, we close down the skill.
this.emit(':tellWithLinkAccountCard', "This skill requires you to link a Facebook account. Seems like you are not linked to a Facebook Account. Please link a valid Facebook account and try again.");
}
},
'LaunchRequest': function () {
this.emit('NewSession');
},
'ReadBbcNewsFacebookPostsIntent': function () {
var alexa = this;
FB.api("bbcnews/posts", function (response) {
if (response && !response.error) {
if (response.data) {
var output = "Here are recent posts" + "<break time=\"1s\"/>";
var max = 5;
for (var i = 0; i < response.data.length; i++) {
if (i < max) {
output += "<break time=\"1s\"/>" + "Post " +
(i + 1) +
response.data[i].message.replace(/(?:https?|ftp):\/\/[\n\S]+/g, '')
+ ". ";
}
}
alexa.emit(':ask', output+ ", What would you like to do next?",HELP_MESSAGE);
} else {
// REPORT PROBLEM WITH PARSING DATA
}
} else {
// Handle errors here.
console.log(response.error);
this.emit(':tell', EMPTY_ACCESS_TOKEN_MESSAGE, TRY_AGAIN_MESSAGE);
}
});
}
};

Resources