Skip to content

Instantly share code, notes, and snippets.

@gmag11
Last active February 26, 2024 10:13
Show Gist options
  • Star 17 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save gmag11/c565a18d361a46993039f8a515e67614 to your computer and use it in GitHub Desktop.
Save gmag11/c565a18d361a46993039f8a515e67614 to your computer and use it in GitHub Desktop.
Secure MQTT connection to broker with ESP32 and internal IDF mqtt client library
#include "Arduino.h"
#include <WiFi.h>
#include "esp_log.h"
#include "esp_system.h"
#include "esp_event.h"
#include "mqtt_client.h"
#define SECURE_MQTT // Comment this line if you are not using MQTT over SSL
#ifdef SECURE_MQTT
#include "esp_tls.h"
// Let's Encrypt CA certificate. Change with the one you need
static const unsigned char DSTroot_CA[] PROGMEM = R"EOF(
-----BEGIN CERTIFICATE-----
MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow
PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD
Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O
rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq
OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b
xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw
7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD
aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV
HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG
SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69
ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr
AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz
R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5
JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo
Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
-----END CERTIFICATE-----
)EOF";
#endif // SECURE_MQTT
esp_mqtt_client_config_t mqtt_cfg;
esp_mqtt_client_handle_t client;
const char* WIFI_SSID = "Your_SSID";
const char* WIFI_PASSWD = "Your_password";
const char* MQTT_HOST = "Your_broker_address";
#ifdef SECURE_MQTT
const uint32_t MQTT_PORT = 8883;
#else
const uint32_t MQTT_PORT = 1883;
#endif // SECURE_MQTT
const char* MQTT_USER = "Username_in_broker";
const char* MQTT_PASSWD = "password";
static esp_err_t mqtt_event_handler (esp_mqtt_event_handle_t event) {
if (event->event_id == MQTT_EVENT_CONNECTED) {
ESP_LOGI ("TEST", "MQTT msgid= %d event: %d. MQTT_EVENT_CONNECTED", event->msg_id, event->event_id);
esp_mqtt_client_subscribe (client, "test/hello", 0);
esp_mqtt_client_publish (client, "test/status", "1", 1, 0, false);
}
else if (event->event_id == MQTT_EVENT_DISCONNECTED) {
ESP_LOGI ("TEST", "MQTT event: %d. MQTT_EVENT_DISCONNECTED", event->event_id);
//esp_mqtt_client_reconnect (event->client); //not needed if autoconnect is enabled
} else if (event->event_id == MQTT_EVENT_SUBSCRIBED) {
ESP_LOGI ("TEST", "MQTT msgid= %d event: %d. MQTT_EVENT_SUBSCRIBED", event->msg_id, event->event_id);
} else if (event->event_id == MQTT_EVENT_UNSUBSCRIBED) {
ESP_LOGI ("TEST", "MQTT msgid= %d event: %d. MQTT_EVENT_UNSUBSCRIBED", event->msg_id, event->event_id);
} else if (event->event_id == MQTT_EVENT_PUBLISHED) {
ESP_LOGI ("TEST", "MQTT event: %d. MQTT_EVENT_PUBLISHED", event->event_id);
} else if (event->event_id == MQTT_EVENT_DATA) {
ESP_LOGI ("TEST", "MQTT msgid= %d event: %d. MQTT_EVENT_DATA", event->msg_id, event->event_id);
ESP_LOGI ("TEST", "Topic length %d. Data length %d", event->topic_len, event->data_len);
ESP_LOGI ("TEST","Incoming data: %.*s %.*s\n", event->topic_len, event->topic, event->data_len, event->data);
} else if (event->event_id == MQTT_EVENT_BEFORE_CONNECT) {
ESP_LOGI ("TEST", "MQTT event: %d. MQTT_EVENT_BEFORE_CONNECT", event->event_id);
}
return ESP_OK;
}
void setup () {
mqtt_cfg.host = MQTT_HOST;
mqtt_cfg.port = MQTT_PORT;
mqtt_cfg.username = MQTT_USER;
mqtt_cfg.password = MQTT_PASSWD;
mqtt_cfg.keepalive = 15;
#ifdef SECURE_MQTT
mqtt_cfg.transport = MQTT_TRANSPORT_OVER_SSL;
#else
mqtt_cfg.transport = MQTT_TRANSPORT_OVER_TCP;
#endif // SECURE_MQTT
mqtt_cfg.event_handle = mqtt_event_handler;
mqtt_cfg.lwt_topic = "test/status";
mqtt_cfg.lwt_msg = "0";
mqtt_cfg.lwt_msg_len = 1;
Serial.begin (115200);
WiFi.mode (WIFI_MODE_STA);
WiFi.begin (WIFI_SSID, WIFI_PASSWD);
while (!WiFi.isConnected ()) {
Serial.print ('.');
delay (100);
}
Serial.println ();
#ifdef SECURE_MQTT
esp_err_t err = esp_tls_set_global_ca_store (DSTroot_CA, sizeof (DSTroot_CA));
ESP_LOGI ("TEST","CA store set. Error = %d %s", err, esp_err_to_name(err));
#endif // SECURE_MQTT
client = esp_mqtt_client_init (&mqtt_cfg);
//esp_mqtt_client_register_event (client, ESP_EVENT_ANY_ID, mqtt_event_handler, client); // not implemented in current Arduino core
err = esp_mqtt_client_start (client);
ESP_LOGI ("TEST", "Client connect. Error = %d %s", err, esp_err_to_name (err));
}
void loop () {
esp_mqtt_client_publish (client, "test/bye", "data", 4, 0, false);
delay (2000);
}
@poky
Copy link

