MQTT Client
MQTT client v3.1.1 implementation, based on callback (non-netconn) connection API.
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
-
enumerator LWESP_MQTT_QOS_AT_MOST_ONCE = 0x00
-
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
-
enumerator LWESP_MQTT_CONN_DISCONNECTED = 0x00
-
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
-
enumerator LWESP_MQTT_EVT_CONNECT
-
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
-
enumerator LWESP_MQTT_CONN_STATUS_ACCEPTED = 0x00
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.
-
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.
-
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
-
const char *id
-
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
-
uint8_t status
-
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
-
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
-
lwesp_mqtt_evt_type_t type
-
typedef struct lwesp_mqtt_client *lwesp_mqtt_client_p
- 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.
-
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
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
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
-
lwesp_mqtt_client_evt_connect_get_status(client, evt)