Application description

The Asset Tracker v2 application introduces a set of new features, which are not present in the nRF9160: Asset Tracker application:

  • Ultra-low power by design - The application highlights the power saving features of the nRF9160 SiP, which is critical for successfully developing small form-factor devices and products which need very long battery lifetime.

  • Offline first - Highly-mobile cellular IoT products need to handle unreliable connections gracefully by implementing mechanisms to retry the failed sending of data.

  • Timestamping on the device - Sensor data is timestamped on the device using multiple time sources. When the device is offline (planned or unplanned), the timestamping does not rely on the cloud side.

  • Batching of data - Data can be batched to reduce the number of messages transmitted, and to be able to retain collected data while the device is offline.

  • Configurable at run time - The application behavior (for example, accelerometer sensitivity or GNSS timeout) can be configured at run time. This improves the development experience with individual devices or when debugging the device behavior in specific areas and situations. It also reduces the cost for transmitting data to the devices by reducing the frequency of sending firmware updates to the devices.

Implementation of the above features required a rework of the existing application. Hence, this application is not backward compatible to the nRF9160: Asset Tracker application.


The code is currently a work in progress and is not fully optimized yet. It will undergo changes and improvements in the future.


The application samples sensor data and publishes the data to a connected cloud service over TCP/IP through LTE. As of now, the application supports the following cloud services and the corresponding cloud-side instances:

Cloud service

Cloud-side instance

AWS IoT Core

nRF Asset Tracker for AWS

Azure IoT Hub

nRF Asset Tracker for Azure

nRF Cloud

nRF Cloud documentation

Firmware architecture

The Asset Tracker v2 application has a modular structure, where each module has a defined scope of responsibility. The application makes use of the Event Manager to distribute events between modules in the system. The event manager is used for all the communication between the modules. A module converts incoming events to messages and processes them in a FIFO manner. The processing happens either in a dedicated processing thread in the module, or directly in the event manager callback.

The following figure shows the relationship between the modules and the event manager. It also shows the modules with thread and the modules without thread.

Module hierarchy

Relationship between modules and the event manager

See Internal modules for more information.

Data types

Data from multiple sensor sources are collected to construct information about the location, environment, and the health of the nRF9160-based device. The application supports the following data types:

Data type




GNSS coordinates



Temperature, humidity






LTE link data, device data





Neighbor cells

Neighbor cell measurements


The sets of sensor data that are published to the cloud service consist of relative timestamps that originate from the time of sampling.

Device modes

The application can be either in an active or in a passive state depending on the applied device mode. The device mode is a part of the application’s real-time configurations. The device modes and their descriptions are listed in the following table:

Real-time Configurations


Default values

Device mode

Either in active or passive mode.



Sample and publish data at regular intervals.

Active wait time

Number of seconds between each sampling/publication.

120 seconds


Sample and publish data only if movement has been detected.

Movement resolution

Sample and publish data after detecting movement. Wait for a duration specified by the parameter until a movement triggers the next update.

120 seconds

Movement timeout

Sample and publish data at a minimum of the time interval specified by the parameter. Not dependent on movement.

3600 seconds

GPS timeout

Timeout for acquiring a GNSS fix during sampling of the data.

60 seconds

Accelerometer threshold

Accelerometer threshold in m/s². Minimal absolute value in m/s² for the accelerometer readings to be considered as a valid movement.

10 m/s²

No Data List (NOD)

List containing data types that is not included when the application samples data. Currently, the application supports only APP_DATA_GNSS and APP_DATA_NEIGHBOR_CELLS.

No entries (Request all)

See Kconfig options for default device configuration values for a list of configuration options that can set the default values of the device configuration parameters.


The configurations that are used depend on the application state. For instance, in active mode, the Movement resolution and the Movement timeout parameters are not used.

The following flow charts shows the functioning of the application in active and passive states. The charts also show the relationship between data sampling, publishing, and device configurations. All the configurations that are not essential to this relationship are abstracted for simplicity.

Active state flow chart

Active state flow chart

In the active state, the application samples and publishes data at regular intervals that are set by the Active wait timeout configuration.

Passive state flow chart

Passive state flow chart

