@alteriom/painlessmesh 1.6.1 → 1.7.2

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 (129) hide show
  1. package/CHANGELOG.md +380 -143
  2. package/LICENSE +674 -674
  3. package/README.md +477 -434
  4. package/RELEASE_GUIDE.md +504 -418
  5. package/docs/DOCUMENTATION_MIGRATION_PLAN.md +175 -175
  6. package/docs/IMPLEMENTATION_PLAN_MESH_TOPOLOGY.md +1062 -0
  7. package/docs/MESH_TOPOLOGY_GUIDE.md +992 -0
  8. package/docs/MESH_TOPOLOGY_PROGRESS.md +422 -0
  9. package/docs/MQTT_BRIDGE_COMMANDS.md +894 -0
  10. package/docs/MQTT_BRIDGE_IMPLEMENTATION_SUMMARY.md +324 -0
  11. package/docs/MQTT_COMMAND_SCHEMA_PROPOSAL.md +576 -0
  12. package/docs/MQTT_SCHEMA_COMPLIANCE.md +285 -0
  13. package/docs/MQTT_SCHEMA_PROPOSALS.md +446 -0
  14. package/docs/MQTT_SCHEMA_REVIEW.md +690 -0
  15. package/docs/OTA_COMMANDS_REFERENCE.md +554 -0
  16. package/docs/PHASE1_GUIDE.md +349 -0
  17. package/docs/PHASE2_GUIDE.md +543 -0
  18. package/docs/README.md +77 -70
  19. package/docs/SCHEMA_VALIDATION_CHECKLIST.md +222 -0
  20. package/docs/alteriom/overview.md +507 -507
  21. package/docs/api/core-api.md +606 -606
  22. package/docs/architecture/mesh-architecture.md +378 -378
  23. package/docs/architecture/plugin-system.md +516 -516
  24. package/docs/getting-started/first-mesh.md +409 -409
  25. package/docs/getting-started/installation.md +274 -274
  26. package/docs/getting-started/quickstart.md +157 -157
  27. package/docs/improvements/FEATURE_PROPOSALS.md +337 -0
  28. package/docs/improvements/PHASE1_IMPLEMENTATION.md +325 -0
  29. package/docs/improvements/PHASE2_IMPLEMENTATION.md +567 -0
  30. package/docs/improvements/README.md +86 -68
  31. package/docs/improvements/ota-and-status-enhancements.md +911 -0
  32. package/docs/improvements/ota-status-architecture-diagrams.md +658 -0
  33. package/docs/improvements/ota-status-quick-reference.md +284 -0
  34. package/docs/platformio-publishing.md +255 -0
  35. package/docs/platformio-setup-summary.md +121 -0
  36. package/docs/troubleshooting/common-issues.md +520 -520
  37. package/docs/troubleshooting/faq.md +472 -472
  38. package/docs/tutorials/basic-examples.md +717 -717
  39. package/docs/wiki/API-Reference.md +245 -245
  40. package/docs/wiki/Complete-Documentation.md +122 -122
  41. package/examples/alteriom/README.md +139 -81
  42. package/examples/alteriom/alteriom.ino +186 -185
  43. package/examples/alteriom/alteriom_sensor_package.hpp +240 -127
  44. package/examples/alteriom/platformio.ini +24 -24
  45. package/examples/alteriomImproved/alteriom_sensor_package.hpp +224 -0
  46. package/examples/{alteriom → alteriomImproved}/improved_sensor_node.ino +245 -245
  47. package/examples/alteriomImproved/platformio.ini +25 -0
  48. package/examples/alteriomPhase1/alteriom_sensor_package.hpp +224 -0
  49. package/examples/alteriomPhase1/phase1_features.ino +242 -0
  50. package/examples/alteriomPhase1/platformio.ini +25 -0
  51. package/examples/alteriomPhase2/alteriom_sensor_package.hpp +224 -0
  52. package/examples/alteriomPhase2/phase2_features.ino +186 -0
  53. package/examples/alteriomPhase2/platformio.ini +25 -0
  54. package/examples/{alteriom → alteriomSensorNode}/alteriom_sensor_node.ino +183 -183
  55. package/examples/alteriomSensorNode/alteriom_sensor_package.hpp +224 -0
  56. package/examples/alteriomSensorNode/platformio.ini +25 -0
  57. package/examples/basic/basic.ino +66 -66
  58. package/examples/basic/platformio.ini +25 -25
  59. package/examples/bridge/bridge.ino +51 -51
  60. package/examples/bridge/mesh_event_publisher.hpp +253 -0
  61. package/examples/bridge/mesh_topology_reporter.hpp +303 -0
  62. package/examples/bridge/mqtt_command_bridge.hpp +459 -0
  63. package/examples/bridge/mqtt_status_bridge.hpp +519 -0
  64. package/examples/bridge/platformio.ini +25 -25
  65. package/examples/echoNode/echoNode.ino +33 -33
  66. package/examples/echoNode/platformio.ini +25 -25
  67. package/examples/logClient/logClient.ino +109 -109
  68. package/examples/logClient/platformio.ini +25 -25
  69. package/examples/logServer/logServer.ino +81 -81
  70. package/examples/logServer/platformio.ini +25 -25
  71. package/examples/meshCommandNode/alteriom_sensor_package.hpp +235 -0
  72. package/examples/meshCommandNode/meshCommandNode.ino +263 -0
  73. package/examples/meshCommandNode/platformio.ini +25 -0
  74. package/examples/mqttBridge/mqttBridge.ino +118 -118
  75. package/examples/mqttBridge/platformio.ini +26 -26
  76. package/examples/mqttCommandBridge/alteriom_sensor_package.hpp +235 -0
  77. package/examples/mqttCommandBridge/mesh_event_publisher.hpp +253 -0
  78. package/examples/mqttCommandBridge/mesh_topology_reporter.hpp +303 -0
  79. package/examples/mqttCommandBridge/mqttCommandBridge.ino +252 -0
  80. package/examples/mqttCommandBridge/mqtt_command_bridge.hpp +459 -0
  81. package/examples/mqttCommandBridge/platformio.ini +26 -0
  82. package/examples/mqttStatusBridge/mqttStatusBridge.ino +216 -0
  83. package/examples/mqttStatusBridge/mqtt_status_bridge.hpp +522 -0
  84. package/examples/mqttStatusBridge/platformio.ini +26 -0
  85. package/examples/mqttTopologyTest/README.md +467 -0
  86. package/examples/mqttTopologyTest/mqttTopologyTest.ino +748 -0
  87. package/examples/mqttTopologyTest/platformio.ini +26 -0
  88. package/examples/namedMesh/namedMesh.ino +97 -97
  89. package/examples/namedMesh/platformio.ini +25 -25
  90. package/examples/otaReceiver/otaReceiver.ino +79 -79
  91. package/examples/otaReceiver/platformio.ini +25 -25
  92. package/examples/otaSender/otaSender.ino +160 -151
  93. package/examples/otaSender/platformio.ini +25 -25
  94. package/examples/startHere/platformio.ini +25 -25
  95. package/examples/startHere/startHere.ino +159 -159
  96. package/examples/webServer/platformio.ini +27 -27
  97. package/examples/webServer/webServer.ino +89 -89
  98. package/keywords.txt +48 -48
  99. package/library.json +55 -34
  100. package/library.properties +10 -10
  101. package/package.json +86 -78
  102. package/src/AlteriomPainlessMesh.h +97 -97
  103. package/src/arduino/wifi.hpp +365 -365
  104. package/src/boost/asynctcp.hpp +279 -279
  105. package/src/painlessMesh.h +70 -70
  106. package/src/painlessMeshSTA.cpp +236 -236
  107. package/src/painlessMeshSTA.h +58 -58
  108. package/src/painlessTaskOptions.h +4 -4
  109. package/src/painlessmesh/base64.hpp +111 -111
  110. package/src/painlessmesh/buffer.hpp +229 -229
  111. package/src/painlessmesh/callback.hpp +91 -91
  112. package/src/painlessmesh/configuration.hpp +77 -77
  113. package/src/painlessmesh/connection.hpp +192 -192
  114. package/src/painlessmesh/layout.hpp +188 -188
  115. package/src/painlessmesh/logger.hpp +158 -158
  116. package/src/painlessmesh/memory.hpp +119 -119
  117. package/src/painlessmesh/mesh.hpp +761 -560
  118. package/src/painlessmesh/metrics.hpp +322 -322
  119. package/src/painlessmesh/ntp.hpp +263 -263
  120. package/src/painlessmesh/ota.hpp +582 -553
  121. package/src/painlessmesh/plugin.hpp +188 -188
  122. package/src/painlessmesh/protocol.hpp +813 -813
  123. package/src/painlessmesh/router.hpp +322 -322
  124. package/src/painlessmesh/tcp.hpp +71 -71
  125. package/src/painlessmesh/validation.hpp +238 -238
  126. package/src/plugin/performance.hpp +214 -214
  127. package/src/plugin/remote.hpp +64 -64
  128. package/src/scheduler.cpp +10 -10
  129. package/src/wifi.cpp +2 -2
