MQTT Client

MQTT client v3.1.1 implementation, based on callback (non-netconn) connection API.

MQTT application example code
  1/*
  2 * MQTT client example with ESP device using asynchronous callbacks
  3 *
  4 * Once device is connected to network,
  5 * it will try to connect to mosquitto test server and start the MQTT.
  6 *
  7 * If successfully connected, it will publish data to "lwesp_topic" topic every x seconds.
  8 *
  9 * To check if data are sent, you can use mqtt-spy PC software to inspect
 10 * test.mosquitto.org server and subscribe to publishing topic
 11 */
 12#include "lwesp/apps/lwesp_mqtt_client.h"
 13#include "lwesp/lwesp.h"
 14#include "lwesp/lwesp_timeout.h"
 15#include "mqtt_client.h"
 16
 17static lwesp_mqtt_client_p  mqtt_client;    /*!< MQTT client structure */
 18static char mqtt_client_id[13];             /*!< Client ID is structured from ESP station MAC address */
 19
 20/**
 21 * \brief           Connection information for MQTT CONNECT packet
 22 */
 23static const lwesp_mqtt_client_info_t
 24mqtt_client_info = {
 25    .id = mqtt_client_id,                       /* The only required field for connection! */
 26
 27    .keep_alive = 10,
 28    // .user = "test_username",
 29    // .pass = "test_password",
 30};
 31
 32static void prv_mqtt_cb(lwesp_mqtt_client_p client, lwesp_mqtt_evt_t* evt);
 33static void prv_example_do_connect(lwesp_mqtt_client_p client);
 34static uint32_t retries = 0;
 35
 36/**
 37 * \brief           Custom callback function for ESP events
 38 * \param[in]       evt: ESP event callback function
 39 */
 40static lwespr_t
 41prv_mqtt_lwesp_cb(lwesp_evt_t* evt) {
 42    switch (lwesp_evt_get_type(evt)) {
 43#if LWESP_CFG_MODE_STATION
 44        case LWESP_EVT_WIFI_GOT_IP: {
 45            prv_example_do_connect(mqtt_client);/* Start connection after we have a connection to network client */
 46            break;
 47        }
 48#endif /* LWESP_CFG_MODE_STATION */
 49        default:
 50            break;
 51    }
 52    return lwespOK;
 53}
 54
 55/**
 56 * \brief           MQTT client thread
 57 * \param[in]       arg: User argument
 58 */
 59void
 60mqtt_client_thread(void const* arg) {
 61    lwesp_mac_t mac;
 62
 63    LWESP_UNUSED(arg);
 64
 65    /* Register new callback for general events from ESP stack */
 66    lwesp_evt_register(prv_mqtt_lwesp_cb);
 67
 68    /* Get station MAC to format client ID */
 69    if (lwesp_sta_getmac(&mac, NULL, NULL, 1) == lwespOK) {
 70        snprintf(mqtt_client_id, sizeof(mqtt_client_id), "%02X%02X%02X%02X%02X%02X",
 71                 (unsigned)mac.mac[0], (unsigned)mac.mac[1], (unsigned)mac.mac[2],
 72                 (unsigned)mac.mac[3], (unsigned)mac.mac[4], (unsigned)mac.mac[5]
 73                );
 74    } else {
 75        strcpy(mqtt_client_id, "unknown");
 76    }
 77    printf("MQTT Client ID: %s\r\n", mqtt_client_id);
 78
 79    /*
 80     * Create a new client with 256 bytes of RAW TX data
 81     * and 128 bytes of RAW incoming data
 82     * 
 83     * If station is already connected to access point,
 84     * try to connect immediately, otherwise it
 85     * will get connected from callback function instead 
 86     */
 87    mqtt_client = lwesp_mqtt_client_new(256, 128);  /* Create new MQTT client */
 88    if (lwesp_sta_is_joined()) {                /* If ESP is already joined to network */
 89        prv_example_do_connect(mqtt_client);    /* Start connection to MQTT server */
 90    }                                           
 91
 92    /* Make dummy delay of thread */
 93    while (1) {
 94        lwesp_delay(1000);
 95    }
 96}
 97
 98/**
 99 * \brief           Timeout callback for MQTT events
100 * \param[in]       arg: User argument
101 */
102static void
103prv_mqtt_timeout_cb(void* arg) {
104    static char tx_data[20];
105    static uint32_t num = 10;
106    lwesp_mqtt_client_p client = arg;
107    lwespr_t res;
108    
109    if (lwesp_mqtt_client_is_connected(client)) {
110        sprintf(tx_data, "R: %u, N: %u", (unsigned)retries, (unsigned)num);
111        if ((res = lwesp_mqtt_client_publish(client, "lwesp_topic", tx_data, LWESP_U16(strlen(tx_data)), LWESP_MQTT_QOS_EXACTLY_ONCE, 0, (void*)((uintptr_t)num))) == lwespOK) {
112            printf("Publishing %d...\r\n", (int)num);
113            num++;
114        } else {
115            printf("Cannot publish...: %d\r\n", (int)res);
116        }
117    }
118    lwesp_timeout_add(10000, prv_mqtt_timeout_cb, arg);
119}
120
121/**
122 * \brief           MQTT event callback function
123 * \param[in]       client: MQTT client where event occurred
124 * \param[in]       evt: Event type and data
125 */
126static void
127prv_mqtt_cb(lwesp_mqtt_client_p client, lwesp_mqtt_evt_t* evt) {
128    switch (lwesp_mqtt_client_evt_get_type(client, evt)) {
129        /*
130         * Connect event
131         * Called if user successfully connected to MQTT server
132         * or even if connection failed for some reason
133         */
134        case LWESP_MQTT_EVT_CONNECT: {            /* MQTT connect event occurred */
135            lwesp_mqtt_conn_status_t status = lwesp_mqtt_client_evt_connect_get_status(client, evt);
136
137            if (status == LWESP_MQTT_CONN_STATUS_ACCEPTED) {
138                printf("MQTT accepted!\r\n");
139                /*
140                 * Once we are accepted by server,
141                 * it is time to subscribe to different topics
142                 * We will subscrive to "mqtt_lwesp_example_topic" topic,
143                 * and will also set the same name as subscribe argument for callback later
144                 */
145                lwesp_mqtt_client_subscribe(client, "lwesp_topic", LWESP_MQTT_QOS_EXACTLY_ONCE, "lwesp_topic");
146
147                /* Start timeout timer after 5000ms and call mqtt_timeout_cb function */
148                lwesp_timeout_add(5000, prv_mqtt_timeout_cb, client);
149            } else {
150                printf("MQTT server connection was not successful: %d\r\n", (int)status);
151
152                /* Try to connect all over again */
153                prv_example_do_connect(client);
154            }
155            break;
156        }
157
158        /*
159         * Subscribe event just happened.
160         * Here it is time to check if it was successful or failed attempt
161         */
162        case LWESP_MQTT_EVT_SUBSCRIBE: {
163            const char* arg = lwesp_mqtt_client_evt_subscribe_get_argument(client, evt);  /* Get user argument */
164            lwespr_t res = lwesp_mqtt_client_evt_subscribe_get_result(client, evt); /* Get result of subscribe event */
165
166            if (res == lwespOK) {
167                printf("Successfully subscribed to %s topic\r\n", arg);
168                if (!strcmp(arg, "lwesp_topic")) {   /* Check topic name we were subscribed */
169                    /* Subscribed to "lwesp_topic" topic */
170
171                    /*
172                     * Now publish an even on example topic
173                     * and set QoS to minimal value which does not guarantee message delivery to received
174                     */
175                    lwesp_mqtt_client_publish(client, "lwesp_topic", "test_data", 9, LWESP_MQTT_QOS_AT_MOST_ONCE, 0, (void*)1);
176                }
177            }
178            break;
179        }
180
181        /* Message published event occurred */
182        case LWESP_MQTT_EVT_PUBLISH: {
183            uint32_t val = (uint32_t)(uintptr_t)lwesp_mqtt_client_evt_publish_get_argument(client, evt);/* Get user argument, which is in fact our custom number */
184
185            printf("Publish event, user argument on message was: %d\r\n", (int)val);
186            break;
187        }
188
189        /*
190         * A new message was published to us
191         * and now it is time to read the data
192         */
193        case LWESP_MQTT_EVT_PUBLISH_RECV: {
194            const char* topic = lwesp_mqtt_client_evt_publish_recv_get_topic(client, evt);
195            size_t topic_len = lwesp_mqtt_client_evt_publish_recv_get_topic_len(client, evt);
196            const uint8_t* payload = lwesp_mqtt_client_evt_publish_recv_get_payload(client, evt);
197            size_t payload_len = lwesp_mqtt_client_evt_publish_recv_get_payload_len(client, evt);
198
199            LWESP_UNUSED(payload);
200            LWESP_UNUSED(payload_len);
201            LWESP_UNUSED(topic);
202            LWESP_UNUSED(topic_len);
203            break;
204        }
205
206        /* Client is fully disconnected from MQTT server */
207        case LWESP_MQTT_EVT_DISCONNECT: {
208            printf("MQTT client disconnected!\r\n");
209            prv_example_do_connect(client);         /* Connect to server all over again */
210            break;
211        }
212
213        default:
214            break;
215    }
216}
217
218/**
219 * \brief           Make a connection to MQTT server in non-blocking mode
220 * Act only if client ready to connect and not already connected 
221 */
222static void
223prv_example_do_connect(lwesp_mqtt_client_p client) {
224    if (client == NULL
225        || lwesp_mqtt_client_is_connected(client)) {
226        return;
227    }
228    printf("Trying to connect to MQTT server\r\n");
229
230    /*
231     * Start a simple connection to open source
232     * MQTT server on mosquitto.org
233     */
234    retries++;
235    lwesp_timeout_remove(prv_mqtt_timeout_cb);
236    lwesp_mqtt_client_connect(mqtt_client, "test.mosquitto.org", 1883, prv_mqtt_cb, &mqtt_client_info);
237}
group LWESP_APP_MQTT_CLIENT

