Skip to content

Instantly share code, notes, and snippets.

@AndiSHFR
Last active February 13, 2023 06:23
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save AndiSHFR/e9c46890af7cddff6cb5ea7d4f1c5c49 to your computer and use it in GitHub Desktop.
Save AndiSHFR/e9c46890af7cddff6cb5ea7d4f1c5c49 to your computer and use it in GitHub Desktop.
ESP8266 : WiFiAutoSelector - Pick wifi with best signal from a list and connect to it.
/**
* WiFiAutoSelector.h - Include file for class WiFiAutoSelector
* Copyright (c) 2016 Andreas Schaefer <asc@schaefer-it.net>
*
* A class to pick a wifi network from a list, based on the
* highest receive signal strength, and connect to it.
* Inspired by "WiFiMulti"
*
* This source code is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* Usage example:
*
* #include <ESP8266WiFi.h>
* #include "WiFiAutoSelector.h"
*
* #define WIFI_CONNECT_TIMEOUT 8000
* WiFiAutoSelector wifiAutoSelector(WIFI_CONNECT_TIMEOUT);
*
* void setup() {
* Serial.begin(9600);
* wifiAutoSelector.add("myApOne", "s4crzt");
* wifiAutoSelector.add("anotherApTwo", "moreSecret");
* }
*
* void loop() {
* if(WiFi.status() != WL_CONNECTED) {
* Serial.print("Connecting wifi ");
* if(-1 < wifiAutoSelector.scanAndConnect()) {
* int connectedIndex = wifiAutoSelector.getConnectedIndex();
* Serial.print("to '");
* Serial.print(wifiAutoSelector.getSSID(connectedIndex));
* Serial.println("'. Done.");
* }else{
* Serial.println("failed.");
* }
* }
* delay(1000);
* }
*
*/
class WiFiAutoSelector {
private:
typedef struct _NetworkInfo {
int rssi;
char ssid[32];
char key[64];
} NetworkInfo;
protected:
const int _WAIT_CONNECT_DELAY = 500;
NetworkInfo* _networks;
int _count;
int _capacity;
int _connectedIndex;
int _connectTimeout;
int _debug;
bool resize(int newCapacity) {
if(newCapacity <= _capacity) return true;
NetworkInfo* tni = (NetworkInfo*)malloc( sizeof(NetworkInfo) * newCapacity );
if(!tni) return false;
memset(tni, 0, sizeof(NetworkInfo) * newCapacity);
for(int i=0; i < _count; i++) {
tni[i] = _networks[i];
}
if(_networks) free(_networks);
_networks = tni;
_capacity = newCapacity;
return true;
}
public:
int getCount() { return _count; }
int getCapacity() { return _capacity; }
int getConnectedIndex() { return _connectedIndex; }
int getRSSI(int index) { return _networks[index].rssi; }
char* getSSID(int index) { return _networks[index].ssid; }
char* getKey(int index) { return _networks[index].key; }
void clear() {
memset(_networks, 0, sizeof(NetworkInfo) * _capacity );
_count = 0;
}
int add(const char* ssid, const char* key) {
bool canAdd = true;
if((_count + 1) >= _capacity) { canAdd = resize( _capacity + 4 ); }
if(canAdd) {
_networks[_count].rssi = -1000;
strncpy(_networks[_count].ssid, ssid, sizeof(_networks[_count].ssid));
strncpy(_networks[_count].key, key, sizeof(_networks[_count].key));
_count++;
return _count - 1;
}
// Could not add the ssid so return -1
return -1;
}
int scanAndConnect() {
// Initialize some variables
_connectedIndex = -1;
// No networks, then return;
if(!_networks || !_count) return _connectedIndex;
// Reset RSSI for every known network to lowest value
for(int i = 0; i < _count; i++) {
_networks[i].rssi = -1000;
}
int foundNetworkCount = WiFi.scanNetworks();
if(0 >= foundNetworkCount) return _connectedIndex;
int bestRSSI = -1000;
int bestNetworkIndex = -1;
while(foundNetworkCount-- > 0 ) {
String foundSSID = WiFi.SSID(foundNetworkCount);
if(_debug) {
Serial.print("WiFiAutoSelector found network: ");
Serial.println(foundSSID);
}
for(int i = 0; i < _count; i++ ) {
if(foundSSID.equals(_networks[i].ssid)) {
// RSSI : the current RSSI / Received Signal Strength in dBm
_networks[i].rssi = WiFi.RSSI(foundNetworkCount);
// Keep the network index with the best signal strength
if(bestRSSI < _networks[i].rssi) {
bestRSSI = _networks[i].rssi;
bestNetworkIndex = i;
}
break;
}
} // for(int i = 0; i < _count; i++ ) ...
} // while(foundNetworkCount > 0 ) ...
// If we have found a best network, connect to it.
if(-1 < bestNetworkIndex) {
if(_debug) {
Serial.print("WiFiAutoSelector will connect to: ");
Serial.print(_networks[bestNetworkIndex].ssid);
}
WiFi.disconnect();
delay(_WAIT_CONNECT_DELAY);
WiFi.begin(_networks[bestNetworkIndex].ssid, _networks[bestNetworkIndex].key);
// Wait for the wifi to connect. This should happen within the timeout period.
for(int loop = _connectTimeout; loop > 0; loop -= _WAIT_CONNECT_DELAY ) {
delay(_WAIT_CONNECT_DELAY);
if(WiFi.status() == WL_CONNECTED) {
_connectedIndex = bestNetworkIndex;
if(_debug) {
Serial.print("WiFi IP Address: ");
Serial.println(WiFi.localIP());
}
break;
}
}
}
return _connectedIndex;
}
~WiFiAutoSelector() {
if(_networks) free(_networks);
}
WiFiAutoSelector(int connectTimeout, int debug = false) :
_networks(0L), _count(0), _capacity(0)
, _connectedIndex(-1) , _connectTimeout(connectTimeout), _debug(debug) {
}
};
@WanaGo
Copy link

