Cellular: nRF Cloud multi-service

This sample is a minimal, error tolerant, integrated demonstration of the nRF Cloud, Location, and AT Host libraries. It demonstrates how you can integrate Firmware-Over-The-Air (FOTA), Location Services, Alert and Log Services, periodic sensor sampling, and more in your nRF Cloud-enabled application. It also demonstrates how to build connected, error-tolerant applications without worrying about physical-level specifics using Zephyr’s conn_mgr.

Requirements

The sample supports the following development kits:

Hardware platforms

PCA

Board name

Build target

Shields

Thingy:91

PCA20035

thingy91

thingy91/nrf9160/ns

nRF9161 DK

PCA10153

nrf9161dk

nrf9161dk/nrf9161/ns

nRF9160 DK

PCA10090

nrf9160dk

nrf9160dk/nrf9160/ns

nRF9151 DK

PCA10171

nrf9151dk

nrf9151dk/nrf9151/ns

nRF5340 DK

PCA10095

nrf5340dk

nrf5340dk/nrf5340/cpuapp/ns

When built for an _ns build target, the sample is configured to compile and run as a non-secure application with Cortex-M Security Extensions enabled. Therefore, it automatically includes Trusted Firmware-M that prepares the required peripherals and secure services to be available for the application.

External flash

To use the external flash memory on the nRF9160 DK v0.14.0 or later versions, the board controller firmware must be of version v2.0.1. This is the factory firmware version. If you need to program the board controller firmware again, complete the following steps:

  1. Download the nRF9160 DK board controller firmware from the nRF9160 DK downloads page.

  2. Make sure the PROG/DEBUG SW10 switch on the nRF9160 DK is set to nRF52.

  3. Program the board controller firmware (nrf9160_dk_board_controller_fw_2.0.1.hex) using the Programmer app in nRF Connect for Desktop.

Note

The board controller firmware version must be v2.0.1 or higher, which enables the pin routing to external flash.

See Board controller for more details.

For the nRF9160 DK, when using CoAP, use modem firmware version 1.3.5 or above to benefit from the power savings provided by DTLS Connection ID.

Features

This sample implements or demonstrates the following features:

Structure and theory of operation

This sample is separated into a number of smaller functional units. The top level functional unit and entry point for the sample is the src/main.c file. This file starts three primary threads, each with a distinct function:

src/main.c also optionally starts a fourth thread, the led_thread, which animates any onboard LEDs if LED status indication is enabled.

When using CoAP, two additional threads start:

  • The CoAP FOTA job checking thread (coap_fota, src/fota_support_coap.c) runs the CoAP FOTA job check loop which periodically asks nRF Cloud for any pending FOTA job.

  • The CoAP shadow delta checking thread (coap_shadow, src/shadow_support_coap.c) runs the CoAP shadow delta checking loop which periodically asks nRF Cloud for any shadow changes.

Cloud connection loop

The cloud connection loop (implemented in src/cloud_connection.c) monitors network availability. It starts a connection with nRF Cloud whenever the Internet becomes reachable, and closes that connection whenever Internet access is lost. It has error handling and timeout features to ensure that failed or lost connections are re-established after a waiting period (CONFIG_CLOUD_CONNECTION_RETRY_TIMEOUT_SECONDS).

Since the CONFIG_NRF_MODEM_LIB_NET_IF Kconfig option is enabled, Zephyr’s conn_mgr automatically enables and connects to LTE.

Whenever a connection to nRF Cloud is started, the cloud connection loop follows the nRF Cloud connection process. The nRF Cloud library handles most of the connection process, with exception to the following behavior:

When an MQTT device is first being associated with an nRF Cloud account, the nRF Cloud MQTT API will send a user association request notification to the device. Upon receiving this notification, the device must wait for a user association success notification, and then manually disconnect from and reconnect to nRF Cloud. Notifications of user association success are sent for every subsequent connection after this as well, so the device must only disconnect and reconnect if it previously received a user association request notification. This behavior is handled by the NRF_CLOUD_EVT_USER_ASSOCIATION_REQUEST and NRF_CLOUD_EVT_USER_ASSOCIATED cases inside the cloud_event_handler() function.

When a CoAP device attempts to connect to nRF Cloud, the connection will fail to be authenticated until the device is onboarded to an nRF Cloud account. See Onboarding a device without the nRF Cloud Provisioning Service for details.

Upon startup, the cloud connection loop also updates the device shadow. This is performed in the update_shadow() function.

Device message queue

Any thread may submit device messages to the device message queue (implemented in src/message_queue.c), where they are stored until a working connection to nRF Cloud is established. Once this happens, the message thread transmits all enqueued device messages, one at a time and in fast succession, to nRF Cloud. If an enqueued message fails to send, it will be sent back to the queue and tried again later. Transmission is paused whenever connection to nRF Cloud is lost. If more than CONFIG_MAX_CONSECUTIVE_SEND_FAILURES messages in a row fail to send, the connection to nRF Cloud is reset, and then reconnected after a delay (CONFIG_CLOUD_CONNECTION_RETRY_TIMEOUT_SECONDS).

Most messages sent to nRF Cloud by this sample are sent using the message queue, but the following are sent directly:

Application thread and main application loop

The application thread is implemented in the src/application.c file, and is responsible for the high-level behavior of this sample. It performs the following major tasks:

Note

Periodic location tracking is handled by the Location library once it has been requested, whereas temperature samples are individually requested by the Main Application Loop.

CoAP FOTA job check loop

The nRF Cloud CoAP service provides device-initiated communication with the server. Server to device communication is only in response to a device request, which means the device polls for asynchronous changes to server resources. The CoAP FOTA job checking thread performs the following tasks:

  • Checks the settings storage area to see if the device has recently rebooted after performing a FOTA update.

  • If it had recently rebooted, it sends the results of the FOTA update to the server with the nrf_cloud_coap_fota_job_update() function.

  • Checks for a new FOTA job with the nrf_cloud_coap_fota_job_get() function.

  • If one is available, it downloads the update using HTTPS, saves the job information in settings, then reboots the device.

  • If the download was unsuccessful, it notifies the server with the nrf_cloud_coap_fota_job_update() function.

CoAP shadow delta checking loop

