Skip to content

Commit 0083b7a

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 0b9ab69 commit 0083b7a

File tree

16 files changed

+1118
-11
lines changed

16 files changed

+1118
-11
lines changed

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+
```
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#
2+
# Copyright (c) 2025 Nordic Semiconductor ASA
3+
#
4+
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
#
6+
7+
# Prevent this example module from being included in images that doesn't enable the MQTT cloud module
8+
if (NOT CONFIG_APP_CLOUD_MQTT)
9+
return()
10+
endif()
11+
12+
add_subdirectory(creds)
13+
14+
zephyr_sources(${CMAKE_CURRENT_SOURCE_DIR}/cloud_mqtt.c)
15+
zephyr_sources(${CMAKE_CURRENT_SOURCE_DIR}/cloud_mqtt_shell.c)
16+
17+
if (CONFIG_NRF_CLOUD_COAP_SEC_TAG GREATER_EQUAL 2147483648 AND CONFIG_NRF_CLOUD_COAP_SEC_TAG LESS_EQUAL 2147483667)
18+
message(WARNING "CONFIG_NRF_CLOUD_COAP_SEC_TAG is set to a developer security tag. "
19+
"TLS traffic can now be decrypted with Nordic tools. "
20+
"This should only be used during development and testing.")
21+
endif()
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
#
2+
# Copyright (c) 2025 Nordic Semiconductor
3+
#
4+
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
#
6+
7+
menuconfig APP_CLOUD_MQTT
8+
bool "Cloud module"
9+
depends on MQTT_HELPER
10+
depends on HW_ID_LIBRARY
11+
12+
if APP_CLOUD_MQTT
13+
14+
config APP_CLOUD_MQTT_HOSTNAME
15+
string "MQTT broker hostname"
16+
default "mqtt.nordicsemi.academy"
17+
help
18+
Hostname of the MQTT broker to connect to.
19+
20+
config APP_CLOD_MQTT_TOPIC_SIZE_MAX
21+
int "MQTT topic size"
22+
default 64
23+
help
24+
Maximum size of the MQTT topics used for publishing and subscribing to messages.
25+
26+
config APP_CLOUD_MQTT_PUB_TOPIC
27+
string "MQTT publish topic"
28+
default "att-pub-topic"
29+
help
30+
Topic used for publishing messages to the MQTT broker.
31+
32+
config APP_CLOUD_MQTT_SUB_TOPIC
33+
string "MQTT subscribe topic"
34+
default "att-sub-topic"
35+
help
36+
Topic used for subscribing to messages from the MQTT broker.
37+
38+
config APP_CLOUD_MQTT_SEC_TAG
39+
int "MQTT security tag"
40+
default 888
41+
help
42+
Security tag used to store the MQTT credentials in the modem using Modem Key Management API
43+
44+
config APP_CLOUD_MQTT_SHELL
45+
bool "Enable cloud shell"
46+
default y if SHELL
47+
help
48+
Enable cloud shell commands.
49+
50+
config APP_CLOUD_PAYLOAD_BUFFER_MAX_SIZE
51+
int "Payload maximum buffer size"
52+
default 128
53+
help
54+
Maximum size of the buffer sent over the payload channel when sending RAW JSON messages
55+
to the cloud.
56+
57+
config APP_CLOUD_SHADOW_RESPONSE_BUFFER_MAX_SIZE
58+
int "Payload maximum buffer size"
59+
default 512
60+
help
61+
Maximum size of the buffer used to receive shadow responses from the cloud.
62+
63+
config APP_CLOUD_BACKOFF_INITIAL_SECONDS
64+
int "Reconnection backoff time in seconds"
65+
default 60
66+
help
67+
Time in between reconnection attempts to the MQTT server.
68+
The timer starts after the last failed attempt.
69+
70+
choice APP_CLOUD_BACKOFF_TYPE
71+
prompt "Reconnection backoff type"
72+
default APP_CLOUD_BACKOFF_TYPE_LINEAR
73+
74+
config APP_CLOUD_BACKOFF_TYPE_EXPONENTIAL
75+
bool "Exponential backoff"
76+
help
77+
Exponential backoff doubles the reconnection timeout after each failed attempt.
78+
The maximum reconnection timeout is defined by APP_CLOUD_BACKOFF_MAX_SECONDS.
79+
80+
config APP_CLOUD_BACKOFF_TYPE_LINEAR
81+
bool "Linear backoff"
82+
help
83+
Linear backoff adds a fixed amount of time to the reconnection timeout after each failed attempt,
84+
as defined by APP_CLOUD_BACKOFF_LINEAR_INCREMENT_SECONDS.
85+
86+
config APP_CLOUD_BACKOFF_TYPE_NONE
87+
bool "No backoff"
88+
help
89+
No backoff means that the reconnection timeout is constant at the value defined by
90+
APP_CLOUD_BACKOFF_INITIAL_SECONDS.
91+
92+
endchoice
93+
94+
config APP_CLOUD_BACKOFF_LINEAR_INCREMENT_SECONDS
95+
int "Reconnection backoff time increment"
96+
default 60
97+
help
98+
Time added to the reconnection timeout after each failed attempt in seconds.
99+
The maximum reconnection timeout is defined by APP_CLOUD_BACKOFF_MAX_SECONDS.
100+
101+
config APP_CLOUD_BACKOFF_MAX_SECONDS
102+
int "Maximum reconnection timeout"
103+
default 3600
104+
help
105+
Maximum reconnection backoff value in seconds.
106+
107+
config APP_CLOUD_THREAD_STACK_SIZE
108+
int "Thread stack size"
109+
default 3328
110+
111+
config APP_CLOUD_MESSAGE_QUEUE_SIZE
112+
int "Message queue size"
113+
default 5
114+
help
115+
ZBus subscriber message queue size.
116+
117+
config APP_CLOUD_WATCHDOG_TIMEOUT_SECONDS
118+
int "Watchdog timeout"
119+
default 180
120+
help
121+
Timeout in seconds for the cloud module watchdog.
122+
The timeout given in this option covers both:
123+
* Waiting for an incoming message in zbus_sub_wait_msg().
124+
* Time spent processing the message, defined by
125+
CONFIG_APP_CLOUD_MSG_PROCESSING_TIMEOUT_SECONDS.
126+
Ensure that this value exceeds CONFIG_APP_CLOUD_MSG_PROCESSING_TIMEOUT_SECONDS.
127+
A small difference between the two can mean more frequent watchdog feeds, which increases
128+
power consumption.
129+
130+
131+
config APP_CLOUD_MSG_PROCESSING_TIMEOUT_SECONDS
132+
int "Maximum message processing time"
133+
default 120
134+
help
135+
Maximum time allowed for processing a single message in the module's state machine.
136+
The value must be smaller than CONFIG_APP_CLOUD_WATCHDOG_TIMEOUT_SECONDS.
137+
138+
module = APP_CLOUD_MQTT
139+
module-str = Cloud MQTT
140+
source "subsys/logging/Kconfig.template.log_config"
141+
142+
endif # APP_CLOUD_MQTT

0 commit comments

Comments
 (0)