MQTT Library for ESP32 with TLS, non-blocking

Hi all,
I'm looking for a library which allows me to connect my ESP32 to a MQTT server using SSL/TLS (TLS version 1.2 or 1.3).

In order to avoid blocking functions I don't want to use PubSubClient.h as the function which connects to the MQTT server is blocking afaik. Furthermore I use FreeRTOS.

Does anybody knows a similar library which meets all of my requirements?

  • non-blocking
  • supporting TLS1.2 or 1.3
  • ideally with eventHandler

I already tried with AsyncMQTT_ESP32 (GitHub - khoih-prog/AsyncMQTT_ESP32: Arduino Library for ESP32/S2/S3/C3 asynchronous MQTT client implementation. This library, ported to support ESP32/S2/S3/C3, WT32_ETH01 (ESP32 + LAN8720), ESP32 using LwIP ENC28J60, W5500, W6100 or LAN8720. Supporting TLS/SSL for MQTTS Client) but this doesn't work as it only uses fingerprints but no certificates.
At least that's how it looks like to me. Or I just don't get how to use it correctly.

Thanks a lot in advance!

Best
regards

Based on your requirements, you might want to consider the esp-mqtt library developed by Espressif, the company behind the ESP32. This library supports MQTT over TCP with SSL using mbedtls, which means it can handle TLS 1.2 and 1.3. It's also designed to work with the ESP-IDF, which is the official development framework for the ESP32.

Here are some key features of the esp-mqtt library:

  • Supports MQTT over TCP, SSL with mbedtls, MQTT over Websocket, and MQTT over Websocket Secure.
  • Allows for easy setup with URI.
  • Supports multiple instances (multiple clients in one application).
  • Handles subscribing, publishing, authentication, will messages, keep alive pings, and all 3 QoS levels.

To use esp-mqtt, you would need to integrate it into your ESP-IDF project. The library is a standard ESP-IDF component, and you can refer to the ESP-IDF documentation for instructions on how to use it.

Alternatively, you could look into the espMqttClient library, which is a MQTT 3.1.1 compliant library that supports TCP and TCP/TLS using standard WiFiClient and WiFiClientSecure connections. It's designed to work with the Arduino framework on ESP8266 and ESP32, and it provides fully async clients via AsyncTCP or ESPAsnycTCP.

The espMqttClient library allows you to set up TLS secured connections using methods from WiFiClientSecure, which include setting the CA certificate, client certificate, private key, and pre-shared key.

Here's an example of how you might set up a secure connection with espMqttClient:

#include <WiFi.h>
#include <esp_mqtt_client.h>

// WiFi credentials
const char* ssid = "your_SSID";
const char* password = "your_PASSWORD";

// MQTT server
const char* mqtt_server = "your_MQTT_SERVER";

// CA certificate for TLS
const char* ca_cert = "-----BEGIN CERTIFICATE-----\n"
                      "...your CA certificate here...\n"
                      "-----END CERTIFICATE-----";

void setup() {
  // Connect to WiFi
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
  }

  // Set up MQTT client
  esp_mqtt_client_config_t mqtt_cfg = {
    .uri = mqtt_server,
    .cert_pem = ca_cert,
    // ... other configurations ...
  };

  esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
  esp_mqtt_client_start(client);
}

void loop() {
  // Handle MQTT client loop
  esp_mqtt_client_loop(client,  10);
}

This example sets up a secure MQTT connection using the CA certificate for TLS. You would replace "your_SSID", "your_PASSWORD", and "your_MQTT_SERVER" with your actual WiFi and MQTT server credentials, and you would provide the actual CA certificate in the ca_cert variable.

Remember to check the documentation for the esp-mqtt library and the espMqttClient library for more detailed information on how to use these libraries and configure them to meet your specific needs.

If you're using FreeRTOS, why do you say it's blocking? With the PubSubClient in one task, code in other task can still be doing work while PubSubClient does its thing.

Hi,
sorry for the late answer.
Thanks for your suggestions @codingapacalyspe, I guess I'm going to dive deeper into ESP-IDF

@gfvalvo I've also asked this question to myself and gave it a try.
Basically it worked, but I had to reduce the sampling frequency of my sensor setup as the schedule is pretty full with the "blocking" task, when the connection to the mqtt broker is lost.
Maybe another idea would be to reduce tick length to something shorter than 1ms, because I think the computation of most of the tasks should be completed faster and so the processor is blocked unneccessarily.

Best regards

Why is the connection being lost? What's the point of taking sensor readings if the MQTT is down?

That's the wrong way to look at it. All the code should be event-driven. If a given task finishes it's job quickly, it should block itself until an even happens that gives it something to do.

Without seeing your code and task model, it's impossible to know what you're doing wrong. I make all my MQTT code event-driven and keep the standard 1ms tick. The task that calls the MQTT library's loop() function runs every 10 - 100ms depending on the project. Another task pulls publish requests from a queue and calls publish(). A mutex controls which task has control of the MQTT object. When a new a new post is received from a subscribed topic, the callback simply puts the information in a queue to be picked up by another task.

Thanks for your thoughts.

The system which runs the mosquitto broker is used for lots more stuff and therefore has to restart sometimes. During this periods I don't want to miss sensor data.
I use the recorded data for aposteriori analysis, so an immediate sending of the data isn't required. So the sensor task creates content (timestamp + value) for mqtt messages and stores this into a queue. The mqtt task then reads the data in the queue and sends the messages, but only, if a mqtt connection is available.

As I need a very high sampling rate for the sensor, this task is called every 2 ms but I think it only needs a computation time lower than 1 ms. So with this setup the sensor task uses 50% of the capacity of one core. By reducing the tick length I could reduce this. If the compuation is done within 0.5 ms, and the tick length would be 0.5 ms the usage of this task would drop to 25%.
Maybe I find the time to provide some code during this week.

It seems you need to gain a better understand of how the task scheduler works and how to properly program in a multi-thread environment.

If a task has finished doing what it needs to, it should block itself until it needs to act again. This yields back not only the remainder of its current 1ms tick allotment, but all future 1ms allotments until it is unblocked.

What are your tasks doing now once they've finished their work? Why do you think the remainder of their 1ms is being "wasted"?

Take a look at Mastering the FreeRTOS Real Time Kernel - A Hands On Tutorial Guide to gain a better understanding and how to properly structure your code.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.