@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.
- package/CHANGELOG.md +380 -143
- package/LICENSE +674 -674
- package/README.md +477 -434
- package/RELEASE_GUIDE.md +504 -418
- package/docs/DOCUMENTATION_MIGRATION_PLAN.md +175 -175
- package/docs/IMPLEMENTATION_PLAN_MESH_TOPOLOGY.md +1062 -0
- package/docs/MESH_TOPOLOGY_GUIDE.md +992 -0
- package/docs/MESH_TOPOLOGY_PROGRESS.md +422 -0
- package/docs/MQTT_BRIDGE_COMMANDS.md +894 -0
- package/docs/MQTT_BRIDGE_IMPLEMENTATION_SUMMARY.md +324 -0
- package/docs/MQTT_COMMAND_SCHEMA_PROPOSAL.md +576 -0
- package/docs/MQTT_SCHEMA_COMPLIANCE.md +285 -0
- package/docs/MQTT_SCHEMA_PROPOSALS.md +446 -0
- package/docs/MQTT_SCHEMA_REVIEW.md +690 -0
- package/docs/OTA_COMMANDS_REFERENCE.md +554 -0
- package/docs/PHASE1_GUIDE.md +349 -0
- package/docs/PHASE2_GUIDE.md +543 -0
- package/docs/README.md +77 -70
- package/docs/SCHEMA_VALIDATION_CHECKLIST.md +222 -0
- package/docs/alteriom/overview.md +507 -507
- package/docs/api/core-api.md +606 -606
- package/docs/architecture/mesh-architecture.md +378 -378
- package/docs/architecture/plugin-system.md +516 -516
- package/docs/getting-started/first-mesh.md +409 -409
- package/docs/getting-started/installation.md +274 -274
- package/docs/getting-started/quickstart.md +157 -157
- package/docs/improvements/FEATURE_PROPOSALS.md +337 -0
- package/docs/improvements/PHASE1_IMPLEMENTATION.md +325 -0
- package/docs/improvements/PHASE2_IMPLEMENTATION.md +567 -0
- package/docs/improvements/README.md +86 -68
- package/docs/improvements/ota-and-status-enhancements.md +911 -0
- package/docs/improvements/ota-status-architecture-diagrams.md +658 -0
- package/docs/improvements/ota-status-quick-reference.md +284 -0
- package/docs/platformio-publishing.md +255 -0
- package/docs/platformio-setup-summary.md +121 -0
- package/docs/troubleshooting/common-issues.md +520 -520
- package/docs/troubleshooting/faq.md +472 -472
- package/docs/tutorials/basic-examples.md +717 -717
- package/docs/wiki/API-Reference.md +245 -245
- package/docs/wiki/Complete-Documentation.md +122 -122
- package/examples/alteriom/README.md +139 -81
- package/examples/alteriom/alteriom.ino +186 -185
- package/examples/alteriom/alteriom_sensor_package.hpp +240 -127
- package/examples/alteriom/platformio.ini +24 -24
- package/examples/alteriomImproved/alteriom_sensor_package.hpp +224 -0
- package/examples/{alteriom → alteriomImproved}/improved_sensor_node.ino +245 -245
- package/examples/alteriomImproved/platformio.ini +25 -0
- package/examples/alteriomPhase1/alteriom_sensor_package.hpp +224 -0
- package/examples/alteriomPhase1/phase1_features.ino +242 -0
- package/examples/alteriomPhase1/platformio.ini +25 -0
- package/examples/alteriomPhase2/alteriom_sensor_package.hpp +224 -0
- package/examples/alteriomPhase2/phase2_features.ino +186 -0
- package/examples/alteriomPhase2/platformio.ini +25 -0
- package/examples/{alteriom → alteriomSensorNode}/alteriom_sensor_node.ino +183 -183
- package/examples/alteriomSensorNode/alteriom_sensor_package.hpp +224 -0
- package/examples/alteriomSensorNode/platformio.ini +25 -0
- package/examples/basic/basic.ino +66 -66
- package/examples/basic/platformio.ini +25 -25
- package/examples/bridge/bridge.ino +51 -51
- package/examples/bridge/mesh_event_publisher.hpp +253 -0
- package/examples/bridge/mesh_topology_reporter.hpp +303 -0
- package/examples/bridge/mqtt_command_bridge.hpp +459 -0
- package/examples/bridge/mqtt_status_bridge.hpp +519 -0
- package/examples/bridge/platformio.ini +25 -25
- package/examples/echoNode/echoNode.ino +33 -33
- package/examples/echoNode/platformio.ini +25 -25
- package/examples/logClient/logClient.ino +109 -109
- package/examples/logClient/platformio.ini +25 -25
- package/examples/logServer/logServer.ino +81 -81
- package/examples/logServer/platformio.ini +25 -25
- package/examples/meshCommandNode/alteriom_sensor_package.hpp +235 -0
- package/examples/meshCommandNode/meshCommandNode.ino +263 -0
- package/examples/meshCommandNode/platformio.ini +25 -0
- package/examples/mqttBridge/mqttBridge.ino +118 -118
- package/examples/mqttBridge/platformio.ini +26 -26
- package/examples/mqttCommandBridge/alteriom_sensor_package.hpp +235 -0
- package/examples/mqttCommandBridge/mesh_event_publisher.hpp +253 -0
- package/examples/mqttCommandBridge/mesh_topology_reporter.hpp +303 -0
- package/examples/mqttCommandBridge/mqttCommandBridge.ino +252 -0
- package/examples/mqttCommandBridge/mqtt_command_bridge.hpp +459 -0
- package/examples/mqttCommandBridge/platformio.ini +26 -0
- package/examples/mqttStatusBridge/mqttStatusBridge.ino +216 -0
- package/examples/mqttStatusBridge/mqtt_status_bridge.hpp +522 -0
- package/examples/mqttStatusBridge/platformio.ini +26 -0
- package/examples/mqttTopologyTest/README.md +467 -0
- package/examples/mqttTopologyTest/mqttTopologyTest.ino +748 -0
- package/examples/mqttTopologyTest/platformio.ini +26 -0
- package/examples/namedMesh/namedMesh.ino +97 -97
- package/examples/namedMesh/platformio.ini +25 -25
- package/examples/otaReceiver/otaReceiver.ino +79 -79
- package/examples/otaReceiver/platformio.ini +25 -25
- package/examples/otaSender/otaSender.ino +160 -151
- package/examples/otaSender/platformio.ini +25 -25
- package/examples/startHere/platformio.ini +25 -25
- package/examples/startHere/startHere.ino +159 -159
- package/examples/webServer/platformio.ini +27 -27
- package/examples/webServer/webServer.ino +89 -89
- package/keywords.txt +48 -48
- package/library.json +55 -34
- package/library.properties +10 -10
- package/package.json +86 -78
- package/src/AlteriomPainlessMesh.h +97 -97
- package/src/arduino/wifi.hpp +365 -365
- package/src/boost/asynctcp.hpp +279 -279
- package/src/painlessMesh.h +70 -70
- package/src/painlessMeshSTA.cpp +236 -236
- package/src/painlessMeshSTA.h +58 -58
- package/src/painlessTaskOptions.h +4 -4
- package/src/painlessmesh/base64.hpp +111 -111
- package/src/painlessmesh/buffer.hpp +229 -229
- package/src/painlessmesh/callback.hpp +91 -91
- package/src/painlessmesh/configuration.hpp +77 -77
- package/src/painlessmesh/connection.hpp +192 -192
- package/src/painlessmesh/layout.hpp +188 -188
- package/src/painlessmesh/logger.hpp +158 -158
- package/src/painlessmesh/memory.hpp +119 -119
- package/src/painlessmesh/mesh.hpp +761 -560
- package/src/painlessmesh/metrics.hpp +322 -322
- package/src/painlessmesh/ntp.hpp +263 -263
- package/src/painlessmesh/ota.hpp +582 -553
- package/src/painlessmesh/plugin.hpp +188 -188
- package/src/painlessmesh/protocol.hpp +813 -813
- package/src/painlessmesh/router.hpp +322 -322
- package/src/painlessmesh/tcp.hpp +71 -71
- package/src/painlessmesh/validation.hpp +238 -238
- package/src/plugin/performance.hpp +214 -214
- package/src/plugin/remote.hpp +64 -64
- package/src/scheduler.cpp +10 -10
- package/src/wifi.cpp +2 -2
package/src/painlessMesh.h
CHANGED
|
@@ -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_
|
package/src/painlessMeshSTA.cpp
CHANGED
|
@@ -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
|