diff --git a/src/AutoConnect.cpp b/src/AutoConnect.cpp index 07016a2..05c1dcf 100644 --- a/src/AutoConnect.cpp +++ b/src/AutoConnect.cpp @@ -2,8 +2,8 @@ * AutoConnect class implementation. * @file AutoConnect.cpp * @author hieromon@gmail.com - * @version 1.1.1 - * @date 2019-10-17 + * @version 1.1.5 + * @date 2019-03-17 * @copyright MIT license. */ @@ -95,15 +95,6 @@ bool AutoConnect::begin(const char* ssid, const char* passphrase, unsigned long _ticker->start(AUTOCONNECT_FLICKER_PERIODDC, (uint8_t)AUTOCONNECT_FLICKER_WIDTHDC); } - // Advance configuration for STA mode. Restore previous configuration of STA. - station_config_t current; - if (_getConfigSTA(¤t)) { - AC_DBG("Current:%.32s\n", current.ssid); - _loadAvailCredential(reinterpret_cast(current.ssid)); - } - if (!_configSTA(_apConfig.staip, _apConfig.staGateway, _apConfig.staNetmask, _apConfig.dns1, _apConfig.dns2)) - return false; - // If the portal is requested promptly skip the first WiFi.begin and // immediately start the portal. if (_apConfig.immediateStart) { @@ -112,29 +103,47 @@ bool AutoConnect::begin(const char* ssid, const char* passphrase, unsigned long AC_DBG("Start the portal immediately\n"); } else { - // Try to connect by STA immediately. - if (ssid == nullptr && passphrase == nullptr) - WiFi.begin(); - else { - _disconnectWiFi(false); - WiFi.begin(ssid, passphrase); + cs = true; + // Prepare valid configuration according to the WiFi connection right order. + const char* c_ssid = ssid; + const char* c_password = passphrase; + station_config_t current; + if (_getConfigSTA(¤t)) + AC_DBG("Current:%.32s\n", current.ssid); + if (_apConfig.wifiDisp == AC_WIFIDISP_RSSI && (ssid == nullptr && passphrase == nullptr)) { + // AC_WIFIDISP_RSSI is available when SSID and password are not provided. + // Find the strongest signal from the broadcast among the saved credentials. + if ((cs = _loadAvailCredential(nullptr, AC_WIFIDISP_RSSI, false))) { + memcpy(current.ssid, _credential.ssid, sizeof(station_config_t::ssid)); + memcpy(current.password, _credential.password, sizeof(station_config_t::password)); + c_ssid = reinterpret_cast(current.ssid); + c_password = reinterpret_cast(current.password); + AC_DBG("Adopted:%.32s\n", c_ssid); + } } - AC_DBG("WiFi.begin(%s%s%s)\n", ssid == nullptr ? "" : ssid, passphrase == nullptr ? "" : ",", passphrase == nullptr ? "" : passphrase); - cs = _waitForConnect(_connectTimeout) == WL_CONNECTED; -#ifdef INC_RSSI_USE_SUP //!!! - if(cs==true) { - if(WiFi.RSSI()<_apConfig.conMinRSSI || _apConfig.conFindMaxRSSI==true) { - _disconnectWiFi(false); - cs=false; + + if (cs) { + // Advance configuration for STA mode. Restore previous configuration of STA. + _loadAvailCredential(reinterpret_cast(current.ssid)); + if (!_configSTA(_apConfig.staip, _apConfig.staGateway, _apConfig.staNetmask, _apConfig.dns1, _apConfig.dns2)) + return false; + + // Try to connect by STA immediately. + if (c_ssid == nullptr && c_password == nullptr) + WiFi.begin(); + else { + _disconnectWiFi(false); + WiFi.begin(c_ssid, c_password); } + AC_DBG("WiFi.begin(%s%s%s)\n", c_ssid == nullptr ? "" : c_ssid, c_password == nullptr ? "" : ",", c_password == nullptr ? "" : c_password); + cs = _waitForConnect(_connectTimeout) == WL_CONNECTED; } -#endif } // Reconnect with a valid credential as the autoReconnect option is enabled. if (!cs && _apConfig.autoReconnect && (ssid == nullptr && passphrase == nullptr)) { // Load a valid credential. - if (_loadAvailCredential(nullptr)) { + if (_loadAvailCredential(nullptr, _apConfig.wifiDisp, true)) { // Try to reconnect with a stored credential. char ssid_c[sizeof(station_config_t::ssid) + sizeof('\0')]; char password_c[sizeof(station_config_t::password) + sizeof('\0')]; @@ -142,7 +151,7 @@ bool AutoConnect::begin(const char* ssid, const char* passphrase, unsigned long strncat(ssid_c, reinterpret_cast(_credential.ssid), sizeof(ssid_c) - sizeof('\0')); *password_c = '\0'; strncat(password_c, reinterpret_cast(_credential.password), sizeof(password_c) - sizeof('\0')); - AC_DBG("autoReconnect loaded SSID:%s\n", ssid_c); + AC_DBG("autoReconnect loaded:%s(%s)\n", ssid_c, _apConfig.wifiDisp == AC_WIFIDISP_RECENT ? "RECENT" : "RSSI"); const char* psk = strlen(password_c) ? password_c : nullptr; _configSTA(IPAddress(_credential.config.sta.ip), IPAddress(_credential.config.sta.gateway), IPAddress(_credential.config.sta.netmask), IPAddress(_credential.config.sta.dns1), IPAddress(_credential.config.sta.dns2)); WiFi.begin(ssid_c, psk); @@ -620,9 +629,11 @@ void AutoConnect::onNotFound(WebServerClass::THandlerFunction fn) { /** * Load stored credentials that match nearby WLANs. * @param ssid SSID which should be loaded. If nullptr is assigned, search SSID with WiFi.scan. + * @param wifiDisp WiFi connection disposition. + * @param excludeCurrent Skip loading the current SSID. * @return true A matched credential of BSSID was loaded. */ -bool AutoConnect::_loadAvailCredential(const char* ssid) { +bool AutoConnect::_loadAvailCredential(const char* ssid, const AC_WIFIDISP_t wifiDisp, const bool excludeCurrent) { AutoConnectCredential credential(_apConfig.boundaryOffset); if (credential.entries() > 0) { @@ -632,49 +643,55 @@ bool AutoConnect::_loadAvailCredential(const char* ssid) { int8_t nn = WiFi.scanNetworks(false, true); AC_DBG("%d network(s) found\n", (int)nn); if (nn > 0) { - // Determine valid credentials by BSSID. -#ifdef INC_RSSI_USE_SUP //!!! - int maxRSSIWifiIndex=-1; - int maxRSSICredIndex=-1; -#endif + station_config_t validConfig; // Temporary to find the strongest RSSI. + int32_t minRSSI = -120; // Min value to find the strongest RSSI. + + // Seek SSID + const char* currentSSID = WiFi.SSID().c_str(); + const bool skipCurrent = excludeCurrent & (strlen(currentSSID) > 0); for (uint8_t i = 0; i < credential.entries(); i++) { credential.load(i, &_credential); + // Seek valid configuration according to the WiFi connection disposition. + // Verify that an available SSIDs meet AC_WIFIDISP_t requirements. for (uint8_t n = 0; n < nn; n++) { -#ifdef INC_RSSI_USE_SUP //!!! + if (skipCurrent && !strcmp(currentSSID, WiFi.SSID(n).c_str())) + continue; if (!memcmp(_credential.bssid, WiFi.BSSID(n), sizeof(station_config_t::bssid))) { - - if(WiFi.RSSI(n)>=_apConfig.conMinRSSI) { - if(_apConfig.conFindMaxRSSI!=true) { - return true; - } - - if(maxRSSIWifiIndex<0) { - maxRSSIWifiIndex=n; - maxRSSICredIndex=i; - } else { - if(WiFi.RSSI(n)>WiFi.RSSI(maxRSSIWifiIndex)) { - maxRSSIWifiIndex=n; - maxRSSICredIndex=i; - } - } - - } - - } -#else - if (!memcmp(_credential.bssid, WiFi.BSSID(n), sizeof(station_config_t::bssid))) - return true; -#endif + // Excepts SSID that has weak RSSI under the lower limit. + if (WiFi.RSSI(n) < _apConfig.minRSSI) { + AC_DBG("%s:%" PRId32 "dBm, rejected\n", reinterpret_cast(_credential.ssid), WiFi.RSSI(n)); + continue; + } + // Determine valid credential + switch (wifiDisp) { + case AC_WIFIDISP_RECENT: + // By BSSID, exit to keep the credential just loaded. + return true; + + case AC_WIFIDISP_RSSI: + // Verify that most strong radio signal. + // Continue seeking to find the strongest WIFI signal SSID. + if (WiFi.RSSI(n) > minRSSI) { + minRSSI = WiFi.RSSI(n); + memcpy(&validConfig, &_credential, sizeof(station_config_t)); + } + break; + } + break; + } } } -#ifdef INC_RSSI_USE_SUP //!!! - if(maxRSSIWifiIndex>=0) { - credential.load(maxRSSICredIndex, &_credential); - return true; - } -#endif + // Increasing the minSSI will indicate the successfully sought for AC_WIFIDISP_RSSI. + // Restore the credential that has maximum RSSI. + if (minRSSI > -120) { + memcpy(&_credential, &validConfig, sizeof(station_config_t)); + return true; + } } } + + // The SSID to load was specified. + // Set the IP configuration globally from the saved credential. else if (strlen(ssid)) if (credential.load(ssid, &_credential) >= 0) { if (_credential.dhcp == STA_STATIC) { diff --git a/src/AutoConnect.h b/src/AutoConnect.h index 60beba6..bfed533 100644 --- a/src/AutoConnect.h +++ b/src/AutoConnect.h @@ -2,8 +2,8 @@ * Declaration of AutoConnect class and accompanying AutoConnectConfig class. * @file AutoConnect.h * @author hieromon@gmail.com - * @version 1.1.1 - * @date 2019-10-17 + * @version 1.1.5 + * @date 2020-03-16 * @copyright MIT license. */ @@ -50,6 +50,12 @@ typedef enum AC_ONBOOTURI { AC_ONBOOTURI_HOME } AC_ONBOOTURI_t; +/** WiFi connection disposition, it specifies the order of WiFI connecting with saved credentials. */ +typedef enum AC_WIFIDISP { + AC_WIFIDISP_RECENT, + AC_WIFIDISP_RSSI +} AC_WIFIDISP_t; + class AutoConnectConfig { public: /** @@ -58,10 +64,6 @@ class AutoConnectConfig { * assigned from macro. Password is same as above too. */ AutoConnectConfig() : -#ifdef INC_RSSI_USE_SUP //!!! - conMinRSSI(AUTOCONNECT_CON_MIN_RSSI), - conFindMaxRSSI(AUTOCONNECT_CON_FIND_MAX_RSSI), -#endif apip(AUTOCONNECT_AP_IP), gateway(AUTOCONNECT_AP_GW), netmask(AUTOCONNECT_AP_NM), @@ -69,8 +71,10 @@ class AutoConnectConfig { psk(String(AUTOCONNECT_PSK)), channel(AUTOCONNECT_AP_CH), hidden(0), + minRSSI(AUTOCONNECT_MIN_RSSI), autoSave(AC_SAVECREDENTIAL_AUTO), bootUri(AC_ONBOOTURI_ROOT), + wifiDisp(AC_WIFIDISP_RECENT), boundaryOffset(AC_IDENTIFIER_OFFSET), uptime(AUTOCONNECT_STARTUPTIME), autoRise(true), @@ -94,10 +98,6 @@ class AutoConnectConfig { * Configure by SSID for the captive portal access point and password. */ AutoConnectConfig(const char* ap, const char* password, const unsigned long portalTimeout = 0, const uint8_t channel = AUTOCONNECT_AP_CH) : -#ifdef INC_RSSI_USE_SUP //!!! - conMinRSSI(AUTOCONNECT_CON_MIN_RSSI), - conFindMaxRSSI(AUTOCONNECT_CON_FIND_MAX_RSSI), -#endif apip(AUTOCONNECT_AP_IP), gateway(AUTOCONNECT_AP_GW), netmask(AUTOCONNECT_AP_NM), @@ -105,8 +105,10 @@ class AutoConnectConfig { psk(String(password)), channel(channel), hidden(0), + minRSSI(AUTOCONNECT_MIN_RSSI), autoSave(AC_SAVECREDENTIAL_AUTO), bootUri(AC_ONBOOTURI_ROOT), + wifiDisp(AC_WIFIDISP_RECENT), boundaryOffset(AC_IDENTIFIER_OFFSET), uptime(AUTOCONNECT_STARTUPTIME), autoRise(true), @@ -130,10 +132,6 @@ class AutoConnectConfig { ~AutoConnectConfig() {} AutoConnectConfig& operator=(const AutoConnectConfig& o) { -#ifdef INC_RSSI_USE_SUP //!!! - conMinRSSI=o.conMinRSSI; - conFindMaxRSSI=o.conFindMaxRSSI; -#endif apip = o.apip; gateway = o.gateway; netmask = o.netmask; @@ -141,8 +139,10 @@ class AutoConnectConfig { psk = o.psk; channel = o.channel; hidden = o.hidden; + minRSSI=o.minRSSI; autoSave = o.autoSave; bootUri = o.bootUri; + wifiDisp = o.wifiDisp; boundaryOffset = o.boundaryOffset; uptime = o.uptime; autoRise = o.autoRise; @@ -166,10 +166,6 @@ class AutoConnectConfig { } -#ifdef INC_RSSI_USE_SUP //!!! - int conMinRSSI; /**< Minimum AP signal strength accepted for connection */ - bool conFindMaxRSSI; /**< Find stored AP with highest signal strength for connection */ -#endif IPAddress apip; /**< SoftAP IP address */ IPAddress gateway; /**< SoftAP gateway address */ IPAddress netmask; /**< SoftAP subnet mask */ @@ -177,8 +173,10 @@ class AutoConnectConfig { String psk; /**< SoftAP password */ uint8_t channel; /**< SoftAP used wifi channel */ uint8_t hidden; /**< SoftAP SSID hidden */ + int16_t minRSSI; /**< Lowest WiFi signal strength (RSSI) that can be connected. */ AC_SAVECREDENTIAL_t autoSave; /**< Auto save credential */ AC_ONBOOTURI_t bootUri; /**< An uri invoking after reset */ + AC_WIFIDISP_t wifiDisp; /**< WiFI connection disposition */ uint16_t boundaryOffset; /**< The save storage offset of EEPROM */ int uptime; /**< Length of start up time */ bool autoRise; /**< Automatic starting the captive portal */ @@ -245,7 +243,7 @@ class AutoConnect { void _startWebServer(void); void _startDNSServer(void); void _handleNotFound(void); - bool _loadAvailCredential(const char* ssid); + bool _loadAvailCredential(const char* ssid, const AC_WIFIDISP_t wifiDisp = AC_WIFIDISP_RECENT, const bool excludeCurrent = false); void _stopPortal(void); bool _classifyHandle(HTTPMethod mothod, String uri); void _handleUpload(const String& requestUri, const HTTPUpload& upload); diff --git a/src/AutoConnectDefs.h b/src/AutoConnectDefs.h index 1d10455..3cde0fd 100644 --- a/src/AutoConnectDefs.h +++ b/src/AutoConnectDefs.h @@ -2,8 +2,8 @@ * Predefined AutoConnect configuration parameters. * @file AutoConnectDefs.h * @author hieromon@gmail.com - * @version 1.1.0 - * @date 2019-10-11 + * @version 1.1.5 + * @date 2020-03-16 * @copyright MIT license. */ @@ -14,10 +14,6 @@ #define INC_RSSI_USE_SUP 1 #ifdef INC_RSSI_USE_SUP //!!! -#ifndef AUTOCONNECT_CON_MIN_RSSI -#define AUTOCONNECT_CON_MIN_RSSI -100 // no limit -#endif - #ifndef AUTOCONNECT_CON_FIND_MAX_RSSI #define AUTOCONNECT_CON_FIND_MAX_RSSI false // use first available #endif @@ -188,6 +184,11 @@ #endif #endif +// Lowest WiFi signal strength (RSSI) that can be connected. +#ifndef AUTOCONNECT_MIN_RSSI +#define AUTOCONNECT_MIN_RSSI -120 // No limit +#endif // !AUTOCONNECT_MIN_RSSI + // ArduinoJson buffer size #ifndef AUTOCONNECT_JSONBUFFER_SIZE #define AUTOCONNECT_JSONBUFFER_SIZE 256