The CoAP shadow delta checking thread performs the following tasks:

  • Checks for a change in the device shadow with the nrf_cloud_coap_shadow_get() function.

  • Parse and process the JSON shadow delta document.

  • If a change is received, the thread sends the change back with the nrf_cloud_coap_shadow_state_update() function. This is necessary to prevent the device from unnecessarily receiving the same shadow delta the next time through the loop.

FOTA

When using MQTT, the FOTA update support is almost entirely implemented by enabling the CONFIG_NRF_CLOUD_FOTA option (which is implicitly enabled by CONFIG_NRF_CLOUD_MQTT).

However, even with CONFIG_NRF_CLOUD_FOTA enabled, applications must still reboot themselves manually after FOTA download completion, and must still update their Device Shadow to reflect FOTA support.

Reboot after download completion is handled by the src/fota_support.c file, triggered by a call from the src/cloud_connection.c file.

Device Shadow updates are performed in the src/cloud_connection.c file.

In a real-world setting, these two behaviors could be directly implemented in the src/cloud_connection.c file. In this sample, they are separated for clarity.

This sample supports full modem FOTA for the nRF91 Series development kit. Version 0.14.0 or higher is required for nRF9160 DK. To enable full modem FOTA, add the following parameter to your build command:

-DEXTRA_CONF_FILE=overlay_full_modem_fota.conf

Also, specify your development kit version by appending it to the board name. For example, if you are using an nRF9160 DK version 1.0.1, use the following board name in your build command:

nrf9160dk@1.0.1/nrf9160/ns

This sample also supports placement of the MCUboot secondary partition in external flash for the nRF91x1 DKs, and for nRF9160 DK version 0.14.0 and higher. To enable this, add the following parameter to your build command:

-DEXTRA_CONF_FILE=overlay_mcuboot_ext_flash.conf

Then specify your development kit version as described earlier.

Temperature sensing

Temperature sensing is mostly implemented in the src/temperature.c file. This includes generation of false temperature readings on your nRF91 Series DK, which does not have a built-in temperature sensor.

Using the built-in temperature sensor of the Nordic Thingy:91 requires a devicetree overlay file, namely the boards/thingy91_nrf9160_ns.overlay file, as well as enabling the Kconfig options CONFIG_SENSOR and CONFIG_BME680. The devicetree overlay file is automatically applied during compilation whenever the thingy91/nrf9160/ns target is selected. The required Kconfig options are implicitly enabled by CONFIG_TEMP_DATA_USE_SENSOR.

Note

For temperature readings to be visible in the nRF Cloud portal, they must be marked as enabled in the Device Shadow. This is performed by the src/cloud_connection.c file.

Location tracking

All matters concerning location tracking are handled in the src/location_tracking.c file. This involves setting up a periodic location request, and then passing the results to a callback configured by the src/application.c file.

For location readings to be visible in the nRF Cloud portal, they must be marked as enabled in the Device Shadow. This is performed by the src/cloud_connection.c file.

Each enabled location method is tried in the following order until one succeeds: GNSS, Wi-Fi, then cellular.

The GNSS and cellular location tracking methods are enabled by default and will work on both Thingy:91 and nRF91 Series DK targets.

The Wi-Fi location tracking method is not enabled by default and requires the nRF7002 Wi-Fi companion chip.

When enabled, this location method scans the MAC addresses of nearby access points and submits them to nRF Cloud to obtain a location estimate.

See Building with nRF7002 EK Wi-Fi scanning support (for nRF91 Series DK) for details on how to enable Wi-Fi location tracking.

This sample supports placing P-GPS data in external flash for the nRF91 Series development kit. Version 0.14.0 or later is required for the nRF9160 DK. To enable this, add the following parameter to your build command:

-DEXTRA_CONF_FILE=overlay_pgps_ext_flash.conf

Also, specify your development kit version by appending it to the board name. For example, if you are using an nRF9160 development kit version 1.0.1, use the following board name in your build command:

nrf9160dk@1.0.1/nrf9160/ns

Remote execution of modem AT commands (MQTT only)

If the CONFIG_AT_CMD_REQUESTS Kconfig option is enabled, you can remotely execute modem AT commands on your device by sending a device message with appId MODEM, messageType CMD, and the data key set to the command you would like to execute.

The application executes the command stored in the data key, and responds with a device message containing either an error code or the response from the modem to the AT command.

For example, if you send the following device message to a device running this sample with CONFIG_AT_CMD_REQUESTS enabled:

{"appId":"MODEM", "messageType":"CMD", "data":"AT+CGMR"}

It executes the modem AT command AT+CGMR and sends a device message similar to the following back to nRF Cloud (an example of nRF9160, modem firmware v1.3.2):

{
   "appId": "MODEM",
   "messageType": "DATA",
   "ts": 1669244834095,
   "data": "mfw_nrf9160_1.3.2\r\nOK"
}

To do this in the nRF Cloud portal, write {“appId”:”MODEM”, “messageType”:”CMD”, “data”:”AT+CGMR”} into the Send a message box of the Terminal card and click Send.

LED status indication

On boards that support LED status indication, this sample can indicate its current status with any on-board LEDs.

This is performed by a background thread implemented in the src/led_control.c file.

Other threads may request either a temporary or indefinite LED pattern. This wakes up the led_thread, which begins animating the requested pattern, sleeping for 100 milliseconds at a time between animation frames, until the requested pattern has completed (if it is temporary), or until a new pattern is requested in its place.

This feature is enabled by default for the build_target mentioned in the Requirements sections.

The patterns displayed, the states they describe, and the options required for them to appear are as follows:

Status

Thingy:91

nRF91 Series DK

Conditions

Trying to connect to nRF Cloud (for the first time)

Pulsating orange LED

Single LED lit, spinning around the square of LEDs

LED status indication is enabled

Connection to nRF Cloud lost, reconnecting

Pulsating orange LED

Single LED lit, spinning around the square of LEDs

The CONFIG_LED_VERBOSE_INDICATION option is enabled

Fatal error

Blinking red LED, 75% duty cycle

All four LEDs blinking, 75% duty cycle

LED status indication is enabled

Device message sent successfully

Blinking green LED, 25% duty cycle

Alternating checkerboard pattern (two LEDs are lit at a time, either LED1 and LED4, or LED2 and LED3)

The CONFIG_LED_VERBOSE_INDICATION option is enabled

Idle

LED pulsating between blue and cyan

