diff --git a/.github/workflows/compile_examples.yaml b/.github/workflows/compile_examples.yaml index 315adb4a..46f67136 100644 --- a/.github/workflows/compile_examples.yaml +++ b/.github/workflows/compile_examples.yaml @@ -11,58 +11,58 @@ on: - '.github/workflows/compile_library.yml' jobs: - esp8266: - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - example: - - "examples/Parameters/SPIFFS/AutoConnectWithFSParametersAndCustomIP/AutoConnectWithFSParametersAndCustomIP.ino" - - "examples/Parameters/SPIFFS/AutoConnectWithFSParameters/AutoConnectWithFSParameters.ino" - - "examples/NonBlocking/OnDemandNonBlocking/onDemandNonBlocking.ino" - - "examples/NonBlocking/AutoConnectNonBlockingwParams/AutoConnectNonBlockingwParams.ino" - - "examples/NonBlocking/AutoConnectNonBlocking/AutoConnectNonBlocking.ino" - - "examples/Basic/Basic.ino" - - "examples/Super/OnDemandConfigPortal/OnDemandConfigPortal.ino" - - "examples/Advanced/Advanced.ino" - - "examples/Old_examples/AutoConnectWithStaticIP/AutoConnectWithStaticIP.ino" - - "examples/Old_examples/AutoConnectWithFeedback/AutoConnectWithFeedback.ino" - - "examples/Old_examples/AutoConnectWithReset/AutoConnectWithReset.ino" - - "examples/Old_examples/AutoConnectWithTimeout/AutoConnectWithTimeout.ino" - - "examples/ParamsChildClass/ParamsChildClass.ino" - - "examples/OnDemand/OnDemandConfigPortal/OnDemandConfigPortal.ino" - - "examples/OnDemand/OnDemandWebPortal/onDemandWebPortal.ino" + # esp8266: + # runs-on: ubuntu-latest + # strategy: + # fail-fast: false + # matrix: + # example: + # - "examples/Parameters/SPIFFS/AutoConnectWithFSParametersAndCustomIP/AutoConnectWithFSParametersAndCustomIP.ino" + # - "examples/Parameters/SPIFFS/AutoConnectWithFSParameters/AutoConnectWithFSParameters.ino" + # - "examples/NonBlocking/OnDemandNonBlocking/onDemandNonBlocking.ino" + # - "examples/NonBlocking/AutoConnectNonBlockingwParams/AutoConnectNonBlockingwParams.ino" + # - "examples/NonBlocking/AutoConnectNonBlocking/AutoConnectNonBlocking.ino" + # - "examples/Basic/Basic.ino" + # - "examples/Super/OnDemandConfigPortal/OnDemandConfigPortal.ino" + # - "examples/Advanced/Advanced.ino" + # - "examples/Old_examples/AutoConnectWithStaticIP/AutoConnectWithStaticIP.ino" + # - "examples/Old_examples/AutoConnectWithFeedback/AutoConnectWithFeedback.ino" + # - "examples/Old_examples/AutoConnectWithReset/AutoConnectWithReset.ino" + # - "examples/Old_examples/AutoConnectWithTimeout/AutoConnectWithTimeout.ino" + # - "examples/ParamsChildClass/ParamsChildClass.ino" + # - "examples/OnDemand/OnDemandConfigPortal/OnDemandConfigPortal.ino" + # - "examples/OnDemand/OnDemandWebPortal/onDemandWebPortal.ino" - steps: - - uses: actions/checkout@v2 - - name: Cache pip - uses: actions/cache@v2 - with: - path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} - restore-keys: ${{ runner.os }}-pip- - - name: Cache PlatformIO - uses: actions/cache@v2 - with: - path: ~/.platformio - key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }} - - name: Set up Python - uses: actions/setup-python@v2 - - name: Install PlatformIO - run: | - python -m pip install --upgrade pip - pip install --upgrade platformio - - name: Install 3rd party dependecies - run: | - pio lib -g install \ - https://github.com/tzapu/WiFiManager \ - https://github.com/bblanchon/ArduinoJson \ - https://github.com/knolleary/pubsubclient + # steps: + # - uses: actions/checkout@v2 + # - name: Cache pip + # uses: actions/cache@v2 + # with: + # path: ~/.cache/pip + # key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + # restore-keys: ${{ runner.os }}-pip- + # - name: Cache PlatformIO + # uses: actions/cache@v2 + # with: + # path: ~/.platformio + # key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }} + # - name: Set up Python + # uses: actions/setup-python@v2 + # - name: Install PlatformIO + # run: | + # python -m pip install --upgrade pip + # pip install --upgrade platformio + # - name: Install 3rd party dependecies + # run: | + # pio lib -g install \ + # file://. \ + # https://github.com/bblanchon/ArduinoJson \ + # https://github.com/knolleary/pubsubclient - - name: Run PlatformIO Examples - run: pio ci --board=nodemcuv2 - env: - PLATFORMIO_CI_SRC: ${{ matrix.example }} + # - name: Run PlatformIO Examples + # run: pio ci --board=nodemcuv2 + # env: + # PLATFORMIO_CI_SRC: ${{ matrix.example }} esp32: runs-on: ubuntu-latest @@ -105,14 +105,14 @@ jobs: run: | python -m pip install --upgrade pip pip install --upgrade platformio - - name: Install 3rd party dependecies + - name: Install 3rd party dependencies run: | pio lib -g install \ - https://github.com/tzapu/WiFiManager \ + file://. \ https://github.com/bblanchon/ArduinoJson \ https://github.com/knolleary/pubsubclient - name: Run PlatformIO Examples run: pio ci --board=esp32dev env: - PLATFORMIO_CI_SRC: ${{ matrix.example }} \ No newline at end of file + PLATFORMIO_CI_SRC: ${{ matrix.example }} diff --git a/.github/workflows/compile_library.yml b/.github/workflows/compile_library.yml index 5660b928..00a9bd5b 100644 --- a/.github/workflows/compile_library.yml +++ b/.github/workflows/compile_library.yml @@ -20,8 +20,8 @@ jobs: fail-fast: false matrix: board: - - "nodemcuv2" - "lolin32" + # - "nodemcuv2" steps: - uses: actions/checkout@v2 @@ -50,4 +50,4 @@ jobs: echo "void loop() {}" >> main.ino - name: Run PlatformIO - run: pio ci --board=${{ matrix.board }} . + run: pio ci --board=${{ matrix.board }} --lib="." . diff --git a/.gitignore b/.gitignore index 807b300c..4139bc4f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ .cache .pioenvs .piolibdeps +.idea .vscode !.vscode/extensions.json /platformio_override.ini diff --git a/README.md b/README.md index 2d6ab656..a6209ddf 100644 --- a/README.md +++ b/README.md @@ -8,25 +8,25 @@ Espressif ESPx WiFi Connection manager with fallback web configuration portal ![Release](https://img.shields.io/github/v/release/tzapu/WiFiManager?include_prereleases) -![Build CI Status](https://github.com/tzapu/WiFiManager/actions/workflows/compile_library.yml/badge.svg) +[![Build CI Status](https://github.com/tzapu/WiFiManager/actions/workflows/compile_library.yml/badge.svg)](https://github.com/tzapu/WiFiManager/actions/workflows/compile_library.yml) -![Build CI Status Examples](https://github.com/tzapu/WiFiManager/actions/workflows/compile_examples.yaml/badge.svg) +[![Build CI Status Examples](https://github.com/tzapu/WiFiManager/actions/workflows/compile_examples.yaml/badge.svg)](https://github.com/tzapu/WiFiManager/actions/workflows/compile_examples.yaml) [![arduino-library-badge](https://www.ardu-badge.com/badge/WiFiManager.svg?)](https://www.ardu-badge.com/WiFiManager) [![Build with PlatformIO](https://img.shields.io/badge/PlatformIO-Library-orange?)](https://platformio.org/lib/show/567/WiFiManager/installation) -![ESP8266](https://img.shields.io/badge/ESP-8266-000000.svg?longCache=true&style=flat&colorA=CC101F) +[![ESP8266](https://img.shields.io/badge/ESP-8266-000000.svg?longCache=true&style=flat&colorA=CC101F)](https://www.espressif.com/en/products/socs/esp8266) -![ESP32](https://img.shields.io/badge/ESP-32-000000.svg?longCache=true&style=flat&colorA=CC101F) -![ESP32](https://img.shields.io/badge/ESP-32S2-000000.svg?longCache=true&style=flat&colorA=CC101F) -![ESP32](https://img.shields.io/badge/ESP-32C3-000000.svg?longCache=true&style=flat&colorA=CC101F) +[![ESP32](https://img.shields.io/badge/ESP-32-000000.svg?longCache=true&style=flat&colorA=CC101F)](https://www.espressif.com/en/products/socs/esp32) +[![ESP32](https://img.shields.io/badge/ESP-32S2-000000.svg?longCache=true&style=flat&colorA=CC101F)](https://www.espressif.com/en/products/socs/esp32-s2) +[![ESP32](https://img.shields.io/badge/ESP-32C3-000000.svg?longCache=true&style=flat&colorA=CC101F)](https://www.espressif.com/en/products/socs/esp32-c3) Member to Member Support / Chat [![Join the chat at https://gitter.im/tablatronix/WiFiManager](https://badges.gitter.im/tablatronix/WiFiManager.svg)](https://gitter.im/tablatronix/WiFiManager?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -[![Discord](https://img.shields.io/badge/Discord-WiFiManager-%237289da.svg?logo=discord)](https://discord.gg/dkjJbHwC) +[![Discord](https://img.shields.io/badge/Discord-WiFiManager-%237289da.svg?logo=discord)](https://discord.gg/WgjVprfN) The configuration portal is of the captive variety, so on various devices it will present the configuration dialogue as soon as you connect to the created access point. @@ -171,8 +171,8 @@ Also see [examples](https://github.com/tzapu/WiFiManager/tree/master/examples). [PlatformIO](https://platformio.org/) is an emerging ecosystem for IoT development, and is an alternative to using the Arduino IDE. Install `WiFiManager` -using the platformio [library manager](https://docs.platformio.org/en/latest/librarymanager/index.htm) in your editor, -or using the [PlatformIO Core CLI](https://docs.platformio.org/en/latest/userguide/demo.html#library-manager), +using the platformio [library manager](https://docs.platformio.org/en/latest/librarymanager/index.html#librarymanager) in your editor, +or using the [PlatformIO Core CLI](https://docs.platformio.org/en/latest/core/index.html), or by adding it to your `platformio.ini` as shown below (recommended approach). The simplest way is to open the `platformio.ini` file at the root of your project, and `WifiManager` to the common top-level env @@ -229,7 +229,7 @@ IF YOU NEED TO SAVE PARAMETERS EVEN ON WIFI FAIL OR EMPTY, you must set `setBrea void setBreakAfterConfig(boolean shouldBreak); ``` -See [AutoConnectWithFSParameters Example](https://github.com/tzapu/WiFiManager/tree/master/examples/AutoConnectWithFSParameters). +See [AutoConnectWithFSParameters Example](https://github.com/tzapu/WiFiManager/tree/master/examples/Parameters/SPIFFS/AutoConnectWithFSParameters). ```cpp wifiManager.setSaveConfigCallback(saveConfigCallback); ``` @@ -269,7 +269,7 @@ void loop() { } } ``` -See example for a more complex version. [OnDemandConfigPortal](https://github.com/tzapu/WiFiManager/tree/master/examples/OnDemandConfigPortal) +See example for a more complex version. [OnDemandConfigPortal](https://github.com/tzapu/WiFiManager/tree/master/examples/OnDemand/OnDemandConfigPortal) #### Exiting from the Configuration Portal Normally, once entered, the configuration portal will continue to loop until WiFi credentials have been successfully entered or a timeout is reached. @@ -291,7 +291,7 @@ Usage scenario would be: ``` - if connection to AP fails, configuration portal starts and you can set /change the values (or use on demand configuration portal) -- once configuration is done and connection is established [save config callback]() is called +- once configuration is done and connection is established save config callback() is called - once WiFiManager returns control to your application, read and save the new values using the `WiFiManagerParameter` object. ```cpp mqtt_server = custom_mqtt_server.getValue(); @@ -299,7 +299,7 @@ Usage scenario would be: This feature is a lot more involved than all the others, so here are some examples to fully show how it is done. You should also take a look at adding custom HTML to your form. -- Save and load custom parameters to file system in json form [AutoConnectWithFSParameters](https://github.com/tzapu/WiFiManager/tree/master/examples/AutoConnectWithFSParameters) +- Save and load custom parameters to file system in json form [AutoConnectWithFSParameters](https://github.com/tzapu/WiFiManager/tree/master/examples/Parameters/SPIFFS/AutoConnectWithFSParameters) - *Save and load custom parameters to EEPROM* (not done yet) #### Custom IP Configuration diff --git a/WiFiManager.cpp b/WiFiManager.cpp index 2b9f5689..e3af4055 100644 --- a/WiFiManager.cpp +++ b/WiFiManager.cpp @@ -32,7 +32,7 @@ WiFiManagerParameter::WiFiManagerParameter(const char *custom) { _id = NULL; _label = NULL; _length = 1; - _value = NULL; + _value = nullptr; _labelPlacement = WFM_LABEL_DEFAULT; _customHTML = custom; } @@ -58,6 +58,8 @@ void WiFiManagerParameter::init(const char *id, const char *label, const char *d _label = label; _labelPlacement = labelPlacement; _customHTML = custom; + _length = 1; + _value = nullptr; setValue(defaultValue,length); } @@ -86,8 +88,14 @@ void WiFiManagerParameter::setValue(const char *defaultValue, int length) { // // return false; //@todo bail // } - _length = length; - _value = new char[_length + 1]; + if(_length != length){ + _length = length; + if( _value != nullptr){ + delete[] _value; + } + _value = new char[_length + 1]; + } + memset(_value, 0, _length + 1); // explicit null if (defaultValue != NULL) { @@ -199,7 +207,7 @@ int WiFiManager::getParametersCount() { **/ // constructors -WiFiManager::WiFiManager(Stream& consolePort):_debugPort(consolePort){ +WiFiManager::WiFiManager(Print& consolePort):_debugPort(consolePort){ WiFiManagerInit(); } @@ -226,7 +234,7 @@ WiFiManager::~WiFiManager() { _params = NULL; } - // @todo remove event + // remove event // WiFi.onEvent(std::bind(&WiFiManager::WiFiEvent,this,_1,_2)); #ifdef ESP32 WiFi.removeEvent(wm_event_id); @@ -272,12 +280,27 @@ boolean WiFiManager::autoConnect(char const *apName, char const *apPassword) { DEBUG_WM(F("AutoConnect")); #endif - // no getter for autoreconnectpolicy before this - // https://github.com/esp8266/Arduino/pull/4359 - // so we must force it on else, if not connectimeout then waitforconnectionresult gets stuck endless loop - WiFi_autoReconnect(); - - if(getWiFiIsSaved()){ + bool wifiIsSaved = getWiFiIsSaved(); + + #ifdef ESP32 + setupHostname(true); + + if(_hostname != ""){ + // disable wifi if already on + if(WiFi.getMode() & WIFI_STA){ + WiFi.mode(WIFI_OFF); + int timeout = millis()+1200; + // async loop for mode change + while(WiFi.getMode()!= WIFI_OFF && millis()= DEBUG_DEV) debugSoftAPConfig(); - // @todo add softAP retry here + // @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 @@ -517,6 +556,7 @@ bool WiFiManager::startAP(){ */ void WiFiManager::startWebPortal() { if(configPortalActive || webPortalActive) return; + connect = abort = false; setupConfigPortal(); webPortalActive = true; } @@ -577,6 +617,27 @@ boolean WiFiManager::configPortalHasTimeout(){ void WiFiManager::setupHTTPServer(){ + #ifdef WM_DEBUG_LEVEL + DEBUG_WM(F("Starting Web Portal")); + #endif + + if(_httpPort != 80) { + #ifdef WM_DEBUG_LEVEL + DEBUG_WM(DEBUG_VERBOSE,F("http server started with custom port: "),_httpPort); // @todo not showing ip + #endif + } + + server.reset(new WM_WebServer(_httpPort)); + // 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) { + #ifdef WM_DEBUG_LEVEL + DEBUG_WM(DEBUG_VERBOSE,F("[CB] _webservercallback calling")); + #endif + _webservercallback(); // @CALLBACK + } + // @todo add a new callback maybe, after webserver started, callback cannot override handlers, but can grab them first + server.reset(new WM_WebServer(_httpPort)); /* Setup httpd callbacks, web pages: root, wifi config pages, SO captive portal detectors and not found. */ @@ -600,24 +661,15 @@ void WiFiManager::setupHTTPServer(){ server->on(String(FPSTR(R_updatedone)).c_str(), HTTP_POST,std::bind(&WiFiManager::handleUpdateDone, this, _1), std::bind(&WiFiManager::handleUpdating, this, _1,_2,_3,_4,_5,_6)); } server->begin(); // Web server start -} - -void WiFiManager::teardownHTTPServer(){ + #ifdef WM_DEBUG_LEVEL + DEBUG_WM(DEBUG_VERBOSE,F("HTTP server started")); + #endif } - // setup dns and web servers void WiFiManager::setupDNSD(){ dnsServer.reset(new DNSServer()); - if(_httpPort != 80) { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(DEBUG_VERBOSE,F("http server starting with custom port: "),_httpPort); // @todo not showing ip - #endif - } - - setupHTTPServer(); - /* Setup the DNS server redirecting all the domains to the apIP */ dnsServer->setErrorReplyCode(DNSReplyCode::NoError); #ifdef WM_DEBUG_LEVEL @@ -628,29 +680,8 @@ void WiFiManager::setupDNSD(){ } void WiFiManager::setupConfigPortal() { - - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("Starting Web Portal")); - #endif - - // setup dns and web servers - server.reset(new WM_WebServer(_httpPort)); - - if(_httpPort != 80) { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(DEBUG_VERBOSE,F("http server started with custom port: "),_httpPort); // @todo not showing ip - #endif - } - - if ( _webservercallback != NULL) { - _webservercallback(); - } - // @todo add a new callback maybe, after webserver started, callback cannot override handlers, but can grab them first - - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(DEBUG_VERBOSE,F("HTTP server started")); - #endif - + setupHTTPServer(); + _lastscan = 0; // reset network scan cache if(_preloadwifiscan) WiFi_scanNetworks(true,true); // preload wifiscan , async } @@ -669,6 +700,13 @@ boolean WiFiManager::startConfigPortal() { boolean WiFiManager::startConfigPortal(char const *apName, char const *apPassword) { _begin(); + if(configPortalActive){ + #ifdef WM_DEBUG_LEVEL + DEBUG_WM(DEBUG_VERBOSE,F("Starting Config Portal FAILED, is already running")); + #endif + return false; + } + //setup AP _apName = apName; // @todo check valid apname ? _apPassword = apPassword; @@ -682,9 +720,11 @@ boolean WiFiManager::startConfigPortal(char const *apName, char const *apPasswo 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 - // @todo sometimes still cannot connect to AP for no known reason, no events in log either 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` + #ifdef WM_DISCONWORKAROUND + WiFi.mode(WIFI_AP_STA); + #endif WiFi_Disconnect(); WiFi_enableSTA(false); #ifdef WM_DEBUG_LEVEL @@ -692,8 +732,7 @@ boolean WiFiManager::startConfigPortal(char const *apName, char const *apPasswo #endif } else { - // @todo even if sta is connected, it is possible that softap connections will fail, IOS says "invalid password", windows says "cannot connect to this network" researching - WiFi_enableSTA(true); + // WiFi_enableSTA(true); } // init configportal globals to known states @@ -712,6 +751,9 @@ boolean WiFiManager::startConfigPortal(char const *apName, char const *apPasswo // do AP callback if set if ( _apcallback != NULL) { + #ifdef WM_DEBUG_LEVEL + DEBUG_WM(DEBUG_VERBOSE,F("[CB] _apcallback calling")); + #endif _apcallback(this); } @@ -729,7 +771,7 @@ boolean WiFiManager::startConfigPortal(char const *apName, char const *apPasswo if(!_configPortalIsBlocking){ #ifdef WM_DEBUG_LEVEL - DEBUG_WM(DEBUG_VERBOSE,F("Config Portal Running, non blocking/processing")); + DEBUG_WM(DEBUG_VERBOSE,F("Config Portal Running, non blocking (processing)")); if(_configPortalTimeout > 0) DEBUG_WM(DEBUG_VERBOSE,F("Portal Timeout In"),(String)(_configPortalTimeout/1000) + (String)F(" seconds")); #endif return result; // skip blocking loop @@ -751,6 +793,12 @@ boolean WiFiManager::startConfigPortal(char const *apName, char const *apPasswo #endif shutdownConfigPortal(); result = abort ? portalAbortResult : portalTimeoutResult; // false, false + if (_configportaltimeoutcallback != NULL) { + #ifdef WM_DEBUG_LEVEL + DEBUG_WM(DEBUG_VERBOSE,F("[CB] config portal timeout callback")); + #endif + _configportaltimeoutcallback(); // @CALLBACK + } break; } @@ -758,6 +806,7 @@ boolean WiFiManager::startConfigPortal(char const *apName, char const *apPasswo // 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 if(state != WL_IDLE_STATUS){ result = (state == WL_CONNECTED); // true if connected DEBUG_WM(DEBUG_DEV,F("configportal loop break")); @@ -786,28 +835,36 @@ boolean WiFiManager::process(){ MDNS.update(); #endif - if(configPortalActive && !_configPortalIsBlocking){ - if(configPortalHasTimeout()) shutdownConfigPortal(); - } - if(webPortalActive || (configPortalActive && !_configPortalIsBlocking)){ - // if timed out or abort, break if(_allowExit && (configPortalHasTimeout() || abort)){ #ifdef WM_DEBUG_LEVEL DEBUG_WM(DEBUG_DEV,F("process loop abort")); #endif + webPortalActive = false; shutdownConfigPortal(); + if (_configportaltimeoutcallback != NULL) { + #ifdef WM_DEBUG_LEVEL + DEBUG_WM(DEBUG_VERBOSE,F("[CB] config portal timeout callback")); + #endif + _configportaltimeoutcallback(); // @CALLBACK + } return false; } - uint8_t state = processConfigPortal(); + uint8_t state = processConfigPortal(); // state is WL_IDLE or WL_CONNECTED/FAILED return state == WL_CONNECTED; } return false; } -//using esp wl_status enums as returns for now, should be fine +/** + * [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(){ if(configPortalActive){ //DNS handler @@ -850,10 +907,13 @@ uint8_t WiFiManager::processConfigPortal(){ #endif if ( _savewificallback != NULL) { - _savewificallback(); + #ifdef WM_DEBUG_LEVEL + DEBUG_WM(DEBUG_VERBOSE,F("[CB] _savewificallback calling")); + #endif + _savewificallback(); // @CALLBACK } if(!_connectonsave) return WL_IDLE_STATUS; - shutdownConfigPortal(); + if(_disableConfigPortal) shutdownConfigPortal(); return WL_CONNECTED; // CONNECT SUCCESS } #ifdef WM_DEBUG_LEVEL @@ -868,11 +928,11 @@ uint8_t WiFiManager::processConfigPortal(){ // confirm or verify data was saved to make this more accurate callback if ( _savewificallback != NULL) { #ifdef WM_DEBUG_LEVEL - DEBUG_WM(DEBUG_VERBOSE,F("WiFi/Param save callback")); + DEBUG_WM(DEBUG_VERBOSE,F("[CB] WiFi/Param save callback")); #endif - _savewificallback(); + _savewificallback(); // @CALLBACK } - shutdownConfigPortal(); + if(_disableConfigPortal) shutdownConfigPortal(); return WL_CONNECT_FAILED; // CONNECT FAIL } else if(_configPortalIsBlocking){ @@ -919,6 +979,7 @@ bool WiFiManager::shutdownConfigPortal(){ #endif // @todo what is the proper way to shutdown and free the server up + // debug - many open issues aobut port not clearing for use with other servers #ifdef WM_ASYNCWEBSERVER server->end(); #else @@ -980,7 +1041,7 @@ uint8_t WiFiManager::connectWifi(String ssid, String pass, bool connect) { // 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 - // @todo find out what status is when this is needed, can we detect it and handle it, say in between states or idle_status + // @todo find out what status is when this is needed, can we detect it and handle it, say in between states or idle_status to avoid these // if retry without delay (via begin()), the IDF is still busy even after returning status // E (5130) wifi:sta is connecting, return error @@ -1394,6 +1455,10 @@ String WiFiManager::getMenuOut(){ 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? + if((String)_menutokens[menuId] == "custom" && _customMenuHTML!=NULL){ + page += _customMenuHTML; + continue; + } page += HTTP_PORTAL_MENU[menuId]; } @@ -1430,15 +1495,25 @@ bool WiFiManager::WiFi_scanNetworks(bool force,bool async){ // DEBUG_WM(DEBUG_DEV,_numNetworks,(millis()-_lastscan )); // DEBUG_WM(DEBUG_DEV,"scanNetworks force:",force == true); #endif - if(_numNetworks == 0){ - // DEBUG_WM(DEBUG_DEV,"NO APs found forcing new scan"); - // force = true; + + // 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? + if(_numNetworks == 0 && _autoforcerescan){ + DEBUG_WM(DEBUG_DEV,"NO APs found forcing new scan"); + force = true; + } + + // if scan is empty or stale (last scantime > _scancachetime), this avoids fast reloading wifi page and constant scan delayed page loads appearing to freeze. + if(!_lastscan || (_lastscan>0 && (millis()-_lastscan > _scancachetime))){ + force = true; } + // kludge for asn webserver, always be async - force = false; + //force = false; async = true; - force = _lastscan == 0; - if(force || (millis()-_lastscan > 60000)){ + //force = _lastscan == 0; + +if(force){ int8_t res; _startscan = millis(); @@ -1490,7 +1565,7 @@ bool WiFiManager::WiFi_scanNetworks(bool force,bool async){ DEBUG_WM(DEBUG_VERBOSE,F("WiFi Scan completed"), "in "+(String)(_lastscan - _startscan)+" ms"); #endif return true; - } + } else { #ifdef WM_DEBUG_LEVEL DEBUG_WM(DEBUG_VERBOSE,F("Scan is cached"),(String)(millis()-_lastscan )+" ms ago"); @@ -1588,7 +1663,8 @@ String WiFiManager::WiFiManager::getScanItemOut(){ // Serial.println(WiFi.BSSIDstr(indices[i])); continue; // No idea why I am seeing these, lets just skip them for now } - item.replace(FPSTR(T_v), htmlEntities(WiFi.SSID(indices[i]))); // ssid no encoding + item.replace(FPSTR(T_V), htmlEntities(WiFi.SSID(indices[i]))); // ssid no encoding + item.replace(FPSTR(T_v), htmlEntities(WiFi.SSID(indices[i]),true)); // ssid no encoding if(tok_e) item.replace(FPSTR(T_e), encryptionTypeStr(enc_type)); if(tok_r) item.replace(FPSTR(T_r), (String)rssiperc); // rssi percentage 0-100 if(tok_R) item.replace(FPSTR(T_R), (String)WiFi.RSSI(indices[i])); // rssi db @@ -1680,7 +1756,7 @@ String WiFiManager::getParamOut(){ char valLength[5]; for (int i = 0; i < _paramsCount; i++) { - Serial.println((String)_params[i]->_length); + //Serial.println((String)_params[i]->_length); if (_params[i] == NULL || _params[i]->_length == 0 || _params[i]->_length > 99999) { // try to detect param scope issues, doesnt always catch but works ok #ifdef WM_DEBUG_LEVEL @@ -1743,6 +1819,7 @@ void WiFiManager::handleWiFiStatus(AsyncWebServerRequest *request){ #ifdef WM_JSTEST page = FPSTR(HTTP_JS); #endif + HTTPSend(request,page); } /** @@ -1755,17 +1832,13 @@ void WiFiManager::handleWifiSave(AsyncWebServerRequest *request) { #endif handleRequest(); - // @todo use new callback for before paramsaves - if (!_paramsInWifi && _presavecallback != NULL) { - _presavecallback(); - } - //SAVE/connect here _ssid = request->arg(F("s")).c_str(); _pass = request->arg(F("p")).c_str(); if(_paramsInWifi) doParamSave(request); + // set static ips from server args if (request->arg(FPSTR(S_ip)) != "") { //_sta_static_ip.fromString(request->arg(FPSTR(S_ip)); String ip = request->arg(FPSTR(S_ip)); @@ -1796,6 +1869,12 @@ void WiFiManager::handleWifiSave(AsyncWebServerRequest *request) { #endif } + if (_presavewificallback != NULL) { + _presavewificallback(); // @CALLBACK + } + + if(_paramsInWifi) doParamSave(request); + String page; if(_ssid == ""){ @@ -1843,8 +1922,8 @@ void WiFiManager::handleParamSave(AsyncWebServerRequest *request) { void WiFiManager::doParamSave(AsyncWebServerRequest *request){ // @todo use new callback for before paramsaves, is this really needed? - if ( _presavecallback != NULL) { - _presavecallback(); + if ( _presaveparamscallback != NULL) { + _presaveparamscallback(); // @CALLBACK } //parameters @@ -1882,7 +1961,7 @@ void WiFiManager::doParamSave(AsyncWebServerRequest *request){ } if ( _saveparamscallback != NULL) { - _saveparamscallback(); + _saveparamscallback(); // @CALLBACK } } @@ -1903,7 +1982,7 @@ void WiFiManager::handleInfo(AsyncWebServerRequest *request) { //@todo convert to enum or refactor to strings //@todo wrap in build flag to remove all info code for memory saving #ifdef ESP8266 - infos = 29; + infos = 28; String infoids[] = { F("esphead"), F("uptime"), @@ -1911,7 +1990,6 @@ void WiFiManager::handleInfo(AsyncWebServerRequest *request) { F("fchipid"), F("idesize"), F("flashsize"), - F("sdkver"), F("corever"), F("bootver"), F("cpufreq"), @@ -1946,12 +2024,12 @@ void WiFiManager::handleInfo(AsyncWebServerRequest *request) { F("chiprev"), F("idesize"), F("flashsize"), - F("sdkver"), F("cpufreq"), F("freeheap"), F("memsketch"), F("memsmeter"), F("lastreset"), + F("temp"), F("wifihead"), F("conx"), F("stassid"), @@ -1967,14 +2045,21 @@ void WiFiManager::handleInfo(AsyncWebServerRequest *request) { F("apmac"), F("aphost"), F("apbssid") - // F("temp") }; #endif for(size_t i=0; i"); + + page += F("