MQTT client.

Typedefs

typedef struct lwesp_mqtt_client *lwesp_mqtt_client_p

Pointer to lwesp_mqtt_client_t structure.

typedef void (*lwesp_mqtt_evt_fn)(lwesp_mqtt_client_p client, lwesp_mqtt_evt_t *evt)

MQTT event callback function.

Param client

[in] MQTT client

Param evt

[in] MQTT event with type and related data

Enums

enum lwesp_mqtt_qos_t

Quality of service enumeration.

Values:

enumerator LWESP_MQTT_QOS_AT_MOST_ONCE = 0x00

Delivery is not guaranteed to arrive, but can arrive up to 1 time = non-critical packets where losses are allowed

enumerator LWESP_MQTT_QOS_AT_LEAST_ONCE = 0x01

Delivery is quaranteed at least once, but it may be delivered multiple times with the same content

enumerator LWESP_MQTT_QOS_EXACTLY_ONCE = 0x02

Delivery is quaranteed exactly once = very critical packets such as billing informations or similar

enum lwesp_mqtt_state_t

State of MQTT client.

Values:

enumerator LWESP_MQTT_CONN_DISCONNECTED = 0x00

Connection with server is not established

enumerator LWESP_MQTT_CONN_CONNECTING

Client is connecting to server