In the passive state, the application will only sample and publish upon movement. This reduces the amount of data transferred over the air and the numerous processing cycles. The flow chart does not include the timer that acts on the Movement timeout configuration. This timer is enabled when the application enters the passive state. When the timer expires, the application will initiate data sampling and publishing. The timer ensures that if there is no movement, the application still sends updates to the cloud service. The timeout acts as a failsafe in the case of zero movement for the asset wearing the tracker over a long time. Ideally, the Movement timeout parameter should be set to a value much higher than the value of Movement resolution.

The device retrieves its real-time configurations from the cloud service in either of the following ways:

  • Upon every established connection to the cloud service, the application will always request its cloud-side device state that contains the latest real-time configurations.

  • When the device exits Power Saving Mode (PSM) to publish data, and if the cloud-side device configuration has been updated while the device was in PSM, the application will request for the newly changed configuration.

The application always acknowledges any newly applied device configurations back to the cloud service.


The application always stores any new configuration obtained from the cloud service to the flash memory. If the device reboots unexpectedly in areas without LTE coverage, the application will have access to the configuration that was applied last.

Data buffers

Data sampled from the onboard modem and the external sensors is stored in ring buffers. Newly sampled data is always published prior to the old, buffered data.

The application has LTE and cloud connection awareness. Upon a disconnect from the cloud service, the application keeps the sensor data that has been buffered and empty the buffers in batch messages when the application reconnects to the cloud service.


The application supports the following development kits:

Hardware platforms


Board name

Build target





nRF9160 DK




The sample is configured to compile and run as a non-secure application on nRF91’s Cortex-M33. Therefore, it automatically includes the Secure Partition Manager that prepares the required peripherals to be available for the application.

You can also configure it to use TF-M instead of Secure Partition Manager.

User interface

The application uses the following buttons on the nRF9160-based development kits:

  • Button 1 on Thingy:91

  • Button 1 and Button 2 on nRF9160 DK

Additionally, the application displays LED behavior that corresponds to the task performed by the application. The following table shows the purpose of each supported button:



nRF9160 DK


Send message to the cloud service

Send message to the cloud service.


Send message to the cloud service.

Fake movement. No external accelerometer in nRF9160 DK to trigger movement in passive mode.

The following table shows the LED behavior demonstrated by the application:


Thingy:91 RGB LED

nRF9160 DK solid LEDs

LTE connection search

Yellow, blinking

LED1 blinking

GNSS fix search

Purple, blinking

LED2 blinking

Publishing data

Green, blinking

LED3 blinking

Active mode

Light blue, blinking

LED4 blinking

Passive mode

Dark blue, slow blinking

LED4 slow blinking


Red, on

all 4 LEDs blinking

Completion of FOTA Update

White, rapid blinking

all 4 LEDs on

Using the LwM2M carrier library

This application supports the nRF Connect SDK LwM2M carrier library that can be used to connect to the operator’s device management platform. See the library’s documentation for more information and configuration options.

To enable the LwM2M carrier library, add the following parameter to your build command:


In SEGGER Embedded Studio, select Tools > Options > nRF Connect to add the above CMake parameter. See Providing CMake options for more information.

Alternatively, you can manually set the configuration options to match the contents of the overlay configuration file.


The application has a Kconfig file with options that are specific to the Asset Tracker v2, where each of the modules has a separate submenu. These options can be used to enable and disable modules and modify their behavior and properties. See Configuring your application for information about how to permanently or temporarily change the configuration.


The application is designed to support communication with different cloud services, a single service at a time. Currently, the application supports the following services and technologies in the connection:



AWS IoT Core




nRF Cloud A-GPS

nRF Cloud P-GPS

Azure IoT Hub




nRF Cloud A-GPS

nRF Cloud P-GPS

nRF Cloud




nRF Cloud A-GPS

nRF Cloud P-GPS

When the application is configured to communicate with AWS IoT Core or Azure IoT Hub, it supports processing of received A-GPS and P-GPS data through the nRF Cloud A-GPS and nRF Cloud P-GPS libraries. This enables the cloud to indirectly fetch A-GPS and P-GPS data from nRF Cloud using REST calls and relay the data to the nRF9160 SiP using the pre-established MQTT connection. This approach saves data and energy costs related to maintaining multiple connections. Requesting and processing of A-GPS data is enabled by default when building for all supported cloud providers.


