Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit cceebb5

Browse filesBrowse files
authored
Improves WiFiMulti (espressif#9139)
* feat(wifi): Improves WiFiMulti * fix(wifi): Fixes Initialization of Security Mode * feat(wifi): simplifies the example by using HTTPClient * fix(WiFi): fixes a type in the commentaries
1 parent 39043b8 commit cceebb5
Copy full SHA for cceebb5

File tree

4 files changed

+211
-28
lines changed
Filter options

4 files changed

+211
-28
lines changed

‎libraries/WiFi/examples/WiFiMultiAdvanced/.skip.esp32h2

Copy file name to clipboardExpand all lines: libraries/WiFi/examples/WiFiMultiAdvanced/.skip.esp32h2
Whitespace-only changes.
+64Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* This sketch tries to connect to the best AP available
3+
* and tests for captive portals on open networks
4+
*
5+
*/
6+
7+
#include <WiFi.h>
8+
#include <WiFiMulti.h>
9+
#include <HTTPClient.h>
10+
11+
WiFiMulti wifiMulti;
12+
13+
// callback used to check Internet connectivity
14+
bool testConnection(){
15+
HTTPClient http;
16+
http.begin("http://www.espressif.com");
17+
int httpCode = http.GET();
18+
// we expect to get a 301 because it will ask to use HTTPS instead of HTTP
19+
if (httpCode == HTTP_CODE_MOVED_PERMANENTLY) return true;
20+
return false;
21+
}
22+
23+
void setup()
24+
{
25+
Serial.begin(115200);
26+
delay(10);
27+
28+
wifiMulti.addAP("ssid_from_AP_1", "your_password_for_AP_1");
29+
wifiMulti.addAP("ssid_from_AP_2", "your_password_for_AP_2");
30+
wifiMulti.addAP("ssid_from_AP_3", "your_password_for_AP_3");
31+
32+
// These options can help when you need ANY kind of wifi connection to get a config file, report errors, etc.
33+
wifiMulti.setStrictMode(false); // Default is true. Library will disconnect and forget currently connected AP if it's not in the AP list.
34+
wifiMulti.setAllowOpenAP(true); // Default is false. True adds open APs to the AP list.
35+
wifiMulti.setConnectionTestCallbackFunc(testConnection); // Attempts to connect to a remote webserver in case of captive portals.
36+
37+
Serial.println("Connecting Wifi...");
38+
if(wifiMulti.run() == WL_CONNECTED) {
39+
Serial.println("");
40+
Serial.println("WiFi connected");
41+
Serial.println("IP address: ");
42+
Serial.println(WiFi.localIP());
43+
}
44+
}
45+
46+
void loop()
47+
{
48+
static bool isConnected = false;
49+
uint8_t WiFiStatus = wifiMulti.run();
50+
51+
if (WiFiStatus == WL_CONNECTED) {
52+
if (!isConnected) {
53+
Serial.println("");
54+
Serial.println("WiFi connected");
55+
Serial.println("IP address: ");
56+
Serial.println(WiFi.localIP());
57+
}
58+
isConnected = true;
59+
} else {
60+
Serial.println("WiFi not connected!");
61+
isConnected = false;
62+
delay(5000);
63+
}
64+
}

‎libraries/WiFi/src/WiFiMulti.cpp

Copy file name to clipboardExpand all lines: libraries/WiFi/src/WiFiMulti.cpp
+119-26Lines changed: 119 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,9 @@ WiFiMulti::WiFiMulti()
3333
ipv6_support = false;
3434
}
3535