Single LED lit, bouncing between opposite corners (LED1 and LED4)

The CONFIG_LED_CONTINUOUS_INDICATION option is enabled

Under all other circumstances, on-board LEDs are turned off.

Note

The CONFIG_LED_VERBOSE_INDICATION and CONFIG_LED_CONTINUOUS_INDICATION options are enabled by default.

See Customizing LED status indication for details on customizing the LED behavior.

See Configuring LED status indication for third-party boards for details on configuring LED status indication on third-party boards.

Test counter

You can enable a test counter by enabling the CONFIG_TEST_COUNTER option. Every time a sensor sample is sent, this counter is incremented by one, and its current value is sent to nRF Cloud. A plot of the value of the counter over time is automatically shown in the nRF Cloud portal. This plot is useful for tracking, visualizing, and debugging connection loss, resets, and re-establishment behavior.

Device message formatting

This sample, when using MQTT to communicate with nRF Cloud, constructs JSON-based device messages.

While any valid JSON string can be sent as a device message, and accepted and stored by nRF Cloud, there are some pre-designed message structures, known as schemas. The nRF Cloud portal knows how to interpret these schemas. These schemas are described in nRF Cloud application protocols for long-range devices. The device messages constructed in the src/application.c file all adhere to the general message schema.

GNSS and temperature data device messages conform to the gnss and temp deviceToCloud schemas respectively.

This sample, when using CoAP to communicate with nRF Cloud, uses the nRF Cloud CoAP library to construct and transmit CBOR-based device messages. Some CoAP traffic, specifically AWS shadow traffic, remains in JSON format.

Configuration

See Configuring and building an application for information about how to permanently or temporarily change the configuration.

Disabling key features

You can independently disable the following key features of this sample by setting their respective Kconfig option disabled:

Feature

Kconfig option

GNSS-based location tracking

CONFIG_LOCATION_TRACKING_GNSS

Cellular-based location tracking

CONFIG_LOCATION_TRACKING_CELLULAR

Wi-Fi-based location tracking

CONFIG_LOCATION_TRACKING_WIFI

Temperature tracking

CONFIG_TEMP_TRACKING

GNSS assistance (A-GNSS)

CONFIG_NRF_CLOUD_AGNSS

Predictive GNSS assistance (P-GPS)

CONFIG_NRF_CLOUD_PGPS

FOTA when using MQTT

CONFIG_NRF_CLOUD_FOTA

FOTA when using CoAP

CONFIG_COAP_FOTA

Shadow handling when using CoAP

CONFIG_COAP_SHADOW

If you disable GNSS, Wi-Fi-based, and cellular-based location tracking, location tracking is completely disabled. In that case, also set the CONFIG_LOCATION_TRACKING option to disabled.

For examples, see the related minimal overlays in the Building with minimal services section.

Note

MQTT should only be used with applications that need to stay connected constantly or transfer data frequently. While this sample does allow its core features to be slowed or completely disabled, in real-world applications, you should carefully consider your data throughput and whether MQTT is an appropriate solution. If you want to disable or excessively slow all of these features for a real-world application, other solutions, such as the nRF Cloud Rest API, may be more appropriate.

Customizing GNSS antenna configuration

This sample uses the Modem antenna library, which is enabled by default for the build_target mentioned in the Requirements sections.

If you are using a different board or build target, or would like to use a custom or external GNSS antenna, see the Modem antenna library documentation for configuration instructions.

Enable CONFIG_MODEM_ANTENNA_GNSS_EXTERNAL to use an external antenna.

Customizing LED status indication

To disable LED status indication (other than the selected idle behavior) after a connection to nRF Cloud has been established at least once, disable CONFIG_LED_VERBOSE_INDICATION.

To turn the LED off while the sample is idle (rather than show an idle pattern), disable CONFIG_LED_CONTINUOUS_INDICATION.

If you disable both of these options together, the status indicator LED remains off after a connection to nRF Cloud has been established at least once.

Configuring LED status indication for third-party boards

This sample assumes that the target board either has a single RGB LED with PWM support, or four discrete LEDs available.

For third-party boards, you can select the RGB LED option by enabling both the CONFIG_LED_INDICATION_PWM and CONFIG_LED_INDICATION_RGB options. In this case, the board must have a devicetree entry marked as compatible with the Zephyr pwm-leds driver.

Otherwise, the four-LED option (CONFIG_LED_INDICATION_GPIO and CONFIG_LED_INDICATOR_4LED) is selected by default as long as there is a devicetree entry compatible with the Zephyr gpio-leds driver.

The four-LED option should work even if there are not four LEDs available, as long as an appropriate devicetree entry exists. However, if fewer than four LEDs are available, the patterns may be difficult to identify.

To add your own LED indication implementations, you can add values to the LED_INDICATOR Kconfig choice and modify the src/led_control.c file accordingly.

To disable LED indication, enable the CONFIG_LED_INDICATION_DISABLED option.

For examples of how to set up devicetree entries compatible with the Zephyr gpio-leds and pwm-leds drivers, see the following files, depending on the DK you are using:

  • zephyr/boards/nordic/nrf9161dk/nrf9151dk_nrf9151_common.dts

  • zephyr/boards/nordic/nrf9161dk/nrf9161dk_nrf9161_common.dts

  • zephyr/boards/nordic/nrf9160dk/nrf9160dk_nrf9160_common.dts

  • zephyr/boards/arm/thingy91_nrf9160/thingy91_nrf9160_common.dts

Search for nodes with compatible = "gpio-leds"; and compatible = "pwm-leds"; respectively.

Useful debugging options

To see all debug output for this sample, enable the CONFIG_MULTI_SERVICE_LOG_LEVEL_DBG option.

To monitor the GNSS module (for instance, to see whether A-GNSS or P-GPS assistance data is being consumed), enable the CONFIG_NRF_CLOUD_GPS_LOG_LEVEL_DBG option.

See also the Test counter.

Configuration options

Set the following configuration options for the sample:

CONFIG_MULTI_SERVICE_LOG_LEVEL_DBG - Sample debug logging

Sets the log level for this sample to debug.

CONFIG_CLOUD_CONNECTION_RETRY_TIMEOUT_SECONDS - Cloud connection retry timeout (seconds)

Sets the cloud connection retry timeout in seconds.

