MQTT-SN
Overview
MQTT-SN is a variant of the well-known MQTT protocol - see MQTT.
In contrast to MQTT, MQTT-SN does not require a TCP transport, but is designed to be used over any message-based transport. Originally, it was mainly created with ZigBee in mind, but others like Bluetooth, UDP or even a UART can be used just as well.
Zephyr provides an MQTT-SN client library built on top of BSD sockets API. The
library can be enabled with CONFIG_MQTT_SN_LIB
Kconfig option
and is configurable at a per-client basis, with support for MQTT-SN version
1.2. The Zephyr MQTT-SN implementation can be used with any message-based transport,
but support for UDP is already built-in.
MQTT-SN clients require an MQTT-SN gateway to connect to. These gateways translate between MQTT-SN and MQTT. The Eclipse Paho project offers an implementation of a MQTT-SN gateway, but others are available too. https://www.eclipse.org/paho/index.php?page=components/mqtt-sn-transparent-gateway/index.php
The MQTT-SN spec v1.2 can be found here: https://www.oasis-open.org/committees/download.php/66091/MQTT-SN_spec_v1.2.pdf
Sample usage
To create an MQTT-SN client, a client context structure and buffers need to be defined:
/* Buffers for MQTT client. */
static uint8_t rx_buffer[256];
static uint8_t tx_buffer[256];
/* MQTT-SN client context */
static struct mqtt_sn_client client;
Multiple MQTT-SN client instances can be created in the application and managed independently. Additionally, a structure for the transport is needed as well. The library already comes with an example implementation for UDP.
/* MQTT Broker address information. */
static struct mqtt_sn_transport tp;
The MQTT-SN library will inform clients about certain events using a callback.
static void evt_cb(struct mqtt_sn_client *client,
const struct mqtt_sn_evt *evt)
{
switch(evt->type) {
{
/* Handle events here. */
}
}
For a list of possible events, see API Reference.
The client context structure needs to be initialized and set up before it can be used. An example configuration for UDP transport is shown below:
struct mqtt_sn_data client_id = MQTT_SN_DATA_STRING_LITERAL("ZEPHYR");
struct sockaddr_in gateway = {0};
uint8_t tx_buf[256];
uint8_t rx_buf[256];
mqtt_sn_transport_udp_init(&tp, (struct sockaddr*)&gateway, sizeof((gateway)));
mqtt_sn_client_init(&client, &client_id, &tp.tp, evt_cb, tx_buf, sizeof(tx_buf), rx_buf, sizeof(rx_buf));
After the configuration is set up, the MQTT-SN client can connect to the gateway. While the MQTT-SN protocol offers functionality to discover gateways through an advertisement mechanism, this is not implemented yet in the library.
Call the mqtt_sn_connect
function, which will send a CONNECT
message.
The application should periodically call the mqtt_sn_input
function to process
the response received. The application does not have to call mqtt_sn_input
if it
knows that no data has been received (e.g. when using Bluetooth). Note that
mqtt_sn_input
is a non-blocking function, if the transport struct contains a
poll
compatible function pointer.
If the connection was successful, MQTT_SN_EVT_CONNECTED
will be notified to the
application through the callback function.
err = mqtt_sn_connect(&client, false, true);
__ASSERT(err == 0, "mqtt_sn_connect() failed %d", err);
while (1) {
mqtt_sn_input(&client);
if (connected) {
mqtt_sn_publish(&client, MQTT_SN_QOS_0, &topic_p, false, &pubdata);
}
k_sleep(K_MSEC(500));
}
In the above code snippet, the event handler 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.
After the connection is established, an application needs to call mqtt_input
function periodically to process incoming data. Connection upkeep, on the other hand,
is done automatically using a k_work item.
If a 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_sn_disconnect
function. This
has no effect on the transport, however. If you want to close the transport (e.g.
the socket), call mqtt_sn_client_deinit
, which will deinit the transport as well.
Zephyr provides sample code utilizing the MQTT-SN client API. See MQTT-SN publisher for more information.
Deviations from the standard
Certain parts of the protocol are not yet supported in the library.
Pre-defined topic IDs
QoS -1 - it’s most useful with predefined topics
Gateway discovery using ADVERTISE, SEARCHGW and GWINFO messages.
Setting the will topic and message after the initial connect
Forwarder Encapsulation
API Reference
- group mqtt_sn_socket
Defines
-
MQTT_SN_DATA_STRING_LITERAL(literal)
Initialize memory buffer from C literal string.
Use it as follows:
struct mqtt_sn_data topic = MQTT_SN_DATA_STRING_LITERAL(“/zephyr”);
- Parameters:
literal – [in] Literal string from which to generate mqtt_sn_data object.
-
MQTT_SN_DATA_BYTES(...)
Initialize memory buffer from single bytes.
Use it as follows:
struct mqtt_sn_data data = MQTT_SN_DATA_BYTES(0x13, 0x37);
Typedefs
-
typedef void (*mqtt_sn_evt_cb_t)(struct mqtt_sn_client *client, const struct mqtt_sn_evt *evt)
Asynchronous event notification callback registered by the application.
- Param client:
[in] Identifies the client for which the event is notified.
- Param evt:
[in] Event description along with result and associated parameters (if any).
Enums
-
enum mqtt_sn_qos
Quality of Service.
QoS 0-2 work the same as basic MQTT, QoS -1 is an MQTT-SN addition. QOS -1 is not supported yet.
Values:
-
enumerator MQTT_SN_QOS_0
QOS 0.
-
enumerator MQTT_SN_QOS_1
QOS 1.
-
enumerator MQTT_SN_QOS_2
QOS 2.
-
enumerator MQTT_SN_QOS_M1
QOS -1.
-
enumerator MQTT_SN_QOS_0
-
enum mqtt_sn_topic_type
MQTT-SN topic types.
Values:
-
enumerator MQTT_SN_TOPIC_TYPE_NORMAL
Normal topic.
It allows usage of any valid UTF-8 string as a topic name.
-
enumerator MQTT_SN_TOPIC_TYPE_PREDEF
Pre-defined topic.
It allows usage of a two-byte identifier representing a topic name for which the corresponding topic name is known in advance by both the client and the gateway/server.
-
enumerator MQTT_SN_TOPIC_TYPE_SHORT
Short topic.
It allows usage of a two-byte string as a topic name.
-
enumerator MQTT_SN_TOPIC_TYPE_NORMAL
-
enum mqtt_sn_return_code
MQTT-SN return codes.
Values:
-
enumerator MQTT_SN_CODE_ACCEPTED = 0x00
Accepted.
-
enumerator MQTT_SN_CODE_REJECTED_CONGESTION = 0x01
Rejected: congestion.
-
enumerator MQTT_SN_CODE_REJECTED_TOPIC_ID = 0x02
Rejected: Invalid Topic ID.
-
enumerator MQTT_SN_CODE_REJECTED_NOTSUP = 0x03
Rejected: Not Supported.
-
enumerator MQTT_SN_CODE_ACCEPTED = 0x00
-
enum mqtt_sn_evt_type
Event types that can be emitted by the library.
Values:
-
enumerator MQTT_SN_EVT_CONNECTED
Connected to a gateway.
-
enumerator MQTT_SN_EVT_DISCONNECTED
Disconnected.
-
enumerator MQTT_SN_EVT_ASLEEP
Entered ASLEEP state.
-
enumerator MQTT_SN_EVT_AWAKE
Entered AWAKE state.
-
enumerator MQTT_SN_EVT_PUBLISH
Received a PUBLISH message.
-
enumerator MQTT_SN_EVT_PINGRESP
Received a PINGRESP.
-
enumerator MQTT_SN_EVT_CONNECTED
Functions
-
int mqtt_sn_client_init(struct mqtt_sn_client *client, const struct mqtt_sn_data *client_id, struct mqtt_sn_transport *transport, mqtt_sn_evt_cb_t evt_cb, void *tx, size_t txsz, void *rx, size_t rxsz)
Initialize a client.
- Parameters:
client – The MQTT-SN client to initialize.
client_id – The ID to be used by the client.
transport – The transport to be used by the client.
evt_cb – The event callback function for the client.
tx – Pointer to the transmit buffer.
txsz – Size of the transmit buffer.
rx – Pointer to the receive buffer.
rxsz – Size of the receive buffer.
- Returns:
0 or a negative error code (errno.h) indicating reason of failure.
-
void mqtt_sn_client_deinit(struct mqtt_sn_client *client)
Deinitialize the client.
This removes all topics and publishes, and also de-inits the transport.
- Parameters:
client – The MQTT-SN client to deinitialize.
-
int mqtt_sn_connect(struct mqtt_sn_client *client, bool will, bool clean_session)
Connect the client.
- Parameters:
client – The MQTT-SN client to connect.
will – Flag indicating if a Will message should be sent.
clean_session – Flag indicating if a clean session should be started.
- Returns:
0 or a negative error code (errno.h) indicating reason of failure.
-
int mqtt_sn_disconnect(struct mqtt_sn_client *client)
Disconnect the client.
- Parameters:
client – The MQTT-SN client to disconnect.
- Returns:
0 or a negative error code (errno.h) indicating reason of failure.
-
int mqtt_sn_sleep(struct mqtt_sn_client *client, uint16_t duration)
Set the client into sleep state.
- Parameters:
client – The MQTT-SN client to be put to sleep.
duration – Sleep duration (in seconds).
- Returns:
0 on success, negative errno code on failure.
-
int mqtt_sn_subscribe(struct mqtt_sn_client *client, enum mqtt_sn_qos qos, struct mqtt_sn_data *topic_name)
Subscribe to a given topic.
- Parameters:
client – The MQTT-SN client that should subscribe.
qos – The desired quality of service for the subscription.
topic_name – The name of the topic to subscribe to.
- Returns:
0 or a negative error code (errno.h) indicating reason of failure.
-
int mqtt_sn_unsubscribe(struct mqtt_sn_client *client, enum mqtt_sn_qos qos, struct mqtt_sn_data *topic_name)
Unsubscribe from a topic.
- Parameters:
client – The MQTT-SN client that should unsubscribe.
qos – The quality of service used when subscribing.
topic_name – The name of the topic to unsubscribe from.
- Returns:
0 or a negative error code (errno.h) indicating reason of failure.
-
int mqtt_sn_publish(struct mqtt_sn_client *client, enum mqtt_sn_qos qos, struct mqtt_sn_data *topic_name, bool retain, struct mqtt_sn_data *data)
Publish a value.
If the topic is not yet registered with the gateway, the library takes care of it.
- Parameters:
client – The MQTT-SN client that should publish.
qos – The desired quality of service for the publish.
topic_name – The name of the topic to publish to.
retain – Flag indicating if the message should be retained by the broker.
data – The data to be published.
- Returns:
0 or a negative error code (errno.h) indicating reason of failure.
-
int mqtt_sn_input(struct mqtt_sn_client *client)
Check the transport for new incoming data.
Call this function periodically, or if you have good reason to believe there is any data. If the client’s transport struct contains a poll-function, this function is non-blocking.
- Parameters:
client – The MQTT-SN client to check for incoming data.
- Returns:
0 or a negative error code (errno.h) indicating reason of failure.
-
int mqtt_sn_get_topic_name(struct mqtt_sn_client *client, uint16_t id, struct mqtt_sn_data *topic_name)
Get topic name by topic ID.
- Parameters:
client – [in] The MQTT-SN client that uses this topic.
id – [in] Topic identifier.
topic_name – [out] Will be assigned to topic name.
- Returns:
0 on success, -ENOENT if topic ID doesn’t exist, or -EINVAL on invalid arguments.
-
struct mqtt_sn_data
- #include <mqtt_sn.h>
Abstracts memory buffers.
-
union mqtt_sn_evt_param
- #include <mqtt_sn.h>
Event metadata.
Public Members
-
struct mqtt_sn_data data
The payload data associated with the event.
-
enum mqtt_sn_topic_type topic_type
The type of topic for the event.
-
uint16_t topic_id
The identifier for the topic of the event.
-
struct mqtt_sn_evt_param publish
Structure holding publish event details.
-
struct mqtt_sn_data data
-
struct mqtt_sn_evt
- #include <mqtt_sn.h>
MQTT-SN event structure to be handled by the event callback.
Public Members
-
enum mqtt_sn_evt_type type
Event type.
-
union mqtt_sn_evt_param param
Event parameters.
-
enum mqtt_sn_evt_type type
-
struct mqtt_sn_transport
- #include <mqtt_sn.h>
Structure to describe an MQTT-SN transport.
MQTT-SN does not require transports to be reliable or to hold a connection. Transports just need to be frame-based, so you can use UDP, ZigBee, or even a simple UART, given some kind of framing protocol is used.
Public Members
-
int (*init)(struct mqtt_sn_transport *transport)
Will be called once on client init to initialize the transport.
Use this to open sockets or similar. May be NULL.
-
void (*deinit)(struct mqtt_sn_transport *transport)
Will be called on client deinit.
Use this to close sockets or similar. May be NULL.
-
int (*msg_send)(struct mqtt_sn_client *client, void *buf, size_t sz)
Will be called by the library when it wants to send a message.
-
ssize_t (*recv)(struct mqtt_sn_client *client, void *buffer, size_t length)
Will be called by the library when it wants to receive a message.
Implementations should follow recv conventions.
-
int (*poll)(struct mqtt_sn_client *client)
Check if incoming data is available.
If poll() returns a positive number, recv must not block.
May be NULL, but recv should not block then either.
- Return:
Positive number if data is available, or zero if there is none. Negative values signal errors.
-
int (*init)(struct mqtt_sn_transport *transport)
-
struct mqtt_sn_client
- #include <mqtt_sn.h>
Structure describing an MQTT-SN client.
Public Members
-
struct mqtt_sn_data client_id
1-23 character unique client ID
-
struct mqtt_sn_data will_topic
Topic for Will message.
Must be initialized before connecting with will=true
-
struct mqtt_sn_data will_msg
Will message.
Must be initialized before connecting with will=true
-
enum mqtt_sn_qos will_qos
Quality of Service for the Will message.
-
bool will_retain
Flag indicating if the will message should be retained by the broker.
-
struct mqtt_sn_transport *transport
Underlying transport to be used by the client.
-
struct net_buf_simple tx
Buffer for outgoing data.
-
struct net_buf_simple rx
Buffer for incoming data.
-
mqtt_sn_evt_cb_t evt_cb
Event callback.
-
uint16_t next_msg_id
Message ID for the next message to be sent.
-
sys_slist_t publish
List of pending publish messages.
-
sys_slist_t topic
List of registered topics.
-
int state
Current state of the MQTT-SN client.
-
int64_t last_ping
Timestamp of the last ping request.
-
uint8_t ping_retries
Number of retries for failed ping attempts.
-
struct k_work_delayable process_work
Delayable work structure for processing MQTT-SN events.
-
struct mqtt_sn_data client_id
-
MQTT_SN_DATA_STRING_LITERAL(literal)