enumerator LWESP_MQTT_CONN_DISCONNECTING

Client connection is disconnecting from server

enumerator LWESP_MQTT_CONNECTING

MQTT client is connecting… CONNECT command has been sent to server

enumerator LWESP_MQTT_CONNECTED

MQTT is fully connected and ready to send data on topics

enum lwesp_mqtt_evt_type_t

MQTT event types.

Values:

enumerator LWESP_MQTT_EVT_CONNECT

MQTT client connect event

enumerator LWESP_MQTT_EVT_SUBSCRIBE

MQTT client subscribed to specific topic

enumerator LWESP_MQTT_EVT_UNSUBSCRIBE

MQTT client unsubscribed from specific topic

enumerator LWESP_MQTT_EVT_PUBLISH

MQTT client publish message to server event.

Note

When publishing packet with quality of service LWESP_MQTT_QOS_AT_MOST_ONCE, you may not receive event, even if packet was successfully sent, thus do not rely on this event for packet with qos = LWESP_MQTT_QOS_AT_MOST_ONCE

enumerator LWESP_MQTT_EVT_PUBLISH_RECV

MQTT client received a publish message from server

enumerator LWESP_MQTT_EVT_DISCONNECT

MQTT client disconnected from MQTT server

enumerator LWESP_MQTT_EVT_KEEP_ALIVE