CONFIG_CLOUD_READY_TIMEOUT_SECONDS - Cloud readiness timeout (seconds)

Sets the cloud readiness timeout in seconds. If the connection to nRF Cloud does not become ready within this timeout, the sample will reset its connection and try again.

CONFIG_DATE_TIME_ESTABLISHMENT_TIMEOUT_SECONDS - Modem date and time establishment timeout (seconds)

Sets the timeout for modem date and time establishment (in seconds). The sample waits for this number of seconds for the modem to determine the current date and time before giving up and moving on.

CONFIG_APPLICATION_THREAD_STACK_SIZE - Application Thread Stack Size (bytes)

Sets the stack size (in bytes) for the application thread of the sample.

CONFIG_CONNECTION_THREAD_STACK_SIZE - Connection Thread Stack Size (bytes)

Sets the stack size (in bytes) for the connection thread of the sample.

CONFIG_MESSAGE_THREAD_STACK_SIZE - Message Queue Thread Stack Size (bytes)

Sets the stack size (in bytes) for the message queue processing thread of the sample.

CONFIG_MAX_OUTGOING_MESSAGES - Outgoing message maximum

Sets the maximum number of messages that can be in the outgoing message queue. Messages submitted past this limit will not be enqueued.

CONFIG_MAX_CONSECUTIVE_SEND_FAILURES - Max outgoing consecutive send failures

Sets the maximum number of device messages which may fail to send before a connection reset and cooldown is triggered.

CONFIG_CONSECUTIVE_SEND_FAILURE_COOLDOWN_SECONDS - Cooldown after max consecutive send failures exceeded (seconds)

Sets the cooldown time (in seconds) after the maximum number of consecutive send failures is exceeded. If a connection reset is triggered by too many failed device messages, the sample waits for this long (in seconds) before trying again.

CONFIG_SENSOR_SAMPLE_INTERVAL_SECONDS - Sensor sampling interval (seconds)

Sets the time to wait between each temperature sensor sample.

Note

Decreasing the sensor sampling interval too much leads to more frequent use of the LTE connection, which can prevent GNSS from obtaining a fix. This is because GNSS can operate only when the LTE connection is not active. Every time a sensor sample is sent, it interrupts any attempted GNSS fix. The exact time required to obtain a GNSS fix will vary depending on satellite visibility, time since last fix, the type of antenna used, and other environmental factors. In good conditions, and with A-GNSS data, one minute is a reasonable interval for reliably getting a location estimate. This allows using long enough value for CONFIG_GNSS_FIX_TIMEOUT_SECONDS, while still leaving enough time for falling back to cellular positioning if needed.

The default sensor sampling interval, 60 seconds, will quickly consume cellular data, and should not be used in a production environment. Instead, consider using a less frequent interval, and if necessary, combining multiple sensor samples into a single device message , or combining multiple device messages using the d2c/bulk device message topic.

If you significantly increase the sampling interval, you must keep the CONFIG_MQTT_KEEPALIVE short to avoid the carrier silently closing the MQTT connection due to inactivity, which could result in dropped device messages. The exact maximum value depends on your carrier. In general, a few minutes or less should work well.

CONFIG_GNSS_FIX_TIMEOUT_SECONDS - GNSS fix timeout (seconds)

Sets the GNSS fix timeout in seconds. On each location sample, try for this long to achieve a GNSS fix before falling back to cellular positioning.

CONFIG_LOCATION_TRACKING - Enable or disable location tracking

Enables location tracking. Enable at least one location tracking method to avoid a build error.

CONFIG_LOCATION_TRACKING_SAMPLE_INTERVAL_SECONDS - Location sampling interval (seconds)

Sets the location sampling interval in seconds.

CONFIG_LOCATION_TRACKING_GNSS - GNSS location tracking

Enables GNSS location tracking. Disable CONFIG_LOCATION_TRACKING and all location tracking methods to completely disable location tracking. Defaults to enabled.

CONFIG_LOCATION_TRACKING_CELLULAR - Cellular location tracking

Enables cellular location tracking. Disable CONFIG_LOCATION_TRACKING and all location tracking methods to completely disable location tracking. Defaults to enabled.

CONFIG_LOCATION_TRACKING_WIFI - Wi-Fi location tracking

Enables Wi-Fi location tracking. Disable CONFIG_LOCATION_TRACKING and all location tracking methods to completely disable location tracking. Requires the use of an nRF7002 companion chip. Defaults to disabled.

CONFIG_TEMP_DATA_USE_SENSOR - Use genuine temperature data

Sets whether to take genuine temperature measurements from a connected BME680 sensor, or just simulate sensor data.

CONFIG_TEMP_TRACKING - Track temperature data

Enables tracking and reporting of temperature data to nRF Cloud. Defaults to enabled.

CONFIG_LED_INDICATION_PWM - PWM LED indication

Use the Zephyr pwm-leds driver for LED indication. Defaults to enabled on the Thingy:91.

CONFIG_LED_INDICATION_GPIO - GPIO LED indication

Use the Zephyr gpio-leds driver for LED indication. Defaults to enabled if there is a compatible devicetree entry, and the Thingy:91 is not the target. Defaults to enabled on the nRF91 Series DKs.

CONFIG_LED_INDICATION_DISABLED - Completely disable LED indication

Defaults to enabled if both CONFIG_LED_INDICATION_PWM and CONFIG_LED_INDICATION_GPIO are disabled.

CONFIG_LED_INDICATOR_RGB - RGB LED status indication

Use an on-board RGB LED for status indication. Defaults to enabled on the Thingy:91.

CONFIG_LED_INDICATOR_4LED - Four-LED status indication

Use four discrete LEDs for status indication. Defaults to enabled if CONFIG_LED_INDICATOR_RGB is disabled and LED indication is not disabled.

CONFIG_LED_VERBOSE_INDICATION - Verbose LED status indication

Show more detailed LED status updates. Show a pattern when device messages are successfully sent, and when the initial connection to nRF Cloud is lost. Defaults to enabled if LED indication is enabled.

CONFIG_LED_CONTINUOUS_INDICATION - Continuous LED status indication

Show an idle pattern, rather than turn the LEDs off, when the sample is idle. Defaults to enabled if LED indication is enabled.

CONFIG_TEST_COUNTER - Enable test counter

Enables the test counter.

