@alteriom/painlessmesh 1.7.8 → 1.7.9

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.
Files changed (34) hide show
  1. package/CHANGELOG.md +45 -1
  2. package/README.md +6 -3
  3. package/RELEASE_GUIDE.md +57 -8
  4. package/docs/README.md +2 -1
  5. package/docs/RELEASE_AGENT_SUMMARY.md +386 -0
  6. package/docs/troubleshooting/ESP32_C6_COMPATIBILITY.md +157 -0
  7. package/docs/troubleshooting/common-issues.md +28 -0
  8. package/examples/alteriom/alteriom_sensor_package.hpp +20 -1
  9. package/examples/alteriom/platformio.ini +1 -1
  10. package/examples/alteriomImproved/platformio.ini +1 -1
  11. package/examples/alteriomMetricsHealth/metrics_health_node.ino +18 -7
  12. package/examples/alteriomMetricsHealth/platformio.ini +1 -1
  13. package/examples/alteriomPhase1/platformio.ini +1 -1
  14. package/examples/alteriomPhase2/platformio.ini +1 -1
  15. package/examples/alteriomSensorNode/platformio.ini +1 -1
  16. package/examples/basic/platformio.ini +1 -1
  17. package/examples/bridge/alteriom_sensor_package.hpp +1170 -0
  18. package/examples/bridge/bridge.ino +2 -2
  19. package/examples/bridge/enhanced_mqtt_bridge.hpp +1 -1
  20. package/examples/bridge/mqtt_command_bridge.hpp +2 -2
  21. package/examples/bridge/platformio.ini +2 -1
  22. package/examples/echoNode/platformio.ini +1 -1
  23. package/examples/logClient/platformio.ini +1 -1
  24. package/examples/logServer/platformio.ini +1 -1
  25. package/examples/mqttStatusBridge/platformio.ini +1 -1
  26. package/examples/namedMesh/platformio.ini +1 -1
  27. package/examples/otaReceiver/platformio.ini +1 -1
  28. package/examples/startHere/platformio.ini +1 -1
  29. package/examples/webServer/platformio.ini +1 -1
  30. package/library.json +93 -53
  31. package/library.properties +1 -1
  32. package/package.json +2 -2
  33. package/src/arduino/wifi.hpp +9 -0
  34. package/src/painlessMeshSTA.cpp +5 -0
