Feedback
Feedback

If you are having issues with the exercises, please create a ticket on DevZone: devzone.nordicsemi.com
Click or drag files to this area to upload. You can upload up to 2 files.

MQTT library

v2.9.0 – v2.8.0

We will be using the MQTT helper library in the nRF Connect SDK to connect over MQTT. This library sits on top of the Zephyr MQTT API, and simplifies connecting over MQTT and takes care of the socket handling.

More on this

If you want to learn how to use the Zephyr MQTT API directly, MQTT library in Lesson 4 of the Cellular IoT Fundamentals course covers this topic.

In this topic, we will cover how to enable and configure the library to connect to an MQTT broker.

There are a few general steps needed to use the library, which we will cover in detail in the exercise section of this lesson.

  1. Enabling the MQTT helper library
  2. Defining callback functions for various MQTT events, e.g on_mqtt_connack and on_mqtt_publish
  3. Initializing the library with the callback functions using mqtt_helper_init()
  4. Connecting to the MQTT broker with mqtt_helper_connect()
  5. Publish to topics using struct mqtt_publish_param and mqtt_helper_publish()
  6. Subscribe to topics using struct mqtt_topic, struct mqtt_subscription_list and mqtt_helper_subscribe()
  7. Adding TLS to secure the connection

Enabling the library

First step is to enable the library in the application, using the Kconfig CONFIG_MQTT_HELPER. This Kconfig also selects CONFIG_MQTT_LIB which is the Kconfig that enables the Zephyr MQTT API.

CONFIG_MQTT_HELPER=y
Kconfig

Then, we need to include the header file for the library in the main.c file, like this.

#include <net/mqtt_helper.h>
C

Define callback functions

Before initializing the library, we first need to define callback functions that will be called upon receiving various MQTT control packets from the broker.

The various callback functions are defined in struct mqtt_helper_cfg, which has the following signature

struct mqtt_helper_cfg signature

In the exercises in this lesson, we will define functions for on_connack, on_suback, on_publish and on_disconnect. These callbacks have the following signatures

static void on_mqtt_connack(enum mqtt_conn_return_code return_code, bool session_present);
static void on_mqtt_suback(uint16_t message_id, int result);
static void on_mqtt_publish(struct mqtt_helper_buf topic, struct mqtt_helper_buf payload)
static void on_mqtt_disconnect(int result)
C

Notice that CONNACK, SUBACK, and DISCONNECT all contain a result or return_code that contains the result of the operation, or reason for the operation in the case of DISCONNECT packets from the broker.

Initializing the library

To initialize the library, we will use the API call mqtt_helper_init(), which takes the parameter of type struct mqtt_helper_cfg with all the callback functions as an input.

mqtt_helper_init() signature
struct mqtt_helper_cfg signature

To initialize the library, we first define a variable struct mqtt_helper_cfg with the callback functions that we have defined. Then pass it to mqtt_helper_init().

	struct mqtt_helper_cfg config = {
		.cb = {
			.on_connack = on_mqtt_connack,
			.on_disconnect = on_mqtt_disconnect,
			.on_publish = on_mqtt_publish,
			.on_suback = on_mqtt_suback,
		},
	};

	err = mqtt_helper_init(&config);
	if (err) {
		LOG_ERR("Failed to initialize MQTT helper, error: %d", err);
		return 0;
	}
C

Connect to the MQTT broker

To connect we will use the function mqtt_connect(), which takes the struct mqtt_helper_conn_params as a parameter.

mqtt_helper_connect() signature
struct mqtt_helper_conn_params signature

First we define the struct mqtt_helper_conn_params and set the relevant members, in our case hostname and device_id. The MQTT protocol provides the option of a username and password to authenticate with the broker, however this is outside the scope of this lesson.

	struct mqtt_helper_conn_params conn_params = {
		.hostname.ptr = "mqtt.nordicsemi.academy",
		.hostname.size = strlen("mqtt.nordicsemi.academy"),
		.device_id.ptr = "nrf7002dk-1234",
		.device_id.size = strlen("nrf7002dk-1234"),
	};

	err = mqtt_helper_connect(&conn_params);
	if (err) {
		LOG_ERR("Failed to connect to MQTT, error code: %d", err);
		return 0;
	}
C

Publish and subscribe

To subscribe to topics, we define a struct mqtt_topic for each topic and set the name of the topic and the QoS. Then we define struct mqtt_subscription_list, which is an array consisting of all the topics, and pass that to mqtt_helper_subscribe() to request subscription from the broker.

struct mqtt_topic
struct mqtt_subscription_list

To publish to a topic, we define struct mqtt_publish_param, where we can set the message to publish, the topic to publish the message to and the QoS through struct mqtt_publish_message. To set the message ID, the MQTT helper library has mqtt_helper_msg_id_get() which simply returns a positive non-zero value that increments for each call.

