@alteriom/painlessmesh 1.10.0 → 2.0.1

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 (55) hide show
  1. package/BRIDGE_TO_INTERNET.md +167 -29
  2. package/CHANGELOG.md +542 -0
  3. package/CONTRIBUTING.md +56 -53
  4. package/README.md +102 -95
  5. package/RELEASE_GUIDE.md +94 -788
  6. package/examples/alteriom/README.md +8 -10
  7. package/examples/alteriom/alteriom.ino +2 -2
  8. package/examples/alteriom/alteriom_sensor_package.hpp +17 -11
  9. package/examples/alteriom/mppt_example/alteriom_custom_package_template.hpp +320 -0
  10. package/examples/alteriom/mppt_example/alteriom_sensor_package.hpp +1389 -0
  11. package/examples/alteriom/mppt_example/{alteriom_mppt_example.ino → mppt_example.ino} +4 -0
  12. package/examples/basic/test/simulator/README.md +3 -3
  13. package/examples/bridge_failover/README.md +51 -14
  14. package/examples/commandControl/commandControl.ino +86 -0
  15. package/examples/commandControl/platformio.ini +26 -0
  16. package/examples/mqttBridge/mqttBridge.ino +4 -0
  17. package/examples/mqttBridge/platformio.ini +1 -1
  18. package/examples/otaSender/otaSender.ino +5 -1
  19. package/examples/priority/README.md +1 -1
  20. package/examples/priority/{priority_basic_example.ino → priority_basic_example/priority_basic_example.ino} +4 -4
  21. package/examples/priority/{priority_with_queue.ino → priority_with_queue/priority_with_queue.ino} +20 -2
  22. package/examples/reliableSensorLogging/platformio.ini +26 -0
  23. package/examples/reliableSensorLogging/reliableSensorLogging.ino +151 -0
  24. package/examples/sendToInternet/README.md +12 -5
  25. package/examples/sendToInternet/{CMakeLists.txt → pc_node/CMakeLists.txt} +7 -7
  26. package/examples/sendToInternet/{PC_NODE_README.md → pc_node/PC_NODE_README.md} +15 -15
  27. package/examples/sendToInternet/{build.sh → pc_node/build.sh} +5 -5
  28. package/examples/sendToInternet/{pc_mesh_node.cpp → pc_node/pc_mesh_node.cpp} +12 -1
  29. package/examples/sendToInternet/platformio.ini +2 -2
  30. package/examples/sharedGateway/README.md +1 -2
  31. package/keywords.txt +50 -1
  32. package/library.json +8 -6
  33. package/library.properties +2 -2
  34. package/package.json +3 -3
  35. package/src/AlteriomPainlessMesh.h +4 -4
  36. package/src/arduino/wifi.hpp +556 -126
  37. package/src/painlessMesh.h +2 -2
  38. package/src/painlessMeshSTA.cpp +607 -87
  39. package/src/painlessMeshSTA.h +135 -3
  40. package/src/painlessmesh/ack.hpp +283 -0
  41. package/src/painlessmesh/buffer.hpp +70 -8
  42. package/src/painlessmesh/callback.hpp +38 -5
  43. package/src/painlessmesh/configuration.hpp +69 -1
  44. package/src/painlessmesh/connection.hpp +12 -5
  45. package/src/painlessmesh/gateway.hpp +270 -5
  46. package/src/painlessmesh/layout.hpp +70 -2
  47. package/src/painlessmesh/logger.hpp +15 -0
  48. package/src/painlessmesh/mesh.hpp +552 -48
  49. package/src/painlessmesh/ntp.hpp +2 -4
  50. package/src/painlessmesh/plugin.hpp +30 -6
  51. package/src/painlessmesh/protocol.hpp +55 -2
  52. package/src/painlessmesh/router.hpp +192 -77
  53. package/src/painlessmesh/tcp.hpp +10 -0
  54. package/src/painlessmesh/message_tracker.hpp +0 -311
  55. /package/examples/sendToInternet/{mock_server_test.ino → mock_server_test/mock_server_test.ino} +0 -0
package/CONTRIBUTING.md CHANGED
@@ -1,79 +1,82 @@
1
1
  # Contributing
2
2
 
3
- We try to follow the [git flow](https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow) development model. Which means that we have a `develop` branch and `main` branch. All development is done under feature branches, which are (when finished) merged into the development branch. When a new version is released we merge the `develop` branch into the `main` branch.
3
+ ## Branches
4
4
 
5
- ## Git flow
5
+ - `main` holds released code. A push to `main` that carries a version bump,
6
+ or whose head commit message starts with `release:`, is what tags and
7
+ publishes a release (see [RELEASE_GUIDE.md](RELEASE_GUIDE.md)).
8
+ - `Feat/next-release` is the integration branch for the next version. Open
9
+ pull requests against it.
10
+ - Work happens on short-lived feature branches (`fix/…`, `feat/…`, `docs/…`)
11
+ cut from `Feat/next-release`.
6
12
 
