Repository navigation
api configuration
painlessMesh provides extensive configuration options to customize mesh behavior for your specific use case. These settings control network parameters, debug output, timing, and advanced features.
Initialize the mesh with basic parameters.
void mesh.init(String ssid, String password, Scheduler* userScheduler,
uint16_t port = 5555,
WiFiEventCallback connectCallback = NULL,
uint8_t channel = 1)Parameters:
-
ssid- Mesh network name (prefix for AP names) -
password- Network password for security -
userScheduler- Pointer to your task scheduler -
port- TCP port for mesh communication (default: 5555) -
connectCallback- Optional WiFi event callback -
channel- WiFi channel to use (1-13)
Example:
#define MESH_PREFIX "MyMeshNetwork"
#define MESH_PASSWORD "SecurePassword123"
#define MESH_PORT 5555
Scheduler userScheduler;
painlessMesh mesh;
void setup() {
mesh.init(MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT);
}void setup() {
// Custom channel and callback
mesh.init(MESH_PREFIX, MESH_PASSWORD, &userScheduler,
MESH_PORT, wifiEventCallback, 6);
// Additional configuration
mesh.setDebugMsgTypes(ERROR | STARTUP | CONNECTION);
mesh.setContainsRoot(true);
mesh.setAP("MyMesh", "password", 6, false, 4);
}
void wifiEventCallback(WiFiEvent_t event) {
switch(event) {
case SYSTEM_EVENT_AP_STACONNECTED:
Serial.println("Station connected to AP");
break;
case SYSTEM_EVENT_AP_STADISCONNECTED:
Serial.println("Station disconnected from AP");
break;
}
}Control which debug messages are printed to Serial.
void mesh.setDebugMsgTypes(uint16_t types)Message Types:
-
ERROR- Error messages only -
STARTUP- Initialization messages -
CONNECTION- Connection/disconnection events -
SYNC- Time synchronization messages -
COMMUNICATION- Message sending/receiving -
GENERAL- General information -
MSG_TYPES- Message type information -
REMOTE- Remote debugging messages
Examples:
// Only errors and startup messages
mesh.setDebugMsgTypes(ERROR | STARTUP);
// All messages (verbose debugging)
mesh.setDebugMsgTypes(ERROR | STARTUP | CONNECTION | SYNC |
COMMUNICATION | GENERAL | MSG_TYPES | REMOTE);
// No debug output (production)
mesh.setDebugMsgTypes(0);
// Custom combination for development
mesh.setDebugMsgTypes(ERROR | CONNECTION | COMMUNICATION);Set the logging level for more granular control.
void mesh.logLevel(painlessmesh::logger::LogLevel level)Log Levels:
-
ERROR_LEVEL- Errors only -
INFO_LEVEL- Informational messages -
DEBUG_LEVEL- Debug information -
VERBOSE_LEVEL- Verbose output
// Set to info level
mesh.logLevel(painlessmesh::logger::INFO_LEVEL);
// Enable verbose logging for troubleshooting
mesh.logLevel(painlessmesh::logger::VERBOSE_LEVEL);Configure whether this mesh contains a root node (bridge to external network).
void mesh.setContainsRoot(bool containsRoot = false)Parameters:
-
containsRoot- true if mesh has a bridge/root node
// Enable if you have a bridge node to WiFi/Internet
mesh.setContainsRoot(true);
// Disable for standalone mesh (default)
mesh.setContainsRoot(false);Set this node as the root node (bridge).
void mesh.setRoot(bool shouldRoot = true)Example - Bridge Node:
void setup() {
// Configure as bridge node
mesh.setContainsRoot(true);
mesh.setRoot(true);
// Connect to external WiFi
mesh.stationManual("HomeWiFi", "password");
mesh.init(MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT);
}Configure Access Point parameters.
void mesh.setAP(String ssid, String password = "",
uint8_t channel = 1, bool hidden = false,
uint8_t maxConnection = 4)Parameters:
-
ssid- AP network name -
password- AP password (empty for open network) -
channel- WiFi channel (1-13) -
hidden- Hide SSID from broadcast -
maxConnection- Maximum concurrent connections (1-4 on ESP8266, 1-10 on ESP32)
Examples:
// Open network on channel 6, max 8 connections
mesh.setAP("OpenMesh", "", 6, false, 8);
// Secure hidden network
mesh.setAP("SecretMesh", "secret123", 11, true, 2);
// High capacity mesh (ESP32 only)
mesh.setAP("LargeMesh", "password", 1, false, 10);Manually configure station mode connection (for bridge nodes).
void mesh.stationManual(String ssid, String password,
uint16_t port = 0, IPAddress remote_ip = IPAddress())Parameters:
-
ssid- External WiFi network name -
password- External WiFi password -
port- Port for external connection -
remote_ip- Specific IP to connect to
Example:
// Connect to home WiFi as bridge
mesh.stationManual("HomeWiFi", "wifipassword");
// Connect to specific server
mesh.stationManual("CorpWiFi", "password", 8080, IPAddress(192,168,1,100));Configure time synchronization interval.
void mesh.setNodeSyncTime(uint32_t time_us)Parameters:
-
time_us- Sync interval in microseconds
// Sync every 5 seconds (default)
mesh.setNodeSyncTime(5 * 1000000);
// More frequent sync for time-critical applications
mesh.setNodeSyncTime(1 * 1000000);
// Less frequent sync to reduce network traffic
mesh.setNodeSyncTime(30 * 1000000);Set node timeout for connection management.
void mesh.setNodeTimeout(uint32_t timeout_us)Parameters:
-
timeout_us- Timeout in microseconds
// 10 second timeout (default)
mesh.setNodeTimeout(10 * 1000000);
// Shorter timeout for fast networks
mesh.setNodeTimeout(5 * 1000000);
// Longer timeout for unreliable connections
mesh.setNodeTimeout(30 * 1000000);Tune how a node retries a failed TCP connection before falling back to a full WiFi reconnect.
void mesh.setTcpRetryConfig(const painlessmesh::tcp::TcpRetryConfig& config)
painlessmesh::tcp::TcpRetryConfig mesh.getTcpRetryConfig() constFields:
| Field | Default | Meaning |
|---|---|---|
maxRetries |
5 | TCP connect attempts after the first before giving up |
retryDelayMs |
1000 | Base delay between retries; scaled 1x, 2x, 4x, 8x, 8x |
stabilizationDelayMs |
500 | Wait after IP acquisition before the first attempt |
exhaustionReconnectDelayMs |
10000 | Wait before the WiFi reconnect that follows exhaustion |
failureBlockDurationMs |
60000 | How long a failed peer is skipped during AP selection |
The defaults reproduce the previous hardcoded behaviour exactly — a sketch that never calls this sees no change. With them, a node that cannot reach its parent spends 1 + 2 + 4 + 8 + 8 = 23 s retrying, waits another 10 s before reconnecting WiFi, and will not re-select that peer for 60 s.
Call this before mesh.init() so the first connection attempt already uses
it.
painlessmesh::tcp::TcpRetryConfig cfg; // starts at the defaults
cfg.maxRetries = 1;
cfg.retryDelayMs = 200;
cfg.exhaustionReconnectDelayMs = 1000;
mesh.setTcpRetryConfig(cfg);
mesh.init(MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT);Profiles:
| Real-time | Default | High-reliability | Battery | |
|---|---|---|---|---|
maxRetries |
1 | 5 | 10 | 2 |
retryDelayMs |
200 | 1000 | 2000 | 3000 |
stabilizationDelayMs |
100 | 500 | 1000 | 500 |
exhaustionReconnectDelayMs |
1000 | 10000 | 30000 | 60000 |
failureBlockDurationMs |
5000 | 60000 | 180000 | 300000 |
| worst-case retry time | 0.2 s | 23 s | 126 s | 9 s |
See examples/tcpRetryConfig/ for a runnable sketch with all three.
Clamping:
Two values are coerced into safe bounds, because they can otherwise render a node unusable:
-
maxRetriesis capped at 10 — each retry allocates anAsyncClientand schedules a task, so an unbounded value is a heap and recursion-depth hazard on ESP8266. -
retryDelayMsis held between 50 ms and 60000 ms — a zero delay would schedule retries with no spacing (a hot loop allocating anAsyncClientper scheduler tick); the ceiling keepsretryDelayMs * 8clear ofuint32_toverflow.
Everything else passes through untouched, including zeros, which are meaningful:
maxRetries = 0 means "do not retry at all", stabilizationDelayMs = 0 means
"connect immediately on IP acquisition", exhaustionReconnectDelayMs = 0 means
"reconnect WiFi immediately", and failureBlockDurationMs = 0 means "never
blocklist a failed peer". Use getTcpRetryConfig() to read back what actually
took effect.
Warning
These production defaults protect against connection churn, rapid reconnect
loops, and network congestion. Tuning them down can destabilize a busy mesh.
In particular, keep failureBlockDurationMs greater than
(sum of retry backoffs) + exhaustionReconnectDelayMs, or a dead peer will
leave the blocklist before the node has finished failing over and be
re-selected immediately.
Register custom package types for type-safe messaging.
template<typename T>
void mesh.registerPackage()Example:
// Register custom package types
mesh.registerPackage<SensorPackage>();
mesh.registerPackage<CommandPackage>();
mesh.registerPackage<StatusPackage>();Configure message size and queue limits.
// Set maximum message size (bytes)
mesh.setMaxMessageSize(1024);
// Set message queue size
mesh.setMessageQueueSize(50);
// Set retry attempts for failed messages
mesh.setRetryAttempts(3);Configure connection behavior for different scenarios.
void setup() {
// High-density network (more connections)
mesh.setAP("DenseMesh", "password", 1, false, 10); // ESP32 only
mesh.setNodeTimeout(5 * 1000000); // Faster timeout
mesh.setNodeSyncTime(1 * 1000000); // Frequent sync
// Low-power network (fewer connections, longer intervals)
mesh.setAP("PowerMesh", "password", 1, false, 2);
mesh.setNodeTimeout(60 * 1000000); // Longer timeout
mesh.setNodeSyncTime(30 * 1000000); // Less frequent sync
}Configure memory usage for resource-constrained devices.
void setup() {
// Reduce memory usage on ESP8266
mesh.setMaxMessageSize(512); // Smaller messages
mesh.setMessageQueueSize(20); // Smaller queue
mesh.setAP("LiteMesh", "pass", 1, false, 2); // Fewer connections
// ESP32 can handle larger configurations
mesh.setMaxMessageSize(2048); // Larger messages
mesh.setMessageQueueSize(100); // Larger queue
mesh.setAP("FullMesh", "pass", 1, false, 8); // More connections
}Configure mesh security settings.
void setup() {
// Strong password for mesh security
String strongPassword = "VerySecurePassword2023!";
mesh.init(MESH_PREFIX, strongPassword, &userScheduler, MESH_PORT);
// Hidden network for additional security
mesh.setAP("SecureMesh", strongPassword, 6, true, 4);
}Implement node authentication and authorization.
bool authorizedNodes[] = {123456789, 987654321, 555444333};
mesh.onReceive([](uint32_t from, String& msg) {
// Check if node is authorized
bool authorized = false;
for (uint32_t nodeId : authorizedNodes) {
if (from == nodeId) {
authorized = true;
break;
}
}
if (!authorized) {
Serial.printf("Unauthorized message from node %u\n", from);
return;
}
// Process authorized message
processMessage(from, msg);
});Optimized for indoor use with good WiFi coverage.
void configureIndoor() {
mesh.setAP("IndoorMesh", "password", 6, false, 6);
mesh.setNodeTimeout(10 * 1000000); // 10 second timeout
mesh.setNodeSyncTime(5 * 1000000); // 5 second sync
mesh.setDebugMsgTypes(ERROR | CONNECTION);
}Configured for outdoor use with potentially unreliable connections.
void configureOutdoor() {
mesh.setAP("OutdoorMesh", "password", 1, false, 4);
mesh.setNodeTimeout(30 * 1000000); // 30 second timeout
mesh.setNodeSyncTime(15 * 1000000); // 15 second sync
mesh.setRetryAttempts(5); // More retries
mesh.setDebugMsgTypes(ERROR | CONNECTION | SYNC);
}Heavy-duty configuration for industrial applications.
void configureIndustrial() {
mesh.setAP("IndustrialMesh", "SecureIndustrial2023", 11, true, 8);
mesh.setNodeTimeout(60 * 1000000); // 60 second timeout
mesh.setNodeSyncTime(10 * 1000000); // 10 second sync
mesh.setMaxMessageSize(2048); // Larger messages
mesh.setRetryAttempts(3);
mesh.setDebugMsgTypes(ERROR | STARTUP);
}Optimized for battery-powered devices.
void configureLowPower() {
mesh.setAP("PowerMesh", "password", 1, false, 2);
mesh.setNodeTimeout(120 * 1000000); // 2 minute timeout
mesh.setNodeSyncTime(60 * 1000000); // 1 minute sync
mesh.setMaxMessageSize(256); // Small messages
mesh.setMessageQueueSize(10); // Small queue
mesh.setDebugMsgTypes(ERROR); // Minimal logging
}Modify configuration during runtime based on conditions.
void adaptiveConfiguration() {
int networkSize = mesh.getNodeList().size() + 1;
int freeHeap = ESP.getFreeHeap();
// Adjust based on network size
if (networkSize > 10) {
mesh.setNodeSyncTime(15 * 1000000); // Reduce sync frequency
mesh.setMaxMessageSize(512); // Smaller messages
} else {
mesh.setNodeSyncTime(5 * 1000000); // Normal sync
mesh.setMaxMessageSize(1024); // Normal messages
}
// Adjust based on available memory
if (freeHeap < 50000) {
mesh.setMessageQueueSize(10); // Reduce queue
mesh.setDebugMsgTypes(ERROR); // Minimal debug
} else {
mesh.setMessageQueueSize(50); // Normal queue
mesh.setDebugMsgTypes(ERROR | CONNECTION);
}
}
// Call periodically to adjust configuration
Task adaptiveTask(60000, TASK_FOREVER, adaptiveConfiguration);Switch between predefined configuration profiles.
enum ConfigProfile { DEVELOPMENT, PRODUCTION, LOW_POWER, HIGH_PERFORMANCE };
void applyConfigProfile(ConfigProfile profile) {
switch(profile) {
case DEVELOPMENT:
mesh.setDebugMsgTypes(ERROR | STARTUP | CONNECTION | COMMUNICATION);
mesh.setNodeTimeout(5 * 1000000);
mesh.setNodeSyncTime(1 * 1000000);
break;
case PRODUCTION:
mesh.setDebugMsgTypes(ERROR);
mesh.setNodeTimeout(30 * 1000000);
mesh.setNodeSyncTime(10 * 1000000);
break;
case LOW_POWER:
configureLowPower();
break;
case HIGH_PERFORMANCE:
mesh.setAP("FastMesh", "password", 1, false, 10);
mesh.setNodeTimeout(5 * 1000000);
mesh.setNodeSyncTime(1 * 1000000);
mesh.setMaxMessageSize(2048);
break;
}
}Check configuration validity and system capabilities.
bool validateConfiguration() {
// Check memory availability
if (ESP.getFreeHeap() < 30000) {
Serial.println("WARNING: Low memory for current configuration");
return false;
}
// Validate node timeout vs sync time
uint32_t timeout = mesh.getNodeTimeout();
uint32_t syncTime = mesh.getNodeSyncTime();
if (timeout < syncTime * 2) {
Serial.println("WARNING: Node timeout too short relative to sync time");
return false;
}
// Check connection limits for platform
#ifdef ESP8266
if (mesh.getMaxConnections() > 4) {
Serial.println("WARNING: ESP8266 supports max 4 connections");
return false;
}
#endif
return true;
}See also:
- Core API - Complete method reference
- Callbacks - Event handling
- Performance Tuning - Optimization guidelines