@alteriom/painlessmesh 1.9.13 → 1.9.14

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 CHANGED
@@ -19,6 +19,34 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
19
19
 
20
20
  - TBD
21
21
 
22
+ ## [1.9.14] - 2025-12-19
23
+
24
+ ### Fixed
25
+
26
+ - **Gateway Connection Timeout During Long HTTP Requests** - Fixed `sendToInternet()` timeouts with slow APIs like CallmeBot WhatsApp
27
+ - **Issue**: Mesh connections closed after 10s while HTTP requests could take 30s, causing "Request timed out" errors even when messages were successfully delivered
28
+ - **Fix**: Bridge now disables connection timeout during HTTP request processing, ensuring ACK delivery regardless of request duration
29
+ - **Impact**: WhatsApp/CallmeBot users and other slow API integrations now receive proper acknowledgments
30
+ - **Compatibility**: Fully backward compatible, no API changes required
31
+ - See GATEWAY_CONNECTION_TIMEOUT_FIX.md for detailed analysis
32
+ - **Hard Reset on ESP32-C6 - Insufficient AsyncClient Deletion Spacing** - Fixed ESP32-C6 heap corruption crashes caused by insufficient spacing between AsyncClient deletions during network disruptions
33
+ - **Root Cause**: The 250ms spacing between AsyncClient deletions was marginally insufficient for ESP32-C6 hardware, which uses AsyncTCP v3.3.0+ and has different timing characteristics due to RISC-V architecture and enhanced cleanup validation
34
+ - **Symptom**: Device crashes with "CORRUPT HEAP: Bad head at 0x40838a24. Expected 0xabba1234 got 0x4081fae4" even with deletions spaced 264ms apart (only 14ms above minimum), particularly during TCP retries, channel changes, and sendToInternet() operations
35
+ - **Hardware Specific**: ESP32-C6 requires more cleanup time due to:
36
+ - AsyncTCP v3.3.0+ with additional validation steps
37
+ - RISC-V architecture vs. Xtensa (different instruction timing)
38
+ - Enhanced heap allocator with more aggressive corruption detection
39
+ - Different WiFi stack and memory management implementation
40
+ - **Solution**: Increased `TCP_CLIENT_DELETION_SPACING_MS` from 250ms to 500ms
41
+ - Provides 2x safety margin for universal ESP32 compatibility
42
+ - Accommodates ESP32-C6, ESP32-S2/S3, ESP32-C3, ESP32-H2, and future variants
43
+ - Maintains backward compatibility with ESP32/ESP8266
44
+ - Minimal performance impact (250ms additional delay in worst-case scenarios)
45
+ - **Analysis**: Crash occurred at 264ms spacing, demonstrating 250ms was too close to minimum requirement for ESP32-C6; 500ms provides adequate safety margin (89% buffer vs. observed crash)
46
+ - **Testing**: All test suites pass (68+ assertions in TCP/connection tests, 1000+ total assertions)
47
+ - **Documentation**: Added ISSUE_HARD_RESET_ESP32C6_SPACING_FIX.md with detailed ESP32-C6 analysis, architecture comparison, and AsyncTCP v3.3.0+ timing requirements
48
+ - **Impact**: Eliminates critical heap corruption on ESP32-C6 and provides enhanced safety for all ESP32 variants
49
+
22
50
  ## [1.9.13] - 2025-12-19
23
51
 
24
52
  ### Fixed
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  <div align="center">
6
6
 
7
- **Version 1.9.13** - Latest release with HTTP 203 retry logic and AsyncClient deletion race condition fixes
7
+ **Version 1.9.14** - Latest release with ESP32-C6 spacing fix and gateway timeout improvements
8
8
 
