@alteriom/painlessmesh 1.8.12 → 1.8.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 +15 -0
- package/library.json +1 -1
- package/library.properties +1 -1
- package/package.json +2 -2
- package/src/AlteriomPainlessMesh.h +2 -2
- package/src/arduino/wifi.hpp +57 -20
- package/src/painlessMesh.h +2 -2
- package/src/painlessmesh/mesh.hpp +2 -2
- package/src/painlessmesh/protocol.hpp +7 -0
- package/RELEASE_NOTES_1.8.12.md +0 -96
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.8.14] - 2025-11-21
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- **Bridge Internet Detection** - Fixed `hasInternetConnection()` returning false on bridge nodes immediately after initialization
|
|
15
|
+
- **Root Cause**: Base `hasInternetConnection()` only checked `knownBridges` list; bridge self-registration happens asynchronously
|
|
16
|
+
- Added override in Arduino `wifi::Mesh` to check local WiFi status before checking remote bridges
|
|
17
|
+
- Bridge nodes now immediately report correct internet status via `WiFi.status()` check
|
|
18
|
+
- Fixes issue where internet-dependent features (like WhatsApp messaging) failed on bridge nodes
|
|
19
|
+
- **Impact**: Bridge nodes correctly report internet connectivity immediately after initialization
|
|
20
|
+
- **Affected Components**: Bridge_fallover example, any code using `mesh.hasInternetConnection()` on bridge nodes
|
|
21
|
+
- Core fix in `src/arduino/wifi.hpp` - added WiFi status check override
|
|
22
|
+
- Resolves GitHub issue #159
|
|
23
|
+
- Merged via PR #160
|
|
24
|
+
|
|
10
25
|
## [1.8.12] - 2025-11-19
|
|
11
26
|
|
|
12
27
|
### Changed
|
package/library.json
CHANGED
package/library.properties
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
name=Alteriom PainlessMesh
|
|
2
|
-
version=1.8.
|
|
2
|
+
version=1.8.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.8.
|
|
3
|
+
"version": "1.8.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",
|
|
@@ -85,6 +85,6 @@
|
|
|
85
85
|
"CHANGELOG.md",
|
|
86
86
|
"RELEASE_GUIDE.md",
|
|
87
87
|
"DOCUMENTATION_INDEX.md",
|
|
88
|
-
"RELEASE_NOTES_1.8.
|
|
88
|
+
"RELEASE_NOTES_1.8.13.md"
|
|
89
89
|
]
|
|
90
90
|
}
|
|
@@ -29,10 +29,10 @@
|
|
|
29
29
|
/**
|
|
30
30
|
* @brief AlteriomPainlessMesh library version information
|
|
31
31
|
*/
|
|
32
|
-
#define ALTERIOM_PAINLESS_MESH_VERSION "1.8.
|
|
32
|
+
#define ALTERIOM_PAINLESS_MESH_VERSION "1.8.13"
|
|
33
33
|
#define ALTERIOM_PAINLESS_MESH_VERSION_MAJOR 1
|
|
34
34
|
#define ALTERIOM_PAINLESS_MESH_VERSION_MINOR 8
|
|
35
|
-
#define ALTERIOM_PAINLESS_MESH_VERSION_PATCH
|
|
35
|
+
#define ALTERIOM_PAINLESS_MESH_VERSION_PATCH 13
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
38
|
* @brief Library description and usage information
|
package/src/arduino/wifi.hpp
CHANGED
|
@@ -89,9 +89,9 @@ class Mesh : public painlessmesh::Mesh<Connection> {
|
|
|
89
89
|
|
|
90
90
|
this->init(nodeId);
|
|
91
91
|
|
|
92
|
-
// Add bridge election package handler (Type
|
|
92
|
+
// Add bridge election package handler (Type BRIDGE_ELECTION)
|
|
93
93
|
this->callbackList.onPackage(
|
|
94
|
-
|
|
94
|
+
protocol::BRIDGE_ELECTION,
|
|
95
95
|
[this](protocol::Variant& variant, std::shared_ptr<Connection>, uint32_t) {
|
|
96
96
|
JsonDocument doc;
|
|
97
97
|
TSTRING str;
|
|
@@ -113,9 +113,9 @@ class Mesh : public painlessmesh::Mesh<Connection> {
|
|
|
113
113
|
return false; // Don't consume the package
|
|
114
114
|
});
|
|
115
115
|
|
|
116
|
-
// Add bridge takeover package handler (Type
|
|
116
|
+
// Add bridge takeover package handler (Type BRIDGE_TAKEOVER)
|
|
117
117
|
this->callbackList.onPackage(
|
|
118
|
-
|
|
118
|
+
protocol::BRIDGE_TAKEOVER,
|
|
119
119
|
[this](protocol::Variant& variant, std::shared_ptr<Connection>, uint32_t) {
|
|
120
120
|
JsonDocument doc;
|
|
121
121
|
TSTRING str;
|
|
@@ -618,6 +618,28 @@ class Mesh : public painlessmesh::Mesh<Connection> {
|
|
|
618
618
|
return activeBridges;
|
|
619
619
|
}
|
|
620
620
|
|
|
621
|
+
/**
|
|
622
|
+
* Check if any bridge in the mesh has Internet connectivity
|
|
623
|
+
*
|
|
624
|
+
* Override of base class method to also check if THIS node is a bridge
|
|
625
|
+
* with Internet connectivity, not just other bridges in the mesh.
|
|
626
|
+
*
|
|
627
|
+
* @return true if at least one bridge (including this node) has Internet
|
|
628
|
+
*/
|
|
629
|
+
bool hasInternetConnection() {
|
|
630
|
+
// First check if THIS node is a bridge with Internet
|
|
631
|
+
if (this->isBridge()) {
|
|
632
|
+
// Check Internet connectivity: WiFi connected AND valid IP address
|
|
633
|
+
bool hasInternet = (WiFi.status() == WL_CONNECTED) && (WiFi.localIP() != IPAddress(0, 0, 0, 0));
|
|
634
|
+
if (hasInternet) {
|
|
635
|
+
return true;
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
// Then check other bridges in the mesh (call parent implementation)
|
|
640
|
+
return painlessmesh::Mesh<Connection>::hasInternetConnection();
|
|
641
|
+
}
|
|
642
|
+
|
|
621
643
|
/**
|
|
622
644
|
* Get recommended bridge for message transmission
|
|
623
645
|
*
|
|
@@ -817,7 +839,7 @@ class Mesh : public painlessmesh::Mesh<Connection> {
|
|
|
817
839
|
JsonDocument doc;
|
|
818
840
|
JsonObject obj = doc.to<JsonObject>();
|
|
819
841
|
|
|
820
|
-
obj["type"] =
|
|
842
|
+
obj["type"] = protocol::BRIDGE_STATUS;
|
|
821
843
|
obj["from"] = this->nodeId;
|
|
822
844
|
obj["routing"] = 1; // SINGLE routing (direct to node)
|
|
823
845
|
obj["dest"] = nodeId;
|
|
@@ -830,7 +852,7 @@ class Mesh : public painlessmesh::Mesh<Connection> {
|
|
|
830
852
|
obj["routerChannel"] = WiFi.channel();
|
|
831
853
|
obj["uptime"] = millis();
|
|
832
854
|
obj["gatewayIP"] = WiFi.gatewayIP().toString();
|
|
833
|
-
obj["message_type"] =
|
|
855
|
+
obj["message_type"] = protocol::BRIDGE_STATUS;
|
|
834
856
|
|
|
835
857
|
String msg;
|
|
836
858
|
serializeJson(doc, msg);
|
|
@@ -838,8 +860,10 @@ class Mesh : public painlessmesh::Mesh<Connection> {
|
|
|
838
860
|
Log(CONNECTION, "Sending bridge status directly to node %u (Internet: %s)\n",
|
|
839
861
|
nodeId, hasInternet ? "YES" : "NO");
|
|
840
862
|
|
|
841
|
-
// Send directly to the new node using
|
|
842
|
-
|
|
863
|
+
// Send directly to the new node using raw message to preserve type BRIDGE_STATUS
|
|
864
|
+
// Using sendSingle() would wrap it in type 1 (SINGLE) and hide type BRIDGE_STATUS
|
|
865
|
+
protocol::Variant variant(msg);
|
|
866
|
+
router::send<Connection>(variant, (*this));
|
|
843
867
|
});
|
|
844
868
|
});
|
|
845
869
|
|
|
@@ -1072,7 +1096,7 @@ class Mesh : public painlessmesh::Mesh<Connection> {
|
|
|
1072
1096
|
// Broadcast candidacy using JSON directly (avoiding dependency on alteriom package)
|
|
1073
1097
|
JsonDocument doc;
|
|
1074
1098
|
JsonObject obj = doc.to<JsonObject>();
|
|
1075
|
-
obj["type"] =
|
|
1099
|
+
obj["type"] = protocol::BRIDGE_ELECTION;
|
|
1076
1100
|
obj["from"] = this->nodeId;
|
|
1077
1101
|
obj["routing"] = 2; // BROADCAST
|
|
1078
1102
|
obj["routerRSSI"] = routerRSSI;
|
|
@@ -1080,11 +1104,14 @@ class Mesh : public painlessmesh::Mesh<Connection> {
|
|
|
1080
1104
|
obj["freeMemory"] = ESP.getFreeHeap();
|
|
1081
1105
|
obj["timestamp"] = this->getNodeTime();
|
|
1082
1106
|
obj["routerSSID"] = routerSSID;
|
|
1083
|
-
obj["message_type"] =
|
|
1107
|
+
obj["message_type"] = protocol::BRIDGE_ELECTION;
|
|
1084
1108
|
|
|
1085
1109
|
String msg;
|
|
1086
1110
|
serializeJson(doc, msg);
|
|
1087
|
-
|
|
1111
|
+
|
|
1112
|
+
// Send election message using raw broadcast to preserve type BRIDGE_ELECTION
|
|
1113
|
+
protocol::Variant variant(msg);
|
|
1114
|
+
router::broadcast<protocol::Variant, Connection>(variant, (*this), 0);
|
|
1088
1115
|
|
|
1089
1116
|
Log(CONNECTION, "startBridgeElection(): Candidacy broadcast sent\n");
|
|
1090
1117
|
|
|
@@ -1223,18 +1250,21 @@ class Mesh : public painlessmesh::Mesh<Connection> {
|
|
|
1223
1250
|
Log(STARTUP, "Sending takeover announcement on current channel before switching...\n");
|
|
1224
1251
|
JsonDocument doc;
|
|
1225
1252
|
JsonObject obj = doc.to<JsonObject>();
|
|
1226
|
-
obj["type"] =
|
|
1253
|
+
obj["type"] = protocol::BRIDGE_TAKEOVER;
|
|
1227
1254
|
obj["from"] = this->nodeId;
|
|
1228
1255
|
obj["routing"] = 2; // BROADCAST
|
|
1229
1256
|
obj["previousBridge"] = previousBridgeId;
|
|
1230
1257
|
obj["reason"] = "Election winner - best router signal";
|
|
1231
1258
|
obj["routerRSSI"] = 0; // Not yet connected to router
|
|
1232
1259
|
obj["timestamp"] = this->getNodeTime();
|
|
1233
|
-
obj["message_type"] =
|
|
1260
|
+
obj["message_type"] = protocol::BRIDGE_TAKEOVER;
|
|
1234
1261
|
|
|
1235
1262
|
String msg;
|
|
1236
1263
|
serializeJson(doc, msg);
|
|
1237
|
-
|
|
1264
|
+
|
|
1265
|
+
// Send takeover message using raw broadcast to preserve type BRIDGE_TAKEOVER
|
|
1266
|
+
protocol::Variant variant(msg);
|
|
1267
|
+
router::broadcast<protocol::Variant, Connection>(variant, (*this), 0);
|
|
1238
1268
|
|
|
1239
1269
|
// Give time for announcement to propagate before channel switch
|
|
1240
1270
|
delay(1000);
|
|
@@ -1263,18 +1293,22 @@ class Mesh : public painlessmesh::Mesh<Connection> {
|
|
|
1263
1293
|
Log(STARTUP, "Sending follow-up takeover announcement on new channel %d\n", _meshChannel);
|
|
1264
1294
|
JsonDocument doc2;
|
|
1265
1295
|
JsonObject obj2 = doc2.to<JsonObject>();
|
|
1266
|
-
obj2["type"] =
|
|
1296
|
+
obj2["type"] = protocol::BRIDGE_TAKEOVER;
|
|
1267
1297
|
obj2["from"] = this->nodeId;
|
|
1268
1298
|
obj2["routing"] = 2; // BROADCAST
|
|
1269
1299
|
obj2["previousBridge"] = previousBridgeId;
|
|
1270
1300
|
obj2["reason"] = "Election winner - best router signal";
|
|
1271
1301
|
obj2["routerRSSI"] = WiFi.RSSI();
|
|
1272
1302
|
obj2["timestamp"] = this->getNodeTime();
|
|
1273
|
-
obj2["message_type"] =
|
|
1303
|
+
obj2["message_type"] = protocol::BRIDGE_TAKEOVER;
|
|
1274
1304
|
|
|
1275
1305
|
String msg2;
|
|
1276
1306
|
serializeJson(doc2, msg2);
|
|
1277
|
-
|
|
1307
|
+
|
|
1308
|
+
// Send follow-up takeover using raw broadcast to preserve type BRIDGE_TAKEOVER
|
|
1309
|
+
protocol::Variant variant2(msg2);
|
|
1310
|
+
router::broadcast<protocol::Variant, Connection>(variant2, (*this), 0);
|
|
1311
|
+
|
|
1278
1312
|
Log(STARTUP, "✓ Follow-up takeover announcement sent\n");
|
|
1279
1313
|
});
|
|
1280
1314
|
}
|
|
@@ -1329,7 +1363,7 @@ class Mesh : public painlessmesh::Mesh<Connection> {
|
|
|
1329
1363
|
JsonDocument doc;
|
|
1330
1364
|
JsonObject obj = doc.to<JsonObject>();
|
|
1331
1365
|
|
|
1332
|
-
obj["type"] =
|
|
1366
|
+
obj["type"] = protocol::BRIDGE_STATUS;
|
|
1333
1367
|
obj["from"] = this->nodeId;
|
|
1334
1368
|
obj["routing"] = 2; // BROADCAST routing
|
|
1335
1369
|
obj["timestamp"] = this->getNodeTime();
|
|
@@ -1352,7 +1386,7 @@ class Mesh : public painlessmesh::Mesh<Connection> {
|
|
|
1352
1386
|
obj["routerChannel"] = channel;
|
|
1353
1387
|
obj["uptime"] = uptime;
|
|
1354
1388
|
obj["gatewayIP"] = gatewayIP;
|
|
1355
|
-
obj["message_type"] =
|
|
1389
|
+
obj["message_type"] = protocol::BRIDGE_STATUS;
|
|
1356
1390
|
|
|
1357
1391
|
String msg;
|
|
1358
1392
|
serializeJson(doc, msg);
|
|
@@ -1367,7 +1401,10 @@ class Mesh : public painlessmesh::Mesh<Connection> {
|
|
|
1367
1401
|
this->updateBridgeStatus(this->nodeId, hasInternet, rssi, channel,
|
|
1368
1402
|
uptime, gatewayIP, this->getNodeTime());
|
|
1369
1403
|
|
|
1370
|
-
|
|
1404
|
+
// Send bridge status using raw broadcast to preserve type BRIDGE_STATUS
|
|
1405
|
+
// Using sendBroadcast(msg) would wrap it in type 8 (BROADCAST) and hide type BRIDGE_STATUS
|
|
1406
|
+
protocol::Variant variant(msg);
|
|
1407
|
+
router::broadcast<protocol::Variant, Connection>(variant, (*this), 0);
|
|
1371
1408
|
}
|
|
1372
1409
|
void eventHandleInit() {
|
|
1373
1410
|
using namespace logger;
|
package/src/painlessMesh.h
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* @file painlessMesh.h
|
|
6
6
|
* @brief Main header file for Alteriom painlessMesh library
|
|
7
7
|
*
|
|
8
|
-
* @version 1.8.
|
|
9
|
-
* @date 2025-11-
|
|
8
|
+
* @version 1.8.13
|
|
9
|
+
* @date 2025-11-20
|
|
10
10
|
*
|
|
11
11
|
* painlessMesh is a user-friendly library for creating mesh networks with
|
|
12
12
|
* ESP8266 and ESP32 devices. This Alteriom fork includes additional packages
|
|
@@ -167,10 +167,10 @@ class Mesh : public ntp::MeshTime, public plugin::PackageHandler<T> {
|
|
|
167
167
|
this->callbackList = painlessmesh::router::addPackageCallback(
|
|
168
168
|
std::move(this->callbackList), (*this));
|
|
169
169
|
|
|
170
|
-
// Add bridge status package handler (Type
|
|
170
|
+
// Add bridge status package handler (Type BRIDGE_STATUS)
|
|
171
171
|
// This will be called when any node receives a bridge status broadcast
|
|
172
172
|
this->callbackList.onPackage(
|
|
173
|
-
|
|
173
|
+
protocol::BRIDGE_STATUS,
|
|
174
174
|
[this](protocol::Variant& variant, std::shared_ptr<T>, uint32_t) {
|
|
175
175
|
// We need to manually parse the JSON since BridgeStatusPackage is in alteriom namespace
|
|
176
176
|
// and may not be available in all contexts. We'll parse the critical fields directly.
|
|
@@ -49,6 +49,13 @@ enum TimeType {
|
|
|
49
49
|
TIME_REPLY
|
|
50
50
|
};
|
|
51
51
|
|
|
52
|
+
// Bridge protocol package types
|
|
53
|
+
// These are used for bridge discovery, election, and coordination
|
|
54
|
+
constexpr int BRIDGE_STATUS = 610; // Bridge status broadcast (internet, RSSI, etc.)
|
|
55
|
+
constexpr int BRIDGE_ELECTION = 611; // Bridge election candidacy announcement
|
|
56
|
+
constexpr int BRIDGE_TAKEOVER = 612; // Bridge takeover notification
|
|
57
|
+
constexpr int BRIDGE_COORDINATION = 613; // Multi-bridge coordination (defined in plugin.hpp)
|
|
58
|
+
|
|
52
59
|
class PackageInterface {
|
|
53
60
|
public:
|
|
54
61
|
virtual JsonObject addTo(JsonObject&& jsonObj) const = 0;
|
package/RELEASE_NOTES_1.8.12.md
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
# Release Notes - Version 1.8.12
|
|
2
|
-
|
|
3
|
-
**Release Date:** 2025-11-19
|
|
4
|
-
|
|
5
|
-
## Overview
|
|
6
|
-
|
|
7
|
-
Version 1.8.12 is a maintenance release focused on documentation improvements and code quality enhancements. This release includes changes from PRs #152 and #153, ensuring comprehensive documentation coverage and adherence to code formatting standards.
|
|
8
|
-
|
|
9
|
-
## What's New
|
|
10
|
-
|
|
11
|
-
### Documentation Enhancements
|
|
12
|
-
|
|
13
|
-
- **Comprehensive Documentation Review** - All documentation has been reviewed and updated to reflect the current state of the library
|
|
14
|
-
- **API Reference Updates** - Improved clarity and completeness in API documentation
|
|
15
|
-
- **Example Code Documentation** - Enhanced inline documentation for example projects
|
|
16
|
-
- **Package Documentation** - Updated documentation for all Alteriom custom packages
|
|
17
|
-
|
|
18
|
-
### Code Quality Improvements
|
|
19
|
-
|
|
20
|
-
- **Prettier Configuration** - Added prettier configuration for consistent JSON and Markdown formatting
|
|
21
|
-
- New `.prettierrc` configuration file
|
|
22
|
-
- New `.prettierignore` file to exclude build artifacts and dependencies
|
|
23
|
-
- Added `npm run format` and `npm run format:check` scripts
|
|
24
|
-
- **Clang-Format Compliance** - Ensured all C++ code follows established formatting standards
|
|
25
|
-
- **Code Organization** - Improved code structure and maintainability
|
|
26
|
-
|
|
27
|
-
### Version Updates
|
|
28
|
-
|
|
29
|
-
- Updated all version references across:
|
|
30
|
-
- `package.json` - NPM package version
|
|
31
|
-
- `library.json` - PlatformIO library version
|
|
32
|
-
- `library.properties` - Arduino library version
|
|
33
|
-
- `src/painlessMesh.h` - Header file version comments
|
|
34
|
-
- `src/AlteriomPainlessMesh.h` - Version defines and comments
|
|
35
|
-
|
|
36
|
-
## Installation
|
|
37
|
-
|
|
38
|
-
### Arduino Library Manager
|
|
39
|
-
```
|
|
40
|
-
Sketch → Include Library → Manage Libraries → Search "AlteriomPainlessMesh" → Install
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
### PlatformIO
|
|
44
|
-
```ini
|
|
45
|
-
[env:myenv]
|
|
46
|
-
lib_deps =
|
|
47
|
-
alteriom/AlteriomPainlessMesh @ ^1.8.12
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
### NPM
|
|
51
|
-
```bash
|
|
52
|
-
npm install @alteriom/painlessmesh@1.8.12
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
## Compatibility
|
|
56
|
-
|
|
57
|
-
- **ESP32** - All variants supported
|
|
58
|
-
- **ESP8266** - All variants supported
|
|
59
|
-
- **Arduino IDE** - Version 1.8.0 or higher
|
|
60
|
-
- **PlatformIO** - Latest version
|
|
61
|
-
- **ArduinoJson** - Version 7.4.2 or higher
|
|
62
|
-
- **TaskScheduler** - Version 4.0.0 or higher
|
|
63
|
-
|
|
64
|
-
## Migration Guide
|
|
65
|
-
|
|
66
|
-
This is a patch release with no breaking changes. Users can upgrade from any 1.8.x version without code modifications.
|
|
67
|
-
|
|
68
|
-
## Known Issues
|
|
69
|
-
|
|
70
|
-
None identified in this release.
|
|
71
|
-
|
|
72
|
-
## Pull Requests Included
|
|
73
|
-
|
|
74
|
-
- PR #152 - Documentation improvements
|
|
75
|
-
- PR #153 - Code quality enhancements
|
|
76
|
-
|
|
77
|
-
## Contributors
|
|
78
|
-
|
|
79
|
-
Special thanks to all contributors who helped make this release possible!
|
|
80
|
-
|
|
81
|
-
## Documentation
|
|
82
|
-
|
|
83
|
-
- **Main Documentation**: https://alteriom.github.io/painlessMesh/
|
|
84
|
-
- **API Reference**: https://alteriom.github.io/painlessMesh/#/api/doxygen
|
|
85
|
-
- **Examples**: https://alteriom.github.io/painlessMesh/#/tutorials/basic-examples
|
|
86
|
-
- **GitHub Repository**: https://github.com/Alteriom/painlessMesh
|
|
87
|
-
|
|
88
|
-
## Support
|
|
89
|
-
|
|
90
|
-
For questions, issues, or feature requests:
|
|
91
|
-
- **GitHub Issues**: https://github.com/Alteriom/painlessMesh/issues
|
|
92
|
-
- **Documentation**: https://alteriom.github.io/painlessMesh/
|
|
93
|
-
|
|
94
|
-
## License
|
|
95
|
-
|
|
96
|
-
This project is licensed under LGPL-3.0. See the LICENSE file for details.
|