diff --git a/Network.cpp b/Network.cpp index f9df89b1..570ebb1d 100644 --- a/Network.cpp +++ b/Network.cpp @@ -686,6 +686,11 @@ const String Network::networkDeviceName() const return _device->deviceName(); } +const String Network::networkBSSID() const +{ + return _device->BSSIDstr(); +} + void Network::publishFloat(const char* prefix, const char* topic, const float value, const uint8_t precision) { char str[30]; diff --git a/Network.h b/Network.h index cdcff4f2..55d9a3e8 100644 --- a/Network.h +++ b/Network.h @@ -67,6 +67,7 @@ class Network int mqttConnectionState(); // 0 = not connected; 1 = connected; 2 = connected and mqtt processed bool encryptionSupported(); const String networkDeviceName() const; + const String networkBSSID() const; const NetworkDeviceType networkDeviceType(); diff --git a/PreferencesKeys.h b/PreferencesKeys.h index 7adf00ac..2a57b64f 100644 --- a/PreferencesKeys.h +++ b/PreferencesKeys.h @@ -36,6 +36,7 @@ #define preference_network_hardware "nwhw" #define preference_network_hardware_gpio "nwhwdt" // obsolete #define preference_network_wifi_fallback_disabled "nwwififb" +#define preference_find_best_rssi "nwbestrssi" #define preference_rssi_publish_interval "rssipb" #define preference_hostname "hostname" #define preference_network_timeout "nettmout" @@ -80,7 +81,7 @@ class DebugPreferences preference_mqtt_ca, preference_mqtt_crt, preference_mqtt_key, preference_mqtt_hass_discovery, preference_mqtt_hass_cu_url, preference_ip_dhcp_enabled, preference_ip_address, preference_ip_subnet, preference_ip_gateway, preference_ip_dns_server, preference_network_hardware, preference_network_wifi_fallback_disabled, preference_rssi_publish_interval, - preference_hostname, preference_network_timeout, preference_restart_on_disconnect, + preference_find_best_rssi, preference_hostname, preference_network_timeout, preference_restart_on_disconnect, preference_restart_ble_beacon_lost, preference_query_interval_lockstate, preference_query_interval_configuration, preference_query_interval_battery, preference_query_interval_keypad, preference_keypad_control_enabled, preference_admin_enabled, preference_keypad_info_enabled, preference_acl, @@ -100,7 +101,7 @@ class DebugPreferences std::vector _boolPrefs = { preference_started_before, preference_mqtt_log_enabled, preference_check_updates, preference_lock_enabled, preference_opener_enabled, preference_opener_continuous_mode, - preference_restart_on_disconnect, preference_keypad_control_enabled, preference_admin_enabled, preference_keypad_info_enabled, + preference_find_best_rssi, preference_restart_on_disconnect, preference_keypad_control_enabled, preference_admin_enabled, preference_keypad_info_enabled, preference_timecontrol_control_enabled, preference_timecontrol_info_enabled, preference_register_as_app, preference_ip_dhcp_enabled, preference_publish_authdata, preference_has_mac_saved, preference_publish_debug_info, preference_network_wifi_fallback_disabled }; diff --git a/README.md b/README.md index f23a787c..f7e769b1 100644 --- a/README.md +++ b/README.md @@ -112,6 +112,7 @@ In a browser navigate to the IP address assigned to the ESP32. - MQTT SSL Client Key: Optionally set to the Client SSL key of the MQTT broker, see the "MQTT Encryption" section of this README. - Network hardware: "Wi-Fi only" by default, set to one of the specified ethernet modules if available, see the "Supported Ethernet devices" and "Connecting via Ethernet" section of this README. - Disable fallback to Wi-Fi / Wi-Fi config portal: By default the Nuki Hub will fallback to Wi-Fi and open the Wi-Fi configuration portal when the network connection fails. Enable this setting to disable this fallback. +- Connect to AP with the best signal in an environment with multiple APs with the same SSID: Enable to perform a scan for the Access Point with the best signal strenght for the specified SSID in a multi AP/Mesh environment. - RSSI Publish interval: Set to a positive integer to set the amount of seconds between updates to the maintenance/wifiRssi MQTT topic with the current Wi-Fi RSSI, set to -1 to disable, default 60. - Network Timeout until restart: Set to a positive integer to restart the Nuki Hub after the set amount of seconds has passed without an active connection to the MQTT broker, set to -1 to disable, default 60. - Restart on disconnect: Enable to restart the Nuki Hub after 60 seconds without a connection to a network. diff --git a/WebCfgServer.cpp b/WebCfgServer.cpp index 209df279..7819d2b1 100644 --- a/WebCfgServer.cpp +++ b/WebCfgServer.cpp @@ -371,6 +371,11 @@ bool WebCfgServer::processArgs(String& message) _preferences->putString(preference_mqtt_hass_cu_url, value); configChanged = true; } + else if(key == "BESTRSSI") + { + _preferences->putBool(preference_find_best_rssi, (value == "1")); + configChanged = true; + } else if(key == "HOSTNAME") { _preferences->putString(preference_hostname, value); @@ -955,6 +960,7 @@ void WebCfgServer::buildMqttConfigHtml(String &response) printTextarea(response, "MQTTKEY", "MQTT SSL Client Key (*, optional)", _preferences->getString(preference_mqtt_key).c_str(), TLS_KEY_MAX_SIZE, _network->encryptionSupported(), true); printDropDown(response, "NWHW", "Network hardware", String(_preferences->getInt(preference_network_hardware)), getNetworkDetectionOptions()); printCheckBox(response, "NWHWWIFIFB", "Disable fallback to Wi-Fi / Wi-Fi config portal", _preferences->getBool(preference_network_wifi_fallback_disabled)); + printCheckBox(response, "BESTRSSI", "Connect to AP with the best signal in an environment with multiple APs with the same SSID", _preferences->getBool(preference_find_best_rssi)); printInputField(response, "RSSI", "RSSI Publish interval (seconds; -1 to disable)", _preferences->getInt(preference_rssi_publish_interval), 6); printInputField(response, "NETTIMEOUT", "Network Timeout until restart (seconds; -1 to disable)", _preferences->getInt(preference_network_timeout), 5); printCheckBox(response, "RSTDISC", "Restart on disconnect", _preferences->getBool(preference_restart_on_disconnect)); @@ -1210,6 +1216,13 @@ void WebCfgServer::buildInfoHtml(String &response) response.concat("Network device: "); response.concat(_network->networkDeviceName()); response.concat("\n"); + + if(_network->networkDeviceName() == "Built-in Wi-Fi") + { + response.concat("BSSID of AP: "); + response.concat(_network->networkBSSID()); + response.concat("\n"); + } response.concat("Uptime: "); response.concat(millis() / 1000 / 60); diff --git a/lib/WiFiManager/WiFiManager.cpp b/lib/WiFiManager/WiFiManager.cpp index ca2f1da2..9369a5cd 100644 --- a/lib/WiFiManager/WiFiManager.cpp +++ b/lib/WiFiManager/WiFiManager.cpp @@ -1,9 +1,9 @@ /** * WiFiManager.cpp - * + * * WiFiManager, a library for the ESP8266/Arduino platform * for configuration of WiFi credentials using a Captive Portal - * + * * @author Creator tzapu * @author tablatronix * @version 0.0.0 @@ -11,6 +11,7 @@ */ #include "WiFiManager.h" +#include "hardware/WifiEthServer.h" #if defined(ESP8266) || defined(ESP32) @@ -82,10 +83,10 @@ void WiFiManagerParameter::setValue(const char *defaultValue, int length) { // Serial.println("cannot set value of this parameter"); return; } - + // if(strlen(defaultValue) > length){ // // Serial.println("defaultValue length mismatch"); - // // return false; //@todo bail + // // return false; //@todo bail // } if(_length != length || _value == nullptr){ @@ -93,17 +94,17 @@ void WiFiManagerParameter::setValue(const char *defaultValue, int length) { if( _value != nullptr){ delete[] _value; } - _value = new char[_length + 1]; + _value = new char[_length + 1]; } memset(_value, 0, _length + 1); // explicit null - + if (defaultValue != NULL) { strncpy(_value, defaultValue, _length); } } const char* WiFiManagerParameter::getValue() const { - // Serial.println(printf("Address of _value is %p\n", (void *)_value)); + // Serial.println(printf("Address of _value is %p\n", (void *)_value)); return _value; } const char* WiFiManagerParameter::getID() const { @@ -147,7 +148,7 @@ bool WiFiManager::addParameter(WiFiManagerParameter *p) { // init params if never malloc if(_params == NULL){ #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_DEV,F("allocating params bytes:"),_max_params * sizeof(WiFiManagerParameter*)); + DEBUG_WM(WM_DEBUG_DEV,F("allocating params bytes:"),_max_params * sizeof(WiFiManagerParameter*)); #endif _params = (WiFiManagerParameter**)malloc(_max_params * sizeof(WiFiManagerParameter*)); } @@ -157,7 +158,7 @@ bool WiFiManager::addParameter(WiFiManagerParameter *p) { _max_params += WIFI_MANAGER_MAX_PARAMS; #ifdef WM_DEBUG_LEVEL DEBUG_WM(WM_DEBUG_DEV,F("Updated _max_params:"),_max_params); - DEBUG_WM(WM_DEBUG_DEV,F("re-allocating params bytes:"),_max_params * sizeof(WiFiManagerParameter*)); + DEBUG_WM(WM_DEBUG_DEV,F("re-allocating params bytes:"),_max_params * sizeof(WiFiManagerParameter*)); #endif WiFiManagerParameter** new_params = (WiFiManagerParameter**)realloc(_params, _max_params * sizeof(WiFiManagerParameter*)); #ifdef WM_DEBUG_LEVEL @@ -177,7 +178,7 @@ bool WiFiManager::addParameter(WiFiManagerParameter *p) { _params[_paramsCount] = p; _paramsCount++; - + #ifdef WM_DEBUG_LEVEL DEBUG_WM(WM_DEBUG_VERBOSE,F("Added Parameter:"),p->getID()); #endif @@ -202,7 +203,7 @@ int WiFiManager::getParametersCount() { /** * -------------------------------------------------------------------------------- - * WiFiManager + * WiFiManager * -------------------------------------------------------------------------------- **/ @@ -211,8 +212,19 @@ WiFiManager::WiFiManager(Print& consolePort):_debugPort(consolePort){ WiFiManagerInit(); } +WiFiManager::WiFiManager(const char* user, const char* password) { + WiFiManagerInit(); + + if(strlen(user) > 0) + { + strcpy(_credUser, user); + strcpy(_credPassword, password); + _hasCredentials = true; + } +} + WiFiManager::WiFiManager() { - WiFiManagerInit(); + WiFiManagerInit(); } void WiFiManager::WiFiManagerInit(){ @@ -313,7 +325,7 @@ boolean WiFiManager::autoConnect(char const *apName, char const *apPassword) { #endif return false; } - + WiFiSetCountry(); #ifdef ESP32 @@ -333,7 +345,7 @@ boolean WiFiManager::autoConnect(char const *apName, char const *apPassword) { } #endif - // if already connected, or try stored connect + // if already connected, or try stored connect // @note @todo ESP32 has no autoconnect, so connectwifi will always be called unless user called begin etc before // @todo check if correct ssid == saved ssid when already connected bool connected = false; @@ -395,7 +407,7 @@ bool WiFiManager::setupHostname(bool restart){ DEBUG_WM(WM_DEBUG_DEV,F("No Hostname to set")); #endif return false; - } + } else { #ifdef WM_DEBUG_LEVEL DEBUG_WM(WM_DEBUG_VERBOSE,F("Setting Hostnames: "),_hostname); @@ -420,7 +432,7 @@ bool WiFiManager::setupHostname(bool restart){ // @note hostname must be set after STA_START // @note, this may have changed at some point, now it wont work, I have to set it before. // same for S2, must set it before mode(STA) now - + #ifdef WM_DEBUG_LEVEL DEBUG_WM(WM_DEBUG_VERBOSE,F("Setting WiFi hostname")); #endif @@ -432,7 +444,7 @@ bool WiFiManager::setupHostname(bool restart){ // if(err){ // log_e("Could not set hostname! %d", err); // return false; - // } + // } // #ifdef ESP32MDNS_H #ifdef WM_MDNS #ifdef WM_DEBUG_LEVEL @@ -492,7 +504,7 @@ bool WiFiManager::startAP(){ //@todo add callback here if needed to modify ap but cannot use setAPStaticIPConfig //@todo rework wifi channelsync as it will work unpredictably when not connected in sta - + int32_t channel = 0; if(_channelSync) channel = WiFi.channel(); else channel = _apChannel; @@ -508,26 +520,26 @@ bool WiFiManager::startAP(){ if (_apPassword != "") { if(channel>0){ ret = WiFi.softAP(_apName.c_str(), _apPassword.c_str(),channel,_apHidden); - } + } else{ ret = WiFi.softAP(_apName.c_str(), _apPassword.c_str(),1,_apHidden);//password option } } else { #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("AP has anonymous access!")); + DEBUG_WM(WM_DEBUG_VERBOSE,F("AP has anonymous access!")); #endif if(channel>0){ ret = WiFi.softAP(_apName.c_str(),"",channel,_apHidden); - } + } else{ ret = WiFi.softAP(_apName.c_str(),"",1,_apHidden); - } + } } if(_debugLevel >= WM_DEBUG_DEV) debugSoftAPConfig(); // @todo add softAP retry here to dela with unknown failures - + delay(500); // slight delay to make sure we get an AP IP #ifdef WM_DEBUG_LEVEL if(!ret) DEBUG_WM(WM_DEBUG_ERROR,F("[ERROR] There was a problem starting the AP")); @@ -569,7 +581,7 @@ void WiFiManager::startWebPortal() { void WiFiManager::stopWebPortal() { if(!configPortalActive && !webPortalActive) return; #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("Stopping Web Portal")); + DEBUG_WM(WM_DEBUG_VERBOSE,F("Stopping Web Portal")); #endif webPortalActive = false; shutdownConfigPortal(); @@ -601,7 +613,7 @@ boolean WiFiManager::configPortalHasTimeout(){ DEBUG_WM(F("config portal has timed out")); #endif return true; // timeout bail, else do debug logging - } + } else if(_debug && _debugLevel > 0) { // log timeout time remaining every 30s if((millis() - timer) > logintvl){ @@ -627,7 +639,7 @@ void WiFiManager::setupHTTPServer(){ #endif } - server.reset(new WM_WebServer(_httpPort)); + server.reset(new WM_WebServer(new WifiEthServer(80))); // This is not the safest way to reset the webserver, it can cause crashes on callbacks initilized before this and since its a shared pointer... if ( _webservercallback != NULL) { @@ -637,7 +649,7 @@ void WiFiManager::setupHTTPServer(){ _webservercallback(); // @CALLBACK } // @todo add a new callback maybe, after webserver started, callback cannot override handlers, but can grab them first - + /* Setup httpd callbacks, web pages: root, wifi config pages, SO captive portal detectors and not found. */ // G macro workaround for Uri() bug https://github.com/esp8266/Arduino/issues/7102 @@ -654,10 +666,10 @@ void WiFiManager::setupHTTPServer(){ server->on(WM_G(R_erase), std::bind(&WiFiManager::handleErase, this, false)); server->on(WM_G(R_status), std::bind(&WiFiManager::handleWiFiStatus, this)); server->onNotFound (std::bind(&WiFiManager::handleNotFound, this)); - + server->on(WM_G(R_update), std::bind(&WiFiManager::handleUpdate, this)); server->on(WM_G(R_updatedone), HTTP_POST, std::bind(&WiFiManager::handleUpdateDone, this), std::bind(&WiFiManager::handleUpdating, this)); - + server->begin(); // Web server start #ifdef WM_DEBUG_LEVEL DEBUG_WM(WM_DEBUG_VERBOSE,F("HTTP server started")); @@ -700,14 +712,14 @@ boolean WiFiManager::startConfigPortal(char const *apName, char const *apPasswo if(configPortalActive){ #ifdef WM_DEBUG_LEVEL DEBUG_WM(WM_DEBUG_VERBOSE,F("Starting Config Portal FAILED, is already running")); - #endif + #endif return false; } //setup AP _apName = apName; // @todo check valid apname ? _apPassword = apPassword; - + #ifdef WM_DEBUG_LEVEL DEBUG_WM(WM_DEBUG_VERBOSE,F("Starting Config Portal")); #endif @@ -715,10 +727,10 @@ boolean WiFiManager::startConfigPortal(char const *apName, char const *apPasswo if(_apName == "") _apName = getDefaultAPName(); if(!validApPassword()) return false; - + // HANDLE issues with STA connections, shutdown sta if not connected, or else this will hang channel scanning and softap will not respond if(_disableSTA || (!WiFi.isConnected() && _disableSTAConn)){ - // this fixes most ap problems, however, simply doing mode(WIFI_AP) does not work if sta connection is hanging, must `wifi_station_disconnect` + // this fixes most ap problems, however, simply doing mode(WIFI_AP) does not work if sta connection is hanging, must `wifi_station_disconnect` #ifdef WM_DISCONWORKAROUND WiFi.mode(WIFI_AP_STA); #endif @@ -762,9 +774,9 @@ boolean WiFiManager::startConfigPortal(char const *apName, char const *apPasswo #ifdef WM_DEBUG_LEVEL DEBUG_WM(WM_DEBUG_DEV,F("setupDNSD")); - #endif + #endif setupDNSD(); - + if(!_configPortalIsBlocking){ #ifdef WM_DEBUG_LEVEL @@ -775,7 +787,7 @@ boolean WiFiManager::startConfigPortal(char const *apName, char const *apPasswo } // enter blocking loop, waiting for config - + #ifdef WM_DEBUG_LEVEL DEBUG_WM(WM_DEBUG_VERBOSE,F("Config Portal Running, blocking, waiting for clients...")); if(_configPortalTimeout > 0) DEBUG_WM(WM_DEBUG_VERBOSE,F("Portal Timeout In"),(String)(_configPortalTimeout/1000) + (String)F(" seconds")); @@ -800,7 +812,7 @@ boolean WiFiManager::startConfigPortal(char const *apName, char const *apPasswo } state = processConfigPortal(); - + // status change, break // @todo what is this for, should be moved inside the processor // I think.. this is to detect autoconnect by esp in background, there are also many open issues about autoreconnect not working @@ -831,7 +843,7 @@ boolean WiFiManager::process(){ #if defined(WM_MDNS) && defined(ESP8266) MDNS.update(); #endif - + if(webPortalActive || (configPortalActive && !_configPortalIsBlocking)){ // if timed out or abort, break if(_allowExit && (configPortalHasTimeout() || abort)){ @@ -859,7 +871,7 @@ boolean WiFiManager::process(){ * [processConfigPortal description] * using esp wl_status enums as returns for now, should be fine * returns WL_IDLE_STATUS or WL_CONNECTED/WL_CONNECT_FAILED upon connect/save flag - * + * * @return {[type]} [description] */ uint8_t WiFiManager::processConfigPortal(){ @@ -913,7 +925,7 @@ uint8_t WiFiManager::processConfigPortal(){ DEBUG_WM(WM_DEBUG_ERROR,F("[ERROR] Connect to new AP Failed")); #endif } - + if (_shouldBreakAfterConfig) { // do save callback @@ -942,7 +954,7 @@ uint8_t WiFiManager::processConfigPortal(){ else{ #ifdef WM_DEBUG_LEVEL DEBUG_WM(WM_DEBUG_VERBOSE,F("Portal is non blocking - remaining open")); - #endif + #endif } } @@ -989,7 +1001,7 @@ bool WiFiManager::shutdownConfigPortal(){ bool ret = false; ret = WiFi.softAPdisconnect(false); - + #ifdef WM_DEBUG_LEVEL if(!ret)DEBUG_WM(WM_DEBUG_ERROR,F("[ERROR] disconnect configportal - softAPdisconnect FAILED")); DEBUG_WM(WM_DEBUG_VERBOSE,F("restoring usermode"),getModeString(_usermode)); @@ -1024,7 +1036,7 @@ uint8_t WiFiManager::connectWifi(String ssid, String pass, bool connect) { setSTAConfig(); //@todo catch failures in set_config - + // make sure sta is on before `begin` so it does not call enablesta->mode while persistent is ON ( which would save WM AP state to eeprom !) // WiFi.setAutoReconnect(false); if(_cleanConnect) WiFi_Disconnect(); // disconnect before begin, in case anything is hung, this causes a 2 seconds delay for connect @@ -1038,7 +1050,7 @@ uint8_t WiFiManager::connectWifi(String ssid, String pass, bool connect) { if(_connectRetries > 1){ if(_aggresiveReconn) delay(1000); // add idle time before recon #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("Connect Wifi, ATTEMPT #"),(String)retry+" of "+(String)_connectRetries); + DEBUG_WM(F("Connect Wifi, ATTEMPT #"),(String)retry+" of "+(String)_connectRetries); #endif } // if ssid argument provided connect to that @@ -1096,8 +1108,8 @@ uint8_t WiFiManager::connectWifi(String ssid, String pass, bool connect) { /** * connect to a new wifi ap * @since $dev - * @param String ssid - * @param String pass + * @param String ssid + * @param String pass * @return bool success * @return connect only save if false */ @@ -1110,7 +1122,65 @@ bool WiFiManager::wifiConnectNew(String ssid, String pass,bool connect){ #endif WiFi_enableSTA(true,storeSTAmode); // storeSTAmode will also toggle STA on in default opmode (persistent) if true (default) WiFi.persistent(true); - ret = WiFi.begin(ssid.c_str(), pass.c_str(), 0, NULL, connect); + + if (_findBestRSSI) { + #ifdef WM_DEBUG_LEVEL + DEBUG_WM(F("find best RSSI: TRUE")); + #endif + if (!_numNetworks) + WiFi_scanNetworks(); // scan in case this gets called before any scans + + int n = _numNetworks; + if (n == 0) { + #ifdef WM_DEBUG_LEVEL + DEBUG_WM(F("No networks found")); + #endif + } else { + #ifdef WM_DEBUG_LEVEL + DEBUG_WM(n, F("networks found")); + #endif + int bestConnection = -1; + // Find best RSSI AP for given SSID + for (int i = 0; i < n; i++) { + if (ssid == WiFi.SSID(i)) { + #ifdef WM_DEBUG_LEVEL + DEBUG_WM(String(F("SSID ")) + ssid + String(F(" found with RSSI: ")) + + String(WiFi.RSSI(i)) + String(F("(")) + + String(constrain((100.0 + WiFi.RSSI(i)) * 2, 0, 100)) + + String(F(" %) and BSSID: ")) + WiFi.BSSIDstr(i) + + String(F(" and channel: ")) + String(WiFi.channel(i))); + #endif + if (bestConnection == -1) { + bestConnection = i; + } else { + if (WiFi.RSSI(i) > WiFi.RSSI(bestConnection)) { + bestConnection = i; + } + } + } + } + if (bestConnection == -1) { + #ifdef WM_DEBUG_LEVEL + DEBUG_WM(F("No network found with SSID: "), ssid); + #endif + } else { + #ifdef WM_DEBUG_LEVEL + DEBUG_WM(String(F("Trying to connect to SSID ")) + ssid + String(F(" found with RSSI: ")) + + String(WiFi.RSSI(bestConnection)) + String(F("(")) + + String(constrain((100.0 + WiFi.RSSI(bestConnection)) * 2, 0, 100)) + + String(F(" %) and BSSID: ")) + WiFi.BSSIDstr(bestConnection) + + String(F(" and channel: ")) + String(WiFi.channel(bestConnection))); + #endif + ret = WiFi.begin(ssid.c_str(), pass.c_str(), 0, WiFi.BSSID(bestConnection), connect); + } + } + } else { + #ifdef WM_DEBUG_LEVEL + DEBUG_WM(F("find best RSSI: FALSE")); + #endif + ret = WiFi.begin(ssid.c_str(), pass.c_str(), 0, NULL, connect); + } + WiFi.persistent(false); #ifdef WM_DEBUG_LEVEL if(!ret) DEBUG_WM(WM_DEBUG_ERROR,F("[ERROR] wifi begin failed")); @@ -1126,11 +1196,14 @@ bool WiFiManager::wifiConnectNew(String ssid, String pass,bool connect){ bool WiFiManager::wifiConnectDefault(){ bool ret = false; + String ssid = WiFi_SSID(true); + String pass = WiFi_psk(true); + #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("Connecting to SAVED AP:"),WiFi_SSID(true)); - DEBUG_WM(WM_DEBUG_DEV,F("Using Password:"),WiFi_psk(true)); + DEBUG_WM(F("Connecting to SAVED AP:"),ssid); + DEBUG_WM(WM_DEBUG_DEV,F("Using Password:"),pass); #endif - + ret = WiFi_enableSTA(true,storeSTAmode); delay(500); // THIS DELAY ? @@ -1139,7 +1212,63 @@ bool WiFiManager::wifiConnectDefault(){ if(!ret) DEBUG_WM(WM_DEBUG_ERROR,F("[ERROR] wifi enableSta failed")); #endif - ret = WiFi.begin(); + if (_findBestRSSI) { + #ifdef WM_DEBUG_LEVEL + DEBUG_WM(F("find best RSSI: TRUE")); + #endif + if (!_numNetworks) + WiFi_scanNetworks(); // scan in case this gets called before any scans + + int n = _numNetworks; + if (n == 0) { + #ifdef WM_DEBUG_LEVEL + DEBUG_WM(F("No networks found")); + #endif + } else { + #ifdef WM_DEBUG_LEVEL + DEBUG_WM(n, F("networks found")); + #endif + int bestConnection = -1; + // Find best RSSI AP for given SSID + for (int i = 0; i < n; i++) { + if (ssid == WiFi.SSID(i)) { + #ifdef WM_DEBUG_LEVEL + DEBUG_WM(String(F("SSID ")) + ssid + String(F(" found with RSSI: ")) + + String(WiFi.RSSI(i)) + String(F("(")) + + String(constrain((100.0 + WiFi.RSSI(i)) * 2, 0, 100)) + + String(F(" %) and BSSID: ")) + WiFi.BSSIDstr(i) + + String(F(" and channel: ")) + String(WiFi.channel(i))); + #endif + if (bestConnection == -1) { + bestConnection = i; + } else { + if (WiFi.RSSI(i) > WiFi.RSSI(bestConnection)) { + bestConnection = i; + } + } + } + } + if (bestConnection == -1) { + #ifdef WM_DEBUG_LEVEL + DEBUG_WM(F("No network found with SSID: "), ssid); + #endif + } else { + #ifdef WM_DEBUG_LEVEL + DEBUG_WM(String(F("Trying to connect to SSID ")) + ssid + String(F(" found with RSSI: ")) + + String(WiFi.RSSI(bestConnection)) + String(F("(")) + + String(constrain((100.0 + WiFi.RSSI(bestConnection)) * 2, 0, 100)) + + String(F(" %) and BSSID: ")) + WiFi.BSSIDstr(bestConnection) + + String(F(" and channel: ")) + String(WiFi.channel(bestConnection))); + #endif + ret = WiFi.begin(ssid.c_str(), pass.c_str(), 0, WiFi.BSSID(bestConnection), true); + } + } + } else { + #ifdef WM_DEBUG_LEVEL + DEBUG_WM(F("find best RSSI: FALSE")); + #endif + ret = WiFi.begin(); + } #ifdef WM_DEBUG_LEVEL if(!ret) DEBUG_WM(WM_DEBUG_ERROR,F("[ERROR] wifi begin failed")); @@ -1156,7 +1285,7 @@ bool WiFiManager::wifiConnectDefault(){ */ bool WiFiManager::setSTAConfig(){ #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_DEV,F("STA static IP:"),_sta_static_ip); + DEBUG_WM(WM_DEBUG_DEV,F("STA static IP:"),_sta_static_ip); #endif bool ret = true; if (_sta_static_ip) { @@ -1180,7 +1309,7 @@ bool WiFiManager::setSTAConfig(){ if(!ret) DEBUG_WM(WM_DEBUG_ERROR,F("[ERROR] wifi config failed")); else DEBUG_WM(F("STA IP set:"),WiFi.localIP()); #endif - } + } else { #ifdef WM_DEBUG_LEVEL DEBUG_WM(WM_DEBUG_VERBOSE,F("setSTAConfig static ip not set, skipping")); @@ -1203,7 +1332,7 @@ void WiFiManager::updateConxResult(uint8_t status){ // if(_lastconxresult == WL_CONNECT_FAILED){ if(_lastconxresult == WL_CONNECT_FAILED || _lastconxresult == WL_DISCONNECTED){ #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_DEV,F("lastconxresulttmp:"),getWLStatusString(_lastconxresulttmp)); + DEBUG_WM(WM_DEBUG_DEV,F("lastconxresulttmp:"),getWLStatusString(_lastconxresulttmp)); #endif if(_lastconxresulttmp != WL_IDLE_STATUS){ _lastconxresult = _lastconxresulttmp; @@ -1214,10 +1343,10 @@ void WiFiManager::updateConxResult(uint8_t status){ #endif } - + uint8_t WiFiManager::waitForConnectResult() { #ifdef WM_DEBUG_LEVEL - if(_connectTimeout > 0) DEBUG_WM(WM_DEBUG_DEV,_connectTimeout,F("ms connectTimeout set")); + if(_connectTimeout > 0) DEBUG_WM(WM_DEBUG_DEV,_connectTimeout,F("ms connectTimeout set")); #endif return waitForConnectResult(_connectTimeout); } @@ -1240,7 +1369,7 @@ uint8_t WiFiManager::waitForConnectResult(uint32_t timeout) { DEBUG_WM(WM_DEBUG_VERBOSE,timeout,F("ms timeout, waiting for connect...")); #endif uint8_t status = WiFi.status(); - + while(millis() < timeoutmillis) { status = WiFi.status(); // @todo detect additional states, connect happens, then dhcp then get ip, there is some delay here, make sure not to timeout if waiting on IP @@ -1261,7 +1390,7 @@ void WiFiManager::startWPS() { #ifdef WM_DEBUG_LEVEL DEBUG_WM(F("START WPS")); #endif - #ifdef ESP8266 + #ifdef ESP8266 WiFi.beginWPSConfig(); #else // @todo @@ -1287,7 +1416,7 @@ String WiFiManager::getHTTPHead(String title){ } else { page += FPSTR(HTTP_HEAD_END); - } + } return page; } @@ -1296,7 +1425,7 @@ void WiFiManager::HTTPSend(const String &content){ server->send(200, FPSTR(HTTP_HEAD_CT), content); } -/** +/** * HTTPD handler for page requests */ void WiFiManager::handleRequest() { @@ -1312,7 +1441,7 @@ void WiFiManager::handleRequest() { // 2.3 NO AUTH available bool testauth = false; if(!testauth) return; - + DEBUG_WM(WM_DEBUG_DEV,F("DOING AUTH")); bool res = server->authenticate("admin","12345"); if(!res){ @@ -1323,13 +1452,16 @@ void WiFiManager::handleRequest() { } } -/** +/** * HTTPD CALLBACK root or redirect to captive portal */ void WiFiManager::handleRoot() { #ifdef WM_DEBUG_LEVEL DEBUG_WM(WM_DEBUG_VERBOSE,F("<- HTTP Root")); #endif + if (_hasCredentials && !server->authenticate(_credUser, _credPassword)) { + return server->requestAuthentication(); + } if (captivePortal()) return; // If captive portal redirect instead of displaying the page handleRequest(); String page = getHTTPHead(_title); // @token options @todo replace options with title @@ -1356,6 +1488,9 @@ void WiFiManager::handleWifi(boolean scan) { #ifdef WM_DEBUG_LEVEL DEBUG_WM(WM_DEBUG_VERBOSE,F("<- HTTP Wifi")); #endif + if (_hasCredentials && !server->authenticate(_credUser, _credPassword)) { + return server->requestAuthentication(); + } handleRequest(); String page = getHTTPHead(FPSTR(S_titlewifi)); // @token titlewifi if (scan) { @@ -1378,10 +1513,10 @@ void WiFiManager::handleWifi(boolean scan) { pitem.replace(FPSTR(T_p), WiFi_psk()); } else if(WiFi_psk() != ""){ - pitem.replace(FPSTR(T_p),FPSTR(S_passph)); + pitem.replace(FPSTR(T_p),FPSTR(S_passph)); } else { - pitem.replace(FPSTR(T_p),""); + pitem.replace(FPSTR(T_p),""); } page += pitem; @@ -1412,6 +1547,9 @@ void WiFiManager::handleParam(){ #ifdef WM_DEBUG_LEVEL DEBUG_WM(WM_DEBUG_VERBOSE,F("<- HTTP Param")); #endif + if (_hasCredentials && !server->authenticate(_credUser, _credPassword)) { + return server->requestAuthentication(); + } handleRequest(); String page = getHTTPHead(FPSTR(S_titleparam)); // @token titlewifi @@ -1436,7 +1574,7 @@ void WiFiManager::handleParam(){ String WiFiManager::getMenuOut(){ - String page; + String page; for(auto menuId :_menuIds ){ if((String)_menutokens[menuId] == "param" && _paramsCount == 0) continue; // no params set, omit params from menu, @todo this may be undesired by someone, use only menu to force? @@ -1460,7 +1598,7 @@ void WiFiManager::WiFi_scanComplete(int networksFound){ _lastscan = millis(); _numNetworks = networksFound; #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("WiFi Scan ASYNC completed"), "in "+(String)(_lastscan - _startscan)+" ms"); + DEBUG_WM(WM_DEBUG_VERBOSE,F("WiFi Scan ASYNC completed"), "in "+(String)(_lastscan - _startscan)+" ms"); DEBUG_WM(WM_DEBUG_VERBOSE,F("WiFi Scan ASYNC found:"),_numNetworks); #endif } @@ -1468,7 +1606,7 @@ void WiFiManager::WiFi_scanComplete(int networksFound){ bool WiFiManager::WiFi_scanNetworks(){ return WiFi_scanNetworks(false,false); } - + bool WiFiManager::WiFi_scanNetworks(unsigned int cachetime,bool async){ return WiFi_scanNetworks(millis()-_lastscan > cachetime,async); } @@ -1483,7 +1621,7 @@ bool WiFiManager::WiFi_scanNetworks(bool force,bool async){ #endif // if 0 networks, rescan @note this was a kludge, now disabling to test real cause ( maybe wifi not init etc) - // enable only if preload failed? + // enable only if preload failed? if(_numNetworks == 0 && _autoforcerescan){ DEBUG_WM(WM_DEBUG_DEV,"NO APs found forcing new scan"); force = true; @@ -1525,7 +1663,7 @@ bool WiFiManager::WiFi_scanNetworks(bool force,bool async){ #ifdef WM_DEBUG_LEVEL DEBUG_WM(WM_DEBUG_ERROR,F("[ERROR] scan failed")); #endif - } + } else if(res == WIFI_SCAN_RUNNING){ #ifdef WM_DEBUG_LEVEL DEBUG_WM(WM_DEBUG_ERROR,F("[ERROR] scan waiting")); @@ -1617,14 +1755,14 @@ String WiFiManager::WiFiManager::getScanItemOut(){ HTTP_ITEM_STR.replace("{h}",_scanDispOptions ? "" : "h"); HTTP_ITEM_STR.replace("{qi}", FPSTR(HTTP_ITEM_QI)); HTTP_ITEM_STR.replace("{h}",_scanDispOptions ? "h" : ""); - + // set token precheck flags bool tok_r = HTTP_ITEM_STR.indexOf(FPSTR(T_r)) > 0; bool tok_R = HTTP_ITEM_STR.indexOf(FPSTR(T_R)) > 0; bool tok_e = HTTP_ITEM_STR.indexOf(FPSTR(T_e)) > 0; bool tok_q = HTTP_ITEM_STR.indexOf(FPSTR(T_q)) > 0; bool tok_i = HTTP_ITEM_STR.indexOf(FPSTR(T_i)) > 0; - + //display networks in page for (int i = 0; i < n; i++) { if (indices[i] == -1) continue; // skip dups @@ -1684,7 +1822,7 @@ String WiFiManager::getIpForm(String id, String title, String value){ item.replace(FPSTR(T_l), F("15")); item.replace(FPSTR(T_v), value); item.replace(FPSTR(T_c), ""); - return item; + return item; } String WiFiManager::getStaticOut(){ @@ -1792,6 +1930,9 @@ void WiFiManager::handleWiFiStatus(){ #ifdef WM_DEBUG_LEVEL DEBUG_WM(WM_DEBUG_VERBOSE,F("<- HTTP WiFi status ")); #endif + if (_hasCredentials && !server->authenticate(_credUser, _credPassword)) { + return server->requestAuthentication(); + } handleRequest(); String page; // String page = "{\"result\":true,\"count\":1}"; @@ -1801,7 +1942,7 @@ void WiFiManager::handleWiFiStatus(){ HTTPSend(page); } -/** +/** * HTTPD CALLBACK save form and redirect to WLAN config page again */ void WiFiManager::handleWifiSave() { @@ -1809,6 +1950,9 @@ void WiFiManager::handleWifiSave() { DEBUG_WM(WM_DEBUG_VERBOSE,F("<- HTTP WiFi save ")); DEBUG_WM(WM_DEBUG_DEV,F("Method:"),server->method() == HTTP_GET ? (String)FPSTR(S_GET) : (String)FPSTR(S_POST)); #endif + if (_hasCredentials && !server->authenticate(_credUser, _credPassword)) { + return server->requestAuthentication(); + } handleRequest(); //SAVE/connect here @@ -1819,7 +1963,7 @@ void WiFiManager::handleWifiSave() { _ssid = WiFi_SSID(true); // password change, placeholder ssid, @todo compare pass to old?, confirm ssid is clean #ifdef WM_DEBUG_LEVEL DEBUG_WM(WM_DEBUG_VERBOSE,F("Detected WiFi password change")); - #endif + #endif } #ifdef WM_DEBUG_LEVEL @@ -1870,7 +2014,7 @@ void WiFiManager::handleWifiSave() { } if (_presavewificallback != NULL) { - _presavewificallback(); // @CALLBACK + _presavewificallback(); // @CALLBACK } if(_paramsInWifi) doParamSave(); @@ -1907,13 +2051,16 @@ void WiFiManager::handleParamSave() { #ifdef WM_DEBUG_LEVEL DEBUG_WM(WM_DEBUG_DEV,F("Method:"),server->method() == HTTP_GET ? (String)FPSTR(S_GET) : (String)FPSTR(S_POST)); #endif + if (_hasCredentials && !server->authenticate(_credUser, _credPassword)) { + return server->requestAuthentication(); + } handleRequest(); doParamSave(); String page = getHTTPHead(FPSTR(S_titleparamsaved)); // @token titleparamsaved page += FPSTR(HTTP_PARAMSAVED); - if(_showBack) page += FPSTR(HTTP_BACKBTN); + if(_showBack) page += FPSTR(HTTP_BACKBTN); page += FPSTR(HTTP_END); HTTPSend(page); @@ -1966,16 +2113,19 @@ void WiFiManager::doParamSave(){ if ( _saveparamscallback != NULL) { _saveparamscallback(); // @CALLBACK } - + } -/** +/** * HTTPD CALLBACK info page */ void WiFiManager::handleInfo() { #ifdef WM_DEBUG_LEVEL DEBUG_WM(WM_DEBUG_VERBOSE,F("<- HTTP Info")); #endif + if (_hasCredentials && !server->authenticate(_credUser, _credPassword)) { + return server->requestAuthentication(); + } handleRequest(); String page = getHTTPHead(FPSTR(S_titleinfo)); // @token titleinfo reportStatus(page); @@ -2026,11 +2176,11 @@ void WiFiManager::handleInfo() { F("chipid"), F("chiprev"), F("idesize"), - F("flashsize"), + F("flashsize"), F("cpufreq"), F("freeheap"), F("memsketch"), - F("memsmeter"), + F("memsmeter"), F("lastreset"), F("temp"), // F("hall"), @@ -2131,14 +2281,14 @@ String WiFiManager::getInfoData(String id){ p.replace(FPSTR(T_1),(String)ESP.getFlashChipRealSize()); #elif defined ESP32 p = FPSTR(HTTP_INFO_psrsize); - p.replace(FPSTR(T_1),(String)ESP.getPsramSize()); + p.replace(FPSTR(T_1),(String)ESP.getPsramSize()); #endif } else if(id==F("corever")){ #ifdef ESP8266 p = FPSTR(HTTP_INFO_corever); p.replace(FPSTR(T_1),(String)ESP.getCoreVersion()); - #endif + #endif } #ifdef ESP8266 else if(id==F("bootver")){ @@ -2277,7 +2427,7 @@ String WiFiManager::getInfoData(String id){ p.replace(FPSTR(T_1),(String)temperatureRead()); p.replace(FPSTR(T_2),(String)((temperatureRead()+32)*1.8f)); } - // else if(id==F("hall")){ + // else if(id==F("hall")){ // p = FPSTR(HTTP_INFO_hall); // p.replace(FPSTR(T_1),(String)hallRead()); // hall sensor reads can cause issues with adcs // } @@ -2314,13 +2464,16 @@ String WiFiManager::getInfoData(String id){ return p; } -/** +/** * HTTPD CALLBACK exit, closes configportal if blocking, if non blocking undefined */ void WiFiManager::handleExit() { #ifdef WM_DEBUG_LEVEL DEBUG_WM(WM_DEBUG_VERBOSE,F("<- HTTP Exit")); #endif + if (_hasCredentials && !server->authenticate(_credUser, _credPassword)) { + return server->requestAuthentication(); + } handleRequest(); String page = getHTTPHead(FPSTR(S_titleexit)); // @token titleexit page += FPSTR(S_exiting); // @token exiting @@ -2331,13 +2484,16 @@ void WiFiManager::handleExit() { abort = true; } -/** +/** * HTTPD CALLBACK reset page */ void WiFiManager::handleReset() { #ifdef WM_DEBUG_LEVEL DEBUG_WM(WM_DEBUG_VERBOSE,F("<- HTTP Reset")); #endif + if (_hasCredentials && !server->authenticate(_credUser, _credPassword)) { + return server->requestAuthentication(); + } handleRequest(); String page = getHTTPHead(FPSTR(S_titlereset)); //@token titlereset page += FPSTR(S_resetting); //@token resetting @@ -2352,7 +2508,7 @@ void WiFiManager::handleReset() { reboot(); } -/** +/** * HTTPD CALLBACK erase page */ @@ -2363,6 +2519,9 @@ void WiFiManager::handleErase(boolean opt) { #ifdef WM_DEBUG_LEVEL DEBUG_WM(WM_DEBUG_NOTIFY,F("<- HTTP Erase")); #endif + if (_hasCredentials && !server->authenticate(_credUser, _credPassword)) { + return server->requestAuthentication(); + } handleRequest(); String page = getHTTPHead(FPSTR(S_titleerase)); // @token titleerase @@ -2385,10 +2544,10 @@ void WiFiManager::handleErase(boolean opt) { DEBUG_WM(F("RESETTING ESP")); #endif reboot(); - } + } } -/** +/** * HTTPD CALLBACK 404 */ void WiFiManager::handleNotFound() { @@ -2418,14 +2577,14 @@ void WiFiManager::handleNotFound() { /** * HTTPD redirector - * Redirect to captive portal if we got a request for another domain. - * Return true in that case so the page handler do not try to handle the request again. + * Redirect to captive portal if we got a request for another domain. + * Return true in that case so the page handler do not try to handle the request again. */ boolean WiFiManager::captivePortal() { - + if(!_enableCaptivePortal || !configPortalActive) return false; // skip redirections if cp not enabled or not in ap mode - - String serverLoc = toStringIp(server->client().localIP()); + + String serverLoc = toStringIp(server->client()->localIP()); #ifdef WM_DEBUG_LEVEL DEBUG_WM(WM_DEBUG_DEV,"-> " + server->hostHeader()); @@ -2439,10 +2598,10 @@ boolean WiFiManager::captivePortal() { else serverLoc = toStringIp(WiFi.localIP()); } - + if(_httpPort != 80) serverLoc += ":" + (String)_httpPort; // add port if not default bool doredirect = serverLoc != server->hostHeader(); // redirect if hostheader not server ip, prevent redirect loops - + if (doredirect) { #ifdef WM_DEBUG_LEVEL DEBUG_WM(WM_DEBUG_VERBOSE,F("<- Request redirected to captive portal")); @@ -2450,7 +2609,7 @@ boolean WiFiManager::captivePortal() { #endif server->sendHeader(F("Location"), (String)F("http://") + serverLoc, true); // @HTTPHEAD send redirect server->send ( 302, FPSTR(HTTP_HEAD_CT2), ""); // Empty content inhibits Content-length header so we have to close the socket ourselves. - server->client().stop(); // Stop is needed because we sent no content length + server->client()->stop(); // Stop is needed because we sent no content length return true; } return false; @@ -2464,6 +2623,9 @@ void WiFiManager::stopCaptivePortal(){ // HTTPD CALLBACK, handle close, stop captive portal, if not enabled undefined void WiFiManager::handleClose(){ DEBUG_WM(WM_DEBUG_VERBOSE,F("Disabling Captive Portal")); + if (_hasCredentials && !server->authenticate(_credUser, _credPassword)) { + return server->requestAuthentication(); + } stopCaptivePortal(); #ifdef WM_DEBUG_LEVEL DEBUG_WM(WM_DEBUG_VERBOSE,F("<- HTTP close")); @@ -2511,7 +2673,7 @@ void WiFiManager::reportStatus(String &page){ else{ str.replace(FPSTR(T_c),""); str.replace(FPSTR(T_r),""); - } + } } } else { @@ -2537,7 +2699,7 @@ bool WiFiManager::stopConfigPortal(){ abort = true; return true; } - return shutdownConfigPortal(); + return shutdownConfigPortal(); } /** @@ -2552,7 +2714,7 @@ bool WiFiManager::disconnect(){ DEBUG_WM(WM_DEBUG_VERBOSE,F("Disconnecting: Not connected")); #endif return false; - } + } #ifdef WM_DEBUG_LEVEL DEBUG_WM(F("Disconnecting")); #endif @@ -2642,7 +2804,7 @@ void WiFiManager::resetSettings() { if (_resetcallback != NULL){ _resetcallback(); // @CALLBACK } - + #ifdef ESP32 WiFi.disconnect(true,true); #else @@ -2711,7 +2873,7 @@ void WiFiManager::setSaveConnectTimeout(unsigned long seconds) { } /** - * Set save portal connect on save option, + * Set save portal connect on save option, * if false, will only save credentials not connect * @access public * @param {[type]} bool connect [description] @@ -2803,7 +2965,7 @@ void WiFiManager::setBreakAfterConfig(boolean shouldBreak) { /** * setAPCallback, set a callback when softap is started - * @access public + * @access public * @param {[type]} void (*func)(WiFiManager* wminstance) */ void WiFiManager::setAPCallback( std::function func ) { @@ -2814,7 +2976,7 @@ void WiFiManager::setAPCallback( std::function func ) { * setWebServerCallback, set a callback after webserver is reset, and before routes are setup * if we set webserver handlers before wm, they are used and wm is not by esp webserver * on events cannot be overrided once set, and are not mutiples - * @access public + * @access public * @param {[type]} void (*func)(void) */ void WiFiManager::setWebServerCallback( std::function func ) { @@ -2991,6 +3153,14 @@ void WiFiManager::setCaptivePortalEnable(boolean enabled){ _enableCaptivePortal = enabled; } +/** + * toggle connecting to the best AP based on RSSI + * @param boolean enabled [false] + */ +void WiFiManager::setFindBestRSSI(boolean enabled) { + _findBestRSSI = enabled; +} + /** * toggle wifi autoreconnect policy * if enabled, then wifi will autoreconnect automatically always @@ -3205,9 +3375,9 @@ void WiFiManager::setMenu(std::vector& menu){ /** * set params as sperate page not in wifi - * NOT COMPATIBLE WITH setMenu! + * NOT COMPATIBLE WITH setMenu! * @todo scan menuids and insert param after wifi or something, same for ota - * @param bool enable + * @param bool enable * @since $dev */ void WiFiManager::setParamsPage(bool enable){ @@ -3252,13 +3422,13 @@ bool WiFiManager::getWiFiIsSaved(){ /** * getDefaultAPName * @since $dev - * @return string + * @return string */ String WiFiManager::getDefaultAPName(){ String hostString = String(WIFI_getChipId(),HEX); hostString.toUpperCase(); // char hostString[16] = {0}; - // sprintf(hostString, "%06X", ESP.getChipId()); + // sprintf(hostString, "%06X", ESP.getChipId()); return _wifissidprefix + "_" + hostString; } @@ -3322,7 +3492,7 @@ String WiFiManager::getWiFiSSID(bool persistent){ */ String WiFiManager::getWiFiPass(bool persistent){ return WiFi_psk(persistent); -} +} // DEBUG // @todo fix DEBUG_WM(0,0); @@ -3351,7 +3521,7 @@ void WiFiManager::DEBUG_WM(wm_debuglevel_t level,Generic text,Genericb textb) { // uint16_t max; // uint8_t frag; // ESP.getHeapStats(&free, &max, &frag);// @todo Does not exist in 2.3.0 - // _debugPort.printf("[MEM] free: %5d | max: %5d | frag: %3d%% \n", free, max, frag); + // _debugPort.printf("[MEM] free: %5d | max: %5d | frag: %3d%% \n", free, max, frag); #elif defined ESP32 // total_free_bytes; ///< Total free bytes in the heap. Equivalent to multi_free_heap_size(). // total_allocated_bytes; ///< Total bytes allocated to data in the heap. @@ -3365,7 +3535,7 @@ void WiFiManager::DEBUG_WM(wm_debuglevel_t level,Generic text,Genericb textb) { uint32_t free = info.total_free_bytes; uint16_t max = info.largest_free_block; uint8_t frag = 100 - (max * 100) / free; - _debugPort.printf("[MEM] free: %5d | max: %5d | frag: %3d%% \n", free, max, frag); + _debugPort.printf("[MEM] free: %5d | max: %5d | frag: %3d%% \n", free, max, frag); #endif } @@ -3385,7 +3555,7 @@ void WiFiManager::DEBUG_WM(wm_debuglevel_t level,Generic text,Genericb textb) { * @return {[type]} [description] */ void WiFiManager::debugSoftAPConfig(){ - + #ifdef ESP8266 softap_config config; wifi_softap_get_config(&config); @@ -3412,7 +3582,7 @@ void WiFiManager::debugSoftAPConfig(){ DEBUG_WM(F("ssid_hidden: "),config.ssid_hidden); DEBUG_WM(F("max_connection: "),config.max_connection); #endif - #if !defined(WM_NOCOUNTRY) + #if !defined(WM_NOCOUNTRY) #ifdef WM_DEBUG_LEVEL DEBUG_WM(F("country: "),(String)country.cc); #endif @@ -3577,7 +3747,7 @@ bool WiFiManager::WiFiSetCountry(){ esp_err_t err = ESP_OK; // @todo check if wifi is init, no idea how, doesnt seem to be exposed atm ( check again it might be now! ) if(WiFi.getMode() == WIFI_MODE_NULL){ - DEBUG_WM(WM_DEBUG_ERROR,"[ERROR] cannot set country, wifi not init"); + DEBUG_WM(WM_DEBUG_ERROR,"[ERROR] cannot set country, wifi not init"); } // exception if wifi not init! // Assumes that _wificountry is set to one of the supported country codes : "01"(world safe mode) "AT","AU","BE","BG","BR", // "CA","CH","CN","CY","CZ","DE","DK","EE","ES","FI","FR","GB","GR","HK","HR","HU", @@ -3602,7 +3772,7 @@ bool WiFiManager::WiFiSetCountry(){ } #endif ret = err == ESP_OK; - + #elif defined(ESP8266) && !defined(WM_NOCOUNTRY) // if(WiFi.getMode() == WIFI_OFF); // exception if wifi not init! if(_wificountry == "US") ret = wifi_set_country((wifi_country_t*)&WM_COUNTRY_US); @@ -3612,15 +3782,15 @@ bool WiFiManager::WiFiSetCountry(){ else DEBUG_WM(WM_DEBUG_ERROR,F("[ERROR] country code not found")); #endif #endif - + #ifdef WM_DEBUG_LEVEL if(ret) DEBUG_WM(WM_DEBUG_VERBOSE,F("[OK] esp_wifi_set_country: "),_wificountry); - else DEBUG_WM(WM_DEBUG_ERROR,F("[ERROR] esp_wifi_set_country failed")); + else DEBUG_WM(WM_DEBUG_ERROR,F("[ERROR] esp_wifi_set_country failed")); #endif return ret; } -// set mode ignores WiFi.persistent +// set mode ignores WiFi.persistent bool WiFiManager::WiFi_Mode(WiFiMode_t m,bool persistent) { bool ret; #ifdef ESP8266 @@ -3653,7 +3823,7 @@ bool WiFiManager::WiFi_Disconnect() { #endif ETS_UART_INTR_DISABLE(); // @todo possibly not needed ret = wifi_station_disconnect(); - ETS_UART_INTR_ENABLE(); + ETS_UART_INTR_ENABLE(); return ret; } #elif defined(ESP32) @@ -3709,7 +3879,7 @@ bool WiFiManager::WiFi_eraseConfig() { #endif #ifdef ESP8266 - #ifndef WM_FIXERASECONFIG + #ifndef WM_FIXERASECONFIG return ESP.eraseConfig(); #else // erase config BUG replacement @@ -3759,7 +3929,7 @@ String WiFiManager::WiFi_SSID(bool persistent) const{ memcpy(tmp, conf.ssid, sizeof(conf.ssid)); tmp[32] = 0; //nullterm in case of 32 char ssid return String(reinterpret_cast(tmp)); - + #elif defined(ESP32) // bool res = WiFi.wifiLowLevelInit(true); // @todo fix for S3, not found // wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); @@ -3792,7 +3962,7 @@ String WiFiManager::WiFi_psk(bool persistent) const { memcpy(tmp, conf.password, sizeof(conf.password)); tmp[64] = 0; //null term in case of 64 byte psk return String(reinterpret_cast(tmp)); - + #elif defined(ESP32) // only if wifi is init if(WiFiGenericClass::getMode() == WIFI_MODE_NULL){ @@ -3837,7 +4007,7 @@ String WiFiManager::WiFi_psk(bool persistent) const { if(info.wifi_sta_disconnected.reason == WIFI_REASON_ASSOC_FAIL){ if(_aggresiveReconn && _connectRetries<4) _connectRetries=4; DEBUG_WM(WM_DEBUG_VERBOSE,F("[EVENT] WIFI_REASON: AUTH FAIL")); - } + } #endif #ifdef esp32autoreconnect #ifdef WM_DEBUG_LEVEL @@ -3873,6 +4043,9 @@ void WiFiManager::handleUpdate() { #ifdef WM_DEBUG_LEVEL DEBUG_WM(WM_DEBUG_VERBOSE,F("<- Handle update")); #endif + if (_hasCredentials && !server->authenticate(_credUser, _credPassword)) { + return server->requestAuthentication(); + } if (captivePortal()) return; // If captive portal redirect instead of displaying the page String page = getHTTPHead(_title); // @token options String str = FPSTR(HTTP_ROOT_MAIN); @@ -3899,7 +4072,7 @@ void WiFiManager::handleUpdating(){ // combine route handlers into one callback and use argument or post checking instead of mutiple functions maybe, if POST process else server upload page? // [x] add upload checking, do we need too check file? // convert output to debugger if not moving to example - + // if (captivePortal()) return; // If captive portal redirect instead of displaying the page bool error = false; unsigned long _configPortalTimeoutSAV = _configPortalTimeout; // store cp timeout @@ -3913,7 +4086,7 @@ void WiFiManager::handleUpdating(){ if (upload.status == UPLOAD_FILE_START) { // if(_debug) Serial.setDebugOutput(true); uint32_t maxSketchSpace; - + // Use new callback for before OTA update if (_preotaupdatecallback != NULL) { _preotaupdatecallback(); // @CALLBACK @@ -3984,6 +4157,9 @@ void WiFiManager::handleUpdateDone() { DEBUG_WM(WM_DEBUG_VERBOSE, F("<- Handle update done")); // if (captivePortal()) return; // If captive portal redirect instead of displaying the page + if (_hasCredentials && !server->authenticate(_credUser, _credPassword)) { + return server->requestAuthentication(); + } String page = getHTTPHead(FPSTR(S_options)); // @token options String str = FPSTR(HTTP_ROOT_MAIN); str.replace(FPSTR(T_t),_title); diff --git a/lib/WiFiManager/WiFiManager.h b/lib/WiFiManager/WiFiManager.h index f911beb0..98f40d49 100644 --- a/lib/WiFiManager/WiFiManager.h +++ b/lib/WiFiManager/WiFiManager.h @@ -248,6 +248,7 @@ class WiFiManager { public: WiFiManager(Print& consolePort); + WiFiManager(const char* user, const char* password); WiFiManager(); ~WiFiManager(); void WiFiManagerInit(); @@ -411,6 +412,9 @@ class WiFiManager // if true (default) then stop the config portal from autoConnect when wifi is saved void setDisableConfigPortal(boolean enable); + + // if true then find the AP with the best RSSI for the given SSID + void setFindBestRSSI(boolean enabled); // set a custom hostname, sets sta and ap dhcp client id for esp32, and sta for esp8266 bool setHostname(const char * hostname); @@ -593,6 +597,7 @@ class WiFiManager boolean _showBack = false; // show back button boolean _enableConfigPortal = true; // FOR autoconnect - start config portal if autoconnect failed boolean _disableConfigPortal = true; // FOR autoconnect - stop config portal if cp wifi save + boolean _findBestRSSI = false; // find best rssi ap in wifiscan String _hostname = ""; // hostname for esp8266 for dhcp, and or MDNS const char* _customHeadElement = ""; // store custom head element html from user isnide @@ -836,6 +841,10 @@ class WiFiManager std::function _resetcallback; std::function _preotaupdatecallback; std::function _configportaltimeoutcallback; + + bool _hasCredentials = false; + char _credUser[31] = {0}; + char _credPassword[31] = {0}; template auto optionalIPFromString(T *obj, const char *s) -> decltype( obj->fromString(s) ) { diff --git a/networkDevices/EthLan8720Device.cpp b/networkDevices/EthLan8720Device.cpp index 92707437..d5018c96 100644 --- a/networkDevices/EthLan8720Device.cpp +++ b/networkDevices/EthLan8720Device.cpp @@ -143,3 +143,8 @@ String EthLan8720Device::localIP() { return ETH.localIP().toString(); } + +String EthLan8720Device::BSSIDstr() +{ + return ""; +} \ No newline at end of file diff --git a/networkDevices/EthLan8720Device.h b/networkDevices/EthLan8720Device.h index b26d1b01..ef4f5434 100644 --- a/networkDevices/EthLan8720Device.h +++ b/networkDevices/EthLan8720Device.h @@ -35,6 +35,7 @@ class EthLan8720Device : public NetworkDevice int8_t signalStrength() override; String localIP() override; + String BSSIDstr() override; private: void onDisconnected(); diff --git a/networkDevices/NetworkDevice.h b/networkDevices/NetworkDevice.h index 9721be4f..4cdc2403 100644 --- a/networkDevices/NetworkDevice.h +++ b/networkDevices/NetworkDevice.h @@ -33,6 +33,7 @@ class NetworkDevice virtual int8_t signalStrength() = 0; virtual String localIP() = 0; + virtual String BSSIDstr() = 0; virtual void mqttSetClientId(const char* clientId); virtual void mqttSetCleanSession(bool cleanSession); diff --git a/networkDevices/W5500Device.cpp b/networkDevices/W5500Device.cpp index 3b8720a4..445d7d63 100644 --- a/networkDevices/W5500Device.cpp +++ b/networkDevices/W5500Device.cpp @@ -225,3 +225,8 @@ String W5500Device::localIP() { return Ethernet.localIP().toString(); } + +String W5500Device::BSSIDstr() +{ + return ""; +} \ No newline at end of file diff --git a/networkDevices/W5500Device.h b/networkDevices/W5500Device.h index a3407f58..4c5db6a7 100644 --- a/networkDevices/W5500Device.h +++ b/networkDevices/W5500Device.h @@ -33,6 +33,7 @@ class W5500Device : public NetworkDevice int8_t signalStrength() override; String localIP() override; + String BSSIDstr() override; private: void resetDevice(); diff --git a/networkDevices/WifiDevice.cpp b/networkDevices/WifiDevice.cpp index e2d366bb..d6e7cc42 100644 --- a/networkDevices/WifiDevice.cpp +++ b/networkDevices/WifiDevice.cpp @@ -67,6 +67,7 @@ void WifiDevice::initialize() wm_menu.push_back("exit"); _wm.setEnableConfigPortal(_startAp || !_preferences->getBool(preference_network_wifi_fallback_disabled)); // reduced tieout if ESP is set to restart on disconnect + _wm.setFindBestRSSI(_preferences->getBool(preference_find_best_rssi)); _wm.setConfigPortalTimeout(_restartOnDisconnect ? 60 * 3 : 60 * 30); _wm.setShowInfoUpdate(false); _wm.setMenu(wm_menu); @@ -159,6 +160,11 @@ String WifiDevice::localIP() return WiFi.localIP().toString(); } +String WifiDevice::BSSIDstr() +{ + return WiFi.BSSIDstr(); +} + void WifiDevice::clearRtcInitVar(WiFiManager *) { memset(WiFiDevice_reconfdetect, 0, sizeof WiFiDevice_reconfdetect); diff --git a/networkDevices/WifiDevice.h b/networkDevices/WifiDevice.h index 0e5c1645..152fbc4d 100644 --- a/networkDevices/WifiDevice.h +++ b/networkDevices/WifiDevice.h @@ -25,6 +25,7 @@ class WifiDevice : public NetworkDevice int8_t signalStrength() override; String localIP() override; + String BSSIDstr() override; private: static void clearRtcInitVar(WiFiManager*);