Sending commands from nRF Cloud to LTE Device

Hi!

In our project, we need to send cloud-to-device commands. By "command" I mean a request to do some short action, not a request to change device's configuration/state. We see two ways of sending such requests:

1. C2D messages

2. Device shadow

What are the pros and cons of each way?

Here I see a recommendation to use Device shadow for commands sending. But if we talk about commands in the sense I described above, would this recommendation be still actual?

If yes, is there a recommended way (or some sample) of Device shadow usage for sending such commands? I mean, which fields Device shadow should contain and some algorithm of updating desired and reported section during sending command and its execution.

In case of C2D messages, the main problem seems to be command delivery when the device is offline. Right? Or is there some mechanism for this case in nRF Cloud?

Thank you!

  • Hi  ,

    what you describe is what I would expect to see, but it's not what I am seeing.

    When the device comes online and sends an empty message to  $aws/things/${deviceId}/shadow/get it gets a shadow back, but that shadow does not contain the pending delta, even though the delta is pending in the cloud:

    i.e. a cloud API FetchDevice shows 

     "state": {

    "desired": {

    "nrfcloud_mqtt_topic_prefix": "prod/...",

    "pairing": {

    "state": "paired",

    "topics": {

    "d2c": "prod/.../d2c",

    "c2d": "prod/.../m/d/devsim4/+/r"

    }

    },

    "config": {

    "cmd": "command26"

    }

    },

     

    but the shadow received via ${deviceId}/shadow/get/accepted shows the following (note that the pending delta "config" is missing:

      "desired": {

        "nrfcloud_mqtt_topic_prefix": "prod/.../"

        "pairing": {

          "state": "paired",

          "topics": {

            "d2c": "prod/.../d2c",

            "c2d": "prod/.../+/r"

          }

        },

      },

    Here is the relevant code in the device simulator, this is executed in the onconnect callback:

     // subscribe to shadow gets `${deviceId}/shadow/get/accepted`
     await device.subscribe(device.topics.shadow.accepted);
    device.registerListener(device.topics.shadow.accepted, (param: { topic: string; payload: object}) =>
    {
    log.info(`shadow accepted: ${JSON.stringify(param.payload)}`);
    processCmd(param);
    });


    // subscribe to shadow rejected `${deviceId}/shadow/get/rejected`
     await device.subscribe(device.topics.shadow.rejected);
    device.registerListener(device.topics.shadow.rejected, (param: { topic: string; payload: object}) =>
    {
    log.info(`shadow rejected: ${JSON.stringify(param.payload)}`);
    });

    // subscribe to shadow updates `${deviceId}/shadow/update/delta`
     await device.subscribe(device.topics.shadow.delta);
    device.registerListener(device.topics.shadow.delta, (param: { topic: string; payload: object}) =>
    {
    log.info(`shadow delta: ${JSON.stringify(param.payload)}`);
    processCmd(param);
    });


    // since we just connected, get the current shadow from the cloud `$aws/things/${deviceId}/shadow/get`
     await device.publish(device.topics.shadow.get, {}); // payload is irrelevant

    Thanks,
    -- Terrence

Related