Implement memory monitoring and queue size reporting in MQTTBridge and CommonCLI
- Added `getQueueSize` method to `MyMesh` and `CommonCLI` for better queue management. - Introduced memory logging functionality in `MQTTBridge` to monitor heap usage and detect potential memory leaks. - Adjusted maximum queue size in `MQTTBridge` from 50 to 10 for improved resource management. - Enhanced command handling in `CommonCLI` to report memory status upon request.
This commit is contained in:
1 parent
1219668fb1
commit
2b0475998a
5 files changed
+111
-24
No files matched your search
@@ -314,6 +314,10 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
|
||||
} else {
|
||||
strcpy(reply, "ERR: clock cannot go backwards");
|
||||
}
|
||||
} else if (memcmp(command, "memory", 6) == 0) {
|
||||
sprintf(reply, "Free: %d, Min: %d, Max: %d, Queue: %d",
|
||||
ESP.getFreeHeap(), ESP.getMinFreeHeap(), ESP.getMaxAllocHeap(),
|
||||
_callbacks->getQueueSize());
|
||||
} else if (memcmp(command, "start ota", 9) == 0) {
|
||||
if (!_board->startOTAUpdate(_prefs->node_name, reply)) {
|
||||
strcpy(reply, "Error");
|
||||
|
||||
@@ -315,6 +315,39 @@ void MQTTBridge::loop() {
|
||||
publishStatus();
|
||||
_last_status_publish = millis();
|
||||
}
|
||||
|
||||
// Memory monitoring (every 5 minutes)
|
||||
static unsigned long last_memory_log = 0;
|
||||
if (millis() - last_memory_log > 300000) { // 5 minutes
|
||||
logMemoryStatus();
|
||||
last_memory_log = millis();
|
||||
}
|
||||
|
||||
// Critical memory check (every 15 minutes)
|
||||
static unsigned long last_critical_check = 0;
|
||||
if (millis() - last_critical_check > 900000) { // 15 minutes
|
||||
if (ESP.getMaxAllocHeap() < 60000) { // Less than 60KB max alloc
|
||||
MQTT_DEBUG_PRINTLN("WARNING: Max alloc heap below 60KB - potential memory leak detected!");
|
||||
MQTT_DEBUG_PRINTLN("Free: %d, Min: %d, Max: %d", ESP.getFreeHeap(), ESP.getMinFreeHeap(), ESP.getMaxAllocHeap());
|
||||
|
||||
// Attempt memory defragmentation by forcing garbage collection
|
||||
MQTT_DEBUG_PRINTLN("Attempting memory defragmentation...");
|
||||
// Force a small allocation and immediate free to trigger defrag
|
||||
void* temp = malloc(1024);
|
||||
if (temp) {
|
||||
free(temp);
|
||||
MQTT_DEBUG_PRINTLN("Defragmentation complete. New Max Alloc: %d", ESP.getMaxAllocHeap());
|
||||
}
|
||||
}
|
||||
|
||||
// Critical threshold check
|
||||
if (ESP.getMaxAllocHeap() < 40000) { // Less than 40KB max alloc
|
||||
MQTT_DEBUG_PRINTLN("CRITICAL: Max alloc heap below 40KB - severe memory leak!");
|
||||
MQTT_DEBUG_PRINTLN("Free: %d, Min: %d, Max: %d", ESP.getFreeHeap(), ESP.getMinFreeHeap(), ESP.getMaxAllocHeap());
|
||||
}
|
||||
|
||||
last_critical_check = millis();
|
||||
}
|
||||
}
|
||||
|
||||
void MQTTBridge::onPacketReceived(mesh::Packet *packet) {
|
||||
@@ -459,6 +492,12 @@ void MQTTBridge::processPacketQueue() {
|
||||
publishRaw(queued.packet);
|
||||
}
|
||||
|
||||
// Free packet memory before removing from queue
|
||||
if (queued.packet) {
|
||||
_mgr->free(queued.packet);
|
||||
queued.packet = nullptr;
|
||||
}
|
||||
|
||||
// Remove from queue
|
||||
dequeuePacket();
|
||||
processed++;
|
||||
@@ -533,7 +572,7 @@ void MQTTBridge::publishStatus() {
|
||||
void MQTTBridge::publishPacket(mesh::Packet* packet, bool is_tx) {
|
||||
if (!packet) return;
|
||||
|
||||
char json_buffer[1024];
|
||||
char json_buffer[512];
|
||||
char origin_id[65];
|
||||
|
||||
// Use actual device ID
|
||||
@@ -1057,26 +1096,41 @@ void MQTTBridge::syncTimeWithNTP() {
|
||||
|
||||
MQTT_DEBUG_PRINTLN("Time synced: %lu", epochTime);
|
||||
|
||||
// Set timezone from string (with DST support)
|
||||
MQTT_DEBUG_PRINTLN("Setting timezone: %s", _prefs->timezone_string);
|
||||
|
||||
// Clean up old timezone object to prevent memory leak
|
||||
if (_timezone) {
|
||||
delete _timezone;
|
||||
_timezone = nullptr;
|
||||
}
|
||||
|
||||
// Create timezone object based on timezone string
|
||||
Timezone* tz = createTimezoneFromString(_prefs->timezone_string);
|
||||
if (tz) {
|
||||
MQTT_DEBUG_PRINTLN("Timezone created successfully");
|
||||
// Store timezone for later use in message building
|
||||
_timezone = tz;
|
||||
} else {
|
||||
MQTT_DEBUG_PRINTLN("Failed to create timezone, using UTC");
|
||||
// Create UTC timezone as fallback
|
||||
TimeChangeRule utc = {"UTC", Last, Sun, Mar, 0, 0};
|
||||
_timezone = new Timezone(utc, utc);
|
||||
// Set timezone from string (with DST support) - only if changed
|
||||
static char last_timezone[64] = "";
|
||||
if (strcmp(_prefs->timezone_string, last_timezone) != 0) {
|
||||
MQTT_DEBUG_PRINTLN("Setting timezone: %s", _prefs->timezone_string);
|
||||
|
||||
// Clean up old timezone object to prevent memory leak
|
||||
if (_timezone) {
|
||||
delete _timezone;
|
||||
_timezone = nullptr;
|
||||
}
|
||||
|
||||
// Create timezone object based on timezone string
|
||||
Timezone* tz = createTimezoneFromString(_prefs->timezone_string);
|
||||
if (tz) {
|
||||
MQTT_DEBUG_PRINTLN("Timezone created successfully");
|
||||
// Store timezone for later use in message building
|
||||
_timezone = tz;
|
||||
} else {
|
||||
MQTT_DEBUG_PRINTLN("Failed to create timezone, using UTC");
|
||||
// Create UTC timezone as fallback
|
||||
TimeChangeRule utc = {"UTC", Last, Sun, Mar, 0, 0};
|
||||
_timezone = new Timezone(utc, utc);
|
||||
}
|
||||
|
||||
// Remember this timezone string
|
||||
strncpy(last_timezone, _prefs->timezone_string, sizeof(last_timezone) - 1);
|
||||
last_timezone[sizeof(last_timezone) - 1] = '\0';
|
||||
|
||||
// Force memory defragmentation after timezone recreation
|
||||
MQTT_DEBUG_PRINTLN("Forcing memory defragmentation after timezone change");
|
||||
void* temp = malloc(1024);
|
||||
if (temp) {
|
||||
free(temp);
|
||||
MQTT_DEBUG_PRINTLN("Defragmentation complete. Max Alloc: %d", ESP.getMaxAllocHeap());
|
||||
}
|
||||
}
|
||||
|
||||
// Show current time in both UTC and local
|
||||
@@ -1227,4 +1281,15 @@ Timezone* MQTTBridge::createTimezoneFromString(const char* tz_string) {
|
||||
}
|
||||
}
|
||||
|
||||
void MQTTBridge::logMemoryStatus() {
|
||||
MQTT_DEBUG_PRINTLN("=== Memory Status ===");
|
||||
MQTT_DEBUG_PRINTLN("Free heap: %d bytes", ESP.getFreeHeap());
|
||||
MQTT_DEBUG_PRINTLN("Min free heap: %d bytes", ESP.getMinFreeHeap());
|
||||
MQTT_DEBUG_PRINTLN("Max alloc heap: %d bytes", ESP.getMaxAllocHeap());
|
||||
MQTT_DEBUG_PRINTLN("Heap size: %d bytes", ESP.getHeapSize());
|
||||
MQTT_DEBUG_PRINTLN("Free PSRAM: %d bytes", ESP.getFreePsram());
|
||||
MQTT_DEBUG_PRINTLN("Queue size: %d/%d packets", _queue_count, MAX_QUEUE_SIZE);
|
||||
MQTT_DEBUG_PRINTLN("===================");
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -86,7 +86,7 @@ private:
|
||||
bool is_tx;
|
||||
};
|
||||
|
||||
static const int MAX_QUEUE_SIZE = 50;
|
||||
static const int MAX_QUEUE_SIZE = 10;
|
||||
QueuedPacket _packet_queue[MAX_QUEUE_SIZE];
|
||||
int _queue_head;
|
||||
int _queue_tail;
|
||||
@@ -111,8 +111,8 @@ private:
|
||||
// Let's Mesh Analyzer support
|
||||
bool _analyzer_us_enabled;
|
||||
bool _analyzer_eu_enabled;
|
||||
char _auth_token_us[1024]; // JWT token for US server authentication
|
||||
char _auth_token_eu[1024]; // JWT token for EU server authentication
|
||||
char _auth_token_us[512]; // JWT token for US server authentication
|
||||
char _auth_token_eu[512]; // JWT token for EU server authentication
|
||||
char _analyzer_username[70]; // Username in format v1_{UPPERCASE_PUBLIC_KEY}
|
||||
|
||||
// Device identity for JWT token creation
|
||||
@@ -312,6 +312,12 @@ public:
|
||||
* @return Number of queued packets
|
||||
*/
|
||||
int getQueueSize() const;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Log memory status for debugging
|
||||
*/
|
||||
void logMemoryStatus();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -51,6 +51,9 @@ build_flags =
|
||||
build_src_filter = ${Heltec_lora32_v3.build_src_filter}
|
||||
+<helpers/ui/SSD1306Display.cpp>
|
||||
+<../examples/simple_repeater>
|
||||
-<helpers/bridges/MQTTBridge.cpp>
|
||||
-<helpers/MQTTMessageBuilder.cpp>
|
||||
-<helpers/JWTHelper.cpp>
|
||||
lib_deps =
|
||||
${Heltec_lora32_v3.lib_deps}
|
||||
${esp32_ota.lib_deps}
|
||||
@@ -275,6 +278,9 @@ build_flags =
|
||||
; -D MESH_DEBUG=1
|
||||
build_src_filter = ${Heltec_lora32_v3.build_src_filter}
|
||||
+<../examples/simple_repeater>
|
||||
-<helpers/bridges/MQTTBridge.cpp>
|
||||
-<helpers/MQTTMessageBuilder.cpp>
|
||||
-<helpers/JWTHelper.cpp>
|
||||
lib_deps =
|
||||
${Heltec_lora32_v3.lib_deps}
|
||||
${esp32_ota.lib_deps}
|
||||
|
||||
@@ -54,6 +54,9 @@ build_flags =
|
||||
; -D MESH_DEBUG=1
|
||||
build_src_filter = ${Station_G2.build_src_filter}
|
||||
+<../examples/simple_repeater>
|
||||
-<helpers/bridges/MQTTBridge.cpp>
|
||||
-<helpers/MQTTMessageBuilder.cpp>
|
||||
-<helpers/JWTHelper.cpp>
|
||||
lib_deps =
|
||||
${Station_G2.lib_deps}
|
||||
${esp32_ota.lib_deps}
|
||||
@@ -115,6 +118,9 @@ build_flags =
|
||||
; -D MESH_DEBUG=1
|
||||
build_src_filter = ${Station_G2.build_src_filter}
|
||||
+<../examples/simple_repeater>
|
||||
-<helpers/bridges/MQTTBridge.cpp>
|
||||
-<helpers/MQTTMessageBuilder.cpp>
|
||||
-<helpers/JWTHelper.cpp>
|
||||
lib_deps =
|
||||
${Station_G2.lib_deps}
|
||||
${esp32_ota.lib_deps}
|
||||
|
||||
Reference in new issue
Block a user