7
- If you would like to use [git flow tools](http://danielkummer.github.io/git-flow-cheatsheet/) you are more than welcome to. We use it and it's pretty nifty. If you see a `feature\` prefix on a comment then that is git flow automating branch creation. It does need more typing than just plain git so I suggest creating shell aliases for the commands.
13
+ Maintainers merge quickly, often as a squash. Push every commit you describe
14
+ before you describe it, and cut follow-up work from the merged base rather
15
+ than from a stale branch.
8
16
 
9
- ## Submit a pull request:
17
+ ## Submit a pull request
10
18
 
11
- * If your push triggered a 'you just pushed...' message from GitHub then click on the button provided by that pop up to create a pull request.
12
- * If not, then create a pull request and point it to your branch.
13
- * Make sure that you're attempting to merge into `develop` and not `main`.
14
- * Get your code reviewed by another contributor. If there are no contributors who possess the same set of skills then get them to review it anyway but explain what the code does beforehand and why. Use it as an opportunity for discussion around the feature set, to transfer knowledge, and to possibly [rubber duck](https://en.wikipedia.org/wiki/Rubber_duck_debugging) your code.
15
- * Once the code is reviewed then have your reviewer merge your code.
19
+ - Point the pull request at `Feat/next-release`, not `main`.
20
+ - Say what was wrong, how you know (a log, a test, a measurement), and what
21
+ the change does about it. For anything that touches the radio, routing,
22
+ the gateway or OTA, the evidence is a serial log or a run on the
23
+ hardware-in-the-loop rig; a unit test alone is not enough there, because
24
+ the unit tests mock the radio.
25
+ - Get your code reviewed by another contributor, and let the reviewer merge.
16
26
 
17
- NOTE: Tests *must* pass in order for the code to be merged.
27
+ Tests must pass for the code to be merged. Add a changelog entry under
28
+ `## [Unreleased]` in [CHANGELOG.md](CHANGELOG.md) for any user-visible change.
18
29
 
19
- NOTE: Always do a `git pull` on `develop` before you start working to capture the latest changes.
30
+ ## Testing requirements
20
31
 
21
- ## Testing Requirements
32
+ ### Running the desktop tests
22
33
 
23
- ### Running Tests
24
-
25
- Before submitting a pull request, ensure all tests pass:
34
+ Before submitting a pull request, build and run the Catch2 and Boost suites:
26
35
 
27
36
  ```bash
28
- # Build and run unit/integration tests
37
+ git submodule update --init
29
38
  cmake -G Ninja .
30
39
  ninja
31
40
  run-parts --regex catch_ bin/
32
-
33
- # Run simulator tests (for examples)
34
- cd test/simulator
35
- mkdir build && cd build
36
- cmake -G Ninja .. && ninja
37
- bin/painlessmesh-simulator --config ../../../examples/basic/test/simulator/scenarios/basic_mesh_test.yaml
38
41
  ```
39
42
 
40
- ### Adding Tests for New Features
41
-
42
- When adding new features or examples:
43
-
44
- 1. **Unit Tests**: Add tests in `test/catch/` for new components
45
- 2. **Integration Tests**: Add to `test/boost/tcp_integration.cpp` for core functionality
46
- 3. **Simulator Tests**: Create test scenarios in `examples/your_example/test/simulator/` for new examples
47
- 4. **Documentation**: Update relevant test documentation
48
-
49
- ### Example Validation with Simulator
43
+ The same suites run in CI under gcc, clang and AddressSanitizer, and CI also
44
+ compiles every example for esp32 and esp8266 with `arduino-cli`, builds the
45
+ PlatformIO projects under `test/ci/`, and checks formatting and library
46
+ metadata.
50
47
 
51
- All example sketches should have simulator tests that validate behavior with multiple virtual nodes:
48
+ ### Simulator and hardware tests
52
49
 
53
- 1. Create firmware adapter in `examples/your_example/test/simulator/firmware/`
54
- 2. Create YAML test scenarios in `examples/your_example/test/simulator/scenarios/`
55
- 3. Document test setup in `examples/your_example/test/simulator/README.md`
50
+ Multi-node behaviour is tested with the external
51
+ [painlessMesh-simulator](https://github.com/Alteriom/painlessMesh-simulator);
52
+ scenarios for an example live under `examples/<example>/test/simulator/`
53
+ (see `examples/basic/test/simulator/`). Radio, routing, gateway, failover
54
+ and OTA behaviour is validated on the Alteriom hardware-in-the-loop farm; a
55
+ maintainer runs it on a pull request by adding the `run-hil` label, and the
56
+ release gate is three consecutive clean runs of the whole suite.
56
57
 
57
- See [Simulator Testing Guide](docs/SIMULATOR_TESTING.md) for complete instructions.
58
+ ### Adding tests for new features
58
59
 
59
- This ensures examples:
60
- - Work as documented with multiple nodes
61
- - Handle edge cases properly
62
- - Don't regress with library changes
63
- - Serve as validated references for users
60
+ 1. **Unit tests**: add to `test/catch/` for new components.
61
+ 2. **Integration tests**: add to `test/boost/tcp_integration.cpp` for core
62
+ behaviour that spans connections.
63
+ 3. **Simulator scenarios**: add YAML scenarios under
64
+ `examples/<example>/test/simulator/` for new examples.
65
+ 4. **Documentation**: keep `USER_GUIDE.md`, `README.md` and the example's
66
+ own README in step with the change.
64
67
 
65
68
  ## Versioning
66
69
 
67
- This project will try its best to adhere to [semver](http://semver.org/) i.e, a codified guide to versioning software. When a new feature is developed or a bug is fixed the version will need to be bumped to signify the change.
68
-
69
- The semver string is built like this:
70
-
71
- Major.Minor.Patch
72
-
73
- A major version bump means that a massive change took place and that application will probably have to be redeployed because a *backwards incompatible* version was released. Example: A library => model relationship change which requires previous configuration options to become invalid.
74
-
75
- A minor version is a *backwards compatible* addition or change to the core software. Most development activity will be this type of version bump. Example: A new feature or model.
70
+ This project follows [semver](https://semver.org/). Version 2.0 patch
71
+ releases must remain wire-compatible with the 2.0 protocol; anything that
72
+ changes what a node puts on the wire, or what an existing sketch has to do to
73
+ keep working, is a major version.
76
74
 
77
- A patch version is a *backwards compatible* bug fix or application configuration change.
75
+ - **Major**: a backwards-incompatible change (a new or changed protocol
76
+ message, a removed API).
77
+ - **Minor**: a backwards-compatible addition.
78
+ - **Patch**: a backwards-compatible fix.
78
79
 
79
- Documentation doesn't require a version bump.
80
+ Documentation does not require a version bump. The three version files
81
+ (`library.properties`, `library.json`, `package.json`) are changed together
82
+ with `./scripts/bump-version.sh`.
package/README.md CHANGED
@@ -4,15 +4,14 @@
4
4
 
5
5
  <div align="center">
6
6
 
7
- **Version 1.10.0** - Tunable TCP connect-retry behaviour via `setTcpRetryConfig()` (#378)
7
+ **Version 2.0.0** delivery confirmation, a unified send path, and gateway failover, routing and channel following validated on a six-family hardware rig
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)
11
11
  [![Release](https://github.com/Alteriom/painlessMesh/actions/workflows/release.yml/badge.svg)](https://github.com/Alteriom/painlessMesh/actions/workflows/release.yml)
12
12
  [![GitHub release](https://img.shields.io/github/v/release/Alteriom/painlessMesh?label=version)](https://github.com/Alteriom/painlessMesh/releases)
13
13
  [![NPM Version](https://img.shields.io/npm/v/@alteriom/painlessmesh?label=npm)](https://www.npmjs.com/package/@alteriom/painlessmesh)
14
- [![PlatformIO Registry](https://badges.registry.platformio.org/packages/alteriom/library/AlteriomPainlessMesh.svg)](https://registry.platformio.org/libraries/alteriom/AlteriomPainlessMesh)
15
- [![Arduino Library Manager](https://img.shields.io/badge/Arduino-Library%20Manager-blue.svg)](https://www.arduino.cc/reference/en/libraries/alteriompainlessmesh/)
14
+ [![PlatformIO Registry](https://badges.registry.platformio.org/packages/sparck75/library/AlteriomPainlessMesh.svg)](https://registry.platformio.org/libraries/sparck75/AlteriomPainlessMesh)
16
15
 
17
16
  </div>
18
17
 
@@ -156,12 +155,13 @@ See [BRIDGE_TO_INTERNET.md](BRIDGE_TO_INTERNET.md) for complete documentation.
156
155
 
157
156
  **High Availability for Critical Systems**
158
157
 
159
- - 🎯 **RSSI-Based Election** - Best signal strength wins bridge role
160
- - 🔍 **Automatic Detection** - 60-second failure detection via heartbeats
161
- - **Fast Failover** - 60-70 second typical recovery time
162
- - 🌐 **Distributed Consensus** - No single coordinator, deterministic winner selection
163
- - 🛡️ **Split-Brain Prevention** - State machine prevents concurrent elections
164
- - 📊 **Tiebreaker Rules** - RSSI Uptime Memory Node ID
158
+ - 🎯 **RSSI-Based Election** - Best router signal wins the bridge role; ties go to uptime, then free memory, then node ID
159
+ - 📣 **A bridge that stops cleanly says so** - `mesh.stop()` on a bridge announces it is leaving, and the candidates hold their election within seconds
160
+ - 🔍 **Heartbeat Detection** - A bridge that loses power is noticed when its last status ages out: the bridge timeout (60 s) plus up to one 30 s monitor tick
161
+ - 🏠 **The mesh follows the bridge** - Peers learn the elected bridge's channel from the takeover message and treat it as home; a node that loses its uplink there rescans that channel first
162
+ - 🌐 **Distributed Consensus** - No single coordinator; every node evaluates the same candidates by the same rules
163
+ - 🛡️ **Split-Brain Prevention** - One election at a time, a 60 s hold between role changes, and a minimum router RSSI for a lone candidate
164
+ - 🔬 **Validated on hardware** - The failover scenario runs on the Alteriom rig with a real router; see [CHANGELOG.md](CHANGELOG.md)
165
165
 
166
166
  **Use Cases:**
167
167
  - Fish farm alarm systems requiring 24/7 Internet connectivity
@@ -184,7 +184,7 @@ void bridgeRoleCallback(bool isBridge, const String& reason) {
184
184
 
185
185
  See [bridge_failover example](examples/bridge_failover/) for complete documentation.
186
186
 
187
- #### 🌉 Multi-Bridge Coordination (v1.8.2)
187
+ #### 🌉 Multi-Bridge Coordination
188
188
 
189
189
  **Enterprise Load Balancing and Geographic Redundancy**
190
190
 
@@ -232,7 +232,7 @@ mesh.onBridgeCoordinationChanged(
232
232
 
233
233
  See [BRIDGE_TO_INTERNET.md](BRIDGE_TO_INTERNET.md) for multi-bridge documentation.
234
234
 
235
- #### 📬 Message Queue for Offline Mode (v1.8.2)
235
+ #### 📬 Message Queue for Offline Mode
236
236
 
237
237
  **Zero Data Loss During Internet Outages**
238
238
 
@@ -255,14 +255,15 @@ See [BRIDGE_TO_INTERNET.md](BRIDGE_TO_INTERNET.md) for multi-bridge documentatio
255
255
  // Enable message queue with max 100 messages
256
256
  mesh.enableMessageQueue(true, 100);
257
257
 
258
- // Queue critical alarm message
258
+ // Queue a critical alarm for the Internet endpoint; it is sent when a
259
+ // gateway with Internet is available and never evicted by lower priorities
259
260
  String criticalAlarm = "{\"sensor\":\"O2\",\"value\":2.5,\"alarm\":true}";
260
- mesh.queueMessage(bridgeNodeId, criticalAlarm);
261
+ mesh.queueMessage(criticalAlarm, "https://api.example.com/alarm", PRIORITY_CRITICAL);
261
262
  ```
262
263
 
263
264
  See [BRIDGE_TO_INTERNET.md](BRIDGE_TO_INTERNET.md) for message queue documentation.
264
265
 
265
- #### 🌐 Shared Gateway Mode (v1.9.0+)
266
+ #### 🌐 Shared Gateway Mode
266
267
 
267
268
  **All Nodes as Internet Gateways with Automatic Failover**
268
269
 
@@ -298,8 +299,8 @@ mesh.sendToInternet(
298
299
  );
299
300
 
300
301
  // Monitor gateway changes
301
- mesh.onGatewayChanged([](uint32_t newGateway) {
302
- Serial.printf("Primary gateway: %u\n", newGateway);
302
+ mesh.onGatewayChanged([](uint32_t oldGateway, uint32_t newGateway) {
303
+ Serial.printf("Primary gateway: %u -> %u\n", oldGateway, newGateway);
303
304
  });
304
305
  ```
305
306
 
@@ -331,6 +332,32 @@ The library handles routing and network management automatically, so you can foc
331
332
 
332
333
  painlessMesh is a true ad-hoc network, meaning that no-planning, central controller, or router is required. Any system of 1 or more nodes will self-organize into fully functional mesh. The maximum size of the mesh is limited (we think) by the amount of memory in the heap that can be allocated to the sub-connections buffer and so should be really quite high.
333
334
 
335
+ ### ESP8266 capacity
336
+
337
+ The ESP8266 is specified for **small meshes**, or as a **leaf** in larger ones.
338
+ Measured as an interior node of a seven-node mesh it runs at 10–13 KB free —
339
+ a working set that tracks its live connections and the traffic through them,
340
+ not a leak — and at that level a single 8 KB package or one OTA part can fail
341
+ to allocate. That is the part's limit, not a library defect. Every ESP32
342
+ family holds within a few percent of its starting heap in the same mesh.
343
+
344
+ Configure an ESP8266 as a leaf with `init(..., maxconn = 0)` (or `1` to allow
345
+ one child). The library checks every thirty seconds on ESP8266 and logs an
346
+ `ERROR` when the node is below 12 KB free with more than one child attached;
347
+ `mesh.overCapacity()` reports the same condition to the sketch, and
348
+ `mesh.apChildren()` says how many are attached.
349
+
350
+ ### Validated on hardware
351
+
352
+ Every 2.0 change to failover, routing, channel following and the station
353
+ scan was found in the serial logs of the Alteriom hardware-in-the-loop rig —
354
+ an ESP32, ESP32-C3, ESP32-C5, ESP32-C6, ESP32-S3 and ESP8266 in one mesh with
355
+ a real router — and confirmed there. The release gate is three consecutive
356
+ clean runs of the rig's whole suite (mesh formation, delivery and
357
+ acknowledgement, priorities, dedicated and shared gateways, Internet relay,
358
+ gateway failover, mesh OTA, sustained soak). Each fix in the changelog names
359
+ the run that found it.
360
+
334
361
  ### JSON based
335
362
 
336
363
  painlessMesh uses JSON objects for all its messaging. There are a couple of reasons for this. First, it makes the code and the messages human readable and painless to understand and second, it makes it painless to integrate painlessMesh with javascript front-ends, web applications, and other apps. Some performance is lost, but I haven’t been running into performance issues yet. Converting to binary messaging would be fairly straight forward if someone wants to contribute.
@@ -341,29 +368,29 @@ painlessMesh is designed to be used with Arduino, but it does not use the Arduin
341
368
 
342
369
  ### painlessMesh is not IP networking
343
370
 
344
- painlessMesh does not create a TCP/IP network of nodes. Rather each of the nodes is uniquely identified by its 32bit chipId which is retrieved from the esp8266/esp32 using the `system_get_chip_id()` call in the SDK. Every node will have a unique number. Messages can either be broadcast to all the nodes on the mesh, or sent specifically to an individual node which is identified by its `nodeId.
371
+ painlessMesh does not create a TCP/IP network of nodes. Rather each of the nodes is uniquely identified by its 32bit chipId which is retrieved from the esp8266/esp32 using the `system_get_chip_id()` call in the SDK. Every node will have a unique number. Messages can either be broadcast to all the nodes on the mesh, or sent specifically to an individual node which is identified by its `nodeId`.
345
372
 
346
373
  ### Limitations and caveats
347
374
 
348
375
  - Try to avoid using `delay()` in your code. To maintain the mesh we need to perform some tasks in the background. Using `delay()` will stop these tasks from happening and can cause the mesh to lose stability/fall apart. Instead, we recommend using [TaskScheduler](http://playground.arduino.cc/Code/TaskScheduler) which is used in `painlessMesh` itself. Documentation can be found [here](https://github.com/arkhipenko/TaskScheduler/wiki/Full-Document). For other examples on how to use the scheduler see the example folder.
349
376
  - `painlessMesh` subscribes to WiFi events. Please be aware that as a result `painlessMesh` can be incompatible with user programs/other libraries that try to bind to the same events.
350
377
  - Try to be conservative in the number of messages (and especially broadcast messages) you sent per minute. This is to prevent the hardware from overloading. Both esp8266 and esp32 are limited in processing power/memory, making it easy to overload the mesh and destabilize it. And while `painlessMesh` tries to prevent this from happening, it is not always possible to do so.
351
- - Messages can go missing or be dropped due to high traffic and you can not rely on all messages to be delivered. One suggestion to work around is to resend messages every so often. Even if some go missing, most should go through. Another option is to have your nodes send replies when they receive a message. The sending nodes can the resend the message if they haven’t gotten a reply in a certain amount of time.
378
+ - Messages can go missing or be dropped due to high traffic and you can not rely on all messages to be delivered. One suggestion to work around is to resend messages every so often. Even if some go missing, most should go through. Another option is to have your nodes send replies when they receive a message. The sending nodes can then resend the message if they haven’t gotten a reply in a certain amount of time.
352
379
 
353
380
  ## Installation
354
381
 
355
382
  ### Arduino Library Manager
356
383
 
357
- **Once registered**, installation will be available via Arduino IDE:
384
+ The library is in the Arduino Library Manager as **Alteriom PainlessMesh**:
358
385
 
359
386
  1. Open Arduino IDE
360
387
  2. Go to **Tools** → **Manage Libraries...**
361
- 3. Search for **"AlteriomPainlessMesh"**
362
- 4. Click **Install**
388
+ 3. Search for **"Alteriom PainlessMesh"** and click **Install**; accept the dependencies it offers (ArduinoJson, TaskScheduler, PubSubClient)
389
+ 4. Also install **AsyncTCP** (ESP32) or **ESPAsyncTCP** (ESP8266) from the same dialog; the Library Manager cannot pick one per platform, so they are not listed as dependencies
363
390
 
364
- The library includes the header file `AlteriomPainlessMesh.h` which provides access to both the core painlessMesh functionality and Alteriom-specific extensions.
391
+ The index follows a GitHub release within a day. The header `AlteriomPainlessMesh.h` gives access to the core painlessMesh functionality and the Alteriom extensions; `painlessMesh.h` alone gives the core.
365
392
 
366
- #### Manual Installation (Current Method)
393
+ #### Manual Installation
367
394
 
368
395
  **Option 1: Download ZIP from GitHub Release**
369
396
 
@@ -383,7 +410,12 @@ git clone https://github.com/Alteriom/painlessMesh.git AlteriomPainlessMesh
383
410
 
384
411
  ### PlatformIO
385
412
 
386
- `painlessMesh` is included in both the Arduino Library Manager and the platformio library registry and can easily be installed via either of those methods.
413
+ The library is published on the [PlatformIO registry](https://registry.platformio.org/libraries/sparck75/AlteriomPainlessMesh) as `sparck75/AlteriomPainlessMesh`. The registry also lists an `alteriom/AlteriomPainlessMesh` that stops at 1.10.0; its owner account is not one the project can publish from, so 2.0.0 and later live under `sparck75`, which has carried every automated release since 1.7.6. Name the owner in `lib_deps`, since the bare name matches both:
414
+
415
+ ```ini
416
+ lib_deps =
417
+ sparck75/AlteriomPainlessMesh@^2.0.0
418
+ ```
387
419
 
388
420
  ### Dependencies
389
421
 
@@ -392,7 +424,7 @@ painlessMesh makes use of the following libraries, which can be installed throug
392
424
  - [ArduinoJson](https://github.com/bblanchon/ArduinoJson)
393
425
  - [TaskScheduler](https://github.com/arkhipenko/TaskScheduler)
394
426
  - [ESPAsyncTCP](https://github.com/me-no-dev/ESPAsyncTCP) (ESP8266)
395
- - [AsyncTCP](https://github.com/ESP32Async/AsyncTCP) (ESP32) - v3.3.0+ required for ESP32-C6
427
+ - [AsyncTCP](https://github.com/ESP32Async/AsyncTCP) (ESP32) - v3.4.7 or later (v3.3.0 was the first to work on the ESP32-C6)
396
428
 
397
429
  If platformio is used to install the library, then the dependencies will be installed automatically.
398
430
 
@@ -502,9 +534,13 @@ These types are used internally by painlessMesh for mesh management and are hand
502
534
  | 4 | `TIME_SYNC` | Time synchronization protocol messages |
503
535
  | 5 | `NODE_SYNC_REQUEST` | Node discovery and topology requests |
504
536
  | 6 | `NODE_SYNC_REPLY` | Node discovery and topology responses |
505
- | 7 | `CONTROL` | Deprecated control messages |
506
- | 8 | `BROADCAST` | Internal broadcast routing indicator |
507
- | 9 | `SINGLE` | Internal single-node routing indicator |
537
+ | 7 | `CONTROL` | Deprecated, unused |
538
+ | 8 | `BROADCAST` | Application data for every node |
539
+ | 9 | `SINGLE` | Application data for one node |
540
+ | 620 | `GATEWAY_DATA` | An Internet request routed to a gateway (`sendToInternet()`) |
541
+ | 621 | `GATEWAY_ACK` | The gateway's answer to it |
542
+ | 622 | `GATEWAY_HEARTBEAT` | Gateway health monitoring |
543
+ | 630 | `MESSAGE_ACK` | Delivery confirmation for a message sent with a callback (2.0) |
508
544
 
509
545
  **Note**: These protocol types are managed automatically by painlessMesh and are not typically used in application code.
510
546
 
@@ -516,19 +552,19 @@ These are the message types used by applications built on painlessMesh:
516
552
  |------|-------|---------|--------|
517
553
  | 200 | `SensorPackage` | Environmental data | `temperature`, `humidity`, `pressure`, `sensorId`, `timestamp`, `batteryLevel` |
518
554
  | 202 | `StatusPackage` | Health monitoring | `deviceStatus`, `uptime`, `freeMemory`, `wifiStrength`, `firmwareVersion` |
519
- | 204 | `MetricsPackage` | Sensor metrics (v1.7.7+, aligns with schema v0.7.2+) | `cpuUsage`, `freeHeap`, `bytesReceived`, `currentThroughput`, `connectionQuality`, `wifiRSSI` |
520
- | 400 | `CommandPackage` | Device control (v1.7.7+, moved from 201) | `command`, `targetDevice`, `parameters`, `commandId` |
521
- | 600 | `MeshNodeListPackage` | Mesh node list (v1.7.7+, MESH_NODE_LIST) | `nodes[]` (nodeId, status, lastSeen, signalStrength), `nodeCount`, `meshId` |
522
- | 601 | `MeshTopologyPackage` | Mesh topology (v1.7.7+, MESH_TOPOLOGY) | `connections[]` (fromNode, toNode, linkQuality, latencyMs), `rootNode` |
523
- | 602 | `MeshAlertPackage` | Mesh alerts (v1.7.7+, MESH_ALERT) | `alerts[]` (alertType, severity, message, nodeId), `alertCount` |
524
- | 603 | `MeshBridgePackage` | Mesh bridge (v1.7.7+, MESH_BRIDGE) | `meshProtocol`, `fromNodeId`, `toNodeId`, `meshType`, `rawPayload`, `rssi`, `hopCount` |
555
+ | 204 | `MetricsPackage` | Sensor metrics (schema v0.7.2+) | `cpuUsage`, `freeHeap`, `bytesReceived`, `currentThroughput`, `connectionQuality`, `wifiRSSI` |
556
+ | 400 | `CommandPackage` | Device control | `command`, `targetDevice`, `parameters`, `commandId` |
557
+ | 600 | `MeshNodeListPackage` | Mesh node list (`MESH_NODE_LIST`) | `nodes[]` (nodeId, status, lastSeen, signalStrength), `nodeCount`, `meshId` |
558
+ | 601 | `MeshTopologyPackage` | Mesh topology (`MESH_TOPOLOGY`) | `connections[]` (fromNode, toNode, linkQuality, latencyMs), `rootNode` |
559
+ | 602 | `MeshAlertPackage` | Mesh alerts (`MESH_ALERT`) | `alerts[]` (alertType, severity, message, nodeId), `alertCount` |
560
+ | 603 | `MeshBridgePackage` | Mesh bridge (`MESH_BRIDGE`) | `meshProtocol`, `fromNodeId`, `toNodeId`, `meshType`, `rawPayload`, `rssi`, `hopCount` |
525
561
  | 604 | `EnhancedStatusPackage` | Mesh status (MESH_STATUS per schema v0.7.2+) | `nodeCount`, `connectionCount`, `messagesReceived`, `messagesSent`, `avgLatency`, `packetLossRate` |
526
- | 605 | `HealthCheckPackage` | Mesh metrics (v1.7.7+, MESH_METRICS per schema v0.7.2+) | `healthStatus`, `problemFlags`, `memoryHealth`, `networkHealth`, `performanceHealth`, `recommendations` |
527
- | 610 | `BridgeStatusPackage` | Bridge health monitoring (v1.8.0+, BRIDGE_STATUS per schema v0.7.3+) | `internetConnected`, `routerRSSI`, `routerChannel`, `uptime`, `gatewayIP`, `timestamp` |
528
- | 611 | `BridgeElectionPackage` | Bridge failover election (v1.8.0+, BRIDGE_ELECTION per schema v0.7.3+) | `routerRSSI`, `uptime`, `freeMemory`, `timestamp`, `routerSSID` |
529
- | 612 | `BridgeTakeoverPackage` | Bridge role announcement (v1.8.0+, BRIDGE_TAKEOVER per schema v0.7.3+) | `previousBridge`, `reason`, `timestamp` |
530
- | 613 | `BridgeCoordinationPackage` | Multi-bridge coordination (v1.8.2+, BRIDGE_COORDINATION) | `priority`, `role`, `peerBridges[]`, `load`, `timestamp` |
531
- | 614 | `NTPTimeSyncPackage` | NTP time synchronization (v1.8.0+, TIME_SYNC_NTP per schema v0.7.3+) | `ntpTime`, `accuracy`, `source`, `timestamp` |
562
+ | 605 | `HealthCheckPackage` | Mesh metrics (`MESH_METRICS`, schema v0.7.2+) | `healthStatus`, `problemFlags`, `memoryHealth`, `networkHealth`, `performanceHealth`, `recommendations` |
563
+ | 610 | `BridgeStatusPackage` | Bridge health monitoring (`BRIDGE_STATUS`) | `internetConnected`, `routerRSSI`, `routerChannel`, `uptime`, `gatewayIP`, `timestamp` |
564
+ | 611 | `BridgeElectionPackage` | Bridge failover election (`BRIDGE_ELECTION`) | `routerRSSI`, `routerChannel`, `uptime`, `freeMemory`, `timestamp`, `routerSSID` |
565
+ | 612 | `BridgeTakeoverPackage` | Bridge role announcement (`BRIDGE_TAKEOVER`) | `previousBridge`, `reason`, `routerChannel`, `timestamp` |
566
+ | 613 | `BridgeCoordinationPackage` | Multi-bridge coordination (`BRIDGE_COORDINATION`) | `priority`, `role`, `peerBridges[]`, `load`, `timestamp` |
567
+ | 614 | `NTPTimeSyncPackage` | NTP time synchronization (`TIME_SYNC_NTP`) | `ntpTime`, `accuracy`, `source`, `timestamp` |
532
568
 
533
569
  ## Key Features
534
570
 
@@ -560,54 +596,25 @@ These are the message types used by applications built on painlessMesh:
560
596
  - **Event Coordination** - Synchronized displays, distributed processing
561
597
  - **Bridge Networks** - Connect mesh to WiFi/Internet/MQTT - [📖 Bridge Guide](BRIDGE_TO_INTERNET.md)
562
598
 
563
- ## Latest Release: v1.10.0 (August 12, 2026)
564
-
565
- **Tunable TCP Connect-Retry Behaviour (issue #378)**
566
-
567
- - The five TCP connect-retry values that were hardcoded in `tcp.hpp` are now tunable per mesh instance via `mesh.setTcpRetryConfig()` / `mesh.getTcpRetryConfig()` (#378, PR #395)
568
- - Defaults match the previous constants exactly — **no behaviour change unless you call the setter**
569
- - New `examples/tcpRetryConfig/` with real-time, high-reliability and battery-saver profiles
570
- - `MessageQueue` documentation corrected: it is a manual buffer, never an auto-flush queue (#385)
571
- - `MIN_FREE_MEMORY` / `MAX_MESSAGE_QUEUE` deprecated as ignored no-ops, values preserved for source compatibility (#385)
572
- - Fixed `bridge_failover` example failing to compile on an unqualified `plugin::` type (#360)
573
-
574
- > **npm users:** v1.9.21 was never published to npm ([#381](https://github.com/Alteriom/painlessMesh/issues/381) — expired token). npm's previous version is 1.9.20, so upgrading from npm picks up both releases. GitHub, PlatformIO and Arduino were unaffected.
575
-
576
- **Previous Release: v1.9.21 (August 4, 2026)**
577
-
578
- **Crash Fixes: Task & TCP Connection Lifecycle (issue #373)**
599
+ ## Latest Release: v2.0.1 (September 7, 2026)
579
600
 
580
- - Fixed use-after-free in `Task::disable()` that crashed nodes on every peer disconnect (#373, PR #376 by @vaz82)
581
- - Fixed `PackageHandler::stop()` destroying the currently-executing task during bridge promotion
582
- - Fixed stale-pcb heap corruption window in `~BufferedConnection()` and an `onError`/`onConnect` double-handling race
583
- - New AddressSanitizer CI job and regression test for the task/connection cleanup lifecycle
601
+ **A packaging fix over 2.0.0 — no library behaviour changed.** 2.0.0's installation instructions named a PlatformIO package that has no 2.0.0 (`alteriom/…` stops at 1.10.0; releases go out under `sparck75`), and its GitHub release carries no library archive because the upload was refused by an immutable release. Both are fixed; upgrading from 2.0.0 is optional.
584
602
 
585
- **Previous Release: v1.9.20 (March 27, 2026)** Full repo cleanup, bug fixes & bridge coordination callbacks:
603
+ **2.0.0 delivery confirmation, a unified send path, and a mesh that holds together on real hardware**
586
604
 
587
- - New `onBridgeCoordination()` and `onBridgeCoordinationChanged()` monitoring callbacks
588
- - Fixed 13 critical/high/medium bugs (double-free, RSSI overflow, memory leaks, blocking delays)
589
- - Removed ~3,600 lines of dead code and 40 AI-generated docs
590
- - Fixed all CI/CD workflows (corrected action versions)
591
- - Removed 15 fake test files, fixed test infrastructure
592
- - Documentation consistency audit — fixed broken links, API examples, version references
593
-
594
- **Recent Key Features (v1.9.0 - v1.9.16):**
595
-
596
- - 🔍 **Mesh Connectivity Detection** - New `hasActiveMeshConnections()` and `getLastKnownBridge()` APIs
597
- - 🌉 **Improved Bridge Detection** - `getPrimaryBridge()` returns last known bridge when disconnected
598
- - ⚡ **Enhanced TCP Reliability** - Exponential backoff and increased retries for mesh connections
599
- - 🛡️ **Race Condition Fixes** - Improved bridge status and connection validation
600
- - 📦 **Consolidated Examples** - Streamlined to 15 essential examples
601
- - ⚙️ **Configurable Election Timing** - Prevent split-brain with `setElectionStartupDelay()` and `setElectionRandomDelay()`
605
+ - `sendSingle()` and `sendBroadcast()` accept a delivery callback — it fires with `delivered=true` and the round-trip latency on acknowledgment, or `delivered=false` on timeout — and a `SendOptions` struct that carries a priority and a callback in one call. Priority is kept across hops.
606
+ - Thirty-odd defects in gateway failover, channel following, routing and the station scan, every one found in the serial logs of a six-family hardware rig and fixed there: a bridge that stops says so, the mesh follows an elected bridge to its channel and treats it as home, a node is in one place in every neighbour's tree, a dead connection is not a route, a stale scan does not consume a live one.
607
+ - The ESP32-C5 and ESP32-C6 (Arduino core 3.x) no longer hang after a channel follow; the ESP8266 is specified for small meshes or as a leaf, and says so at runtime.
608
+ - Gateway HTTP work is bounded by `NODE_TIMEOUT`, so an Internet request can no longer partition the mesh around its own gateway.
609
+ - The release candidate passed the rig's whole suite three times in a row. Delivery confirmation and cross-hop priority need 2.0 on every node of the path.
602
610
 
603
611
  **[📋 Full CHANGELOG](CHANGELOG.md)**
604
612
 
605
613
  ## Getting Help
606
614
 
607
- - **[FAQ](USER_GUIDE.md)** - Common questions and solutions
608
- - **[Common Issues](USER_GUIDE.md)** - Troubleshooting guide
615
+ - **[Troubleshooting](USER_GUIDE.md#troubleshooting)** - Common issues, debug configuration, best practices
616
+ - **[FAQ](docsify-site/troubleshooting/faq.md)** - Frequently asked questions
609
617
  - **[GitHub Issues](https://github.com/Alteriom/painlessMesh/issues)** - Bug reports and feature requests
610
- - **[Community Forum](https://groups.google.com/forum/#!forum/painlessmesh-user)** - Community support
611
618
  - **[API Documentation](https://alteriom.github.io/painlessMesh/#/api/doxygen)** - Generated API docs
612
619
 
613
620
  ## Development
@@ -625,7 +632,8 @@ run-parts --regex catch_ bin/ # Run tests
625
632
 
626
633
  ### Requirements
627
634
 
628
- - **ESP32/ESP8266**: Arduino Core 2.0.0+
635
+ - **ESP32**: Arduino core 2.0.x or 3.x; the ESP32-C5 and ESP32-C6 need 3.x
636
+ - **ESP8266**: Arduino core 3.x
629
637
  - **Dependencies**: ArduinoJson 7.x, TaskScheduler 4.x
630
638
  - **Development**: CMake, Ninja, Boost (for desktop testing)
631
639
 
@@ -678,7 +686,7 @@ painlessMesh features a state-of-the-art automated CI/CD pipeline:
678
686
  ./scripts/validate-release.sh # Validate release readiness
679
687
 
680
688
  # Edit CHANGELOG.md, then commit with release prefix
681
- git commit -am "release: v1.5.7"
689
+ git commit -am "release: vX.Y.Z"
682
690
  git push origin main # Triggers automated release
683
691
  ```
684
692
 
@@ -686,13 +694,8 @@ See [RELEASE_GUIDE.md](RELEASE_GUIDE.md) for complete release documentation.
686
694
 
687
695
  ## Contributing
688
696
 
689
- We try to follow the [git flow](https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow) development model. Which means that we have a `develop` branch and `main` branch. All development is done under feature branches, which are (when finished) merged into the development branch. When a new version is released we merge the `develop` branch into the `main` branch. For more details see the [CONTRIBUTING.md](CONTRIBUTING.md) file.
690
-
691
- ## Funding
692
-
693
- If you like the library please consider supporting its development. Your contributions help me spend more time improving painlessMesh.
697
+ Pull requests go to `Feat/next-release`, the integration branch for the next version; `main` holds released code and a push to it publishes a release. For branches, tests and what a pull request needs to show, see [CONTRIBUTING.md](CONTRIBUTING.md).
694
698
 
695
- **[Donate via PayPal](https://www.paypal.com/paypalme/domlavoie)** • [dominic.lavoie@gmail.com](mailto:dominic.lavoie@gmail.com)
696
699
 
697
700
  ## 📚 Documentation
698
701
 
@@ -708,18 +711,18 @@ If you like the library please consider supporting its development. Your contrib
708
711
  ### 🚀 Quick Links
709
712
 
710
713
  **New to AlteriomPainlessMesh?**
711
- - [Quick Start](USER_GUIDE.md) - Get your first mesh running in 5 minutes
712
- - [Installation](USER_GUIDE.md) - Arduino IDE and PlatformIO setup
713
- - [First Mesh](USER_GUIDE.md) - Build a multi-node network
714
+ - [Quick Start](USER_GUIDE.md#getting-started) - Get your first mesh running in 5 minutes
715
+ - [Installation](USER_GUIDE.md#installation) - Arduino IDE and PlatformIO setup
716
+ - [First Mesh](USER_GUIDE.md#your-first-mesh-network) - Build a multi-node network
714
717
 
715
718
  **Reference Documentation:**
716
- - [Core API](USER_GUIDE.md) - painlessMesh class methods
719
+ - [Core API](USER_GUIDE.md#api-reference) - painlessMesh class methods
717
720
  - [Alteriom Extensions](examples/alteriom/README.md) - SensorPackage, CommandPackage, StatusPackage
718
- - [Examples](examples/) - 15 working examples for common scenarios
721
+ - [Examples](examples/) - 18 example directories, 21 sketches, every one compiled for esp32 and esp8266 on each pull request; [.github/DOCUMENTATION.md](.github/DOCUMENTATION.md) lists what each shows
719
722
 
720
723
  **Need Help?**
721
- - [FAQ](USER_GUIDE.md) - Frequently asked questions
722
- - [Common Issues](USER_GUIDE.md) - Troubleshooting guide
724
+ - [Troubleshooting](USER_GUIDE.md#troubleshooting) - Common issues and how to read the logs
725
+ - [FAQ](docsify-site/troubleshooting/faq.md) - Frequently asked questions
723
726
  - [GitHub Issues](https://github.com/Alteriom/painlessMesh/issues) - Bug reports and support
724
727
 
725
728
  ## 🔧 Quick API Reference
@@ -755,7 +758,11 @@ mesh.setDebugMsgTypes(ERROR | STARTUP | CONNECTION);
755
758
 
756
759
  **For complete API documentation, see [USER_GUIDE.md](USER_GUIDE.md#api-reference) or [online docs](https://alteriom.github.io/painlessMesh/#/api/core-api).**
757
760
 
758
- # Funding
761
+ ## Funding
762
+
763
+ If you like the library please consider supporting its development. Your contributions help me spend more time improving painlessMesh.
764
+
765
+ **[Donate via PayPal](https://www.paypal.com/paypalme/domlavoie)** • [dominic.lavoie@gmail.com](mailto:dominic.lavoie@gmail.com)
759
766
 
760
767
  Most development of painlessMesh has been done as a hobby, but some specific features have been funded by the companies listed below:
761
768