You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Adafruit SCD-41 - True CO2 Temperature and Humidity Sensor
Adafruit PCF8523 Real Time Clock Breakout Board
Version
other
IDE Name
PlatformIO
Operating System
Windows 10
Flash frequency
80mHz
PSRAM enabled
no
Upload speed
not specified
Description
A CO2 measuring device tries to publish it's measurements through MQTT in certain intervals, i.e. 3 minutes. The device deep-sleeps between measurements, therefore WifiClient and PubSubClient need to be instantiated and destroyed every time new measurements need to be published.
Since the user can upload the mqtt broker certificate it needs to be kept in a file on SD-card. Each tim a new instance of WifiClientSecure is created, the certificate file is opened and passed to that client through: WiFiClientSecure::loadCACert(Stream& stream, size_t size)
ESP.getFreeHeap() returns ~70000bytes when first measurements are published, but reduces with each publish operation, until at ~60.000bytes the following error shows:
With SSL not correctly set up any more, further connections fail and subsequently mqtt publish fails too.
Workaround: free heap roughly reduces by the size of the certificate file each time. Looking at the code of WifiClientSecure it seems that a certificate, once loaded, never is freed when the client instance is destroyed.
When loading the certificate manually, then using. WiFiClientSecure::setCACert (const char *rootCA)
rather than WiFiClientSecure::loadCACert(Stream& stream, size_t size)
and freeing the loaded data before destroying the client, the memory leak appears to be fixed.
Sketch
//--------------------------------------------------------------------------------// first solution (memory leak)// instantiate wifi-client
WiFiClient* wifiClient;
char* certFileData = NULL;
if (crt != "" && ModuleCard::existsPath(crt)) {
wifiClient = newWiFiClientSecure();
File32 certFile;
certFile.open(crt, O_RDONLY);
((WiFiClientSecure*)wifiClient)->loadCACert(certFile, certFile.size());
certFile.close();
} else {
wifiClient = newWiFiClient();
}
// instantiate mqtt-client
PubSubClient* mqttClient;
mqttClient = new PubSubClient(*wifiClient);
mqttClient->setServer(srv, prt);
if (usr != "" && pwd != "") {
mqttClient->connect(cli, usr, pwd, 0, 0, 0, 0, 0);
} else {
mqttClient->connect(cli);
}
if (mqttClient->connected()) {
// mqtt publishing happening here, around 100bytes/measurement, 300bytes total
mqttClient->disconnect(); // calls stop() on wificlient
}
// redundant call to wifi-client stop
wifiClient->stop();
delete mqttClient; // releases some bufferdelete wifiClient; // calls stop (again) and deletes an internal sslclient instance
mqttClient = NULL;
wifiClient = NULL;
//--------------------------------------------------------------------------------// alternative solution (no memory leak)// instantiate wifi-client
WiFiClient* wifiClient;
char* certFileData = NULL;
if (mqtt.crt != "" && ModuleCard::existsPath(mqtt.crt)) {
wifiClient = newWiFiClientSecure();
File32 certFile;
certFile.open(mqtt.crt, O_RDONLY);
certFileData = (char*)malloc(certFile.size() + 1);
certFile.readBytes(certFileData, certFile.size());
((WiFiClientSecure*)wifiClient)->setCACert(certFileData);
certFile.close();
} else {
wifiClient = newWiFiClient();
}
// instantiate mqtt-client
PubSubClient* mqttClient;
mqttClient = new PubSubClient(*wifiClient);
mqttClient->setServer(mqtt.srv, mqtt.prt);
if (mqtt.usr != "" && mqtt.pwd != "") {
mqttClient->connect(mqtt.cli, mqtt.usr, mqtt.pwd, 0, 0, 0, 0, 0);
} else {
mqttClient->connect(mqtt.cli); // connect without credentials
}
if (mqttClient->connected()) {
// mqtt publishing happening here, around 100bytes/measurement, 300bytes total
mqttClient->disconnect(); // calls stop() on wificlient
}
// redundant call to wifi-client stop
wifiClient->stop();
if (certFileData != NULL) {
free(const_cast<char*>(certFileData)); // free the memory used to hold the certificate
certFileData = NULL;
}
delete mqttClient; // releases some bufferdelete wifiClient; // calls stop (again) and deletes an internal sslclient instance
mqttClient = NULL;
wifiClient = NULL;
EDIT: or doesn't. but has a problem related to the fix of that problem. If setCaCert is first used with the cert on stack or global, and the load is invoked, it will attempt to delete the instance on stack or global
Board
featheresp32-s2
Device Description
Adafruit ESP32-S2 Feather with BME280 Sensor
https://www.adafruit.com/product/5303
platformio.ini as follows:
[env:featheresp32-s2]
platform = espressif32
board = featheresp32-s2
framework = arduino
board_build.f_cpu = 80000000L
board_build.f_flash = 80000000L
board_build.flash_mode = qio
board_build.partitions = min_spiffs.csv
monitor_speed = 115200
lib_deps =
adafruit/Adafruit NeoPixel@^1.12.0
adafruit/Adafruit BusIO@^1.15.0
SPI@^2.0.0
adafruit/SdFat - Adafruit Fork@^2.2.3
sensirion/Sensirion I2C SCD4x@^0.4.0
adafruit/Adafruit EPD@^4.5.4
adafruit/Adafruit BME280 Library@^2.2.4
adafruit/Adafruit LC709203F@^1.3.4
adafruit/RTClib@^2.1.3
bblanchon/[email protected]
ottowinter/ESPAsyncWebServer-esphome@^3.1.0
ricmoo/QRCode@^0.0.1
knolleary/PubSubClient@^2.8
build_flags = -DCORE_DEBUG_LEVEL=0
Hardware Configuration
Yes
Version
other
IDE Name
PlatformIO
Operating System
Windows 10
Flash frequency
80mHz
PSRAM enabled
no
Upload speed
not specified
Description
A CO2 measuring device tries to publish it's measurements through MQTT in certain intervals, i.e. 3 minutes. The device deep-sleeps between measurements, therefore WifiClient and PubSubClient need to be instantiated and destroyed every time new measurements need to be published.
Since the user can upload the mqtt broker certificate it needs to be kept in a file on SD-card. Each tim a new instance of WifiClientSecure is created, the certificate file is opened and passed to that client through:
WiFiClientSecure::loadCACert(Stream& stream, size_t size)
ESP.getFreeHeap() returns ~70000bytes when first measurements are published, but reduces with each publish operation, until at ~60.000bytes the following error shows:
[start_ssl_client():273]: (-32512) SSL - Memory allocation failed
With SSL not correctly set up any more, further connections fail and subsequently mqtt publish fails too.
Workaround: free heap roughly reduces by the size of the certificate file each time. Looking at the code of WifiClientSecure it seems that a certificate, once loaded, never is freed when the client instance is destroyed.
When loading the certificate manually, then using.
WiFiClientSecure::setCACert (const char *rootCA)
rather than
WiFiClientSecure::loadCACert(Stream& stream, size_t size)
and freeing the loaded data before destroying the client, the memory leak appears to be fixed.
Sketch
Debug Message
Other Steps to Reproduce
No response
I have checked existing issues, online documentation and the Troubleshooting Guide
The text was updated successfully, but these errors were encountered: