|
|
@ -2,8 +2,8 @@ |
|
|
|
* AutoConnect class implementation. |
|
|
|
* AutoConnect class implementation. |
|
|
|
* @file AutoConnect.cpp |
|
|
|
* @file AutoConnect.cpp |
|
|
|
* @author hieromon@gmail.com |
|
|
|
* @author hieromon@gmail.com |
|
|
|
* @version 1.1.1 |
|
|
|
* @version 1.1.5 |
|
|
|
* @date 2019-10-17 |
|
|
|
* @date 2019-03-17 |
|
|
|
* @copyright MIT license. |
|
|
|
* @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); |
|
|
|
_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<const char*>(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
|
|
|
|
// If the portal is requested promptly skip the first WiFi.begin and
|
|
|
|
// immediately start the portal.
|
|
|
|
// immediately start the portal.
|
|
|
|
if (_apConfig.immediateStart) { |
|
|
|
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"); |
|
|
|
AC_DBG("Start the portal immediately\n"); |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
else { |
|
|
|
|
|
|
|
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<const char*>(current.ssid); |
|
|
|
|
|
|
|
c_password = reinterpret_cast<const char*>(current.password); |
|
|
|
|
|
|
|
AC_DBG("Adopted:%.32s\n", c_ssid); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (cs) { |
|
|
|
|
|
|
|
// Advance configuration for STA mode. Restore previous configuration of STA.
|
|
|
|
|
|
|
|
_loadAvailCredential(reinterpret_cast<const char*>(current.ssid)); |
|
|
|
|
|
|
|
if (!_configSTA(_apConfig.staip, _apConfig.staGateway, _apConfig.staNetmask, _apConfig.dns1, _apConfig.dns2)) |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
|
|
// Try to connect by STA immediately.
|
|
|
|
// Try to connect by STA immediately.
|
|
|
|
if (ssid == nullptr && passphrase == nullptr) |
|
|
|
if (c_ssid == nullptr && c_password == nullptr) |
|
|
|
WiFi.begin(); |
|
|
|
WiFi.begin(); |
|
|
|
else { |
|
|
|
else { |
|
|
|
_disconnectWiFi(false); |
|
|
|
_disconnectWiFi(false); |
|
|
|
WiFi.begin(ssid, passphrase); |
|
|
|
WiFi.begin(c_ssid, c_password); |
|
|
|
} |
|
|
|
} |
|
|
|
AC_DBG("WiFi.begin(%s%s%s)\n", ssid == nullptr ? "" : ssid, passphrase == nullptr ? "" : ",", passphrase == nullptr ? "" : passphrase); |
|
|
|
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; |
|
|
|
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; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Reconnect with a valid credential as the autoReconnect option is enabled.
|
|
|
|
// Reconnect with a valid credential as the autoReconnect option is enabled.
|
|
|
|
if (!cs && _apConfig.autoReconnect && (ssid == nullptr && passphrase == nullptr)) { |
|
|
|
if (!cs && _apConfig.autoReconnect && (ssid == nullptr && passphrase == nullptr)) { |
|
|
|
// Load a valid credential.
|
|
|
|
// Load a valid credential.
|
|
|
|
if (_loadAvailCredential(nullptr)) { |
|
|
|
if (_loadAvailCredential(nullptr, _apConfig.wifiDisp, true)) { |
|
|
|
// Try to reconnect with a stored credential.
|
|
|
|
// Try to reconnect with a stored credential.
|
|
|
|
char ssid_c[sizeof(station_config_t::ssid) + sizeof('\0')]; |
|
|
|
char ssid_c[sizeof(station_config_t::ssid) + sizeof('\0')]; |
|
|
|
char password_c[sizeof(station_config_t::password) + 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<const char*>(_credential.ssid), sizeof(ssid_c) - sizeof('\0')); |
|
|
|
strncat(ssid_c, reinterpret_cast<const char*>(_credential.ssid), sizeof(ssid_c) - sizeof('\0')); |
|
|
|
*password_c = '\0'; |
|
|
|
*password_c = '\0'; |
|
|
|
strncat(password_c, reinterpret_cast<const char*>(_credential.password), sizeof(password_c) - sizeof('\0')); |
|
|
|
strncat(password_c, reinterpret_cast<const char*>(_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; |
|
|
|
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)); |
|
|
|
_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); |
|
|
|
WiFi.begin(ssid_c, psk); |
|
|
@ -620,9 +629,11 @@ void AutoConnect::onNotFound(WebServerClass::THandlerFunction fn) { |
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Load stored credentials that match nearby WLANs. |
|
|
|
* Load stored credentials that match nearby WLANs. |
|
|
|
* @param ssid SSID which should be loaded. If nullptr is assigned, search SSID with WiFi.scan. |
|
|
|
* @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. |
|
|
|
* @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); |
|
|
|
AutoConnectCredential credential(_apConfig.boundaryOffset); |
|
|
|
|
|
|
|
|
|
|
|
if (credential.entries() > 0) { |
|
|
|
if (credential.entries() > 0) { |
|
|
@ -632,49 +643,55 @@ bool AutoConnect::_loadAvailCredential(const char* ssid) { |
|
|
|
int8_t nn = WiFi.scanNetworks(false, true); |
|
|
|
int8_t nn = WiFi.scanNetworks(false, true); |
|
|
|
AC_DBG("%d network(s) found\n", (int)nn); |
|
|
|
AC_DBG("%d network(s) found\n", (int)nn); |
|
|
|
if (nn > 0) { |
|
|
|
if (nn > 0) { |
|
|
|
// Determine valid credentials by BSSID.
|
|
|
|
station_config_t validConfig; // Temporary to find the strongest RSSI.
|
|
|
|
#ifdef INC_RSSI_USE_SUP //!!!
|
|
|
|
int32_t minRSSI = -120; // Min value to find the strongest RSSI.
|
|
|
|
int maxRSSIWifiIndex=-1; |
|
|
|
|
|
|
|
int maxRSSICredIndex=-1; |
|
|
|
// Seek SSID
|
|
|
|
#endif |
|
|
|
const char* currentSSID = WiFi.SSID().c_str(); |
|
|
|
|
|
|
|
const bool skipCurrent = excludeCurrent & (strlen(currentSSID) > 0); |
|
|
|
for (uint8_t i = 0; i < credential.entries(); i++) { |
|
|
|
for (uint8_t i = 0; i < credential.entries(); i++) { |
|
|
|
credential.load(i, &_credential); |
|
|
|
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++) { |
|
|
|
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 (!memcmp(_credential.bssid, WiFi.BSSID(n), sizeof(station_config_t::bssid))) { |
|
|
|
|
|
|
|
// Excepts SSID that has weak RSSI under the lower limit.
|
|
|
|
if(WiFi.RSSI(n)>=_apConfig.conMinRSSI) { |
|
|
|
if (WiFi.RSSI(n) < _apConfig.minRSSI) { |
|
|
|
if(_apConfig.conFindMaxRSSI!=true) { |
|
|
|
AC_DBG("%s:%" PRId32 "dBm, rejected\n", reinterpret_cast<const char*>(_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; |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(maxRSSIWifiIndex<0) { |
|
|
|
case AC_WIFIDISP_RSSI: |
|
|
|
maxRSSIWifiIndex=n; |
|
|
|
// Verify that most strong radio signal.
|
|
|
|
maxRSSICredIndex=i; |
|
|
|
// Continue seeking to find the strongest WIFI signal SSID.
|
|
|
|
} else { |
|
|
|
if (WiFi.RSSI(n) > minRSSI) { |
|
|
|
if(WiFi.RSSI(n)>WiFi.RSSI(maxRSSIWifiIndex)) { |
|
|
|
minRSSI = WiFi.RSSI(n); |
|
|
|
maxRSSIWifiIndex=n; |
|
|
|
memcpy(&validConfig, &_credential, sizeof(station_config_t)); |
|
|
|
maxRSSICredIndex=i; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
#else |
|
|
|
|
|
|
|
if (!memcmp(_credential.bssid, WiFi.BSSID(n), sizeof(station_config_t::bssid))) |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
#ifdef INC_RSSI_USE_SUP //!!!
|
|
|
|
// Increasing the minSSI will indicate the successfully sought for AC_WIFIDISP_RSSI.
|
|
|
|
if(maxRSSIWifiIndex>=0) { |
|
|
|
// Restore the credential that has maximum RSSI.
|
|
|
|
credential.load(maxRSSICredIndex, &_credential); |
|
|
|
if (minRSSI > -120) { |
|
|
|
|
|
|
|
memcpy(&_credential, &validConfig, sizeof(station_config_t)); |
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// The SSID to load was specified.
|
|
|
|
|
|
|
|
// Set the IP configuration globally from the saved credential.
|
|
|
|
else if (strlen(ssid)) |
|
|
|
else if (strlen(ssid)) |
|
|
|
if (credential.load(ssid, &_credential) >= 0) { |
|
|
|
if (credential.load(ssid, &_credential) >= 0) { |
|
|
|
if (_credential.dhcp == STA_STATIC) { |
|
|
|
if (_credential.dhcp == STA_STATIC) { |
|
|
|