For more information on the various trade-offs of using A-GPS compared to using P-GPS, see the nRF Cloud Location Services documentation.

By default, the application is configured to communicate with nRF Cloud using the factory-provisioned certificates on Thingy:91 and nRF9160 DK. This enables the application to function out-of-the-box with nRF Cloud. However, nRF Cloud does not fully support the application firmware and has limitations. For more information, see Support for nRF Cloud. To enable all features of the Asset Tracker v2, use the other supported cloud service implementations.


The Azure FOTA process is expected to change in the near future depending on the new Azure Device Update for IoT Hub that is currently in preview.

Setting up the Asset Tracker cloud example

To set up the application to work with a specific cloud example, see the following documentation:

For every cloud service that is supported by this application, you must configure the corresponding cloud library by setting certain mandatory Kconfig options that are specific to the cloud library. For more information, see Cloud-specific mandatory Kconfig options.

Configuration options

Check and configure the following configuration options for the application:

CONFIG_ASSET_TRACKER_V2_APP_VERSION - Configuration for providing the application version

The application publishes its version number as a part of the static device data. The default value for the application version is 0.0.0-development. To configure the application version, set CONFIG_ASSET_TRACKER_V2_APP_VERSION to the desired version.

CONFIG_CLOUD_CLIENT_ID_USE_CUSTOM - Configuration for enabling the use of custom cloud client ID

This application configuration is used to enable the use of custom client ID for the respective cloud. By default, the application uses the IMEI of the nRF9160-based device as the client ID in the cloud connection.

CONFIG_CLOUD_CLIENT_ID - Configuration for providing a custom cloud client ID

This application configuration sets a custom client ID for the respective cloud. For setting a custom client ID, you need to set CONFIG_CLOUD_CLIENT_ID_USE_CUSTOM to y.

The default values for the device configuration parameters can be set by manipulating the following configurations:

CONFIG_DATA_DEVICE_MODE - Configuration for the device mode

This application configuration sets the device mode.

CONFIG_DATA_ACTIVE_TIMEOUT_SECONDS - Configuration for Active mode

This application configuration sets the Active mode timeout value.

CONFIG_DATA_MOVEMENT_RESOLUTION_SECONDS - Configuration for Movement resolution

This configuration sets the Movement resolution timeout value.

CONFIG_DATA_MOVEMENT_TIMEOUT_SECONDS - Configuration for Movement timeout

This configuration sets the Movement timeout value.

CONFIG_DATA_ACCELEROMETER_THRESHOLD - Configuration for Accelerometer threshold

This configuration sets the Accelerometer threshold value.

CONFIG_DATA_GPS_TIMEOUT_SECONDS - Configuration for GNSS timeout

This configuration sets the GNSS timeout value.

Mandatory library configuration

You can set the mandatory library-specific Kconfig options in the designated overlay-<feature>.conf file located in the root folder of the application.

Configurations for AWS IoT library

These options are located in the overlay-aws.conf file.

Configurations for Azure IoT Hub library

These options are located in the overlay-azure.conf file.

Optional library configurations

You can add the following optional configurations to configure the heap or to provide additional information such as APN to the modem for registering with an LTE network:

Configuration files

The application provides predefined configuration files for typical use cases. You can find the configuration files in the applications/asset_tracker_v2/ directory.

It is possible to build the application with overlay files for both DTS and Kconfig to override the default values for the board. The application contains examples of Kconfig overlays.

The following configuration files are available in the application folder:

  • prj.conf - Configuration file common for all build targets

  • boards/thingy91_nrf9160_ns.conf - Configuration file specific for Thingy:91. This file is automatically merged with the prj.conf file when you build for the thingy91_nrf9160_ns build target.

  • boards/nrf9160dk_nrf9160_ns.conf - Configuration file specific for nRF9160 DK. This file is automatically merged with the prj.conf file when you build for the nrf9160dk_nrf9160_ns build target.

  • overlay-aws.conf - Configuration file to set AWS as cloud provider.

  • overlay-azure.conf - Configuration file to set Azure as cloud provider.

  • overlay-pgps.conf - Configuration file to enable P-GPS.

  • overlay-low-power.conf - Configuration file that achieves the lowest power consumption by disabling features that consume extra power, such as LED control and logging.

  • overlay-debug.conf - Configuration file that adds additional verbose logging capabilities and enables the debug module.

  • overlay-memfault.conf - Configuration file that enables Memfault. To take advantage of all Memfault features in the application, you must build Memfault with the debug module enabled. To enable the debug module, include both overlay-debug.conf and overlay-memfault.conf in the west build command.

  • overlay-carrier.conf - Configuration file that adds nRF Connect SDK LwM2M carrier support. See Using the LwM2M carrier library for more information.

  • boards/<BOARD>/led_state_def.h - Header file that describes the LED behavior of the CAF LEDs module.

