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 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.
-
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)