AWS Lambda putting item from MQTT request - node.js

I try to put MQTT request content into DynamoDB with Lambda function with this script :
var AWS = require("aws-sdk");
var dynamodb = new AWS.DynamoDB();
exports.handler = function index(e,ctx,callback){
//var msg = JSON.stringify(ctx);
var msg = e.Name;
var params = {
TableName:"myTable",
Item:{
Val: {S: msg},
ValId: { S:"Id"}
}
};
dynamodb.putItem(params,callback);
callback(null,"Putting item Marcel !!");
}
I have create/set thing/rule/policy and this script work but, i have undefined value, i try to get MQTT content for store it into DB.
For test this i post new topic with SNS, i didn't use the correct format i have post some message like this (raw):
{"Val":"Value"}
Val:"Value"
"Val":Value

I find a way to solve this with :
var AWS = require("aws-sdk");
var dynamodb = new AWS.DynamoDB();
exports.handler = function index(e,ctx,callback){
// new block
const record = e.Records[0].Sns.Message;
var msgJSON = JSON.parse(record);
var msg = msgJSON.key1;
var msg2 = msgJSON.key2;
var string_to_send = JSON.stringify(msg)+"-"+JSON.stringify(msg2);
//
var clean_string = string_to_send.split('"').join('');
var params = {
TableName:"myTable",
Item:{
Val: {S: clean_string},
ValId: {S: "Id"}
}
};
dynamodb.putItem(params,callback);
callback(null,"Putting item Marcel !!");
}
For test this you need use SNS to publish in topic like this :
{"key1": {"TheValue1"},"key2": {"TheValue2"}}
or with lambda actions -> configure test event -> SNS, in the Message field put :
{\"key1\": \"Val\",\"key2\": \"ValId\"}
This work but i have useless " so i use split for delete it.

Related

Undefined logger in firebase function

I am trying to send push notifications to firebase using swift, node.js and firebase functions. I can successfully push some of my notifications however I am having a hard time with my messages.
my firebase functions look like,
my functions in node.js look like,
exports.observeMessages = functions.database.ref('/messages/{fromId}/{toId}').onCreate((snapshot, context) => {
const fromId = snapshot.val().fromId;
const toId = snapshot.val().toId;
console.log('LOGGER --- uid is ' + fromId);
console.log('LOGGER --- workerId is ' + toId)
})
these messages are stored in firebase like,
I have tried to send these push notifications with
var toId = context.params.toId;
var fromId = context.params.fromId;
When I post the latter in my node.js code, I see
below is how I am sending the message information to firebase
fileprivate func sendMessageWithProperties(_ properties: [String: Any]) {
let ref = Database.database().reference().child("messages")
let childRef = ref.childByAutoId()
let toId = user!.uid!
let fromId = Auth.auth().currentUser!.uid
let timestamp = Int(Date().timeIntervalSince1970)
var values: [String: Any] = ["toId": toId, "fromId": fromId, "timestamp": timestamp, "checked": 0]
properties.forEach({values[$0] = $1})
childRef.updateChildValues(values) { (error, ref) in
if error != nil {
print(error!)
return
}
self.inputContainerView.inputTextField.text = nil
guard let messageId = childRef.key else { return }
let userMessagesRef = Database.database().reference().child("user-messages").child(fromId).child(toId).child(messageId)
userMessagesRef.setValue(1)
let recipientUserMessagesRef = Database.database().reference().child("user-messages").child(toId).child(fromId).child(messageId)
recipientUserMessagesRef.setValue(1)
}
}
The issue might be in ref('/messages/{fromId}/{toId}'). As you want to fire the function when a new message is added in the messages array, try changing it to ref('/messages/{messageId}').
exports.observeMessages = functions.database.ref('/messages/{messageId}').onCreate((snapshot, context) => {
const fromId = snapshot.val().fromId;
const toId = snapshot.val().toId;
console.log('LOGGER --- uid is ' + fromId);
console.log('LOGGER --- workerId is ' + toId)
})

Firebase Database Get All Value In Order Cloud Functions

I develop for Firebase Cloud Functions. I have a Firebase Realtime Database like this:
----- myData
-------eqewrwrepere (this one is a device token)
---------Lta+sde-fer (this one is a firebase id)
firstvalue : "a"
secondvalue : "b"
----------Qrgd+ad-qdda (this one is second firebase id)
firstvalue : "c"
secondvalue : "d"
-------eqwerSAsdqe (this one is another device token)
---------Lta+sde-fer (this one is a firebase id)
firstvalue : "x"
secondvalue : "y"
----------Qrgd+ad-qdda (this one is second firebase id)
firstvalue : "z"
secondvalue : "t"
I fetch these data by this code. With this code i fetch all data and put them an array. And when fetching done, i loop this array for finding items. I am an iOS developer, so i am a newbie for NodeJS. Here is what i want to do:
Get firstvalue for each database data.
Make a api request with firstvalue of each database data.
Api returns an image.
Write image temp directory.
Process this image for visionApi.
Extract text.
Update database.
Send notification for deviceToken
Now i am able to retrieve database items in my array. When i make a request in for loop, request called async. So for loop continues, but request response or writing file and vision processing executed only once.
In for loop, get databasearray[0], make request, write file, process it with vision api, update database and go for next databasearray[1] item.
I read about Promises on different pages. But i did not understand.
Thank you.
'use strict';
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
var request = require('request');
var fs = require('fs');
//var fs = require("fs");
// Get a reference to the Cloud Vision API component
const Vision = require('#google-cloud/vision');
const vision = new Vision.ImageAnnotatorClient();
// Imports the Google Cloud client library
//const {Storage} = require('#google-cloud/storage');
var fs = require("fs");
var os = require("os");
var databaseArray = [];
exports.hourly_job = functions.pubsub
.topic('hourly-job')
.onPublish((event) => {
console.log("Hourly Job");
var db = admin.database();
var ref = db.ref("myData")
ref.once("value").then(function(allData) {
allData.forEach(function(deviceToken) {
deviceToken.forEach(function(firebaseIDs) {
var deviceTokenVar = deviceToken.key;
var firebaseIDVar = firebaseIDs.key;
var firstvalue = firebaseIDs.child("firstvalue").val();
var secondvalue = firebaseIDs.child("secondvalue").val();
var items = [deviceTokenVar, firebaseIDVar, firstvalue, secondvalue];
databaseArray.push([...items]);
});
});
return databaseArray;
}).then(function(databasem) {
var i;
for (i = 0; i < databaseArray.length; i++) {
var databaseArrayDeviceToken = databaseArray[i][0];
console.log("DeviceToken: " + databaseArrayDeviceToken);
var databaseArrayFirebaseID = databaseArray[i][1];
console.log("FirebaseID: " + databaseArrayFirebaseID);
var databaseArrayfirstvalue = databaseArray[i][2];
console.log("firstval: " + databaseArrayfirstvalue);
var databaseArraysecondval = databaseArray[i][3];
console.log("Second: " + databaseArraysecondval);
var url = "http://api.blabla" + databaseArrayfirstvalue;
/////////////here make a request, pause loop, process returned image, but how //////////////////////
request.get({
url: url,
encoding: 'binary'
}, function(error, httpResponse, body) {
if (!error && httpResponse.statusCode == 200) {
fs.writeFileSync('/tmp/processed.jpg', body, 'binary')
console.log("file written");
})
}
});
return true;
});
I found solution with Mocas helps. Here is the solution. I use async/await functions in code. Now for loop waits for the function response. But now I have different problems. I think main async function hangs because of awaits. And then next hourly trigger, it runs again. So console log shows 15-16-17 or more ‘i’ values in for loop. I have 4 element in database array but console log shows more than this every hour. And it increases every time. So I guess that I should cancel this await functions after a timeout. But I don’t know how. Here is code:
use strict';
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
var request = require('request-promise').defaults({ encoding: null });
var fs = require('fs');
// Get a reference to the Cloud Vision API component
const Vision = require('#google-cloud/vision');
const vision = new Vision.ImageAnnotatorClient();
var os = require("os");
var databaseArray = [];
var uniqueFilename = require('unique-filename')
exports.hourly_job = functions.pubsub
.topic('hourly-job')
.onPublish((event) => {
console.log("Hourly Job");
var db = admin.database();
var ref = db.ref("myData")
ref.once("value").then(function(allData) {
allData.forEach(function(deviceToken) {
deviceToken.forEach(function(firebaseIDs) {
var deviceTokenVar = deviceToken.key;
var firebaseIDVar = firebaseIDs.key;
var firstvalue = firebaseIDs.child("firstvalue").val();
var secondvalue = firebaseIDs.child("secondvalue").val();
var items = [deviceTokenVar, firebaseIDVar, firstvalue, secondvalue];
databaseArray.push([...items]);
//console.log(databaseArray);
//return true;
});
//return true;
});
return databaseArray;
}).then(function (databasem) {
main().catch(console.error);
});
return true;
});
const main = async () => {
var i;
for (i = 0; i < databaseArray.length; i++) {
console.log("Database Arrays " + i + ". elements: ");
var databaseArrayDeviceToken = databaseArray[i][0];
console.log("DeviceToken: " + databaseArrayDeviceToken);
var databaseArrayFirebaseID = databaseArray[i][1];
console.log("FirebaseID: " + databaseArrayFirebaseID);
var databaseArrayfirst = databaseArray[i][2];
console.log("first: " + databaseArrayfirst);
var databaseArraysecond = databaseArray[i][3];
console.log("second: " + databaseArraysecond);
if (databaseArrayfirst != "") {
var apiUrl = "http://api.blabla;
try {
const apiBody = await request.get(apiUrl);
///////////////////////////vison start//////////////////////
const visionResponseBody = await vision.documentTextDetection(apiBody)
var visionResponse = visionResponseBody[0].textAnnotations[0].description;
console.log("Vision response text " + visionResponse );
...some logic here about response...
/////////////////////////////////////////////////
var getdatabasevar = await admin.database().ref("myData/" + databaseArrayDeviceToken + "/" + databaseArrayFirebaseID);
await getdatabasevar.update({
"firstvalue": visionResponse
});
/////////////////////////////////////////////////
var getanotgerdatabasevar = await admin.database().ref("myData/" + databaseArrayDeviceToken + "/" + databaseArrayFirebaseID + "/" + "secondvalue");
await getanotgerdatabasevar.once("value")
.then(function(var) {
..some logic..
//send notification
});
} catch (error) {
console.error(error);
}
///////////////////////////vison end//////////////////////
}
};
return true;
};

Sending a SMS message using AWS Pinpoint to a specific phone number

I am trying to send a SMS message using AWS Pinpoint to a specific phone number.
Here is what I have so far in nodejs:
var AWS = require('aws-sdk');
AWS.config.update({region: 'us-east-1'});
var pinpoint = new AWS.Pinpoint({apiVersion: '2016-12-01'});
pinpoint.sendMessages(XXX);
I am very confused by what needs to go into XXX. https://docs.aws.amazon.com/cli/latest/reference/pinpoint/send-messages.html has a long input. Where does the phone number go? A simple example would be greatly appreciated.
This is what finally worked. [Telephone] is the number, for example [15553451234]:
var AWS = require('aws-sdk');
// Set region
AWS.config.update({region: 'us-east-1'});
var pinpoint = new AWS.Pinpoint({apiVersion: '2016-12-01'});
var params = {
ApplicationId: 'ecba683ea3ee4af1bba3176a70ac1e71',
MessageRequest : {
Addresses : {
[telephone] : {
"BodyOverride": message,
"ChannelType": "SMS",
}
},
MessageConfiguration : {
SMSMessage:
{
Body : message,
MessageType : "TRANSACTIONAL"
}
}
}
};
var publishTextPromise = await pinpoint.sendMessages(params).promise();
This is what we did to handle the answer, stores in DynamoDB:
const doc = require('dynamodb-doc');
const dynamo = new doc.DynamoDB();
exports.handler = async (event) => {
// TODO implement
console.log(JSON.stringify(event));
var pinpointResponse = JSON.parse(event.Records[0].Sns.Message);
var phoneNumber = pinpointResponse.originationNumber.substring(2);
var message = pinpointResponse.messageBody;
console.log("phoneNumber", phoneNumber);
console.log("message", message);
//Insert into DynamoDB
var InsertParams = {
TableName : "ChatHistory",
Item : {
"phoneNumber" : phoneNumber + "",
"Answer" : message
}
};
var AWSNew = require('aws-sdk');
AWSNew.config.update({region: 'us-east-2'});
var docClient = new AWSNew.DynamoDB.DocumentClient();
await docClient.put(InsertParams).promise();
const response = {
statusCode: 200,
body: JSON.stringify('SUCCESS'),
};
return response;
};

Lambda#Edge when triggered Dynamodb giving 503 Error

I am trying to invoke Lambda through cloudfront viewer request . Here is my Lambda code
'use strict';
const AWS = require("aws-sdk");
const docClient = new AWS.DynamoDB.DocumentClient();
exports.handler = (event, context, callback) => {
/* Get request */
const request = event.Records[0].cf.request;
const requestbody = Buffer.from(request.body.data, 'base64').toString();
const data = JSON.parse(requestbody);
const Id = data.Name;
console.log(Id);
/* Generate body for response */
const body =
'<html>\n'
+ '<head><title>Hello From Lambda#Edge</title></head>\n'
+ '<body>\n'
+ '<h1>You clicked more than 10 Times </h1>\n'
+ '</body>\n'
+ '</html>';
var params = {
TableName: "Test",
ProjectionExpression: "#V,#N",
KeyConditionExpression: "#N = :v1",
ExpressionAttributeNames: {
"#N" : "Name",
"#V" : "Value"
},
ExpressionAttributeValues: {
":v1": Id
}
};
var querydb = docClient.query(params).promise();
querydb.then(function(data) {
console.log(data.Items[0].Value);
if(data.Items[0].Value >= 11){
const response = {
status: '200',
body: body,
};
callback(null, response);
}else {
callback(null,request);
}
}).catch(function(err) {
console.log(err);
});
};
When i triggered the same lambda through console it is giving correct response. But when i deployed through Cloudfront it is giving 503 Error. But i had tried the same code withcode Dynamodb Client it worked perfectly fine. Here is the working one
'use strict';
const AWS = require("aws-sdk");
const docClient = new AWS.DynamoDB.DocumentClient();
exports.handler = (event, context, callback) => {
/* Get request */
const request = event.Records[0].cf.request;
const requestbody = Buffer.from(request.body.data, 'base64').toString();
const data = JSON.parse(requestbody);
/* Generate body for response */
const body =
'<html>\n'
+ '<head><title>Hello From Lambda#Edge</title></head>\n'
+ '<body>\n'
+ '<h1>You clicked more than 10 Times </h1>\n'
+ '</body>\n'
+ '</html>';
if(data.Value >= 10){
const response = {
status: '200',
body: body,
};
callback(null, response);
}
else {
callback(null, request);
}
};
I had given full dynamodb permissions to the lambda#edge.
Any help is appreciated
Thanks
Where have you specified region for DyanamoDB?
It is possible that Lambda#Edge is executing in a region where your DDB table is missing.
Have a look at AWS doc on region's order of precedence. You can also look at this L#E workshop code and documentation for more details on calling DDB.
On a side note: A viewer facing Lambda function, making a call to a cross region dynamodb table will have negative effects on your latency. Not sure about your use case but see if it is possible to move this call to an origin facing event or make async call to ddb.

AWS Lambda cannot publish to IoT topic properly

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

Resources