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.

Note

After TCP connection is established, CONNECT packet is automatically sent to server

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