9
9
  [![CI/CD Pipeline](https://github.com/Alteriom/painlessMesh/actions/workflows/ci.yml/badge.svg)](https://github.com/Alteriom/painlessMesh/actions/workflows/ci.yml)
10
10
  [![Documentation](https://github.com/Alteriom/painlessMesh/actions/workflows/docs.yml/badge.svg)](https://github.com/Alteriom/painlessMesh/actions/workflows/docs.yml)
package/library.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "type": "git",
7
7
  "url": "https://github.com/Alteriom/painlessMesh"
8
8
  },
9
- "version": "1.9.13",
9
+ "version": "1.9.14",
10
10
  "frameworks": [
11
11
  "arduino"
12
12
  ],
@@ -1,5 +1,5 @@
1
1
  name=Alteriom PainlessMesh
2
- version=1.9.13
2
+ version=1.9.14
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.13",
3
+ "version": "1.9.14",
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",
@@ -29,10 +29,10 @@
29
29
  /**
30
30
  * @brief AlteriomPainlessMesh library version information
31
31
  */
32
- #define ALTERIOM_PAINLESS_MESH_VERSION "1.9.13"
32
+ #define ALTERIOM_PAINLESS_MESH_VERSION "1.9.14"
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 13
35
+ #define ALTERIOM_PAINLESS_MESH_VERSION_PATCH 14
36
36
 
37
37
  /**
38
38
  * @brief Library description and usage information
@@ -1246,9 +1246,16 @@ class Mesh : public painlessmesh::Mesh<Connection> {
1246
1246
  Log(STARTUP,
1247
1247
  "initBridgeStatusBroadcast(): Setting up bridge status broadcast\n");
1248
1248
 
1249
+ // CRITICAL FIX: Schedule tasks with a small delay to avoid crashes when
1250
+ // called immediately after stop()/init cycle. The delay allows the scheduler
1251
+ // and internal task structures to stabilize before adding new tasks.
1252
+ // This fixes the "Load access fault" Guru Meditation error that occurred
1253
+ // when promoting to bridge role.
1254
+ const uint32_t INIT_DELAY_MS = 100;
1255
+
1249
1256
  // Register ourselves as a bridge in the knownBridges list
1250
1257
  // This ensures the bridge knows about itself and reports correct status
1251
- this->addTask([this]() {
1258
+ this->addTask(INIT_DELAY_MS, TASK_ONCE, [this]() {
1252
1259
  // Check Internet connectivity: WiFi connected AND valid IP address
1253
1260
  bool hasInternet = (WiFi.status() == WL_CONNECTED) &&
1254
1261
  (WiFi.localIP() != IPAddress(0, 0, 0, 0));
@@ -1269,12 +1276,16 @@ class Mesh : public painlessmesh::Mesh<Connection> {
1269
1276
  });
1270
1277
 
1271
1278
  // Create periodic task to broadcast bridge status
1272
- bridgeStatusTask = this->addTask(this->bridgeStatusIntervalMs, TASK_FOREVER,
1273
- [this]() { this->sendBridgeStatus(); });
1279
+ // Schedule with delay to avoid crashes during stop/init cycle
1280
+ this->addTask(INIT_DELAY_MS, TASK_ONCE, [this]() {
1281
+ bridgeStatusTask = this->addTask(this->bridgeStatusIntervalMs, TASK_FOREVER,
1282
+ [this]() { this->sendBridgeStatus(); });
1283
+ });
1274
1284
 
1275
1285
  // Send immediate broadcast so nodes can discover this bridge right away
1276
1286
  // This ensures bridge is discoverable before the first periodic broadcast
1277
- this->addTask([this]() {
1287
+ // Use slightly larger delay to allow bridge status task to be set up first
1288
+ this->addTask(INIT_DELAY_MS + 50, TASK_ONCE, [this]() {
1278
1289
  Log(STARTUP, "Sending initial bridge status broadcast\n");
1279
1290
  this->sendBridgeStatus();
1280
1291
  });
@@ -2101,13 +2112,26 @@ class Mesh : public painlessmesh::Mesh<Connection> {
2101
2112
 
2102
2113
  this->callbackList.onPackage(
2103
2114
  protocol::GATEWAY_DATA, [this](protocol::Variant& variant,
2104
- std::shared_ptr<Connection>, uint32_t) {
2115
+ std::shared_ptr<Connection> connection, uint32_t) {
2105
2116
  auto pkg = variant.to<gateway::GatewayDataPackage>();
2106
2117
 
2107
2118
  Log(COMMUNICATION,
2108
2119
  "Gateway received Internet request: msgId=%u dest=%s\n",
2109
2120
  pkg.messageId, pkg.destination.c_str());
2110
2121
 
2122
+ // Disable connection timeout during HTTP request processing
2123
+ // HTTP requests can take up to 30 seconds (GATEWAY_HTTP_TIMEOUT_MS)
2124
+ // but mesh connections timeout after 10 seconds (NODE_TIMEOUT).
2125
+ // We disable the timeout here to prevent connection drop during
2126
+ // long-running HTTP requests. The timeout will be automatically
2127
+ // re-enabled when the next sync packet is received.
2128
+ if (connection) {
2129
+ connection->timeOutTask.disable();
2130
+ Log(COMMUNICATION,
2131
+ "Gateway disabled connection timeout for node %u during HTTP request\n",
2132
+ connection->nodeId);
2133
+ }
2134
+
2111
2135
  // Check Internet connectivity
2112
2136
  if (WiFi.status() != WL_CONNECTED) {
2113
2137
  sendGatewayAck(pkg, false, 0, "Gateway not connected to Internet");
@@ -5,7 +5,7 @@
5
5
  * @file painlessMesh.h
6
6
  * @brief Main header file for Alteriom painlessMesh library
7
7
  *
8
- * @version 1.9.13
8
+ * @version 1.9.14
9
9
  * @date 2025-12-19
10
10
  *
11
11
  * painlessMesh is a user-friendly library for creating mesh networks with
@@ -26,7 +26,9 @@ static const uint32_t TCP_CLIENT_CLEANUP_DELAY_MS = 1000; // 1000ms delay before
26
26
  // When multiple AsyncClients are deleted in rapid succession, the AsyncTCP library's
27
27
  // internal cleanup routines can interfere with each other, causing heap corruption
28
28
  // This spacing ensures each deletion completes before the next one begins
29
- static const uint32_t TCP_CLIENT_DELETION_SPACING_MS = 250; // 250ms spacing between deletions
29
+ // Increased from 250ms to 500ms to support ESP32-C6 and other ESP32 variants which
30
+ // require more time for AsyncTCP internal cleanup operations
31
+ static const uint32_t TCP_CLIENT_DELETION_SPACING_MS = 500; // 500ms spacing between deletions
30
32
 
31
33
  // Global state to track AsyncClient deletion scheduling and execution
32
34
  // This ensures deletions are spaced out even when multiple deletion requests arrive simultaneously