Generally, Kconfig overlays have an overlay- prefix and a .conf extension. Board-specific configuration files are placed in the boards folder and are named as <BOARD>.conf. DTS overlay files are named the same as the build target and use the file extension .overlay. They are placed in the boards folder. When the DTS overlay filename matches the build target, the overlay is automatically chosen and applied by the build system.

Building and running

Before building and running the firmware ensure that the cloud side is set up. Also, the device must be provisioned and configured with the certificates according to the instructions for the respective cloud for the connection attempt to succeed.

The application defaults to using nRF Cloud as the cloud provider. However, you can change the cloud provider by specifying the overlay file that corresponds to another supported cloud provider when building the application. Set the CMake variable OVERLAY_CONFIG when calling the west build command. You can set this variable to contain a list of overlays that will be patched in, each enabling a specific feature. See Building with overlays on how to combine overlay configuration files to enable multiple features at the same time.


This application supports Secure bootloader chain, which is disabled by default. To enable the immutable bootloader, set CONFIG_SECURE_BOOT=y.

This sample can be found under applications/asset_tracker_v2 in the nRF Connect SDK folder structure.

The sample is built as a non-secure firmware image for the nrf9160dk_nrf9160_ns build target. Because of this, it automatically includes the Secure Partition Manager. You can also configure it to use TF-M instead of SPM.

See Building and programming an application for information about how to build and program the application.


When you build the application for the nRF9160 DK v0.15.0 and later, set the CONFIG_GPS_MODULE_ANTENNA_EXTERNAL option to y to achieve the best external antenna performance.

Building with overlays

To build with a Kconfig overlay, it must be passed to the build system, as shown in the following example:

west build -b nrf9160dk_nrf9160_ns -- -DOVERLAY_CONFIG=overlay-low-power.conf

This command builds for the nRF9160 DK using the configurations found in the overlay-low-power.conf file, in addition to the configurations found in the prj.conf file. If some options are defined in both files, the options set in the overlay take precedence.

To build with multiple overlay files, -DOVERLAY_CONFIG must be set to a list of overlay configurations, as shown in the following example:

west build -b nrf9160dk_nrf9160_ns -- -DOVERLAY_CONFIG="overlay-aws.conf;overlay-debug.conf;overlay-memfault.conf"


After programming the application and all the prerequisites to your development kit, test the application by performing the following steps:

  1. Connect the kit to the computer using a USB cable. The kit is assigned a COM port (Windows) or ttyACM device (Linux), which is visible in the Device Manager.

  2. Connect to the kit with a terminal emulator (for example, LTE Link Monitor). See How to connect with LTE Link Monitor for more information.

  3. Reset the development kit.

  4. Observe in the terminal window that the development kit starts up in the Secure Partition Manager and that the application starts. This is indicated by the following output:

    *** Booting Zephyr OS build v2.4.0-ncs1-2616-g3420cde0e37b  ***
    <inf> event_manager: APP_EVT_START
  5. Observe in the terminal window that LTE connection is established, indicated by the following output:

    <inf> event_manager: MODEM_EVT_LTE_CONNECTING
    <inf> event_manager: MODEM_EVT_LTE_CONNECTED
  6. Observe that the device establishes connection to the cloud:

    <inf> event_manager: CLOUD_EVT_CONNECTING
    <inf> event_manager: CLOUD_EVT_CONNECTED
  7. Observe that data is sampled periodically and sent to the cloud:

    <inf> event_manager: APP_EVT_DATA_GET_ALL
    <inf> event_manager: APP_EVT_DATA_GET - Requested data types (MOD_DYN, BAT, ENV, GNSS)
    <inf> event_manager: GPS_EVT_ACTIVE
    <inf> event_manager: MODEM_EVT_MODEM_DYNAMIC_DATA_READY
    <inf> event_manager: MODEM_EVT_BATTERY_DATA_READY
    <inf> event_manager: GPS_EVT_DATA_READY
    <inf> event_manager: DATA_EVT_DATA_READY
    <inf> event_manager: GPS_EVT_INACTIVE
    <inf> event_manager: DATA_EVT_DATA_SEND
    <wrn> data_module: No batch data to encode, ringbuffers empty
    <inf> event_manager: CLOUD_EVT_DATA_ACK