CONFIG_AT_CMD_REQUESTS - Enable AT command requests

Allow remote execution of modem AT commands, requested using application-specific device messages. See Remote execution of modem AT commands (MQTT only) for details.

CONFIG_AT_CMD_REQUEST_RESPONSE_BUFFER_LENGTH - Length of AT command request response buffer (bytes)

Sets the size of the buffer for storing responses to modem AT commands before they are forwarded to the cloud. Modem responses longer than this length will be replaced with an error code message (-NRF_E2BIG). Cannot be less than 40 bytes.

When using CoAP, the following additional configuration options are available:

CONFIG_COAP_SHADOW - Enable shadow handling

Periodically check for and process shadow delta messages.

If CONFIG_COAP_SHADOW is enabled, these options additional are available:

CONFIG_COAP_SHADOW_CHECK_RATE_SECONDS - Rate to check for shadow changes

How many seconds between requests for any change (delta) in the device shadow.

CONFIG_COAP_SHADOW_THREAD_STACK_SIZE - CoAP Shadow Thread Stack Size (bytes)

Sets the stack size (in bytes) for the shadow delta checking thread of the sample.

CONFIG_COAP_FOTA - Enable FOTA with CoAP

The sample periodically checks for pending FOTA jobs. The sample performs the FOTA update when received.

If CONFIG_COAP_FOTA is enabled, these options additional are available:

CONFIG_COAP_FOTA_DL_TIMEOUT_MIN - CoAP FOTA download timeout

The time in minutes allotted for a FOTA download to complete.

CONFIG_COAP_FOTA_USE_NRF_CLOUD_SETTINGS_AREA - Make FOTA compatible with other samples

Use the same settings area as the nRF Cloud FOTA library.

CONFIG_COAP_FOTA_SETTINGS_NAME - Settings identifier

Set the identifier for the CoAP FOTA storage if CONFIG_COAP_FOTA_USE_NRF_CLOUD_SETTINGS_AREA is not enabled.

CONFIG_COAP_FOTA_SETTINGS_KEY_PENDING_JOB - Settings item key

Set the settings item key for pending FOTA job info if CONFIG_COAP_FOTA_USE_NRF_CLOUD_SETTINGS_AREA is not enabled.

CONFIG_COAP_FOTA_JOB_CHECK_RATE_MINUTES - FOTA job check interval (minutes)

How many minutes between requests for a FOTA job.

CONFIG_COAP_FOTA_THREAD_STACK_SIZE - CoAP FOTA Thread Stack Size (bytes)

Sets the stack size (in bytes) for the FOTA job checking thread of the sample.

Sending traces over UART on an nRF91 Series DK

To send modem traces over UART on an nRF91 Series DK, configuration must be added for the UART device in the devicetree and Kconfig. This is done by adding the modem trace UART snippet when building and programming.

Use the Cellular Monitor app for capturing and analyzing modem traces.

TF-M logging must use the same UART as the application. For more details, see shared TF-M logging.

Building and running

This sample can be found under samples/cellular/nrf_cloud_multi_service in the nRF Connect SDK folder structure.

When built as firmware image for the _ns build target, the sample has Cortex-M Security Extensions (CMSE) enabled and separates the firmware between Non-Secure Processing Environment (NSPE) and Secure Processing Environment (SPE). Because of this, it automatically includes the Trusted Firmware-M (TF-M). To read more about CMSE, see Processing environments.

To build the sample with Visual Studio Code, follow the steps listed on the How to build an application page in the nRF Connect for VS Code extension documentation. See Configuring and building an application for other building scenarios, Programming an application for programming steps, and Testing and optimization for general information about testing and debugging in the nRF Connect SDK.

Building with LTE connectivity

You can build the sample to connect over LTE as follows:

west build -p -b build_target

Replace the build_target with the build target of the nRF91 Series device you are using (see the Requirements section).

Once the sample is built and flashed, proceed to Onboarding a device without the nRF Cloud Provisioning Service for instructions on how to onboard your device.

Building with nRF Cloud Provisioning Service Support

The nRF Cloud Provisioning Service allows you to securely provision and onboard your Nordic Semiconductor devices entirely over-the-air (after you have obtained an attestation token for the device).

Note

This service is not compatible with devices that use the nRF9160, but only for the nRF9161 device.

You can enable support for this service by building the sample as follows:

west build -p -b nrf9161dk/nrf9161/ns -- -DEXTRA_CONF_FILE="overlay-http_nrf_provisioning.conf"

The overlay-http_nrf_provisioning.conf overlay enables the nRF Cloud device provisioning library, and its shell interface to use HTTP for communication. A side-effect of this is that the sample will use the AT shell library instead of the AT Host library, so AT commands must be issued using the at shell command.

Once the sample is built and flashed, proceed to Provisioning with the nRF Cloud Provisioning Service for instructions on how to provision your device with the Provisioning Service. The device is identified using its UUID rather than its IMEI, since both overlays set the CONFIG_NRF_CLOUD_CLIENT_ID_SRC_INTERNAL_UUID Kconfig option.

Building with nRF7002 EK Wi-Fi scanning support (for nRF91 Series DK)

To build the sample with nRF7002 EK Wi-Fi scanning support, use the -DSHIELD=nrf7002ek and -DEXTRA_CONF_FILE=overlay-nrf7002ek-wifi-scan-only.conf options.

This enables the Wi-Fi location tracking method automatically.

west build -p -b build_target -- -DSHIELD=nrf7002ek -DEXTRA_CONF_FILE="overlay-nrf7002ek-wifi-scan-only.conf"

Replace the build_target with the build target of the nRF91 Series device you are using (see the Requirements section).

See also the paragraphs on the Wi-Fi location tracking method.

Once the sample is built and flashed, proceed to Onboarding a device without the nRF Cloud Provisioning Service for instructions on how to onboard your device.

Note

This option enables Wi-Fi scanning, but still uses LTE connectivity.

Building with experimental support for Wi-Fi connectivity for nRF5340 DK with nRF7002 EK (MQTT only)

This sample experimentally supports connecting to nRF Cloud using Wi-Fi instead of using LTE.

An overlay for this is only provided for the nRF5340 DK with the nRF7002 EK shield attached.