MQTT keep-alive event. It gets invoked after client and server exchange successful “keep-alive message”, defined by MQTT protocol

enumerator LWESP_MQTT_EVT_CONN_POLL

Local ESP connection poll event. When connection is active, stack periodically sends polling events to user. This event is propagated to user MQTT space

enum lwesp_mqtt_conn_status_t

List of possible results from MQTT server when executing connect command.

Values:

enumerator LWESP_MQTT_CONN_STATUS_ACCEPTED = 0x00

Connection accepted and ready to use

enumerator LWESP_MQTT_CONN_STATUS_REFUSED_PROTOCOL_VERSION = 0x01

Connection Refused, unacceptable protocol version

enumerator LWESP_MQTT_CONN_STATUS_REFUSED_ID = 0x02

Connection refused, identifier rejected

enumerator LWESP_MQTT_CONN_STATUS_REFUSED_SERVER = 0x03

Connection refused, server unavailable

enumerator LWESP_MQTT_CONN_STATUS_REFUSED_USER_PASS = 0x04

Connection refused, bad user name or password

enumerator LWESP_MQTT_CONN_STATUS_REFUSED_NOT_AUTHORIZED = 0x05

Connection refused, not authorized

enumerator LWESP_MQTT_CONN_STATUS_TCP_FAILED = 0x100

TCP connection to server was not successful

Functions

lwesp_mqtt_client_p lwesp_mqtt_client_new(size_t tx_buff_len, size_t rx_buff_len)

Allocate a new MQTT client structure.

Parameters
  • tx_buff_len[in] Length of raw data output buffer

  • rx_buff_len[in] Length of raw data input buffer

Returns

Pointer to new allocated MQTT client structure or NULL on failure

void lwesp_mqtt_client_delete(lwesp_mqtt_client_p client)

Delete MQTT client structure.

Note

MQTT client must be disconnected first

Parameters

client[in] MQTT client

lwespr_t lwesp_mqtt_client_connect(lwesp_mqtt_client_p client, const char *host, lwesp_port_t port, lwesp_mqtt_evt_fn evt_fn, const lwesp_mqtt_client_info_t *info)

Connect to MQTT server in non-blocking mode. Function returns immediately and does not wait for server to be connected.

Note

After TCP connection is established, CONNECT packet is automatically sent to server. Application must rely on events coming to event function, passed at connect stage

Parameters
  • client[in] MQTT client

  • host[in] Host address for server

  • port[in] Host port number

  • evt_fn[in] Callback function for all events on this MQTT client

  • info[in] Information structure for connection. It is used after connection is successfully established. Variable must not be a local or changes will be lost with potential faulty operation

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_mqtt_client_disconnect(lwesp_mqtt_client_p client)

Disconnect from MQTT server.

Parameters

client[in] MQTT client

Returns

lwespOK if request sent to queue or member of lwespr_t otherwise

uint8_t lwesp_mqtt_client_is_connected(lwesp_mqtt_client_p client)

Test if client is connected to server and accepted to MQTT protocol.

Note

Function will return error if TCP is connected but MQTT not accepted

Parameters

client[in] MQTT client

Returns

1 on success, 0 otherwise

lwespr_t lwesp_mqtt_client_subscribe(lwesp_mqtt_client_p client, const char *topic, lwesp_mqtt_qos_t qos, void *arg)

