2019-02-01 23:11:18 +08:00
|
|
|
.. _mqtt_socket_interface:
|
|
|
|
|
|
|
|
MQTT
|
2019-02-05 22:09:54 +08:00
|
|
|
####
|
2019-02-01 23:11:18 +08:00
|
|
|
|
2019-02-27 21:29:53 +08:00
|
|
|
.. contents::
|
|
|
|
:local:
|
|
|
|
:depth: 2
|
|
|
|
|
2019-02-01 23:11:18 +08:00
|
|
|
Overview
|
|
|
|
********
|
|
|
|
|
2019-02-05 22:09:54 +08:00
|
|
|
MQTT (Message Queuing Telemetry Transport) is an application layer protocol
|
|
|
|
which works on top of the TCP/IP stack. It is a lightweight
|
|
|
|
publish/subscribe messaging transport for machine-to-machine communication.
|
|
|
|
For more information about the protocol itself, see http://mqtt.org/.
|
|
|
|
|
|
|
|
Zephyr provides an MQTT client library built on top of BSD sockets API. The
|
|
|
|
library is configurable at a per-client basis, with support for MQTT versions
|
|
|
|
3.1.0 and 3.1.1. The Zephyr MQTT implementation can be used with either plain
|
|
|
|
sockets communicating over TCP, or with secure sockets communicating over
|
|
|
|
TLS. See :ref:`bsd_sockets_interface` for more information about Zephyr sockets.
|
|
|
|
|
|
|
|
MQTT clients require an MQTT server to connect to. Such a server, called an MQTT Broker,
|
|
|
|
is responsible for managing client subscriptions and distributing messages
|
|
|
|
published by clients. There are many implementations of MQTT brokers, one of them
|
|
|
|
being Eclipse Mosquitto. See https://mosquitto.org/ for more information about
|
|
|
|
the Eclipse Mosquitto project.
|
|
|
|
|
|
|
|
Sample usage
|
|
|
|
************
|
|
|
|
|
|
|
|
To create an MQTT client, a client context structure and buffers need to be
|
|
|
|
defined:
|
|
|
|
|
|
|
|
.. code-block:: c
|
|
|
|
|
|
|
|
/* Buffers for MQTT client. */
|
|
|
|
static u8_t rx_buffer[256];
|
|
|
|
static u8_t tx_buffer[256];
|
|
|
|
|
|
|
|
/* MQTT client context */
|
|
|
|
static struct mqtt_client client_ctx;
|
|
|
|
|
|
|
|
Multiple MQTT client instances can be created in the application and managed
|
|
|
|
independently. Additionally, a structure for MQTT Broker address information
|
|
|
|
is needed. This structure must be accessible throughout the lifespan
|
|
|
|
of the MQTT client and can be shared among MQTT clients:
|
|
|
|
|
|
|
|
.. code-block:: c
|
|
|
|
|
|
|
|
/* MQTT Broker address information. */
|
|
|
|
static struct sockaddr_storage broker;
|
|
|
|
|
|
|
|
An MQTT client library will notify MQTT events to the application through a
|
|
|
|
callback function created to handle respective events:
|
|
|
|
|
|
|
|
.. code-block:: c
|
|
|
|
|
|
|
|
void mqtt_evt_handler(struct mqtt_client *client,
|
|
|
|
const struct mqtt_evt *evt)
|
|
|
|
{
|
|
|
|
switch (evt->type) {
|
|
|
|
/* Handle events here. */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
For a list of possible events, see :ref:`mqtt_api_reference`.
|
|
|
|
|
|
|
|
The client context structure needs to be initialized and set up before it can be
|
|
|
|
used. An example configuration for TCP transport is shown below:
|
|
|
|
|
|
|
|
.. code-block:: c
|
|
|
|
|
|
|
|
mqtt_client_init(&client_ctx);
|
|
|
|
|
|
|
|
/* MQTT client configuration */
|
|
|
|
client_ctx.broker = &broker;
|
|
|
|
client_ctx.evt_cb = mqtt_evt_handler;
|
|
|
|
client_ctx.client_id.utf8 = (u8_t *)"zephyr_mqtt_client";
|
|
|
|
client_ctx.client_id.size = sizeof("zephyr_mqtt_client") - 1;
|
|
|
|
client_ctx.password = NULL;
|
|
|
|
client_ctx.user_name = NULL;
|
|
|
|
client_ctx.protocol_version = MQTT_VERSION_3_1_1;
|
|
|
|
client_ctx.transport.type = MQTT_TRANSPORT_NON_SECURE;
|
|
|
|
|
|
|
|
/* MQTT buffers configuration */
|
|
|
|
client_ctx.rx_buf = rx_buffer;
|
|
|
|
client_ctx.rx_buf_size = sizeof(rx_buffer);
|
|
|
|
client_ctx.tx_buf = tx_buffer;
|
|
|
|
client_ctx.tx_buf_size = sizeof(tx_buffer);
|
|
|
|
|
|
|
|
After the configuration is set up, the MQTT client can connect to the MQTT broker.
|
|
|
|
Call the ``mqtt_connect`` function, which will create the appropriate socket,
|
2019-03-13 06:39:09 +08:00
|
|
|
establish a TCP/TLS connection, and send an ``MQTT CONNECT`` message.
|
2019-02-05 22:09:54 +08:00
|
|
|
When notified, the application should call the ``mqtt_input`` function to process
|
|
|
|
the response received. Note, that ``mqtt_input`` is a non-blocking function,
|
|
|
|
therefore the application should use socket ``poll`` to wait for the response.
|
|
|
|
If the connection was successful, ``MQTT_EVT_CONNACK`` will be notified to the
|
|
|
|
application through the callback function.
|
|
|
|
|
|
|
|
.. code-block:: c
|
|
|
|
|
|
|
|
rc = mqtt_connect(&client_ctx);
|
|
|
|
if (rc != 0) {
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
fds[0].fd = client_ctx.transport.tcp.sock;
|
|
|
|
fds[0].events = ZSOCK_POLLIN;
|
|
|
|
poll(fds, 1, K_MSEC(5000));
|
|
|
|
|
|
|
|
mqtt_input(&client_ctx);
|
|
|
|
|
|
|
|
if (!connected) {
|
|
|
|
mqtt_abort(&client_ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
In the above code snippet, the MQTT callback function should set the ``connected``
|
|
|
|
flag upon a successful connection. If the connection fails at the MQTT level
|
|
|
|
or a timeout occurs, the connection will be aborted, and the underlying socket
|
|
|
|
closed.
|
|
|
|
|
|
|
|
After the connection is established, an application needs to call ``mqtt_input``
|
|
|
|
and ``mqtt_live`` functions periodically to process incoming data and upkeep
|
|
|
|
the connection. If an MQTT message is received, an MQTT callback function will
|
|
|
|
be called and an appropriate event notified.
|
|
|
|
|
|
|
|
The connection can be closed by calling the ``mqtt_disconnect`` function.
|
|
|
|
|
|
|
|
Zephyr provides sample code utilizing the MQTT client API. See
|
|
|
|
:ref:`mqtt-publisher-sample` for more information.
|
|
|
|
|
|
|
|
Using MQTT with TLS
|
|
|
|
*******************
|
|
|
|
|
|
|
|
The Zephyr MQTT library can be used with TLS transport for secure communication
|
|
|
|
by selecting a secure transport type (``MQTT_TRANSPORT_SECURE``) and some
|
|
|
|
additional configuration information:
|
|
|
|
|
|
|
|
.. code-block:: c
|
|
|
|
|
|
|
|
client_ctx.transport.type = MQTT_TRANSPORT_SECURE;
|
|
|
|
|
|
|
|
struct mqtt_sec_config *tls_config = &client_ctx.transport.tls.config;
|
|
|
|
|
|
|
|
tls_config->peer_verify = 2;
|
|
|
|
tls_config->cipher_list = NULL;
|
|
|
|
tls_config->sec_tag_list = m_sec_tags;
|
|
|
|
tls_config->sec_tag_count = ARRAY_SIZE(m_sec_tags);
|
|
|
|
tls_config->hostname = MQTT_BROKER_HOSTNAME;
|
|
|
|
|
|
|
|
In this sample code, the ``m_sec_tags`` array holds a list of tags, referencing TLS
|
|
|
|
credentials that the MQTT library should use for authentication. We do not specify
|
|
|
|
``cipher_list``, to allow the use of all cipher suites available in the system.
|
|
|
|
We set ``hostname`` field to broker hostname, which is required for server
|
|
|
|
authentication. Finally, we enforce peer certificate verification by setting
|
|
|
|
the ``peer_verify`` field.
|
|
|
|
|
|
|
|
Note, that TLS credentials referenced by the ``m_sec_tags`` array must be
|
|
|
|
registered in the system first. For more information on how to do that, refer
|
|
|
|
to :ref:`secure sockets documentation <secure_sockets_interface>`.
|
|
|
|
|
|
|
|
An example of how to use TLS with MQTT is also present in
|
|
|
|
:ref:`mqtt-publisher-sample`.
|
|
|
|
|
|
|
|
.. _mqtt_api_reference:
|
2019-02-01 23:11:18 +08:00
|
|
|
|
|
|
|
API Reference
|
|
|
|
*************
|
|
|
|
|
|
|
|
.. doxygengroup:: mqtt_socket
|
|
|
|
:project: Zephyr
|