@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,365 +1,365 @@
1
- #ifndef _PAINLESS_MESH_ARDUINO_WIFI_HPP_
2
- #define _PAINLESS_MESH_ARDUINO_WIFI_HPP_
3
-
4
- #include "painlessmesh/configuration.hpp"
5
-
6
- #include "painlessmesh/logger.hpp"
7
- #ifdef PAINLESSMESH_ENABLE_ARDUINO_WIFI
8
- #include "painlessMeshSTA.h"
9
-
10
- #include "painlessmesh/callback.hpp"
11
- #include "painlessmesh/mesh.hpp"
12
- #include "painlessmesh/router.hpp"
13
- #include "painlessmesh/tcp.hpp"
14
-
15
- extern painlessmesh::logger::LogClass Log;
16
-
17
- namespace painlessmesh {
18
- namespace wifi {
19
- class Mesh : public painlessmesh::Mesh<Connection> {
20
- public:
21
- /** Initialize the mesh network
22
- *
23
- * Add this to your setup() function. This routine does the following things:
24
- *
25
- * - Starts a wifi network
26
- * - Begins searching for other wifi networks that are part of the mesh
27
- * - Logs on to the best mesh network node it finds… if it doesn’t find
28
- * anything, it starts a new search in 5 seconds.
29
- *
30
- * @param ssid The name of your mesh. All nodes share same AP ssid. They are
31
- * distinguished by BSSID.
32
- * @param password Wifi password to your mesh.
33
- * @param port the TCP port that you want the mesh server to run on. Defaults
34
- * to 5555 if not specified.
35
- * @param connectMode Switch between WIFI_AP, WIFI_STA and WIFI_AP_STA
36
- * (default) mode
37
- */
38
- void init(TSTRING ssid, TSTRING password, uint16_t port = 5555,
39
- WiFiMode_t connectMode = WIFI_AP_STA, uint8_t channel = 1,
40
- uint8_t hidden = 0, uint8_t maxconn = MAX_CONN) {
41
- using namespace logger;
42
- // Init random generator seed to generate delay variance
43
- randomSeed(millis());
44
-
45
- // Shut Wifi down and start with a blank slage
46
- if (WiFi.status() != WL_DISCONNECTED) WiFi.disconnect();
47
-
48
- Log(STARTUP, "init(): %d\n",
49
- #if ESP_ARDUINO_VERSION_MAJOR >= 3
50
- // Disable autoconnect
51
- WiFi.setAutoReconnect(false));
52
- #else
53
- // Disable autoconnect
54
- WiFi.setAutoConnect(false));
55
- #endif
56
- WiFi.persistent(false);
57
-
58
- // start configuration
59
- if (!WiFi.mode(connectMode)) {
60
- Log(GENERAL, "WiFi.mode() false");
61
- }
62
-
63
- _meshSSID = ssid;
64
- _meshPassword = password;
65
- _meshChannel = channel;
66
- _meshHidden = hidden;
67
- _meshMaxConn = maxconn;
68
- _meshPort = port;
69
-
70
- uint8_t MAC[] = {0, 0, 0, 0, 0, 0};
71
- #if ESP_ARDUINO_VERSION_MAJOR >= 3
72
- esp_read_mac(MAC, ESP_MAC_WIFI_SOFTAP);
73
- #else
74
- if (WiFi.softAPmacAddress(MAC) == 0) {
75
- Log(ERROR, "init(): WiFi.softAPmacAddress(MAC) failed.\n");
76
- }
77
- #endif
78
- uint32_t nodeId = tcp::encodeNodeId(MAC);
79
- if (nodeId == 0) Log(ERROR, "NodeId set to 0\n");
80
-
81
- this->init(nodeId);
82
-
83
- tcpServerInit();
84
- eventHandleInit();
85
-
86
- _apIp = IPAddress(0, 0, 0, 0);
87
-
88
- if (connectMode & WIFI_AP) {
89
- apInit(nodeId); // setup AP
90
- }
91
- if (connectMode & WIFI_STA) {
92
- this->initStation();
93
- }
94
- }
95
-
96
- /** Initialize the mesh network
97
- *
98
- * Add this to your setup() function. This routine does the following things:
99
- *
100
- * - Starts a wifi network
101
- * - Begins searching for other wifi networks that are part of the mesh
102
- * - Logs on to the best mesh network node it finds… if it doesn’t find
103
- * anything, it starts a new search in 5 seconds.
104
- *
105
- * @param ssid The name of your mesh. All nodes share same AP ssid. They are
106
- * distinguished by BSSID.
107
- * @param password Wifi password to your mesh.
108
- * @param port the TCP port that you want the mesh server to run on. Defaults
109
- * to 5555 if not specified.
110
- * @param connectMode Switch between WIFI_AP, WIFI_STA and WIFI_AP_STA
111
- * (default) mode
112
- */
113
- void init(TSTRING ssid, TSTRING password, Scheduler *baseScheduler,
114
- uint16_t port = 5555, WiFiMode_t connectMode = WIFI_AP_STA,
115
- uint8_t channel = 1, uint8_t hidden = 0,
116
- uint8_t maxconn = MAX_CONN) {
117
- this->setScheduler(baseScheduler);
118
- init(ssid, password, port, connectMode, channel, hidden, maxconn);
119
- }
120
-
121
- /**
122
- * Connect (as a station) to a specified network and ip
123
- *
124
- * You can pass {0,0,0,0} as IP to have it connect to the gateway
125
- *
126
- * This stops the node from scanning for other (non specified) nodes
127
- * and you should probably also use this node as an anchor: `setAnchor(true)`
128
- */
129
- void stationManual(TSTRING ssid, TSTRING password, uint16_t port = 0,
130
- IPAddress remote_ip = IPAddress(0, 0, 0, 0)) {
131
- // Set station config
132
- stationScan.manualIP = remote_ip;
133
-
134
- // Start scan
135
- stationScan.init(this, ssid, password, port, _meshChannel,
136
- static_cast<bool>(_meshHidden));
137
- stationScan.manual = true;
138
- }
139
-
140
- void initStation() {
141
- stationScan.init(this, _meshSSID, _meshPassword, _meshPort, _meshChannel,
142
- static_cast<bool>(_meshHidden));
143
- mScheduler->addTask(stationScan.task);
144
- stationScan.task.enable();
145
-
146
- this->droppedConnectionCallbacks.push_back(
147
- [this](uint32_t nodeId, bool station) {
148
- if (station) {
149
- if (WiFi.status() == WL_CONNECTED) WiFi.disconnect();
150
- // TODO: Can we do this when we get signalled that wifi disconnect
151
- // is complete
152
- this->stationScan.yieldConnectToAP();
153
- // Re-enable it if it was disabled
154
- this->stationScan.task.enableIfNot();
155
- }
156
- });
157
- }
158
-
159
- void tcpServerInit() {
160
- using namespace logger;
161
- Log(GENERAL, "tcpServerInit():\n");
162
- _tcpListener = new AsyncServer(_meshPort);
163
- painlessmesh::tcp::initServer<Connection, painlessmesh::Mesh<Connection>>(
164
- (*_tcpListener), (*this));
165
- Log(STARTUP, "AP tcp server established on port %d\n", _meshPort);
166
- return;
167
- }
168
-
169
- void tcpConnect() {
170
- using namespace logger;
171
- // TODO: move to Connection or StationConnection?
172
- Log(GENERAL, "tcpConnect():\n");
173
- if (stationScan.manual && stationScan.port == 0)
174
- return; // We have been configured not to connect to the mesh
175
-
176
- // TODO: We could pass this to tcpConnect instead of loading it here
177
- if (WiFi.status() == WL_CONNECTED && WiFi.localIP()) {
178
- AsyncClient *pConn = new AsyncClient();
179
-
180
- IPAddress ip = WiFi.gatewayIP();
181
- if (stationScan.manualIP) {
182
- ip = stationScan.manualIP;
183
- }
184
-
185
- painlessmesh::tcp::connect<Connection, painlessmesh::Mesh<Connection>>(
186
- (*pConn), ip, stationScan.port, (*this));
187
- } else {
188
- Log(ERROR, "tcpConnect(): err Something un expected in tcpConnect()\n");
189
- }
190
- }
191
-
192
- bool setHostname(const char *hostname) {
193
- #ifdef ESP8266
194
- return WiFi.hostname(hostname);
195
- #elif defined(ESP32)
196
- if (strlen(hostname) > 32) {
197
- return false;
198
- }
199
- return WiFi.setHostname(hostname);
200
- #endif // ESP8266
201
- }
202
-
203
- IPAddress getStationIP() { return WiFi.localIP(); }
204
- IPAddress getAPIP() { return _apIp; }
205
-
206
- void stop() {
207
- // remove all WiFi events
208
- #ifdef ESP32
209
- WiFi.removeEvent(eventScanDoneHandler);
210
- WiFi.removeEvent(eventSTAStartHandler);
211
- WiFi.removeEvent(eventSTADisconnectedHandler);
212
- WiFi.removeEvent(eventSTAGotIPHandler);
213
- #elif defined(ESP8266)
214
- eventSTAConnectedHandler = WiFiEventHandler();
215
- eventSTADisconnectedHandler = WiFiEventHandler();
216
- eventSTAGotIPHandler = WiFiEventHandler();
217
-
218
- stationScan.asyncTask.setCallback(NULL);
219
- mScheduler->deleteTask(stationScan.asyncTask);
220
- #endif // ESP32
221
- // Stop scanning task
222
- stationScan.task.setCallback(NULL);
223
- mScheduler->deleteTask(stationScan.task);
224
- painlessmesh::Mesh<Connection>::stop();
225
-
226
- // Shutdown wifi hardware
227
- if (WiFi.status() != WL_DISCONNECTED) WiFi.disconnect();
228
-
229
- // Delete the tcp server
230
- delete _tcpListener;
231
- }
232
-
233
- protected:
234
- friend class ::StationScan;
235
- TSTRING _meshSSID;
236
- TSTRING _meshPassword;
237
- uint8_t _meshChannel;
238
- uint8_t _meshHidden;
239
- uint8_t _meshMaxConn;
240
- uint16_t _meshPort;
241
-
242
- IPAddress _apIp;
243
- StationScan stationScan;
244
-
245
- void init(Scheduler *scheduler, uint32_t id) {
246
- painlessmesh::Mesh<Connection>::init(scheduler, id);
247
- }
248
-
249
- void init(uint32_t id) { painlessmesh::Mesh<Connection>::init(id); }
250
-
251
- void apInit(uint32_t nodeId) {
252
- _apIp = IPAddress(10, (nodeId & 0xFF00) >> 8, (nodeId & 0xFF), 1);
253
- IPAddress netmask(255, 255, 255, 0);
254
-
255
- WiFi.softAPConfig(_apIp, _apIp, netmask);
256
- WiFi.softAP(_meshSSID.c_str(), _meshPassword.c_str(), _meshChannel,
257
- _meshHidden, _meshMaxConn);
258
- }
259
- void eventHandleInit() {
260
- using namespace logger;
261
- #ifdef ESP32
262
- eventScanDoneHandler = WiFi.onEvent(
263
- [this](WiFiEvent_t event, WiFiEventInfo_t info) {
264
- if (this->semaphoreTake()) {
265
- Log(CONNECTION,
266
- "eventScanDoneHandler: ARDUINO_EVENT_WIFI_SCAN_DONE\n");
267
- this->stationScan.scanComplete();
268
- this->semaphoreGive();
269
- }
270
- },
271
- #if ESP_ARDUINO_VERSION_MAJOR >= 2
272
- WiFiEvent_t::ARDUINO_EVENT_WIFI_SCAN_DONE);
273
- #else
274
- WiFiEvent_t::SYSTEM_EVENT_SCAN_DONE);
275
- #endif
276
-
277
- eventSTAStartHandler = WiFi.onEvent(
278
- [this](WiFiEvent_t event, WiFiEventInfo_t info) {
279
- if (this->semaphoreTake()) {
280
- Log(CONNECTION,
281
- "eventSTAStartHandler: ARDUINO_EVENT_WIFI_STA_START\n");
282
- this->semaphoreGive();
283
- }
284
- },
285
- #if ESP_ARDUINO_VERSION_MAJOR >= 2
286
- WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_START);
287
- #else
288
- WiFiEvent_t::SYSTEM_EVENT_STA_START);
289
- #endif
290
-
291
- eventSTADisconnectedHandler = WiFi.onEvent(
292
- [this](WiFiEvent_t event, WiFiEventInfo_t info) {
293
- if (this->semaphoreTake()) {
294
- Log(CONNECTION,
295
- "eventSTADisconnectedHandler: "
296
- "ARDUINO_EVENT_WIFI_STA_DISCONNECTED\n");
297
- this->droppedConnectionCallbacks.execute(0, true);
298
- this->semaphoreGive();
299
- }
300
- },
301
- #if ESP_ARDUINO_VERSION_MAJOR >= 2
302
- WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_DISCONNECTED);
303
- #else
304
- WiFiEvent_t::SYSTEM_EVENT_STA_DISCONNECTED);
305
- #endif
306
-
307
- eventSTAGotIPHandler = WiFi.onEvent(
308
- [this](WiFiEvent_t event, WiFiEventInfo_t info) {
309
- if (this->semaphoreTake()) {
310
- Log(CONNECTION,
311
- "eventSTAGotIPHandler: ARDUINO_EVENT_WIFI_STA_GOT_IP\n");
312
- this->tcpConnect(); // Connect to TCP port
313
- this->semaphoreGive();
314
- }
315
- },
316
- #if ESP_ARDUINO_VERSION_MAJOR >= 2
317
- WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_GOT_IP);
318
- #else
319
- WiFiEvent_t::SYSTEM_EVENT_STA_GOT_IP);
320
- #endif
321
-
322
- #elif defined(ESP8266)
323
- eventSTAConnectedHandler = WiFi.onStationModeConnected(
324
- [&](const WiFiEventStationModeConnected &event) {
325
- // Log(CONNECTION, "Event: Station Mode Connected to \"%s\"\n",
326
- // event.ssid.c_str());
327
- Log(CONNECTION, "Event: Station Mode Connected\n");
328
- });
329
-
330
- eventSTADisconnectedHandler = WiFi.onStationModeDisconnected(
331
- [&](const WiFiEventStationModeDisconnected &event) {
332
- Log(CONNECTION, "Event: Station Mode Disconnected\n");
333
- this->droppedConnectionCallbacks.execute(0, true);
334
- });
335
-
336
- eventSTAGotIPHandler =
337
- WiFi.onStationModeGotIP([&](const WiFiEventStationModeGotIP &event) {
338
- Log(CONNECTION,
339
- "Event: Station Mode Got IP (IP: %s Mask: %s Gateway: %s)\n",
340
- event.ip.toString().c_str(), event.mask.toString().c_str(),
341
- event.gw.toString().c_str());
342
- this->tcpConnect(); // Connect to TCP port
343
- });
344
- #endif // ESP32
345
- return;
346
- }
347
-
348
- #ifdef ESP32
349
- WiFiEventId_t eventScanDoneHandler;
350
- WiFiEventId_t eventSTAStartHandler;
351
- WiFiEventId_t eventSTADisconnectedHandler;
352
- WiFiEventId_t eventSTAGotIPHandler;
353
- #elif defined(ESP8266)
354
- WiFiEventHandler eventSTAConnectedHandler;
355
- WiFiEventHandler eventSTADisconnectedHandler;
356
- WiFiEventHandler eventSTAGotIPHandler;
357
- #endif // ESP8266
358
- AsyncServer *_tcpListener;
359
- };
360
- } // namespace wifi
361
- }; // namespace painlessmesh
362
-
363
- #endif
364
-
365
- #endif
1
+ #ifndef _PAINLESS_MESH_ARDUINO_WIFI_HPP_
2
+ #define _PAINLESS_MESH_ARDUINO_WIFI_HPP_
3
+
4
+ #include "painlessmesh/configuration.hpp"
5
+
6
+ #include "painlessmesh/logger.hpp"
7
+ #ifdef PAINLESSMESH_ENABLE_ARDUINO_WIFI
8
+ #include "painlessMeshSTA.h"
9
+
10
+ #include "painlessmesh/callback.hpp"
11
+ #include "painlessmesh/mesh.hpp"
12
+ #include "painlessmesh/router.hpp"
13
+ #include "painlessmesh/tcp.hpp"
14
+
15
+ extern painlessmesh::logger::LogClass Log;
16
+
17
+ namespace painlessmesh {
18
+ namespace wifi {
19
+ class Mesh : public painlessmesh::Mesh<Connection> {
20
+ public:
21
+ /** Initialize the mesh network
22
+ *
23
+ * Add this to your setup() function. This routine does the following things:
24
+ *
25
+ * - Starts a wifi network
26
+ * - Begins searching for other wifi networks that are part of the mesh
27
+ * - Logs on to the best mesh network node it finds… if it doesn’t find
28
+ * anything, it starts a new search in 5 seconds.
29
+ *
30
+ * @param ssid The name of your mesh. All nodes share same AP ssid. They are
31
+ * distinguished by BSSID.
32
+ * @param password Wifi password to your mesh.
33
+ * @param port the TCP port that you want the mesh server to run on. Defaults
34
+ * to 5555 if not specified.
35
+ * @param connectMode Switch between WIFI_AP, WIFI_STA and WIFI_AP_STA
36
+ * (default) mode
37
+ */
38
+ void init(TSTRING ssid, TSTRING password, uint16_t port = 5555,
39
+ WiFiMode_t connectMode = WIFI_AP_STA, uint8_t channel = 1,
40
+ uint8_t hidden = 0, uint8_t maxconn = MAX_CONN) {
41
+ using namespace logger;
42
+ // Init random generator seed to generate delay variance
43
+ randomSeed(millis());
44
+
45
+ // Shut Wifi down and start with a blank slage
46
+ if (WiFi.status() != WL_DISCONNECTED) WiFi.disconnect();
47
+
48
+ Log(STARTUP, "init(): %d\n",
49
+ #if ESP_ARDUINO_VERSION_MAJOR >= 3
50
+ // Disable autoconnect
51
+ WiFi.setAutoReconnect(false));
52
+ #else
53
+ // Disable autoconnect
54
+ WiFi.setAutoConnect(false));
55
+ #endif
56
+ WiFi.persistent(false);
57
+
58
+ // start configuration
59
+ if (!WiFi.mode(connectMode)) {
60
+ Log(GENERAL, "WiFi.mode() false");
61
+ }
62
+
63
+ _meshSSID = ssid;
64
+ _meshPassword = password;
65
+ _meshChannel = channel;
66
+ _meshHidden = hidden;
67
+ _meshMaxConn = maxconn;
68
+ _meshPort = port;
69
+
70
+ uint8_t MAC[] = {0, 0, 0, 0, 0, 0};
71
+ #if ESP_ARDUINO_VERSION_MAJOR >= 3
72
+ esp_read_mac(MAC, ESP_MAC_WIFI_SOFTAP);
73
+ #else
74
+ if (WiFi.softAPmacAddress(MAC) == 0) {
75
+ Log(ERROR, "init(): WiFi.softAPmacAddress(MAC) failed.\n");
76
+ }
77
+ #endif
78
+ uint32_t nodeId = tcp::encodeNodeId(MAC);
79
+ if (nodeId == 0) Log(ERROR, "NodeId set to 0\n");
80
+
81
+ this->init(nodeId);
82
+
83
+ tcpServerInit();
84
+ eventHandleInit();
85
+
86
+ _apIp = IPAddress(0, 0, 0, 0);
87
+
88
+ if (connectMode & WIFI_AP) {
89
+ apInit(nodeId); // setup AP
90
+ }
91
+ if (connectMode & WIFI_STA) {
92
+ this->initStation();
93
+ }
94
+ }
95
+
96
+ /** Initialize the mesh network
97
+ *
98
+ * Add this to your setup() function. This routine does the following things:
99
+ *
100
+ * - Starts a wifi network
101
+ * - Begins searching for other wifi networks that are part of the mesh
102
+ * - Logs on to the best mesh network node it finds… if it doesn’t find
103
+ * anything, it starts a new search in 5 seconds.
104
+ *
105
+ * @param ssid The name of your mesh. All nodes share same AP ssid. They are
106
+ * distinguished by BSSID.
107
+ * @param password Wifi password to your mesh.
108
+ * @param port the TCP port that you want the mesh server to run on. Defaults
109
+ * to 5555 if not specified.
110
+ * @param connectMode Switch between WIFI_AP, WIFI_STA and WIFI_AP_STA
111
+ * (default) mode
112
+ */
113
+ void init(TSTRING ssid, TSTRING password, Scheduler *baseScheduler,
114
+ uint16_t port = 5555, WiFiMode_t connectMode = WIFI_AP_STA,
115
+ uint8_t channel = 1, uint8_t hidden = 0,
116
+ uint8_t maxconn = MAX_CONN) {
117
+ this->setScheduler(baseScheduler);
118
+ init(ssid, password, port, connectMode, channel, hidden, maxconn);
119
+ }
120
+
121
+ /**
122
+ * Connect (as a station) to a specified network and ip
123
+ *
124
+ * You can pass {0,0,0,0} as IP to have it connect to the gateway
125
+ *
126
+ * This stops the node from scanning for other (non specified) nodes
127
+ * and you should probably also use this node as an anchor: `setAnchor(true)`
128
+ */
129
+ void stationManual(TSTRING ssid, TSTRING password, uint16_t port = 0,
130
+ IPAddress remote_ip = IPAddress(0, 0, 0, 0)) {
131
+ // Set station config
132
+ stationScan.manualIP = remote_ip;
133
+
134
+ // Start scan
135
+ stationScan.init(this, ssid, password, port, _meshChannel,
136
+ static_cast<bool>(_meshHidden));
137
+ stationScan.manual = true;
138
+ }
139
+
140
+ void initStation() {
141
+ stationScan.init(this, _meshSSID, _meshPassword, _meshPort, _meshChannel,
142
+ static_cast<bool>(_meshHidden));
143
+ mScheduler->addTask(stationScan.task);
144
+ stationScan.task.enable();
145
+
146
+ this->droppedConnectionCallbacks.push_back(
147
+ [this](uint32_t nodeId, bool station) {
148
+ if (station) {
149
+ if (WiFi.status() == WL_CONNECTED) WiFi.disconnect();
150
+ // TODO: Can we do this when we get signalled that wifi disconnect
151
+ // is complete
152
+ this->stationScan.yieldConnectToAP();
153
+ // Re-enable it if it was disabled
154
+ this->stationScan.task.enableIfNot();
155
+ }
156
+ });
157
+ }
158
+
159
+ void tcpServerInit() {
160
+ using namespace logger;
161
+ Log(GENERAL, "tcpServerInit():\n");
162
+ _tcpListener = new AsyncServer(_meshPort);
163
+ painlessmesh::tcp::initServer<Connection, painlessmesh::Mesh<Connection>>(
164
+ (*_tcpListener), (*this));
165
+ Log(STARTUP, "AP tcp server established on port %d\n", _meshPort);
166
+ return;
167
+ }
168
+
169
+ void tcpConnect() {
170
+ using namespace logger;
171
+ // TODO: move to Connection or StationConnection?
172
+ Log(GENERAL, "tcpConnect():\n");
173
+ if (stationScan.manual && stationScan.port == 0)
174
+ return; // We have been configured not to connect to the mesh
175
+
176
+ // TODO: We could pass this to tcpConnect instead of loading it here
177
+ if (WiFi.status() == WL_CONNECTED && WiFi.localIP()) {
178
+ AsyncClient *pConn = new AsyncClient();
179
+
180
+ IPAddress ip = WiFi.gatewayIP();
181
+ if (stationScan.manualIP) {
182
+ ip = stationScan.manualIP;
183
+ }
184
+
185
+ painlessmesh::tcp::connect<Connection, painlessmesh::Mesh<Connection>>(
186
+ (*pConn), ip, stationScan.port, (*this));
187
+ } else {
188
+ Log(ERROR, "tcpConnect(): err Something un expected in tcpConnect()\n");
189
+ }
190
+ }
191
+
192
+ bool setHostname(const char *hostname) {
193
+ #ifdef ESP8266
194
+ return WiFi.hostname(hostname);
195
+ #elif defined(ESP32)
196
+ if (strlen(hostname) > 32) {
197
+ return false;
198
+ }
199
+ return WiFi.setHostname(hostname);
200
+ #endif // ESP8266
201
+ }
202
+
203
+ IPAddress getStationIP() { return WiFi.localIP(); }
204
+ IPAddress getAPIP() { return _apIp; }
205
+
206
+ void stop() {
207
+ // remove all WiFi events
208
+ #ifdef ESP32
209
+ WiFi.removeEvent(eventScanDoneHandler);
210
+ WiFi.removeEvent(eventSTAStartHandler);
211
+ WiFi.removeEvent(eventSTADisconnectedHandler);
212
+ WiFi.removeEvent(eventSTAGotIPHandler);
213
+ #elif defined(ESP8266)
214
+ eventSTAConnectedHandler = WiFiEventHandler();
215
+ eventSTADisconnectedHandler = WiFiEventHandler();
216
+ eventSTAGotIPHandler = WiFiEventHandler();
217
+
218
+ stationScan.asyncTask.setCallback(NULL);
219
+ mScheduler->deleteTask(stationScan.asyncTask);
220
+ #endif // ESP32
221
+ // Stop scanning task
222
+ stationScan.task.setCallback(NULL);
223
+ mScheduler->deleteTask(stationScan.task);
224
+ painlessmesh::Mesh<Connection>::stop();
225
+
226
+ // Shutdown wifi hardware
227
+ if (WiFi.status() != WL_DISCONNECTED) WiFi.disconnect();
228
+
229
+ // Delete the tcp server
230
+ delete _tcpListener;
231
+ }
232
+
233
+ protected:
234
+ friend class ::StationScan;
235
+ TSTRING _meshSSID;
236
+ TSTRING _meshPassword;
237
+ uint8_t _meshChannel;
238
+ uint8_t _meshHidden;
239
+ uint8_t _meshMaxConn;
240
+ uint16_t _meshPort;
241
+
242
+ IPAddress _apIp;
243
+ StationScan stationScan;
244
+
245
+ void init(Scheduler *scheduler, uint32_t id) {
246
+ painlessmesh::Mesh<Connection>::init(scheduler, id);
247
+ }
248
+
249
+ void init(uint32_t id) { painlessmesh::Mesh<Connection>::init(id); }
250
+
251
+ void apInit(uint32_t nodeId) {
252
+ _apIp = IPAddress(10, (nodeId & 0xFF00) >> 8, (nodeId & 0xFF), 1);
253
+ IPAddress netmask(255, 255, 255, 0);
254
+
255
+ WiFi.softAPConfig(_apIp, _apIp, netmask);
256
+ WiFi.softAP(_meshSSID.c_str(), _meshPassword.c_str(), _meshChannel,
257
+ _meshHidden, _meshMaxConn);
258
+ }
259
+ void eventHandleInit() {
260
+ using namespace logger;
261
+ #ifdef ESP32
262
+ eventScanDoneHandler = WiFi.onEvent(
263
+ [this](WiFiEvent_t event, WiFiEventInfo_t info) {
264
+ if (this->semaphoreTake()) {
265
+ Log(CONNECTION,
266
+ "eventScanDoneHandler: ARDUINO_EVENT_WIFI_SCAN_DONE\n");
267
+ this->stationScan.scanComplete();
268
+ this->semaphoreGive();
269
+ }
270
+ },
271
+ #if ESP_ARDUINO_VERSION_MAJOR >= 2
272
+ WiFiEvent_t::ARDUINO_EVENT_WIFI_SCAN_DONE);
273
+ #else
274
+ WiFiEvent_t::SYSTEM_EVENT_SCAN_DONE);
275
+ #endif
276
+
277
+ eventSTAStartHandler = WiFi.onEvent(
278
+ [this](WiFiEvent_t event, WiFiEventInfo_t info) {
279
+ if (this->semaphoreTake()) {
280
+ Log(CONNECTION,
281
+ "eventSTAStartHandler: ARDUINO_EVENT_WIFI_STA_START\n");
282
+ this->semaphoreGive();
283
+ }
284
+ },
285
+ #if ESP_ARDUINO_VERSION_MAJOR >= 2
286
+ WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_START);
287
+ #else
288
+ WiFiEvent_t::SYSTEM_EVENT_STA_START);
289
+ #endif
290
+
291
+ eventSTADisconnectedHandler = WiFi.onEvent(
292
+ [this](WiFiEvent_t event, WiFiEventInfo_t info) {
293
+ if (this->semaphoreTake()) {
294
+ Log(CONNECTION,
295
+ "eventSTADisconnectedHandler: "
296
+ "ARDUINO_EVENT_WIFI_STA_DISCONNECTED\n");
297
+ this->droppedConnectionCallbacks.execute(0, true);
298
+ this->semaphoreGive();
299
+ }
300
+ },
301
+ #if ESP_ARDUINO_VERSION_MAJOR >= 2
302
+ WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_DISCONNECTED);
303
+ #else
304
+ WiFiEvent_t::SYSTEM_EVENT_STA_DISCONNECTED);
305
+ #endif
306
+
307
+ eventSTAGotIPHandler = WiFi.onEvent(
308
+ [this](WiFiEvent_t event, WiFiEventInfo_t info) {
309
+ if (this->semaphoreTake()) {
310
+ Log(CONNECTION,
311
+ "eventSTAGotIPHandler: ARDUINO_EVENT_WIFI_STA_GOT_IP\n");
312
+ this->tcpConnect(); // Connect to TCP port
313
+ this->semaphoreGive();
314
+ }
315
+ },
316
+ #if ESP_ARDUINO_VERSION_MAJOR >= 2
317
+ WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_GOT_IP);
318
+ #else
319
+ WiFiEvent_t::SYSTEM_EVENT_STA_GOT_IP);
320
+ #endif
321
+
322
+ #elif defined(ESP8266)
323
+ eventSTAConnectedHandler = WiFi.onStationModeConnected(
324
+ [&](const WiFiEventStationModeConnected &event) {
325
+ // Log(CONNECTION, "Event: Station Mode Connected to \"%s\"\n",
326
+ // event.ssid.c_str());
327
+ Log(CONNECTION, "Event: Station Mode Connected\n");
328
+ });
329
+
330
+ eventSTADisconnectedHandler = WiFi.onStationModeDisconnected(
331
+ [&](const WiFiEventStationModeDisconnected &event) {
332
+ Log(CONNECTION, "Event: Station Mode Disconnected\n");
333
+ this->droppedConnectionCallbacks.execute(0, true);
334
+ });
335
+
336
+ eventSTAGotIPHandler =
337
+ WiFi.onStationModeGotIP([&](const WiFiEventStationModeGotIP &event) {
338
+ Log(CONNECTION,
339
+ "Event: Station Mode Got IP (IP: %s Mask: %s Gateway: %s)\n",
340
+ event.ip.toString().c_str(), event.mask.toString().c_str(),
341
+ event.gw.toString().c_str());
342
+ this->tcpConnect(); // Connect to TCP port
343
+ });
344
+ #endif // ESP32
345
+ return;
346
+ }
347
+
348
+ #ifdef ESP32
349
+ WiFiEventId_t eventScanDoneHandler;
350
+ WiFiEventId_t eventSTAStartHandler;
351
+ WiFiEventId_t eventSTADisconnectedHandler;
352
+ WiFiEventId_t eventSTAGotIPHandler;
353
+ #elif defined(ESP8266)
354
+ WiFiEventHandler eventSTAConnectedHandler;
355
+ WiFiEventHandler eventSTADisconnectedHandler;
356
+ WiFiEventHandler eventSTAGotIPHandler;
357
+ #endif // ESP8266
358
+ AsyncServer *_tcpListener;
359
+ };
360
+ } // namespace wifi
361
+ }; // namespace painlessmesh
362
+
363
+ #endif
364
+
365
+ #endif