WanaGo commented Jul 28, 2018

This is brilliant, thank you for sharing this

@ahmedalkhabeer
Copy link

where can i get the wifiautoselector.h file from

@AndiSHFR
Copy link
Author

where can i get the wifiautoselector.h file from

You can get it from here. Just click on the "raw" button in the top right corner.
Then copy the content of your browser window into a new tab in the arduino ide.
That's all.

The comment section on top of th file contains an example how to use it.

@vh2c
Copy link

vh2c commented May 16, 2019

Thanks for sharing. It's a very nice code.
Is that possible to connect FREE WIFI scanned adapting your code with something like this :
if(WiFi.encryptionType(indices[i]) == ENC_TYPE_NONE){//TRY CONNECTION}
?
Thank you once more.

@RaphaelGirardRioTinto
Copy link

Hello.

Thanks for sharing this library, it works pretty well for me.

Does your library works with hidden SSID ? I tried it with 2 AP broadcasting networks with hidden SSID and I could not connect to them with this library.

Regards,
Raphael

@AndiSHFR
Copy link
Author

AndiSHFR commented Nov 14, 2020 via email

@albe62
Copy link

albe62 commented Dec 27, 2020

Hi, thanks for the code, it’s very useful and works perfectly. I have two questions, if I can ask you:

  • Why “return -1” at row 103?
  • At rows 126 & 131 you use inList (false and true), why? I commented them and the code works as well.
    If you want, you could correct row 26 (“setuo” instead “setup”) because one user could uncomment the code and have it not working.
    Thanks again
    Alberto

@AndiSHFR
Copy link
Author

Hello albe62.

Line 103
The add() method returns the array index position the item has been added at (see line 101).
So for the first element it will be 0, for the second 1 and so on. If the add() fails (i.e. resize() failed) the return value will be -1.
For the sake of simplicity in the example at the very top the check has been omitted.
Usually one would write it like:

if( -1 == wifiAutoSelector.add("myApOne", "s4crzt")) Serial.println("Error calling wifiAutoSelector.add()!");

Line 126 & 131
You are absolutely right. Code will also work without the inList flag.
While writing the code at first i had a slightly different approach comparing the list of found networks from the WiFi object against the list of known networks of the WifiAutoSelector class. inList is a left over from this old code.

I got an updated version of the class/file with some optional debugging output.

Thanks for the notes.

@maurimerel
Copy link

Hi there , Your library is just what I was looking for , just one thing I don't know if can be done . I have at least 10 AP with the same SSID distributed across a building , would it be possible to select the one with strongest signal in that case ??? If not ,could I let's say somehow list the macids instead and select based on them???
Thank you !!!!

@AndiSHFR
Copy link
Author

AndiSHFR commented Jun 21, 2022 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment