@alteriom/painlessmesh 1.9.9 → 1.9.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +33 -0
- package/README.md +2 -2
- package/docs/troubleshooting/common-issues.md +5 -4
- package/examples/bridge_failover/bridge_failover.ino +1 -1
- package/library.json +1 -1
- package/library.properties +1 -1
- package/package.json +2 -2
- package/src/AlteriomPainlessMesh.h +2 -2
- package/src/arduino/wifi.hpp +2 -2
- package/src/painlessMesh.h +2 -2
- package/src/painlessmesh/plugin.hpp +14 -2
package/CHANGELOG.md
CHANGED
|
@@ -19,6 +19,39 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
19
19
|
|
|
20
20
|
- TBD
|
|
21
21
|
|
|
22
|
+
## [1.9.10] - 2025-12-15
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
|
|
26
|
+
- **TCP Connection Retry Immediate Execution** - Fixed mesh connection failures where TCP retries executed immediately instead of with exponential backoff delays
|
|
27
|
+
- **Root Cause**: `PackageHandler::addTask()` was calling `task->enable()` instead of `task->enableDelayed()` for one-shot delayed tasks, causing immediate execution
|
|
28
|
+
- **Symptom**: Nodes unable to establish mesh connection - TCP error -14 (ERR_CONN) with all retry attempts happening immediately rather than with 1s, 2s, 4s, 8s, 8s delays
|
|
29
|
+
- **Solution**: Modified `PackageHandler::addTask()` to use `enableDelayed()` for `TASK_ONCE` tasks with intervals > 0
|
|
30
|
+
- Retry tasks now properly wait for their scheduled delays before executing
|
|
31
|
+
- Exponential backoff mechanism now works as designed (total ~23s before WiFi reconnection)
|
|
32
|
+
- Reduces network congestion from multiple simultaneously retrying nodes
|
|
33
|
+
- **Impact**: Enables successful mesh connection establishment with proper retry timing
|
|
34
|
+
- **Files Modified**:
|
|
35
|
+
- `src/painlessmesh/plugin.hpp` (lines 231, 239, 245-251)
|
|
36
|
+
- `docs/troubleshooting/common-issues.md` (lines 206-212)
|
|
37
|
+
- `test/catch/catch_delayed_task_execution.cpp` (new test file)
|
|
38
|
+
- `ISSUE_TCP_RETRY_FIX.md` (new documentation)
|
|
39
|
+
|
|
40
|
+
- **Hard Reset on Bridge Failover Election Winner** - Fixed ESP32 hard reset (Guru Meditation Error: Load access fault) when node becomes bridge after election
|
|
41
|
+
- **Root Cause**: The `bridgeRoleChangedCallback` signature used pass-by-value for the String parameter (`TSTRING reason`), causing temporary String object creation from const char* literals. On memory-constrained ESP32/ESP8266, this could trigger heap allocation failures and memory access faults
|
|
42
|
+
- **Symptom**: Device crashes with "Guru Meditation Error: Core 0 panic'ed (Load access fault)" immediately after logging "🎯 PROMOTED TO BRIDGE: Election winner - best router signal"
|
|
43
|
+
- **Solution**: Changed callback signature to use const reference (`const TSTRING& reason`) instead of pass-by-value
|
|
44
|
+
- Eliminates unnecessary String object copying and temporary creation
|
|
45
|
+
- Reduces memory pressure during callback invocation
|
|
46
|
+
- String literals are now directly bound to const references without heap allocation
|
|
47
|
+
- **Impact**: Eliminates hard resets during bridge promotion, allows stable failover operation
|
|
48
|
+
- **Breaking Change**: Users must update their callback function signatures from `void callback(bool, String)` to `void callback(bool, const String&)`
|
|
49
|
+
- **Files Modified**:
|
|
50
|
+
- `src/arduino/wifi.hpp` (lines 970, 2326)
|
|
51
|
+
- `examples/bridge_failover/bridge_failover.ino` (line 147)
|
|
52
|
+
- `README.md` (line 171)
|
|
53
|
+
- `USER_GUIDE.md` (line 731)
|
|
54
|
+
|
|
22
55
|
## [1.9.9] - 2025-12-14
|
|
23
56
|
|
|
24
57
|
### Fixed
|
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
<div align="center">
|
|
6
6
|
|
|
7
|
-
**Version 1.9.
|
|
7
|
+
**Version 1.9.10** - Latest release with critical bug fixes for TCP retry and bridge failover
|
|
8
8
|
|
|
9
9
|
[](https://github.com/Alteriom/painlessMesh/actions/workflows/ci.yml)
|
|
10
10
|
[](https://github.com/Alteriom/painlessMesh/actions/workflows/docs.yml)
|
|
@@ -168,7 +168,7 @@ mesh.setRouterCredentials(ROUTER_SSID, ROUTER_PASSWORD);
|
|
|
168
168
|
mesh.enableBridgeFailover(true);
|
|
169
169
|
mesh.onBridgeRoleChanged(&bridgeRoleCallback);
|
|
170
170
|
|
|
171
|
-
void bridgeRoleCallback(bool isBridge, String reason) {
|
|
171
|
+
void bridgeRoleCallback(bool isBridge, const String& reason) {
|
|
172
172
|
if (isBridge) {
|
|
173
173
|
Serial.printf("🎯 Promoted to bridge: %s\n", reason.c_str());
|
|
174
174
|
}
|
|
@@ -205,11 +205,12 @@ For Arduino IDE, install manually from: https://github.com/ESP32Async/AsyncTCP
|
|
|
205
205
|
|
|
206
206
|
#### 2. Built-in Retry Mechanism
|
|
207
207
|
painlessMesh now includes automatic TCP connection retry with the following behavior:
|
|
208
|
-
- Up to
|
|
209
|
-
-
|
|
210
|
-
-
|
|
208
|
+
- Up to 6 total connection attempts (initial + 5 retries)
|
|
209
|
+
- Exponential backoff delays between retries: 1s, 2s, 4s, 8s, 8s (total ~23s)
|
|
210
|
+
- 500ms stabilization delay after IP acquisition before first connection attempt
|
|
211
|
+
- Full WiFi reconnection with 10s delay only triggered after all retries are exhausted
|
|
211
212
|
|
|
212
|
-
This helps handle transient timing issues automatically.
|
|
213
|
+
This exponential backoff helps handle transient timing issues automatically while reducing network congestion from multiple retrying nodes.
|
|
213
214
|
|
|
214
215
|
#### 3. Check Node Resource Usage
|
|
215
216
|
Monitor memory and ensure nodes aren't overloaded:
|
|
@@ -144,7 +144,7 @@ void bridgeStatusCallback(uint32_t bridgeNodeId, bool hasInternet) {
|
|
|
144
144
|
}
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
-
void bridgeRoleCallback(bool isBridge, String reason) {
|
|
147
|
+
void bridgeRoleCallback(bool isBridge, const String& reason) {
|
|
148
148
|
if (isBridge) {
|
|
149
149
|
Serial.printf("🎯 PROMOTED TO BRIDGE: %s\n", reason.c_str());
|
|
150
150
|
Serial.println("This node is now the primary bridge!");
|
package/library.json
CHANGED
package/library.properties
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
name=Alteriom PainlessMesh
|
|
2
|
-
version=1.9.
|
|
2
|
+
version=1.9.10
|
|
3
3
|
author=Coopdis,Scotty Franzyshen,Edwin van Leeuwen,Germán Martín,Maximilian Schwarz,Doanh Doanh,Alteriom
|
|
4
4
|
maintainer=Alteriom
|
|
5
5
|
sentence=A painless way to setup a mesh with ESP8266 and ESP32 devices with Alteriom extensions
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alteriom/painlessmesh",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.10",
|
|
4
4
|
"description": "painlessMesh is a user-friendly library for creating mesh networks with ESP8266 and ESP32 devices. This Alteriom fork includes additional packages for sensor data (SensorPackage), device commands (CommandPackage), and status monitoring (StatusPackage). It handles routing and network management automatically, so you can focus on your application. The library uses JSON-based messaging and syncs time across all nodes, making it ideal for coordinated behaviour like synchronized light displays or sensor networks reporting to a central node.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"arduino",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@alteriom/mqtt-schema": "^0.8.0",
|
|
43
|
-
"@eslint/js": "^9.39.
|
|
43
|
+
"@eslint/js": "^9.39.2",
|
|
44
44
|
"ajv": "^8.17.1",
|
|
45
45
|
"ajv-formats": "^3.0.1",
|
|
46
46
|
"prettier": "^3.7.4"
|
|
@@ -29,10 +29,10 @@
|
|
|
29
29
|
/**
|
|
30
30
|
* @brief AlteriomPainlessMesh library version information
|
|
31
31
|
*/
|
|
32
|
-
#define ALTERIOM_PAINLESS_MESH_VERSION "1.9.
|
|
32
|
+
#define ALTERIOM_PAINLESS_MESH_VERSION "1.9.10"
|
|
33
33
|
#define ALTERIOM_PAINLESS_MESH_VERSION_MAJOR 1
|
|
34
34
|
#define ALTERIOM_PAINLESS_MESH_VERSION_MINOR 9
|
|
35
|
-
#define ALTERIOM_PAINLESS_MESH_VERSION_PATCH
|
|
35
|
+
#define ALTERIOM_PAINLESS_MESH_VERSION_PATCH 10
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
38
|
* @brief Library description and usage information
|
package/src/arduino/wifi.hpp
CHANGED
|
@@ -967,7 +967,7 @@ class Mesh : public painlessmesh::Mesh<Connection> {
|
|
|
967
967
|
* @param callback Function to call when role changes
|
|
968
968
|
*/
|
|
969
969
|
void onBridgeRoleChanged(
|
|
970
|
-
std::function<void(bool isBridge, TSTRING reason)> callback) {
|
|
970
|
+
std::function<void(bool isBridge, const TSTRING& reason)> callback) {
|
|
971
971
|
bridgeRoleChangedCallback = callback;
|
|
972
972
|
}
|
|
973
973
|
|
|
@@ -2323,7 +2323,7 @@ class Mesh : public painlessmesh::Mesh<Connection> {
|
|
|
2323
2323
|
ElectionState electionState = ELECTION_IDLE;
|
|
2324
2324
|
uint32_t electionDeadline = 0;
|
|
2325
2325
|
std::vector<BridgeCandidate> electionCandidates;
|
|
2326
|
-
std::function<void(bool isBridge, TSTRING reason)> bridgeRoleChangedCallback;
|
|
2326
|
+
std::function<void(bool isBridge, const TSTRING& reason)> bridgeRoleChangedCallback;
|
|
2327
2327
|
|
|
2328
2328
|
// Isolated bridge retry state and configuration
|
|
2329
2329
|
uint8_t _isolatedBridgeRetryAttempts = 0;
|
package/src/painlessMesh.h
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* @file painlessMesh.h
|
|
6
6
|
* @brief Main header file for Alteriom painlessMesh library
|
|
7
7
|
*
|
|
8
|
-
* @version 1.9.
|
|
9
|
-
* @date 2025-12-
|
|
8
|
+
* @version 1.9.10
|
|
9
|
+
* @date 2025-12-15
|
|
10
10
|
*
|
|
11
11
|
* painlessMesh is a user-friendly library for creating mesh networks with
|
|
12
12
|
* ESP8266 and ESP32 devices. This Alteriom fork includes additional packages
|
|
@@ -228,7 +228,13 @@ class PackageHandler : public layout::Layout<T> {
|
|
|
228
228
|
for (auto&& task : taskList) {
|
|
229
229
|
if (task.use_count() == 1 && !task->isEnabled()) {
|
|
230
230
|
task->set(aInterval, aIterations, aCallback, NULL, NULL);
|
|
231
|
-
|
|
231
|
+
// Use enableDelayed() for delayed one-shot tasks to prevent immediate execution
|
|
232
|
+
// This ensures tasks with intervals execute after the delay, not immediately
|
|
233
|
+
if (aInterval > 0 && aIterations == TASK_ONCE) {
|
|
234
|
+
task->enableDelayed();
|
|
235
|
+
} else {
|
|
236
|
+
task->enable();
|
|
237
|
+
}
|
|
232
238
|
return task;
|
|
233
239
|
}
|
|
234
240
|
}
|
|
@@ -236,7 +242,13 @@ class PackageHandler : public layout::Layout<T> {
|
|
|
236
242
|
std::shared_ptr<Task> task =
|
|
237
243
|
std::make_shared<Task>(aInterval, aIterations, aCallback);
|
|
238
244
|
scheduler.addTask((*task));
|
|
239
|
-
|
|
245
|
+
// Use enableDelayed() for delayed one-shot tasks to prevent immediate execution
|
|
246
|
+
// This ensures tasks with intervals execute after the delay, not immediately
|
|
247
|
+
if (aInterval > 0 && aIterations == TASK_ONCE) {
|
|
248
|
+
task->enableDelayed();
|
|
249
|
+
} else {
|
|
250
|
+
task->enable();
|
|
251
|
+
}
|
|
240
252
|
taskList.push_front(task);
|
|
241
253
|
return task;
|
|
242
254
|
}
|