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) {
}
};
@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