About


"); + page += getInfoData("aboutver"); + page += getInfoData("aboutarduinover"); + page += getInfoData("aboutidfver"); + page += getInfoData("aboutdate"); + page += F("
"); + if(_showInfoUpdate){ page += HTTP_PORTAL_MENU[8]; page += HTTP_PORTAL_MENU[9]; @@ -1994,9 +2079,16 @@ void WiFiManager::handleInfo(AsyncWebServerRequest *request) { String WiFiManager::getInfoData(String id){ String p; - // @todo add WM versioning - if(id==F("esphead"))p = FPSTR(HTTP_INFO_esphead); - else if(id==F("wifihead"))p = FPSTR(HTTP_INFO_wifihead); + if(id==F("esphead")){ + p = FPSTR(HTTP_INFO_esphead); + #ifdef ESP32 + p.replace(FPSTR(T_1), (String)ESP.getChipModel()); + #endif + } + else if(id==F("wifihead")){ + p = FPSTR(HTTP_INFO_wifihead); + p.replace(FPSTR(T_1),getModeString(WiFi.getMode())); + } else if(id==F("uptime")){ // subject to rollover! p = FPSTR(HTTP_INFO_uptime); @@ -2038,15 +2130,6 @@ String WiFiManager::getInfoData(String id){ p.replace(FPSTR(T_1),(String)ESP.getPsramSize()); #endif } - else if(id==F("sdkver")){ - p = FPSTR(HTTP_INFO_sdkver); - #ifdef ESP32 - p.replace(FPSTR(T_1),(String)esp_get_idf_version()); - // p.replace(FPSTR(T_1),(String)system_get_sdk_version()); // deprecated - #else - p.replace(FPSTR(T_1),(String)system_get_sdk_version()); - #endif - } else if(id==F("corever")){ #ifdef ESP8266 p = FPSTR(HTTP_INFO_corever); @@ -2058,7 +2141,7 @@ String WiFiManager::getInfoData(String id){ p = FPSTR(HTTP_INFO_bootver); p.replace(FPSTR(T_1),(String)system_get_boot_version()); } - #endif + #endif else if(id==F("cpufreq")){ p = FPSTR(HTTP_INFO_cpufreq); p.replace(FPSTR(T_1),(String)ESP.getCpuFreqMHz()); @@ -2124,12 +2207,14 @@ String WiFiManager::getInfoData(String id){ p.replace(FPSTR(T_1),WiFi.softAPgetHostname()); } #endif + #ifndef WM_NOSOFTAPSSID #ifdef ESP8266 else if(id==F("apssid")){ p = FPSTR(HTTP_INFO_apssid); p.replace(FPSTR(T_1),htmlEntities(WiFi.softAPSSID())); } #endif + #endif else if(id==F("apbssid")){ p = FPSTR(HTTP_INFO_apbssid); p.replace(FPSTR(T_1),(String)WiFi.BSSIDstr()); @@ -2181,16 +2266,45 @@ String WiFiManager::getInfoData(String id){ p.replace(FPSTR(T_1),WiFi.getAutoConnect() ? FPSTR(S_enable) : FPSTR(S_disable)); } #endif - #ifdef ESP32 + #if defined(ESP32) && !defined(WM_NOTEMP) else if(id==F("temp")){ // temperature is not calibrated, varying large offsets are present, use for relative temp changes only p = FPSTR(HTTP_INFO_temp); p.replace(FPSTR(T_1),(String)temperatureRead()); p.replace(FPSTR(T_2),(String)((temperatureRead()+32)*1.8)); // p.replace(FPSTR(T_3),(String)hallRead()); - p.replace(FPSTR(T_3),"NA"); + // p.replace(FPSTR(T_3),"NA"); // removed hall sensor as reads can cause issues with adcs } #endif + else if(id==F("aboutver")){ + p = FPSTR(HTTP_INFO_aboutver); + p.replace(FPSTR(T_1),FPSTR(WM_VERSION_STR)); + } + else if(id==F("aboutarduinover")){ + #ifdef VER_ARDUINO_STR + p = FPSTR(HTTP_INFO_aboutarduino); + p.replace(FPSTR(T_1),String(VER_ARDUINO_STR)); + #endif + } + // else if(id==F("aboutidfver")){ + // #ifdef VER_IDF_STR + // p = FPSTR(HTTP_INFO_aboutidf); + // p.replace(FPSTR(T_1),String(VER_IDF_STR)); + // #endif + // } + else if(id==F("aboutsdkver")){ + p = FPSTR(HTTP_INFO_sdkver); + #ifdef ESP32 + p.replace(FPSTR(T_1),(String)esp_get_idf_version()); + // p.replace(FPSTR(T_1),(String)system_get_sdk_version()); // deprecated + #else + p.replace(FPSTR(T_1),(String)system_get_sdk_version()); + #endif + } + else if(id==F("aboutdate")){ + p = FPSTR(HTTP_INFO_aboutdate); + p.replace(FPSTR(T_1),String(__DATE__ " " __TIME__)); + } return p; } @@ -2264,7 +2378,6 @@ void WiFiManager::handleErase(AsyncWebServerRequest *request,bool opt = false) { } page += FPSTR(HTTP_END); - HTTPSend(request,page); if(ret){ @@ -2350,7 +2463,6 @@ void WiFiManager::handleClose(AsyncWebServerRequest *request){ AsyncWebServerResponse *response = request->beginResponse(200,FPSTR(HTTP_HEAD_CT), page); response->addHeader(F("Cache-Control"), F("no-cache, no-store, must-revalidate")); request->send(response); - } void WiFiManager::reportStatus(String &page){ @@ -2515,9 +2627,10 @@ void WiFiManager::resetSettings() { DEBUG_WM(F("resetSettings")); #endif WiFi_enableSTA(true,true); // must be sta to disconnect erase - - if (_resetcallback != NULL) - _resetcallback(); + delay(500); // ensure sta is enabled + if (_resetcallback != NULL){ + _resetcallback(); // @CALLBACK + } #ifdef ESP32 WiFi.disconnect(true,true); @@ -2699,6 +2812,15 @@ void WiFiManager::setSaveConfigCallback( std::function func ) { _savewificallback = func; } +/** + * setPreSaveConfigCallback, set a callback to fire before saving wifi or params + * @access public + * @param {[type]} void (*func)(void) + */ +void WiFiManager::setPreSaveConfigCallback( std::function func ) { + _presavewificallback = func; +} + /** * setConfigResetCallback, set a callback to occur when a resetSettings() occurs * @access public @@ -2718,12 +2840,12 @@ void WiFiManager::setSaveParamsCallback( std::function func ) { } /** - * setPreSaveConfigCallback, set a callback to fire before saving wifi or params + * setPreSaveParamsCallback, set a pre save params callback on params save prior to anything else * @access public * @param {[type]} void (*func)(void) */ -void WiFiManager::setPreSaveConfigCallback( std::function func ) { - _presavecallback = func; +void WiFiManager::setPreSaveParamsCallback( std::function func ) { + _presaveparamscallback = func; } /** @@ -2735,14 +2857,33 @@ void WiFiManager::setPreOtaUpdateCallback( std::function func ) { _preotaupdatecallback = func; } +/** + * setConfigPortalTimeoutCallback, set a callback to config portal is timeout + * @access public + * @param {[type]} void (*func)(void) + */ +void WiFiManager::setConfigPortalTimeoutCallback( std::function func ) { + _configportaltimeoutcallback = func; +} + /** * set custom head html - * custom element will be added to head, eg. new style tag etc. + * custom element will be added to head, eg. new meta,style,script tag etc. * @access public * @param char element */ -void WiFiManager::setCustomHeadElement(const char* element) { - _customHeadElement = element; +void WiFiManager::setCustomHeadElement(const char* html) { + _customHeadElement = html; +} + +/** + * set custom menu html + * custom element will be added to menu under custom menu item. + * @access public + * @param char element + */ +void WiFiManager::setCustomMenuHTML(const char* html) { + _customMenuHTML = html; } /** @@ -2763,8 +2904,8 @@ void WiFiManager::setRemoveDuplicateAPs(boolean removeDuplicates) { * @access public * @param boolean shoudlBlock [false] */ -void WiFiManager::setConfigPortalBlocking(boolean shoudlBlock) { - _configPortalIsBlocking = shoudlBlock; +void WiFiManager::setConfigPortalBlocking(boolean shouldBlock) { + _configPortalIsBlocking = shouldBlock; } /** @@ -2889,6 +3030,17 @@ void WiFiManager::setEnableConfigPortal(boolean enable) _enableConfigPortal = enable; } +/** + * toggle configportal if autoconnect failed + * if enabled, then the configportal will be de-activated on wifi save + * @since $dev + * @access public + * @param boolean enabled [true] + */ +void WiFiManager::setDisableConfigPortal(boolean enable) +{ + _disableConfigPortal = enable; +} /** * set the hostname (dhcp client id) @@ -3256,26 +3408,25 @@ void WiFiManager::debugPlatformInfo(){ #ifdef ESP8266 system_print_meminfo(); #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("getCoreVersion(): "),ESP.getCoreVersion()); - DEBUG_WM(F("system_get_sdk_version(): "),system_get_sdk_version()); - DEBUG_WM(F("system_get_boot_version():"),system_get_boot_version()); - DEBUG_WM(F("getFreeHeap(): "),(String)ESP.getFreeHeap()); + DEBUG_WM(F("[SYS] getCoreVersion(): "),ESP.getCoreVersion()); + DEBUG_WM(F("[SYS] system_get_sdk_version(): "),system_get_sdk_version()); + DEBUG_WM(F("[SYS] system_get_boot_version():"),system_get_boot_version()); + DEBUG_WM(F("[SYS] getFreeHeap(): "),(String)ESP.getFreeHeap()); #endif #elif defined(ESP32) #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("Free heap: "), ESP.getFreeHeap()); - DEBUG_WM(F("ESP SDK version: "), ESP.getSdkVersion()); + DEBUG_WM(F("[SYS] WM version: "), WM_VERSION_STR); + DEBUG_WM(F("[SYS] Arduino version: "), VER_ARDUINO_STR); + DEBUG_WM(F("[SYS] ESP SDK version: "), ESP.getSdkVersion()); + DEBUG_WM(F("[SYS] Free heap: "), ESP.getFreeHeap()); #endif - // esp_chip_info_t chipInfo; - // esp_chip_info(&chipInfo); + #ifdef WM_DEBUG_LEVEL - // DEBUG_WM("Chip Info: Model: ",chipInfo.model); - // DEBUG_WM("Chip Info: Cores: ",chipInfo.cores); - // DEBUG_WM("Chip Info: Rev: ",chipInfo.revision); - // DEBUG_WM(printf("Chip Info: Model: %d, cores: %d, revision: %d", chipInfo.model.c_str(), chipInfo.cores, chipInfo.revision)); - // DEBUG_WM("Chip Rev: ",(String)ESP.getChipRevision()); + DEBUG_WM(F("[SYS] Chip ID:"),WIFI_getChipId()); + DEBUG_WM(F("[SYS] Chip Model:"), ESP.getChipModel()); + DEBUG_WM(F("[SYS] Chip Cores:"), ESP.getChipCores()); + DEBUG_WM(F("[SYS] Chip Rev:"), ESP.getChipRevision()); #endif - // core version is not avail #endif } @@ -3315,14 +3466,14 @@ String WiFiManager::toStringIp(IPAddress ip) { boolean WiFiManager::validApPassword(){ // check that ap password is valid, return false - if (_apPassword.isEmpty()) _apPassword = ""; + if (_apPassword == NULL) _apPassword = ""; if (_apPassword != "") { if (_apPassword.length() < 8 || _apPassword.length() > 63) { #ifdef WM_DEBUG_LEVEL DEBUG_WM(F("AccessPoint set password is INVALID or <8 chars")); #endif _apPassword = ""; - return false; // @todo FATAL or fallback to empty ? + return false; // @todo FATAL or fallback to empty , currently fatal, fail secure. } #ifdef WM_DEBUG_LEVEL DEBUG_WM(DEBUG_VERBOSE,F("AccessPoint set password is VALID")); @@ -3338,10 +3489,12 @@ boolean WiFiManager::validApPassword(){ * @param string str string to replace entities * @return string encoded string */ -String WiFiManager::htmlEntities(String str) { +String WiFiManager::htmlEntities(String str, bool whitespace) { str.replace("&","&"); str.replace("<","<"); str.replace(">",">"); + str.replace("'","'"); + if(whitespace) str.replace(" "," "); // str.replace("-","–"); // str.replace("\"","""); // str.replace("/": "/"); @@ -3400,20 +3553,29 @@ bool WiFiManager::WiFiSetCountry(){ // ret = esp_wifi_set_bandwidth(WIFI_IF_AP,WIFI_BW_HT20); // WIFI_BW_HT40 #ifdef ESP32 esp_err_t err = ESP_OK; - // @todo check if wifi is init, no idea how, doesnt seem to be exposed atm ( might be now! ) + // @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(DEBUG_ERROR,"[ERROR] cannot set country, wifi not init"); } // exception if wifi not init! - else if(_wificountry == "US") err = esp_wifi_set_country(&WM_COUNTRY_US); - else if(_wificountry == "JP") err = esp_wifi_set_country(&WM_COUNTRY_JP); - else if(_wificountry == "CN") err = esp_wifi_set_country(&WM_COUNTRY_CN); + // 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", + // "IE","IN","IS","IT","JP","KR","LI","LT","LU","LV","MT","MX","NL","NO","NZ","PL","PT", + // "RO","SE","SI","SK","TW","US" + // If an invalid country code is passed, ESP_ERR_WIFI_ARG will be returned + // This also uses 802.11d mode, which matches the STA to the country code of the AP it connects to (meaning + // that the country code will be overridden if connecting to a "foreign" AP) + else { + #ifndef WM_NOCOUNTRY + err = esp_wifi_set_country_code(_wificountry.c_str(), true); + #else + DEBUG_WM(DEBUG_ERROR,"[ERROR] esp wifi set country is not available"); + err = true; + #endif + } #ifdef WM_DEBUG_LEVEL - else{ - DEBUG_WM(DEBUG_ERROR,"[ERROR] country code not found"); - } if(err){ if(err == ESP_ERR_WIFI_NOT_INIT) DEBUG_WM(DEBUG_ERROR,"[ERROR] ESP_ERR_WIFI_NOT_INIT"); - else if(err == ESP_ERR_INVALID_ARG) DEBUG_WM(DEBUG_ERROR,"[ERROR] ESP_ERR_WIFI_ARG"); + else if(err == ESP_ERR_INVALID_ARG) DEBUG_WM(DEBUG_ERROR,"[ERROR] ESP_ERR_WIFI_ARG (invalid country code)"); else if(err != ESP_OK)DEBUG_WM(DEBUG_ERROR,"[ERROR] unknown error",(String)err); } #endif @@ -3450,7 +3612,7 @@ bool WiFiManager::WiFi_Mode(WiFiMode_t m,bool persistent) { return ret; #elif defined(ESP32) if(persistent && esp32persistent) WiFi.persistent(true); - ret = WiFi.mode(m); // @todo persistent check persistant mode , NI + ret = WiFi.mode(m); // @todo persistent check persistant mode, was eventually added to esp lib, but have to add version checking probably if(persistent && esp32persistent) WiFi.persistent(false); return ret; #endif @@ -3467,7 +3629,7 @@ bool WiFiManager::WiFi_Disconnect() { #ifdef WM_DEBUG_LEVEL DEBUG_WM(DEBUG_DEV,F("WiFi station disconnect")); #endif - ETS_UART_INTR_DISABLE(); // @todo probably not needed + ETS_UART_INTR_DISABLE(); // @todo possibly not needed ret = wifi_station_disconnect(); ETS_UART_INTR_ENABLE(); return ret; @@ -3545,7 +3707,7 @@ bool WiFiManager::WiFi_eraseConfig() { bool ret; WiFi.mode(WIFI_AP_STA); // cannot erase if not in STA mode ! WiFi.persistent(true); - ret = WiFi.disconnect(true,true); + ret = WiFi.disconnect(true,true); // disconnect(bool wifioff, bool eraseap) delay(500); WiFi.persistent(false); return ret; @@ -3660,7 +3822,7 @@ String WiFiManager::WiFi_psk(bool persistent) const { WiFi.reconnect(); #endif } - else if(event == ARDUINO_EVENT_WIFI_SCAN_DONE){ + else if(event == ARDUINO_EVENT_WIFI_SCAN_DONE && _asyncScan){ uint16_t scans = WiFi.scanComplete(); WiFi_scanComplete(scans); } @@ -3677,7 +3839,7 @@ void WiFiManager::WiFi_autoReconnect(){ DEBUG_WM(DEBUG_VERBOSE,F("[ESP32] event handler enabled")); #endif using namespace std::placeholders; - wm_event_id = WiFi.onEvent(std::bind(&WiFiManager::WiFiEvent,this,_1,_2)); // @todo move, needed for async esp32 scannetworks + if(wm_event_id == 0) wm_event_id = WiFi.onEvent(std::bind(&WiFiManager::WiFiEvent,this,_1,_2)); // @todo move, needed for async esp32 scannetworks // } #endif } @@ -3715,7 +3877,7 @@ void WiFiManager::handleUpdating(AsyncWebServerRequest *request,String filename, // [x] add upload checking, do we need too check file? // convert output to debugger if not moving to example - // if (captivePortal(request)) return; skip check for speed + // if (captivePortal(request)) return; // If captive portal redirect instead of displaying the page bool error = false; unsigned long _configPortalTimeoutSAV = _configPortalTimeout; // store cp timeout _configPortalTimeout = 0; // disable timeout @@ -3723,12 +3885,12 @@ void WiFiManager::handleUpdating(AsyncWebServerRequest *request,String filename, // UPLOAD START if (!index) { - if(_debug) Serial.setDebugOutput(true); + // if(_debug) Serial.setDebugOutput(true); uint32_t maxSketchSpace; // Use new callback for before OTA update if (_preotaupdatecallback != NULL) { - _preotaupdatecallback(); + _preotaupdatecallback(); // @CALLBACK } #ifdef ESP8266 WiFiUDP::stopAll(); @@ -3741,9 +3903,14 @@ void WiFiManager::handleUpdating(AsyncWebServerRequest *request,String filename, #endif #ifdef WM_DEBUG_LEVEL - DEBUG_WM(DEBUG_VERBOSE,"Update file: ", filename.c_str()); + DEBUG_WM(DEBUG_VERBOSE,"[OTA] Update file: ", filename.c_str()); #endif + // Update.onProgress(THandlerFunction_Progress fn); + // Update.onProgress([](unsigned int progress, unsigned int total) { + // Serial.printf("Progress: %u%%\r", (progress / (total / 100))); + // }); + if (!Update.begin(maxSketchSpace)) { // start with max available size #ifdef WM_DEBUG_LEVEL DEBUG_WM(DEBUG_ERROR,F("[ERROR] OTA Update ERROR"), Update.getError()); @@ -3777,7 +3944,7 @@ void WiFiManager::handleUpdating(AsyncWebServerRequest *request,String filename, #endif } else { - Update.printError(Serial); + // Update.printError(Serial); error = true; } // Serial.setDebugOutput(false); @@ -3798,7 +3965,7 @@ void WiFiManager::handleUpdating(AsyncWebServerRequest *request,String filename, // upload and ota done, show status void WiFiManager::handleUpdateDone(AsyncWebServerRequest *request) { DEBUG_WM(DEBUG_VERBOSE, F("<- Handle update done")); - if (captivePortal(request)) return; // If captive portal redirect instead of displaying the page + // if (captivePortal(request)) return; // If captive portal redirect instead of displaying the page String page = getHTTPHead(FPSTR(S_options)); // @token options String str = FPSTR(HTTP_ROOT_MAIN); diff --git a/WiFiManager.h b/WiFiManager.h index 11541aeb..1eab88e6 100644 --- a/WiFiManager.h +++ b/WiFiManager.h @@ -39,6 +39,23 @@ #define WM_NOSOFTAPSSID // no softapssid() @todo shim #endif +// #ifdef CONFIG_IDF_TARGET_ESP32S2 +// #warning ESP32S2 +// #endif + +// #ifdef CONFIG_IDF_TARGET_ESP32C3 +// #warning ESP32C3 +// #endif + +// #ifdef CONFIG_IDF_TARGET_ESP32S3 +// #warning ESP32S3 +// #endif + +#if defined(ARDUINO_ESP32S3_DEV) || defined(CONFIG_IDF_TARGET_ESP32S3) +#warning "WM_NOTEMP" +#define WM_NOTEMP // disabled temp sensor, have to determine which chip we are on +#endif + // #include "soc/efuse_reg.h" // include to add efuse chip rev to info, getChipRevision() is almost always the same though, so not sure why it matters. // #define esp32autoreconnect // implement esp32 autoreconnect event listener kludge, @DEPRECATED @@ -47,6 +64,8 @@ #define WM_WEBSERVERSHIM // use webserver shim lib #define WM_ASYNCWEBSERVER // use async webserver +#define WM_G(string_literal) (String(FPSTR(string_literal)).c_str()) + #ifdef ESP8266 extern "C" { @@ -70,28 +89,6 @@ #elif defined(ESP32) - // #define STRING2(x) #x - // #define STRING(x) STRING2(x) - - // // #include - // #ifdef ESP_IDF_VERSION - // #pragma message "ESP_IDF_VERSION_MAJOR = " STRING(ESP_IDF_VERSION_MAJOR) - // #pragma message "ESP_IDF_VERSION_MINOR = " STRING(ESP_IDF_VERSION_MINOR) - // #pragma message "ESP_IDF_VERSION_PATCH = " STRING(ESP_IDF_VERSION_PATCH) - // #endif - - // // #include "esp_arduino_version.h" - // #ifdef ESP_ARDUINO_VERSION - // #pragma message "ESP_ARDUINO_VERSION_MAJOR = " STRING(ESP_ARDUINO_VERSION_MAJOR) - // #pragma message "ESP_ARDUINO_VERSION_MINOR = " STRING(ESP_ARDUINO_VERSION_MINOR) - // #pragma message "ESP_ARDUINO_VERSION_PATCH = " STRING(ESP_ARDUINO_VERSION_PATCH) - // #else - // #include - // #pragma message "ESP_ARDUINO_VERSION_GIT = " STRING(ARDUINO_ESP32_GIT_VER)// 0x46d5afb1 - // #pragma message "ESP_ARDUINO_VERSION_DESC = " STRING(ARDUINO_ESP32_GIT_DESC) // 1.0.6 - // // #pragma message "ESP_ARDUINO_VERSION_REL = " STRING(ARDUINO_ESP32_RELEASE) //"1_0_6" - // #endif - #include #include #include @@ -123,7 +120,21 @@ #endif #ifdef WM_RTC - #include + #ifdef ESP_IDF_VERSION_MAJOR // IDF 4+ + #if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4 + #include "esp32/rom/rtc.h" + #elif CONFIG_IDF_TARGET_ESP32S2 + #include "esp32s2/rom/rtc.h" + #elif CONFIG_IDF_TARGET_ESP32C3 + #include "esp32c3/rom/rtc.h" + #elif CONFIG_IDF_TARGET_ESP32S3 + #include "esp32s3/rom/rtc.h" + #else + #error Target CONFIG_IDF_TARGET is not supported + #endif + #else // ESP32 Before IDF 4.0 + #include "rom/rtc.h" + #endif #endif #else @@ -133,6 +144,46 @@ #include #include "strings_en.h" +// prep string concat vars +#define WM_STRING2(x) #x +#define WM_STRING(x) WM_STRING2(x) + + +// #include +#ifdef ESP_IDF_VERSION + // #pragma message "ESP_IDF_VERSION_MAJOR = " WM_STRING(ESP_IDF_VERSION_MAJOR) + // #pragma message "ESP_IDF_VERSION_MINOR = " WM_STRING(ESP_IDF_VERSION_MINOR) + // #pragma message "ESP_IDF_VERSION_PATCH = " WM_STRING(ESP_IDF_VERSION_PATCH) + #define VER_IDF_STR WM_STRING(ESP_IDF_VERSION_MAJOR) "." WM_STRING(ESP_IDF_VERSION_MINOR) "." WM_STRING(ESP_IDF_VERSION_PATCH) +#else + #define VER_IDF_STR "Unknown" +#endif + +#ifdef Arduino_h + #ifdef ESP32 + #include "esp_arduino_version.h" + #endif + // esp_get_idf_version + #ifdef ESP_ARDUINO_VERSION + // #pragma message "ESP_ARDUINO_VERSION_MAJOR = " WM_STRING(ESP_ARDUINO_VERSION_MAJOR) + // #pragma message "ESP_ARDUINO_VERSION_MINOR = " WM_STRING(ESP_ARDUINO_VERSION_MINOR) + // #pragma message "ESP_ARDUINO_VERSION_PATCH = " WM_STRING(ESP_ARDUINO_VERSION_PATCH) + #define VER_ARDUINO_STR WM_STRING(ESP_ARDUINO_VERSION_MAJOR) "." WM_STRING(ESP_ARDUINO_VERSION_MINOR) "." WM_STRING(ESP_ARDUINO_VERSION_PATCH) + #else + #include + // #pragma message "ESP_ARDUINO_VERSION_GIT = " WM_STRING(ARDUINO_ESP32_GIT_VER)// 0x46d5afb1 + // #pragma message "ESP_ARDUINO_VERSION_DESC = " WM_STRING(ARDUINO_ESP32_GIT_DESC) // 1.0.6 + // #pragma message "ESP_ARDUINO_VERSION_REL = " WM_STRING(ARDUINO_ESP32_RELEASE) //"1_0_6" + #define VER_ARDUINO_STR WM_STRING(ESP_ARDUINO_VERSION_MAJOR) "." WM_STRING(ESP_ARDUINO_VERSION_MINOR) "." WM_STRING(ESP_ARDUINO_VERSION_PATCH) + #endif +#else +#define VER_ARDUINO_STR "Unknown" +#endif + + +// #pragma message "VER_IDF_STR = " WM_STRING(VER_IDF_STR) +// #pragma message "VER_ARDUINO_STR = " WM_STRING(VER_ARDUINO_STR) + #ifndef WIFI_MANAGER_MAX_PARAMS #define WIFI_MANAGER_MAX_PARAMS 5 // params will autoincrement and realloc by this amount when max is reached #endif @@ -185,7 +236,7 @@ class WiFiManagerParameter { class WiFiManager { public: - WiFiManager(Stream& consolePort); + WiFiManager(Print& consolePort); WiFiManager(); ~WiFiManager(); void WiFiManagerInit(); @@ -250,15 +301,21 @@ class WiFiManager //called when wifi settings have been changed and connection was successful ( or setBreakAfterConfig(true) ) void setSaveConfigCallback( std::function func ); - //called when saving either params-in-wifi or params page - void setSaveParamsCallback( std::function func ); - //called when saving params-in-wifi or params before anything else happens (eg wifi) void setPreSaveConfigCallback( std::function func ); + //called when saving params before anything else happens + void setPreSaveParamsCallback( std::function func ); + + //called when saving either params-in-wifi or params page + void setSaveParamsCallback( std::function func ); + //called just before doing OTA update void setPreOtaUpdateCallback( std::function func ); + //called when config portal is timeout + void setConfigPortalTimeoutCallback( std::function func ); + //sets timeout before AP,webserver loop ends and exits even if there has been no setup. //useful for devices that failed to connect at some point and got stuck in a webserver loop //in seconds setConfigPortalTimeout is a new name for setTimeout, ! not used if setConfigPortalBlocking @@ -301,9 +358,12 @@ class WiFiManager // setConfigPortalTimeout is ignored in this mode, user is responsible for closing configportal void setConfigPortalBlocking(boolean shouldBlock); + //add custom html at inside for all pages + void setCustomHeadElement(const char* html); + //if this is set, customise style - void setCustomHeadElement(const char* element); - + void setCustomMenuHTML(const char* html); + //if this is true, remove duplicated Access Points - defaut true void setRemoveDuplicateAPs(boolean removeDuplicates); @@ -336,7 +396,10 @@ class WiFiManager // if true (default) then start the config portal from autoConnect if connection failed void setEnableConfigPortal(boolean enable); - + + // if true (default) then stop the config portal from autoConnect when wifi is saved + void setDisableConfigPortal(boolean enable); + // set a custom hostname, sets sta and ap dhcp client id for esp32, and sta for esp8266 bool setHostname(const char * hostname); bool setHostname(String hostname); @@ -393,7 +456,7 @@ class WiFiManager void debugPlatformInfo(); // helper for html - String htmlEntities(String str); + String htmlEntities(String str, bool whitespace = false); // set the country code for wifi settings, CN void setCountry(String cc); @@ -443,6 +506,7 @@ class WiFiManager private: + // vars std::vector _menuIds; std::vector _menuIdsParams = {"wifi","param","info","exit"}; std::vector _menuIdsUpdate = {"wifi","param","info","update","exit"}; @@ -457,9 +521,16 @@ class WiFiManager IPAddress _sta_static_sn; IPAddress _sta_static_dns; + unsigned long _configPortalStart = 0; // ms config portal start time (updated for timeouts) + unsigned long _webPortalAccessed = 0; // ms last web access time + uint8_t _lastconxresult = WL_IDLE_STATUS; // store last result when doing connect operations + int _numNetworks = 0; // init index for numnetworks wifiscans + unsigned long _lastscan = 0; // ms for timing wifi scans + unsigned long _startscan = 0; // ms for timing wifi scans + unsigned long _startconn = 0; // ms for timing wifi connects + // defaults const byte DNS_PORT = 53; - const byte HTTP_PORT = 80; String _apName = "no-net"; String _apPassword = ""; String _ssid = ""; // var temp ssid @@ -471,32 +542,27 @@ class WiFiManager unsigned long _configPortalTimeout = 0; // ms close config portal loop if set (depending on _cp/webClientCheck options) unsigned long _connectTimeout = 0; // ms stop trying to connect to ap if set unsigned long _saveTimeout = 0; // ms stop trying to connect to ap on saves, in case bugs in esp waitforconnectresult - unsigned long _configPortalStart = 0; // ms config portal start time (updated for timeouts) - unsigned long _webPortalAccessed = 0; // ms last web access time + WiFiMode_t _usermode = WIFI_STA; // Default user mode String _wifissidprefix = FPSTR(S_ssidpre); // auto apname prefix prefix+chipid - uint8_t _lastconxresult = WL_IDLE_STATUS; // store last result when doing connect operations - int _numNetworks = 0; // init index for numnetworks wifiscans - unsigned long _lastscan = 0; // ms for timing wifi scans - unsigned long _startscan = 0; // ms for timing wifi scans int _cpclosedelay = 2000; // delay before wifisave, prevents captive portal from closing to fast. bool _cleanConnect = false; // disconnect before connect in connectwifi, increases stability on connects bool _connectonsave = true; // connect to wifi when saving creds bool _disableSTA = false; // disable sta when starting ap, always bool _disableSTAConn = true; // disable sta when starting ap, if sta is not connected ( stability ) bool _channelSync = false; // use same wifi sta channel when starting ap - int32_t _apChannel = 0; // channel to use for ap + int32_t _apChannel = 0; // default channel to use for ap, 0 for auto bool _apHidden = false; // store softap hidden value uint16_t _httpPort = 80; // port for webserver // uint8_t _retryCount = 0; // counter for retries, probably not needed if synchronous uint8_t _connectRetries = 1; // number of sta connect retries, force reconnect, wait loop (connectimeout) does not always work and first disconnect bails - unsigned long _startconn = 0; // ms for timing wifi connects - bool _aggresiveReconn = false; // use an agrressive reconnect strategy, WILL delay conxs + bool _aggresiveReconn = true; // use an agrressive reconnect strategy, WILL delay conxs // on some conn failure modes will add delays and many retries to work around esp and ap bugs, ie, anti de-auth protections - bool _allowExit = true; // allow exit non blocking + // https://github.com/tzapu/WiFiManager/issues/1067 + bool _allowExit = true; // allow exit in nonblocking, else user exit/abort calls will be ignored including cptimeout #ifdef ESP32 - wifi_event_id_t wm_event_id; + wifi_event_id_t wm_event_id = 0; static uint8_t _lastconxresulttmp; // tmp var for esp32 callback #endif @@ -506,8 +572,8 @@ class WiFiManager // parameter options int _minimumQuality = -1; // filter wifiscan ap by this rssi - int _staShowStaticFields = 0; // ternary 1=always show static ip fields, 0=only if set, -1=never(cannot change ips via web!) - int _staShowDns = 0; // ternary 1=always show dns, 0=only if set, -1=never(cannot change dns via web!) + int _staShowStaticFields = 0; // ternary 1=always show static ip fields, 0=only if set, -1=never(cannot change ips via web!) + int _staShowDns = 0; // ternary 1=always show dns, 0=only if set, -1=never(cannot change dns via web!) boolean _removeDuplicateAPs = true; // remove dup aps from wifiscan boolean _showPassword = false; // show or hide saved password on wifi form, might be a security issue! boolean _shouldBreakAfterConfig = false; // stop configportal on save failure @@ -522,10 +588,12 @@ class WiFiManager boolean _showInfoErase = true; // info page erase button boolean _showInfoUpdate = true; // info page update button boolean _showBack = false; // show back button - boolean _enableConfigPortal = true; // use config portal if autoconnect failed + boolean _enableConfigPortal = true; // FOR autoconnect - start config portal if autoconnect failed + boolean _disableConfigPortal = true; // FOR autoconnect - stop config portal if cp wifi save String _hostname = ""; // hostname for esp8266 for dhcp, and or MDNS - const char* _customHeadElement = ""; // store custom head element html from user + const char* _customHeadElement = ""; // store custom head element html from user isnide + const char* _customMenuHTML = ""; // store custom head element html from user inside <> String _bodyClass = ""; // class to add to body String _title = FPSTR(S_brand); // app title - default WiFiManager @@ -534,6 +602,7 @@ class WiFiManager bool _rebootNeeded = false; // async reboot flag // wifiscan notes + // currently disabled due to issues with caching, sometimes first scan is empty esp32 wifi not init yet race, or portals hit server nonstop flood // The following are background wifi scanning optimizations // experimental to make scans faster, preload scans after starting cp, and visiting home page, so when you click wifi its already has your list // ideally we would add async and xhr here but I am holding off on js requirements atm @@ -542,10 +611,17 @@ class WiFiManager // async enables asyncronous scans, so they do not block anything // the refresh button bypasses cache // no aps found is problematic as scans are always going to want to run, leading to page load delays - boolean _preloadwifiscan = false; // preload wifiscan if true - boolean _asyncScan = false; // perform wifi network scan async - unsigned int _scancachetime = 30000; // ms cache time for background scans + // + // These settings really only make sense with _preloadwifiscan true + // but not limited to, we could run continuous background scans on various page hits, or xhr hits + // which would be better coupled with asyncscan + // atm preload is only done on root hit and startcp + boolean _preloadwifiscan = true; // preload wifiscan if true + unsigned int _scancachetime = 30000; // ms cache time for preload scans + boolean _asyncScan = true; // perform wifi network scan async + boolean _autoforcerescan = false; // automatically force rescan if scan networks is 0, ignoring cache + boolean _disableIpFields = false; // modify function of setShow_X_Fields(false), forces ip fields off instead of default show if set, eg. _staShowStaticFields=-1 String _wificountry = ""; // country code, @todo define in strings lang @@ -580,6 +656,7 @@ class WiFiManager void updateConxResult(uint8_t status); // webserver handlers + void HTTPSend(AsyncWebServerRequest *request, String page); void handleRoot(AsyncWebServerRequest *request); void handleWifi(AsyncWebServerRequest *request,bool scan); void handleWifiSave(AsyncWebServerRequest *request); @@ -594,9 +671,7 @@ class WiFiManager void handleWiFiStatus(AsyncWebServerRequest *request); void handleParamSave(AsyncWebServerRequest *request); void doParamSave(AsyncWebServerRequest *request); - void handleRequest(); - void HTTPSend(AsyncWebServerRequest *request, String page); boolean captivePortal(AsyncWebServerRequest *request); @@ -633,15 +708,28 @@ class WiFiManager #if defined(ESP_ARDUINO_VERSION) && defined(ESP_ARDUINO_VERSION_VAL) #define WM_ARDUINOVERCHECK ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(2, 0, 0) + #define WM_ARDUINOVERCHECK_204 ESP_ARDUINO_VERSION <= ESP_ARDUINO_VERSION_VAL(2, 0, 5) #ifdef WM_ARDUINOVERCHECK #define WM_ARDUINOEVENTS #else #define WM_NOSOFTAPSSID + #define WM_NOCOUNTRY + #endif + + #ifdef WM_ARDUINOVERCHECK_204 + #define WM_DISCONWORKAROUND #endif + #else + #define WM_NOCOUNTRY #endif + #ifdef WM_NOCOUNTRY + #warning "ESP32 set country unavailable" + #endif + + #ifdef WM_ARDUINOEVENTS void WiFiEvent(WiFiEvent_t event, arduino_event_info_t info); #else @@ -665,8 +753,8 @@ class WiFiManager String getInfoData(String id); // flags - boolean connect; - boolean abort; + boolean connect = false; + boolean abort = false; boolean reset = false; boolean configPortalActive = false; boolean webPortalActive = false; @@ -715,9 +803,9 @@ class WiFiManager // @todo use DEBUG_ESP_PORT ? #ifdef WM_DEBUG_PORT - Stream& _debugPort = WM_DEBUG_PORT; + Print& _debugPort = WM_DEBUG_PORT; #else - Stream& _debugPort = Serial; // debug output stream ref + Print& _debugPort = Serial; // debug output stream ref #endif template @@ -735,10 +823,12 @@ class WiFiManager std::function _apcallback; std::function _webservercallback; std::function _savewificallback; - std::function _presavecallback; + std::function _presavewificallback; + std::function _presaveparamscallback; std::function _saveparamscallback; std::function _resetcallback; std::function _preotaupdatecallback; + std::function _configportaltimeoutcallback; template auto optionalIPFromString(T *obj, const char *s) -> decltype( obj->fromString(s) ) { diff --git a/examples/Basic/Basic.ino b/examples/Basic/Basic.ino index 5f163041..bf1e263b 100644 --- a/examples/Basic/Basic.ino +++ b/examples/Basic/Basic.ino @@ -2,7 +2,7 @@ void setup() { - WiFi.mode(WIFI_STA); // explicitly set mode, esp defaults to STA+AP + // WiFi.mode(WIFI_STA); // explicitly set mode, esp defaults to STA+AP // it is a good practice to make sure your code sets wifi mode how you want it. // put your setup code here, to run once: @@ -13,7 +13,7 @@ void setup() { // reset settings - wipe stored credentials for testing // these are stored by the esp library - //wm.resetSettings(); + // wm.resetSettings(); // Automatically connect using saved credentials, // if connection fails, it starts an access point with the specified name ( "AutoConnectAP"), diff --git a/examples/NonBlocking/AutoConnectNonBlocking/AutoConnectNonBlocking.ino b/examples/NonBlocking/AutoConnectNonBlocking/AutoConnectNonBlocking.ino index 28c50249..ab523960 100644 --- a/examples/NonBlocking/AutoConnectNonBlocking/AutoConnectNonBlocking.ino +++ b/examples/NonBlocking/AutoConnectNonBlocking/AutoConnectNonBlocking.ino @@ -19,9 +19,6 @@ void setup() { else { Serial.println("Configportal running"); } - - wm.startConfigPortal(); - // wm.startWebPortal(); } void loop() { diff --git a/examples/Parameters/LittleFS/LittleFSParameters.ino b/examples/Parameters/LittleFS/LittleFSParameters.ino new file mode 100644 index 00000000..188b3c16 --- /dev/null +++ b/examples/Parameters/LittleFS/LittleFSParameters.ino @@ -0,0 +1,79 @@ +/** + * Basic example using LittleFS to store data + */ + +#include +#include +#include + +String readFile(fs::FS &fs, const char * path){ + Serial.printf("Reading file: %s\r\n", path); + File file = fs.open(path, "r"); + if(!file || file.isDirectory()){ + Serial.println("- empty file or failed to open file"); + return String(); + } + Serial.println("- read from file:"); + String fileContent; + while(file.available()){ + fileContent+=String((char)file.read()); + } + file.close(); + Serial.println(fileContent); + return fileContent; +} +void writeFile(fs::FS &fs, const char * path, const char * message){ + Serial.printf("Writing file: %s\r\n", path); + File file = fs.open(path, "w"); + if(!file){ + Serial.println("- failed to open file for writing"); + return; + } + if(file.print(message)){ + Serial.println("- file written"); + } else { + Serial.println("- write failed"); + } + file.close(); +} + +int data = 4; + +#include +#define TRIGGER_PIN 2 +int timeout = 120; // seconds to run for + +void setup() { +if (!LittleFS.begin()) { //to start littlefs +Serial.println("LittleFS mount failed"); +return; +} +data = readFile(LittleFS, "/data.txt").toInt(); +WiFi.mode(WIFI_STA); // explicitly set mode, esp defaults to STA+AP + // put your setup code here, to run once: + pinMode(TRIGGER_PIN, INPUT_PULLUP); + WiFiManager wm; + //wm.resetSettings(); + bool res; + res = wm.autoConnect("Setup"); + if(!res) { + Serial.println("Failed to connect"); + // ESP.restart(); + } + +} + +void loop() { +if ( digitalRead(TRIGGER_PIN) == LOW) { + WiFiManager wm; + //wm.resetSettings(); + wm.setConfigPortalTimeout(timeout); + if (!wm.startConfigPortal("Sharmander")) { + Serial.println("failed to connect and hit timeout"); + delay(3000); + ESP.restart(); + delay(5000); + } + Serial.println("connected...yeey :)"); +} +} \ No newline at end of file diff --git a/examples/Parameters/SPIFFS/AutoConnectWithFSParameters/AutoConnectWithFSParameters.ino b/examples/Parameters/SPIFFS/AutoConnectWithFSParameters/AutoConnectWithFSParameters.ino index 0e1cd0cf..a9c7b790 100644 --- a/examples/Parameters/SPIFFS/AutoConnectWithFSParameters/AutoConnectWithFSParameters.ino +++ b/examples/Parameters/SPIFFS/AutoConnectWithFSParameters/AutoConnectWithFSParameters.ino @@ -46,7 +46,7 @@ void setup() { configFile.readBytes(buf.get(), size); -#ifdef ARDUINOJSON_VERSION_MAJOR >= 6 + #if defined(ARDUINOJSON_VERSION_MAJOR) && ARDUINOJSON_VERSION_MAJOR >= 6 DynamicJsonDocument json(1024); auto deserializeError = deserializeJson(json, buf.get()); serializeJson(json, Serial); @@ -133,7 +133,7 @@ void setup() { //save the custom parameters to FS if (shouldSaveConfig) { Serial.println("saving config"); -#ifdef ARDUINOJSON_VERSION_MAJOR >= 6 + #if defined(ARDUINOJSON_VERSION_MAJOR) && ARDUINOJSON_VERSION_MAJOR >= 6 DynamicJsonDocument json(1024); #else DynamicJsonBuffer jsonBuffer; @@ -148,7 +148,7 @@ void setup() { Serial.println("failed to open config file for writing"); } -#ifdef ARDUINOJSON_VERSION_MAJOR >= 6 +#if defined(ARDUINOJSON_VERSION_MAJOR) && ARDUINOJSON_VERSION_MAJOR >= 6 serializeJson(json, Serial); serializeJson(json, configFile); #else diff --git a/examples/Parameters/SPIFFS/AutoConnectWithFSParametersAndCustomIP/AutoConnectWithFSParametersAndCustomIP.ino b/examples/Parameters/SPIFFS/AutoConnectWithFSParametersAndCustomIP/AutoConnectWithFSParametersAndCustomIP.ino index 27b9da92..63523e9b 100644 --- a/examples/Parameters/SPIFFS/AutoConnectWithFSParametersAndCustomIP/AutoConnectWithFSParametersAndCustomIP.ino +++ b/examples/Parameters/SPIFFS/AutoConnectWithFSParametersAndCustomIP/AutoConnectWithFSParametersAndCustomIP.ino @@ -51,7 +51,7 @@ void setup() { std::unique_ptr buf(new char[size]); configFile.readBytes(buf.get(), size); -#ifdef ARDUINOJSON_VERSION_MAJOR >= 6 + #if defined(ARDUINOJSON_VERSION_MAJOR) && ARDUINOJSON_VERSION_MAJOR >= 6 DynamicJsonDocument json(1024); auto deserializeError = deserializeJson(json, buf.get()); serializeJson(json, Serial); @@ -153,7 +153,7 @@ void setup() { //save the custom parameters to FS if (shouldSaveConfig) { Serial.println("saving config"); -#ifdef ARDUINOJSON_VERSION_MAJOR >= 6 + #if defined(ARDUINOJSON_VERSION_MAJOR) && ARDUINOJSON_VERSION_MAJOR >= 6 DynamicJsonDocument json(1024); #else DynamicJsonBuffer jsonBuffer; @@ -172,7 +172,7 @@ void setup() { Serial.println("failed to open config file for writing"); } -#ifdef ARDUINOJSON_VERSION_MAJOR >= 6 + #if defined(ARDUINOJSON_VERSION_MAJOR) && ARDUINOJSON_VERSION_MAJOR >= 6 serializeJson(json, Serial); serializeJson(json, configFile); #else diff --git a/examples/Super/OnDemandConfigPortal/OnDemandConfigPortal.ino b/examples/Super/OnDemandConfigPortal/OnDemandConfigPortal.ino index 9f712aec..ca74ddf8 100644 --- a/examples/Super/OnDemandConfigPortal/OnDemandConfigPortal.ino +++ b/examples/Super/OnDemandConfigPortal/OnDemandConfigPortal.ino @@ -34,6 +34,23 @@ bool WMISBLOCKING = true; // use blocking or non blocking mode, non global pa // char ssid[] = "*************"; // your network SSID (name) // char pass[] = "********"; // your network password + +//callbacks + // called after AP mode and config portal has started + // setAPCallback( std::function func ); + // called after webserver has started + // setWebServerCallback( std::function func ); + // called when settings reset have been triggered + // setConfigResetCallback( std::function func ); + // called when wifi settings have been changed and connection was successful ( or setBreakAfterConfig(true) ) + // setSaveConfigCallback( std::function func ); + // called when saving either params-in-wifi or params page + // setSaveParamsCallback( std::function func ); + // called when saving params-in-wifi or params before anything else happens (eg wifi) + // setPreSaveConfigCallback( std::function func ); + // called just before doing OTA update + // setPreOtaUpdateCallback( std::function func ); + void saveWifiCallback(){ Serial.println("[CALLBACK] saveCallback fired"); } @@ -55,7 +72,8 @@ void saveParamCallback(){ } void bindServerCallback(){ - // wm.server->on("/custom",handleRoute); + // wm.server->on("/custom",handleRoute); // this is now crashing esp32 for some reason + wm.server->on("/custom", HTTP_ANY, std::bind(handleRoute, wm, std::placeholders::_1, true)); // wm.server->on("/info",handleRoute); // you can override wm! } @@ -64,15 +82,19 @@ void handleRoute(){ // wm.server->send(200, "text/plain", "hello from user code"); } +void handlePreOtaUpdateCallback(){ + Update.onProgress([](unsigned int progress, unsigned int total) { + Serial.printf("CUSTOM Progress: %u%%\r", (progress / (total / 100))); + }); +} + void setup() { - WiFi.mode(WIFI_STA); // explicitly set mode, esp defaults to STA+AP + // WiFi.mode(WIFI_STA); // explicitly set mode, esp can default to STA+AP // put your setup code here, to run once: Serial.begin(115200); - // Serial1.begin(115200); - Serial.setDebugOutput(true); - delay(1000); + // Serial.setDebugOutput(true); Serial.println("\n Starting"); // WiFi.setSleepMode(WIFI_NONE_SLEEP); // disable sleep, can improve ap stability @@ -83,19 +105,23 @@ void setup() { Serial.println("[ERROR] TEST"); Serial.println("[INFORMATION] TEST"); + + wm.setDebugOutput(true); wm.debugPlatformInfo(); //reset settings - for testing // wm.resetSettings(); - // wm.erase(); + // wm.erase(); // setup some parameters + WiFiManagerParameter custom_html("

This Is Custom HTML

"); // only custom html WiFiManagerParameter custom_mqtt_server("server", "mqtt server", "", 40); WiFiManagerParameter custom_mqtt_port("port", "mqtt port", "", 6); WiFiManagerParameter custom_token("api_token", "api token", "", 16); WiFiManagerParameter custom_tokenb("invalid token", "invalid token", "", 0); // id is invalid, cannot contain spaces WiFiManagerParameter custom_ipaddress("input_ip", "input IP", "", 15,"pattern='\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}'"); // custom input attrs (ip mask) + WiFiManagerParameter custom_input_type("input_pwd", "input pass", "", 15,"type='password'"); // custom input attrs (ip mask) const char _customHtml_checkbox[] = "type=\"checkbox\""; WiFiManagerParameter custom_checkbox("my_checkbox", "My Checkbox", "T", 2, _customHtml_checkbox,WFM_LABEL_AFTER); @@ -127,6 +153,7 @@ void setup() { wm.setWebServerCallback(bindServerCallback); wm.setSaveConfigCallback(saveWifiCallback); wm.setSaveParamsCallback(saveParamCallback); + wm.setPreOtaUpdateCallback(handlePreOtaUpdateCallback); // add all your parameters here wm.addParameter(&custom_html); @@ -136,6 +163,7 @@ void setup() { wm.addParameter(&custom_tokenb); wm.addParameter(&custom_ipaddress); wm.addParameter(&custom_checkbox); + wm.addParameter(&custom_input_type); wm.addParameter(&custom_html_inputs); @@ -143,6 +171,24 @@ void setup() { custom_html.setValue("test",4); custom_token.setValue("test",4); + // const char* icon = " + // "; + + + // set custom html head content , inside + // examples of favicon, or meta tags etc + // const char* headhtml = ""; + // const char* headhtml = ""; + // wm.setCustomHeadElement(headhtml); + + // set custom html menu content , inside menu item "custom", see setMenu() + const char* menuhtml = "

\n"; + wm.setCustomMenuHTML(menuhtml); + // invert theme, dark wm.setDarkMode(true); @@ -155,7 +201,7 @@ void setup() { wm.setMenu(menu,9); // custom menu array must provide length */ - std::vector menu = {"wifi","wifinoscan","info","param","close","sep","erase","update","restart","exit"}; + std::vector menu = {"wifi","wifinoscan","info","param","custom","close","sep","erase","update","restart","exit"}; wm.setMenu(menu); // custom menu, pass vector // wm.setParamsPage(true); // move params to seperate page, not wifi, do not combine with setmenu! @@ -172,11 +218,13 @@ void setup() { // set country // setting wifi country seems to improve OSX soft ap connectivity, // may help others as well, default is CN which has different channels - wm.setCountry("US"); + + // wm.setCountry("US"); // crashing on esp32 2.0 // set Hostname - wm.setHostname(("WM_"+wm.getDefaultAPName()).c_str()); + wm.setHostname(("WM_"+wm.getDefaultAPName()).c_str()); + // wm.setHostname("WM_RANDO_1234"); // set custom channel // wm.setWiFiAPChannel(13); @@ -208,7 +256,7 @@ void setup() { // wm.setConnectRetries(2); // connect after portal save toggle - wm.setSaveConnect(false); // do not connect, only save + // wm.setSaveConnect(false); // do not connect, only save // show static ip fields // wm.setShowStaticFields(true); @@ -233,6 +281,9 @@ void setup() { wifiInfo(); + // to preload autoconnect with credentials + // wm.preloadWiFi("ssid","password"); + if(!wm.autoConnect("WM_AutoConnectAP","12345678")) { Serial.println("failed to connect and hit timeout"); } @@ -241,7 +292,7 @@ void setup() { delay(1000); Serial.println("TEST_CP ENABLED"); wm.setConfigPortalTimeout(TESP_CP_TIMEOUT); - wm.startConfigPortal("WM_ConnectAP"); + wm.startConfigPortal("WM_ConnectAP","12345678"); } else { //if you get here you have connected to the WiFi @@ -258,10 +309,13 @@ void setup() { } void wifiInfo(){ - WiFi.printDiag(Serial); - Serial.println("SAVED: " + (String)wm.getWiFiIsSaved() ? "YES" : "NO"); - Serial.println("SSID: " + (String)wm.getWiFiSSID()); - Serial.println("PASS: " + (String)wm.getWiFiPass()); + // can contain gargbage on esp32 if wifi is not ready yet + Serial.println("[WIFI] WIFI INFO DEBUG"); + // WiFi.printDiag(Serial); + Serial.println("[WIFI] SAVED: " + (String)(wm.getWiFiIsSaved() ? "YES" : "NO")); + Serial.println("[WIFI] SSID: " + (String)wm.getWiFiSSID()); + Serial.println("[WIFI] PASS: " + (String)wm.getWiFiPass()); + Serial.println("[WIFI] HOSTNAME: " + (String)WiFi.getHostname()); } void loop() { @@ -334,7 +388,7 @@ void getTime() { } Serial.println(""); struct tm timeinfo; - gmtime_r(&now, &timeinfo); // @NOTE doesnt work in esp2.3.0 + gmtime_r(&now, &timeinfo); Serial.print("Current time: "); Serial.print(asctime(&timeinfo)); } diff --git a/examples/Tests/wifi_softap/wifi_softap.ino b/examples/Tests/wifi_softap/wifi_softap.ino new file mode 100644 index 00000000..aa3e45c8 --- /dev/null +++ b/examples/Tests/wifi_softap/wifi_softap.ino @@ -0,0 +1,51 @@ +// wifi_basic.ino + +#include +#include + +// #define NVSERASE +#ifdef NVSERASE +#include +#include +#endif + +void setup(){ + Serial.begin(115200); + delay(2000); + Serial.println("Startup...."); + + #ifdef NVSERASE + esp_err_t err; + err = nvs_flash_init(); + err = nvs_flash_erase(); + #endif + + Serial.setDebugOutput(true); + + WiFi.begin("hellowifi","noonehere"); + + while (WiFi.status() != WL_CONNECTED && millis()<15000) { + delay(500); + Serial.print("."); + } + + if(WiFi.status() == WL_CONNECTED){ + Serial.println(""); + Serial.println("WiFi connected."); + Serial.println("IP address: "); + // Serial.println(WiFi.localIP()); + } + else { + Serial.println("WiFi NOT CONNECTED, starting ap"); + /////////////// + /// BUG + // WiFi.enableSTA(false); // BREAKS softap start, says ok BUT no ap found + + delay(2000); + WiFi.softAP("espsoftap","12345678"); + } +} + +void loop(){ + +} \ No newline at end of file diff --git a/extras/WiFiManager.template.html b/extras/WiFiManager.template.html index 39bdea05..20787e13 100644 --- a/extras/WiFiManager.template.html +++ b/extras/WiFiManager.template.html @@ -173,10 +173,28 @@ background-color:#dc3630; } -input:disabled { - opacity: 0.5; +button{ + /*transition: 0s filter;*/ + transition: 0s opacity; + transition-delay: 3s; + transition-duration: 0s; + cursor: pointer; +} + +button:active{ + opacity: 50% !important; + /*filter: brightness(50%);*/ + cursor: wait; + transition-delay: 0s; } +button:hover{ + /*opacity: 80%;*/ +} + +:disabled { + opacity: 0.5; +} @@ -185,6 +203,7 @@ p = l.nextElementSibling.classList.contains('l'); document.getElementById('p').disabled = !p; if(p)document.getElementById('p').focus()}; + function f() {var x = document.getElementById('p');x.type==='password'?x.type='text':x.type='password';} @@ -232,7 +251,7 @@

/wifi


-



+

Show Password

custom parameter


@@ -283,7 +302,11 @@

custom parameter


H4 Color Header S

content
-

/info


+

Heading 1

+

Heading 2

+

Heading 3

+

Heading 4

+

WIFI HEAD (WIFI_OFF)


Chip ID
123456
Flash Chip ID
1234556
@@ -318,7 +341,12 @@

/info


/erase Erase WiFi configuration and reboot Device. Device will not reconnect to a network until new WiFi configuration data is entered. -

More information about WiFiManager at https://github.com/tzapu/WiFiManager +

About


+ Version v1.x.x-xxxxx
+ Build_date
+ Build_file
+ Arduino_version
+

Github https://github.com/tzapu/WiFiManager

Form UPLOAD
diff --git a/library.json b/library.json index 1c2f505e..0357a370 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "WiFiManager", - "version": "2.0.9-beta", + "version": "2.0.13-beta", "keywords": "wifi,wi-fi,esp,esp8266,esp32,espressif8266,espressif32,nodemcu,wemos,arduino", "description": "WiFi Configuration manager with web configuration portal for ESP boards", "authors": @@ -21,9 +21,17 @@ "url": "https://github.com/tzapu/WiFiManager.git" }, "frameworks": "arduino", + "dependencies": { + "me-no-dev/AsyncTCP": "*", + "bbx10/DNSServer": "^1.1.0", + "external-repo": "https://github.com/me-no-dev/ESPAsyncWebServer.git" + }, + "build": { + "libLDFMode": "chain+" + }, "platforms": [ "espressif8266", "espressif32" ] -} \ No newline at end of file +} diff --git a/library.properties b/library.properties index 71f53afa..791cd61e 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=WiFiManager -version=2.0.9-beta +version=2.0.13-beta author=tzapu maintainer=tablatronix sentence=WiFi Configuration manager with web configuration portal for Espressif ESPx boards, by tzapu diff --git a/strings_en.h b/strings_en.h index 09ab44a6..5ea622ec 100644 --- a/strings_en.h +++ b/strings_en.h @@ -13,9 +13,12 @@ #ifndef _WM_STRINGS_H_ #define _WM_STRINGS_H_ + #ifndef WIFI_MANAGER_OVERRIDE_STRINGS // !!! ABOVE WILL NOT WORK if you define in your sketch, must be build flag, if anyone one knows how to order includes to be able to do this it would be neat.. I have seen it done.. +const char WM_VERSION_STR[] PROGMEM = "v2.0.13-beta"; + const char HTTP_HEAD_START[] PROGMEM = "" "" "" @@ -24,15 +27,18 @@ const char HTTP_HEAD_START[] PROGMEM = "" "{v}"; const char HTTP_SCRIPT[] PROGMEM = ""; // @todo add button states, disable on click , show ack , spinner etc +"if(p)document.getElementById('p').focus();};" +"function f() {var x = document.getElementById('p');x.type==='password'?x.type='text':x.type='password';}" +""; // @todo add button states, disable on click , show ack , spinner etc const char HTTP_HEAD_END[] PROGMEM = "

"; // {c} = _bodyclass // example of embedded logo, base64 encoded inline, No styling here // const char HTTP_ROOT_MAIN[] PROGMEM = "

{v}

WiFiManager

"; const char HTTP_ROOT_MAIN[] PROGMEM = "

{t}

{v}

"; + const char * const HTTP_PORTAL_MENU[] PROGMEM = { "
\n", // MENU_WIFI "

\n", // MENU_WIFINOSCAN @@ -50,11 +56,11 @@ const char * const HTTP_PORTAL_MENU[] PROGMEM = { const char HTTP_PORTAL_OPTIONS[] PROGMEM = ""; const char HTTP_ITEM_QI[] PROGMEM = ""; // rssi icons const char HTTP_ITEM_QP[] PROGMEM = "
{r}%
"; // rssi percentage {h} = hidden showperc pref -const char HTTP_ITEM[] PROGMEM = "
{v}{qi}{qp}
"; // {q} = HTTP_ITEM_QI, {r} = HTTP_ITEM_QP +const char HTTP_ITEM[] PROGMEM = "
{v}{qi}{qp}
"; // {q} = HTTP_ITEM_QI, {r} = HTTP_ITEM_QP // const char HTTP_ITEM[] PROGMEM = "
{v} {R} {r}% {q} {e}
"; // test all tokens const char HTTP_FORM_START[] PROGMEM = "
"; -const char HTTP_FORM_WIFI[] PROGMEM = "
"; +const char HTTP_FORM_WIFI[] PROGMEM = "
Show Password"; const char HTTP_FORM_WIFI_END[] PROGMEM = ""; const char HTTP_FORM_STATIC_HEAD[] PROGMEM = "

"; const char HTTP_FORM_END[] PROGMEM = "

"; @@ -99,12 +105,14 @@ const char HTTP_STYLE[] PROGMEM = ""; #ifndef WM_NOHELP @@ -133,7 +141,7 @@ const char HTTP_HELP[] PROGMEM = "/erase" "Erase WiFi configuration and reboot Device. Device will not reconnect to a network until new WiFi configuration data is entered." "" - "

More information about WiFiManager at https://github.com/tzapu/WiFiManager."; + "

Github https://github.com/tzapu/WiFiManager."; #else const char HTTP_HELP[] PROGMEM = ""; #endif @@ -163,13 +171,15 @@ const char HTTP_JS[] PROGMEM = #endif // Info html +// @todo remove html elements from progmem, repetetive strings #ifdef ESP32 - const char HTTP_INFO_esphead[] PROGMEM = "

esp32


"; + const char HTTP_INFO_esphead[] PROGMEM = "

{1}


"; const char HTTP_INFO_chiprev[] PROGMEM = "
Chip Rev
{1}
"; const char HTTP_INFO_lastreset[] PROGMEM = "
Last reset reason
CPU0: {1}
CPU1: {2}
"; const char HTTP_INFO_aphost[] PROGMEM = "
Access Point Hostname
{1}
"; const char HTTP_INFO_psrsize[] PROGMEM = "
PSRAM Size
{1} bytes
"; - const char HTTP_INFO_temp[] PROGMEM = "
Temperature
{1} C° / {2} F°
Hall
{3}
"; + const char HTTP_INFO_temp[] PROGMEM = "
Temperature
{1} C° / {2} F°
"; + // const char HTTP_INFO_temp[] PROGMEM = "
Hall
{3}
"; #else const char HTTP_INFO_esphead[] PROGMEM = "

esp8266


"; const char HTTP_INFO_fchipid[] PROGMEM = "
Flash Chip ID
{1}
"; @@ -182,7 +192,7 @@ const char HTTP_JS[] PROGMEM = const char HTTP_INFO_memsmeter[] PROGMEM = "
"; const char HTTP_INFO_memsketch[] PROGMEM = "
Memory - Sketch Size
Used / Total bytes
{1} / {2}"; const char HTTP_INFO_freeheap[] PROGMEM = "
Memory - Free Heap
{1} bytes available
"; -const char HTTP_INFO_wifihead[] PROGMEM = "

WiFi


"; +const char HTTP_INFO_wifihead[] PROGMEM = "

WiFi ({1})


"; const char HTTP_INFO_uptime[] PROGMEM = "
Uptime
{1} Mins {2} Secs
"; const char HTTP_INFO_chipid[] PROGMEM = "
Chip ID
{1}
"; const char HTTP_INFO_idesize[] PROGMEM = "
Flash Size
{1} bytes
"; @@ -202,6 +212,10 @@ const char HTTP_INFO_stamac[] PROGMEM = "
Station MAC
{1}
"; const char HTTP_INFO_conx[] PROGMEM = "
Connected
{1}
"; const char HTTP_INFO_autoconx[] PROGMEM = "
Autoconnect
{1}
"; +const char HTTP_INFO_aboutver[] PROGMEM = "
WiFiManager
{1}
"; +const char HTTP_INFO_aboutarduino[] PROGMEM = "
Arduino
{1}
"; +const char HTTP_INFO_aboutsdk[] PROGMEM = "
ESP-SDK/IDF
{1}
"; +const char HTTP_INFO_aboutdate[] PROGMEM = "
Build Date
{1}
"; const char S_brand[] PROGMEM = "WiFiManager"; const char S_debugPrefix[] PROGMEM = "*wm:"; @@ -248,8 +262,8 @@ const char D_HR[] PROGMEM = "--------------------"; // ----------------------------------------------------------------------------------------------- // DO NOT EDIT BELOW THIS LINE -const uint8_t _nummenutokens = 10; -const char * const _menutokens[10] PROGMEM = { +const uint8_t _nummenutokens = 11; +const char * const _menutokens[_nummenutokens] PROGMEM = { "wifi", "wifinoscan", "info", @@ -259,7 +273,8 @@ const char * const _menutokens[10] PROGMEM = { "exit", "erase", "update", - "sep" + "sep", + "custom" }; const char R_root[] PROGMEM = "/"; @@ -301,6 +316,7 @@ const char T_1[] PROGMEM = "{1}"; // @token 1 const char T_2[] PROGMEM = "{2}"; // @token 2 const char T_3[] PROGMEM = "{3}"; // @token 2 const char T_v[] PROGMEM = "{v}"; // @token v +const char T_V[] PROGMEM = "{V}"; // @token v const char T_I[] PROGMEM = "{I}"; // @token I const char T_i[] PROGMEM = "{i}"; // @token i const char T_n[] PROGMEM = "{n}"; // @token n