This structure also has two flag members, dup_flag to indicate a retransmission and retain_flag, if the message should be stored persistently.

struct mqtt_publish_param
struct mqtt_publish_message

When struct mqtt_publish_param is defined, pass it to mqtt_helper_publish() to publish the message.

Enabling TLS

To enable connection over TLS, we first enable the following Kconfig

CONFIG_MQTT_LIB_TLS=y
CONFIG_TLS_CREDENTIALS=y
CONFIG_NET_SOCKETS_SOCKOPT_TLS=y
Kconfig

This will also configure the MQTT helper library to use MQTT broker port 8883, which is default for TLS connection.

In addition, we need to set a couple TLS related Kconfigs in the MQTT helper library

CONFIG_MQTT_HELPER_SEC_TAG=24
CONFIG_MQTT_HELPER_CERTIFICATES_FOLDER="src/credentials"
Kconfig

CONFIG_MQTT_HELPER_SEC_TAG sets the security tag where the TLS credentials are stored
CONFIG_MQTT_HELPER_CERTIFICATES_FOLDER sets the default path for the folder where the credentials are stored (relative to the application directory).

By default, the MQTT helper library expects the credentials to be in PEM format.

v2.7.0 – v2.6.1

The nRF Connect SDK contains an MQTT client library, that let’s you configure your device as an MQTT client and connect to an MQTT broker that you provide the information for in the application. The MQTT library is built on top of the sockets API that we covered in the previous lesson, so the library handles creating the socket used to communicate with the MQTT broker.

In this topic, we will cover how to enable and configure the library to connect to an MQTT broker.

There are a few general steps needed to use the library, which we will cover in detail in the exercise section of this lesson.

  1. Creating, initializing and configuring the structure struct mqtt_client
  2. Connecting to the MQTT broker
  3. Creating the MQTT event handler to handle the different events
  4. Publish to topics using struct mqtt_publish_param and mqtt_publish()
  5. Subscribe to topics using struct mqtt_topic, struct mqtt_subscription_list and mqtt_subscribe()
  6. Keeping the connection alive, mqtt_live()
  7. Adding TLS to secure the connection

Create an MQTT client

The first step is to initialize and configure the MQTT client, of type struct mqtt_client. This is the structure that maintains information relevant to the client, and is passed to all subsequent calls relevant to the client, like subscribing or publishing to topics.

static struct mqtt_client client_ctx
C

Before configuring the structure, we must initialize it with mqtt_client_init().

Then we can set parameters like the broker details, the callback function and client ID.

Define the callback function

Define the callback function of type mqtt_evt_cb_t, which takes the client struct mqtt_client and the event struct mqtt_evt as parameters.

struct mqtt_evt signature

mqtt_evt_type contains the full list of possible MQTT events. The two essential MQTT events which we will discuss now are MQTT_EVT_CONNACK and MQTT_EVT_PUBLISH.

MQTT_EVT_CONNACK: Acknowledgment of connection request. The event result being 0 indicates a successful connection.

This event is important because once a successful connection has been established, the client can subscribe to the applicable topics.

MQTT_EVT_PUBLISH: Message from broker, that a message has been published to a topic we subscribe to.

This event is important because we want to examine the published message in the application and depending on what message is published determine what to do next.

For all the other events, we will simply print the result of the event on the console.

Connect to the MQTT broker

To connect we will use the function mqtt_connect(), which takes the client as a parameter. This will create the appropriate socket, accessed in client_ctx.transport.tcp.sock and establish a TLS/TCP connection.

To receive incoming packets, we call mqtt_input(). Just like in Lesson 3 Exercise 1, we poll the socket for a POLLIN event to know when to call this function. Additionally, due to the keep-alive functionality of MQTT, we periodically call mqtt_live() to keep the connection alive.

Just like closing the socket, it is important to call mqtt_disconnect() to close the connection and deallocate the resources.

Publish and subscribe

To subscribe to topics, we define a struct mqtt_topic for each topic and set the name of the topic and the QoS. Then we define struct mqtt_subscription_list, essentially an array consiting of all the topics, and pass that to mqtt_subscribe() along with the client.

To publish to a topic, we define struct mqtt_publish_param and set the name of the topic to publish to, along with the QoS, message to publish and message ID. This structure also has two flag members, dup_flag to indicate a retransmission and retain_flag, if the message should be stored persistently. Then pass this to mqtt_publish() along with the client, to publish the message.

Enabling TLS

To enable TLS support for the MQTT Library, we first enable the following Kconfig

CONFIG_MQTT_LIB_TLS=y
Kconfig

Then we set the transport type of the client to be secure. This is done in the mqtt_transport transport field in struct mqtt_client, by setting transport.type to MQTT_TRANSPORT_SECURE.

