@alteriom/painlessmesh 1.9.20 → 2.0.0
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/BRIDGE_TO_INTERNET.md +167 -29
- package/CHANGELOG.md +604 -0
- package/CONTRIBUTING.md +56 -53
- package/README.md +100 -75
- package/RELEASE_GUIDE.md +81 -641
- package/examples/alteriom/README.md +8 -10
- package/examples/alteriom/alteriom.ino +2 -2
- package/examples/alteriom/alteriom_custom_package_template.hpp +11 -11
- package/examples/alteriom/alteriom_sensor_package.hpp +17 -11
- package/examples/alteriom/mppt_example/alteriom_custom_package_template.hpp +320 -0
- package/examples/alteriom/mppt_example/alteriom_sensor_package.hpp +1389 -0
- package/examples/alteriom/mppt_example/{alteriom_mppt_example.ino → mppt_example.ino} +5 -1
- package/examples/basic/test/simulator/README.md +3 -3
- package/examples/bridge_failover/README.md +51 -14
- package/examples/bridge_failover/bridge_failover.ino +2 -2
- package/examples/commandControl/commandControl.ino +86 -0
- package/examples/commandControl/platformio.ini +26 -0
- package/examples/mqttBridge/mqttBridge.ino +4 -0
- package/examples/mqttBridge/platformio.ini +1 -1
- package/examples/otaSender/otaSender.ino +5 -1
- package/examples/priority/README.md +1 -1
- package/examples/priority/{priority_basic_example.ino → priority_basic_example/priority_basic_example.ino} +4 -4
- package/examples/priority/{priority_with_queue.ino → priority_with_queue/priority_with_queue.ino} +20 -2
- package/examples/reliableSensorLogging/platformio.ini +26 -0
- package/examples/reliableSensorLogging/reliableSensorLogging.ino +151 -0
- package/examples/sendToInternet/README.md +12 -5
- package/examples/sendToInternet/{CMakeLists.txt → pc_node/CMakeLists.txt} +7 -7
- package/examples/sendToInternet/{PC_NODE_README.md → pc_node/PC_NODE_README.md} +15 -15
- package/examples/sendToInternet/{build.sh → pc_node/build.sh} +5 -5
- package/examples/sendToInternet/{pc_mesh_node.cpp → pc_node/pc_mesh_node.cpp} +12 -1
- package/examples/sharedGateway/README.md +1 -2
- package/examples/tcpRetryConfig/README.md +110 -0
- package/examples/tcpRetryConfig/platformio.ini +26 -0
- package/examples/tcpRetryConfig/tcpRetryConfig.ino +154 -0
- package/keywords.txt +53 -1
- package/library.json +8 -6
- package/library.properties +2 -2
- package/package.json +3 -3
- package/src/AlteriomPainlessMesh.h +4 -4
- package/src/arduino/wifi.hpp +605 -143
- package/src/painlessMesh.h +2 -2
- package/src/painlessMeshSTA.cpp +607 -87
- package/src/painlessMeshSTA.h +135 -3
- package/src/painlessTaskOptions.h +9 -0
- package/src/painlessmesh/ack.hpp +283 -0
- package/src/painlessmesh/buffer.hpp +74 -9
- package/src/painlessmesh/callback.hpp +38 -5
- package/src/painlessmesh/configuration.hpp +82 -3
- package/src/painlessmesh/connection.hpp +43 -16
- package/src/painlessmesh/gateway.hpp +270 -5
- package/src/painlessmesh/layout.hpp +70 -2
- package/src/painlessmesh/logger.hpp +15 -0
- package/src/painlessmesh/mesh.hpp +625 -70
- package/src/painlessmesh/message_queue.hpp +24 -13
- package/src/painlessmesh/ntp.hpp +2 -4
- package/src/painlessmesh/plugin.hpp +52 -6
- package/src/painlessmesh/protocol.hpp +55 -2
- package/src/painlessmesh/router.hpp +192 -77
- package/src/painlessmesh/tcp.hpp +168 -29
- package/src/painlessmesh/message_tracker.hpp +0 -311
- /package/examples/sendToInternet/{mock_server_test.ino → mock_server_test/mock_server_test.ino} +0 -0
|
@@ -6,7 +6,7 @@ This example provides a **PC-based mesh node** that can join a painlessMesh netw
|
|
|
6
6
|
|
|
7
7
|
### The Problem This Solves
|
|
8
8
|
|
|
9
|
-
Previous examples (
|
|
9
|
+
Previous examples (`../mock_server_test/mock_server_test.ino`) tested the bridge making HTTP requests directly, but did **NOT** test the complete flow:
|
|
10
10
|
|
|
11
11
|
```
|
|
12
12
|
Regular Node → Mesh Network → Bridge → Internet → Bridge → Mesh Network → Regular Node
|
|
@@ -90,7 +90,7 @@ brew install cmake boost
|
|
|
90
90
|
For testing, start the mock HTTP server:
|
|
91
91
|
|
|
92
92
|
```bash
|
|
93
|
-
cd
|
|
93
|
+
cd ../../../test/mock-http-server
|
|
94
94
|
python3 server.py
|
|
95
95
|
```
|
|
96
96
|
|
|
@@ -101,13 +101,13 @@ The server will run on `http://localhost:8080` by default.
|
|
|
101
101
|
### Quick Build (Using make)
|
|
102
102
|
|
|
103
103
|
```bash
|
|
104
|
-
cd examples/sendToInternet
|
|
104
|
+
cd examples/sendToInternet/pc_node
|
|
105
105
|
|
|
106
106
|
# Initialize dependencies (if not already done)
|
|
107
|
-
cd
|
|
107
|
+
cd ../../../test
|
|
108
108
|
git clone https://github.com/bblanchon/ArduinoJson.git
|
|
109
109
|
git clone https://github.com/arkhipenko/TaskScheduler
|
|
110
|
-
cd ../examples/sendToInternet
|
|
110
|
+
cd ../examples/sendToInternet/pc_node
|
|
111
111
|
|
|
112
112
|
# Build
|
|
113
113
|
cmake .
|
|
@@ -131,9 +131,9 @@ make
|
|
|
131
131
|
|
|
132
132
|
```bash
|
|
133
133
|
g++ -std=c++14 -o pc_mesh_node pc_mesh_node.cpp \
|
|
134
|
-
-I
|
|
135
|
-
-I
|
|
136
|
-
|
|
134
|
+
-I../../../src -I../../../test/include -I../../../test/ArduinoJson/src \
|
|
135
|
+
-I../../../test/TaskScheduler/src -I../../../test/boost \
|
|
136
|
+
../../../test/catch/fake_serial.cpp ../../../src/scheduler.cpp \
|
|
137
137
|
-lboost_system -pthread
|
|
138
138
|
```
|
|
139
139
|
|
|
@@ -371,14 +371,14 @@ brew install boost
|
|
|
371
371
|
#### "ArduinoJson not found"
|
|
372
372
|
|
|
373
373
|
```bash
|
|
374
|
-
cd
|
|
374
|
+
cd ../../../test
|
|
375
375
|
git clone https://github.com/bblanchon/ArduinoJson.git
|
|
376
376
|
```
|
|
377
377
|
|
|
378
378
|
#### "TaskScheduler not found"
|
|
379
379
|
|
|
380
380
|
```bash
|
|
381
|
-
cd
|
|
381
|
+
cd ../../../test
|
|
382
382
|
git clone https://github.com/arkhipenko/TaskScheduler
|
|
383
383
|
```
|
|
384
384
|
|
|
@@ -476,7 +476,7 @@ python3 test/mock-http-server/server.py &
|
|
|
476
476
|
SERVER_PID=$!
|
|
477
477
|
|
|
478
478
|
# Build PC node
|
|
479
|
-
cd examples/sendToInternet
|
|
479
|
+
cd examples/sendToInternet/pc_node
|
|
480
480
|
cmake . && make
|
|
481
481
|
|
|
482
482
|
# Run test (assuming bridge is running at known IP)
|
|
@@ -501,10 +501,10 @@ kill $SERVER_PID
|
|
|
501
501
|
|
|
502
502
|
## Related Documentation
|
|
503
503
|
|
|
504
|
-
- [sendToInternet Example](sendToInternet.ino) - ESP32/ESP8266 example
|
|
505
|
-
- [Mock HTTP Server](
|
|
506
|
-
- [Bridge Documentation](
|
|
507
|
-
- [Testing Guide](
|
|
504
|
+
- [sendToInternet Example](../sendToInternet.ino) - ESP32/ESP8266 example
|
|
505
|
+
- [Mock HTTP Server](../../../test/mock-http-server/README.md) - Testing endpoint
|
|
506
|
+
- [Bridge Documentation](../../../BRIDGE_TO_INTERNET.md) - Bridge setup guide
|
|
507
|
+
- [Testing Guide](../../../test/mock-http-server/TESTING_GUIDE.md) - Complete testing workflow
|
|
508
508
|
|
|
509
509
|
## Credits
|
|
510
510
|
|
|
@@ -73,10 +73,10 @@ echo " - Windows: See https://www.boost.org/"
|
|
|
73
73
|
echo ""
|
|
74
74
|
echo "Checking test dependencies..."
|
|
75
75
|
|
|
76
|
-
if [ ! -d "
|
|
76
|
+
if [ ! -d "../../../test/ArduinoJson/src" ]; then
|
|
77
77
|
echo "⚠️ ArduinoJson not found"
|
|
78
78
|
echo " Cloning ArduinoJson..."
|
|
79
|
-
cd
|
|
79
|
+
cd ../../../test
|
|
80
80
|
if [ -d "ArduinoJson" ]; then
|
|
81
81
|
rm -rf ArduinoJson
|
|
82
82
|
fi
|
|
@@ -86,10 +86,10 @@ else
|
|
|
86
86
|
echo "✓ ArduinoJson found"
|
|
87
87
|
fi
|
|
88
88
|
|
|
89
|
-
if [ ! -d "
|
|
89
|
+
if [ ! -d "../../../test/TaskScheduler/src" ]; then
|
|
90
90
|
echo "⚠️ TaskScheduler not found"
|
|
91
91
|
echo " Cloning TaskScheduler..."
|
|
92
|
-
cd
|
|
92
|
+
cd ../../../test
|
|
93
93
|
if [ -d "TaskScheduler" ]; then
|
|
94
94
|
rm -rf TaskScheduler
|
|
95
95
|
fi
|
|
@@ -135,7 +135,7 @@ if make 2>&1; then
|
|
|
135
135
|
echo ""
|
|
136
136
|
echo "Next steps:"
|
|
137
137
|
echo " 1. Start mock HTTP server:"
|
|
138
|
-
echo " cd
|
|
138
|
+
echo " cd ../../../test/mock-http-server && python3 server.py"
|
|
139
139
|
echo ""
|
|
140
140
|
echo " 2. Configure and upload bridge to ESP32/ESP8266"
|
|
141
141
|
echo " (see sendToInternet.ino with IS_BRIDGE_NODE=true)"
|
|
@@ -38,6 +38,15 @@
|
|
|
38
38
|
* - 5555 is the TCP port the bridge is listening on (MESH_PORT)
|
|
39
39
|
**/
|
|
40
40
|
|
|
41
|
+
// This is a PC-side (desktop) program: it needs Boost and the Arduino
|
|
42
|
+
// emulation layer under test/, neither of which exists for an embedded
|
|
43
|
+
// target. Both the Arduino IDE and arduino-cli compile *every* .cpp in a
|
|
44
|
+
// sketch folder, so without this guard they try to build this file for the
|
|
45
|
+
// ESP and fail on <boost/asio/ip/address.hpp>. ARDUINO is defined by every
|
|
46
|
+
// Arduino toolchain, so the whole file collapses to an empty translation
|
|
47
|
+
// unit there and is left to the CMake/g++ build described above.
|
|
48
|
+
#ifndef ARDUINO
|
|
49
|
+
|
|
41
50
|
#include <iostream>
|
|
42
51
|
#include <string>
|
|
43
52
|
#include <memory>
|
|
@@ -356,6 +365,8 @@ int main(int argc, char* argv[]) {
|
|
|
356
365
|
node.runUpdateLoop(10);
|
|
357
366
|
|
|
358
367
|
std::cout << "\n✓ PC Mesh Node shutting down..." << std::endl;
|
|
359
|
-
|
|
368
|
+
|
|
360
369
|
return 0;
|
|
361
370
|
}
|
|
371
|
+
|
|
372
|
+
#endif // !ARDUINO
|
|
@@ -225,8 +225,7 @@ WiFi.channel()
|
|
|
225
225
|
|
|
226
226
|
## Related Documentation
|
|
227
227
|
|
|
228
|
-
- [
|
|
229
|
-
- [Bridge Mode Example](../bridge/README.md)
|
|
228
|
+
- [Bridge Mode Example](../bridge/bridge.ino)
|
|
230
229
|
- [Bridge Failover Example](../bridge_failover/README.md)
|
|
231
230
|
- [painlessMesh Documentation](https://gitlab.com/painlessMesh/painlessMesh/-/wikis/home)
|
|
232
231
|
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# tcpRetryConfig
|
|
2
|
+
|
|
3
|
+
Tuning painlessMesh's TCP connection retry behaviour with
|
|
4
|
+
`setTcpRetryConfig()` (issue
|
|
5
|
+
[#378](https://github.com/Alteriom/painlessMesh/issues/378)).
|
|
6
|
+
|
|
7
|
+
## What this controls
|
|
8
|
+
|
|
9
|
+
When a node acquires an IP and tries to open its TCP connection to the mesh,
|
|
10
|
+
that connection can fail — the parent's TCP server may not be ready yet, the
|
|
11
|
+
network stack may still be settling, or several nodes may be connecting at
|
|
12
|
+
once. painlessMesh retries with exponential backoff before giving up and
|
|
13
|
+
falling back to a full WiFi reconnect.
|
|
14
|
+
|
|
15
|
+
Five parameters describe that behaviour:
|
|
16
|
+
|
|
17
|
+
| Field | Default | Meaning |
|
|
18
|
+
|---|---|---|
|
|
19
|
+
| `maxRetries` | 5 | TCP connect attempts after the first before giving up |
|
|
20
|
+
| `retryDelayMs` | 1000 | Base delay between retries; scaled 1x, 2x, 4x, 8x, 8x |
|
|
21
|
+
| `stabilizationDelayMs` | 500 | Wait after IP acquisition before the first attempt |
|
|
22
|
+
| `exhaustionReconnectDelayMs` | 10000 | Wait before the WiFi reconnect that follows exhaustion |
|
|
23
|
+
| `failureBlockDurationMs` | 60000 | How long a failed peer is skipped during AP selection |
|
|
24
|
+
|
|
25
|
+
With the defaults, a node that cannot reach its parent spends
|
|
26
|
+
1 + 2 + 4 + 8 + 8 = **23 s** retrying, then waits another **10 s** before
|
|
27
|
+
reconnecting WiFi, and will not re-select that same peer for **60 s**.
|
|
28
|
+
|
|
29
|
+
## Profiles in this sketch
|
|
30
|
+
|
|
31
|
+
Switch with `#define ACTIVE_PROFILE`.
|
|
32
|
+
|
|
33
|
+
| | `PROFILE_REALTIME` | default | `PROFILE_RELIABLE` | `PROFILE_BATTERY` |
|
|
34
|
+
|---|---|---|---|---|
|
|
35
|
+
| `maxRetries` | 1 | 5 | 10 | 2 |
|
|
36
|
+
| `retryDelayMs` | 200 | 1000 | 2000 | 3000 |
|
|
37
|
+
| `stabilizationDelayMs` | 100 | 500 | 1000 | 500 |
|
|
38
|
+
| `exhaustionReconnectDelayMs` | 1000 | 10000 | 30000 | 60000 |
|
|
39
|
+
| `failureBlockDurationMs` | 5000 | 60000 | 180000 | 300000 |
|
|
40
|
+
| worst-case retry time | 0.2 s | 23 s | 126 s | 9 s |
|
|
41
|
+
| full failure cycle | 1.2 s | 33 s | 156 s | 69 s |
|
|
42
|
+
|
|
43
|
+
- **`PROFILE_REALTIME`** — real-time sensor and LED meshes, the use case from
|
|
44
|
+
[discussion #368](https://github.com/Alteriom/painlessMesh/discussions/368).
|
|
45
|
+
A node stuck in a 23 s backoff is worse than one that drops and re-scans, so
|
|
46
|
+
fail fast and move on.
|
|
47
|
+
- **`PROFILE_RELIABLE`** — industrial meshes where getting connected matters
|
|
48
|
+
more than how long it takes. `maxRetries = 10` is the maximum the library
|
|
49
|
+
accepts.
|
|
50
|
+
- **`PROFILE_BATTERY`** — every retry is radio-on time. Few attempts, spaced
|
|
51
|
+
widely, and a long blocklist so the node stops waking up for a peer that is
|
|
52
|
+
known to be down.
|
|
53
|
+
|
|
54
|
+
## Clamping
|
|
55
|
+
|
|
56
|
+
`setTcpRetryConfig()` coerces the two values that can render a node unusable:
|
|
57
|
+
|
|
58
|
+
- `maxRetries` is capped at **10**. Each retry allocates an `AsyncClient` and
|
|
59
|
+
schedules a task, so an unbounded value is a heap and recursion-depth hazard
|
|
60
|
+
on ESP8266.
|
|
61
|
+
- `retryDelayMs` is held between **50 ms** and **60000 ms**. A zero delay would
|
|
62
|
+
schedule retries with no spacing — a hot loop allocating an `AsyncClient`
|
|
63
|
+
every scheduler tick. The ceiling keeps `retryDelayMs * 8` clear of `uint32_t`
|
|
64
|
+
overflow.
|
|
65
|
+
|
|
66
|
+
Everything else passes through untouched, including zeros, which are
|
|
67
|
+
meaningful:
|
|
68
|
+
|
|
69
|
+
- `maxRetries = 0` — do not retry at all; fall straight back to a WiFi
|
|
70
|
+
reconnect on the first TCP error.
|
|
71
|
+
- `stabilizationDelayMs = 0` — attempt the TCP connection immediately on IP
|
|
72
|
+
acquisition.
|
|
73
|
+
- `exhaustionReconnectDelayMs = 0` — reconnect WiFi immediately after
|
|
74
|
+
exhaustion.
|
|
75
|
+
- `failureBlockDurationMs = 0` — never blocklist a failed peer.
|
|
76
|
+
|
|
77
|
+
Call `getTcpRetryConfig()` after setting to see what actually took effect; the
|
|
78
|
+
sketch prints this at startup.
|
|
79
|
+
|
|
80
|
+
## The defaults exist for a reason
|
|
81
|
+
|
|
82
|
+
painlessMesh 1.9.x deliberately *raised* these values (retries 3 → 5, base
|
|
83
|
+
delay 500 ms → 1000 ms) to fix real-world mesh instability. Tuning them back
|
|
84
|
+
down reintroduces the problems that change fixed. Symptoms of an over-aggressive
|
|
85
|
+
profile:
|
|
86
|
+
|
|
87
|
+
- **Connection churn** — nodes repeatedly connect and drop. `maxRetries` is too
|
|
88
|
+
low for how long your parent actually takes to be ready; raise it or raise
|
|
89
|
+
`stabilizationDelayMs`.
|
|
90
|
+
- **Rapid reconnect loops / network congestion** — a node hammers a parent whose
|
|
91
|
+
TCP server is down. `exhaustionReconnectDelayMs` is too short.
|
|
92
|
+
- **The same dead peer is picked over and over** — `failureBlockDurationMs` is
|
|
93
|
+
shorter than one full retry-plus-reconnect cycle, so the peer comes off the
|
|
94
|
+
blocklist before the node has finished failing over. Keep
|
|
95
|
+
`failureBlockDurationMs` greater than
|
|
96
|
+
`(sum of retry backoffs) + exhaustionReconnectDelayMs`. All three profiles
|
|
97
|
+
above satisfy this; `catch_tcp_blocklist.cpp` pins it as a test.
|
|
98
|
+
|
|
99
|
+
Change one parameter at a time and watch the serial log with
|
|
100
|
+
`mesh.setDebugMsgTypes(ERROR | STARTUP | CONNECTION)`.
|
|
101
|
+
|
|
102
|
+
## Building
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
# PlatformIO
|
|
106
|
+
pio run -e esp32 # or -e esp8266
|
|
107
|
+
|
|
108
|
+
# Arduino CLI
|
|
109
|
+
arduino-cli compile --fqbn esp32:esp32:esp32 examples/tcpRetryConfig/tcpRetryConfig.ino
|
|
110
|
+
```
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
[platformio]
|
|
2
|
+
src_dir = .
|
|
3
|
+
|
|
4
|
+
[env]
|
|
5
|
+
lib_deps =
|
|
6
|
+
bblanchon/ArduinoJson
|
|
7
|
+
arkhipenko/TaskScheduler
|
|
8
|
+
|
|
9
|
+
lib_ldf_mode = deep+
|
|
10
|
+
[env:esp8266]
|
|
11
|
+
platform = espressif8266
|
|
12
|
+
board = nodemcuv2
|
|
13
|
+
framework = arduino
|
|
14
|
+
lib_extra_dirs = ../../
|
|
15
|
+
lib_deps =
|
|
16
|
+
${env.lib_deps} ; Inherit common dependencies
|
|
17
|
+
esp32async/ESPAsyncTCP@^2.0.0 ; Only for ESP8266
|
|
18
|
+
|
|
19
|
+
[env:esp32]
|
|
20
|
+
platform = espressif32
|
|
21
|
+
board = esp32dev
|
|
22
|
+
framework = arduino
|
|
23
|
+
lib_extra_dirs = ../../
|
|
24
|
+
lib_deps =
|
|
25
|
+
${env.lib_deps} ; Inherit common dependencies
|
|
26
|
+
esp32async/AsyncTCP
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
//************************************************************
|
|
2
|
+
// Tuning the TCP connection retry behaviour (issue #378)
|
|
3
|
+
//
|
|
4
|
+
// painlessMesh retries a failed TCP connection with exponential backoff
|
|
5
|
+
// before giving up and falling back to a full WiFi reconnect. The defaults
|
|
6
|
+
// (5 retries, 1s base delay -> 1s, 2s, 4s, 8s, 8s) are tuned for general
|
|
7
|
+
// purpose meshes and deliberately favour reliability over speed.
|
|
8
|
+
//
|
|
9
|
+
// setTcpRetryConfig() lets you pick a different trade-off. Three ready-made
|
|
10
|
+
// profiles are shown below; switch between them with ACTIVE_PROFILE.
|
|
11
|
+
//
|
|
12
|
+
// Read examples/tcpRetryConfig/README.md before changing these values - the
|
|
13
|
+
// defaults exist because 1.9.x raised them to fix real mesh instability.
|
|
14
|
+
//************************************************************
|
|
15
|
+
#include <painlessMesh.h>
|
|
16
|
+
|
|
17
|
+
#define MESH_SSID "whateverYouLike"
|
|
18
|
+
#define MESH_PASSWORD "somethingSneaky"
|
|
19
|
+
#define MESH_PORT 5555
|
|
20
|
+
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
// Profiles
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
#define PROFILE_REALTIME 1 // low latency: fail fast, reconnect fast
|
|
25
|
+
#define PROFILE_RELIABLE 2 // industrial: many retries, long backoff
|
|
26
|
+
#define PROFILE_BATTERY 3 // conserve power: few retries, long block
|
|
27
|
+
|
|
28
|
+
// >>> Change this line to try a different profile <<<
|
|
29
|
+
#define ACTIVE_PROFILE PROFILE_REALTIME
|
|
30
|
+
|
|
31
|
+
// Prototypes
|
|
32
|
+
void sendMessage();
|
|
33
|
+
void receivedCallback(uint32_t from, String &msg);
|
|
34
|
+
void newConnectionCallback(uint32_t nodeId);
|
|
35
|
+
void droppedConnectionCallback(uint32_t nodeId);
|
|
36
|
+
|
|
37
|
+
Scheduler userScheduler;
|
|
38
|
+
painlessMesh mesh;
|
|
39
|
+
|
|
40
|
+
Task taskSendMessage(TASK_SECOND * 5, TASK_FOREVER, &sendMessage);
|
|
41
|
+
|
|
42
|
+
// Build the retry configuration for the selected profile.
|
|
43
|
+
painlessmesh::tcp::TcpRetryConfig buildRetryConfig() {
|
|
44
|
+
painlessmesh::tcp::TcpRetryConfig cfg; // starts at the library defaults
|
|
45
|
+
|
|
46
|
+
#if ACTIVE_PROFILE == PROFILE_REALTIME
|
|
47
|
+
// Real-time sensor / LED meshes: a stalled node is worse than a dropped
|
|
48
|
+
// one. Give up on the TCP handshake almost immediately and go straight
|
|
49
|
+
// back to scanning for another parent.
|
|
50
|
+
cfg.maxRetries = 1; // default 5
|
|
51
|
+
cfg.retryDelayMs = 200; // default 1000
|
|
52
|
+
cfg.stabilizationDelayMs = 100; // default 500
|
|
53
|
+
cfg.exhaustionReconnectDelayMs = 1000; // default 10000
|
|
54
|
+
cfg.failureBlockDurationMs = 5000; // default 60000
|
|
55
|
+
|
|
56
|
+
#elif ACTIVE_PROFILE == PROFILE_RELIABLE
|
|
57
|
+
// Industrial / high-reliability meshes: connectivity matters more than
|
|
58
|
+
// how long it takes to get there. Retry patiently and keep a failed peer
|
|
59
|
+
// out of the running for a good while.
|
|
60
|
+
cfg.maxRetries = 10; // default 5 (this is the maximum)
|
|
61
|
+
cfg.retryDelayMs = 2000; // default 1000
|
|
62
|
+
cfg.stabilizationDelayMs = 1000; // default 500
|
|
63
|
+
cfg.exhaustionReconnectDelayMs = 30000; // default 10000
|
|
64
|
+
// Must exceed one full failure cycle (126s of retries + 30s reconnect),
|
|
65
|
+
// otherwise a dead peer leaves the blocklist before we finished failing
|
|
66
|
+
// over and gets re-selected immediately.
|
|
67
|
+
cfg.failureBlockDurationMs = 180000; // default 60000
|
|
68
|
+
|
|
69
|
+
#elif ACTIVE_PROFILE == PROFILE_BATTERY
|
|
70
|
+
// Battery-powered nodes: every retry is radio time. Few attempts, spaced
|
|
71
|
+
// widely, and a long blocklist so we do not keep waking up for a peer
|
|
72
|
+
// that is known to be down.
|
|
73
|
+
cfg.maxRetries = 2; // default 5
|
|
74
|
+
cfg.retryDelayMs = 3000; // default 1000
|
|
75
|
+
cfg.stabilizationDelayMs = 500; // default 500
|
|
76
|
+
cfg.exhaustionReconnectDelayMs = 60000; // default 10000
|
|
77
|
+
cfg.failureBlockDurationMs = 300000; // default 60000
|
|
78
|
+
|
|
79
|
+
#else
|
|
80
|
+
#error "ACTIVE_PROFILE must be one of PROFILE_REALTIME, PROFILE_RELIABLE, PROFILE_BATTERY"
|
|
81
|
+
#endif
|
|
82
|
+
|
|
83
|
+
return cfg;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
void setup() {
|
|
87
|
+
Serial.begin(115200);
|
|
88
|
+
|
|
89
|
+
mesh.setDebugMsgTypes(ERROR | STARTUP | CONNECTION);
|
|
90
|
+
|
|
91
|
+
// Apply the retry configuration BEFORE init() so the very first connection
|
|
92
|
+
// attempt already uses it.
|
|
93
|
+
mesh.setTcpRetryConfig(buildRetryConfig());
|
|
94
|
+
|
|
95
|
+
mesh.init(MESH_SSID, MESH_PASSWORD, &userScheduler, MESH_PORT);
|
|
96
|
+
|
|
97
|
+
// Read the configuration back. Values outside safe operating bounds are
|
|
98
|
+
// clamped by the setter, so this prints what is actually in effect - not
|
|
99
|
+
// necessarily what was requested.
|
|
100
|
+
painlessmesh::tcp::TcpRetryConfig active = mesh.getTcpRetryConfig();
|
|
101
|
+
Serial.println();
|
|
102
|
+
Serial.println(F("Effective TCP retry configuration:"));
|
|
103
|
+
Serial.printf(" maxRetries = %u\n",
|
|
104
|
+
(unsigned)active.maxRetries);
|
|
105
|
+
Serial.printf(" retryDelayMs = %u\n",
|
|
106
|
+
(unsigned)active.retryDelayMs);
|
|
107
|
+
Serial.printf(" stabilizationDelayMs = %u\n",
|
|
108
|
+
(unsigned)active.stabilizationDelayMs);
|
|
109
|
+
Serial.printf(" exhaustionReconnectDelayMs = %u\n",
|
|
110
|
+
(unsigned)active.exhaustionReconnectDelayMs);
|
|
111
|
+
Serial.printf(" failureBlockDurationMs = %u\n",
|
|
112
|
+
(unsigned)active.failureBlockDurationMs);
|
|
113
|
+
|
|
114
|
+
// Worst-case time spent retrying before falling back to a WiFi reconnect.
|
|
115
|
+
uint32_t worstCase = 0;
|
|
116
|
+
for (uint8_t i = 0; i < active.maxRetries; ++i) {
|
|
117
|
+
worstCase += painlessmesh::tcp::retryBackoffDelay(active, i);
|
|
118
|
+
}
|
|
119
|
+
Serial.printf(" -> worst-case retry time = %u ms\n", (unsigned)worstCase);
|
|
120
|
+
Serial.printf(" -> plus reconnect delay = %u ms\n",
|
|
121
|
+
(unsigned)(worstCase + active.exhaustionReconnectDelayMs));
|
|
122
|
+
Serial.println();
|
|
123
|
+
|
|
124
|
+
mesh.onReceive(&receivedCallback);
|
|
125
|
+
mesh.onNewConnection(&newConnectionCallback);
|
|
126
|
+
mesh.onDroppedConnection(&droppedConnectionCallback);
|
|
127
|
+
|
|
128
|
+
userScheduler.addTask(taskSendMessage);
|
|
129
|
+
taskSendMessage.enable();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
void loop() {
|
|
133
|
+
mesh.update();
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
void sendMessage() {
|
|
137
|
+
String msg = "Hello from node ";
|
|
138
|
+
msg += mesh.getNodeId();
|
|
139
|
+
mesh.sendBroadcast(msg);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
void receivedCallback(uint32_t from, String &msg) {
|
|
143
|
+
Serial.printf("tcpRetryConfig: Received from %u msg=%s\n", from, msg.c_str());
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
void newConnectionCallback(uint32_t nodeId) {
|
|
147
|
+
Serial.printf("--> Connected to node %u\n", nodeId);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
void droppedConnectionCallback(uint32_t nodeId) {
|
|
151
|
+
// With an aggressive profile you should expect to see this more often -
|
|
152
|
+
// and to see the reconnect that follows it happen much sooner.
|
|
153
|
+
Serial.printf("--> Dropped connection to node %u\n", nodeId);
|
|
154
|
+
}
|
package/keywords.txt
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
painlessMesh KEYWORD1
|
|
5
5
|
Scheduler KEYWORD1
|
|
6
6
|
Task KEYWORD1
|
|
7
|
+
TcpRetryConfig KEYWORD1
|
|
8
|
+
SendOptions KEYWORD1
|
|
7
9
|
|
|
8
10
|
# Methods and Functions (KEYWORD2)
|
|
9
11
|
init KEYWORD2
|
|
@@ -18,11 +20,57 @@ getNodeList KEYWORD2
|
|
|
18
20
|
getNodeId KEYWORD2
|
|
19
21
|
getNodeTime KEYWORD2
|
|
20
22
|
setDebugMsgTypes KEYWORD2
|
|
23
|
+
checkAcks KEYWORD2
|
|
24
|
+
pendingAcks KEYWORD2
|
|
25
|
+
setTcpRetryConfig KEYWORD2
|
|
26
|
+
getTcpRetryConfig KEYWORD2
|
|
27
|
+
stop KEYWORD2
|
|
28
|
+
isConnected KEYWORD2
|
|
29
|
+
subConnectionJson KEYWORD2
|
|
30
|
+
startDelayMeas KEYWORD2
|
|
31
|
+
onNodeDelayReceived KEYWORD2
|
|
32
|
+
setRoot KEYWORD2
|
|
33
|
+
setContainsRoot KEYWORD2
|
|
34
|
+
isRoot KEYWORD2
|
|
35
|
+
stationManual KEYWORD2
|
|
36
|
+
setHostname KEYWORD2
|
|
37
|
+
initAsBridge KEYWORD2
|
|
38
|
+
initAsSharedGateway KEYWORD2
|
|
39
|
+
isBridge KEYWORD2
|
|
40
|
+
setRouterCredentials KEYWORD2
|
|
41
|
+
enableBridgeFailover KEYWORD2
|
|
42
|
+
onBridgeRoleChanged KEYWORD2
|
|
43
|
+
onBridgeStatusChanged KEYWORD2
|
|
44
|
+
onGatewayChanged KEYWORD2
|
|
45
|
+
setElectionStartupDelay KEYWORD2
|
|
46
|
+
setElectionRandomDelay KEYWORD2
|
|
47
|
+
setElectionTimeout KEYWORD2
|
|
48
|
+
setMinimumBridgeRSSI KEYWORD2
|
|
49
|
+
setBridgeStatusInterval KEYWORD2
|
|
50
|
+
setBridgeTimeout KEYWORD2
|
|
51
|
+
hasInternetConnection KEYWORD2
|
|
52
|
+
hasLocalInternet KEYWORD2
|
|
53
|
+
getBridges KEYWORD2
|
|
54
|
+
getPrimaryBridge KEYWORD2
|
|
55
|
+
getPrimaryGateway KEYWORD2
|
|
56
|
+
enableSendToInternet KEYWORD2
|
|
57
|
+
sendToInternet KEYWORD2
|
|
58
|
+
enableMessageQueue KEYWORD2
|
|
59
|
+
queueMessage KEYWORD2
|
|
60
|
+
flushMessageQueue KEYWORD2
|
|
61
|
+
getQueueStats KEYWORD2
|
|
62
|
+
initOTASend KEYWORD2
|
|
63
|
+
initOTAReceive KEYWORD2
|
|
64
|
+
overCapacity KEYWORD2
|
|
65
|
+
apChildren KEYWORD2
|
|
66
|
+
getTcpRetryConfig KEYWORD2
|
|
21
67
|
subConnectionJson KEYWORD2
|
|
22
68
|
asNodeTree KEYWORD2
|
|
23
69
|
|
|
24
70
|
# Alteriom Extensions (KEYWORD1)
|
|
25
71
|
SensorPackage KEYWORD1
|
|
72
|
+
MessageAckPackage KEYWORD1
|
|
73
|
+
deliveryCallback_t KEYWORD1
|
|
26
74
|
CommandPackage KEYWORD1
|
|
27
75
|
StatusPackage KEYWORD1
|
|
28
76
|
|
|
@@ -46,4 +94,8 @@ COMMUNICATION LITERAL1
|
|
|
46
94
|
GENERAL LITERAL1
|
|
47
95
|
MSG_TYPES LITERAL1
|
|
48
96
|
REMOTE LITERAL1
|
|
49
|
-
DEBUG LITERAL1
|
|
97
|
+
DEBUG LITERAL1
|
|
98
|
+
PRIORITY_CRITICAL LITERAL1
|
|
99
|
+
PRIORITY_HIGH LITERAL1
|
|
100
|
+
PRIORITY_NORMAL LITERAL1
|
|
101
|
+
PRIORITY_LOW LITERAL1
|
package/library.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "https://github.com/Alteriom/painlessMesh"
|
|
8
8
|
},
|
|
9
|
-
"version": "
|
|
9
|
+
"version": "2.0.0",
|
|
10
10
|
"frameworks": [
|
|
11
11
|
"arduino"
|
|
12
12
|
],
|
|
@@ -87,13 +87,15 @@
|
|
|
87
87
|
"examples/namedMesh/namedMesh.ino",
|
|
88
88
|
"examples/otaReceiver/otaReceiver.ino",
|
|
89
89
|
"examples/otaSender/otaSender.ino",
|
|
90
|
-
"examples/alteriom/mppt_example/
|
|
91
|
-
"examples/priority/priority_basic_example.ino",
|
|
92
|
-
"examples/priority/priority_with_queue.ino",
|
|
93
|
-
"examples/sendToInternet/mock_server_test.ino",
|
|
90
|
+
"examples/alteriom/mppt_example/mppt_example.ino",
|
|
91
|
+
"examples/priority/priority_basic_example/priority_basic_example.ino",
|
|
92
|
+
"examples/priority/priority_with_queue/priority_with_queue.ino",
|
|
93
|
+
"examples/sendToInternet/mock_server_test/mock_server_test.ino",
|
|
94
94
|
"examples/sendToInternet/sendToInternet.ino",
|
|
95
95
|
"examples/sharedGateway/sharedGateway.ino",
|
|
96
96
|
"examples/startHere/startHere.ino",
|
|
97
|
-
"examples/webServer/webServer.ino"
|
|
97
|
+
"examples/webServer/webServer.ino",
|
|
98
|
+
"examples/commandControl/commandControl.ino",
|
|
99
|
+
"examples/reliableSensorLogging/reliableSensorLogging.ino"
|
|
98
100
|
]
|
|
99
101
|
}
|
package/library.properties
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
name=Alteriom PainlessMesh
|
|
2
|
-
version=
|
|
2
|
+
version=2.0.0
|
|
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
|
|
@@ -8,4 +8,4 @@ category=Communication
|
|
|
8
8
|
url=https://github.com/Alteriom/painlessMesh
|
|
9
9
|
architectures=esp8266,esp32
|
|
10
10
|
includes=painlessMesh.h,AlteriomPainlessMesh.h
|
|
11
|
-
depends=ArduinoJson, TaskScheduler
|
|
11
|
+
depends=ArduinoJson, TaskScheduler, PubSubClient
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alteriom/painlessmesh",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
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",
|
|
@@ -41,9 +41,9 @@
|
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@alteriom/mqtt-schema": "^0.8.0",
|
|
43
43
|
"@eslint/js": "^10.0.1",
|
|
44
|
-
"ajv": "^8.
|
|
44
|
+
"ajv": "^8.20.0",
|
|
45
45
|
"ajv-formats": "^3.0.1",
|
|
46
|
-
"prettier": "^3.
|
|
46
|
+
"prettier": "^3.9.6"
|
|
47
47
|
},
|
|
48
48
|
"scripts": {
|
|
49
49
|
"test": "run-parts --regex catch_ bin/ || echo 'Tests completed'",
|
|
@@ -29,10 +29,10 @@
|
|
|
29
29
|
/**
|
|
30
30
|
* @brief AlteriomPainlessMesh library version information
|
|
31
31
|
*/
|
|
32
|
-
#define ALTERIOM_PAINLESS_MESH_VERSION "
|
|
33
|
-
#define ALTERIOM_PAINLESS_MESH_VERSION_MAJOR
|
|
34
|
-
#define ALTERIOM_PAINLESS_MESH_VERSION_MINOR
|
|
35
|
-
#define ALTERIOM_PAINLESS_MESH_VERSION_PATCH
|
|
32
|
+
#define ALTERIOM_PAINLESS_MESH_VERSION "2.0.0"
|
|
33
|
+
#define ALTERIOM_PAINLESS_MESH_VERSION_MAJOR 2
|
|
34
|
+
#define ALTERIOM_PAINLESS_MESH_VERSION_MINOR 0
|
|
35
|
+
#define ALTERIOM_PAINLESS_MESH_VERSION_PATCH 0
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
38
|
* @brief Library description and usage information
|