-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathWiFiManager.cpp
344 lines (250 loc) · 8.13 KB
/
WiFiManager.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
#include "WiFiManager.h"
WiFiManager::WiFiManager() {
}
WiFiManager::~WiFiManager() {
}
void WiFiManager::setup() {
#ifdef WDEBUG
Serial.println("The WiFiManager says hi !!");
#endif
isFirstScan = true;
lastWiFiStateUpdateTime = 0;
// We directly start to check if an SSID is available
state = WIFI_CHECK_SSID_AVAILABLE;
//updateWiFiStates();
}
void WiFiManager::loop() {
if ( ( millis() - lastWiFiStateUpdateTime >= 1000 ) ||
( previousState != state )
) {
updateWiFiStates();
lastWiFiStateUpdateTime = millis();
}
}
bool WiFiManager::connected() {
if(state == WIFI_CONNECTED) return true;
else return false;
}
void WiFiManager::resetWiFiRetryConnectTimer() {
// when we are active on the softap we don't want to move out of the WiFi Direct state
// this make the time a bit longer indeed
// we call this when someone asks for a page.
// we need to improve this function later on, for example to check if
// someone is really active.
if(state == WIFI_DIRECT) currentStateStartTime = millis();
}
void WiFiManager::updateWiFiStates() {
// we don't control the states completely by our selves.
// however we use build in functions to check what's going on.
// later (when softap is fully supported) more states can be introduced
// for example if a client is actually actively doing something.
switch(state) {
case WIFI_DIRECT:
if(WiFi.ready()) state = WIFI_CONNECTED;
else {
// check if we are really in WiFi Direct mode
// if not we enter it.
if(!WiFi.listening()) {
WiFi.listen();
#ifdef WDEBUG
//Serial.print("WiFi.listening() status after WiFi.listen() call: ");
//Serial.println(WiFi.listening());
#endif
}
#ifdef WDEBUG
Serial.print("time in WiFi direct (listen) state: ");
Serial.println(millis() - currentStateStartTime);
#endif
// we check if the stored SSID is avaiable every n seconds
if(millis() - currentStateStartTime >= WIFI_DIRECT_SSID_ATTEMPT_CALL_TIMEOUT) {
state = WIFI_CHECK_SSID_AVAILABLE;
weakRSSIFlag = false; // reset the flag here for a new attempt
}
}
break;
case WIFI_CONNECTED:
if(WiFi.listening()) state = WIFI_DIRECT;
else {
if(!WiFi.ready()) {
// we probably lost connection
// we might be able to go directly to WIFI_ATTEMPT_CONNECTING
// otherwise we have never ended up here. However this is more secure.
// because SSID Available sends us to wifi direct mode.
state = WIFI_CHECK_SSID_AVAILABLE;
}
}
// manually connect to the cloud if we didn't do it yet
if(!Particle.connected()) {
Particle.connect();
}
else {
Particle.process();
// time sync
if (millis() - lastRtcUpdateTime >= ONE_DAY_MILLIS) {
Particle.syncTime();
lastRtcUpdateTime = millis();
}
}
#ifdef WDEBUG
//Serial.print("Current RSSI: ");
//Serial.println(WiFi.RSSI());
#endif
break;
case WIFI_CHECK_SSID_AVAILABLE:
// We have to stop the listen mode when doing a connection attempt.
// We only do this when we know that our stored SSID is available and that
// The signal strength is sufficient enough to be stable.
// Time out is to prevent that we get stuck in case the RSSI is weak.
if(WiFi.hasCredentials()) {
// always check if there is an update in credentials
storedWAPsAmount = WiFi.getCredentials(storedWAPs, 5);
if(isStoredSSIDAvailable()) {
// >-50 dBm (excellent), -50 to -60 dBm (good), 60 to -75 dBm (fair), < -75 dBm (weak)
if(foundSSID_RSSI > -75)
{
#ifdef WDEBUG
Serial.println("SSID Found with signal strength higher then -75 dBm");
#endif
// we reset it here, this seems the most logical
failedConnectionAttemptFlag = false;
weakRSSIFlag = false;
state = WIFI_ATTEMPT_CONNECTING;
}
else {
#ifdef WDEBUG
Serial.println("weak RSSI");
#endif
// Weak RSSI
weakRSSIFlag = true;
// move to WIFI_DIRECT
if(millis() - currentStateStartTime >= CHECK_SSID_AVAILABLE_TIMEOUT) {
state = WIFI_DIRECT;
}
}
}
else {
// credentials stored in Photon
// however we can't find them with a scan
if(millis() - currentStateStartTime >= CHECK_SSID_AVAILABLE_TIMEOUT) {
state = WIFI_DIRECT;
}
}
}
else {
// no credentials so we can go directly (back) to WiFI Direct
state = WIFI_DIRECT;
}
break;
case WIFI_ATTEMPT_CONNECTING:
// in this state we already have found to SSID that we try to
// connect to. So if this fails why probably have a wrong password entered
// or the connection is not stable enough...
if(millis() - currentStateStartTime <= ATTEMPT_CONNECTING_TIMEOUT) {
if(WiFi.ready()) {
state = WIFI_CONNECTED;
}
else {
//WiFi.listen(false);
//Serial.print("connecting() :");
//Serial.println(WiFi.connecting());
//WiFi.connecting will return false once the device has successfully
//connected to the Wi-Fi network.
if( !WiFi.connecting() ) {
// WiFi connect won't work if we are listening
WiFi.listen(false);
// we manage listen ourself
WiFi.connect(WIFI_CONNECT_SKIP_LISTEN);
//Serial.print("connecting after call to connect :");
//Serial.println(WiFi.connecting());
#ifdef WDEBUG
Serial.println("Attempting to connect.");
#endif
}
}
}
else {
// we are attempting for more than n seconds now.
// time to move on...
state = WIFI_DIRECT;
// set the failedConnectAttemptFlag
// we don't use it to block this state. However we can give feedback
// to the user that they probably have entered a wrong password.
failedConnectionAttemptFlag = true;
#ifdef WDEBUG
Serial.println("Failed attempt!");
#endif
}
break;
};
// we'd like to know how long we are in a certain state.
if(previousState != state) {
currentStateStartTime = millis();
#ifdef WDEBUG
Serial.print("Current state: ");
Serial.print(state);
Serial.print(" ");
if(state == WIFI_DIRECT) Serial.print(" WIFI_DIRECT");
if(state == WIFI_CONNECTED) Serial.print(" WIFI_CONNECTED");
if(state == WIFI_CHECK_SSID_AVAILABLE) Serial.print(" WIFI_CHECK_SSID_AVAILABLE");
if(state == WIFI_ATTEMPT_CONNECTING) Serial.print(" WIFI_ATTEMPT_CONNECTING");
if(state == WIFI_OFF) Serial.print(" WIFI_OFF");
Serial.println();
#endif
previousState = state;
}
}
// This is the callback passed to WiFi.scan()
// It makes the call on the `self` instance - to go from a static
// member function to an instance member function.
void WiFiManager::handle_ap(WiFiAccessPoint* wap, WiFiManager* self)
{
self->next(*wap);
}
void WiFiManager::next(WiFiAccessPoint& ap)
{
#ifdef WDEBUG
Serial.print("SSID: ");
Serial.println(ap.ssid);
#endif
for (int i = 0; i < storedWAPsAmount; i++) {
if (strcmp(ap.ssid, storedWAPs[i].ssid) == 0) {
isStoredSSIDFound = true;
foundSSID_RSSI = ap.rssi;
#ifdef WDEBUG
Serial.print("Found Stored SSID: ");
Serial.print(ap.ssid);
Serial.print(" RSSI: ");
Serial.println(ap.rssi);
#endif
// we move out of the loop when we found
// the ssid
break;
}
}
}
bool WiFiManager::isStoredSSIDAvailable() {
// in the callback we compare scanned WAPs with the stored WAPs
// storedSSIDFound will be set to true if we have a match
// this is global so we can access this after a call to this function
isStoredSSIDFound = false;
#ifdef WDEBUG
Serial.println("Call WiFi.scan");
#endif
// safety measures againt firmware crash.
// this only works when in a certain
if(isFirstScan) {
//Serial.print("isFirstScan before WiFi.listening() status : ");
//Serial.println(WiFi.listening());
WiFi.on();
// necessary
// https://github.com/spark/firmware/issues/1062#issuecomment-246777494
// delay in loop doesn't matter since led functionality is controlled
// in a separate thread
delay(500);
//Serial.print("isFirstScan after WiFi.listening() status : ");
//Serial.println(WiFi.listening());
isFirstScan = false;
}
WiFi.scan(handle_ap, this);
return isStoredSSIDFound;
}