MQTT Client

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

MQTT application example code
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
/*
 * MQTT client example with ESP device.
 *
 * Once device is connected to network,
 * it will try to connect to mosquitto test server and start the MQTT.
 *
 * If successfully connected, it will publish data to "esp8266_mqtt_topic" topic every x seconds.
 *
 * To check if data are sent, you can use mqtt-spy PC software to inspect
 * test.mosquitto.org server and subscribe to publishing topic
 */

#include "esp/apps/esp_mqtt_client.h"
#include "esp/esp.h"
#include "esp/esp_timeout.h"
#include "mqtt_client.h"

/**
 * \brief           MQTT client structure
 */
static esp_mqtt_client_p
mqtt_client;

/**
 * \brief           Client ID is structured from ESP station MAC address
 */
static char
mqtt_client_id[13];

/**
 * \brief           Connection information for MQTT CONNECT packet
 */
static const esp_mqtt_client_info_t
mqtt_client_info = {
    .id = mqtt_client_id,                       /* The only required field for connection! */
    
    .keep_alive = 10,
    // .user = "test_username",
    // .pass = "test_password",
};

static void mqtt_cb(esp_mqtt_client_p client, esp_mqtt_evt_t* evt);
static void example_do_connect(esp_mqtt_client_p client);
static uint32_t retries = 0;

/**
 * \brief           Custom callback function for ESP events
 */
static espr_t
mqtt_esp_cb(esp_evt_t* evt) {
    switch (esp_evt_get_type(evt)) {
#if ESP_CFG_MODE_STATION
        case ESP_EVT_WIFI_GOT_IP: {
            example_do_connect(mqtt_client);    /* Start connection after we have a connection to network client */
            break;
        }
#endif /* ESP_CFG_MODE_STATION */
        default: break;
    }
    return espOK;
}

/**
 * \brief           MQTT client thread
 * \param[in]       arg: User argument
 */
void
mqtt_client_thread(void const* arg) {
    esp_mac_t mac;

    esp_evt_register(mqtt_esp_cb);              /* Register new callback for general events from ESP stack */
    
    /* Get station MAC to format client ID */
    if (esp_sta_getmac(&mac, NULL, NULL, 1) == espOK) {
        snprintf(mqtt_client_id, sizeof(mqtt_client_id), "%02X%02X%02X%02X%02X%02X",
            (unsigned)mac.mac[0], (unsigned)mac.mac[1], (unsigned)mac.mac[2],
            (unsigned)mac.mac[3], (unsigned)mac.mac[4], (unsigned)mac.mac[5]
        );
    } else {
        strcpy(mqtt_client_id, "unknown");
    }
    printf("MQTT Client ID: %s\r\n", mqtt_client_id);

    /*
     * Create a new client with 256 bytes of RAW TX data
     * and 128 bytes of RAW incoming data
     */
    mqtt_client = esp_mqtt_client_new(256, 128);/* Create new MQTT client */
    if (esp_sta_is_joined()) {                  /* If ESP is already joined to network */
        example_do_connect(mqtt_client);        /* Start connection to MQTT server */
    }
    
    /* Make dummy delay of thread */
    while (1) {
        esp_delay(1000);
    }
}

/**
 * \brief           Timeout callback for MQTT events
 * \param[in]       arg: User argument
 */
void
mqtt_timeout_cb(void* arg) {
    static uint32_t num = 10;
    esp_mqtt_client_p client = arg;
    espr_t res;

    static char tx_data[20];
    
    if (esp_mqtt_client_is_connected(client)) {
        sprintf(tx_data, "R: %u, N: %u", (unsigned)retries, (unsigned)num);
        if ((res = esp_mqtt_client_publish(client, "esp8266_mqtt_topic", tx_data, ESP_U16(strlen(tx_data)), ESP_MQTT_QOS_EXACTLY_ONCE, 0, (void *)num)) == espOK) {
            printf("Publishing %d...\r\n", (int)num);
            num++;
        } else {
            printf("Cannot publish...: %d\r\n", (int)res);
        }
    }
    esp_timeout_add(10000, mqtt_timeout_cb, client);
}