poky commented Mar 29, 2021

Added last will, subscription, publishing and unsecure connection as an (not recommended) option

Where is the line of code for subscribing?

Line 56?

esp_mqtt_client_subscribe (client, "test/hello", 0);

@gmag11
Copy link
Author

gmag11 commented Apr 1, 2021

Exactly. It is done just after connected event.

@gjt211
Copy link

gjt211 commented Apr 3, 2021

Hi, I just copy-pasted this into a new blank sketch and it doesn't compile for me. It looks like there is meant to be a return value for the mqtt_event_handler but there is not one there.

Documents/Arduino/esp32test/esp32test.ino: In function 'esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t)':
esp32test:76:1: error: no return statement in function returning non-void [-Werror=return-type]
 }
 ^

Any ideas where I should start looking? I am guessing it is working for others so it must be something on my system. (MacOS, Arduino 1.8.10)

@poky
Copy link

poky commented Apr 3, 2021

Hi, I just copy-pasted this into a new blank sketch and it doesn't compile for me. It looks like there is meant to be a return value for the mqtt_event_handler but there is not one there.

Documents/Arduino/esp32test/esp32test.ino: In function 'esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t)':
esp32test:76:1: error: no return statement in function returning non-void [-Werror=return-type]
 }
 ^

Any ideas where I should start looking? I am guessing it is working for others so it must be something on my system. (MacOS, Arduino 1.8.10)

Compiled and ran fine on my Mac with Arduino 1.8.13 and esp 1.0.6

@poky
Copy link

poky commented Apr 3, 2021

Hi, I just copy-pasted this into a new blank sketch and it doesn't compile for me. It looks like there is meant to be a return value for the mqtt_event_handler but there is not one there.

Documents/Arduino/esp32test/esp32test.ino: In function 'esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t)':
esp32test:76:1: error: no return statement in function returning non-void [-Werror=return-type]
 }
 ^

Any ideas where I should start looking? I am guessing it is working for others so it must be something on my system. (MacOS, Arduino 1.8.10)

Or you could add

return ESP_OK;

in the end of that statement

@gmag11
Copy link
Author

gmag11 commented Apr 5, 2021

Hi, I just copy-pasted this into a new blank sketch and it doesn't compile for me. It looks like there is meant to be a return value for the mqtt_event_handler but there is not one there.

Documents/Arduino/esp32test/esp32test.ino: In function 'esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t)':
esp32test:76:1: error: no return statement in function returning non-void [-Werror=return-type]
 }
 ^

Any ideas where I should start looking? I am guessing it is working for others so it must be something on my system. (MacOS, Arduino 1.8.10)

Hi. You are right. There is a missing return statement there. I'll add it soon. Meanwhile as @poky suggest here you may add return ESP_OK; at the end of that function.

@gjt211
Copy link

gjt211 commented Apr 5, 2021

Thanks poky and gmag11, The return statement did fix the problem.
Great work, and thanks for providing this. Highly appreciated.

@poky
Copy link

poky commented Apr 6, 2021

Thanks poky and gmag11, The return statement did fix the problem.
Great work, and thanks for providing this. Highly appreciated.

Glad it works for you!

Just a friendly reminder, that you should not put any "hard work" especially IO tasks in this block or function call from it.

} else  if (event->event_id == MQTT_EVENT_DATA) {
		ESP_LOGI ("TEST", "MQTT msgid= %d event: %d. MQTT_EVENT_DATA", event->msg_id, event->event_id);
		ESP_LOGI ("TEST", "Topic length %d. Data length %d", event->topic_len, event->data_len);
		ESP_LOGI ("TEST","Incoming data: %.*s %.*s\n", event->topic_len, event->topic, event->data_len, event->data);

}