It is possible to use Wi-Fi with other hardware combinations (such as the nRF7002 DK), but you must adjust heap and stack usage accordingly. See the src/prj.conf configuration file and the overlay_nrf7002ek_wifi_no_lte.conf overlay for additional details.

Important

Connecting to nRF Cloud using Wi-Fi currently requires that device credentials are used insecurely.

The provided overlay for Wi-Fi connectivity uses the TLS Credentials Subsystem (with the PSA Protected Storage backend, see CONFIG_TLS_CREDENTIALS_BACKEND_PROTECTED_STORAGE) to store credentials when not in use. Even though this is more secure than hard-coded credentials, the device private key still has to be loaded into unprotected memory during TLS connections.

This overlay also enables the TLS Credentials Shell for run-time credential installation.

If you are certain you understand the risks, you can configure your build to use Wi-Fi connectivity on the nRF5340 DK with the nRF7002 EK shield by using the --board nrf5340dk/nrf5340/cpuapp/ns target and the -DSHIELD=nrf7002ek and -DEXTRA_CONF_FILE=overlay_nrf7002ek_wifi_no_lte.conf options.

You must also configure a (globally unique) device ID at build time by enabling the CONFIG_NRF_CLOUD_CLIENT_ID_SRC_COMPILE_TIME Kconfig option and setting CONFIG_NRF_CLOUD_CLIENT_ID to the device ID.

For example, for a device with the device ID 698d4c11-0ccc-4f04-89cd-6882724e3f6f:

west build --board nrf5340dk/nrf5340/cpuapp/ns -p always -- -DSHIELD=nrf7002ek -DEXTRA_CONF_FILE=overlay_nrf7002ek_wifi_no_lte.conf -DCONFIG_NRF_CLOUD_CLIENT_ID_SRC_COMPILE_TIME=y -DCONFIG_NRF_CLOUD_CLIENT_ID="698d4c11-0ccc-4f04-89cd-6882724e3f6f"

Once the sample is built and flashed, proceed to Onboarding a device without the nRF Cloud Provisioning Service for instructions on how to onboard your device.

Once your device is onboarded, proceed to Setting up Wi-Fi access point credentials for instructions on configuring your device to connect to a specific access point.

Building with hard-coded CA and device credentials

The CONFIG_NRF_CLOUD_PROVISION_CERTIFICATES Kconfig option allows you to use hard-coded CA and device credentials stored in unprotected program memory for connecting to nRF Cloud.

Important

The CONFIG_NRF_CLOUD_PROVISION_CERTIFICATES Kconfig option is not secure, and should be used only for demonstration purposes! Because this setting stores your device’s private key in unprotected program memory, using it makes your device vulnerable to impersonation.

Note

This is only one of several mutually exclusive ways to install credentials to your device. See Provisioning and onboarding for a list of other methods.

If you are certain you understand the inherent security risks, you can use this option as follows:

  1. Follow the instructions under Onboarding with hard-coded device credentials.

  2. Create a certs folder directly in the nrf_cloud_multi_service folder, and copy client-cert.pem, private-key.pem, and ca-cert.pem files into it.

    Make sure not to place the new folder in the nrf_cloud_multi_service/src folder by accident.

    Now, these certificates are automatically used if the CONFIG_NRF_CLOUD_PROVISION_CERTIFICATES Kconfig option is enabled.

  3. Build the sample with the CONFIG_NRF_CLOUD_PROVISION_CERTIFICATES Kconfig option enabled and the device ID you created configured.

    This is required for onboarding to succeed.

    Enable the CONFIG_NRF_CLOUD_CLIENT_ID_SRC_COMPILE_TIME Kconfig option and set CONFIG_NRF_CLOUD_CLIENT_ID to the device ID.

    For example, if the device ID is 698d4c11-0ccc-4f04-89cd-6882724e3f6f:

    west build --board your_board -p always -- -DCONFIG_NRF_CLOUD_PROVISION_CERTIFICATES=y -DCONFIG_NRF_CLOUD_CLIENT_ID_SRC_COMPILE_TIME=y -DCONFIG_NRF_CLOUD_CLIENT_ID="698d4c11-0ccc-4f04-89cd-6882724e3f6f"

Setting up Wi-Fi access point credentials

This sample uses the Wi-Fi credentials library to manage Wi-Fi credentials. Before the sample can connect to a Wi-Fi network, you must add at least one credential set.

Once your device has been flashed with this sample, you can add a credential by connecting to your device’s UART interface and then entering the following command:

wifi_cred add NetworkSSID WPA2-PSK NetworkPassword

Where NetworkSSID is replaced with the SSID of the Wi-Fi access point you want your device to connect to, and NetworkPassword is its password. Then either reboot the device or use the wifi_cred auto_connect command to manually trigger a connection attempt.

From now on, these credentials will automatically be used when the configured network is reachable.

See the Wi-Fi shell sample documentation for more details on the wifi_cred command.

Building with nRF Cloud logging support

To enable transmission of logs to nRF Cloud using the nRF Cloud Log library, add the following parameter to your build command:

-DEXTRA_CONF_FILE=overlay_nrfcloud_logging.conf

This overlay enables transmission of logs to nRF Cloud. Set the CONFIG_NRF_CLOUD_LOG_OUTPUT_LEVEL Kconfig option to the log level of messages to send to nRF Cloud, such as 4 for debug log messages.

The overlay selects the CONFIG_LOG_BACKEND_NRF_CLOUD_OUTPUT_TEXT Kconfig option that enables log messages in JSON format. You can read JSON log messages in real-time in the nRF Cloud user interface. However, because JSON logs are large, you may want to edit the overlay file to change to using dictionary logging. Deselect the CONFIG_LOG_BACKEND_NRF_CLOUD_OUTPUT_TEXT Kconfig option and select CONFIG_LOG_BACKEND_NRF_CLOUD_OUTPUT_DICTIONARY instead. See Dictionary-based Logging to learn how dictionary-based logging works, how the dictionary is built, and how to decode the binary log output.

Building with minimal services

To build the sample with only temperature tracking enabled for either MQTT or CoAP, add the following parameter to your build command:

-DEXTRA_CONF_FILE=overlay_min_mqtt.conf

or

-DEXTRA_CONF_FILE=overlay_min_coap.conf

These overlays show all the Kconfig settings changes needed to properly disable all but a single sensor.

Provisioning and onboarding

