@alteriom/painlessmesh 1.6.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 (80) hide show
  1. package/CHANGELOG.md +144 -0
  2. package/LICENSE +674 -0
  3. package/README.md +434 -0
  4. package/RELEASE_GUIDE.md +419 -0
  5. package/docs/DOCUMENTATION_MIGRATION_PLAN.md +176 -0
  6. package/docs/README.md +71 -0
  7. package/docs/alteriom/overview.md +508 -0
  8. package/docs/api/core-api.md +607 -0
  9. package/docs/architecture/mesh-architecture.md +379 -0
  10. package/docs/architecture/plugin-system.md +517 -0
  11. package/docs/getting-started/first-mesh.md +410 -0
  12. package/docs/getting-started/installation.md +275 -0
  13. package/docs/getting-started/quickstart.md +158 -0
  14. package/docs/improvements/README.md +69 -0
  15. package/docs/troubleshooting/common-issues.md +521 -0
  16. package/docs/troubleshooting/faq.md +473 -0
  17. package/docs/tutorials/basic-examples.md +718 -0
  18. package/docs/wiki/API-Reference.md +246 -0
  19. package/docs/wiki/Complete-Documentation.md +123 -0
  20. package/examples/alteriom/README.md +82 -0
  21. package/examples/alteriom/alteriom.ino +186 -0
  22. package/examples/alteriom/alteriom_sensor_node.ino +184 -0
  23. package/examples/alteriom/alteriom_sensor_package.hpp +128 -0
  24. package/examples/alteriom/improved_sensor_node.ino +246 -0
  25. package/examples/alteriom/platformio.ini +25 -0
  26. package/examples/basic/basic.ino +66 -0
  27. package/examples/basic/platformio.ini +25 -0
  28. package/examples/bridge/bridge.ino +51 -0
  29. package/examples/bridge/platformio.ini +25 -0
  30. package/examples/echoNode/echoNode.ino +33 -0
  31. package/examples/echoNode/platformio.ini +25 -0
  32. package/examples/logClient/logClient.ino +109 -0
  33. package/examples/logClient/platformio.ini +25 -0
  34. package/examples/logServer/logServer.ino +81 -0
  35. package/examples/logServer/platformio.ini +25 -0
  36. package/examples/mqttBridge/mqttBridge.ino +118 -0
  37. package/examples/mqttBridge/platformio.ini +26 -0
  38. package/examples/namedMesh/namedMesh.ino +97 -0
  39. package/examples/namedMesh/platformio.ini +25 -0
  40. package/examples/otaReceiver/otaReceiver.ino +79 -0
  41. package/examples/otaReceiver/platformio.ini +25 -0
  42. package/examples/otaSender/nodemcu32s_connections.JPG +0 -0
  43. package/examples/otaSender/otaSender.ino +151 -0
  44. package/examples/otaSender/platformio.ini +25 -0
  45. package/examples/startHere/platformio.ini +25 -0
  46. package/examples/startHere/startHere.ino +159 -0
  47. package/examples/webServer/platformio.ini +27 -0
  48. package/examples/webServer/webServer.ino +89 -0
  49. package/keywords.txt +49 -0
  50. package/library.json +34 -0
  51. package/library.properties +11 -0
  52. package/package.json +78 -0
  53. package/src/AlteriomPainlessMesh.h +98 -0
  54. package/src/arduino/wifi.hpp +365 -0
  55. package/src/boost/asynctcp.hpp +279 -0
  56. package/src/painlessMesh.h +70 -0
  57. package/src/painlessMeshSTA.cpp +236 -0
  58. package/src/painlessMeshSTA.h +58 -0
  59. package/src/painlessTaskOptions.h +4 -0
  60. package/src/painlessmesh/base64.hpp +111 -0
  61. package/src/painlessmesh/buffer.hpp +229 -0
  62. package/src/painlessmesh/callback.hpp +91 -0
  63. package/src/painlessmesh/configuration.hpp +77 -0
  64. package/src/painlessmesh/connection.hpp +192 -0
  65. package/src/painlessmesh/layout.hpp +188 -0
  66. package/src/painlessmesh/logger.hpp +158 -0
  67. package/src/painlessmesh/memory.hpp +120 -0
  68. package/src/painlessmesh/mesh.hpp +560 -0
  69. package/src/painlessmesh/metrics.hpp +323 -0
  70. package/src/painlessmesh/ntp.hpp +263 -0
  71. package/src/painlessmesh/ota.hpp +553 -0
  72. package/src/painlessmesh/plugin.hpp +188 -0
  73. package/src/painlessmesh/protocol.hpp +813 -0
  74. package/src/painlessmesh/router.hpp +322 -0
  75. package/src/painlessmesh/tcp.hpp +71 -0
  76. package/src/painlessmesh/validation.hpp +239 -0
  77. package/src/plugin/performance.hpp +214 -0
  78. package/src/plugin/remote.hpp +64 -0
  79. package/src/scheduler.cpp +10 -0
  80. package/src/wifi.cpp +2 -0