Subscribe to MQTT topic.

Parameters
  • client[in] MQTT client

  • topic[in] Topic name to subscribe to

  • qos[in] Quality of service. This parameter can be a value of lwesp_mqtt_qos_t

  • arg[in] User custom argument used in callback

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_mqtt_client_unsubscribe(lwesp_mqtt_client_p client, const char *topic, void *arg)

Unsubscribe from MQTT topic.

Parameters
  • client[in] MQTT client

  • topic[in] Topic name to unsubscribe from

  • arg[in] User custom argument used in callback

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_mqtt_client_publish(lwesp_mqtt_client_p client, const char *topic, const void *payload, uint16_t len, lwesp_mqtt_qos_t qos, uint8_t retain, void *arg)

Publish a new message on specific topic.

Parameters
  • client[in] MQTT client

  • topic[in] Topic to send message to

  • payload[in] Message data

  • payload_len[in] Length of payload data

  • qos[in] Quality of service. This parameter can be a value of lwesp_mqtt_qos_t enumeration

  • retain[in] Retian parameter value

  • arg[in] User custom argument used in callback

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

void *lwesp_mqtt_client_get_arg(lwesp_mqtt_client_p client)

Get user argument on client.

Parameters

client[in] MQTT client handle

Returns

User argument

void lwesp_mqtt_client_set_arg(lwesp_mqtt_client_p client, void *arg)

Set user argument on client.

Parameters
  • client[in] MQTT client handle

  • arg[in] User argument

struct lwesp_mqtt_client_info_t
#include <lwesp_mqtt_client.h>

MQTT client information structure.

Public Members

const char *id

Client unique identifier. It is required and must be set by user

const char *user

Authentication username. Set to NULL if not required

const char *pass

Authentication password, set to NULL if not required

uint16_t keep_alive

Keep-alive parameter in units of seconds. When set to 0, functionality is disabled (not recommended)

const char *will_topic

Will topic

const char *will_message

Will message

lwesp_mqtt_qos_t will_qos

Will topic quality of service

uint8_t use_ssl

Connect to server using SSL connection with AT commands

struct lwesp_mqtt_request_t
#include <lwesp_mqtt_client.h>

MQTT request object.

Public Members

uint8_t status

Entry status flag for in use or pending bit

uint16_t packet_id

Packet ID generated by client on publish

void *arg

User defined argument

uint32_t expected_sent_len

Number of total bytes which must be sent on connection before we can say “packet was sent”.

uint32_t timeout_start_time

Timeout start time in units of milliseconds

struct lwesp_mqtt_evt_t
#include <lwesp_mqtt_client.h>

MQTT event structure for callback function.

Public Members

lwesp_mqtt_evt_type_t type

Event type

lwesp_mqtt_conn_status_t status

Connection status with MQTT

struct lwesp_mqtt_evt_t::[anonymous]::[anonymous] connect

Event for connecting to server

uint8_t is_accepted

Status if client was accepted to MQTT prior disconnect event

struct lwesp_mqtt_evt_t::[anonymous]::[anonymous] disconnect

Event for disconnecting from server

void *arg

User argument for callback function

lwespr_t res

Response status

struct lwesp_mqtt_evt_t::[anonymous]::[anonymous] sub_unsub_scribed

Event for (un)subscribe to/from topics

struct lwesp_mqtt_evt_t::[anonymous]::[anonymous] publish

Published event

const uint8_t *topic

Pointer to topic identifier

size_t topic_len

Length of topic

const void *payload

Topic payload

size_t payload_len

Length of topic payload

uint8_t dup

Duplicate flag if message was sent again

lwesp_mqtt_qos_t qos

Received packet quality of service

struct lwesp_mqtt_evt_t::[anonymous]::[anonymous] publish_recv

Publish received event

union lwesp_mqtt_evt_t::[anonymous] evt

Event data parameters

group LWESP_APP_MQTT_CLIENT_EVT

Event helper functions.

Connect event

Note

