Debugging - Alteriom/painlessMesh GitHub Wiki
Debugging Guide
This guide provides tools and techniques for debugging painlessMesh applications.
Debug Message Types
painlessMesh includes a built-in debugging system that lets you control which types of messages are logged.
Setting Debug Message Types
#include "painlessMesh.h"
painlessMesh mesh;
void setup() {
Serial.begin(115200);
// Set which message types to display
mesh.setDebugMsgTypes(ERROR | STARTUP | CONNECTION);
// Initialize mesh
mesh.init(MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT);
}
Available Debug Message Types
| Type | Description |
|---|---|
ERROR |
Critical errors and failures |
STARTUP |
Initialization and startup messages |
CONNECTION |
Connection and disconnection events |
SYNC |
Time synchronization messages |
COMMUNICATION |
Message sending/receiving |
GENERAL |
General informational messages |
MSG_TYPES |
Message type information |
REMOTE |
Remote node messages |
APPLICATION |
Application-level messages |
DEBUG |
Detailed debugging information |
Common Debug Configurations
Minimal (Production):
mesh.setDebugMsgTypes(ERROR | STARTUP);
Standard (Development):
mesh.setDebugMsgTypes(ERROR | STARTUP | CONNECTION);
Verbose (Troubleshooting):
mesh.setDebugMsgTypes(ERROR | STARTUP | CONNECTION | SYNC | COMMUNICATION);
Full Debug (Deep Dive):
mesh.setDebugMsgTypes(ERROR | STARTUP | CONNECTION | SYNC |
COMMUNICATION | GENERAL | MSG_TYPES |
REMOTE | APPLICATION | DEBUG);
Common Debugging Scenarios
1. Nodes Not Connecting
Symptoms:
- Nodes don't appear in
mesh.getNodeList() onNewConnectioncallback never fires- Mesh appears to run but no communication
Debugging Steps:
// Enable connection debugging
mesh.setDebugMsgTypes(ERROR | STARTUP | CONNECTION | SYNC);
void setup() {
Serial.begin(115200);
// Add connection callbacks
mesh.onNewConnection([](uint32_t nodeId) {
Serial.printf("New connection: %u\n", nodeId);
Serial.printf("Total nodes: %d\n", mesh.getNodeList().size());
});
mesh.onChangedConnections([]() {
Serial.printf("Connections changed. Current nodes: %d\n",
mesh.getNodeList().size());
auto nodes = mesh.getNodeList();
for (auto node : nodes) {
Serial.printf(" - Node: %u\n", node);
}
});
mesh.onDroppedConnection([](uint32_t nodeId) {
Serial.printf("Lost connection: %u\n", nodeId);
});
}
Common Causes:
- Mismatched
MESH_PREFIXorMESH_PASSWORD - Different
MESH_PORTvalues - Wi-Fi channel conflicts
- Power supply issues (voltage drops during connection)
- Too many nodes (exceeds platform limits)
2. Messages Not Received
Symptoms:
mesh.sendBroadcast()ormesh.sendSingle()returns true but messages not receivedonReceivecallback never fires
Debugging Steps:
// Enable communication debugging
mesh.setDebugMsgTypes(ERROR | COMMUNICATION | MSG_TYPES);
void setup() {
Serial.begin(115200);
mesh.onReceive([](uint32_t from, String& msg) {
Serial.printf("Received from %u: %s\n", from, msg.c_str());
});
// Add send status checking
if (mesh.sendBroadcast(msg)) {
Serial.println("Broadcast sent successfully");
} else {
Serial.println("ERROR: Broadcast failed to send");
}
}
Common Causes:
- Message buffer overflow (message too large)
- Network congestion (too many messages)
- JSON parsing errors (malformed messages)
- Node ID mismatch for
sendSingle() - Memory constraints on receiving node
3. Time Synchronization Issues
Symptoms:
mesh.getNodeTime()returns unexpected values- Time-dependent features not working
onNodeTimeAdjustedfires frequently
Debugging Steps:
// Enable time sync debugging
mesh.setDebugMsgTypes(ERROR | SYNC);
void setup() {
Serial.begin(115200);
mesh.onNodeTimeAdjusted([](int32_t offset) {
Serial.printf("Time adjusted by: %d microseconds\n", offset);
Serial.printf("Current mesh time: %u\n", mesh.getNodeTime());
});
// Periodically check time
Task checkTime(TASK_SECOND * 10, TASK_FOREVER, []() {
Serial.printf("Mesh time: %u, System: %u\n",
mesh.getNodeTime(), micros());
});
userScheduler.addTask(checkTime);
checkTime.enable();
}
4. Memory Issues
Symptoms:
- Random crashes or reboots
- Mesh stops responding
heap_caps_check_integrityfailures on ESP32
Debugging Steps:
void setup() {
Serial.begin(115200);
// Monitor free memory
Task memoryCheck(TASK_SECOND * 5, TASK_FOREVER, []() {
Serial.printf("Free heap: %u bytes\n", ESP.getFreeHeap());
#ifdef ESP32
Serial.printf("Free PSRAM: %u bytes\n", ESP.getFreePsram());
Serial.printf("Largest free block: %u bytes\n",
heap_caps_get_largest_free_block(MALLOC_CAP_8BIT));
#endif
});
userScheduler.addTask(memoryCheck);
memoryCheck.enable();
}
Memory Optimization Tips:
- Use
Stringsparingly, preferconst char* - Limit broadcast message frequency
- Reduce node count for ESP8266
- Clear unused tasks from scheduler
- Use
F()macro for string literals
5. OTA Update Failures
Symptoms:
- OTA updates don't start
- Updates fail partway through
- Nodes become unresponsive during update
Debugging Steps:
// Enable OTA debugging
mesh.setDebugMsgTypes(ERROR | STARTUP | COMMUNICATION);
void setup() {
Serial.begin(115200);
// Add OTA callbacks if using broadcast OTA
mesh.onOTAProgress([](size_t progress, size_t total) {
Serial.printf("OTA Progress: %u/%u bytes (%.1f%%)\n",
progress, total, (progress * 100.0) / total);
});
mesh.onOTAComplete([]() {
Serial.println("OTA Update Complete - Rebooting...");
});
mesh.onOTAError([](int error) {
Serial.printf("OTA Error: %d\n", error);
});
}
Common Causes:
- Insufficient flash memory
- Power interruption during update
- Network instability
- Firmware size exceeds partition size
- Memory fragmentation
Debugging Tools
1. Serial Monitor
Arduino IDE:
- Tools → Serial Monitor
- Set baud rate to 115200
- Enable newline and carriage return
PlatformIO:
pio device monitor --baud 115200
Screen (Linux/Mac):
screen /dev/ttyUSB0 115200
2. Network Analyzer
Wireshark:
- Capture Wi-Fi traffic to see mesh packets
- Filter by ESP32/ESP8266 MAC addresses
- Analyze packet timing and retransmissions
3. Mesh Topology Visualization
For MQTT-enabled setups:
- Use MQTT Explorer to view mesh topology
- Monitor
alteriom/mesh/topologytopic - Visualize node connections and status
4. Remote Logging
Log Server Example:
// On one node, set up as log server
mesh.onReceive([](uint32_t from, String& msg) {
DynamicJsonDocument doc(1024);
deserializeJson(doc, msg);
if (doc["type"] == "log") {
Serial.printf("[%u] %s\n", from, doc["msg"].as<const char*>());
}
});
// On other nodes, send logs
void logToServer(const char* message) {
DynamicJsonDocument doc(256);
doc["type"] = "log";
doc["msg"] = message;
String msg;
serializeJson(doc, msg);
mesh.sendBroadcast(msg);
}
Performance Profiling
Measure Message Latency
uint32_t sendTime = 0;
void sendMessage() {
DynamicJsonDocument doc(256);
doc["type"] = "ping";
doc["timestamp"] = mesh.getNodeTime();
String msg;
serializeJson(doc, msg);
sendTime = millis();
mesh.sendBroadcast(msg);
}
void onMessageReceived(uint32_t from, String& msg) {
DynamicJsonDocument doc(256);
deserializeJson(doc, msg);
if (doc["type"] == "ping") {
uint32_t latency = millis() - sendTime;
Serial.printf("Ping latency: %u ms\n", latency);
}
}
Monitor Task Execution
void setup() {
// Enable TaskScheduler debugging
userScheduler.enableAll();
Task debugTask(TASK_SECOND * 10, TASK_FOREVER, []() {
Serial.printf("Active tasks: %d\n", userScheduler.size());
// List all tasks
for (auto task = userScheduler.getFirstTask();
task != nullptr;
task = task->getNext()) {
Serial.printf(" Task ID: %d, Enabled: %d\n",
task->getId(), task->isEnabled());
}
});
userScheduler.addTask(debugTask);
debugTask.enable();
}
Best Practices
- Start Minimal: Enable only ERROR and STARTUP for initial testing
- Add Incrementally: Add more debug types as needed
- Use Callbacks: Implement all mesh callbacks to catch events
- Monitor Memory: Regularly check free heap, especially on ESP8266
- Test Incrementally: Test with 2 nodes before scaling to larger networks
- Power Management: Ensure stable power supply during debugging
- Version Control: Use consistent firmware versions across all nodes
- Document Issues: Keep notes on error patterns and solutions
Advanced Debugging
Enable TaskScheduler Debug Mode
// Add to top of sketch BEFORE including headers
#define _TASK_DEBUG
#include <TaskScheduler.h>
#include "painlessMesh.h"
Enable ArduinoJson Debug
#define ARDUINOJSON_DEBUG 1
#include <ArduinoJson.h>
ESP32 Core Debug Level
In platformio.ini:
build_flags =
-DCORE_DEBUG_LEVEL=5 ; 0=None, 5=Verbose
Troubleshooting Checklist
- All nodes use same MESH_PREFIX, MESH_PASSWORD, MESH_PORT
- Serial baud rate set to 115200
- Debug messages enabled for relevant types
- Callbacks implemented (onReceive, onNewConnection, etc.)
- Free heap monitored (especially on ESP8266)
- Power supply stable (2A+ recommended)
- Firmware versions consistent across nodes
- JSON messages properly formatted
- Message sizes within limits (< 1KB recommended)
- Network not oversaturated (reasonable message frequency)
Getting Help
If you're still experiencing issues:
- Search Existing Issues: Check GitHub Issues
- Community Forum: Post on painlessMesh Discussions
- Include Details:
- Hardware (ESP32/ESP8266 model)
- Firmware version
- Number of nodes
- Debug output
- Minimal reproducible example
- Check Documentation:
See Also
- Common Issues - Known problems and solutions
- FAQ - Frequently asked questions
- Performance Optimization - Scaling best practices
- MQTT Bridge Commands - MQTT debugging