Skip to content

Commit 46dc1b8

Browse files
committed
feat: add nRF Cloud provisioning support
Add support for nRF Cloud provisioning: - Modify the cloud module to include states for provisioning. - Add support for reprovisioning of the device via the device shadow. The device will initiate reprovisioning if receiving provisioning commands via the device shadow. This pipeline can be used to issue other commands as well. Reboot also added as an example command. If the device has no valid credentials after boot, it is considered unclaimed. The user needs to claim the device using the attestation token. The device will back off using the cloud built-in backoff mechanism until it's claimed and provisioning can start. If the device is claimed and authenticated, it will start the connection immediately as before. - Update main CDDL format to be able to parse the new shadow format. - Add on-target test that tests different provisioning scenarios on target. Documentation on how to use the feature will follow. Signed-off-by: Simen S. Røstad <simen.rostad@nordicsemi.no>
1 parent 643e6ef commit 46dc1b8

File tree

30 files changed

+1148
-279
lines changed

30 files changed

+1148
-279
lines changed

README.md

Lines changed: 46 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -14,104 +14,81 @@
1414

1515
## Overview
1616

17-
The Asset Tracker Template is a framework for developing IoT applications on nRF91-based devices. Built on the [nRF Connect SDK](https://www.nordicsemi.com/Products/Development-software/nRF-Connect-SDK) and [Zephyr RTOS](https://docs.zephyrproject.org/latest/), it provides a modular, event-driven architecture suitable for battery-powered IoT use cases. The framework supports features such as cloud connectivity, location tracking, and sensor data collection.
17+
The Asset Tracker Template is a modular framework for developing IoT applications on nRF91-based devices. Built on [nRF Connect SDK](https://www.nordicsemi.com/Products/Development-software/nRF-Connect-SDK) and [Zephyr RTOS](https://docs.zephyrproject.org/latest/), it provides an event-driven architecture for battery-powered IoT use cases with cloud connectivity, location tracking, and sensor data collection.
1818

19-
The system is organized into modules, each responsible for a specific functionality, such as managing network connectivity, handling cloud communication, or collecting environmental data. Modules communicate through [zbus](https://docs.nordicsemi.com/bundle/ncs-latest/page/zephyr/services/zbus/index.html) channels, ensuring loose coupling and maintainability.
19+
The system uses modules that communicate through [zbus](https://docs.nordicsemi.com/bundle/ncs-latest/page/zephyr/services/zbus/index.html) channels for loose coupling and maintainability. It's suitable for asset tracking, environmental monitoring, and other IoT applications requiring modularity and power efficiency.
2020

21-
This template is suitable for applications like asset tracking, environmental monitoring, and other IoT use cases requiring modularity, configurability, and efficient power management. It includes a test setup with GitHub Actions for automated testing and continuous integration.
21+
**Supported hardware**: [Thingy:91 X](https://www.nordicsemi.com/Products/Development-hardware/Nordic-Thingy-91-X), [nRF9151 DK](https://www.nordicsemi.com/Products/Development-hardware/nRF9151-DK)
2222

23-
**Supported and verified hardware**:
24-
25-
* [Thingy:91 X](https://www.nordicsemi.com/Products/Development-hardware/Nordic-Thingy-91-X)
26-
* [nRF9151 DK](https://www.nordicsemi.com/Products/Development-hardware/nRF9151-DK)
27-
28-
If you are not familiar with the nRF91 series SiPs and cellular in general, it's recommended to go through the [Nordic Developer Academy Cellular Fundamentals Course](https://academy.nordicsemi.com/courses/cellular-iot-fundamentals) to get a better understanding of the technology and how to customize the template for your needs.
29-
30-
## System Architecture
31-
32-
The template consists of the following modules:
33-
34-
* [**Main module**](docs/modules/main.md): Central coordinator implementing business logic and control flow.
35-
* [**Network module**](docs/modules/network.md): Manages LTE connectivity and tracks network status.
36-
* [**Cloud module**](docs/modules/cloud.md): Handles communication with nRF Cloud using CoAP.
37-
* [**Location module**](docs/modules/location.md): Provides location services using GNSS, Wi-Fi and cellular positioning.
38-
* [**LED module**](docs/modules/led.md): Controls RGB LED for visual feedback on Thingy:91 X.
39-
* [**Button module**](docs/modules/button.md): Handles button input for user interaction.
40-
* [**FOTA module**](docs/modules/fota.md): Manages firmware over-the-air updates.
41-
* [**Environmental module**](docs/modules/environmental.md): Collects environmental sensor data.
42-
* [**Power module**](docs/modules/power.md): Monitors battery status and provides power management.
43-
44-
The image below illustrates the system architecture and the interaction between the modules.
45-
The zbus channels are indicated with colored arrows showing the direction of communication, with the arrows pointing in to the module that is subscribing to the respective channel.
46-
47-
![System overview](docs/images/system_overview.svg)
48-
49-
The system archtecture is described in more detail in the [Architecture](docs/common/architecture.md) document.
50-
51-
### Key Technical Features
52-
53-
1. **State Machine Framework (SMF)**
54-
* Each module implements its own state machine using Zephyr's [State Machine Framework](https://docs.nordicsemi.com/bundle/ncs-latest/page/zephyr/services/smf/index.html).
55-
* Run-to-completion model ensures predictable behavior.
56-
57-
2. **Message-Based Communication (zbus)**
58-
* Modules communicate through dedicated message channels using [zbus](https://docs.nordicsemi.com/bundle/ncs-latest/page/zephyr/services/zbus/index.html).
59-
60-
3. **Modular Architecture**
61-
* Separation of concerns between modules.
62-
* Each module that performs blocking operations runs in its own thread and use zbus message subscribers to queue messages.
63-
* Non-blocking modules use zbus listeners for immediate processing.
64-
65-
4. **Power Optimization**
66-
* LTE Power Saving Mode (PSM) enabled by default.
67-
* Configurable power-saving features.
68-
69-
### Customization and Extension
70-
71-
The framework is designed for customization, allowing developers to:
72-
73-
* Modify the central business logic in the `main.c` file.
74-
* Enable, disable and configure modules via Kconfig options.
75-
* Add new modules following the established patterns.
76-
* Modify existing modules to suit specific requirements.
77-
* Contribute to the open-source project by submitting improvements, bug fixes, or new features.
78-
79-
More information on how to customize the template can be found in the [Customization](docs/common/customization.md) document.
23+
> **Note**: If you're new to nRF91 series and cellular IoT, consider taking the [Nordic Developer Academy Cellular Fundamentals Course](https://academy.nordicsemi.com/courses/cellular-iot-fundamentals).
8024
8125
## Quick Start
8226

83-
This section provides a brief introduction to building and running the Asset Tracker Template on supported hardware. For detailed instructions, refer to the [Getting Started](docs/common/getting_started.md) document.
27+
For detailed setup instructions using the [nRF Connect for VS Code extension](https://docs.nordicsemi.com/bundle/nrf-connect-vscode/page/index.html) and advanced configuration options, see the [Getting Started Guide](docs/common/getting_started.md).
8428

8529
### Prerequisites
8630

87-
* nRF Connect SDK development environment ([Getting started guide](https://docs.nordicsemi.com/bundle/ncs-latest/page/nrf/installation.html))
31+
* nRF Connect SDK development environment ([setup guide](https://docs.nordicsemi.com/bundle/ncs-latest/page/nrf/installation.html))
8832

8933
### Build and Run
9034

91-
1. Initialize workspace:
35+
<details>
36+
<summary>1. <strong>Initialize workspace:</strong></summary>
9237

9338
```shell
9439
# Launch toolchain
95-
nrfutil sdk-manager toolchain launch --ncs-version v3.0.0 --shell # Or the version you are using
40+
nrfutil sdk-manager toolchain launch --ncs-version v3.0.0 --shell
9641

9742
# Initialize workspace
9843
west init -m https://github.com/nrfconnect/Asset-Tracker-Template.git --mr main asset-tracker-template
9944
cd asset-tracker-template/project/app
10045
west update
10146
```
47+
</details>
10248

103-
2. Build and flash:
49+
<details>
50+
<summary>2. <strong>Build and flash:</strong></summary>
10451

10552
```shell
10653
west build --pristine --board thingy91x/nrf9151/ns
10754
west thingy91x-dfu # For Thingy:91 X serial bootloader
108-
# Or if you use an external debugger (ensure that nRF9151 is selected with the switch on the Thingy:91 X)
55+
# Or with external debugger:
10956
west flash --erase
11057
```
58+
</details>
59+
60+
<details>
61+
<summary>3. <strong>Provision device:</strong></summary>
62+
63+
Use [nRF Connect for Desktop Quickstart](https://docs.nordicsemi.com/bundle/nrf-connect-desktop/page/index.html) to provision the device for nRF Cloud CoAP connectivity. See [Provisioning](docs/common/provisioning.md) for details.
64+
</details>
65+
66+
## System Architecture
67+
68+
Core modules include:
69+
70+
* **[Main](docs/modules/main.md)**: Central coordinator implementing business logic
71+
* **[Network](docs/modules/network.md)**: LTE connectivity management
72+
* **[Cloud](docs/modules/cloud.md)**: nRF Cloud CoAP communication
73+
* **[Location](docs/modules/location.md)**: GNSS, Wi-Fi, and cellular positioning
74+
* **[LED](docs/modules/led.md)**: RGB LED control for Thingy:91 X
75+
* **[Button](docs/modules/button.md)**: User input handling
76+
* **[FOTA](docs/modules/fota.md)**: Firmware over-the-air updates
77+
* **[Environmental](docs/modules/environmental.md)**: Sensor data collection
78+
* **[Power](docs/modules/power.md)**: Battery monitoring and power management
79+
80+
![System overview](docs/images/system_overview.svg)
81+
82+
### Key Features
83+
84+
* **State Machine Framework (SMF)**: Predictable behavior with run-to-completion model
85+
* **Message-Based Communication**: Loose coupling via [zbus](https://docs.nordicsemi.com/bundle/ncs-latest/page/zephyr/services/zbus/index.html) channels
86+
* **Modular Architecture**: Separation of concerns with dedicated threads for blocking operations
87+
* **Power Optimization**: LTE PSM enabled by default with configurable power-saving features
11188

112-
For detailed setup including nRF Cloud provisioning and advanced build configurations, see [Getting Started](docs/common/getting_started.md).
89+
The architecture is detailed in the [Architecture documentation](docs/common/architecture.md).
11390

114-
## Further reading
91+
## Table of Content
11592

11693
* [Getting Started](docs/common/getting_started.md)
11794
* [Architecture](docs/common/architecture.md)
@@ -138,7 +115,7 @@ For detailed setup including nRF Cloud provisioning and advanced build configura
138115
* [Modem Tracing](docs/common/tooling_troubleshooting.md#modem-tracing)
139116
* [Common Issues and Solutions](docs/common/tooling_troubleshooting.md#common-issues-and-solutions)
140117

141-
### Modules
118+
### Module Documentation
142119

143120
* [Button](docs/modules/button.md)
144121
* [Cloud](docs/modules/cloud.md)

app/Kconfig.sysbuild

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,7 @@ endchoice
2121
config PM_EXTERNAL_FLASH_MCUBOOT_SECONDARY
2222
default y if BOARD_NRF9151DK_NRF9151_NS
2323

24+
config MCUBOOT_USE_ALL_AVAILABLE_RAM
25+
default y
26+
2427
source "${ZEPHYR_BASE}/share/sysbuild/Kconfig"

app/boards/thingy91x_nrf9151_ns.conf

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,6 @@ CONFIG_NET_STATISTICS_WIFI=y
3636
# Heap allocations should be changed when CONFIG_LOCATION_METHOD_WIFI_SCANNING_RESULTS_MAX_CNT
3737
# and CONFIG_NRF_WIFI_SCAN_MAX_BSS_CNT (which should be the same value) are changed.
3838
CONFIG_NRF_WIFI_CTRL_HEAP_SIZE=10240
39-
CONFIG_HEAP_MEM_POOL_SIZE=6144
40-
CONFIG_HEAP_MEM_POOL_IGNORE_MIN=y
4139

4240
# Wi-Fi location
4341
CONFIG_LOCATION_METHOD_WIFI=y

app/prj.conf

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ CONFIG_TFM_SPM_LOG_LEVEL_DEBUG=y
2525
CONFIG_MAIN_STACK_SIZE=2560
2626
# Extended AT host/monitor stack/heap sizes since some nrf_cloud credentials are longer than 1024 bytes.
2727
CONFIG_AT_MONITOR_HEAP_SIZE=2176
28-
CONFIG_HEAP_MEM_POOL_SIZE=10000
28+
CONFIG_HEAP_MEM_POOL_SIZE=12288
2929
CONFIG_HEAP_MEM_POOL_IGNORE_MIN=y
3030
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=1280
3131

@@ -230,3 +230,17 @@ CONFIG_TASK_WDT_MIN_TIMEOUT=10000
230230
# Device power management
231231
CONFIG_PM_DEVICE=y
232232
CONFIG_PM_DEVICE_SHELL=y
233+
234+
# nRF Cloud Provisioning
235+
CONFIG_MODEM_ATTEST_TOKEN=y
236+
CONFIG_NRF_PROVISIONING=y
237+
CONFIG_NRF_PROVISIONING_LOG_LEVEL_DBG=y
238+
CONFIG_NRF_PROVISIONING_CBOR_RECORDS=5
239+
CONFIG_NRF_PROVISIONING_COAP=y
240+
CONFIG_NRF_PROVISIONING_CODEC=y
241+
CONFIG_NRF_PROVISIONING_CBOR=y
242+
CONFIG_NRF_PROVISIONING_WITH_CERT=y
243+
CONFIG_NRF_PROVISIONING_RX_BUF_SZ=4096
244+
CONFIG_NRF_PROVISIONING_TX_BUF_SZ=4096
245+
CONFIG_NRF_PROVISIONING_CODEC_AT_CMD_LEN=2048
246+
CONFIG_NRF_PROVISIONING_CODEC_RX_SZ_START=2048

app/src/cbor/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ set(zcbor_command
1313
--cddl ${CMAKE_CURRENT_SOURCE_DIR}/device_shadow.cddl
1414
--decode # Generate decoding functions
1515
--short-names # Attempt to make generated symbol names shorter (at the risk of collision)
16-
-t config-object # Create a public API for decoding the "config-object" type from the cddl file
16+
-t desired-object # Create a public API for decoding the "desired-object" type from the cddl file
1717
--output-cmake device_shadow.cmake # The generated cmake file will be placed here
1818
)
1919
execute_process(COMMAND ${zcbor_command}

app/src/cbor/cbor_helper.c

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,47 @@
44
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
55
*/
66
#include <errno.h>
7+
#include <string.h>
8+
9+
#include "cbor_helper.h"
710
#include "device_shadow_decode.h"
811

9-
int get_update_interval_from_cbor_response(const uint8_t *cbor,
10-
size_t len,
11-
uint32_t *interval_sec)
12+
#include <zephyr/logging/log.h>
13+
14+
LOG_MODULE_REGISTER(cbor_helper, CONFIG_APP_LOG_LEVEL);
15+
16+
int get_parameters_from_cbor_response(const uint8_t *cbor,
17+
size_t len,
18+
uint32_t *interval_sec,
19+
uint32_t *command_type)
1220
{
13-
struct config_object object = { 0 };
14-
size_t not_used;
21+
int err;
22+
struct desired_object desired_object = { 0 };
23+
size_t decode_len = len;
1524

16-
int err = cbor_decode_config_object(cbor, len, &object, &not_used);
25+
if (!cbor || !interval_sec || !command_type || len == 0) {
26+
return -EINVAL;
27+
}
1728

29+
err = cbor_decode_desired_object(cbor, decode_len, &desired_object, &decode_len);
1830
if (err) {
31+
LOG_ERR("cbor_decode_desired_object, error: %d", err);
32+
LOG_HEXDUMP_ERR(cbor, len, "Unexpected CBOR data");
1933
return -EFAULT;
2034
}
2135

22-
*interval_sec = object.update_interval;
36+
if (desired_object.config_present && desired_object.config.update_interval_present) {
37+
*interval_sec = desired_object.config.update_interval.update_interval;
38+
} else {
39+
LOG_DBG("Update interval parameter not present");
40+
}
41+
42+
if (desired_object.command_present) {
43+
*command_type = desired_object.command.type;
44+
/* ID entry not used */
45+
} else {
46+
LOG_DBG("Command parameter not present");
47+
}
2348

2449
return 0;
2550
}

app/src/cbor/cbor_helper.h

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,23 @@
66

77
#include <zephyr/types.h>
88

9+
#define CLOUD_COMMAND_TYPE_PROVISION 1
10+
#define CLOUD_COMMAND_TYPE_REBOOT 2
11+
912
/**
10-
* @brief Get the update interval from a CBOR buffer.
13+
* @brief Get the device shadow parameters from a CBOR buffer.
1114
*
1215
* @param[in] cbor The CBOR buffer.
1316
* @param[in] len The length of the CBOR buffer.
14-
* @param[out] interval_sec The update interval in seconds.
17+
* @param[out] interval_sec Update interval in seconds.
18+
* @param[out] command_type Cloud command type.
1519
*
1620
* @returns 0 If the operation was successful.
1721
* Otherwise, a (negative) error code is returned.
1822
* @retval -EFAULT if the CBOR buffer is invalid.
1923
*
2024
*/
21-
int get_update_interval_from_cbor_response(const uint8_t *cbor,
22-
size_t len,
23-
uint32_t *interval_sec);
25+
int get_parameters_from_cbor_response(const uint8_t *cbor,
26+
size_t len,
27+
uint32_t *interval_sec,
28+
uint32_t *command_type);

app/src/cbor/device_shadow.cddl

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,25 @@
1-
config-object = {
2-
"config": {
3-
"update_interval": uint .size 4
4-
}
1+
; Device Shadow Desired Object Definition
2+
; ---------------------------------------
3+
; This section defines the structure of the "desired" object in the device shadow.
4+
; All sections are optional, but if present, they must appear in the specified order when decoding the CBOR buffer.
5+
;
6+
; Sections:
7+
; 1. "config": Contains device configuration parameters.
8+
; - "update_interval": (optional) A 4-byte unsigned integer specifying the update interval.
9+
; - Additional configuration parameters may be included as key-value pairs (tstr => any).
10+
;
11+
; 2. "command": (optional) An array specifying a command for the device to execute.
12+
; - Structure: [type, id]
13+
; - type: 4-byte unsigned integer indicating the command type.
14+
; - id: 4-byte unsigned integer indicating the command ID.
15+
;
16+
; Any additional fields may be included as key-value pairs (tstr => any).
17+
18+
desired-object = {
19+
? "config": {
20+
? "update_interval": uint .size 4,
21+
* tstr => any
22+
},
23+
? "command": [type: uint .size 4, id: uint .size 4],
24+
* tstr => any
525
}

0 commit comments

Comments
 (0)