Skip to content

Device shadow

A device shadow or digital twin refers to a JSON document containing data on the device state that is stored in the cloud. Shadows apply only to IP devices.

See more about device shadows in the AWS documentation.

nRF Cloud defines JSON schemas for device shadows. If you want your device to be fully supported by nRF Cloud, keep the default schemas, particularly when defining portions. You can add custom fields to a device shadow. Each shadow can be maximum 8 KB in size.

It is often best to interact with devices through their shadows instead of sending them messages directly. Devices can then subscribe to the /shadow/delta/delta topic and take action on any changes they detect while online and connected to an MQTT broker. A device can also be programmed to retrieve its shadow when it comes back online. This negates any concerns about a device being offline when you want to change its state.

You might, for example, want to change your device's configuration to send temperature sensor readings more frequently. Instead of publishing a message directly to the device, you can update the device's configuration in the shadow. The device sees the change and updates its message frequency.

Example shadows

This section contains examples of device shadows for non-gateway and gateway devices.

Non-gateway devices

This example shadow follows the ipShadow JSON schema:

 {
    "desired": {
        "pairing": {
        "state": "paired",
        "topics": {
            "d2c": "prod/63ae73c3-9918-4b03-a1a8-132174824392/m/d/nrf-352656101397613/d2c",
            "c2d": "prod/63ae73c3-9918-4b03-a1a8-132174824392/m/d/nrf-352656101397613/c2d"
          }
        },
        "nrfcloud_mqtt_topic_prefix": "prod/63ae73c3-9918-4b03-a1a8-132174824392/"
    },
    "reported": {
        "connection": {
        "status": "connected"
        },
        "pairing": {
        "state": "paired",
        "topics": {
            "d2c": "prod/63ae73c3-9918-4b03-a1a8-132174824392/m/d/nrf-352656101397613/d2c",
            "c2d": "prod/63ae73c3-9918-4b03-a1a8-132174824392/m/d/nrf-352656101397613/c2d"
          }
        },
        "nrfcloud_mqtt_topic_prefix": "prod/63ae73c3-9918-4b03-a1a8-132174824392/",
        "device": {
        "networkInfo": {
            "currentBand": 12,
            "supportedBands": "(2,3,4,8,12,13,20,28)\r\n",
            "areaCode": 34049,
            "mccmnc": "310410",
            "ipAddress": "10.165.197.1",
            "ueMode": 2,
            "cellID": 128566289,
            "networkMode": "LTE-M GPS"
        },
        "simInfo": {
            "uiccMode": 1,
            "iccid": "8931080019073573173",
            "imsi": "204080813558856"
        },
        "deviceInfo": {
            "modemFirmware": "mfw_nrf9160_1.2.2",
            "batteryVoltage": 4121,
            "imei": "352656101397613",
            "board": "thingy91_nrf9160",
            "appVersion": "v1.4.0",
            "appName": "asset_tracker"
        },
        "serviceInfo": {
            "ui": [
            "GPS",
            "FLIP",
            "TEMP",
            "HUMID",
            "AIR_PRESS",
            "BUTTON",
            "LIGHT",
            "RSRP"
            ],
            "fota_v2": [
            "APP",
            "MODEM",
            "BOOT"
          ]
        }
        },
        "config": {
        "GPS": {
            "enable": false
        }
      }
    }
  }

Gateways

This example shadow uses the gatewayShadow JSON schema:

  {
    "desired": {
      "nrfcloud_mqtt_topic_prefix": "prod/0d114c02-9699-4721-85f2-66baa38070d9/",
      "desiredConnections": [
        {
          "id": "EA:78:EA:96:28:22"
        }
      ]
    },
    "reported": {
      "connection": {
        "status": "disconnected",
        "disconnectReason": "CONNECTION_LOST",
        "clientInitiatedDisconnect": false
      },
      "statusConnections": {
        "EA:78:EA:96:28:22": {
          "id": "EA:78:EA:96:28:22",
          "status": {
            "connected": true
          }
        }
      }
    }
  }

Getting a device shadow

This section explains how to get data from the device shadow using REST or MQTT.

Through the REST API

You can retrieve a device shadow by calling the FetchDevice or ListDevices endpoints. If using ListDevices, set the includeState parameter to true.

Through the MQTT API

A device can retrieve its own shadow by publishing any message to the /shadow/get topic. See the MQTT API for more information.

Updating a device shadow

This section explains how to update the device shadow.

Through the REST API

You can update a device shadow through the UpdateDeviceState endpoint.

Through the MQTT API

Devices can retrieve their own shadows by publishing to the /shadow/update topic. See more about shadow topics in the MQTT API documentation.

Example: enabling FOTA

If you want to enable the nRF Cloud firmware over-the-air (FOTA) update service, you must configure your device for FOTA. For a non-gateway device, this means the device must contain a reported.device.serviceInfo.fota_v2 array in its shadow, for example:

  ...
  "reported": {
      "device": {
        "serviceInfo": {
          "fota_v2": [
            "APP",
            "MODEM",
            "BOOT"
          ]
        }
      }
    }

Gateway devices that support Bluetooth® Low Energy (LE) FOTA must also set a fota_v2_ble flag. This example snippet from a gateway shadow shows that it supports APP and MODEM (but not BOOT) FOTA for itself, as well as Bluetooth LE FOTA for its connected peripherals:

  ...
  "reported": {
      "device": {
        "serviceInfo": {
          "fota_v2": [
            "APP",
            "MODEM"
          ],
          "fota_v2_ble": true
        },
      }
    }

See the REST preparations section of the FOTA documentation for REST API instructions.

To do this over MQTT, send the following message to the /shadow/update topic (include the state field):

{
  "state": {
    "reported": {
      "device": {
        "serviceInfo": {
          "fota_v2": [
            "APP",
            "MODEM",
            "BOOT"
          ]
        }
      }
    }
  }
}