/**
 * \brief           MQTT event callback function
 * \param[in]       client: MQTT client where event occurred
 * \param[in]       evt: Event type and data
 */
static void
mqtt_cb(esp_mqtt_client_p client, esp_mqtt_evt_t* evt) {
    switch (esp_mqtt_client_evt_get_type(client, evt)) {
        /*
         * Connect event
         * Called if user successfully connected to MQTT server
         * or even if connection failed for some reason
         */
        case ESP_MQTT_EVT_CONNECT: {            /* MQTT connect event occurred */
            esp_mqtt_conn_status_t status = esp_mqtt_client_evt_connect_get_status(client, evt);
            
            if (status == ESP_MQTT_CONN_STATUS_ACCEPTED) {
                printf("MQTT accepted!\r\n");
                /*
                 * Once we are accepted by server, 
                 * it is time to subscribe to different topics
                 * We will subscrive to "mqtt_esp_example_topic" topic,
                 * and will also set the same name as subscribe argument for callback later
                 */
                esp_mqtt_client_subscribe(client, "esp8266_mqtt_topic", ESP_MQTT_QOS_EXACTLY_ONCE, "esp8266_mqtt_topic");
                
                /* Start timeout timer after 5000ms and call mqtt_timeout_cb function */
                esp_timeout_add(5000, mqtt_timeout_cb, client);
            } else {
                printf("MQTT server connection was not successful: %d\r\n", (int)status);
                
                /* Try to connect all over again */
                example_do_connect(client);
            }
            break;
        }
        
        /*
         * Subscribe event just happened.
         * Here it is time to check if it was successful or failed attempt
         */
        case ESP_MQTT_EVT_SUBSCRIBE: {
            const char* arg = esp_mqtt_client_evt_subscribe_get_argument(client, evt);  /* Get user argument */
            espr_t res = esp_mqtt_client_evt_subscribe_get_result(client, evt); /* Get result of subscribe event */
            
            if (res == espOK) {
                printf("Successfully subscribed to %s topic\r\n", arg);
                if (!strcmp(arg, "esp8266_mqtt_topic")) {   /* Check topic name we were subscribed */
                    /* Subscribed to "esp8266_mqtt_topic" topic */
                    
                    /*
                     * Now publish an even on example topic
                     * and set QoS to minimal value which does not guarantee message delivery to received
                     */
                    esp_mqtt_client_publish(client, "esp8266_mqtt_topic", "test_data", 9, ESP_MQTT_QOS_AT_MOST_ONCE, 0, (void *)1);
                }
            }
            break;
        }
        
        /* Message published event occurred */
        case ESP_MQTT_EVT_PUBLISH: {
            uint32_t val = (uint32_t)esp_mqtt_client_evt_publish_get_argument(client, evt); /* Get user argument, which is in fact our custom number */
            
            printf("Publish event, user argument on message was: %d\r\n", (int)val);
            break;
        }
        
        /*
         * A new message was published to us
         * and now it is time to read the data
         */
        case ESP_MQTT_EVT_PUBLISH_RECV: {
            const char* topic = esp_mqtt_client_evt_publish_recv_get_topic(client, evt);
            size_t topic_len = esp_mqtt_client_evt_publish_recv_get_topic_len(client, evt);
            const uint8_t* payload = esp_mqtt_client_evt_publish_recv_get_payload(client, evt);
            size_t payload_len = esp_mqtt_client_evt_publish_recv_get_payload_len(client, evt);
            
            ESP_UNUSED(payload);
            ESP_UNUSED(payload_len);
            ESP_UNUSED(topic);
            ESP_UNUSED(topic_len);
            break;
        }
        
        /* Client is fully disconnected from MQTT server */
        case ESP_MQTT_EVT_DISCONNECT: {
            printf("MQTT client disconnected!\r\n");
            example_do_connect(client);         /* Connect to server all over again */
            break;
        }
        
        default: 
            break;
    }
}

