@alteriom/painlessmesh 1.6.1 → 1.7.3

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 (152) hide show
  1. package/CHANGELOG.md +435 -144
  2. package/LICENSE +674 -674
  3. package/README.md +491 -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 +130 -71
  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/archive/DOCUSAURUS_DEPLOYMENT.md +166 -0
  25. package/docs/archive/FEATURE_PROPOSALS.md +337 -0
  26. package/docs/archive/LIBRARY_JSON_FIX.md +98 -0
  27. package/docs/archive/LIBRARY_STRUCTURE_FIX.md +215 -0
  28. package/docs/archive/PHASE1_IMPLEMENTATION.md +325 -0
  29. package/docs/archive/PHASE2_IMPLEMENTATION.md +567 -0
  30. package/docs/archive/RELEASE_SUMMARY.md +173 -0
  31. package/docs/archive/SCONS_BUILD_FIX.md +313 -0
  32. package/docs/archive/TRIGGER_RELEASE.md +280 -0
  33. package/docs/archive/VECTOR_INCLUDE_FIX.md +129 -0
  34. package/docs/archive/ota-and-status-enhancements.md +911 -0
  35. package/docs/archive/ota-status-architecture-diagrams.md +658 -0
  36. package/docs/archive/ota-status-quick-reference.md +284 -0
  37. package/docs/development/ARDUINO_COMPLIANCE_SUMMARY.md +71 -0
  38. package/docs/development/CODE_REFACTORING_RECOMMENDATIONS.md +1011 -0
  39. package/docs/development/DOCKER_TESTING.md +196 -0
  40. package/docs/development/PLATFORMIO_USAGE.md +180 -0
  41. package/docs/development/TESTING_SUMMARY.md +126 -0
  42. package/docs/development/contributing.md +301 -0
  43. package/docs/development/documentation.md +583 -0
  44. package/docs/getting-started/first-mesh.md +409 -409
  45. package/docs/getting-started/installation.md +274 -274
  46. package/docs/getting-started/quickstart.md +157 -157
  47. package/docs/improvements/FUTURE_PROPOSALS.md +1016 -0
  48. package/docs/improvements/IMPLEMENTATION_HISTORY.md +1091 -0
  49. package/docs/improvements/OTA_STATUS_ENHANCEMENTS.md +709 -0
  50. package/docs/improvements/README.md +212 -69
  51. package/docs/platformio-publishing.md +255 -0
  52. package/docs/platformio-setup-summary.md +121 -0
  53. package/docs/releases/FEATURE_HISTORY.md +543 -0
  54. package/docs/releases/PATCH_v1.7.3.md +262 -0
  55. package/docs/releases/PHASE1_SUMMARY.md +246 -0
  56. package/docs/releases/PHASE2_SUMMARY.md +499 -0
  57. package/docs/releases/RELEASE_NOTES_1.7.0.md +539 -0
  58. package/docs/troubleshooting/common-issues.md +520 -520
  59. package/docs/troubleshooting/debugging.md +455 -0
  60. package/docs/troubleshooting/faq.md +472 -472
  61. package/docs/tutorials/basic-examples.md +717 -717
  62. package/docs/wiki/API-Reference.md +245 -245
  63. package/docs/wiki/Complete-Documentation.md +122 -122
  64. package/examples/alteriom/README.md +139 -81
  65. package/examples/alteriom/alteriom.ino +186 -185
  66. package/examples/alteriom/alteriom_sensor_package.hpp +240 -127
  67. package/examples/alteriom/platformio.ini +24 -24
  68. package/examples/alteriomImproved/alteriom_sensor_package.hpp +224 -0
  69. package/examples/{alteriom → alteriomImproved}/improved_sensor_node.ino +245 -245
  70. package/examples/alteriomImproved/platformio.ini +25 -0
  71. package/examples/alteriomPhase1/alteriom_sensor_package.hpp +224 -0
  72. package/examples/alteriomPhase1/phase1_features.ino +242 -0
  73. package/examples/alteriomPhase1/platformio.ini +25 -0
  74. package/examples/alteriomPhase2/alteriom_sensor_package.hpp +224 -0
  75. package/examples/alteriomPhase2/phase2_features.ino +186 -0
  76. package/examples/alteriomPhase2/platformio.ini +25 -0
  77. package/examples/{alteriom → alteriomSensorNode}/alteriom_sensor_node.ino +183 -183
  78. package/examples/alteriomSensorNode/alteriom_sensor_package.hpp +224 -0
  79. package/examples/alteriomSensorNode/platformio.ini +25 -0
  80. package/examples/basic/basic.ino +66 -66
  81. package/examples/basic/platformio.ini +25 -25
  82. package/examples/bridge/bridge.ino +51 -51
  83. package/examples/bridge/mesh_event_publisher.hpp +253 -0
  84. package/examples/bridge/mesh_topology_reporter.hpp +303 -0
  85. package/examples/bridge/mqtt_command_bridge.hpp +459 -0
  86. package/examples/bridge/mqtt_status_bridge.hpp +519 -0
  87. package/examples/bridge/platformio.ini +25 -25
  88. package/examples/echoNode/echoNode.ino +33 -33
  89. package/examples/echoNode/platformio.ini +25 -25
  90. package/examples/logClient/logClient.ino +109 -109
  91. package/examples/logClient/platformio.ini +25 -25
  92. package/examples/logServer/logServer.ino +81 -81
  93. package/examples/logServer/platformio.ini +25 -25
  94. package/examples/meshCommandNode/alteriom_sensor_package.hpp +235 -0
  95. package/examples/meshCommandNode/meshCommandNode.ino +263 -0
  96. package/examples/meshCommandNode/platformio.ini +25 -0
  97. package/examples/mqttBridge/mqttBridge.ino +118 -118
  98. package/examples/mqttBridge/platformio.ini +26 -26
  99. package/examples/mqttCommandBridge/alteriom_sensor_package.hpp +235 -0
  100. package/examples/mqttCommandBridge/mesh_event_publisher.hpp +253 -0
  101. package/examples/mqttCommandBridge/mesh_topology_reporter.hpp +303 -0
  102. package/examples/mqttCommandBridge/mqttCommandBridge.ino +252 -0
  103. package/examples/mqttCommandBridge/mqtt_command_bridge.hpp +459 -0
  104. package/examples/mqttCommandBridge/platformio.ini +26 -0
  105. package/examples/mqttStatusBridge/mqttStatusBridge.ino +216 -0
  106. package/examples/mqttStatusBridge/mqtt_status_bridge.hpp +522 -0
  107. package/examples/mqttStatusBridge/platformio.ini +26 -0
  108. package/examples/mqttTopologyTest/README.md +467 -0
  109. package/examples/mqttTopologyTest/mqttTopologyTest.ino +748 -0
  110. package/examples/mqttTopologyTest/platformio.ini +26 -0
  111. package/examples/namedMesh/namedMesh.ino +97 -97
  112. package/examples/namedMesh/platformio.ini +25 -25
  113. package/examples/otaReceiver/otaReceiver.ino +79 -79
  114. package/examples/otaReceiver/platformio.ini +25 -25
  115. package/examples/otaSender/otaSender.ino +160 -151
  116. package/examples/otaSender/platformio.ini +25 -25
  117. package/examples/startHere/platformio.ini +25 -25
  118. package/examples/startHere/startHere.ino +159 -159
  119. package/examples/webServer/platformio.ini +27 -27
  120. package/examples/webServer/webServer.ino +89 -89
  121. package/keywords.txt +48 -48
  122. package/library.json +55 -34
  123. package/library.properties +10 -10
  124. package/package.json +86 -78
  125. package/src/AlteriomPainlessMesh.h +97 -97
  126. package/src/arduino/wifi.hpp +365 -365
  127. package/src/boost/asynctcp.hpp +279 -279
  128. package/src/painlessMesh.h +70 -70
  129. package/src/painlessMeshSTA.cpp +236 -236
  130. package/src/painlessMeshSTA.h +58 -58
  131. package/src/painlessTaskOptions.h +4 -4
  132. package/src/painlessmesh/base64.hpp +111 -111
  133. package/src/painlessmesh/buffer.hpp +229 -229
  134. package/src/painlessmesh/callback.hpp +91 -91
  135. package/src/painlessmesh/configuration.hpp +77 -77
  136. package/src/painlessmesh/connection.hpp +192 -192
  137. package/src/painlessmesh/layout.hpp +188 -188
  138. package/src/painlessmesh/logger.hpp +158 -158
  139. package/src/painlessmesh/memory.hpp +119 -119
  140. package/src/painlessmesh/mesh.hpp +761 -560
  141. package/src/painlessmesh/metrics.hpp +322 -322
  142. package/src/painlessmesh/ntp.hpp +263 -263
  143. package/src/painlessmesh/ota.hpp +582 -553
  144. package/src/painlessmesh/plugin.hpp +188 -188
  145. package/src/painlessmesh/protocol.hpp +813 -813
  146. package/src/painlessmesh/router.hpp +338 -322
  147. package/src/painlessmesh/tcp.hpp +71 -71
  148. package/src/painlessmesh/validation.hpp +238 -238
  149. package/src/plugin/performance.hpp +214 -214
  150. package/src/plugin/remote.hpp +64 -64
  151. package/src/scheduler.cpp +10 -10
  152. package/src/wifi.cpp +2 -2