For your device to successfully connect to nRF Cloud, you must onboard it. The following sections outline the various onboarding methods that this sample supports.

Note

You only need to perform one of the above methods. Select the one that best matches your needs, then build and run the sample with the required build configuration.

Download and install nRF Cloud Utilities

To perform many of the actions in the other sections, you will need to install the nRF Cloud Utilities repository. This is not necessary if you are using the auto-onboarding feature of the nRF Cloud Provisioning Service.

To install the repository, clone or download it and install the required packages.

Provisioning with the nRF Cloud Provisioning Service

The nRF Cloud Provisioning Service is only compatible with nRF91x1 devices. For devices using the nRF9160, proceed to Onboarding a device without the nRF Cloud Provisioning Service.

If you have enabled support for the provisioning service, you can provision and onboard your device in one of two ways:

  • Using auto-onboarding, the easiest method.

    The nRF Cloud Provisioning Service auto-onboarding is currently compatible with CoAP and REST but not MQTT connectivity to nRF Cloud; for that, use scripted onboarding.

    With this method, use the nRF Connect Serial Terminal program and the nRF Cloud portal. The device ID used in nRF Cloud portal requires the UUID format and not the ‘nrf-IMEI‘ format. See device claiming for more information.

  • Using scripted onboarding, as follows:

    First, create a self-signed CA certificate.

    Then, complete the following steps for each device you wish to onboard:

    1. Make sure that your device is plugged in and this sample has been flashed to it.

    2. Use the claim_and_provision_device.py Python script you installed to provision and onboard your device

      python3 claim_and_provision_device.py --api_key "your_api_key" --ca="self_self_cert_serial_ca.pem" --ca_key="self_self_cert_serial_prv.pem" --install_ca --unclaim --id_imei --id_str "nrf-"

      Where the .pem files are the self-signed CA certificate and private key files you created and your_api_key is your nRF Cloud REST API key.

      Note

      This command assumes you have left the CONFIG_NRF_CLOUD_CLIENT_ID_SRC_IMEI option enabled and the CONFIG_NRF_CLOUD_CLIENT_ID_PREFIX option set to nrf-. See Configuration options for device ID to use other device ID formats.

      This script automatically performs the following steps:

      1. Obtains an attestation token from your device over UART using the nRF Cloud device provisioning library shell, and then claims your device on nRF Cloud.

      2. Generates, signs, and installs a device credential for your device.

        • This happens entirely over-the-air.

        • The private key for this credential is generated by the device itself. It is stored securely and never leaves the device.

      3. Installs any necessary root CA certificates.

        • CoAP connections use one root CA certificate, whereas HTTPS and MQTT use another.

        • Devices using CoAP need both installed, since HTTPS is used for FOTA and P-GPS on CoAP devices.

      This script may take a few minutes. When it succeeds, you should see several provisioning commands be issued and succeed, and some additional final output:

      Adding device 'nrf-IMEI' to cloud account...
      ProvisionDevices API call response: 202 - Accepted
      Done.

      Where IMEI is the IMEI of your device.

      The device should also appear in the devices list in the nRF Cloud portal.

      Once the script is complete, you can connect to your device with a UART terminal to monitor its activity.

      Within a few minutes of script completion, it should successfully connect to nRF Cloud and begin demonstrating the supported nRF Cloud features.

Onboarding a device without the nRF Cloud Provisioning Service

If you are not using provisioning service support, you can onboard your devices as follows:

First, create a self-signed CA certificate.

Then, complete the following steps for each device you wish to onboard:

  1. Make sure your device is plugged in and that this sample has been flashed to it.

  2. Install the device and server credentials using the device_credentials_installer.py Python script you installed:

    (Select the protocol (MQTT or CoAP) and connectivity technology (LTE or Wi-Fi) you built the sample for)

    python3 device_credentials_installer.py --ca self_self_cert_serial_ca.pem --ca_key self_self_cert_serial_prv.pem --id_str nrf- --id_imei -s -d --verify

    Where the .pem files are the self-signed CA certificate and private key files you created.

    Note

    This command assumes you have left the CONFIG_NRF_CLOUD_CLIENT_ID_SRC_IMEI option enabled and the CONFIG_NRF_CLOUD_CLIENT_ID_PREFIX option set to nrf-. See Configuration options for device ID to use other device ID formats.

    This script generates, signs, and installs a device credential for your device. The private key for this credential is generated by the device itself, and stored on the modem.

    This script also installs any nRF Cloud root CA certificates required in a single chain to the CONFIG_NRF_CLOUD_SEC_TAG security tag (sec_tag). CoAP connections use one root CA certificate, whereas HTTPS and MQTT use another. Devices using CoAP need both installed, since HTTPS is used for FOTA and P-GPS on CoAP devices.

    If the script succeeds, you should see the following output:

    Saving provisioning endpoint CSV file provision.csv...
    Provisioning CSV file saved
    

    And a new file, provision.csv should be created. This file will be used in the next step.

  3. Navigate to the Bulk Onboard Devices page of the nRF Cloud portal and upload the provision.csv file to onboard the device.

    To get there from the Dashboard, click Devices under Device Management in the navigation pane on the left, then click Add Devices and select Bulk Onboard.

    Once the Bulk Onboard Devices page is open, drag in the provision.csv file and click Onboard.

    You should see a message stating that the file was uploaded successfully, and your device should appear in the Devices page.

Onboarding with hard-coded device credentials

It is possible to onboard your devices using hard-coded device credentials. If you are certain you understand the inherent security risks, you can do so as follows:

First, create a self-signed CA certificate.

Next, complete the following steps for each device you wish to onboard:

  1. Locally generate a device credential

    In addition to the arguments prescribed in that section, also include the -embed_save argument when running the create_device_credentials.py Python script:

    python3 create_device_credentials.py -ca "self_self_cert_serial_ca.pem" -ca_key "self_self_cert_serial_prv.pem" -c US -cn "device_id" -f cred_ -embed_save

    This automatically generates the following three files that are needed for the next step:

    • client-cert.pem

    • private-key.pem

    • ca-cert.pem

    The client-cert.pem and private-key.pem files are specially formatted versions of the cred_<device_id>_crt.pem and cred_<device_id>_prv.pem files respectively. The ca-cert.pem is a copy of the nRF Cloud root CA in the same format. Do not confuse this CA certificate with your self-signed CA certificate. See CA certificates for server authentication in AWS IoT Core for more details.

    Your device needs these three credentials to connect successfully with nRF Cloud.

  2. Manually onboard the device to nRF Cloud

  3. Follow the instructions under Building with hard-coded CA and device credentials.

