0
votes

I'm trying to connect to an already deployed AWS IoT stack

const AWS = require('aws-sdk');
const iotData = new AWS.IotData({ endpoint: MYENDPOINT });

exports.handler = async (event) => {
try {
   const request = event;
   console.log(request);

    const params = {
        topic: common.topicOut,
        payload: 'MYPAYLOAD'
    }
    console.log("endpoint:",iotData.endpoint,"params:",params);
    iotData.publish(params, (err,res) => {
        if (err) throw err;
        return { statusCode: 200, body: res };
    })


} catch (e) {
   console.error(e);
   return { statusCode: 400, body: 'error, see lambda console' };
}
};

formally everything 'compiles' (no errors) but then I receive no response. Narrowing the problem I see that I'm trying to use an https REST endpoint but MYENDPOINT only supports wss

I'm aware of https://aws.amazon.com/es/blogs/compute/announcing-websocket-apis-in-amazon-api-gateway/ but that's for having lambdas as 'server' of a wscat client. I've also read some discouraging posts here but I prefer to double check if any of you guys have already found a solution to it using AWS-Lambda

If not, I'll start using this workaround but I'm not in control of the wss endpoint so I'll have to make one on my own and suggest the counterpart to do the changes for me on their side (and I'm not in control at all)

Your experiences (even if they're tips about 'not to follow this path'-ish) are really appreciated.

UPDATE: I have a console-based test client that is able to connect to the endpoint via awsIot.device and providing keyPath,certPath,caPath and clientId.

Could it be that I'm receiving a silent error because of permissions? When I try to use awsIot.device without cert it fails with Error: No "keyPath" or "privateKey" option supplied. so I cannot check that if on console I would have received the same (silent)error

UPDATE2: Following https://docs.aws.amazon.com/iot/latest/developerguide/http.html I can do

$ curl --tlsv1.2 --cacert ./certificates/Amazon_Root_CA_1.pem --cert ./certificates/MYCRT --key ./certificates/MYKEY -X POST -d"PAYLOAD" "https://XXX.iot.REGION.amazonaws.com:8443/topics/MYTOPIC?qos=0"

and it works. So I'm even more convinced than before that this will work if I'm able to add the certificates to the request

UPDATE3: I'm currently not using anything AWS for this, and just creating an https request that mimics the aforementioned curl call

2

2 Answers

2
votes

I try to write in the async-await style. It work as tested. Please make sure Role and Endpoint are correct.

var AWS = require('aws-sdk');

const iotdata = new AWS.IotData({ endpoint: 'XXXXXXXXXX.iot.YYYYYYYYYYY.amazonaws.com' });

exports.handler = async(event) => {
    try {
        const params = {
            topic: 'smartHomeTest',
            payload: 'Hello there',
            qos: 0
        };

        const data = await iotdata.publish(params).promise();

        console.log(data);
        const response = {
            statusCode: 200,
            body: JSON.stringify(data)
        };
        return response;
    }
    catch (e) {
        console.error(e);
        return { statusCode: 400, body: 'error, see lambda console' };
    }
}
1
votes

Your solution isn't working because your Lambda function isn't being invoked by anything. It's just a zip file on an AWS Lambda server somewhere, waiting for an invocation to trigger AWS to run it. So there's no way for the Lambda function to be creating a websocket connection and holding it open listening for a message.

You seem to be missing the fact that the AWS IoT service has built-in native support for invoking AWS Lambda functions when events are received. You need to define a Lambda function as an event target in your AWS IoT service, and it will automatically invoke your function, and pass the MQTT message as the event parameter of your function.