How to listen to AWS IOT Thing Shadow updates

2.8k views Asked by At

I have a THING and an APP connected together using AWS IOT, both using the AWS IOT SDK for Node.js. THING has a temperature (set_temp) which can be set and a temperature sensor (actual_temp).

THING listens on the $aws/things/THING_ID/shadow/updates/delta/ MQTT topic. APP publishes on the $aws/things/THING_ID/shadow/updates/ topic using the following message:

{
    "state": {
        "desired": {
            "set_temp": 38.7
        }
    }
}

This MQTT message propagates to the Thing Shadow and then through to the THING itself. However, when the THING reports the following on the $aws/things/THING_ID/shadow/updates/ topic:

{
    "state": {
        "reported": {
            "set_temp": 38.7,
            "actual_temp": 32.4
        }
    }
}

... the Thing Shadow receives it, but it does not propagate the message to the APP. This is fine for set_temp, since it does not really need to propagate back to the APP. But when the actual_temp changes, it should propagate back to the APP, but it never does.

According to the AWS IOT documentation this should work. They even say to send include "desired: null" in the message from the THING.

How can you "listen" to the Thing Shadow without polling it? Either I'm doing something wrong or AWS have a gaping hole in their IOT platform.

Update (including actual code):

App.js:

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

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

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

app.on('message', function(topic, payload) {
    // THIS LINE OF CODE NEVER RUNS
    console.log('got message', topic, payload.toString());
});

Device.js:

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

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

device.subscribe('$aws/things/' + name + '/shadow/update/delta');

device.on('message', function (topic, payload) {
    console.log('got message', topic, payload.toString());
});

// Publish state.reported every 1 second with changing temp
setInterval(function () {
    device.publish('$aws/things/' + name + '/shadow/update', JSON.stringify({
        'state': {
            'reported': {
                'actual_pool_temp': 20 + Math.random() * 10
            }
        }
    }));
}, 1000);
1

There are 1 answers

0
psiphi75 On BEST ANSWER

It appears that because I was using the same clientId for the APP and the THING. They shouldn't have the same clientId. Below is the code I was using that contains the clientId.

var app = awsIot.device({
    keyPath: '../../certs/private.pem.key',
    certPath: '../../certs/certificate.pem.crt',
    caPath: '../../certs/root-ca.pem.crt',
    clientId: 'MY_ID',            // This needs to be different for all parties
    region: 'ap-southeast-2'
});

This was answered thanks to AWS Support, here is the specific thread.