/** Make a connection to MQTT server in non-blocking mode */
static void
example_do_connect(esp_mqtt_client_p client) {
    if (client == NULL) {
        return;
    }
    
    /*
     * Start a simple connection to open source
     * MQTT server on mosquitto.org
     */
    retries++;
    esp_timeout_remove(mqtt_timeout_cb);
    esp_mqtt_client_connect(mqtt_client, "test.mosquitto.org", 1883, mqtt_cb, &mqtt_client_info);
}
group ESP_APP_MQTT_CLIENT

MQTT client.

Typedefs

typedef struct esp_mqtt_client *esp_mqtt_client_p

Pointer to esp_mqtt_client_t structure.

typedef void (*esp_mqtt_evt_fn)(esp_mqtt_client_p client, esp_mqtt_evt_t *evt)

MQTT event callback function.

Parameters
  • [in] client: MQTT client

  • [in] evt: MQTT event with type and related data

Enums

enum esp_mqtt_qos_t

Quality of service enumeration.

Values:

ESP_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

ESP_MQTT_QOS_AT_LEAST_ONCE = 0x01

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

ESP_MQTT_QOS_EXACTLY_ONCE = 0x02

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

enum esp_mqtt_state_t

State of MQTT client.

Values:

ESP_MQTT_CONN_DISCONNECTED = 0x00

Connection with server is not established

ESP_MQTT_CONN_CONNECTING

Client is connecting to server

ESP_MQTT_CONN_DISCONNECTING

Client connection is disconnecting from server

ESP_MQTT_CONNECTING

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

ESP_MQTT_CONNECTED

MQTT is fully connected and ready to send data on topics

enum esp_mqtt_evt_type_t

MQTT event types.

Values:

ESP_MQTT_EVT_CONNECT

MQTT client connect event

ESP_MQTT_EVT_SUBSCRIBE

MQTT client subscribed to specific topic

ESP_MQTT_EVT_UNSUBSCRIBE

MQTT client unsubscribed from specific topic

ESP_MQTT_EVT_PUBLISH

MQTT client publish message to server event.

Note

When publishing packet with quality of service ESP_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 = ESP_MQTT_QOS_AT_MOST_ONCE

ESP_MQTT_EVT_PUBLISH_RECV

MQTT client received a publish message from server

ESP_MQTT_EVT_DISCONNECT

MQTT client disconnected from MQTT server

ESP_MQTT_EVT_KEEP_ALIVE

MQTT keep-alive sent to server and reply received

enum esp_mqtt_conn_status_t

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

Values:

ESP_MQTT_CONN_STATUS_ACCEPTED = 0x00

Connection accepted and ready to use

ESP_MQTT_CONN_STATUS_REFUSED_PROTOCOL_VERSION = 0x01

Connection Refused, unacceptable protocol version

ESP_MQTT_CONN_STATUS_REFUSED_ID = 0x02

Connection refused, identifier rejected

ESP_MQTT_CONN_STATUS_REFUSED_SERVER = 0x03

Connection refused, server unavailable

ESP_MQTT_CONN_STATUS_REFUSED_USER_PASS = 0x04

Connection refused, bad user name or password

ESP_MQTT_CONN_STATUS_REFUSED_NOT_AUTHORIZED = 0x05

Connection refused, not authorized

ESP_MQTT_CONN_STATUS_TCP_FAILED = 0x100

TCP connection to server was not successful

Functions

esp_mqtt_client_p esp_mqtt_client_new(size_t tx_buff_len, size_t rx_buff_len)

Allocate a new MQTT client structure.

Return