I was having a headache try to debug the random crash issue when too many data received at once, the best way to handle it is to put a flag, and that the outer function catches it to do the rest of work.

@Phil-VK6PH
Copy link

Hi, as a novice could you please explain where I can find the esp_log.h, esp_system.h etc files.

Also can this code publish with QoS 2?

Thanks

@r-sherwood
Copy link

I was having a headache try to debug the random crash issue when too many data received at once, the best way to handle it is to put a flag, and that the outer function catches it to do the rest of work.

@poky I'm facing the same issues and don't know how to solve it. Can you provide a sample how to deal with your recommended flaged incoming MQTT_EVENT_DATA and outer functions?

Thanks

@poky
Copy link

poky commented Nov 21, 2022

I was having a headache try to debug the random crash issue when too many data received at once, the best way to handle it is to put a flag, and that the outer function catches it to do the rest of work.

@poky I'm facing the same issues and don't know how to solve it. Can you provide a sample how to deal with your recommended flaged incoming MQTT_EVENT_DATA and outer functions?

Thanks

Add a function something like this...

void example_task()
{
if(flag)
{
// Some codes
flag = false;
}
}

add example_task() to the loop function to run.
Once the MQTT_EVENT_DATA event arrived, just make flag = true, so the function will run outside of the event handler.

@pprakash
Copy link

pprakash commented Jan 8, 2023

Hi, I tried to compile and run this on Platform IO. Compile was successful but was getting below error while running on ESP32-WROOM-32.
Any help on resolving this?

E (327) esp-tls-mbedtls: No server verification option set in esp_tls_cfg_t structure. Check esp_tls API reference E (328) esp-tls-mbedtls: Failed to set client configurations, returned [0x8017] (ESP_ERR_MBEDTLS_SSL_SETUP_FAILED) E (337) esp-tls: create_ssl_handle failed E (341) esp-tls: Failed to open new connection E (345) TRANSPORT_BASE: Failed to open a new connection E (352) MQTT_CLIENT: Error transport connect

Build Enviornment:
Visual Studio Code with Platform IO
PLATFORM: Espressif 32 (5.2.0)

  • framework-arduinoespressif32 @ 3.20005.220925 (2.0.5)
  • tool-esptoolpy @ 1.40201.0 (4.2.1)

@gmag11
Copy link
Author

gmag11 commented Jan 8, 2023

Maybe something has changed in IDF. I'll test it

@pprakash
Copy link

pprakash commented Jan 10, 2023

It works with Espresif 32 ( 3.2.1) core of Platform IO.

@gmag11
Copy link
Author

gmag11 commented Jan 21, 2023

Hi, I tried to compile and run this on Platform IO. Compile was successful but was getting below error while running on ESP32-WROOM-32. Any help on resolving this?

E (327) esp-tls-mbedtls: No server verification option set in esp_tls_cfg_t structure. Check esp_tls API reference E (328) esp-tls-mbedtls: Failed to set client configurations, returned [0x8017] (ESP_ERR_MBEDTLS_SSL_SETUP_FAILED) E (337) esp-tls: create_ssl_handle failed E (341) esp-tls: Failed to open new connection E (345) TRANSPORT_BASE: Failed to open a new connection E (352) MQTT_CLIENT: Error transport connect

Build Enviornment: Visual Studio Code with Platform IO PLATFORM: Espressif 32 (5.2.0)

  • framework-arduinoespressif32 @ 3.20005.220925 (2.0.5)
  • tool-esptoolpy @ 1.40201.0 (4.2.1)

I've compiled on latest Platformio ESP32 (6.0.0) and it compiles fine.

image

image

@MichMich
Copy link

Try adding the following:

mqtt_cfg.use_global_ca_store = true;

@russinnes
Copy link

mqtt_cfg.use_global_ca_store = true;

Required in arduino IDE 2.2 if you want TLS to work..

@JNRAY
Copy link

JNRAY commented Nov 18, 2023

Hello,
Could you tel me how do you generate the certificat ?

@bimalsatheesh
Copy link

Hello @gmag11, I have tested the code in esp32 Arduino platform and successfully published test messages to the given topic - test/bye. But I couldn't get any messages in the subscribed topic - test/hello. Couldn't find what is the issue. Please guide,
Thanks

@gmag11
Copy link
Author

gmag11 commented Nov 29, 2023

Hello, Could you tel me how do you generate the certificat ?

You can use OpenSSL utility. For instance http://www.steves-internet-guide.com/mosquitto-tls/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment