Skip to content

Commit 39d888a

Browse files
committed
add support for MQTT
This commit adds support for MQTT in the cloud module. Signed-off-by: Simen S. Røstad <simen.rostad@nordicsemi.no>
1 parent 8bdfdb9 commit 39d888a

File tree

21 files changed

+1209
-14
lines changed

21 files changed

+1209
-14
lines changed

.github/actions/build-step/action.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@ runs:
5757
-d build \
5858
-p --sysbuild \
5959
-- -DEXTRA_CONF_FILE="overlay-debug-att.conf" 2>&1 | tee ../../artifacts/build_output_${{ inputs.short_board }}_debug.log
60+
elif [[ "${{ inputs.mqtt }}" == "true" ]]; then
61+
west build -b ${{ inputs.board }} \
62+
-d build \
63+
-p --sysbuild \
64+
-- -DEXTRA_CONF_FILE="$(PWD)/../examples/modules/cloud/overlay-mqtt.conf" 2>&1 | tee ../../artifacts/build_output_${{ inputs.short_board }}_mqtt.log
6065
else
6166
west build -b ${{ inputs.board }} \
6267
-d build \

.github/workflows/build.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,16 @@ jobs:
188188
version: ${{ env.VERSION }}-patched
189189
path: asset-tracker-template/app
190190

191+
# Asset Tracker Template firmware build with MQTT cloud moduel for Thingy91x
192+
- name: Build thingy91x firmware with MQTT cloud module
193+
if: ${{ github.event_name != 'pull_request' }}
194+
uses: ./asset-tracker-template/.github/actions/build-step
195+
with:
196+
board: thingy91x/nrf9151/ns
197+
short_board: thingy91x
198+
version: ${{ env.VERSION }}-mqtt
199+
path: asset-tracker-template/app
200+
191201
- name: Upload artifacts
192202
uses: actions/upload-artifact@v4
193203
with:

.github/workflows/target-test.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,27 @@ jobs:
206206
MEMFAULT_PROJECT_SLUG: ${{ vars.MEMFAULT_PROJECT_SLUG }}
207207
APP_BUNDLEID: ${{ env.APP_BUNDLEID }}
208208

209+
- name: Test MQTT Firmware
210+
if: ${{ matrix.device == 'thingy91x' && endsWith(inputs.artifact_fw_version, '-mqtt') }}
211+
working-directory: asset-tracker-template/tests/on_target
212+
run: |
213+
pytest -v \
214+
--junit-xml=results/test-results-mqtt.xml \
215+
--html=results/test-results-mqtt.html --self-contained-html \
216+
tests/test_functional/test_mqtt.py
217+
shell: bash
218+
env:
219+
SEGGER: ${{ env.RUNNER_SERIAL_NUMBER }}
220+
DUT_DEVICE_TYPE: ${{ vars.DUT_DEVICE_TYPE }}
221+
UUID: ${{ env.UUID }}
222+
NRFCLOUD_API_KEY: ${{ secrets.NRF_CLOUD_API_KEY }}
223+
LOG_FILENAME: att_test_log_mqtt
224+
TEST_REPORT_NAME: ATT MQTT Firwmare Test Report
225+
MEMFAULT_ORGANIZATION_TOKEN: ${{ secrets.MEMFAULT_ORGANIZATION_TOKEN }}
226+
MEMFAULT_ORGANIZATION_SLUG: ${{ vars.MEMFAULT_ORGANIZATION_SLUG }}
227+
MEMFAULT_PROJECT_SLUG: ${{ vars.MEMFAULT_PROJECT_SLUG }}
228+
APP_BUNDLEID: ${{ env.APP_BUNDLEID }}
229+
209230
- name: Generate and Push Power Badge
210231
if: ${{ matrix.device }} == ppk_thingy91x
211232
continue-on-error: true

CMakeLists.txt

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,4 @@
44
# This CMake file is picked by the Zephyr build system because it is defined
55
# as the module CMake entry point (see zephyr/module.yml).
66

7-
8-
zephyr_include_directories(include)
9-
10-
add_subdirectory(drivers)
7+
add_subdirectory(examples/modules/cloud)

Kconfig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Copyright (c) 2025 Nordic Semiconductor ASA
2+
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
3+
#
4+
# This Kconfig file is picked by the Zephyr build system because it is defined
5+
# as the module Kconfig entry point (see zephyr/module.yml). You can browse
6+
# module options by going to Zephyr -> Modules in Kconfig.
7+
8+
rsource "examples/modules/cloud/Kconfig.cloud_mqtt"

app/CMakeLists.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@ target_include_directories(app PRIVATE src/common)
1515
# Add main application source
1616
target_sources(app PRIVATE src/main.c)
1717

18-
# Include mandatory module source folders
18+
# Module source folders
19+
add_subdirectory(src/modules/location)
20+
add_subdirectory(src/modules/cloud)
21+
add_subdirectory(src/modules/fota)
1922
add_subdirectory(src/modules/network)
2023
add_subdirectory(src/modules/button)
2124
add_subdirectory(src/cbor)
@@ -24,6 +27,3 @@ add_subdirectory(src/cbor)
2427
add_subdirectory_ifdef(CONFIG_APP_POWER src/modules/power)
2528
add_subdirectory_ifdef(CONFIG_APP_ENVIRONMENTAL src/modules/environmental)
2629
add_subdirectory_ifdef(CONFIG_APP_LED src/modules/led)
27-
add_subdirectory_ifdef(CONFIG_APP_LOCATION src/modules/location)
28-
add_subdirectory_ifdef(CONFIG_APP_CLOUD src/modules/cloud)
29-
add_subdirectory_ifdef(CONFIG_APP_FOTA src/modules/fota)