Use these functions on LWESP_MQTT_EVT_CONNECT event

lwesp_mqtt_client_evt_connect_get_status(client, evt)

Get connection status.

Parameters
  • client[in] MQTT client

  • evt[in] Event handle

Returns

Connection status. Member of lwesp_mqtt_conn_status_t

Disconnect event

Note

Use these functions on LWESP_MQTT_EVT_DISCONNECT event

lwesp_mqtt_client_evt_disconnect_is_accepted(client, evt)

Check if MQTT client was accepted by server when disconnect event occurred.

Parameters
  • client[in] MQTT client

  • evt[in] Event handle

Returns

1 on success, 0 otherwise

Subscribe/unsubscribe event

Note

Use these functions on LWESP_MQTT_EVT_SUBSCRIBE or LWESP_MQTT_EVT_UNSUBSCRIBE events

lwesp_mqtt_client_evt_subscribe_get_argument(client, evt)

Get user argument used on lwesp_mqtt_client_subscribe.

Parameters
  • client[in] MQTT client

  • evt[in] Event handle

Returns

User argument

lwesp_mqtt_client_evt_subscribe_get_result(client, evt)

Get result of subscribe event.

Parameters
  • client[in] MQTT client

  • evt[in] Event handle

Returns

lwespOK on success, member of lwespr_t otherwise

lwesp_mqtt_client_evt_unsubscribe_get_argument(client, evt)

Get user argument used on lwesp_mqtt_client_unsubscribe.

Parameters
  • client[in] MQTT client

  • evt[in] Event handle

Returns

User argument

lwesp_mqtt_client_evt_unsubscribe_get_result(client, evt)

Get result of unsubscribe event.

Parameters
  • client[in] MQTT client

  • evt[in] Event handle

Returns

lwespOK on success, member of lwespr_t otherwise

Publish receive event

Note

Use these functions on LWESP_MQTT_EVT_PUBLISH_RECV event

lwesp_mqtt_client_evt_publish_recv_get_topic(client, evt)

Get topic from received publish packet.

Parameters
  • client[in] MQTT client

  • evt[in] Event handle

Returns

Topic name

lwesp_mqtt_client_evt_publish_recv_get_topic_len(client, evt)

Get topic length from received publish packet.

Parameters
  • client[in] MQTT client

  • evt[in] Event handle

Returns

Topic length

lwesp_mqtt_client_evt_publish_recv_get_payload(client, evt)

Get payload from received publish packet.

Parameters
  • client[in] MQTT client

  • evt[in] Event handle

Returns

Packet payload

lwesp_mqtt_client_evt_publish_recv_get_payload_len(client, evt)

Get payload length from received publish packet.

Parameters
  • client[in] MQTT client

  • evt[in] Event handle

Returns

Payload length

lwesp_mqtt_client_evt_publish_recv_is_duplicate(client, evt)

Check if packet is duplicated.

Parameters
  • client[in] MQTT client

  • evt[in] Event handle

Returns

1 if duplicated, 0 otherwise

lwesp_mqtt_client_evt_publish_recv_get_qos(client, evt)

Get received quality of service.

Parameters
  • client[in] MQTT client

  • evt[in] Event handle

Returns

Member of lwesp_mqtt_qos_t enumeration

Publish event

Note

Use these functions on LWESP_MQTT_EVT_PUBLISH event

lwesp_mqtt_client_evt_publish_get_argument(client, evt)

Get user argument used on lwesp_mqtt_client_publish.

Parameters
  • client[in] MQTT client

  • evt[in] Event handle

Returns

User argument

lwesp_mqtt_client_evt_publish_get_result(client, evt)

Get result of publish event.

Parameters
  • client[in] MQTT client

  • evt[in] Event handle

Returns

lwespOK on success, member of lwespr_t otherwise

Defines

lwesp_mqtt_client_evt_get_type(client, evt)

Get MQTT event type.

Parameters
  • client[in] MQTT client

  • evt[in] Event handle

Returns

MQTT Event type, value of lwesp_mqtt_evt_type_t enumeration