@@ -1,70 +1,70 @@
1
- #ifndef _EASY_MESH_H_
2
- #define _EASY_MESH_H_
3
-
4
- #include "painlessTaskOptions.h"
5
-
6
- #include <Arduino.h>
7
- #include <functional>
8
- #include <list>
9
- #include <memory>
10
- #include "painlessmesh/configuration.hpp"
11
- #ifdef ESP32
12
- #include <AsyncTCP.h>
13
- #include <WiFi.h>
14
- #if ESP_ARDUINO_VERSION_MAJOR >= 3
15
- #include "esp_mac.h" // required for core 3.x - exposes esp_mac_type_t values
16
- #endif
17
- #elif defined(ESP8266)
18
- #include <ESP8266WiFi.h>
19
- #include <ESPAsyncTCP.h>
20
- #endif // ESP32
21
-
22
- #ifdef PAINLESSMESH_ENABLE_ARDUINO_WIFI
23
- #include "painlessMeshSTA.h"
24
-
25
- #include "arduino/wifi.hpp"
26
- #endif
27
-
28
- #ifdef PAINLESSMESH_ENABLE_OTA
29
- #include "painlessmesh/ota.hpp"
30
- #endif
31
-
32
- // Include improvement modules when enabled
33
- #ifdef PAINLESSMESH_ENABLE_VALIDATION
34
- #include "painlessmesh/validation.hpp"
35
- #endif
36
-
37
- #ifdef PAINLESSMESH_ENABLE_METRICS
38
- #include "painlessmesh/metrics.hpp"
39
- #endif
40
-
41
- #ifdef PAINLESSMESH_ENABLE_MEMORY_OPTIMIZATION
42
- #include "painlessmesh/memory.hpp"
43
- #endif
44
-
45
- #include "painlessmesh/buffer.hpp"
46
- #include "painlessmesh/layout.hpp"
47
- #include "painlessmesh/logger.hpp"
48
- #include "painlessmesh/mesh.hpp"
49
- #include "painlessmesh/ntp.hpp"
50
- #include "painlessmesh/plugin.hpp"
51
- #include "painlessmesh/protocol.hpp"
52
- #include "painlessmesh/router.hpp"
53
- #include "painlessmesh/tcp.hpp"
54
- using namespace painlessmesh::logger;
55
-
56
- /*! \mainpage painlessMesh: A painless way to setup a mesh.
57
- *
58
- * painlessMesh is designed in a modular way, with many parent classes. The best
59
- * place to get started with the documentation is to have a look at
60
- * painlessmesh::wifi::Mesh (the main painlessMesh class is an alias (typedef)
61
- * of the painlessmesh::wifi::Mesh class). Make sure to also explore the public
62
- * member functions inherited from other classes, to get full information on the
63
- * functions available to you.
64
- */
65
-
66
- #ifndef PAINLESSMESH_ENABLE_ARDUINO_WIFI
67
- using painlessMesh = painlessmesh::Mesh<Connection>;
68
- #endif
69
-
70
- #endif // _EASY_MESH_H_
1
+ #ifndef _EASY_MESH_H_
2
+ #define _EASY_MESH_H_
3
+
4
+ #include "painlessTaskOptions.h"
5
+
6
+ #include <Arduino.h>
7
+ #include <functional>
8
+ #include <list>
9
+ #include <memory>
10
+ #include "painlessmesh/configuration.hpp"
11
+ #ifdef ESP32
12
+ #include <AsyncTCP.h>
13
+ #include <WiFi.h>
14
+ #if ESP_ARDUINO_VERSION_MAJOR >= 3
15
+ #include "esp_mac.h" // required for core 3.x - exposes esp_mac_type_t values
16
+ #endif
17
+ #elif defined(ESP8266)
18
+ #include <ESP8266WiFi.h>
19
+ #include <ESPAsyncTCP.h>
20
+ #endif // ESP32
21
+
22
+ #ifdef PAINLESSMESH_ENABLE_ARDUINO_WIFI
23
+ #include "painlessMeshSTA.h"
24
+
25
+ #include "arduino/wifi.hpp"
26
+ #endif
27
+
28
+ #ifdef PAINLESSMESH_ENABLE_OTA
29
+ #include "painlessmesh/ota.hpp"
30
+ #endif
31
+
32
+ // Include improvement modules when enabled
33
+ #ifdef PAINLESSMESH_ENABLE_VALIDATION
34
+ #include "painlessmesh/validation.hpp"
35
+ #endif
36
+
37
+ #ifdef PAINLESSMESH_ENABLE_METRICS
38
+ #include "painlessmesh/metrics.hpp"
39
+ #endif
40
+
41
+ #ifdef PAINLESSMESH_ENABLE_MEMORY_OPTIMIZATION
42
+ #include "painlessmesh/memory.hpp"
43
+ #endif
44
+
45
+ #include "painlessmesh/buffer.hpp"
46
+ #include "painlessmesh/layout.hpp"
47
+ #include "painlessmesh/logger.hpp"
48
+ #include "painlessmesh/mesh.hpp"
49
+ #include "painlessmesh/ntp.hpp"
50
+ #include "painlessmesh/plugin.hpp"
51
+ #include "painlessmesh/protocol.hpp"
52
+ #include "painlessmesh/router.hpp"
53
+ #include "painlessmesh/tcp.hpp"
54
+ using namespace painlessmesh::logger;
55
+
56
+ /*! \mainpage painlessMesh: A painless way to setup a mesh.
57
+ *
58
+ * painlessMesh is designed in a modular way, with many parent classes. The best
59
+ * place to get started with the documentation is to have a look at
60
+ * painlessmesh::wifi::Mesh (the main painlessMesh class is an alias (typedef)
61
+ * of the painlessmesh::wifi::Mesh class). Make sure to also explore the public
62
+ * member functions inherited from other classes, to get full information on the
63
+ * functions available to you.
64
+ */
65
+
66
+ #ifndef PAINLESSMESH_ENABLE_ARDUINO_WIFI
67
+ using painlessMesh = painlessmesh::Mesh<Connection>;
68
+ #endif
69
+
70
+ #endif // _EASY_MESH_H_
@@ -1,236 +1,236 @@
1
- //
2
- // painlessMeshSTA.cpp
3
- //
4
- //
5
- // Created by Bill Gray on 7/26/16.
6
- //
7
- //
8
- #include "painlessmesh/configuration.hpp"
9
-
10
- #ifdef PAINLESSMESH_ENABLE_ARDUINO_WIFI
11
-
12
- #include <Arduino.h>
13
- #include <algorithm>
14
- #include <memory>
15
-
16
- #include "arduino/wifi.hpp"
17
-
18
- #include "painlessmesh/layout.hpp"
19
- #include "painlessmesh/tcp.hpp"
20
-
21
- extern painlessmesh::logger::LogClass Log;
22
-
23
- //***********************************************************************
24
- // Calculate NodeID from a hardware MAC address
25
- void ICACHE_FLASH_ATTR StationScan::init(painlessmesh::wifi::Mesh *pMesh,
26
- TSTRING pssid, TSTRING ppassword,
27
- uint16_t pport, uint8_t pchannel,
28
- bool phidden) {
29
- ssid = pssid;
30
- password = ppassword;
31
- mesh = pMesh;
32
- port = pport;
33
- channel = pchannel;
34
- hidden = phidden;
35
-
36
- task.set(SCAN_INTERVAL, TASK_FOREVER, [this]() { stationScan(); });
37
- }
38
-
39
- // Starts scan for APs whose name is Mesh SSID
40
- void ICACHE_FLASH_ATTR StationScan::stationScan() {
41
- using namespace painlessmesh::logger;
42
- Log(CONNECTION, "stationScan(): %s\n", ssid.c_str());
43
-
44
- #ifdef ESP32
45
- WiFi.scanNetworks(true, hidden, false, 300U, channel);
46
- #elif defined(ESP8266)
47
- // WiFi.scanNetworksAsync([&](int networks) { this->scanComplete(); }, true);
48
- // Try 600 times (60 seconds). If not completed after that, give up
49
- asyncTask.set(100 * TASK_MILLISECOND, 600, [this]() {
50
- auto num = WiFi.scanComplete();
51
- if (num == WIFI_SCAN_FAILED || num > 0) {
52
- this->asyncTask.disable();
53
- this->scanComplete();
54
- }
55
- });
56
- mesh->mScheduler->addTask(asyncTask);
57
- asyncTask.enableDelayed();
58
- WiFi.scanNetworks(true, hidden, channel);
59
- #endif
60
-
61
- task.delay(10 * SCAN_INTERVAL); // Scan should be completed by then and next
62
- // step called. If not then we restart here.
63
- return;
64
- }
65
-
66
- void ICACHE_FLASH_ATTR StationScan::scanComplete() {
67
- using namespace painlessmesh::logger;
68
- Log(CONNECTION, "scanComplete(): Scan finished\n");
69
-
70
- aps.clear();
71
- Log(CONNECTION, "scanComplete():-- > Cleared old APs.\n");
72
-
73
- auto num = WiFi.scanComplete();
74
- if (num == WIFI_SCAN_FAILED) {
75
- Log(ERROR, "wifi scan failed. Retrying....\n");
76
- task.forceNextIteration();
77
- return;
78
- } else if (num == WIFI_SCAN_RUNNING) {
79
- Log(ERROR,
80
- "scanComplete should never be called when scan is still running.\n");
81
- return;
82
- }
83
-
84
- Log(CONNECTION, "scanComplete(): num = %d\n", num);
85
-
86
- for (auto i = 0; i < num; ++i) {
87
- WiFi_AP_Record_t record;
88
- record.ssid = WiFi.SSID(i);
89
-
90
- if (WiFi.channel(i) != mesh->_meshChannel) {
91
- continue;
92
- }
93
-
94
- if (record.ssid != ssid) {
95
- if (record.ssid.equals("") && mesh->_meshHidden) {
96
- // Hidden mesh
97
- record.ssid = ssid;
98
- } else {
99
- continue;
100
- }
101
- }
102
-
103
- record.rssi = WiFi.RSSI(i);
104
- if (record.rssi == 0) continue;
105
-
106
- memcpy((void *)&record.bssid, (void *)WiFi.BSSID(i), sizeof(record.bssid));
107
- aps.push_back(record);
108
- Log(CONNECTION, "\tfound : %s, %ddBm\n", record.ssid.c_str(),
109
- (int16_t)record.rssi);
110
- }
111
-
112
- Log(CONNECTION, "\tFound %d nodes\n", aps.size());
113
-
114
- task.yield([this]() {
115
- // Task filter all unknown
116
- filterAPs();
117
-
118
- lastAPs = aps;
119
-
120
- // Next task is to sort by strength
121
- task.yield([this] {
122
- aps.sort([](WiFi_AP_Record_t a, WiFi_AP_Record_t b) {
123
- return a.rssi > b.rssi;
124
- });
125
- // Next task is to connect to the top ap
126
- task.yield([this]() { connectToAP(); });
127
- });
128
- });
129
- }
130
-
131
- void ICACHE_FLASH_ATTR StationScan::filterAPs() {
132
- auto ap = aps.begin();
133
- while (ap != aps.end()) {
134
- auto apNodeId = painlessmesh::tcp::encodeNodeId(ap->bssid);
135
- if (painlessmesh::router::findRoute<painlessmesh::Connection>(
136
- (*mesh), apNodeId) != NULL) {
137
- ap = aps.erase(ap);
138
- } else {
139
- ap++;
140
- }
141
- }
142
- }
143
-
144
- void ICACHE_FLASH_ATTR StationScan::requestIP(WiFi_AP_Record_t &ap) {
145
- using namespace painlessmesh::logger;
146
- Log(CONNECTION, "connectToAP(): Best AP is %u<---\n",
147
- painlessmesh::tcp::encodeNodeId(ap.bssid));
148
- WiFi.begin(ap.ssid.c_str(), password.c_str(), mesh->_meshChannel, ap.bssid);
149
- return;
150
- }
151
-
152
- void ICACHE_FLASH_ATTR StationScan::connectToAP() {
153
- using namespace painlessmesh;
154
- using namespace painlessmesh::logger;
155
- // Next task will be to rescan
156
- task.setCallback([this]() { stationScan(); });
157
-
158
- if (manual) {
159
- if ((WiFi.SSID() == ssid) && WiFi.status() == WL_CONNECTED) {
160
- Log(CONNECTION,
161
- "connectToAP(): Already connected using manual connection. "
162
- "Disabling scanning.\n");
163
- task.disable();
164
- return;
165
- } else {
166
- if (WiFi.status() == WL_CONNECTED) {
167
- Log.remote("Close Sta because trying to connect manually\n");
168
- mesh->closeConnectionSTA();
169
- task.enableDelayed(10 * SCAN_INTERVAL);
170
- return;
171
- } else if (aps.empty() || !ssid.equals(aps.begin()->ssid)) {
172
- task.enableDelayed(SCAN_INTERVAL);
173
- return;
174
- }
175
- }
176
- }
177
- bool isRooted = layout::isRooted(mesh->asNodeTree());
178
- if (aps.empty()) {
179
- // No unknown nodes found
180
- if (WiFi.status() == WL_CONNECTED &&
181
- !(mesh->shouldContainRoot && !isRooted)) {
182
- // if already connected -> scan slow
183
- Log(CONNECTION,
184
- "connectToAP(): Already connected, and no unknown nodes found: "
185
- "scan rate set to slow\n");
186
- task.delay(4 * SCAN_INTERVAL);
187
- } else {
188
- // else scan fast (SCAN_INTERVAL)
189
- Log(CONNECTION,
190
- "connectToAP(): No unknown nodes found scan rate set to "
191
- "fast\n");
192
- task.setInterval(0.5 * SCAN_INTERVAL);
193
- }
194
- mesh->stability += min(1000 - mesh->stability, (size_t)25);
195
- } else {
196
- if (WiFi.status() == WL_CONNECTED) {
197
- // TODO: Use %u instead of String() here and below
198
- // Also prob is always equal to stability, so we should use that directly
199
- Log(CONNECTION,
200
- "connectToAP(): Unknown nodes found. Current stability: %s\n",
201
- String(mesh->stability).c_str());
202
-
203
- int prob = mesh->stability;
204
- if (!isRooted && random(0, 1000) < prob) {
205
- Log(CONNECTION, "connectToAP(): Reconfigure network: %s\n",
206
- String(prob).c_str());
207
- // close STA connection, this will trigger station disconnect which
208
- // will trigger connectToAP()
209
- mesh->closeConnectionSTA();
210
- mesh->stability = 0; // Discourage switching again
211
- Log.remote("Close Sta to reconfigure network\n");
212
- // wifiEventCB should be triggered before this delay runs out
213
- // and reset the connecting
214
- task.delay(4 * SCAN_INTERVAL);
215
- } else {
216
- if (!isRooted && mesh->shouldContainRoot)
217
- // Increase scanning rate, because we want to find root
218
- task.delay(0.5 * SCAN_INTERVAL);
219
- else
220
- task.delay(4 * SCAN_INTERVAL);
221
- }
222
- } else {
223
- // Else try to connect to first
224
- auto ap = aps.front();
225
- aps.pop_front(); // drop bestAP from mesh list, so if doesn't work out,
226
- // we can try the next one
227
- requestIP(ap);
228
- // Trying to connect, if that fails we will reconnect later
229
- Log(CONNECTION,
230
- "connectToAP(): Trying to connect, scan rate set to "
231
- "4*normal\n");
232
- task.delay(4 * SCAN_INTERVAL);
233
- }
234
- }
235
- }
236
- #endif
1
+ //
2
+ // painlessMeshSTA.cpp
3
+ //
4
+ //
5
+ // Created by Bill Gray on 7/26/16.
6
+ //
7
+ //
8
+ #include "painlessmesh/configuration.hpp"
9
+
10
+ #ifdef PAINLESSMESH_ENABLE_ARDUINO_WIFI
11
+
12
+ #include <Arduino.h>
13
+ #include <algorithm>
14
+ #include <memory>
15
+
16
+ #include "arduino/wifi.hpp"
17
+
18
+ #include "painlessmesh/layout.hpp"
19
+ #include "painlessmesh/tcp.hpp"
20
+
21
+ extern painlessmesh::logger::LogClass Log;
22
+
23
+ //***********************************************************************
24
+ // Calculate NodeID from a hardware MAC address
25
+ void ICACHE_FLASH_ATTR StationScan::init(painlessmesh::wifi::Mesh *pMesh,
26
+ TSTRING pssid, TSTRING ppassword,
27
+ uint16_t pport, uint8_t pchannel,
28
+ bool phidden) {
29
+ ssid = pssid;
30
+ password = ppassword;
31
+ mesh = pMesh;
32
+ port = pport;
33
+ channel = pchannel;
34
+ hidden = phidden;
35
+
36
+ task.set(SCAN_INTERVAL, TASK_FOREVER, [this]() { stationScan(); });
37
+ }
38
+
39
+ // Starts scan for APs whose name is Mesh SSID
40
+ void ICACHE_FLASH_ATTR StationScan::stationScan() {
41
+ using namespace painlessmesh::logger;
42
+ Log(CONNECTION, "stationScan(): %s\n", ssid.c_str());
43
+
44
+ #ifdef ESP32
45
+ WiFi.scanNetworks(true, hidden, false, 300U, channel);
46
+ #elif defined(ESP8266)
47
+ // WiFi.scanNetworksAsync([&](int networks) { this->scanComplete(); }, true);
48
+ // Try 600 times (60 seconds). If not completed after that, give up
49
+ asyncTask.set(100 * TASK_MILLISECOND, 600, [this]() {
50
+ auto num = WiFi.scanComplete();
51
+ if (num == WIFI_SCAN_FAILED || num > 0) {
52
+ this->asyncTask.disable();
53
+ this->scanComplete();
54
+ }
55
+ });
56
+ mesh->mScheduler->addTask(asyncTask);
57
+ asyncTask.enableDelayed();
58
+ WiFi.scanNetworks(true, hidden, channel);
59
+ #endif
60
+
61
+ task.delay(10 * SCAN_INTERVAL); // Scan should be completed by then and next
62
+ // step called. If not then we restart here.
63
+ return;
64
+ }
65
+
66
+ void ICACHE_FLASH_ATTR StationScan::scanComplete() {
67
+ using namespace painlessmesh::logger;
68
+ Log(CONNECTION, "scanComplete(): Scan finished\n");
69
+
70
+ aps.clear();
71
+ Log(CONNECTION, "scanComplete():-- > Cleared old APs.\n");
72
+
73
+ auto num = WiFi.scanComplete();
74
+ if (num == WIFI_SCAN_FAILED) {
75
+ Log(ERROR, "wifi scan failed. Retrying....\n");
76
+ task.forceNextIteration();
77
+ return;
78
+ } else if (num == WIFI_SCAN_RUNNING) {
79
+ Log(ERROR,
80
+ "scanComplete should never be called when scan is still running.\n");
81
+ return;
82
+ }
83
+
84
+ Log(CONNECTION, "scanComplete(): num = %d\n", num);
85
+
86
+ for (auto i = 0; i < num; ++i) {
87
+ WiFi_AP_Record_t record;
88
+ record.ssid = WiFi.SSID(i);
89
+
90
+ if (WiFi.channel(i) != mesh->_meshChannel) {
91
+ continue;
92
+ }
93
+
94
+ if (record.ssid != ssid) {
95
+ if (record.ssid.equals("") && mesh->_meshHidden) {
96
+ // Hidden mesh
97
+ record.ssid = ssid;
98
+ } else {
99
+ continue;
100
+ }
101
+ }
102
+
103
+ record.rssi = WiFi.RSSI(i);
104
+ if (record.rssi == 0) continue;
105
+
106
+ memcpy((void *)&record.bssid, (void *)WiFi.BSSID(i), sizeof(record.bssid));
107
+ aps.push_back(record);
108
+ Log(CONNECTION, "\tfound : %s, %ddBm\n", record.ssid.c_str(),
109
+ (int16_t)record.rssi);
110
+ }
111
+
112
+ Log(CONNECTION, "\tFound %d nodes\n", aps.size());
113
+
114
+ task.yield([this]() {
115
+ // Task filter all unknown
116
+ filterAPs();
117
+
118
+ lastAPs = aps;
119
+
120
+ // Next task is to sort by strength
121
+ task.yield([this] {
122
+ aps.sort([](WiFi_AP_Record_t a, WiFi_AP_Record_t b) {
123
+ return a.rssi > b.rssi;
124
+ });
125
+ // Next task is to connect to the top ap
126
+ task.yield([this]() { connectToAP(); });
127
+ });
128
+ });
129
+ }
130
+
131
+ void ICACHE_FLASH_ATTR StationScan::filterAPs() {
132
+ auto ap = aps.begin();
133
+ while (ap != aps.end()) {
134
+ auto apNodeId = painlessmesh::tcp::encodeNodeId(ap->bssid);
135
+ if (painlessmesh::router::findRoute<painlessmesh::Connection>(
136
+ (*mesh), apNodeId) != NULL) {
137
+ ap = aps.erase(ap);
138
+ } else {
139
+ ap++;
140
+ }
141
+ }
142
+ }
143
+
144
+ void ICACHE_FLASH_ATTR StationScan::requestIP(WiFi_AP_Record_t &ap) {
145
+ using namespace painlessmesh::logger;
146
+ Log(CONNECTION, "connectToAP(): Best AP is %u<---\n",
147
+ painlessmesh::tcp::encodeNodeId(ap.bssid));
148
+ WiFi.begin(ap.ssid.c_str(), password.c_str(), mesh->_meshChannel, ap.bssid);
149
+ return;
150
+ }
151
+
152
+ void ICACHE_FLASH_ATTR StationScan::connectToAP() {
153
+ using namespace painlessmesh;
154
+ using namespace painlessmesh::logger;
155
+ // Next task will be to rescan
156
+ task.setCallback([this]() { stationScan(); });
157
+
158
+ if (manual) {
159
+ if ((WiFi.SSID() == ssid) && WiFi.status() == WL_CONNECTED) {
160
+ Log(CONNECTION,
161
+ "connectToAP(): Already connected using manual connection. "
162
+ "Disabling scanning.\n");
163
+ task.disable();
164
+ return;
165
+ } else {
166
+ if (WiFi.status() == WL_CONNECTED) {
167
+ Log.remote("Close Sta because trying to connect manually\n");
168
+ mesh->closeConnectionSTA();
169
+ task.enableDelayed(10 * SCAN_INTERVAL);
170
+ return;
171
+ } else if (aps.empty() || !ssid.equals(aps.begin()->ssid)) {
172
+ task.enableDelayed(SCAN_INTERVAL);
173
+ return;
174
+ }
175
+ }
176
+ }
177
+ bool isRooted = layout::isRooted(mesh->asNodeTree());
178
+ if (aps.empty()) {
179
+ // No unknown nodes found
180
+ if (WiFi.status() == WL_CONNECTED &&
181
+ !(mesh->shouldContainRoot && !isRooted)) {
182
+ // if already connected -> scan slow
183
+ Log(CONNECTION,
184
+ "connectToAP(): Already connected, and no unknown nodes found: "
185
+ "scan rate set to slow\n");
186
+ task.delay(4 * SCAN_INTERVAL);
187
+ } else {
188
+ // else scan fast (SCAN_INTERVAL)
189
+ Log(CONNECTION,
190
+ "connectToAP(): No unknown nodes found scan rate set to "
191
+ "fast\n");
192
+ task.setInterval(0.5 * SCAN_INTERVAL);
193
+ }
194
+ mesh->stability += min(1000 - mesh->stability, (size_t)25);
195
+ } else {
196
+ if (WiFi.status() == WL_CONNECTED) {
197
+ // TODO: Use %u instead of String() here and below
198
+ // Also prob is always equal to stability, so we should use that directly
199
+ Log(CONNECTION,
200
+ "connectToAP(): Unknown nodes found. Current stability: %s\n",
201
+ String(mesh->stability).c_str());
202
+
203
+ int prob = mesh->stability;
204
+ if (!isRooted && random(0, 1000) < prob) {
205
+ Log(CONNECTION, "connectToAP(): Reconfigure network: %s\n",
206
+ String(prob).c_str());
207
+ // close STA connection, this will trigger station disconnect which
208
+ // will trigger connectToAP()
209
+ mesh->closeConnectionSTA();
210
+ mesh->stability = 0; // Discourage switching again
211
+ Log.remote("Close Sta to reconfigure network\n");
212
+ // wifiEventCB should be triggered before this delay runs out
213
+ // and reset the connecting
214
+ task.delay(4 * SCAN_INTERVAL);
215
+ } else {
216
+ if (!isRooted && mesh->shouldContainRoot)
217
+ // Increase scanning rate, because we want to find root
218
+ task.delay(0.5 * SCAN_INTERVAL);
219
+ else
220
+ task.delay(4 * SCAN_INTERVAL);
221
+ }
222
+ } else {
223
+ // Else try to connect to first
224
+ auto ap = aps.front();
225
+ aps.pop_front(); // drop bestAP from mesh list, so if doesn't work out,
226
+ // we can try the next one
227
+ requestIP(ap);
228
+ // Trying to connect, if that fails we will reconnect later
229
+ Log(CONNECTION,
230
+ "connectToAP(): Trying to connect, scan rate set to "
231
+ "4*normal\n");
232
+ task.delay(4 * SCAN_INTERVAL);
233
+ }
234
+ }
235
+ }
236
+ #endif