Stopping and restartig mesh memory leak
I have a functioning and stable mesh network of 9 D1 Mini devices. Two of my devices are battery powered so I want to stop the mesh and turn off the wifi when I don't need to send anything.
The issue After calling mesh.stop(), then mesh.init(...), the node leaks memory until eventually it will reset, or simply just sit doing nothing (does not reconnect).
Reproducing the issue The startHere sketch has been modified to reproduce this behaviour
//************************************************************
// this is a simple example that uses the easyMesh library
//
// 1. blinks led once for every node on the mesh
// 2. blink cycle repeats every BLINK_PERIOD
// 3. sends a silly message to every node on the mesh at a random time between 1 and 5 seconds
// 4. prints anything it receives to Serial.print
//
//
//************************************************************
#include <painlessMesh.h>
// some gpio pin that is connected to an LED...
// on my rig, this is 5, change to the right number of your LED.
#define LED 2 // GPIO number of connected LED, ON ESP-12 IS GPIO2
#define BLINK_PERIOD 3000 // milliseconds until cycle repeat
#define BLINK_DURATION 100 // milliseconds LED is on for
#define MESH_SSID "bbmesh"
#define MESH_PASSWORD "supperSecret"
#define MESH_PORT 5555
// Prototypes
void sendMessage();
void receivedCallback(uint32_t from, String & msg);
void newConnectionCallback(uint32_t nodeId);
void changedConnectionCallback();
void nodeTimeAdjustedCallback(int32_t offset);
void delayReceivedCallback(uint32_t from, int32_t delay);
Scheduler userScheduler; // to control your personal task
painlessMesh mesh;
bool calc_delay = false;
SimpleList<uint32_t> nodes;
void sendMessage() ; // Prototype
Task taskSendMessage( TASK_SECOND * 1, TASK_FOREVER, &sendMessage ); // start with a one second interval
// Task to blink the number of nodes
Task blinkNoNodes;
void stopMesh(); //FD
Task task_stopMesh(1*TASK_MINUTE,TASK_FOREVER,&stopMesh);
boolean meshUp = false;
uint32_t delayUp = 0;
bool onFlag = false;
uint32_t t1=0;
uint64_t st1=0;
uint32_t ct1=0;
void setup() {
Serial.begin(115200);
pinMode(LED, OUTPUT);
mesh.setDebugMsgTypes(ERROR | DEBUG); // set before init() so that you can see error messages
//mesh.init(MESH_SSID, MESH_PASSWORD, &userScheduler, MESH_PORT);
startMesh();
mesh.onReceive(&receivedCallback);
mesh.onNewConnection(&newConnectionCallback);
mesh.onChangedConnections(&changedConnectionCallback);
mesh.onNodeTimeAdjusted(&nodeTimeAdjustedCallback);
mesh.onNodeDelayReceived(&delayReceivedCallback);
userScheduler.addTask( taskSendMessage );
taskSendMessage.enable();
userScheduler.addTask(task_stopMesh);
task_stopMesh.enableDelayed(5*TASK_MINUTE); // allow baseline mem
blinkNoNodes.set(BLINK_PERIOD, (mesh.getNodeList().size() + 1) * 2, []() {
// If on, switch off, else switch on
if (onFlag)
onFlag = false;
else
onFlag = true;
blinkNoNodes.delay(BLINK_DURATION);
if (blinkNoNodes.isLastIteration()) {
// Finished blinking. Reset task for next run
// blink number of nodes (including this node) times
blinkNoNodes.setIterations((mesh.getNodeList().size() + 1) * 2);
// Calculate delay based on current mesh time and BLINK_PERIOD
// This results in blinks between nodes being synced
blinkNoNodes.enableDelayed(BLINK_PERIOD -
(mesh.getNodeTime() % (BLINK_PERIOD*1000))/1000);
}
});
userScheduler.addTask(blinkNoNodes);
blinkNoNodes.enable();
randomSeed(analogRead(A0));
}
void loop() {
t1=micros();
if (!meshUp && millis() > delayUp)
startMesh();
mesh.update();
digitalWrite(LED, !onFlag);
st1 += micros()-t1; ct1++;
if (ct1 % 50000 == 0)
{
Serial.printf("Average loop duration: %1.3fus\nHeap %u, MaxFree %u, Frag %u%%, Uptime %1.3fh\n",
st1/(ct1*1.0),ESP.getFreeHeap(),ESP.getMaxFreeBlockSize(),
ESP.getHeapFragmentation(),millis()/3600000.0);
st1=0; ct1=0;
}
}
void startMesh()
{
Serial.println("Starting mesh");
mesh.init(MESH_SSID, MESH_PASSWORD, &userScheduler, MESH_PORT);
meshUp = true;
}
void stopMesh()
{
Serial.println("Stopping mesh");
mesh.stop();
meshUp = false;
delayUp = millis() + 30000; // keep stopped for 30s
}
void sendMessage() {
if (!meshUp) return;
String msg = "Hello from node ";
msg += mesh.getNodeId();
msg += " myFreeMemory: " + String(ESP.getFreeHeap());
mesh.sendBroadcast(msg);
if (calc_delay) {
SimpleList<uint32_t>::iterator node = nodes.begin();
while (node != nodes.end()) {
mesh.startDelayMeas(*node);
node++;
}
calc_delay = false;
}
Serial.printf("Sending message: %s\n", msg.c_str());
taskSendMessage.setInterval( random(TASK_SECOND * 1, TASK_SECOND * 5)); // between 1 and 5 seconds
}
void receivedCallback(uint32_t from, String & msg) {
Serial.printf("startHere: Received from %u msg=%s\n", from, msg.c_str());
}
void newConnectionCallback(uint32_t nodeId) {
// Reset blink task
onFlag = false;
blinkNoNodes.setIterations((mesh.getNodeList().size() + 1) * 2);
blinkNoNodes.enableDelayed(BLINK_PERIOD - (mesh.getNodeTime() % (BLINK_PERIOD*1000))/1000);
Serial.printf("--> startHere: New Connection, nodeId = %u\n", nodeId);
Serial.printf("--> startHere: New Connection, %s\n", mesh.subConnectionJson(true).c_str());
}
void changedConnectionCallback() {
Serial.printf("Changed connections\n");
// Reset blink task
onFlag = false;
blinkNoNodes.setIterations((mesh.getNodeList().size() + 1) * 2);
blinkNoNodes.enableDelayed(BLINK_PERIOD - (mesh.getNodeTime() % (BLINK_PERIOD*1000))/1000);
nodes = mesh.getNodeList();
Serial.printf("Num nodes: %d\n", nodes.size());
Serial.printf("Connection list:");
SimpleList<uint32_t>::iterator node = nodes.begin();
while (node != nodes.end()) {
Serial.printf(" %u", *node);
node++;
}
Serial.println();
calc_delay = true;
}
void nodeTimeAdjustedCallback(int32_t offset) {
Serial.printf("Adjusted time %u. Offset = %d\n", mesh.getNodeTime(), offset);
}
void delayReceivedCallback(uint32_t from, int32_t delay) {
Serial.printf("Delay to node %u is %d us\n", from, delay);
}
The code runs for 5 minutes without stopping and starting to get a baseline. After 5 minutes it repeated stops and starts every 30s.
The attached graph shows the memory leakage.