Then define struct mqtt_sec_config and set the TLS configuration for the application. This includes the hostname for the MQTT broker, the security tags, and the preference for peer verification. Also note that when connecting over TLS, the socket handle is found at client_ctx.transport.tls.sock.

Lastly, before establishing the connection to the MQTT broker, we need to write the certificate for the TLS connection to the device. This will be done using the TLS credentials subsystem of the Zephyr socket API, specifically the API call tls_credential_add().

v2.6.0 – v2.5.0

The nRF Connect SDK contains an MQTT client library, that let’s you configure your device as an MQTT client and connect to an MQTT broker that you provide the information for in the application. The MQTT library is built on top of the sockets API that we covered in the previous lesson, so the library handles creating the socket used to communicate with the MQTT broker.

In this topic, we will cover how to enable and configure the library to connect to an MQTT broker.

There are a few general steps needed to use the library, which we will cover in detail in the exercise section of this lesson.

  1. Creating, initializing and configuring the structure struct mqtt_client
  2. Connecting to the MQTT broker
  3. Creating the MQTT event handler to handle the different events
  4. Publish to topics using struct mqtt_publish_param and mqtt_publish()
  5. Subscribe to topics using struct mqtt_topic, struct mqtt_subscription_list and mqtt_subscribe()
  6. Keeping the connection alive, mqtt_live()
  7. Adding TLS to secure the connection

Create an MQTT client

The first step is to initialize and configure the MQTT client, of type struct mqtt_client. This is the structure that holds the information relevant to the client, and is passed to all subsequent calls relevant to the client, like subscribing or publishing to topics.

static struct mqtt_client client_ctx
C

Before configuring the structure, we must initialize it with mqtt_client_init().

Then we can set parameters like the broker details, the callback function and client ID.

Define the callback function

Define the callback function of type mqtt_evt_cb_t, which takes the client struct mqtt_client and the event struct mqtt_evt as parameters.

struct mqtt_evt signature

mqtt_evt_type contains the full list of possible MQTT events. The two essential MQTT events which we will discuss now are MQTT_EVT_CONNACK and MQTT_EVT_PUBLISH.

MQTT_EVT_CONNACK: Acknowledgment of connection request. The event result being 0 indicates a successful connection.

This event is important because once a successful connection has been established, the client can subscribe to the applicable topics.

MQTT_EVT_PUBLISH: Message from broker, that a message has been published to a topic we subscribe to.

This event is important because we want to examine the published message in the application and depending on what message is published determine what to do next.

For all the other events, we will simply print the result of the event on the console.

Connect to the MQTT broker

To connect we will use the function mqtt_connect(), which takes the client as a parameter. This will create the appropriate socket, accessed in client_ctx.transport.tcp.sock and establish a TLS/TCP connection.

To receive incoming packets, we call mqtt_input(). Just like in Lesson 3 Exercise 1, we poll the socket for a POLLIN event to know when to call this function. Additionally, due to the keep-alive functionality of MQTT, we periodically call mqtt_live() to keep the connection alive.

Just like closing the socket, it is important to call mqtt_disconnect() to close the connection and deallocate the resources.

Publish and subscribe

To subscribe to topics, we define a struct mqtt_topic for each topic and set the name of the topic and the QoS. Then we define struct mqtt_subscription_list, essentially an array consiting of all the topics, and pass that to mqtt_subscribe() along with the client.

To publish to a topic, we define struct mqtt_publish_param and set the name of the topic to publish to, along with the QoS, message to publish, and message ID. This structure also has two flag members, dup_flag to indicate a retransmission and retain_flag, if the message should be stored persistently. Then pass this to mqtt_publish() along with the client, to publish the message.

Enabling TLS

To enable TLS support for the MQTT Library, we first enable the following Kconfig

CONFIG_MQTT_LIB_TLS=y
Kconfig

Then we set the transport type of the client to be secure. This is done in the mqtt_transport transport field in struct mqtt_client, by setting transport.type to MQTT_TRANSPORT_SECURE.

Then define struct mqtt_sec_config and set the TLS configuration for the application. This includes the hostname for the MQTT broker, the security tags, and the preference for peer verification. Also note that when connecting over TLS, the socket handle is found at client_ctx.transport.tls.sock.

Lastly, before establishing the connection to the MQTT broker, we need to write the certificate for the TLS connection to the device. This will be done using the TLS credentials subsystem of the Zephyr socket API, specifically the API call tls_credential_add().

Register an account
Already have an account? Log in
(All fields are required unless specified optional)

  • 8 or more characters
  • Upper and lower case letters
  • At least one number or special character

Forgot your password?
Enter the email associated with your account, and we will send you a link to reset your password.