From d536181a730b6203f77956c5a5d44c7d1d7642f1 Mon Sep 17 00:00:00 2001 From: Jan Philipp Ecker Date: Sat, 26 Jul 2025 22:14:58 +0200 Subject: [PATCH 1/5] Introduces new heap debugging feature and fixes some memory leaks in website feature Introduces a new define HEAP_DEBUG_MESSAGE(location) that can be used to instrument the code to get heap information output on the Serial output. It can be enabled via the define ENABLE_HEAP_DEBUGGING. Also fixes some memory leaks in the website part of the project. --- src/debug.h | 12 ++++++++++++ src/website.cpp | 10 ++++++++++ 2 files changed, 22 insertions(+) create mode 100644 src/debug.h diff --git a/src/debug.h b/src/debug.h new file mode 100644 index 0000000..8cc1efc --- /dev/null +++ b/src/debug.h @@ -0,0 +1,12 @@ +#include + + +#ifdef ENABLE_HEAP_DEBUGGING + #define HEAP_DEBUG_MESSAGE(location) printHeapDebugData(location); +#else + #define HEAP_DEBUG_MESSAGE(location) +#endif + +inline void printHeapDebugData(String location){ + Serial.println("Heap: " + String(ESP.getMinFreeHeap()/1024) + "\t" + String(ESP.getFreeHeap()/1024) + "\t" + String(ESP.getMaxAllocHeap()/1024) + "\t" + location); +} \ No newline at end of file diff --git a/src/website.cpp b/src/website.cpp index 0ff02db..56ddf78 100644 --- a/src/website.cpp +++ b/src/website.cpp @@ -10,6 +10,7 @@ #include #include "display.h" #include "ota.h" +#include "debug.h" #ifndef VERSION #define VERSION "1.1.0" @@ -26,6 +27,7 @@ nfcReaderStateType lastnfcReaderState = NFC_IDLE; void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) { + HEAP_DEBUG_MESSAGE("onWsEvent begin"); if (type == WS_EVT_CONNECT) { Serial.println("Neuer Client verbunden!"); // Sende die AMS-Daten an den neuen Client @@ -33,6 +35,10 @@ void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventTyp sendNfcData(client); foundNfcTag(client, 0); sendWriteResult(client, 3); + + // Clean up dead connections + (*server).cleanupClients(); + Serial.println("Currently connected number of clients: " + String((*server).getClients().size())); } else if (type == WS_EVT_DISCONNECT) { Serial.println("Client getrennt."); } else if (type == WS_EVT_ERROR) { @@ -113,7 +119,9 @@ void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventTyp else { Serial.println("Unbekannter WebSocket-Typ: " + doc["type"].as()); } + doc.clear(); } + HEAP_DEBUG_MESSAGE("onWsEvent end"); } // Funktion zum Laden und Ersetzen des Headers in einer HTML-Datei @@ -280,6 +288,8 @@ void setupWebserver(AsyncWebServer &server) { html.replace("{{autoSendTime}}", String(autoSetBambuAmsCounter)); } + doc.clear(); + request->send(200, "text/html", html); }); From faaffee3915c2d07f635f0fd9294e7d9b7e4caec Mon Sep 17 00:00:00 2001 From: Jan Philipp Ecker Date: Sat, 26 Jul 2025 22:36:04 +0200 Subject: [PATCH 2/5] Memory leak fixes in api and nfc, location tag fix Fixes multiple potential memory leaks in API and NFC. Also fixes an issue in the new locaiton tag feature that could lead to multiple parallel API requests. This could cause memory leak issues but also result in wrong weights being registered for a spool. --- src/api.cpp | 26 ++++++++++++++++++++++++-- src/main.cpp | 6 +++--- src/nfc.cpp | 17 ++++++++++++----- src/nfc.h | 3 ++- 4 files changed, 41 insertions(+), 11 deletions(-) diff --git a/src/api.cpp b/src/api.cpp index a100239..5d86c6e 100644 --- a/src/api.cpp +++ b/src/api.cpp @@ -2,6 +2,7 @@ #include #include #include "commonFS.h" +#include "debug.h" volatile spoolmanApiStateType spoolmanApiState = API_INIT; //bool spoolman_connected = false; @@ -87,6 +88,8 @@ JsonDocument fetchSingleSpoolInfo(int spoolId) { } void sendToApi(void *parameter) { + HEAP_DEBUG_MESSAGE("sendToApi begin"); + spoolmanApiState = API_TRANSMITTING; SendToApiParams* params = (SendToApiParams*)parameter; @@ -131,8 +134,8 @@ void sendToApi(void *parameter) { } vTaskDelay(3000 / portTICK_PERIOD_MS); - doc.clear(); } + doc.clear(); } else { Serial.println("Fehler beim Senden an Spoolman! HTTP Code: " + String(httpCode)); @@ -145,8 +148,9 @@ void sendToApi(void *parameter) { // Speicher freigeben delete params; - vTaskDelete(NULL); + HEAP_DEBUG_MESSAGE("sendToApi end"); spoolmanApiState = API_IDLE; + vTaskDelete(NULL); } bool updateSpoolTagId(String uidString, const char* payload) { @@ -169,6 +173,8 @@ bool updateSpoolTagId(String uidString, const char* payload) { Serial.print("Update Spule mit URL: "); Serial.println(spoolsUrl); + doc.clear(); + // Update Payload erstellen JsonDocument updateDoc; updateDoc["extra"]["nfc_id"] = "\""+uidString+"\""; @@ -207,6 +213,7 @@ bool updateSpoolTagId(String uidString, const char* payload) { } uint8_t updateSpoolWeight(String spoolId, uint16_t weight) { + HEAP_DEBUG_MESSAGE("updateSpoolWeight begin"); String spoolsUrl = spoolmanUrl + apiUrl + "/spool/" + spoolId + "/measure"; Serial.print("Update Spule mit URL: "); Serial.println(spoolsUrl); @@ -241,11 +248,14 @@ uint8_t updateSpoolWeight(String spoolId, uint16_t weight) { ); updateDoc.clear(); + HEAP_DEBUG_MESSAGE("updateSpoolWeight end"); return 1; } uint8_t updateSpoolLocation(String spoolId, String location){ + HEAP_DEBUG_MESSAGE("updateSpoolLocation begin"); + String spoolsUrl = spoolmanUrl + apiUrl + "/spool/" + spoolId; Serial.print("Update Spule mit URL: "); Serial.println(spoolsUrl); @@ -281,6 +291,7 @@ uint8_t updateSpoolLocation(String spoolId, String location){ updateDoc.clear(); + HEAP_DEBUG_MESSAGE("updateSpoolLocation end"); return 1; } @@ -345,6 +356,10 @@ bool updateSpoolBambuData(String payload) { String updatePayload; serializeJson(updateDoc, updatePayload); + + doc.clear(); + updateDoc.clear(); + Serial.print("Update Payload: "); Serial.println(updatePayload); @@ -511,6 +526,7 @@ bool checkSpoolmanExtraFields() { vTaskDelay(100 / portTICK_PERIOD_MS); } } + doc.clear(); } } @@ -557,6 +573,8 @@ bool checkSpoolmanInstance(const String& url) { oledShowTopRow(); return strcmp(status, "healthy") == 0; } + + doc.clear(); } } else { Serial.println("Error contacting spoolman instance! HTTP Code: " + String(httpCode)); @@ -584,6 +602,8 @@ bool saveSpoolmanUrl(const String& url, bool octoOn, const String& octoWh, const octoUrl = octoWh; octoToken = octoTk; + doc.clear(); + return true; } @@ -600,6 +620,8 @@ String loadSpoolmanUrl() { return doc["url"].as(); } Serial.println("Keine gültige Spoolman-URL gefunden."); + + doc.clear(); return ""; } diff --git a/src/main.cpp b/src/main.cpp index 01763d4..9980cbc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -212,14 +212,14 @@ void loop() { lastWeight = weight; // Wenn ein Tag mit SM id erkannte wurde und der Waage Counter anspricht an SM Senden - if (spoolId != "" && weigthCouterToApi > 3 && weightSend == 0 && nfcReaderState == NFC_READ_SUCCESS) { + if (activeSpoolId != "" && weigthCouterToApi > 3 && weightSend == 0 && nfcReaderState == NFC_READ_SUCCESS) { oledShowIcon("loading"); - if (updateSpoolWeight(spoolId, weight)) + if (updateSpoolWeight(activeSpoolId, weight)) { oledShowIcon("success"); vTaskDelay(2000 / portTICK_PERIOD_MS); weightSend = 1; - autoSetToBambuSpoolId = spoolId.toInt(); + autoSetToBambuSpoolId = activeSpoolId.toInt(); if (octoEnabled) { diff --git a/src/nfc.cpp b/src/nfc.cpp index ea10267..47dbab4 100644 --- a/src/nfc.cpp +++ b/src/nfc.cpp @@ -14,7 +14,8 @@ Adafruit_PN532 nfc(PN532_IRQ, PN532_RESET); TaskHandle_t RfidReaderTask; JsonDocument rfidData; -String spoolId = ""; +String activeSpoolId = ""; +String lastSpoolId = ""; String nfcJsonData = ""; volatile bool pauseBambuMqttTask = false; @@ -64,6 +65,8 @@ void payloadToJson(uint8_t *data) { Serial.print("deserializeJson() failed: "); Serial.println(error.f_str()); } + + doc.clear(); } else { Serial.println("Kein gültiger JSON-Inhalt gefunden oder fehlerhafte Formatierung."); //writeJsonToTag("{\"version\":\"1.0\",\"protocol\":\"NFC\",\"color_hex\":\"#FFFFFF\",\"type\":\"Example\",\"min_temp\":10,\"max_temp\":30,\"brand\":\"BrandName\"}"); @@ -221,14 +224,15 @@ bool decodeNdefAndReturnJson(const byte* encodedMessage) { if (doc.containsKey("sm_id") && doc["sm_id"] != "") { Serial.println("SPOOL-ID gefunden: " + doc["sm_id"].as()); - spoolId = doc["sm_id"].as(); + activeSpoolId = doc["sm_id"].as(); + lastSpoolId = activeSpoolId; } else if(doc.containsKey("location") && doc["location"] != "") { Serial.println("Location Tag found!"); String location = doc["location"].as(); - if(spoolId != ""){ - updateSpoolLocation(spoolId, location); + if(lastSpoolId != ""){ + updateSpoolLocation(lastSpoolId, location); } else { @@ -240,12 +244,14 @@ bool decodeNdefAndReturnJson(const byte* encodedMessage) { else { Serial.println("Keine SPOOL-ID gefunden."); - spoolId = ""; + activeSpoolId = ""; oledShowMessage("Unknown Spool"); vTaskDelay(2000 / portTICK_PERIOD_MS); } } + doc.clear(); + return true; } @@ -446,6 +452,7 @@ void scanRfidTask(void * parameter) { nfcReaderState = NFC_IDLE; //uidString = ""; nfcJsonData = ""; + activeSpoolId = ""; Serial.println("Tag entfernt"); if (!autoSendToBambu) oledShowWeight(weight); } diff --git a/src/nfc.h b/src/nfc.h index 0d964f2..8f8cf5a 100644 --- a/src/nfc.h +++ b/src/nfc.h @@ -19,7 +19,8 @@ void startWriteJsonToTag(const char* payload); extern TaskHandle_t RfidReaderTask; extern String nfcJsonData; -extern String spoolId; +extern String activeSpoolId; +extern String lastSpoolId; extern volatile nfcReaderStateType nfcReaderState; extern volatile bool pauseBambuMqttTask; From 537f452601736d3870432c7ed56b40c4a44db436 Mon Sep 17 00:00:00 2001 From: Jan Philipp Ecker Date: Sat, 26 Jul 2025 22:39:37 +0200 Subject: [PATCH 3/5] Adds data directory and further .vscode files to to .gitignore Adds the whole data folder that is created during build of the project and further visual studio code related files to the .gitignore file. --- .gitignore | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8f5d62f --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +.pio +.vscode/.browse.c_cpp.db* +.vscode/c_cpp_properties.json +.vscode/launch.json +.vscode/ipch +.vscode/extensions.json +.vscode/settings.json +data \ No newline at end of file From e2e0a23f0addc8ce54fac625839a482b57620d1f Mon Sep 17 00:00:00 2001 From: Jan Philipp Ecker Date: Sat, 26 Jul 2025 22:50:08 +0200 Subject: [PATCH 4/5] Adds ENABLE_HEAP_DEBUGGING define as comment to the build flags Adds the new ENABLE_HEAP_DEBUGGING define to the build falgs. The option is commented out, but it makes it easier to quickly enable it --- platformio.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/platformio.ini b/platformio.ini index dc7cd21..c1ba693 100644 --- a/platformio.ini +++ b/platformio.ini @@ -52,6 +52,7 @@ build_flags = -mtext-section-literals -DVERSION=\"${common.version}\" -DTOOLDVERSION=\"${common.to_old_version}\" + #-DENABLE_HEAP_DEBUGGING -DASYNCWEBSERVER_REGEX #-DCORE_DEBUG_LEVEL=3 -DCONFIG_ARDUHAL_LOG_COLORS=1 From b991f2ee2722754c9faf46cdc1ac28f58d2a5d84 Mon Sep 17 00:00:00 2001 From: Jan Philipp Ecker Date: Sat, 26 Jul 2025 22:52:10 +0200 Subject: [PATCH 5/5] Fixes compiler warnings in nfc Replaces the depricated function call containsKey() with is() of JsonDocument. --- src/nfc.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/nfc.cpp b/src/nfc.cpp index 47dbab4..1003835 100644 --- a/src/nfc.cpp +++ b/src/nfc.cpp @@ -221,13 +221,13 @@ bool decodeNdefAndReturnJson(const byte* encodedMessage) { // Sende die aktualisierten AMS-Daten an alle WebSocket-Clients Serial.println("JSON-Dokument erfolgreich verarbeitet"); Serial.println(doc.as()); - if (doc.containsKey("sm_id") && doc["sm_id"] != "") + if (doc["sm_id"].is() && doc["sm_id"] != "") { Serial.println("SPOOL-ID gefunden: " + doc["sm_id"].as()); activeSpoolId = doc["sm_id"].as(); lastSpoolId = activeSpoolId; } - else if(doc.containsKey("location") && doc["location"] != "") + else if(doc["location"].is() && doc["location"] != "") { Serial.println("Location Tag found!"); String location = doc["location"].as();