Pointer to new allocated MQTT client structure or NULL on failure

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

  • [in] rx_buff_len: Length of raw data input buffer

void esp_mqtt_client_delete(esp_mqtt_client_p client)

Delete MQTT client structure.

Note

MQTT client must be disconnected first

Parameters
  • [in] client: MQTT client

espr_t esp_mqtt_client_connect(esp_mqtt_client_p client, const char *host, esp_port_t port, esp_mqtt_evt_fn evt_fn, const esp_mqtt_client_info_t *info)

Connect to MQTT server.

Note

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

Return

espOK on success, member of espr_t enumeration otherwise

Parameters
  • [in] client: MQTT client

  • [in] host: Host address for server

  • [in] port: Host port number

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

  • [in] info: Information structure for connection

espr_t esp_mqtt_client_disconnect(esp_mqtt_client_p client)

Disconnect from MQTT server.

Return

espOK if request sent to queue or member of espr_t otherwise

Parameters
  • [in] client: MQTT client

uint8_t esp_mqtt_client_is_connected(esp_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

Return

1 on success, 0 otherwise

Parameters
  • [in] client: MQTT client

espr_t esp_mqtt_client_subscribe(esp_mqtt_client_p client, const char *topic, esp_mqtt_qos_t qos, void *arg)

Subscribe to MQTT topic.

Return

espOK on success, member of espr_t enumeration otherwise

Parameters
  • [in] client: MQTT client

  • [in] topic: Topic name to subscribe to

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

  • [in] arg: User custom argument used in callback

espr_t esp_mqtt_client_unsubscribe(esp_mqtt_client_p client, const char *topic, void *arg)

Unsubscribe from MQTT topic.

Return

espOK on success, member of espr_t enumeration otherwise

Parameters
  • [in] client: MQTT client

  • [in] topic: Topic name to unsubscribe from

  • [in] arg: User custom argument used in callback

espr_t esp_mqtt_client_publish(esp_mqtt_client_p client, const char *topic, const void *payload, uint16_t len, esp_mqtt_qos_t qos, uint8_t retain, void *arg)

Publish a new message on specific topic.

Return

espOK on success, member of espr_t enumeration otherwise

Parameters
  • [in] client: MQTT client

  • [in] topic: Topic to send message to

  • [in] payload: Message data

  • [in] payload_len: Length of payload data

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

  • [in] retain: Retian parameter value

  • [in] arg: User custom argument used in callback

void *esp_mqtt_client_get_arg(esp_mqtt_client_p client)

Get user argument on client.

Return

User argument

Parameters
  • [in] client: MQTT client handle

void esp_mqtt_client_set_arg(esp_mqtt_client_p client, void *arg)

Set user argument on client.

Parameters
  • [in] client: MQTT client handle

  • [in] arg: User argument

struct esp_mqtt_client_info_t
#include <esp_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

esp_mqtt_qos_t will_qos

Will topic quality of service

struct esp_mqtt_request_t
#include <esp_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 esp_mqtt_evt_t
#include <esp_mqtt_client.h>

MQTT event structure for callback function.

Public Members

esp_mqtt_evt_type_t type

Event type

esp_mqtt_conn_status_t status

Connection status with MQTT

struct esp_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 esp_mqtt_evt_t::[anonymous]::[anonymous] disconnect

Event for disconnecting from server

void *arg

User argument for callback function

espr_t res

Response status

struct esp_mqtt_evt_t::[anonymous]::[anonymous] sub_unsub_scribed

Event for (un)subscribe to/from topics

struct esp_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

esp_mqtt_qos_t qos

Received packet quality of service

struct esp_mqtt_evt_t::[anonymous]::[anonymous] publish_recv

Publish received event

union esp_mqtt_evt_t::[anonymous] evt

Event data parameters

group ESP_APP_MQTT_CLIENT_EVT

Event helper functions.

Connect event

Note

Use these functions on ESP_MQTT_EVT_CONNECT event

esp_mqtt_client_evt_connect_get_status(client, evt)

Get connection status.

Return

Connection status. Member of esp_mqtt_conn_status_t

Parameters
  • [in] client: MQTT client

  • [in] evt: Event handle

Disconnect event

Note

Use these functions on ESP_MQTT_EVT_DISCONNECT event

esp_mqtt_client_evt_disconnect_is_accepted(client, evt)

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

Return

1 on success, 0 otherwise

Parameters
  • [in] client: MQTT client

  • [in] evt: Event handle

Subscribe/unsubscribe event

Note

Use these functions on ESP_MQTT_EVT_SUBSCRIBE or ESP_MQTT_EVT_UNSUBSCRIBE events

esp_mqtt_client_evt_subscribe_get_argument(client, evt)

Get user argument used on esp_mqtt_client_subscribe.

Return

User argument

Parameters
  • [in] client: MQTT client

  • [in] evt: Event handle

esp_mqtt_client_evt_subscribe_get_result(client, evt)

Get result of subscribe event.

Return

espOK on success, member of espr_t otherwise

Parameters
  • [in] client: MQTT client

  • [in] evt: Event handle

esp_mqtt_client_evt_unsubscribe_get_argument(client, evt)

Get user argument used on esp_mqtt_client_unsubscribe.

Return

User argument

Parameters
  • [in] client: MQTT client

  • [in] evt: Event handle

esp_mqtt_client_evt_unsubscribe_get_result(client, evt)

Get result of unsubscribe event.

Return

espOK on success, member of espr_t otherwise

Parameters
  • [in] client: MQTT client

  • [in] evt: Event handle

Publish receive event

Note

Use these functions on ESP_MQTT_EVT_PUBLISH_RECV event

esp_mqtt_client_evt_publish_recv_get_topic(client, evt)

Get topic from received publish packet.

Return

Topic name

Parameters
  • [in] client: MQTT client

  • [in] evt: Event handle

esp_mqtt_client_evt_publish_recv_get_topic_len(client, evt)

Get topic length from received publish packet.

Return

Topic length

Parameters
  • [in] client: MQTT client

  • [in] evt: Event handle

esp_mqtt_client_evt_publish_recv_get_payload(client, evt)

Get payload from received publish packet.

Return

Packet payload

Parameters
  • [in] client: MQTT client

  • [in] evt: Event handle

esp_mqtt_client_evt_publish_recv_get_payload_len(client, evt)

Get payload length from received publish packet.

Return

Payload length

Parameters
  • [in] client: MQTT client

  • [in] evt: Event handle

esp_mqtt_client_evt_publish_recv_is_duplicate(client, evt)

Check if packet is duplicated.

Return

1 if duplicated, 0 otherwise

Parameters
  • [in] client: MQTT client

  • [in] evt: Event handle

esp_mqtt_client_evt_publish_recv_get_qos(client, evt)

Get received quality of service.

Return

Member of esp_mqtt_qos_t enumeration

Parameters
  • [in] client: MQTT client

  • [in] evt: Event handle

Publish event

Note

Use these functions on ESP_MQTT_EVT_PUBLISH event

esp_mqtt_client_evt_publish_get_argument(client, evt)

Get user argument used on esp_mqtt_client_publish.

Return

User argument

Parameters
  • [in] client: MQTT client

  • [in] evt: Event handle

esp_mqtt_client_evt_publish_get_result(client, evt)

Get result of publish event.

Return

espOK on success, member of espr_t otherwise

Parameters
  • [in] client: MQTT client

  • [in] evt: Event handle

Defines

esp_mqtt_client_evt_get_type(client, evt)

Get MQTT event type.

Return

MQTT Event type, value of esp_mqtt_evt_type_t enumeration

Parameters
  • [in] client: MQTT client

  • [in] evt: Event handle