Support for nRF Cloud

Enabling full support for nRF Cloud is currently a work in progress. Following are the current limitations in the nRF Cloud implementation of the Asset Tracker v2:

  • Data that is sampled by the device must ideally be addressed to the cloud-side device state and published in a single packet for regular device updates. This is to avoid the unnecessary stack overhead associated with splitting the payload and the additional current consumption that might result from splitting and sending the data as separate packets. However, in the case of nRF Cloud implementation, the nRF Cloud front end supports only the display of APP_DATA_MODEM_DYNAMIC (networkInfo) and APP_DATA_MODEM_STATIC (deviceInfo) through the device shadow. The other supported data types (GPS, temperature, and humidity) must be sent in a specified format to a separate message endpoint for the front end to graphically represent the data. You can find the JSON protocol definitions for data sent to the message endpoint in nRF Cloud JSON protocol schemas.

  • The nRF Cloud web application does not support the manipulation of real-time configurations. However, this is possible by using the REST API calls described in nRF Cloud Patch Device State. To manipulate the device configuration, the desired section of the device state must be populated with the desired configuration of the device. The following schema sets the various device configuration parameters to their default values:


Internal modules

The application has two types of modules:

  • Module with dedicated thread

  • Module without thread

Every module has an event manager handler function, which subscribes to one or more event types. When an event is sent from a module, all subscribers receive that event in the respective handler, and acts on the event in the following ways:

  1. The event is converted into a message

  2. The event is either processed directly or queued.

Modules may also receive events from other sources such as drivers and libraries. For instance, the cloud module will also receive events from the configured cloud backend. The event handler converts the events to messages. The messages are then queued in the case of the cloud module or processed directly in the case of modules that do not have a processing thread.

Event handling in modules

Event handling in modules

For more information about each module and its configuration, see the Subpages.

Thread usage

In addition to system threads, some modules have dedicated threads to process messages. Some modules receive messages that may potentially take an extended amount of time to process. Such messages are not suitable to be processed directly in the event handler callbacks that run on the system queue. Therefore, these modules have a dedicated thread to process the messages.

Application-specific threads:

  • Main thread (app module)

  • Data management module

  • Cloud module

  • Sensor module

  • Modem module

Modules that do not have dedicated threads process events in the context of system work queue in the event manager callback. Therefore, their workloads must be light and non-blocking.

All module threads have the following identical properties by default:

  • Thread is initialized at boot.

  • Thread is preemptive.

  • Priority is set to the lowest application priority in the system, which is done by setting CONFIG_NUM_PREEMPT_PRIORITIES to 1.

  • Thread is started instantly after it is initialized in the boot sequence.

Following is the basic structure for all the threads:

static void module_thread_fn(void)
        struct module_specific msg;

        self.thread_id = k_current_get();

        /* Module specific setup */


        while (true) {
                module_get_next_msg(&self, &msg);

                switch (state) {
                case STATE_DISCONNECTED:
                case STATE_CONNECTED:
                        LOG_WRN("Unknown state");


Memory allocation

Mostly, the modules use statically allocated memory. Following are some features that rely on dynamically allocated memory, using the Zephyr heap memory pool implementation:

  • Event manager events

  • Encoding of the data that will be sent to cloud

You can configure the heap memory by using the CONFIG_HEAP_MEM_POOL_SIZE. The data management module that encodes data destined for cloud is the biggest consumer of heap memory. Therefore, when adjusting buffer sizes in the data management module, you must also adjust the heap accordingly. This avoids the problem of running out of heap memory in worst-case scenarios.