@@ -0,0 +1,157 @@
1
+ # ESP32-C6 Compatibility Guide
2
+
3
+ ## Overview
4
+
5
+ ESP32-C6 is a newer ESP32 variant that requires updated dependencies to work correctly with painlessMesh. This guide addresses common issues and solutions for using painlessMesh on ESP32-C6.
6
+
7
+ ## Known Issue: TCP Allocation Crash
8
+
9
+ ### Symptom
10
+
11
+ The device crashes on startup or during mesh initialization with the following error:
12
+
13
+ ```
14
+ assert failed: tcp_alloc /IDF/components/lwip/lwip/src/core/tcp.c:1854 (Required to lock TCPIP core functionality!)
15
+ ```
16
+
17
+ The device enters an endless reboot loop, preventing normal mesh operation.
18
+
19
+ ### Root Cause
20
+
21
+ This issue is caused by incompatibility between:
22
+ - ESP32-C6 hardware
23
+ - Arduino ESP32 core v3.1.0 or later
24
+ - Older versions of the AsyncTCP library
25
+
26
+ The newer ESP32 Arduino core enforces stricter LWIP (Lightweight IP) thread safety requirements. Operations that modify TCP/IP data structures must now be protected with proper mutex locking. Older AsyncTCP versions (< v3.3.0) do not implement this locking, causing runtime assertions and crashes.
27
+
28
+ ### Solution
29
+
30
+ #### Option 1: Update AsyncTCP Library (Recommended)
31
+
32
+ Use the latest version of AsyncTCP that includes proper LWIP locking:
33
+
34
+ **For PlatformIO:**
35
+
36
+ Update your `platformio.ini`:
37
+
38
+ ```ini
39
+ [env:esp32c6]
40
+ platform = espressif32
41
+ board = esp32-c6-devkitc-1 ; or your specific board
42
+ framework = arduino
43
+
44
+ lib_deps =
45
+ https://github.com/Alteriom/painlessMesh.git
46
+ esp32async/AsyncTCP @ ^3.4.7 ; Use latest version with LWIP locking
47
+ bblanchon/ArduinoJson @ ^7.4.2
48
+ arkhipenko/TaskScheduler @ ^4.0.0
49
+ ```
50
+
51
+ **For Arduino IDE:**
52
+
53
+ 1. Remove any existing AsyncTCP library installation
54
+ 2. Download the latest AsyncTCP from: https://github.com/ESP32Async/AsyncTCP
55
+ 3. Install using "Sketch" → "Include Library" → "Add .ZIP Library"
56
+ 4. **Important:** Do not use the Arduino Library Manager for AsyncTCP, as it may install an outdated version
57
+
58
+ #### Option 2: Downgrade Arduino Core (Temporary Workaround)
59
+
60
+ If you need an immediate solution and cannot update AsyncTCP:
61
+
62
+ 1. In Arduino IDE: Tools → Board Manager → ESP32 by Espressif Systems
63
+ 2. Install version **3.0.7** instead of 3.1.0+
64
+ 3. This is not recommended long-term as you'll miss security updates and new features
65
+
66
+ #### Option 3: Use Recommended Build Flags
67
+
68
+ Add these configuration options to improve stability (PlatformIO):
69
+
70
+ ```ini
71
+ build_flags =
72
+ -D CONFIG_ASYNC_TCP_MAX_ACK_TIME=5000
73
+ -D CONFIG_ASYNC_TCP_PRIORITY=10
74
+ -D CONFIG_ASYNC_TCP_QUEUE_SIZE=64
75
+ -D CONFIG_ASYNC_TCP_RUNNING_CORE=1
76
+ -D CONFIG_ASYNC_TCP_STACK_SIZE=4096
77
+ ```
78
+
79
+ These flags help maintain proper task scheduling and LWIP event handling.
80
+
81
+ ## Verification
82
+
83
+ After applying the fix, verify your setup:
84
+
85
+ 1. Upload a simple bridge example
86
+ 2. Monitor serial output for clean startup
87
+ 3. Check for successful mesh initialization without crashes
88
+ 4. Verify mesh connectivity with other nodes
89
+
90
+ Example verification output:
91
+ ```
92
+ setLogLevel: ERROR | STARTUP | CONNECTION |
93
+ STARTUP: init(): 1
94
+ STARTUP: stationManual() Starting WiFi connection
95
+ STARTUP: Connection established
96
+ STARTUP: IP address: 192.168.1.100
97
+ ```
98
+
99
+ ## Additional ESP32-C6 Considerations
100
+
101
+ ### Hardware-Specific Notes
102
+
103
+ - ESP32-C6 uses RISC-V architecture (not Xtensa like older ESP32)
104
+ - Built-in WiFi 6 (802.11ax) support - but mesh uses 802.11n
105
+ - Lower power consumption compared to ESP32
106
+ - Different GPIO pinout - verify your pin assignments
107
+
108
+ ### Memory Constraints
109
+
110
+ ESP32-C6 typically has:
111
+ - 320 KB SRAM
112
+ - 4 MB Flash (typical configuration)
113
+
114
+ This is adequate for painlessMesh, but be mindful of:
115
+ - Maximum node count in mesh (recommend < 20 nodes)
116
+ - Message queue sizes
117
+ - JSON message complexity
118
+
119
+ ### Performance Optimization
120
+
121
+ For best results on ESP32-C6:
122
+
123
+ 1. **WiFi Channel Selection**: Use channels 1, 6, or 11 for best performance
124
+ 2. **Mesh Size**: Keep mesh networks under 15-20 nodes
125
+ 3. **Message Frequency**: Avoid sending messages more than once per second per node
126
+ 4. **Power Management**: Consider WiFi power save modes for battery operation
127
+
128
+ ## Troubleshooting Checklist
129
+
130
+ If you're still experiencing issues:
131
+
132
+ - [ ] Confirmed AsyncTCP version is 3.3.0 or newer
133
+ - [ ] Removed all old AsyncTCP library installations
134
+ - [ ] Arduino ESP32 core is 3.0.7 or 3.1.0+ with updated AsyncTCP
135
+ - [ ] Verified board definition matches your hardware
136
+ - [ ] Checked serial monitor for actual error messages
137
+ - [ ] Tested with minimal example (examples/basic/basic.ino)
138
+ - [ ] Verified WiFi credentials are correct
139
+ - [ ] Confirmed router and mesh use same WiFi channel (for bridge mode)
140
+
141
+ ## References
142
+
143
+ - [AsyncTCP Library (ESP32Async)](https://github.com/ESP32Async/AsyncTCP)
144
+ - [ESP32 Arduino Core Release Notes](https://github.com/espressif/arduino-esp32/releases)
145
+ - [painlessMesh GitHub Issues](https://github.com/Alteriom/painlessMesh/issues)
146
+
147
+ ## Related Documentation
148
+
149
+ - [Common Issues](common-issues.md)
150
+ - [FAQ](faq.md)
151
+ - [Bridge to Internet Guide](../../BRIDGE_TO_INTERNET.md)
152
+ - [Debugging Guide](debugging.md)
153
+
154
+ ---
155
+
156
+ **Last Updated:** 2025-11-05
157
+ **Applies to:** painlessMesh v1.7.8+, ESP32-C6, Arduino ESP32 Core 3.0+
@@ -2,6 +2,34 @@
2
2
 
3
3
  This guide covers the most frequently encountered problems when working with painlessMesh and their solutions.
4
4
 
5
+ ## Platform-Specific Issues
6
+
7
+ ### ESP32-C6 Crashes on Startup
8
+
9
+ **Symptoms:**
10
+ - Device crashes immediately after mesh initialization
11
+ - Endless reboot loop
12
+ - Error message: `assert failed: tcp_alloc ... (Required to lock TCPIP core functionality!)`
13
+
14
+ **Solution:**
15
+
16
+ This is a known compatibility issue with ESP32-C6 and newer ESP32 variants. See the dedicated guide:
17
+
18
+ 📖 **[ESP32-C6 Compatibility Guide](ESP32_C6_COMPATIBILITY.md)**
19
+
20
+ **Quick Fix:**
21
+ Update your AsyncTCP library to version 3.3.0 or newer, or use the ESP32Async library which includes proper LWIP locking for Arduino ESP32 core 3.1.0+.
22
+
23
+ For PlatformIO, add to your `platformio.ini`:
24
+ ```ini
25
+ lib_deps =
26
+ esp32async/AsyncTCP @ ^3.4.7
27
+ ```
28
+
29
+ For Arduino IDE, download and install manually from: https://github.com/ESP32Async/AsyncTCP
30
+
31
+ ---
32
+
5
33
  ## Connection Issues
6
34
 
7
35
  ### Nodes Not Connecting
@@ -153,6 +153,9 @@ class SensorPackage : public painlessmesh::plugin::BroadcastPackage {
153
153
  // Battery level percentage
154
154
  uint8_t batteryLevel = 0;
155
155
 
156
+ // MQTT Schema v0.7.3+ message_type for faster classification
157
+ uint16_t messageType = 200; // SENSOR_DATA
158
+
156
159
  // Type ID 200 for Alteriom sensors
157
160
  SensorPackage() : BroadcastPackage(200) {}
158
161
 
@@ -163,6 +166,7 @@ class SensorPackage : public painlessmesh::plugin::BroadcastPackage {
163
166
  sensorId = jsonObj["sid"];
164
167
  timestamp = jsonObj["ts"];
165
168
  batteryLevel = jsonObj["bat"];
169
+ messageType = jsonObj["message_type"] | 200;
166
170
  }
167
171
 
168
172
  JsonObject addTo(JsonObject&& jsonObj) const {
@@ -173,6 +177,7 @@ class SensorPackage : public painlessmesh::plugin::BroadcastPackage {
173
177
  jsonObj["sid"] = sensorId;
174
178
  jsonObj["ts"] = timestamp;
175
179
  jsonObj["bat"] = batteryLevel;
180
+ jsonObj["message_type"] = messageType;
176
181
  return jsonObj;
177
182
  }
178
183
 
@@ -193,14 +198,18 @@ class CommandPackage : public painlessmesh::plugin::SinglePackage {
193
198
  TSTRING parameters = ""; // Command parameters as JSON string
194
199
  uint32_t commandId = 0; // Unique command identifier for tracking
195
200
 
201
+ // MQTT Schema v0.7.3+ message_type for faster classification
202
+ uint16_t messageType = 400; // COMMAND
203
+
196
204
  CommandPackage()
197
- : SinglePackage(400) {} // Type ID 400 (COMMAND per mqtt-schema v0.7.2+)
205
+ : SinglePackage(400) {} // Type ID 400 (COMMAND per mqtt-schema v0.7.3+)
198
206
 
199
207
  CommandPackage(JsonObject jsonObj) : SinglePackage(jsonObj) {
200
208
  command = jsonObj["cmd"];
201
209
  targetDevice = jsonObj["target"];
202
210
  parameters = jsonObj["params"].as<TSTRING>();
203
211
  commandId = jsonObj["cid"];
212
+ messageType = jsonObj["message_type"] | 400;
204
213
  }
205
214
 
206
215
  JsonObject addTo(JsonObject&& jsonObj) const {
@@ -209,6 +218,7 @@ class CommandPackage : public painlessmesh::plugin::SinglePackage {
209
218
  jsonObj["target"] = targetDevice;
210
219
  jsonObj["params"] = parameters;
211
220
  jsonObj["cid"] = commandId;
221
+ jsonObj["message_type"] = messageType;
212
222
  return jsonObj;
213
223
  }
214
224
 
@@ -305,6 +315,9 @@ class StatusPackage : public painlessmesh::plugin::BroadcastPackage {
305
315
  float mqttBackoffMultiplier =
306
316
  0.0; // Backoff multiplier for exponential backoff
307
317
 
318
+ // MQTT Schema v0.7.3+ message_type for faster classification
319
+ uint16_t messageType = 202; // SENSOR_STATUS
320
+
308
321
  StatusPackage() : BroadcastPackage(202) {} // Type ID 202 for Alteriom status
309
322
 
310
323
  StatusPackage(JsonObject jsonObj) : BroadcastPackage(jsonObj) {
@@ -378,6 +391,9 @@ class StatusPackage : public painlessmesh::plugin::BroadcastPackage {
378
391
  mqttMaxRetryMs = mqttRetry["max_retry_ms"] | 0;
379
392
  mqttBackoffMultiplier = mqttRetry["backoff_multiplier"] | 0.0;
380
393
  }
394
+
395
+ // Deserialize message_type field
396
+ messageType = jsonObj["message_type"] | 202;
381
397
  }
382
398
 
383
399
  JsonObject addTo(JsonObject&& jsonObj) const {
@@ -451,6 +467,9 @@ class StatusPackage : public painlessmesh::plugin::BroadcastPackage {
451
467
  mqttRetry["max_retry_s"] = mqttMaxRetryMs / 1000;
452
468
  mqttRetry["backoff_multiplier"] = mqttBackoffMultiplier;
453
469
 
470
+ // Serialize message_type field
471
+ jsonObj["message_type"] = messageType;
472
+
454
473
  return jsonObj;
455
474
  }
456
475
 
@@ -14,7 +14,7 @@ framework = arduino
14
14
  lib_extra_dirs = ../../ ; Load the local copy of painlessmesh. For your own example add painlessmesh to the lib_deps
15
15
  lib_deps =
16
16
  ${env.lib_deps} ; Inherit common dependencies
17
- esp32async/ESPAsyncTCP ; Only for ESP8266
17
+ esp32async/ESPAsyncTCP@^2.0.0 ; Only for ESP8266
18
18
 
19
19
  [env:esp32]
20
20
  platform = espressif32
@@ -20,7 +20,7 @@ framework = arduino
20
20
  lib_extra_dirs = ../../ ; Load the local copy of painlessmesh. For your own example add painlessmesh to the lib_deps
21
21
  lib_deps =
22
22
  ${env.lib_deps} ; Inherit common dependencies
23
- esp32async/ESPAsyncTCP ; Only for ESP8266
23
+ esp32async/ESPAsyncTCP@^2.0.0 ; Only for ESP8266
24
24
 
25
25
  [env:esp32]
26
26
  platform = espressif32
@@ -116,7 +116,8 @@ void sendMetrics() {
116
116
  // CPU and Processing
117
117
  metrics.loopIterations = ((loopCount - lastLoopCount) * 1000) / timeDelta;
118
118
  metrics.cpuUsage = calculateCPUUsage();
119
- metrics.taskQueueSize = userScheduler.size();
119
+ // Note: TaskScheduler doesn't provide a size() method, so we'll use 0 or estimate
120
+ metrics.taskQueueSize = 0; // TaskScheduler API doesn't expose queue size
120
121
 
121
122
  // Memory Metrics
122
123
  metrics.freeHeap = ESP.getFreeHeap();
@@ -155,8 +156,13 @@ void sendMetrics() {
155
156
  metrics.collectionTimestamp = mesh.getNodeTime();
156
157
  metrics.collectionInterval = METRICS_INTERVAL;
157
158
 
158
- // Send the metrics
159
- String msg = metrics.toJsonString();
159
+ // Serialize and send the metrics
160
+ JsonDocument doc;
161
+ JsonObject obj = doc.to<JsonObject>();
162
+ metrics.addTo(std::move(obj));
163
+
164
+ String msg;
165
+ serializeJson(doc, msg);
160
166
  bool sent = mesh.sendBroadcast(msg);
161
167
 
162
168
  if (sent) {
@@ -266,8 +272,13 @@ void sendHealthCheck() {
266
272
  health.checkTimestamp = mesh.getNodeTime();
267
273
  health.nextCheckDue = health.checkTimestamp + (HEALTH_INTERVAL * 1000);
268
274
 
269
- // Send the health check
270
- String msg = health.toJsonString();
275
+ // Serialize and send the health check
276
+ JsonDocument doc;
277
+ JsonObject obj = doc.to<JsonObject>();
278
+ health.addTo(std::move(obj));
279
+
280
+ String msg;
281
+ serializeJson(doc, msg);
271
282
  bool sent = mesh.sendBroadcast(msg);
272
283
 
273
284
  if (sent) {
@@ -372,10 +383,10 @@ void receivedCallback(uint32_t from, String& msg) {
372
383
  totalPacketsRx++;
373
384
 
374
385
  // Parse message type
375
- DynamicJsonDocument doc(1024);
386
+ JsonDocument doc;
376
387
  deserializeJson(doc, msg);
377
388
  JsonObject obj = doc.as<JsonObject>();
378
- uint8_t msgType = obj["type"];
389
+ uint16_t msgType = obj["type"];
379
390
 
380
391
  Serial.printf("\nReceived Type %d from %u\n", msgType, from);
381
392
 
@@ -14,7 +14,7 @@ framework = arduino
14
14
  lib_extra_dirs = ../../ ; Load the local copy of painlessmesh. For your own example add painlessmesh to the lib_deps
15
15
  lib_deps =
16
16
  ${env.lib_deps} ; Inherit common dependencies
17
- esp32async/ESPAsyncTCP ; Only for ESP8266
17
+ esp32async/ESPAsyncTCP@^2.0.0 ; Only for ESP8266
18
18
 
19
19
  [env:esp32]
20
20
  platform = espressif32
@@ -14,7 +14,7 @@ framework = arduino
14
14
  lib_extra_dirs = ../../ ; Load the local copy of painlessmesh. For your own example add painlessmesh to the lib_deps
15
15
  lib_deps =
16
16
  ${env.lib_deps} ; Inherit common dependencies
17
- esp32async/ESPAsyncTCP ; Only for ESP8266
17
+ esp32async/ESPAsyncTCP@^2.0.0 ; Only for ESP8266
18
18
 
19
19
  [env:esp32]
20
20
  platform = espressif32
@@ -14,7 +14,7 @@ framework = arduino
14
14
  lib_extra_dirs = ../../ ; Load the local copy of painlessmesh. For your own example add painlessmesh to the lib_deps
15
15
  lib_deps =
16
16
  ${env.lib_deps} ; Inherit common dependencies
17
- esp32async/ESPAsyncTCP ; Only for ESP8266
17
+ esp32async/ESPAsyncTCP@^2.0.0 ; Only for ESP8266
18
18
 
19
19
  [env:esp32]
20
20
  platform = espressif32
@@ -14,7 +14,7 @@ framework = arduino
14
14
  lib_extra_dirs = ../../ ; Load the local copy of painlessmesh. For your own example add painlessmesh to the lib_deps
15
15
  lib_deps =
16
16
  ${env.lib_deps} ; Inherit common dependencies
17
- esp32async/ESPAsyncTCP ; Only for ESP8266
17
+ esp32async/ESPAsyncTCP@^2.0.0 ; Only for ESP8266
18
18
 
19
19
  [env:esp32]
20
20
  platform = espressif32
@@ -14,7 +14,7 @@ framework = arduino
14
14
  lib_extra_dirs = ../../
15
15
  lib_deps =
16
16
  ${env.lib_deps} ; Inherit common dependencies
17
- esp32async/ESPAsyncTCP ; Only for ESP8266
17
+ esp32async/ESPAsyncTCP@^2.0.0 ; Only for ESP8266
18
18
 
19
19
  [env:esp32]
20
20
  platform = espressif32