36-
WiFiMulti::~WiFiMulti()
36+
void WiFiMulti::APlistClean(void)
3737
{
38-
for(uint32_t i = 0; i < APlist.size(); i++) {
39-
WifiAPlist_t entry = APlist[i];
38+
for(auto entry : APlist) {
4039
if(entry.ssid) {
4140
free(entry.ssid);
4241
}
@@ -47,17 +46,22 @@ WiFiMulti::~WiFiMulti()
4746
APlist.clear();
4847
}
4948

49+
WiFiMulti::~WiFiMulti()
50+
{
51+
APlistClean();
52+
}
53+
5054
bool WiFiMulti::addAP(const char* ssid, const char *passphrase)
5155
{
5256
WifiAPlist_t newAP;
5357

54-
if(!ssid || *ssid == 0x00 || strlen(ssid) > 31) {
58+
if(!ssid || *ssid == '\0' || strlen(ssid) > 31) {
5559
// fail SSID too long or missing!
5660
log_e("[WIFI][APlistAdd] no ssid or ssid too long");
5761
return false;
5862
}
5963

60-
if(passphrase && strlen(passphrase) > 64) {
64+
if(passphrase && strlen(passphrase) > 63) {
6165
// fail passphrase too long!
6266
log_e("[WIFI][APlistAdd] passphrase too long");
6367
return false;
@@ -70,7 +74,7 @@ bool WiFiMulti::addAP(const char* ssid, const char *passphrase)
7074
return false;
7175
}
7276

73-
if(passphrase && *passphrase != 0x00) {
77+
if(passphrase && *passphrase != '\0') {
7478
newAP.passphrase = strdup(passphrase);
7579
if(!newAP.passphrase) {
7680
log_e("[WIFI][APlistAdd] fail newAP.passphrase == 0");
@@ -80,7 +84,7 @@ bool WiFiMulti::addAP(const char* ssid, const char *passphrase)
8084
} else {
8185
newAP.passphrase = NULL;
8286
}
83-
87+
newAP.hasFailed = false;
8488
APlist.push_back(newAP);
8589
log_i("[WIFI][APlistAdd] add SSID: %s", newAP.ssid);
8690
return true;
@@ -91,9 +95,20 @@ uint8_t WiFiMulti::run(uint32_t connectTimeout)
9195
int8_t scanResult;
9296
uint8_t status = WiFi.status();
9397
if(status == WL_CONNECTED) {
94-
for(uint32_t x = 0; x < APlist.size(); x++) {
95-
if(WiFi.SSID()==APlist[x].ssid) {
98+
if (!_bWFMInit && _connectionTestCBFunc != NULL){
99+
if (_connectionTestCBFunc() == true) {
100+
_bWFMInit = true;
101+
return status;
102+
}
103+
} else {
104+
if (!_bStrict) {
96105
return status;
106+
} else {
107+
for(auto ap : APlist) {
108+
if(WiFi.SSID() == ap.ssid) {
109+
return status;
110+
}
111+
}
97112
}
98113
}
99114
WiFi.disconnect(false,false);
@@ -102,22 +117,27 @@ uint8_t WiFiMulti::run(uint32_t connectTimeout)
102117
}
103118

104119
scanResult = WiFi.scanNetworks();
105-
if(scanResult == WIFI_SCAN_RUNNING) {
120+
if (scanResult == WIFI_SCAN_RUNNING) {
106121
// scan is running
107122
return WL_NO_SSID_AVAIL;
108-
} else if(scanResult >= 0) {
123+
} else if (scanResult >= 0) {
109124
// scan done analyze
110-
WifiAPlist_t bestNetwork { NULL, NULL };
125+
int32_t bestIndex = 0;
126+
WifiAPlist_t bestNetwork { NULL, NULL, false };
111127
int bestNetworkDb = INT_MIN;
128+
int bestNetworkSec = WIFI_AUTH_MAX;
112129
uint8_t bestBSSID[6];
113130
int32_t bestChannel = 0;
114131

115132
log_i("[WIFI] scan done");
116133

117-
if(scanResult == 0) {
134+
if (scanResult == 0) {
118135
log_e("[WIFI] no networks found");
119136
} else {
120137
log_i("[WIFI] %d networks found", scanResult);
138+
139+
int8_t failCount = 0;
140+
int8_t foundCount = 0;
121141
for(int8_t i = 0; i < scanResult; ++i) {
122142

123143
String ssid_scan;
@@ -127,22 +147,47 @@ uint8_t WiFiMulti::run(uint32_t connectTimeout)
127147
int32_t chan_scan;
128148

129149
WiFi.getNetworkInfo(i, ssid_scan, sec_scan, rssi_scan, BSSID_scan, chan_scan);
150+
// add any Open WiFi AP to the list, if allowed with setAllowOpenAP(true)
151+
if (_bAllowOpenAP && sec_scan == WIFI_AUTH_OPEN){
152+
bool found = false;
153+
for(auto check : APlist) {
154+
if (ssid_scan == check.ssid){
155+
found = true;
156+
break;
157+
}
158+
}
159+
// If we didn't find it, add this Open WiFi AP to the list
160+
if (!found){
161+
log_i("[WIFI][APlistAdd] adding Open WiFi SSID: %s", ssid_scan.c_str());
162+
addAP(ssid_scan.c_str());
163+
}
164+
}
130165

131166
bool known = false;
132-
for(uint32_t x = APlist.size() ; x > 0; x--) {
133-
WifiAPlist_t entry = APlist[x-1];
167+
for(uint32_t x = 0; x < APlist.size(); x++) {
168+
WifiAPlist_t entry = APlist[x];
134169

135170
if(ssid_scan == entry.ssid) { // SSID match
136-
known = true;
137-
if(rssi_scan > bestNetworkDb) { // best network
138-
if(sec_scan == WIFI_AUTH_OPEN || entry.passphrase) { // check for passphrase if not open wlan
139-
bestNetworkDb = rssi_scan;
140-
bestChannel = chan_scan;
141-
memcpy((void*) &bestNetwork, (void*) &entry, sizeof(bestNetwork));
142-
memcpy((void*) &bestBSSID, (void*) BSSID_scan, sizeof(bestBSSID));
171+
log_v("known ssid: %s, has failed: %s", entry.ssid, entry.hasFailed ? "yes" : "no");
172+
foundCount++;
173+
if (!entry.hasFailed){
174+
known = true;
175+
log_v("rssi_scan: %d, bestNetworkDb: %d", rssi_scan, bestNetworkDb);
176+
if(rssi_scan > bestNetworkDb) { // best network
177+
if(_bAllowOpenAP || (sec_scan == WIFI_AUTH_OPEN || entry.passphrase)) { // check for passphrase if not open wlan
178+
log_v("best network is now: %s", ssid_scan);
179+
bestIndex = x;
180+
bestNetworkSec = sec_scan;
181+
bestNetworkDb = rssi_scan;
182+
bestChannel = chan_scan;
183+
memcpy((void*) &bestNetwork, (void*) &entry, sizeof(bestNetwork));
184+
memcpy((void*) &bestBSSID, (void*) BSSID_scan, sizeof(bestBSSID));
185+
}
143186
}
187+
break;
188+
} else {
189+
failCount++;
144190
}
145-
break;
146191
}
147192
}
148193

@@ -152,8 +197,12 @@ uint8_t WiFiMulti::run(uint32_t connectTimeout)
152197
log_d(" %d: [%d][%02X:%02X:%02X:%02X:%02X:%02X] %s (%d) %c", i, chan_scan, BSSID_scan[0], BSSID_scan[1], BSSID_scan[2], BSSID_scan[3], BSSID_scan[4], BSSID_scan[5], ssid_scan.c_str(), rssi_scan, (sec_scan == WIFI_AUTH_OPEN) ? ' ' : '*');
153198
}
154199
}
200+
log_v("foundCount = %d, failCount = %d", foundCount, failCount);
201+
// if all the APs in the list have failed, reset the failure flags
202+
if (foundCount == failCount) {
203+
resetFails(); // keeps trying the APs in the list
204+
}
155205
}
156-
157206
// clean up ram
158207
WiFi.scanDelete();
159208

@@ -163,12 +212,15 @@ uint8_t WiFiMulti::run(uint32_t connectTimeout)
163212
if (ipv6_support == true) {
164213
WiFi.enableIPv6();
165214
}
166-
WiFi.begin(bestNetwork.ssid, bestNetwork.passphrase, bestChannel, bestBSSID);
215+
WiFi.disconnect();
216+
delay(10);
217+
WiFi.begin(bestNetwork.ssid, (_bAllowOpenAP && bestNetworkSec == WIFI_AUTH_OPEN) ? NULL : bestNetwork.passphrase, bestChannel, bestBSSID);
167218
status = WiFi.status();
219+
_bWFMInit = true;
168220

169221
auto startTime = millis();
170222
// wait for connection, fail, or timeout
171-
while(status != WL_CONNECTED && status != WL_NO_SSID_AVAIL && status != WL_CONNECT_FAILED && (millis() - startTime) <= connectTimeout) {
223+
while(status != WL_CONNECTED && (millis() - startTime) <= connectTimeout) { // && status != WL_NO_SSID_AVAIL && status != WL_CONNECT_FAILED
172224
delay(10);
173225
status = WiFi.status();
174226
}
@@ -180,15 +232,32 @@ uint8_t WiFiMulti::run(uint32_t connectTimeout)
180232
log_d("[WIFI] IP: %s", WiFi.localIP().toString().c_str());
181233
log_d("[WIFI] MAC: %s", WiFi.BSSIDstr().c_str());
182234
log_d("[WIFI] Channel: %d", WiFi.channel());
235+
236+
if (_connectionTestCBFunc != NULL) {
237+
// We connected to an AP but if it's a captive portal we're not going anywhere. Test it.
238+
if (_connectionTestCBFunc()) {
239+
resetFails();
240+
} else {
241+
markAsFailed(bestIndex);
242+
WiFi.disconnect();
243+
delay(10);
244+
status = WiFi.status();
245+
}
246+
} else {
247+
resetFails();
248+
}
183249
break;
184250
case WL_NO_SSID_AVAIL:
185251
log_e("[WIFI] Connecting Failed AP not found.");
252+
markAsFailed(bestIndex);
186253
break;
187254
case WL_CONNECT_FAILED:
188255
log_e("[WIFI] Connecting Failed.");
256+
markAsFailed(bestIndex);
189257
break;
190258
default:
191259
log_e("[WIFI] Connecting Failed (%d).", status);
260+
markAsFailed(bestIndex);
192261
break;
193262
}
194263
} else {
@@ -210,3 +279,27 @@ uint8_t WiFiMulti::run(uint32_t connectTimeout)
210279
void WiFiMulti::enableIPv6(bool state) {
211280
ipv6_support = state;
212281
}
282+
283+
void WiFiMulti::markAsFailed(int32_t i) {
284+
APlist[i].hasFailed = true;
285+
log_d("[WIFI] Marked SSID %s as failed", APlist[i].ssid);
286+
}
287+
288+
void WiFiMulti::resetFails(){
289+
for(uint32_t i = 0; i < APlist.size(); i++) {
290+
APlist[i].hasFailed = false;
291+
}
292+
log_d("[WIFI] Resetting failure flags");
293+
}
294+
295+
void WiFiMulti::setStrictMode(bool bStrict) {
296+
_bStrict = bStrict;
297+
}
298+
299+
void WiFiMulti::setAllowOpenAP(bool bAllowOpenAP) {
300+
_bAllowOpenAP = bAllowOpenAP;
301+
}
302+
303+
void WiFiMulti::setConnectionTestCallbackFunc(ConnectionTestCB_t cbFunc) {
304+
_connectionTestCBFunc = cbFunc;
305+
}

‎libraries/WiFi/src/WiFiMulti.h

Copy file name to clipboardExpand all lines: libraries/WiFi/src/WiFiMulti.h
+28-2Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,22 +32,48 @@
3232
typedef struct {
3333
char * ssid;
3434
char * passphrase;
35+
bool hasFailed;
3536
} WifiAPlist_t;
3637

38+
typedef std::function<bool(void)> ConnectionTestCB_t;
39+
3740
class WiFiMulti
3841
{
3942
public:
4043
WiFiMulti();
4144
~WiFiMulti();
4245

4346
bool addAP(const char* ssid, const char *passphrase = NULL);
44-
45-
void enableIPv6(bool state);
4647
uint8_t run(uint32_t connectTimeout=5000);
48+
void enableIPv6(bool state);
49+
50+
// Force (default: true) to only keep connected or to connect to an AP from the provided WiFiMulti list.
51+
// When bStrict is false, it will keep the last/current connected AP even if not in the WiFiMulti List.
52+
void setStrictMode(bool bStrict = true);
53+
54+
// allows (true) to connect to ANY open AP, even if not in the user list
55+
// default false (do not connect to an open AP that has not been explicitaly added by the user to list)
56+
void setAllowOpenAP(bool bAllowOpenAP = false);
57+
58+
// clears the current list of Multi APs and frees the memory
59+
void APlistClean(void);
60+
61+
// allow the user to define a callback function that will validate the connection to the Internet.
62+
// if the callback returns true, the connection is considered valid and the AP will added to the validated AP list.
63+
// set the callback to NULL to disable the feature and validate any SSID that is in the list.
64+
void setConnectionTestCallbackFunc(ConnectionTestCB_t cbFunc);
4765

4866
private:
4967
std::vector<WifiAPlist_t> APlist;
5068
bool ipv6_support;
69+
70+
bool _bStrict = true;
71+
bool _bAllowOpenAP = false;
72+
ConnectionTestCB_t _connectionTestCBFunc = NULL;
73+
bool _bWFMInit = false;
74+
75+
void markAsFailed(int32_t i);
76+
void resetFails();
5177
};
5278

5379
#endif /* WIFICLIENTMULTI_H_ */

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.