app/src/modules/cloud/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
55
#
66

7-
target_sources(app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/cloud.c)
7+
target_sources_ifdef(CONFIG_APP_CLOUD app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/cloud.c)
88
target_sources_ifdef(CONFIG_APP_CLOUD_SHELL app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/cloud_shell.c)
99
target_include_directories(app PRIVATE .)
1010

app/src/modules/fota/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@
44
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
55
#
66

7-
target_sources(app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/fota.c)
7+
target_sources_ifdef(CONFIG_APP_FOTA app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/fota.c)
88
target_include_directories(app PRIVATE .)

app/src/modules/location/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@
44
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
55
#
66

7-
target_sources(app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/location.c)
7+
target_sources_ifdef(CONFIG_APP_LOCATION app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/location.c)
88
target_include_directories(app PRIVATE .)

docs/common/customization.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,3 +424,66 @@ The dummy module is now ready to use. It provides the following functionality:
424424
To test the module, send a `DUMMY_SAMPLE_REQUEST` message to its zbus channel. The module will respond with a `DUMMY_SAMPLE_RESPONSE` containing the incremented counter value.
425425

426426
This dummy module serves as a template that you can extend to implement more complex functionality. You can add additional message types, state variables, and processing logic as needed for your specific use case.
427+
428+
## Using a different Cloud
429+
430+
To connect to a generic MQTT server using the Asset Tracker Template, you can use the example cloud module provided under `examples/modules/cloud`. This module replaces the default nRF Cloud CoAP-based cloud integration with a flexible MQTT client implementation.
431+
432+
### Overview
433+
434+
- **Location and FOTA**: These features are deactivated when using the example MQTT module because they depend on nRF Cloud CoAP.
435+
- **FOTA and LOCATION channels**: The MQTT cloud module provides stub channel declarations for FOTA and LOCATION to avoid build errors. You can implement your own FOTA and LOCATION modules based on your chosen cloud service if needed.
436+
- **MQTT Client default configurations:**
437+
438+
- **Broker hostname:** mqtt.nordicsemi.academy
439+
- **Port:** 8883
440+
- **TLS:** Yes
441+
- **Authentication:** Server only
442+
- **CA:** modules/examples/cloud/creds/ca-cert.pem
443+
- **Device ID** IMEI
444+
- **Subscribed topic** imei/att-pub-topic
445+
- **Publishing toptic** imei/att-sub-topic
446+
447+
The default configuration does not require/enable mutual authentication meaning that the device does not authenticate itself to the server.
448+
That would require a device certificate/private key pair. However, the server is authenticated using the server certificate `ca-cert.pem`located in the module example folder.
449+
450+
Configurations for the MQTT stack can be set in the `overlay-mqtt.conf` file and Kconfig options defined in `examples/modules/cloud/Kconfig.cloud_mqtt`.
451+
452+
### How to use the MQTT Cloud Example
453+
454+
1. **Build and flash with the MQTT overlay**
455+
456+
In the template's `app` folder, run:
457+
458+
```sh
459+
west build -p -b thingy91x/nrf9151/ns -- -DEXTRA_CONF_FILE="$(PWD)/../examples/modules/cloud/overlay-mqtt.conf" && west flash --erase --skip-rebuild
460+
```
461+
462+
2. Observe that the device connects to the broker
463+
464+
3. **Test using shell commands**
465+
466+
4. **Shell module for testing**
467+
468+
The MQTT cloud module includes a shell module/commands for testing cloud publishing much like the default CoAP configuration.
469+
To implement custom cloud shell commands this module can be used `examples/modules/cloud/cloud_mqtt_shell.c`
470+
471+
### **Module State Machine**
472+
473+
The cloud MQTT module uses a state machine to manage connection and reconnection logic. Below is a mermaid diagram representing the module's states:
474+
475+
```mermaid
476+
stateDiagram-v2
477+
[*] --> STATE_RUNNING
478+
STATE_RUNNING --> STATE_DISCONNECTED : NETWORK_DISCONNECTED
479+
STATE_DISCONNECTED --> STATE_CONNECTING : NETWORK_CONNECTED
480+
STATE_CONNECTING --> STATE_CONNECTING_ATTEMPT
481+
STATE_CONNECTING_ATTEMPT --> STATE_CONNECTING_BACKOFF : CLOUD_CONN_FAILED
482+
STATE_CONNECTING_BACKOFF --> STATE_CONNECTING_ATTEMPT : CLOUD_BACKOFF_EXPIRED
483+
STATE_CONNECTING_ATTEMPT --> STATE_CONNECTED : CLOUD_CONN_SUCCESS
484+
STATE_CONNECTED --> STATE_DISCONNECTED : NETWORK_DISCONNECTED
485+
STATE_CONNECTED --> STATE_CONNECTED : PAYLOAD_CHAN / send_data()
486+
STATE_CONNECTED --> STATE_CONNECTED : <module>_SAMPLE_RESPONSE / send_<module>_data()
487+
STATE_CONNECTED --> STATE_CONNECTED : NETWORK_CONNECTED / (noop)
488+
STATE_CONNECTED --> STATE_DISCONNECTED : exit / mqtt_helper_disconnect()
489+
```

0 commit comments

Comments
 (0)