@@ -0,0 +1,560 @@
1
+ #ifndef _PAINLESS_MESH_MESH_HPP_
2
+ #define _PAINLESS_MESH_MESH_HPP_
3
+
4
+ #include "painlessmesh/configuration.hpp"
5
+
6
+ #include "painlessmesh/connection.hpp"
7
+ #include "painlessmesh/logger.hpp"
8
+ #include "painlessmesh/ntp.hpp"
9
+ #include "painlessmesh/plugin.hpp"
10
+ #include "painlessmesh/protocol.hpp"
11
+ #include "painlessmesh/tcp.hpp"
12
+
13
+ #ifdef PAINLESSMESH_ENABLE_OTA
14
+ #include "painlessmesh/ota.hpp"
15
+ #endif
16
+
17
+ namespace painlessmesh {
18
+ typedef std::function<void(uint32_t nodeId)> newConnectionCallback_t;
19
+ typedef std::function<void(uint32_t nodeId)> droppedConnectionCallback_t;
20
+ typedef std::function<void(uint32_t from, TSTRING &msg)> receivedCallback_t;
21
+ typedef std::function<void()> changedConnectionsCallback_t;
22
+ typedef std::function<void(int32_t offset)> nodeTimeAdjustedCallback_t;
23
+ typedef std::function<void(uint32_t nodeId, int32_t delay)> nodeDelayCallback_t;
24
+
25
+ /**
26
+ * Main api class for the mesh
27
+ *
28
+ * Brings all the functions together except for the WiFi functions
29
+ */
30
+ template <class T>
31
+ class Mesh : public ntp::MeshTime, public plugin::PackageHandler<T> {
32
+ public:
33
+ void init(uint32_t id) {
34
+ using namespace logger;
35
+ if (!isExternalScheduler) {
36
+ mScheduler = new Scheduler();
37
+ }
38
+ this->nodeId = id;
39
+
40
+ #ifdef ESP32
41
+ xSemaphore = xSemaphoreCreateMutex();
42
+ #endif
43
+
44
+ // Add package handlers
45
+ this->callbackList = painlessmesh::ntp::addPackageCallback(
46
+ std::move(this->callbackList), (*this));
47
+ this->callbackList = painlessmesh::router::addPackageCallback(
48
+ std::move(this->callbackList), (*this));
49
+
50
+ this->changedConnectionCallbacks.push_back([this](uint32_t nodeId) {
51
+ Log(MESH_STATUS, "Changed connections in neighbour %u\n", nodeId);
52
+ if (nodeId != 0) layout::syncLayout<T>((*this), nodeId);
53
+ });
54
+ this->droppedConnectionCallbacks.push_back([this](uint32_t nodeId,
55
+ bool station) {
56
+ Log(MESH_STATUS, "Dropped connection %u, station %d\n", nodeId, station);
57
+ this->eraseClosedConnections();
58
+ });
59
+ this->newConnectionCallbacks.push_back([](uint32_t nodeId) {
60
+ Log(MESH_STATUS, "New connection %u\n", nodeId);
61
+ });
62
+ }
63
+
64
+ void init(Scheduler *scheduler, uint32_t id) {
65
+ this->setScheduler(scheduler);
66
+ this->init(id);
67
+ }
68
+
69
+ #ifdef PAINLESSMESH_ENABLE_OTA
70
+ std::shared_ptr<Task> offerOTA(painlessmesh::plugin::ota::Announce announce) {
71
+ auto announceTask = this->addTask(TASK_SECOND * 60, 60, [this, announce]() {
72
+ this->sendPackage(&announce);
73
+ });
74
+ return announceTask;
75
+ }
76
+
77
+ std::shared_ptr<Task> offerOTA(TSTRING role, TSTRING hardware, TSTRING md5,
78
+ size_t noPart, bool forced = false) {
79
+ painlessmesh::plugin::ota::Announce announce;
80
+ announce.md5 = md5;
81
+ announce.role = role;
82
+ announce.hardware = hardware;
83
+ announce.from = this->nodeId;
84
+ announce.noPart = noPart;
85
+ announce.forced = forced;
86
+ return offerOTA(announce);
87
+ }
88
+
89
+ void initOTASend(
90
+ painlessmesh::plugin::ota::otaDataPacketCallbackType_t callback,
91
+ size_t otaPartSize) {
92
+ painlessmesh::plugin::ota::addSendPackageCallback(
93
+ *this->mScheduler, (*this), callback, otaPartSize);
94
+ }
95
+ void initOTAReceive(TSTRING role = "",
96
+ std::function<void(int, int)> progress_cb = NULL) {
97
+ painlessmesh::plugin::ota::addReceivePackageCallback(
98
+ *this->mScheduler, (*this), role, progress_cb);
99
+ }
100
+ #endif
101
+
102
+ /**
103
+ * Set the node as an root/master node for the mesh
104
+ *
105
+ * This is an optional setting that can speed up mesh formation.
106
+ * At most one node in the mesh should be a root, or you could
107
+ * end up with multiple subMeshes.
108
+ *
109
+ * We recommend any AP_ONLY nodes (e.g. a bridgeNode) to be set
110
+ * as a root node.
111
+ *
112
+ * If one node is root, then it is also recommended to call
113
+ * painlessMesh::setContainsRoot() on all the nodes in the mesh.
114
+ */
115
+ void setRoot(bool on = true) { this->root = on; };
116
+
117
+ /**
118
+ * The mesh should contains a root node
119
+ *
120
+ * This will cause the mesh to restructure more quickly around the root node.
121
+ * Note that this could have adverse effects if set, while there is no root
122
+ * node present. Also see painlessMesh::setRoot().
123
+ */
124
+ void setContainsRoot(bool on = true) { shouldContainRoot = on; };
125
+
126
+ /**
127
+ * Check whether this node is a root node.
128
+ */
129
+ bool isRoot() { return this->root; };
130
+
131
+ /**
132
+ * Change the internal log level
133
+ */
134
+ void setDebugMsgTypes(uint16_t types) { Log.setLogLevel(types); }
135
+
136
+ /**
137
+ * Disconnect and stop this node
138
+ */
139
+ void stop() {
140
+ using namespace logger;
141
+ // Close all connections
142
+ while (this->subs.size() > 0) {
143
+ auto conn = this->subs.begin();
144
+ (*conn)->close();
145
+ this->eraseClosedConnections();
146
+ }
147
+ plugin::PackageHandler<T>::stop();
148
+
149
+ newConnectionCallbacks.clear();
150
+ droppedConnectionCallbacks.clear();
151
+ changedConnectionCallbacks.clear();
152
+
153
+ if (!isExternalScheduler) {
154
+ delete mScheduler;
155
+ }
156
+ }
157
+
158
+ /** Perform crucial maintenance task
159
+ *
160
+ * Add this to your loop() function. This routine runs various maintenance
161
+ * tasks.
162
+ */
163
+ void update(void) {
164
+ if (semaphoreTake()) {
165
+ // Check if something is executed (returns false)
166
+ if (!mScheduler->execute())
167
+ Log(logger::GENERAL, "update(): Scheduler executed a task\n");
168
+ semaphoreGive();
169
+ }
170
+ return;
171
+ }
172
+
173
+ /** Send message to a specific node
174
+ *
175
+ * @param destId The nodeId of the node to send it to.
176
+ * @param msg The message to send
177
+ *
178
+ * @return true if everything works, false if not.
179
+ */
180
+ bool sendSingle(uint32_t destId, TSTRING msg) {
181
+ Log(logger::COMMUNICATION, "sendSingle(): dest=%u msg=%s\n", destId,
182
+ msg.c_str());
183
+ auto single = painlessmesh::protocol::Single(this->nodeId, destId, msg);
184
+ return painlessmesh::router::send<T>(single, (*this));
185
+ }
186
+
187
+ /** Broadcast a message to every node on the mesh network.
188
+ *
189
+ * @param includeSelf Send message to myself as well. Default is false.
190
+ *
191
+ * @return true if everything works, false if not
192
+ */
193
+ bool sendBroadcast(TSTRING msg, bool includeSelf = false) {
194
+ using namespace logger;
195
+ Log(COMMUNICATION, "sendBroadcast(): msg=%s\n", msg.c_str());
196
+ painlessmesh::protocol::Broadcast pkg(this->nodeId, 0, msg);
197
+ auto success = router::broadcast<protocol::Broadcast, T>(pkg, (*this), 0);
198
+ if (includeSelf) {
199
+ protocol::Variant var(pkg);
200
+ this->callbackList.execute(var.type(), var, NULL, 0);
201
+ }
202
+ if (success > 0) return true;
203
+ return false;
204
+ }
205
+
206
+ /** Sends a node a packet to measure network trip delay to that node.
207
+ *
208
+ * After calling this function, user program have to wait to the response in
209
+ * the form of a callback specified by onNodeDelayReceived().
210
+ *
211
+ * @return true if nodeId is connected to the mesh, false otherwise
212
+ */
213
+ bool startDelayMeas(uint32_t id) {
214
+ using namespace logger;
215
+ Log(S_TIME, "startDelayMeas(): NodeId %u\n", id);
216
+ auto conn = painlessmesh::router::findRoute<T>((*this), id);
217
+ if (!conn) return false;
218
+ return router::send<protocol::TimeDelay, T>(
219
+ protocol::TimeDelay(this->nodeId, id, this->getNodeTime()), conn);
220
+ }
221
+
222
+ /** Set a callback routine for any messages that are addressed to this node.
223
+ *
224
+ * Every time this node receives a message, this callback routine will the
225
+ * called. “from” is the id of the original sender of the message, and “msg”
226
+ * is a string that contains the message. The message can be anything. A
227
+ * JSON, some other text string, or binary data.
228
+ *
229
+ * \code
230
+ * mesh.onReceive([](auto nodeId, auto msg) {
231
+ * // Do something with the message
232
+ * Serial.println(msg);
233
+ * });
234
+ * \endcode
235
+ */
236
+ void onReceive(receivedCallback_t onReceive) {
237
+ using namespace painlessmesh;
238
+ this->callbackList.onPackage(
239
+ protocol::SINGLE,
240
+ [onReceive](protocol::Variant &variant, std::shared_ptr<T>, uint32_t) {
241
+ auto pkg = variant.to<protocol::Single>();
242
+ onReceive(pkg.from, pkg.msg);
243
+ return false;
244
+ });
245
+ this->callbackList.onPackage(
246
+ protocol::BROADCAST,
247
+ [onReceive](protocol::Variant &variant, std::shared_ptr<T>, uint32_t) {
248
+ auto pkg = variant.to<protocol::Broadcast>();
249
+ onReceive(pkg.from, pkg.msg);
250
+ return false;
251
+ });
252
+ }
253
+
254
+ /** Callback that gets called every time the local node makes a new
255
+ * connection.
256
+ *
257
+ * \code
258
+ * mesh.onNewConnection([](auto nodeId) {
259
+ * // Do something with the event
260
+ * Serial.println(String(nodeId));
261
+ * });
262
+ * \endcode
263
+ */
264
+ void onNewConnection(newConnectionCallback_t onNewConnection) {
265
+ Log(logger::GENERAL, "onNewConnection():\n");
266
+ newConnectionCallbacks.push_back([onNewConnection](uint32_t nodeId) {
267
+ if (nodeId != 0) onNewConnection(nodeId);
268
+ });
269
+ }
270
+
271
+ /** Callback that gets called every time the local node drops a connection.
272
+ *
273
+ * \code
274
+ * mesh.onDroppedConnection([](auto nodeId) {
275
+ * // Do something with the event
276
+ * Serial.println(String(nodeId));
277
+ * });
278
+ * \endcode
279
+ */
280
+ void onDroppedConnection(droppedConnectionCallback_t onDroppedConnection) {
281
+ droppedConnectionCallbacks.push_back(
282
+ [onDroppedConnection](uint32_t nodeId, bool station) {
283
+ if (nodeId != 0) onDroppedConnection(nodeId);
284
+ });
285
+ }
286
+
287
+ /** Callback that gets called every time the layout of the mesh changes
288
+ *
289
+ * \code
290
+ * mesh.onChangedConnections([]() {
291
+ * // Do something with the event
292
+ * });
293
+ * \endcode
294
+ */
295
+ void onChangedConnections(changedConnectionsCallback_t onChangedConnections) {
296
+ Log(logger::GENERAL, "onChangedConnections():\n");
297
+ changedConnectionCallbacks.push_back(
298
+ [onChangedConnections](uint32_t nodeId) {
299
+ if (nodeId != 0) onChangedConnections();
300
+ });
301
+ }
302
+
303
+ /** Callback that gets called every time node time gets adjusted
304
+ *
305
+ * Node time is automatically kept in sync in the mesh. This gets called
306
+ * whenever the time is to far out of sync with the rest of the mesh and gets
307
+ * adjusted.
308
+ *
309
+ * \code
310
+ * mesh.onNodeTimeAdjusted([](auto offset) {
311
+ * // Do something with the event
312
+ * Serial.println(String(offset));
313
+ * });
314
+ * \endcode
315
+ */
316
+ void onNodeTimeAdjusted(nodeTimeAdjustedCallback_t onTimeAdjusted) {
317
+ Log(logger::GENERAL, "onNodeTimeAdjusted():\n");
318
+ nodeTimeAdjustedCallback = onTimeAdjusted;
319
+ }
320
+
321
+ /** Callback that gets called when a delay measurement is received.
322
+ *
323
+ * This fires when a time delay masurement response is received, after a
324
+ * request was sent.
325
+ *
326
+ * \code
327
+ * mesh.onNodeDelayReceived([](auto nodeId, auto delay) {
328
+ * // Do something with the event
329
+ * Serial.println(String(delay));
330
+ * });
331
+ * \endcode
332
+ */
333
+ void onNodeDelayReceived(nodeDelayCallback_t onDelayReceived) {
334
+ Log(logger::GENERAL, "onNodeDelayReceived():\n");
335
+ nodeDelayReceivedCallback = onDelayReceived;
336
+ }
337
+
338
+ /**
339
+ * Are we connected/know a route to the given node?
340
+ *
341
+ * @param nodeId The nodeId we are looking for
342
+ */
343
+ bool isConnected(uint32_t nodeId) {
344
+ return painlessmesh::router::findRoute<T>((*this), nodeId) != NULL;
345
+ }
346
+
347
+ /** Get a list of all known nodes.
348
+ *
349
+ * This includes nodes that are both directly and indirectly connected to the
350
+ * current node.
351
+ */
352
+ std::list<uint32_t> getNodeList(bool includeSelf = false) {
353
+ return painlessmesh::layout::asList(this->asNodeTree(), includeSelf);
354
+ }
355
+
356
+ /**
357
+ * Return a json representation of the current mesh layout
358
+ */
359
+ inline TSTRING subConnectionJson(bool pretty = false) {
360
+ return this->asNodeTree().toString(pretty);
361
+ }
362
+
363
+ inline std::shared_ptr<Task> addTask(unsigned long aInterval,
364
+ long aIterations,
365
+ std::function<void()> aCallback) {
366
+ return plugin::PackageHandler<T>::addTask((*this->mScheduler), aInterval,
367
+ aIterations, aCallback);
368
+ }
369
+
370
+ inline std::shared_ptr<Task> addTask(std::function<void()> aCallback) {
371
+ return plugin::PackageHandler<T>::addTask((*this->mScheduler), aCallback);
372
+ }
373
+
374
+ ~Mesh() {
375
+ this->stop();
376
+ if (!isExternalScheduler) delete mScheduler;
377
+ }
378
+
379
+ protected:
380
+ void setScheduler(Scheduler *baseScheduler) {
381
+ this->mScheduler = baseScheduler;
382
+ isExternalScheduler = true;
383
+ }
384
+
385
+ void startTimeSync(std::shared_ptr<T> conn) {
386
+ using namespace logger;
387
+ Log(S_TIME, "startTimeSync(): from %u with %u\n", this->nodeId,
388
+ conn->nodeId);
389
+ painlessmesh::protocol::TimeSync timeSync;
390
+ if (ntp::adopt(this->asNodeTree(), (*conn))) {
391
+ timeSync = painlessmesh::protocol::TimeSync(this->nodeId, conn->nodeId,
392
+ this->getNodeTime());
393
+ Log(S_TIME, "startTimeSync(): Requesting time from %u\n", conn->nodeId);
394
+ } else {
395
+ timeSync = painlessmesh::protocol::TimeSync(this->nodeId, conn->nodeId);
396
+ Log(S_TIME, "startTimeSync(): Requesting %u to adopt our time\n",
397
+ conn->nodeId);
398
+ }
399
+ router::send<protocol::TimeSync, T>(timeSync, conn, true);
400
+ }
401
+
402
+ bool closeConnectionSTA() {
403
+ auto connection = this->subs.begin();
404
+ while (connection != this->subs.end()) {
405
+ if ((*connection)->station) {
406
+ // We found the STA connection, close it
407
+ (*connection)->close();
408
+ return true;
409
+ }
410
+ ++connection;
411
+ }
412
+ return false;
413
+ }
414
+
415
+ void eraseClosedConnections() {
416
+ using namespace logger;
417
+ Log(CONNECTION, "eraseClosedConnections():\n");
418
+ this->subs.remove_if(
419
+ [](const std::shared_ptr<T> &conn) { return !conn->connected(); });
420
+ }
421
+
422
+ // Callback functions
423
+ callback::List<uint32_t> newConnectionCallbacks;
424
+ callback::List<uint32_t, bool> droppedConnectionCallbacks;
425
+ callback::List<uint32_t> changedConnectionCallbacks;
426
+ nodeTimeAdjustedCallback_t nodeTimeAdjustedCallback;
427
+ nodeDelayCallback_t nodeDelayReceivedCallback;
428
+ #ifdef ESP32
429
+ SemaphoreHandle_t xSemaphore = NULL;
430
+ #endif
431
+
432
+ bool isExternalScheduler = false;
433
+
434
+ /// Is the node a root node
435
+ bool shouldContainRoot;
436
+
437
+ Scheduler *mScheduler;
438
+
439
+ /**
440
+ * Wrapper function for ESP32 semaphore function
441
+ *
442
+ * Waits for the semaphore to be available and then returns true
443
+ *
444
+ * Always return true on ESP8266
445
+ */
446
+ bool semaphoreTake() {
447
+ #ifdef ESP32
448
+ return xSemaphoreTake(xSemaphore, (TickType_t)10) == pdTRUE;
449
+ #else
450
+ return true;
451
+ #endif
452
+ }
453
+
454
+ /**
455
+ * Wrapper function for ESP32 semaphore give function
456
+ *
457
+ * Does nothing on ESP8266 hardware
458
+ */
459
+ void semaphoreGive() {
460
+ #ifdef ESP32
461
+ xSemaphoreGive(xSemaphore);
462
+ #endif
463
+ }
464
+
465
+ friend T;
466
+ friend void onDataCb(void *, AsyncClient *, void *, size_t);
467
+ friend void tcpSentCb(void *, AsyncClient *, size_t, uint32_t);
468
+ friend void meshRecvCb(void *, AsyncClient *, void *, size_t);
469
+ friend void painlessmesh::ntp::handleTimeSync<Mesh, T>(
470
+ Mesh &, painlessmesh::protocol::TimeSync, std::shared_ptr<T>, uint32_t);
471
+ friend void painlessmesh::ntp::handleTimeDelay<Mesh, T>(
472
+ Mesh &, painlessmesh::protocol::TimeDelay, std::shared_ptr<T>, uint32_t);
473
+ friend void painlessmesh::router::handleNodeSync<Mesh, T>(
474
+ Mesh &, protocol::NodeTree, std::shared_ptr<T> conn);
475
+ friend void painlessmesh::tcp::initServer<T, Mesh>(AsyncServer &, Mesh &);
476
+ friend void painlessmesh::tcp::connect<T, Mesh>(AsyncClient &, IPAddress,
477
+ uint16_t, Mesh &);
478
+ };
479
+
480
+ class Connection : public painlessmesh::layout::Neighbour,
481
+ public painlessmesh::tcp::BufferedConnection {
482
+ public:
483
+ Mesh<Connection> *mesh;
484
+ bool station = true;
485
+ bool newConnection = true;
486
+
487
+ Task timeSyncTask;
488
+ Task nodeSyncTask;
489
+ Task timeOutTask;
490
+
491
+ Connection(AsyncClient *client, Mesh<painlessmesh::Connection> *mesh,
492
+ bool station)
493
+ : painlessmesh::tcp::BufferedConnection(client),
494
+ mesh(mesh),
495
+ station(station) {}
496
+
497
+ void initTasks() {
498
+ auto self = this->shared_from_this();
499
+ auto mesh = this->mesh;
500
+ this->onReceive([self](const TSTRING &str) {
501
+ auto variant = painlessmesh::protocol::Variant(str);
502
+
503
+ router::routePackage<painlessmesh::Connection>(
504
+ (*self->mesh), self->shared_from_this(), str,
505
+ self->mesh->callbackList, self->mesh->getNodeTime());
506
+ });
507
+
508
+ this->onDisconnect([mesh, self]() {
509
+ Log.remote("id:%u AsyncClient disconnect\n", self->nodeId);
510
+ self->timeSyncTask.setCallback(NULL);
511
+ self->timeSyncTask.disable();
512
+ self->nodeSyncTask.setCallback(NULL);
513
+ self->nodeSyncTask.disable();
514
+ self->timeOutTask.setCallback(NULL);
515
+ self->timeOutTask.disable();
516
+ auto nodeId = self->nodeId;
517
+ auto station = self->station;
518
+ mesh->addTask([mesh, nodeId, station]() {
519
+ mesh->changedConnectionCallbacks.execute(nodeId);
520
+ mesh->droppedConnectionCallbacks.execute(nodeId, station);
521
+ });
522
+ self->clear();
523
+ });
524
+
525
+ using namespace logger;
526
+
527
+ timeOutTask.set(NODE_TIMEOUT, TASK_ONCE, [self]() {
528
+ Log(CONNECTION, "Time out reached\n");
529
+ Log.remote("id:%u TimeOut\n", self->nodeId);
530
+ self->close();
531
+ });
532
+ mesh->mScheduler->addTask(timeOutTask);
533
+
534
+ this->nodeSyncTask.set(TASK_MINUTE, TASK_FOREVER, [self]() {
535
+ Log(SYNC, "nodeSyncTask(): request with %u\n", self->nodeId);
536
+ router::send<protocol::NodeSyncRequest, Connection>(
537
+ self->request(self->mesh->asNodeTree()), self);
538
+ self->timeOutTask.disable();
539
+ self->timeOutTask.restartDelayed();
540
+ });
541
+
542
+ mesh->mScheduler->addTask(this->nodeSyncTask);
543
+ if (station)
544
+ this->nodeSyncTask.enable();
545
+ else
546
+ this->nodeSyncTask.enableDelayed(10 * TASK_SECOND);
547
+
548
+ Log(CONNECTION, "painlessmesh::Connection: New connection established.\n");
549
+ this->initialize(mesh->mScheduler);
550
+ }
551
+
552
+ bool addMessage(const TSTRING &msg, bool priority = false) {
553
+ return this->write(msg, priority);
554
+ }
555
+
556
+ protected:
557
+ std::shared_ptr<Connection> shared_from_this() { return shared_from(this); }
558
+ };
559
+ }; // namespace painlessmesh
560
+ #endif