@@ -1,322 +1,322 @@
1
- #ifndef _PAINLESS_MESH_ROUTER_HPP_
2
- #define _PAINLESS_MESH_ROUTER_HPP_
3
-
4
- #include <algorithm>
5
- #include <memory>
6
-
7
- #include "painlessmesh/callback.hpp"
8
- #include "painlessmesh/layout.hpp"
9
- #include "painlessmesh/logger.hpp"
10
- #include "painlessmesh/protocol.hpp"
11
-
12
- extern painlessmesh::logger::LogClass Log;
13
-
14
- namespace painlessmesh {
15
-
16
- /**
17
- * Helper functions to route messages
18
- */
19
- namespace router {
20
- template <class T>
21
- std::shared_ptr<T> findRoute(layout::Layout<T> tree,
22
- std::function<bool(std::shared_ptr<T>)> func) {
23
- auto route = std::find_if(tree.subs.begin(), tree.subs.end(), func);
24
- if (route == tree.subs.end()) return NULL;
25
- return (*route);
26
- }
27
-
28
- template <class T>
29
- std::shared_ptr<T> findRoute(layout::Layout<T> tree, uint32_t nodeId) {
30
- return findRoute<T>(tree, [nodeId](std::shared_ptr<T> s) {
31
- return layout::contains((*s), nodeId);
32
- });
33
- }
34
-
35
- template <class T, class U>
36
- bool send(T& package, std::shared_ptr<U> conn, bool priority = false) {
37
- painlessmesh::protocol::Variant variant(package);
38
- TSTRING msg;
39
- variant.printTo(msg);
40
- return conn->addMessage(msg, priority);
41
- }
42
-
43
- template <class T, class U>
44
- bool send(T&& package, std::shared_ptr<U> conn, bool priority = false) {
45
- painlessmesh::protocol::Variant variant(package);
46
- TSTRING msg;
47
- variant.printTo(msg);
48
- return conn->addMessage(msg, priority);
49
- }
50
-
51
- template <class U>
52
- bool send(protocol::Variant& variant, std::shared_ptr<U> conn,
53
- bool priority = false) {
54
- TSTRING msg;
55
- variant.printTo(msg);
56
- return conn->addMessage(msg, priority);
57
- }
58
-
59
- template <class U>
60
- bool send(protocol::Variant&& variant, std::shared_ptr<U> conn,
61
- bool priority = false) {
62
- TSTRING msg;
63
- variant.printTo(msg);
64
- return conn->addMessage(msg, priority);
65
- }
66
-
67
- template <class T, class U>
68
- bool send(T& package, layout::Layout<U> layout) {
69
- painlessmesh::protocol::Variant variant(package);
70
- TSTRING msg;
71
- variant.printTo(msg);
72
- auto conn = findRoute<U>(layout, variant.dest());
73
- if (conn) return conn->addMessage(msg);
74
- return false;
75
- }
76
-
77
- template <class U>
78
- bool send(protocol::Variant& variant, layout::Layout<U> layout) {
79
- TSTRING msg;
80
- variant.printTo(msg);
81
- auto conn = findRoute<U>(layout, variant.dest());
82
- if (conn) return conn->addMessage(msg);
83
- return false;
84
- }
85
-
86
- template <class T, class U>
87
- bool send(T&& package, layout::Layout<U> layout) {
88
- painlessmesh::protocol::Variant variant(package);
89
- TSTRING msg;
90
- variant.printTo(msg);
91
- auto conn = findRoute<U>(layout, variant.dest());
92
- if (conn) return conn->addMessage(msg);
93
- return false;
94
- }
95
-
96
- template <class U>
97
- bool send(protocol::Variant&& variant, layout::Layout<U> layout) {
98
- TSTRING msg;
99
- variant.printTo(msg);
100
- auto conn = findRoute<U>(layout, variant.dest());
101
- if (conn) return conn->addMessage(msg);
102
- return false;
103
- }
104
-
105
- template <class T, class U>
106
- size_t broadcast(T& package, layout::Layout<U> layout, uint32_t exclude) {
107
- painlessmesh::protocol::Variant variant(package);
108
- TSTRING msg;
109
- variant.printTo(msg);
110
- size_t i = 0;
111
- for (auto&& conn : layout.subs) {
112
- if (conn->nodeId != 0 && conn->nodeId != exclude) {
113
- auto sent = conn->addMessage(msg);
114
- if (sent) ++i;
115
- }
116
- }
117
- return i;
118
- }
119
-
120
- template <class T, class U>
121
- size_t broadcast(T&& package, layout::Layout<U> layout, uint32_t exclude) {
122
- painlessmesh::protocol::Variant variant(package);
123
- TSTRING msg;
124
- variant.printTo(msg);
125
- size_t i = 0;
126
- for (auto&& conn : layout.subs) {
127
- if (conn->nodeId != 0 && conn->nodeId != exclude) {
128
- auto sent = conn->addMessage(msg);
129
- if (sent) ++i;
130
- }
131
- }
132
- return i;
133
- }
134
-
135
- template <class T>
136
- size_t broadcast(protocol::Variant& variant, layout::Layout<T> layout,
137
- uint32_t exclude) {
138
- TSTRING msg;
139
- variant.printTo(msg);
140
- size_t i = 0;
141
- for (auto&& conn : layout.subs) {
142
- if (conn->nodeId != 0 && conn->nodeId != exclude) {
143
- auto sent = conn->addMessage(msg);
144
- if (sent) ++i;
145
- }
146
- }
147
- return i;
148
- }
149
-
150
- template <class T>
151
- size_t broadcast(protocol::Variant&& variant, layout::Layout<T> layout,
152
- uint32_t exclude) {
153
- TSTRING msg;
154
- variant.printTo(msg);
155
- size_t i = 0;
156
- for (auto&& conn : layout.subs) {
157
- if (conn->nodeId != 0 && conn->nodeId != exclude) {
158
- auto sent = conn->addMessage(msg);
159
- if (sent) ++i;
160
- }
161
- }
162
- return i;
163
- }
164
-
165
- template <class T>
166
- void routePackage(layout::Layout<T> layout, std::shared_ptr<T> connection,
167
- const TSTRING& pkg, callback::MeshPackageCallbackList<T> cbl,
168
- uint32_t receivedAt) {
169
- using namespace logger;
170
- Log(COMMUNICATION, "routePackage(): Recvd from %u: %s\n", connection->nodeId,
171
- pkg.c_str());
172
- #if ARDUINOJSON_VERSION_MAJOR == 7
173
- protocol::Variant variant(pkg);
174
- if (variant.error) {
175
- Log(ERROR,
176
- "routePackage(): parsing failed. err=%u, total_length=%d, data=%s<--\n",
177
- variant.error, pkg.length(), pkg.c_str());
178
- return;
179
- }
180
-
181
- if (variant.routing() == SINGLE && variant.dest() != layout.getNodeId()) {
182
- // Send on without further processing
183
- send<T>(variant, layout);
184
- return;
185
- } else if (variant.routing() == BROADCAST) {
186
- broadcast<T>(variant, layout, connection->nodeId);
187
- }
188
- auto calls = cbl.execute(variant.type(), variant, connection, receivedAt);
189
- if (calls == 0)
190
- Log(DEBUG, "routePackage(): No callbacks executed; %u, %s\n",
191
- variant.type(), pkg.c_str());
192
- #else
193
- static size_t baseCapacity = 512;
194
- // Using a ptr so we can overwrite it if we need to grow capacity.
195
- // Bug in copy constructor with grown capacity can cause segmentation fault
196
- auto variant =
197
- std::make_shared<protocol::Variant>(pkg, pkg.length() + baseCapacity);
198
- while (variant->error == DeserializationError::NoMemory &&
199
- baseCapacity <= 20480) {
200
- // Not enough memory, adapt scaling (variant::capacityScaling) and log the
201
- // new value
202
- Log(DEBUG,
203
- "routePackage(): parsing failed. err=%u, increasing capacity: %u\n",
204
- variant->error, baseCapacity);
205
- baseCapacity += 256;
206
- variant =
207
- std::make_shared<protocol::Variant>(pkg, pkg.length() + baseCapacity);
208
- }
209
- if (variant->error) {
210
- Log(ERROR,
211
- "routePackage(): parsing failed. err=%u, total_length=%d, data=%s<--\n",
212
- variant->error, pkg.length(), pkg.c_str());
213
- return;
214
- }
215
-
216
- if (variant->routing() == SINGLE && variant->dest() != layout.getNodeId()) {
217
- // Send on without further processing
218
- send<T>((*variant), layout);
219
- return;
220
- } else if (variant->routing() == BROADCAST) {
221
- broadcast<T>((*variant), layout, connection->nodeId);
222
- }
223
- auto calls = cbl.execute(variant->type(), (*variant), connection, receivedAt);
224
- if (calls == 0)
225
- Log(DEBUG, "routePackage(): No callbacks executed; %u, %s\n",
226
- variant->type(), pkg.c_str());
227
- #endif
228
- }
229
-
230
- template <class T, class U>
231
- void handleNodeSync(T& mesh, protocol::NodeTree newTree,
232
- std::shared_ptr<U> conn) {
233
- Log(logger::SYNC, "handleNodeSync(): with %u\n", conn->nodeId);
234
-
235
- if (!conn->validSubs(newTree)) {
236
- Log(logger::SYNC, "handleNodeSync(): invalid new connection\n");
237
- Log.remote("Invalid connection to %u\n", conn->nodeId);
238
- conn->close();
239
- return;
240
- }
241
-
242
- if (conn->newConnection) {
243
- auto oldConnection = router::findRoute<U>(mesh, newTree.nodeId);
244
- if (oldConnection) {
245
- Log(logger::SYNC,
246
- "handleNodeSync(): already connected to %u. Closing the new "
247
- "connection \n",
248
- newTree.nodeId);
249
- Log.remote("Already connected to %u\n", newTree.nodeId);
250
- conn->close();
251
- return;
252
- }
253
- auto remoteNodeId = newTree.nodeId;
254
- mesh.addTask([&mesh, remoteNodeId]() {
255
- Log(logger::CONNECTION, "newConnectionTask():\n");
256
- Log(logger::CONNECTION, "newConnectionTask(): adding %u now= %u\n",
257
- remoteNodeId, mesh.getNodeTime());
258
- mesh.newConnectionCallbacks.execute(remoteNodeId);
259
- });
260
-
261
- // Initially interval is every 10 seconds,
262
- // this will slow down to TIME_SYNC_INTERVAL
263
- // after first succesfull sync
264
- // TODO move it to a new connection callback and use initTimeSync from
265
- // ntp.hpp
266
- conn->timeSyncTask.set(10 * TASK_SECOND, TASK_FOREVER, [conn, &mesh]() {
267
- Log(logger::S_TIME, "timeSyncTask(): %u\n", conn->nodeId);
268
- mesh.startTimeSync(conn);
269
- });
270
- mesh.mScheduler->addTask(conn->timeSyncTask);
271
- if (conn->station)
272
- // We are STA, request time immediately
273
- conn->timeSyncTask.enable();
274
- else
275
- // We are the AP, give STA the change to initiate time sync
276
- conn->timeSyncTask.enableDelayed();
277
- conn->newConnection = false;
278
- }
279
-
280
- if (conn->updateSubs(newTree)) {
281
- auto nodeId = newTree.nodeId;
282
- mesh.addTask(
283
- [&mesh, nodeId]() { mesh.changedConnectionCallbacks.execute(nodeId); });
284
- } else {
285
- conn->nodeSyncTask.delay();
286
- mesh.stability += std::min(1000 - mesh.stability, (size_t)25);
287
- }
288
- }
289
-
290
- template <class T, typename U>
291
- callback::MeshPackageCallbackList<U> addPackageCallback(
292
- callback::MeshPackageCallbackList<U>&& callbackList, T& mesh) {
293
- // REQUEST type,
294
- callbackList.onPackage(
295
- protocol::NODE_SYNC_REQUEST,
296
- [&mesh](protocol::Variant& variant, std::shared_ptr<U> connection,
297
- uint32_t receivedAt) {
298
- auto newTree = variant.to<protocol::NodeSyncRequest>();
299
- handleNodeSync<T, U>(mesh, newTree, connection);
300
- send<protocol::NodeSyncReply>(
301
- connection->reply(std::move(mesh.asNodeTree())), connection, true);
302
- return false;
303
- });
304
-
305
- // Reply type just handle it
306
- callbackList.onPackage(
307
- protocol::NODE_SYNC_REPLY,
308
- [&mesh](protocol::Variant& variant, std::shared_ptr<U> connection,
309
- uint32_t receivedAt) {
310
- auto newTree = variant.to<protocol::NodeSyncReply>();
311
- handleNodeSync<T, U>(mesh, newTree, connection);
312
- connection->timeOutTask.disable();
313
- return false;
314
- });
315
-
316
- return callbackList;
317
- }
318
-
319
- } // namespace router
320
- } // namespace painlessmesh
321
-
322
- #endif
1
+ #ifndef _PAINLESS_MESH_ROUTER_HPP_
2
+ #define _PAINLESS_MESH_ROUTER_HPP_
3
+
4
+ #include <algorithm>
5
+ #include <memory>
6
+
7
+ #include "painlessmesh/callback.hpp"
8
+ #include "painlessmesh/layout.hpp"
9
+ #include "painlessmesh/logger.hpp"
10
+ #include "painlessmesh/protocol.hpp"
11
+
12
+ extern painlessmesh::logger::LogClass Log;
13
+
14
+ namespace painlessmesh {
15
+
16
+ /**
17
+ * Helper functions to route messages
18
+ */
19
+ namespace router {
20
+ template <class T>
21
+ std::shared_ptr<T> findRoute(layout::Layout<T> tree,
22
+ std::function<bool(std::shared_ptr<T>)> func) {
23
+ auto route = std::find_if(tree.subs.begin(), tree.subs.end(), func);
24
+ if (route == tree.subs.end()) return NULL;
25
+ return (*route);
26
+ }
27
+
28
+ template <class T>
29
+ std::shared_ptr<T> findRoute(layout::Layout<T> tree, uint32_t nodeId) {
30
+ return findRoute<T>(tree, [nodeId](std::shared_ptr<T> s) {
31
+ return layout::contains((*s), nodeId);
32
+ });
33
+ }
34
+
35
+ template <class T, class U>
36
+ bool send(T& package, std::shared_ptr<U> conn, bool priority = false) {
37
+ painlessmesh::protocol::Variant variant(package);
38
+ TSTRING msg;
39
+ variant.printTo(msg);
40
+ return conn->addMessage(msg, priority);
41
+ }
42
+
43
+ template <class T, class U>
44
+ bool send(T&& package, std::shared_ptr<U> conn, bool priority = false) {
45
+ painlessmesh::protocol::Variant variant(package);
46
+ TSTRING msg;
47
+ variant.printTo(msg);
48
+ return conn->addMessage(msg, priority);
49
+ }
50
+
51
+ template <class U>
52
+ bool send(protocol::Variant& variant, std::shared_ptr<U> conn,
53
+ bool priority = false) {
54
+ TSTRING msg;
55
+ variant.printTo(msg);
56
+ return conn->addMessage(msg, priority);
57
+ }
58
+
59
+ template <class U>
60
+ bool send(protocol::Variant&& variant, std::shared_ptr<U> conn,
61
+ bool priority = false) {
62
+ TSTRING msg;
63
+ variant.printTo(msg);
64
+ return conn->addMessage(msg, priority);
65
+ }
66
+
67
+ template <class T, class U>
68
+ bool send(T& package, layout::Layout<U> layout) {
69
+ painlessmesh::protocol::Variant variant(package);
70
+ TSTRING msg;
71
+ variant.printTo(msg);
72
+ auto conn = findRoute<U>(layout, variant.dest());
73
+ if (conn) return conn->addMessage(msg);
74
+ return false;
75
+ }
76
+
77
+ template <class U>
78
+ bool send(protocol::Variant& variant, layout::Layout<U> layout) {
79
+ TSTRING msg;
80
+ variant.printTo(msg);
81
+ auto conn = findRoute<U>(layout, variant.dest());
82
+ if (conn) return conn->addMessage(msg);
83
+ return false;
84
+ }
85
+
86
+ template <class T, class U>
87
+ bool send(T&& package, layout::Layout<U> layout) {
88
+ painlessmesh::protocol::Variant variant(package);
89
+ TSTRING msg;
90
+ variant.printTo(msg);
91
+ auto conn = findRoute<U>(layout, variant.dest());
92
+ if (conn) return conn->addMessage(msg);
93
+ return false;
94
+ }
95
+
96
+ template <class U>
97
+ bool send(protocol::Variant&& variant, layout::Layout<U> layout) {
98
+ TSTRING msg;
99
+ variant.printTo(msg);
100
+ auto conn = findRoute<U>(layout, variant.dest());
101
+ if (conn) return conn->addMessage(msg);
102
+ return false;
103
+ }
104
+
105
+ template <class T, class U>
106
+ size_t broadcast(T& package, layout::Layout<U> layout, uint32_t exclude) {
107
+ painlessmesh::protocol::Variant variant(package);
108
+ TSTRING msg;
109
+ variant.printTo(msg);
110
+ size_t i = 0;
111
+ for (auto&& conn : layout.subs) {
112
+ if (conn->nodeId != 0 && conn->nodeId != exclude) {
113
+ auto sent = conn->addMessage(msg);
114
+ if (sent) ++i;
115
+ }
116
+ }
117
+ return i;
118
+ }
119
+
120
+ template <class T, class U>
121
+ size_t broadcast(T&& package, layout::Layout<U> layout, uint32_t exclude) {
122
+ painlessmesh::protocol::Variant variant(package);
123
+ TSTRING msg;
124
+ variant.printTo(msg);
125
+ size_t i = 0;
126
+ for (auto&& conn : layout.subs) {
127
+ if (conn->nodeId != 0 && conn->nodeId != exclude) {
128
+ auto sent = conn->addMessage(msg);
129
+ if (sent) ++i;
130
+ }
131
+ }
132
+ return i;
133
+ }
134
+
135
+ template <class T>
136
+ size_t broadcast(protocol::Variant& variant, layout::Layout<T> layout,
137
+ uint32_t exclude) {
138
+ TSTRING msg;
139
+ variant.printTo(msg);
140
+ size_t i = 0;
141
+ for (auto&& conn : layout.subs) {
142
+ if (conn->nodeId != 0 && conn->nodeId != exclude) {
143
+ auto sent = conn->addMessage(msg);
144
+ if (sent) ++i;
145
+ }
146
+ }
147
+ return i;
148
+ }
149
+
150
+ template <class T>
151
+ size_t broadcast(protocol::Variant&& variant, layout::Layout<T> layout,
152
+ uint32_t exclude) {
153
+ TSTRING msg;
154
+ variant.printTo(msg);
155
+ size_t i = 0;
156
+ for (auto&& conn : layout.subs) {
157
+ if (conn->nodeId != 0 && conn->nodeId != exclude) {
158
+ auto sent = conn->addMessage(msg);
159
+ if (sent) ++i;
160
+ }
161
+ }
162
+ return i;
163
+ }
164
+
165
+ template <class T>
166
+ void routePackage(layout::Layout<T> layout, std::shared_ptr<T> connection,
167
+ const TSTRING& pkg, callback::MeshPackageCallbackList<T> cbl,
168
+ uint32_t receivedAt) {
169
+ using namespace logger;
170
+ Log(COMMUNICATION, "routePackage(): Recvd from %u: %s\n", connection->nodeId,
171
+ pkg.c_str());
172
+ #if ARDUINOJSON_VERSION_MAJOR == 7
173
+ protocol::Variant variant(pkg);
174
+ if (variant.error) {
175
+ Log(ERROR,
176
+ "routePackage(): parsing failed. err=%u, total_length=%d, data=%s<--\n",
177
+ variant.error, pkg.length(), pkg.c_str());
178
+ return;
179
+ }
180
+
181
+ if (variant.routing() == SINGLE && variant.dest() != layout.getNodeId()) {
182
+ // Send on without further processing
183
+ send<T>(variant, layout);
184
+ return;
185
+ } else if (variant.routing() == BROADCAST) {
186
+ broadcast<T>(variant, layout, connection->nodeId);
187
+ }
188
+ auto calls = cbl.execute(variant.type(), variant, connection, receivedAt);
189
+ if (calls == 0)
190
+ Log(DEBUG, "routePackage(): No callbacks executed; %u, %s\n",
191
+ variant.type(), pkg.c_str());
192
+ #else
193
+ static size_t baseCapacity = 512;
194
+ // Using a ptr so we can overwrite it if we need to grow capacity.
195
+ // Bug in copy constructor with grown capacity can cause segmentation fault
196
+ auto variant =
197
+ std::make_shared<protocol::Variant>(pkg, pkg.length() + baseCapacity);
198
+ while (variant->error == DeserializationError::NoMemory &&
199
+ baseCapacity <= 20480) {
200
+ // Not enough memory, adapt scaling (variant::capacityScaling) and log the
201
+ // new value
202
+ Log(DEBUG,
203
+ "routePackage(): parsing failed. err=%u, increasing capacity: %u\n",
204
+ variant->error, baseCapacity);
205
+ baseCapacity += 256;
206
+ variant =
207
+ std::make_shared<protocol::Variant>(pkg, pkg.length() + baseCapacity);
208
+ }
209
+ if (variant->error) {
210
+ Log(ERROR,
211
+ "routePackage(): parsing failed. err=%u, total_length=%d, data=%s<--\n",
212
+ variant->error, pkg.length(), pkg.c_str());
213
+ return;
214
+ }
215
+
216
+ if (variant->routing() == SINGLE && variant->dest() != layout.getNodeId()) {
217
+ // Send on without further processing
218
+ send<T>((*variant), layout);
219
+ return;
220
+ } else if (variant->routing() == BROADCAST) {
221
+ broadcast<T>((*variant), layout, connection->nodeId);
222
+ }
223
+ auto calls = cbl.execute(variant->type(), (*variant), connection, receivedAt);
224
+ if (calls == 0)
225
+ Log(DEBUG, "routePackage(): No callbacks executed; %u, %s\n",
226
+ variant->type(), pkg.c_str());
227
+ #endif
228
+ }
229
+
230
+ template <class T, class U>
231
+ void handleNodeSync(T& mesh, protocol::NodeTree newTree,
232
+ std::shared_ptr<U> conn) {
233
+ Log(logger::SYNC, "handleNodeSync(): with %u\n", conn->nodeId);
234
+
235
+ if (!conn->validSubs(newTree)) {
236
+ Log(logger::SYNC, "handleNodeSync(): invalid new connection\n");
237
+ Log.remote("Invalid connection to %u\n", conn->nodeId);
238
+ conn->close();
239
+ return;
240
+ }
241
+
242
+ if (conn->newConnection) {
243
+ auto oldConnection = router::findRoute<U>(mesh, newTree.nodeId);
244
+ if (oldConnection) {
245
+ Log(logger::SYNC,
246
+ "handleNodeSync(): already connected to %u. Closing the new "
247
+ "connection \n",
248
+ newTree.nodeId);
249
+ Log.remote("Already connected to %u\n", newTree.nodeId);
250
+ conn->close();
251
+ return;
252
+ }
253
+ auto remoteNodeId = newTree.nodeId;
254
+ mesh.addTask([&mesh, remoteNodeId]() {
255
+ Log(logger::CONNECTION, "newConnectionTask():\n");
256
+ Log(logger::CONNECTION, "newConnectionTask(): adding %u now= %u\n",
257
+ remoteNodeId, mesh.getNodeTime());
258
+ mesh.newConnectionCallbacks.execute(remoteNodeId);
259
+ });
260
+
261
+ // Initially interval is every 10 seconds,
262
+ // this will slow down to TIME_SYNC_INTERVAL
263
+ // after first succesfull sync
264
+ // TODO move it to a new connection callback and use initTimeSync from
265
+ // ntp.hpp
266
+ conn->timeSyncTask.set(10 * TASK_SECOND, TASK_FOREVER, [conn, &mesh]() {
267
+ Log(logger::S_TIME, "timeSyncTask(): %u\n", conn->nodeId);
268
+ mesh.startTimeSync(conn);
269
+ });
270
+ mesh.mScheduler->addTask(conn->timeSyncTask);
271
+ if (conn->station)
272
+ // We are STA, request time immediately
273
+ conn->timeSyncTask.enable();
274
+ else
275
+ // We are the AP, give STA the change to initiate time sync
276
+ conn->timeSyncTask.enableDelayed();
277
+ conn->newConnection = false;
278
+ }
279
+
280
+ if (conn->updateSubs(newTree)) {
281
+ auto nodeId = newTree.nodeId;
282
+ mesh.addTask(
283
+ [&mesh, nodeId]() { mesh.changedConnectionCallbacks.execute(nodeId); });
284
+ } else {
285
+ conn->nodeSyncTask.delay();
286
+ mesh.stability += std::min(1000 - mesh.stability, (size_t)25);
287
+ }
288
+ }
289
+
290
+ template <class T, typename U>
291
+ callback::MeshPackageCallbackList<U> addPackageCallback(
292
+ callback::MeshPackageCallbackList<U>&& callbackList, T& mesh) {
293
+ // REQUEST type,
294
+ callbackList.onPackage(
295
+ protocol::NODE_SYNC_REQUEST,
296
+ [&mesh](protocol::Variant& variant, std::shared_ptr<U> connection,
297
+ uint32_t receivedAt) {
298
+ auto newTree = variant.to<protocol::NodeSyncRequest>();
299
+ handleNodeSync<T, U>(mesh, newTree, connection);
300
+ send<protocol::NodeSyncReply>(
301
+ connection->reply(std::move(mesh.asNodeTree())), connection, true);
302
+ return false;
303
+ });
304
+
305
+ // Reply type just handle it
306
+ callbackList.onPackage(
307
+ protocol::NODE_SYNC_REPLY,
308
+ [&mesh](protocol::Variant& variant, std::shared_ptr<U> connection,
309
+ uint32_t receivedAt) {
310
+ auto newTree = variant.to<protocol::NodeSyncReply>();
311
+ handleNodeSync<T, U>(mesh, newTree, connection);
312
+ connection->timeOutTask.disable();
313
+ return false;
314
+ });
315
+
316
+ return callbackList;
317
+ }
318
+
319
+ } // namespace router
320
+ } // namespace painlessmesh
321
+
322
+ #endif