Creating a self-signed CA certificate for device certificate signing

Before a device can connect to nRF Cloud, it must have device credentials. Unless you are using Just-in-Time provisioning, you need to sign these credentials yourself using a CA certificate you create. This is referred to as your self-signed CA certificate.

To create your self-signed CA certificate:

  1. Download and install the nRF Cloud Utilities repository.

  2. Use the nRF Cloud Utilities create_ca_cert.py Python script to generate the certificate:

    python3 create_ca_cert.py -c US -f self_
    

    Remember to set -c to your two-letter country code. See the Create CA Cert section in the nRF Cloud Utilities documentation for more details.

    You should now have the following three files:

    • self_<self_cert_serial>_ca.pem

    • self_<self_cert_serial>_prv.pem

    • self_<self_cert_serial>_pub.pem

    Where <self_cert_serial> is your self-signed CA certificate’s serial number in hex. These three files are your self-signed CA certificate and private/public keypair. You will use them to sign device credentials.

    If you were directed here as part of other instructions, proceed to the next step of those instructions.

    Note

    You only need to generate these three files once. You can be use them to sign as many device credentials as you need.

Generating device credentials locally

To generate and sign a device credential locally using your self-signed CA certificate, perform the following steps:

  1. Create a globally unique device ID for the device.

    The ID can be anything you want, as long as it is not prefixed with nrf- and is globally unique. Alternatively, if your device is an LTE development kit from Nordic Semiconductor, you can use nrf-<IMEI> where <IMEI> is the IMEI of the device. See nRF Cloud Device ID for details.

    Each device should have its own device ID, and you must use it exactly for all other actions involving that device, otherwise onboarding will fail. This ID is referred to in other steps using the term device_id.

  2. Navigate to the folder where you created your self-signed CA certificate, and use the create_device_credentials.py Python script you installed to generate a self-signed certificate for the device:

    python3 create_device_credentials.py -ca "self_self_cert_serial_ca.pem" -ca_key "self_self_cert_serial_prv.pem" -c US -cn "device_id" -f cred_

    Where device_id is the device ID you created, and the .pem files are the self-signed CA certificate and private key files you created.

    Remember to set -c to your two-letter country code. See the Create Device Credentials section in the nRF Cloud Utilities documentation for more details.

    You should now have the following three files:

    • cred_<device_id>_crt.pem

    • cred_<device_id>_pub.pem

    • cred_<device_id>_prv.pem

    These three files are your device credentials, and can only be used by a single device.

    If you were directed here as part of other instructions, proceed to the next step of those instructions.

    Important

    If an attacker obtains the private key contained in cred_<device_id>_prv.pem, they will be able to impersonate your device.

Onboarding a device manually

Once you have obtained device credentials for your device, it can be onboarded.

To onboard devices manually, you can use the Bulk Onboard Devices page of the nRF Cloud portal as follows:

  1. Create an onboarding CSV file named <device_id>_onboard.csv and give it the following contents:

    device_id,,,,"device_cert"

    Where device_id is replaced by the device ID you created, and device_cert is replaced by the exact contents of <device_id>_crt.pem.

    For example, if the device ID you created is 698d4c11-0ccc-4f04-89cd-6882724e3f6f:

    698d4c11-0ccc-4f04-89cd-6882724e3f6f,,,,"-----BEGIN CERTIFICATE-----
    sCC8AtbNQhzbp4y01FEzXaf5Fko3Qdq0o5LbuNpVA7S6AKAkjt17QzKJAiGWHakh
    RnwzoA2dF4wR0rMP5vR6dqBblaGAA5hN7GE2vPBHTDNZGJ6tZ9dnO6446dg9gGds
    eeadE1HdVnUj8nb+7CGm39vJ4fuNk9vogH0nMdxjCnXAinoOMRx8EklQsR747+Gz
    sxcdVYuNEb/E2vWBHTDNZGJ6tZC1JC9d6/RC3Vb1JC4tWnK9mk/Jw984ZuYugpMc
    1t9umoGFYCz0nMdxjCnXAbnoOMC5A0RxcWPzxfC5A0RH+j+mwoMxwhgfFY4EhVxp
    oCC8labNQhzRC3Vc1JC4tWnK9mpVA7k/o5LbuNpVA7S6AKAkjt17QzKJAiGWHakh
    RXwcoAndF4wPzxfC5A0RHponmwBHTDoM7GE2vPBHTDNZGJ6tZ9dnO6446dg9gGds
    eefdE1HcVnULbuNpVA7S6AKAkjxjCnt1gH0nMdxjCnXAinoOMRx8EklQsR747+Fz
    srm/VYaNEb/E2vPBHTDNZGJ6tZc1JC9d6/RC3Vc1JC4tWnK9mk/Jr984ZuYugpMc
    nt9uZTGFYCzZD0FFAA5NAC4i1PARStFycWPzxfC5A0RqodhswoMxwhgfFY4EhVx=
    -----END CERTIFICATE-----
    "
    

    Do not attempt to use this example directly, it has been filled with dummy data. See nRF Cloud REST API ProvisionDevices for more details.

    If you are onboarding more than a single device at once, you can repeat this format (separated by a newline) for each device you are onboarding. Alternatively, you can create a separate CSV file for each device you wish to onboard, and upload them individually.

  2. Navigate to the Bulk Onboard Devices page of the nRF Cloud portal and upload the <device_id>_onboard.csv file you created.

    To get there from the Dashboard, click Devices under Device Management in the navigation pane on the left, then click Add Devices and select Bulk Onboard.

    Once the Bulk Onboard Devices page is open, drag in the <device_id>_onboard.csv file and click Onboard.

    You should see a message stating that the file was uploaded successfully, and a device with the device ID(s) you created should appear in the Devices page.

If you were directed here as part of other instructions, proceed to the next step of those instructions.

References

Dependencies

This sample uses the following nRF Connect SDK libraries and drivers:

It uses the following sdk-nrfxlib library:

It uses the following Zephyr libraries:

In addition, it uses the following secure firmware component: