aws / aws-sdk-js

AWS SDK for JavaScript in the browser and Node.js
https://aws.amazon.com/developer/language/javascript/
Apache License 2.0
7.59k stars 1.55k forks source link

awsIot.thingShadow#register in plain javascript #3295

Closed mm108 closed 4 years ago

mm108 commented 4 years ago

Just started on AWS and been able to get a device to post the data to AWS in no time (thanks to the good documentation). I am also able to read the data on a mobile device using some code as shown below

var iotdata = new AWS.IotData({endpoint: 'my.host.tld'});
iotdata.getThingShadow(params, function (err, data) {
  if (err) console.log(err, err.stack); // an error occurred
  else     console.log(data);           // successful response
});

Everything works perfect and while I can get the updated data (by polling using the above code), what I prefer is to get the data automatically whenever the device shadow is updated.

From the documentation I understand that I can use awsIot.thingShadow#register(thingName, [options], [callback] ) and subsequently listen for status changes. The issue here is that I am using this on a mobile device which does not support the require() method to load the modules. Can someone point me to a simple example of using the thingShadow#register method in javascript without the need for require()?

ajredniwja commented 4 years ago

Hey @m-menon thank-you for reaching out to us with your issue and apologies for late reply.

Usually require() is not supported on client side JavaScript, which I think is the case for the mobile device too.

I think you can use a script tag by building your custom SDK: https://sdk.amazonaws.com/builder/js/

Please reach out if that doesn't solve your problem.

mm108 commented 4 years ago

Thanks for the tip.

I think you can use a script tag by building your custom SDK: https://sdk.amazonaws.com/builder/js/

This was one of the first things that I tried. As a matter of fact I even created a bundle that included every single js library listed in that builder. I clearly remember I still had no success registering for a shadow change event. Unfortunately I had cleared off some of the testing stuff so I can't list the specific details; But one thing I can confirm 100% is that I used the builder, included every single js library in there, and still could not register a shadow change event.

Basically this is what I am trying to achieve. The below example uses require but as I can't use that, I built a sdk/js library using the online SDK builder.

MyJSApp.js

var awsIot = require('aws-iot-device-sdk');
var name = 'THINGID';

var app = awsIot.device({
    keyPath: '../../certs/private.pem.key',
    certPath: '../../certs/certificate.pem.crt',
    caPath: '../../certs/root-ca.pem.crt',
    clientId: someName,
    region: 'ap-southeast-1'
});

app.subscribe('$aws/things/' + name + '/shadow/update/accepted');

// SHADOW CHANGE EVENT 
app.on('message', function(topic, payload) {
// DO WHATEVER PROCESSING
});

I understand that the IoT device shadow library is a wrapper around the device sdk. So anything would do as long as I can fire off the event when device shadow changes.

A super simple browser based example (without the use of require) will be a good help - either by using device class or thingShadow class.

mm108 commented 4 years ago

If I could get the below working without the need for require to include the modules No matter which library I use (I even tried a bundle with all the libraries) but I hit an error as soon as it gets here var thingShadows = awsIot.thingShadow({

var awsIot = require('aws-iot-device-sdk');

//
// Replace the values of '<YourUniqueClientIdentifier>' and '<YourCustomEndpoint>'
// with a unique client identifier and custom host endpoint provided in AWS IoT cloud
// NOTE: client identifiers must be unique within your AWS account; if a client attempts 
// to connect with a client identifier which is already in use, the existing 
// connection will be terminated.
//
var thingShadows = awsIot.thingShadow({
    keyPath: < YourPrivateKeyPath > ,
    certPath: < YourCertificatePath > ,
    caPath: < YourRootCACertificatePath > ,
    clientId: < YourUniqueClientIdentifier > ,
    host: < YourCustomEndpoint >
});

//
// Client token value returned from thingShadows.update() operation
//
var clientTokenUpdate;

//
// Simulated device values
//
var rval = 187;
var gval = 114;
var bval = 222;

thingShadows.on('connect', function() {
    //
    // After connecting to the AWS IoT platform, register interest in the
    // Thing Shadow named 'RGBLedLamp'.
    //
    thingShadows.register('RGBLedLamp', {}, function() {

        // Once registration is complete, update the Thing Shadow named
        // 'RGBLedLamp' with the latest device state and save the clientToken
        // so that we can correlate it with status or timeout events.
        //
        // Thing shadow state
        //
        var rgbLedLampState = {
            "state": {
                "desired": {
                    "red": rval,
                    "green": gval,
                    "blue": bval
                }
            }
        };

        clientTokenUpdate = thingShadows.update('RGBLedLamp', rgbLedLampState);
        //
        // The update method returns a clientToken; if non-null, this value will
        // be sent in a 'status' event when the operation completes, allowing you
        // to know whether or not the update was successful.  If the update method
        // returns null, it's because another operation is currently in progress and
        // you'll need to wait until it completes (or times out) before updating the 
        // shadow.
        //
        if (clientTokenUpdate === null) {
            console.log('update shadow failed, operation still in progress');
        }
    });
});

thingShadows.on('status',
    function(thingName, stat, clientToken, stateObject) {
        console.log('received ' + stat + ' on ' + thingName + ': ' +
            JSON.stringify(stateObject));
        //
        // These events report the status of update(), get(), and delete() 
        // calls.  The clientToken value associated with the event will have
        // the same value which was returned in an earlier call to get(),
        // update(), or delete().  Use status events to keep track of the
        // status of shadow operations.
        //
    });

thingShadows.on('delta',
    function(thingName, stateObject) {
        console.log('received delta on ' + thingName + ': ' +
            JSON.stringify(stateObject));
    });

thingShadows.on('timeout',
    function(thingName, clientToken) {
        console.log('received timeout on ' + thingName +
            ' with token: ' + clientToken);
        //
        // In the event that a shadow operation times out, you'll receive
        // one of these events.  The clientToken value associated with the
        // event will have the same value which was returned in an earlier
        // call to get(), update(), or delete().
        //
    });
ajredniwja commented 4 years ago

@m-menon while I understand the frustration I think this will be an limitation because of the device you are on, since using js-sdk it would need to make those calls to the iot-sdk, I would have suggested https://github.com/browserify/browserify but it seems you might have already tried it.

I would like to close the issue since is not really an SDK issue, I am open for comments or suggestions.

mm108 commented 4 years ago

@ajredniwja , thanks. I think this can be closed. I'll figure out something but in the meantime if someone has a solution, it will be great if they post it as I am sure this is something many might be wanting to achieve. I am no fan of polling and I am sure there are many who dislike polling.