diff --git a/.github/workflows/compile_library.yml b/.github/workflows/compile_library.yml deleted file mode 100644 index 3f06ca5d..00000000 --- a/.github/workflows/compile_library.yml +++ /dev/null @@ -1,58 +0,0 @@ -name: Compile Library - -on: - push: - paths-ignore: - - '.github/workflows/cpp_lint.yml' - - '.github/workflows/compile_examples.yml' - - 'examples/**' - pull_request: - paths-ignore: - - '.github/workflows/cpp_lint.yml' - - '.github/workflows/compile_examples.yml' - - 'examples/**' - -jobs: - build: - - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - board: - - "nodemcuv2" - - "lolin32" - - steps: - - uses: actions/checkout@v2 - - name: Cache pip - uses: actions/cache@v2 - with: - path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}-${{ matrix.board }} - restore-keys: | - ${{ runner.os }}-pip-${{ matrix.board }}- - ${{ runner.os }}-pip- - - name: Cache PlatformIO - uses: actions/cache@v2 - with: - path: ~/.platformio - key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}-${{ matrix.board }} - restore-keys: | - ${{ runner.os }}-${{ matrix.board }}- - ${{ runner.os }}- - - name: Set up Python - uses: actions/setup-python@v2 - - name: Install PlatformIO - run: | - python -m pip install --upgrade pip - pip install --upgrade platformio - - - name: Create main file - run: | - echo "#include " >> main.ino - echo "void setup() {}" >> main.ino - echo "void loop() {}" >> main.ino - - - name: Run PlatformIO - run: pio ci --board=${{ matrix.board }} . diff --git a/README.md b/README.md index e646277c..e69de29b 100644 --- a/README.md +++ b/README.md @@ -1,591 +0,0 @@ - -# WiFiManager - -Espressif ESPx WiFi Connection manager with fallback web configuration portal - -:warning: This Documentation is out of date, see notes below - - -[![Release](https://img.shields.io/github/v/release/tzapu/WiFiManager?include_prereleases)](#release) - -[![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)](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)](https://www.espressif.com/en/products/socs/esp8266) - -[![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) -[![ESP32](https://img.shields.io/badge/ESP-32S3-000000.svg?longCache=true&style=flat&colorA=CC101F)](https://www.espressif.com/en/products/socs/esp32-S3) - -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/nS5WGkaQH5) -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. - -Works with the [ESP8266 Arduino](https://github.com/esp8266/Arduino) and [ESP32 Arduino](https://github.com/espressif/arduino-esp32) platforms. - -### Known Issues - -* Documentation needs to be updated, see [https://github.com/tzapu/WiFiManager/issues/500](https://github.com/tzapu/WiFiManager/issues/500) -------- - -## Contents - - [How it works](#how-it-works) - - [Wishlist](#wishlist) - - [Quick start](#quick-start) - - Installing - - [Arduino - Through Library Manager](#install-through-library-manager) - - [Arduino - From Github](#checkout-from-github) - - [PlatformIO](#install-using-platformio) - - [Using](#using) - - [Documentation](#documentation) - - [Access Point Password](#password-protect-the-configuration-access-point) - - [Callbacks](#callbacks) - - [Configuration Portal Timeout](#configuration-portal-timeout) - - [On Demand Configuration](#on-demand-configuration-portal) - - [Custom Parameters](#custom-parameters) - - [Custom IP Configuration](#custom-ip-configuration) - - [Filter Low Quality Networks](#filter-networks) - - [Debug Output](#debug) - - [Troubleshooting](#troubleshooting) - - [Releases](#releases) - - [Contributors](#contributions-and-thanks) - - -## How It Works -- When your ESP starts up, it sets it up in Station mode and tries to connect to a previously saved Access Point -- if this is unsuccessful (or no previous network saved) it moves the ESP into Access Point mode and spins up a DNS and WebServer (default ip 192.168.4.1) -- using any wifi enabled device with a browser (computer, phone, tablet) connect to the newly created Access Point -- because of the Captive Portal and the DNS server you will either get a 'Join to network' type of popup or get any domain you try to access redirected to the configuration portal -- choose one of the access points scanned, enter password, click save -- ESP will try to connect. If successful, it relinquishes control back to your app. If not, reconnect to AP and reconfigure. -- There are options to change this behavior or manually start the configportal and webportal independantly as well as run them in non blocking mode. - -## How It Looks -![ESP8266 WiFi Captive Portal Homepage](http://i.imgur.com/YPvW9eql.png) ![ESP8266 WiFi Captive Portal Configuration](http://i.imgur.com/oicWJ4gl.png) - -## Wishlist -- [x] remove dependency on EEPROM library -- [x] move HTML Strings to PROGMEM -- [x] cleanup and streamline code (although this is ongoing) -- [x] if timeout is set, extend it when a page is fetched in AP mode -- [x] add ability to configure more parameters than ssid/password -- [x] maybe allow setting ip of ESP after reboot -- [x] add to Arduino Library Manager -- [x] add to PlatformIO -- [ ] add multiple sets of network credentials -- [x] allow users to customize CSS -- [ ] rewrite documentation for simplicity, based on scenarios/goals - -### Development -- [x] ESP32 support -- [x] rely on the SDK's built in auto connect more than forcing a connect -- [x] add non blocking mode -- [x] easy customization of strings -- [x] hostname support -- [x] fix various bugs and workarounds for esp SDK issues -- [x] additional info page items -- [x] last status display / faiilure reason -- [x] customizeable menu -- [x] seperate custom params page -- [x] ondemand webportal -- [x] complete refactor of code to segment functions -- [x] wiif scan icons or percentage display -- [x] invert class for dark mode -- [x] more template tokens -- [x] progmem for all strings -- [ ] new callbacks -- [ ] new callouts / filters -- [ ] shared web server instance -- [x] latest esp idf/sdk support -- [x] wm is now non persistent, will not erase or change stored esp config on esp8266 -- [x] tons of debugging output / levels -- [ ] disable captiveportal -- [ ] preload wiifscans, faster page loads -- [ ] softap stability fixes when sta is not connected - - -## Quick Start - -### Installing -You can either install through the Arduino Library Manager or checkout the latest changes or a release from github - -#### Install through Library Manager -__Currently version 0.8+ works with release 2.4.0 or newer of the [ESP8266 core for Arduino](https://github.com/esp8266/Arduino)__ - - in Arduino IDE got to Sketch/Include Library/Manage Libraries - ![Manage Libraries](http://i.imgur.com/9BkEBkR.png) - - - search for WiFiManager - ![WiFiManager package](http://i.imgur.com/18yIai8.png) - - - click Install and start [using it](#using) - -#### Checkout from github -__Github version works with release 2.4.0 or newer of the [ESP8266 core for Arduino](https://github.com/esp8266/Arduino)__ -- Checkout library to your Arduino libraries folder - -### Using -- Include in your sketch -```cpp -#include //https://github.com/tzapu/WiFiManager WiFi Configuration Magic -``` - -- Initialize library, in your setup function add, NOTEif you are using non blocking you will make sure you create this in global scope or handle appropriatly , it will not work if in setup and using non blocking mode. -```cpp -WiFiManager wifiManager; -``` - -- Also in the setup function add -```cpp -//first parameter is name of access point, second is the password -wifiManager.autoConnect("AP-NAME", "AP-PASSWORD"); -``` -if you just want an unsecured access point -```cpp -wifiManager.autoConnect("AP-NAME"); -``` -or if you want to use and auto generated name from 'ESP' and the esp's Chip ID use -```cpp -wifiManager.autoConnect(); -``` - -After you write your sketch and start the ESP, it will try to connect to WiFi. If it fails it starts in Access Point mode. -While in AP mode, connect to it then open a browser to the gateway IP, default 192.168.4.1, configure wifi, save and it should reboot and connect. - -Also see [examples](https://github.com/tzapu/WiFiManager/tree/master/examples). - -#### Install Using PlatformIO - -[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.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 -`lib_deps` key like so: - -``` -[env] -lib_deps = - WiFiManager -``` - - -``` -[env] -lib_deps = - https://github.com/tzapu/WiFiManager.git -``` - -## Documentation - -#### Switch languages for the configuration website -You can switch the language for configuration website during compile time. Default is `LANG_EN` for an english setup. Within PlatformIO add the following compile parameter: -```ini -[env] -build_flags = -D LANG_EN -``` -Currently the following language codes are available: -```ini -LANG_DE -LANG_EN -LANG_ES -LANG_FR -``` - - -#### Password protect the configuration Access Point -You can and should password protect the configuration access point. Simply add the password as a second parameter to `autoConnect`. -A short password seems to have unpredictable results so use one that's around 8 characters or more in length. -The guidelines are that a wifi password must consist of 8 to 63 ASCII-encoded characters in the range of 32 to 126 (decimal) -```cpp -wifiManager.autoConnect("AutoConnectAP", "password") -``` - -#### Callbacks -##### Enter Config mode -Use this if you need to do something when your device enters configuration mode on failed WiFi connection attempt. -Before `autoConnect()` -```cpp -wifiManager.setAPCallback(configModeCallback); -``` -`configModeCallback` declaration and example -```cpp -void configModeCallback (WiFiManager *myWiFiManager) { - Serial.println("Entered config mode"); - Serial.println(WiFi.softAPIP()); - - Serial.println(myWiFiManager->getConfigPortalSSID()); -} -``` - -##### Save settings -This gets called when custom parameters have been set **AND** a connection has been established. Use it to set a flag, so when all the configuration finishes, you can save the extra parameters somewhere. - - -IF YOU NEED TO SAVE PARAMETERS EVEN ON WIFI FAIL OR EMPTY, you must set `setBreakAfterConfig` to true, or else saveConfigCallback will not be called. - -```C++ -//if this is set, it will exit after config, even if connection is unsuccessful. - void setBreakAfterConfig(boolean shouldBreak); -``` - -See [AutoConnectWithFSParameters Example](https://github.com/tzapu/WiFiManager/tree/master/examples/Parameters/SPIFFS/AutoConnectWithFSParameters). -```cpp -wifiManager.setSaveConfigCallback(saveConfigCallback); -``` -`saveConfigCallback` declaration and example -```cpp -//flag for saving data -bool shouldSaveConfig = false; - -//callback notifying us of the need to save config -void saveConfigCallback () { - Serial.println("Should save config"); - shouldSaveConfig = true; -} -``` - -#### Configuration Portal Timeout -If you need to set a timeout so the ESP doesn't hang waiting to be configured, for instance after a power failure, you can add -```cpp -wifiManager.setConfigPortalTimeout(180); -``` -which will wait 3 minutes (180 seconds). When the time passes, the autoConnect function will return, no matter the outcome. -Check for connection and if it's still not established do whatever is needed (on some modules I restart them to retry, on others I enter deep sleep) - -#### On Demand Configuration Portal -If you would rather start the configuration portal on demand rather than automatically on a failed connection attempt, then this is for you. - -Instead of calling `autoConnect()` which does all the connecting and failover configuration portal setup for you, you need to use `startConfigPortal()`. __Do not use BOTH.__ - -Example usage -```cpp -void loop() { - // is configuration portal requested? - if ( digitalRead(TRIGGER_PIN) == LOW ) { - WiFiManager wifiManager; - wifiManager.startConfigPortal("OnDemandAP"); - Serial.println("connected...yeey :)"); - } -} -``` -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. -If you'd prefer to exit without joining a WiFi network, say becuase you're going to put the ESP into AP mode, then press the "Exit" button -on the main webpage. -If started via `autoConnect` or `startConfigPortal` then it will return `false (portalAbortResult)` - -#### Custom Parameters -You can use WiFiManager to collect more parameters than just SSID and password. -This could be helpful for configuring stuff like MQTT host and port, [blynk](http://www.blynk.cc) or [emoncms](http://emoncms.org) tokens, just to name a few. -**You are responsible for saving and loading these custom values.** The library just collects and displays the data for you as a convenience. -Usage scenario would be: -- load values from somewhere (EEPROM/FS) or generate some defaults -- add the custom parameters to WiFiManager using -```cpp - // id/name, placeholder/prompt, default, length - WiFiManagerParameter custom_mqtt_server("server", "mqtt server", mqtt_server, 40); - wifiManager.addParameter(&custom_mqtt_server); - -``` -- 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 WiFiManager returns control to your application, read and save the new values using the `WiFiManagerParameter` object. -```cpp - mqtt_server = custom_mqtt_server.getValue(); -``` -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/Parameters/SPIFFS/AutoConnectWithFSParameters) -- *Save and load custom parameters to EEPROM* (not done yet) - -#### Custom IP Configuration -You can set a custom IP for both AP (access point, config mode) and STA (station mode, client mode, normal project state) - -##### Custom Access Point IP Configuration -This will set your captive portal to a specific IP should you need/want such a feature. Add the following snippet before `autoConnect()` -```cpp -//set custom ip for portal -wifiManager.setAPStaticIPConfig(IPAddress(10,0,1,1), IPAddress(10,0,1,1), IPAddress(255,255,255,0)); -``` - -##### Custom Station (client) Static IP Configuration -This will make use the specified IP configuration instead of using DHCP in station mode. -```cpp -wifiManager.setSTAStaticIPConfig(IPAddress(192,168,0,99), IPAddress(192,168,0,1), IPAddress(255,255,255,0)); // optional DNS 4th argument -``` -There are a couple of examples in the examples folder that show you how to set a static IP and even how to configure it through the web configuration portal. - -NOTE: You should fill DNS server if you have HTTP requests with hostnames or syncronize time (NTP). It's the same as gateway ip or a popular (Google DNS: 8.8.8.8). - -#### Custom HTML, CSS, Javascript -There are various ways in which you can inject custom HTML, CSS or Javascript into the configuration portal. -The options are: -- inject custom head element -You can use this to any html bit to the head of the configuration portal. If you add a `"); -``` -- inject a custom bit of html in the configuration/param form -```cpp -WiFiManagerParameter custom_text("

This is just a text paragraph

"); -wifiManager.addParameter(&custom_text); -``` -- inject a custom bit of html in a configuration form element -Just add the bit you want added as the last parameter to the custom parameter constructor. -```cpp -WiFiManagerParameter custom_mqtt_server("server", "mqtt server", "iot.eclipse", 40, " readonly"); -wifiManager.addParameter(&custom_mqtt_server); -``` - -#### Theming -You can customize certain elements of the default template with some builtin classes -```CPP -wifiManager.setClass("invert"); // dark theme -wifiManager.setScanDispPerc(true); // display percentages instead of graphs for RSSI -``` -There are additional classes in the css you can use in your custom html , see the example template. - -#### Filter Networks -You can filter networks based on signal quality and show/hide duplicate networks. - -- If you would like to filter low signal quality networks you can tell WiFiManager to not show networks below an arbitrary quality %; -```cpp -wifiManager.setMinimumSignalQuality(10); -``` -will not show networks under 10% signal quality. If you omit the parameter it defaults to 8%; - -- You can also remove or show duplicate networks (default is remove). -Use this function to show (or hide) all networks. -```cpp -wifiManager.setRemoveDuplicateAPs(false); -``` - -#### Debug -Debug is enabled by default on `Serial` in non-stable releases. To disable add before autoConnect/startConfigPortal -```cpp -wifiManager.setDebugOutput(false); -``` - -You can pass in a custom stream via constructor -```CPP -WiFiManager wifiManager(Serial1); -``` - -You can customize the debug level by changing `_debugLevel` in source -options are: -* DEBUG_ERROR -* DEBUG_NOTIFY -* DEBUG_VERBOSE -* DEBUG_DEV -* DEBUG_MAX - -## Troubleshooting -If you get compilation errors, more often than not, you may need to install a newer version of the ESP8266 core for Arduino. - -Changes added on 0.8 should make the latest trunk work without compilation errors. Tested down to ESP8266 core 2.0.0. **Please update to version 0.8** - -I am trying to keep releases working with release versions of the core, so they can be installed through boards manager, but if you checkout the latest version directly from github, sometimes, the library will only work if you update the ESP8266 core to the latest version because I am using some newly added function. - -If you connect to the created configuration Access Point but the configuration portal does not show up, just open a browser and type in the IP of the web portal, by default `192.168.4.1`. - -If trying to connect ends up in an endless loop, try to add `setConnectTimeout(60)` before `autoConnect();`. The parameter is timeout to try connecting in seconds. - -I get stuck in ap mode when the power goes out or modem resets, try a setConfigPortalTimeout(seconds). This will cause the configportal to close after no activity, and you can reboot or attempt reconnection in your code. - -## Releases -### 1.0.1 - -### Development Overview - -#### Added Public Methods -`setConfigPortalBlocking` - -`setShowStaticFields` - -`setCaptivePortalEnable` - -`setRestorePersistent` - -`setCaptivePortalClientCheck` - -`setWebPortalClientCheck` - -`startWebPortal` - -`stopWebPortal` - -`process` - -`disconnect` - -`erase` - -` debugSoftAPConfig` - -` debugPlatformInfo` - -`setScanDispPerc` - -`setHostname` - -`setMenu(menu_page_t[])` - -`setWiFiAutoReconnect` - -` setSTAStaticIPConfig(..,dns)` - -`setShowDnsFields` - -`getLastConxResult` - -`getWLStatusString` - -`getModeString` - -`getWiFiIsSaved` - -`setShowInfoErase` - -`setEnableConfigPortal` - -`setCountry` - -`setClass` - -`htmleEtities` - - -#### WiFiManagerParameter -`WiFiManagerParameter(id,label)` - -`WiFiManagerParameter.setValue(value,length)` - -`getParameters` - -`getParametersCount` - - -#### Constructors -`WiFiManager(Stream& consolePort)` - -#### define flags -❗️ **Defines cannot be set in user sketches** -`#define WM_MDNS // use MDNS` - -`#define WM_FIXERASECONFIG // use erase flash fix, esp8266 2.4.0` - -`#define WM_ERASE_NVS // esp32 erase(true) will erase NVS` - -`#include // esp32 info page will show last reset reasons if this file is included` - -#### Changes Overview -- ESP32 support ( fairly stable ) -- complete refactor of strings `strings_en.h` -- adds new tokens for wifiscan, and some classes (left , invert icons, MSG color) -- adds status callout panel default, primary, special colors -- adds tons of info on info page, and erase capability -- adds signal icons, replaces percentage ( has hover titles ) -- adds labels to all inputs (replaces placeholders) -- all html ( and eventually all strings except debug) moved to `strings_en.h` -- added additional debugging, compressed debug lines, debuglevels -- persistent disabled, and restored via de/con-stuctor (uses `setRestorePersistent`) -- should retain all user modes including AP, should not overwrite or persist user modes or configs,even STA (`storeSTAmode`) (BUGGY) -- ⚠️ return values may have changed depending on portal abort, or timeout ( `portalTimeoutResult`,`portalAbortResult`) -- params memory is auto allocated by increment of `WIFI_MANAGER_MAX_PARAMS(5)` when exceeded, user no longer needs to specify this at all. -- addparameter now returns bool, and it returns false if param ID is not alphanum [0-9,A-Z,a-z,_] -- param field ids allow {I} token to use param_n instead of string in case someones wants to change this due to i18n or character issues -- provides `#DEFINE FIXERASECONFIG` to help deal with https://github.com/esp8266/Arduino/pull/3635 -- failure reason reporting on portal -- set esp8266 sta hostname, esp32 sta+ap hostname ( DHCP client id) -- pass in debug stream in constructor WiFiManager(Stream& consolePort) -- you can force ip fields off with showxfields(false) if you set _disableIpFields=true -- param menu/page (setup) added to separate params from wifi page, handled automatically by setMenu -- set custom root menu -- disable configportal on autoconnect -- wm parameters init is now protected, allowing child classes, example included -- wifiscans are precached and async for faster page loads, refresh forces rescan -- adds esp32 gettemperature ( currently commented out, useful for relative measurement only ) - -#### 0.12 -- removed 204 header response -- fixed incompatibility with other libs using isnan and other std:: functions without namespace - -##### 0.11 -- a lot more reliable reconnecting to networks -- custom html in custom parameters (for read only params) -- custom html in custom parameter form (like labels) -- custom head element (like custom css) -- sort networks based on signal quality -- remove duplicate networks - -##### 0.10 -- some css changes -- bug fixes and speed improvements -- added an alternative to waitForConnectResult() for debugging -- changed `setTimeout(seconds)` to `setConfigPortalTimeout(seconds)` - -### Contributions and thanks -The support and help I got from the community has been nothing short of phenomenal. I can't thank you guys enough. This is my first real attept in developing open source stuff and I must say, now I understand why people are so dedicated to it, it is because of all the wonderful people involved. - -__THANK YOU__ - -The esp8266 and esp32 arduino and idf maintainers! - -[Shawn A aka tablatronix](https://github.com/tablatronix) - -[liebman](https://github.com/liebman) - -[Evgeny Dontsov](https://github.com/dontsovcmc) - -[Chris Marrin](https://github.com/cmarrin) - -[bbx10](https://github.com/bbx10) - -[kentaylor](https://github.com/kentaylor) - -[Maximiliano Duarte](https://github.com/domonetic) - -[alltheblinkythings](https://github.com/alltheblinkythings) - -[Niklas Wall](https://github.com/niklaswall) - -[Jakub Piasecki](https://github.com/zaporylie) - -[Peter Allan](https://github.com/alwynallan) - -[John Little](https://github.com/j0hnlittle) - -[markaswift](https://github.com/markaswift) - -[franklinvv](https://github.com/franklinvv) - -[Alberto Ricci Bitti](https://github.com/riccibitti) - -[SebiPanther](https://github.com/SebiPanther) - -[jonathanendersby](https://github.com/jonathanendersby) - -[walthercarsten](https://github.com/walthercarsten) - -And countless others - -#### Inspiration - * http://www.esp8266.com/viewtopic.php?f=29&t=2520 - * https://github.com/chriscook8/esp-arduino-apboot - * https://github.com/esp8266/Arduino/tree/master/libraries/DNSServer/examples/CaptivePortalAdvanced - * Built by AlexT https://github.com/tzapu - diff --git a/WiFiManager.cpp b/WiFiManager.cpp deleted file mode 100644 index 21c9e38f..00000000 --- a/WiFiManager.cpp +++ /dev/null @@ -1,4053 +0,0 @@ -/** - * 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 - * @license MIT - */ - -#include "WiFiManager.h" - -#if defined(ESP8266) || defined(ESP32) - -#ifdef ESP32 -uint8_t WiFiManager::_lastconxresulttmp = WL_IDLE_STATUS; -#endif - -/** - * -------------------------------------------------------------------------------- - * WiFiManagerParameter - * -------------------------------------------------------------------------------- -**/ - -WiFiManagerParameter::WiFiManagerParameter() { - WiFiManagerParameter(""); -} - -WiFiManagerParameter::WiFiManagerParameter(const char *custom) { - _id = NULL; - _label = NULL; - _length = 0; - _value = nullptr; - _labelPlacement = WFM_LABEL_DEFAULT; - _customHTML = custom; -} - -WiFiManagerParameter::WiFiManagerParameter(const char *id, const char *label) { - init(id, label, "", 0, "", WFM_LABEL_DEFAULT); -} - -WiFiManagerParameter::WiFiManagerParameter(const char *id, const char *label, const char *defaultValue, int length) { - init(id, label, defaultValue, length, "", WFM_LABEL_DEFAULT); -} - -WiFiManagerParameter::WiFiManagerParameter(const char *id, const char *label, const char *defaultValue, int length, const char *custom) { - init(id, label, defaultValue, length, custom, WFM_LABEL_DEFAULT); -} - -WiFiManagerParameter::WiFiManagerParameter(const char *id, const char *label, const char *defaultValue, int length, const char *custom, int labelPlacement) { - init(id, label, defaultValue, length, custom, labelPlacement); -} - -void WiFiManagerParameter::init(const char *id, const char *label, const char *defaultValue, int length, const char *custom, int labelPlacement) { - _id = id; - _label = label; - _labelPlacement = labelPlacement; - _customHTML = custom; - _length = 0; - _value = nullptr; - setValue(defaultValue,length); -} - -WiFiManagerParameter::~WiFiManagerParameter() { - if (_value != NULL) { - delete[] _value; - } - _length=0; // setting length 0, ideally the entire parameter should be removed, or added to wifimanager scope so it follows -} - -// WiFiManagerParameter& WiFiManagerParameter::operator=(const WiFiManagerParameter& rhs){ -// Serial.println("copy assignment op called"); -// (*this->_value) = (*rhs._value); -// return *this; -// } - -// @note debug is not available in wmparameter class -void WiFiManagerParameter::setValue(const char *defaultValue, int length) { - if(!_id){ - // Serial.println("cannot set value of this parameter"); - return; - } - - // if(strlen(defaultValue) > length){ - // // Serial.println("defaultValue length mismatch"); - // // return false; //@todo bail - // } - - if(_length != length || _value == nullptr){ - _length = length; - if( _value != nullptr){ - delete[] _value; - } - _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)); - return _value; -} -const char* WiFiManagerParameter::getID() const { - return _id; -} -const char* WiFiManagerParameter::getPlaceholder() const { - return _label; -} -const char* WiFiManagerParameter::getLabel() const { - return _label; -} -int WiFiManagerParameter::getValueLength() const { - return _length; -} -int WiFiManagerParameter::getLabelPlacement() const { - return _labelPlacement; -} -const char* WiFiManagerParameter::getCustomHTML() const { - return _customHTML; -} - -/** - * [addParameter description] - * @access public - * @param {[type]} WiFiManagerParameter *p [description] - */ -bool WiFiManager::addParameter(WiFiManagerParameter *p) { - - // check param id is valid, unless null - if(p->getID()){ - for (size_t i = 0; i < strlen(p->getID()); i++){ - if(!(isAlphaNumeric(p->getID()[i])) && !(p->getID()[i]=='_')){ - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_ERROR,F("[ERROR] parameter IDs can only contain alpha numeric chars")); - #endif - return false; - } - } - } - - // 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*)); - #endif - _params = (WiFiManagerParameter**)malloc(_max_params * sizeof(WiFiManagerParameter*)); - } - - // resize the params array by increment of WIFI_MANAGER_MAX_PARAMS - if(_paramsCount == _max_params){ - _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*)); - #endif - WiFiManagerParameter** new_params = (WiFiManagerParameter**)realloc(_params, _max_params * sizeof(WiFiManagerParameter*)); - #ifdef WM_DEBUG_LEVEL - // DEBUG_WM(WIFI_MANAGER_MAX_PARAMS); - // DEBUG_WM(_paramsCount); - // DEBUG_WM(_max_params); - #endif - if (new_params != NULL) { - _params = new_params; - } else { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_ERROR,F("[ERROR] failed to realloc params, size not increased!")); - #endif - return false; - } - } - - _params[_paramsCount] = p; - _paramsCount++; - - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("Added Parameter:"),p->getID()); - #endif - return true; -} - -/** - * [getParameters description] - * @access public - */ -WiFiManagerParameter** WiFiManager::getParameters() { - return _params; -} - -/** - * [getParametersCount description] - * @access public - */ -int WiFiManager::getParametersCount() { - return _paramsCount; -} - -/** - * -------------------------------------------------------------------------------- - * WiFiManager - * -------------------------------------------------------------------------------- -**/ - -// constructors -WiFiManager::WiFiManager(Print& consolePort):_debugPort(consolePort){ - WiFiManagerInit(); -} - -WiFiManager::WiFiManager() { - WiFiManagerInit(); -} - -void WiFiManager::WiFiManagerInit(){ - setMenu(_menuIdsDefault); - if(_debug && _debugLevel >= WM_DEBUG_DEV) debugPlatformInfo(); - _max_params = WIFI_MANAGER_MAX_PARAMS; -} - -// destructor -WiFiManager::~WiFiManager() { - _end(); - // parameters - // @todo below belongs to wifimanagerparameter - if (_params != NULL){ - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_DEV,F("freeing allocated params!")); - #endif - free(_params); - _params = NULL; - } - - // remove event - // WiFi.onEvent(std::bind(&WiFiManager::WiFiEvent,this,_1,_2)); - #ifdef ESP32 - WiFi.removeEvent(wm_event_id); - #endif - - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_DEV,F("unloading")); - #endif -} - -void WiFiManager::_begin(){ - if(_hasBegun) return; - _hasBegun = true; - // _usermode = WiFi.getMode(); - - #ifndef ESP32 - WiFi.persistent(false); // disable persistent so scannetworks and mode switching do not cause overwrites - #endif -} - -void WiFiManager::_end(){ - _hasBegun = false; - if(_userpersistent) WiFi.persistent(true); // reenable persistent, there is no getter we rely on _userpersistent - // if(_usermode != WIFI_OFF) WiFi.mode(_usermode); -} - -// AUTOCONNECT - -boolean WiFiManager::autoConnect() { - String ssid = getDefaultAPName(); - return autoConnect(ssid.c_str(), NULL); -} - -/** - * [autoConnect description] - * @access public - * @param {[type]} char const *apName [description] - * @param {[type]} char const *apPassword [description] - * @return {[type]} [description] - */ -boolean WiFiManager::autoConnect(char const *apName, char const *apPassword) { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("AutoConnect")); - #endif - - // bool wifiIsSaved = getWiFiIsSaved(); - bool wifiIsSaved = true; // workaround until I can check esp32 wifiisinit and has nvs - - #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()0){ - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("Starting AP on channel:"),channel); - #endif - } - - // start soft AP with password or anonymous - // default channel is 1 here and in esplib, @todo just change to default remove conditionals - 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!")); - #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")); - DEBUG_WM(F("AP IP address:"),WiFi.softAPIP()); - #endif - - // set ap hostname - #ifdef ESP32 - if(ret && _hostname != ""){ - bool res = WiFi.softAPsetHostname(_hostname.c_str()); - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("setting softAP Hostname:"),_hostname); - if(!res)DEBUG_WM(WM_DEBUG_ERROR,F("[ERROR] hostname: AP set failed!")); - DEBUG_WM(WM_DEBUG_DEV,F("hostname: AP: "),WiFi.softAPgetHostname()); - #endif - } - #endif - - return ret; -} - -/** - * [startWebPortal description] - * @access public - * @return {[type]} [description] - */ -void WiFiManager::startWebPortal() { - if(configPortalActive || webPortalActive) return; - connect = abort = false; - setupConfigPortal(); - webPortalActive = true; -} - -/** - * [stopWebPortal description] - * @access public - * @return {[type]} [description] - */ -void WiFiManager::stopWebPortal() { - if(!configPortalActive && !webPortalActive) return; - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("Stopping Web Portal")); - #endif - webPortalActive = false; - shutdownConfigPortal(); -} - -boolean WiFiManager::configPortalHasTimeout(){ - if(!configPortalActive) return false; - uint16_t logintvl = 30000; // how often to emit timeing out counter logging - - // handle timeout portal client check - if(_configPortalTimeout == 0 || (_apClientCheck && (WiFi_softap_num_stations() > 0))){ - // debug num clients every 30s - if(millis() - timer > logintvl){ - timer = millis(); - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("NUM CLIENTS: "),(String)WiFi_softap_num_stations()); - #endif - } - _configPortalStart = millis(); // kludge, bump configportal start time to skew timeouts - return false; - } - - // handle timeout webclient check - if(_webClientCheck && (_webPortalAccessed>_configPortalStart)>0) _configPortalStart = _webPortalAccessed; - - // handle timed out - if(millis() > _configPortalStart + _configPortalTimeout){ - #ifdef WM_DEBUG_LEVEL - 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){ - timer = millis(); - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("Portal Timeout In"),(String)((_configPortalStart + _configPortalTimeout-millis())/1000) + (String)F(" seconds")); - #endif - } - } - - return false; -} - -void WiFiManager::setupHTTPServer(){ - - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("Starting Web Portal")); - #endif - - if(_httpPort != 80) { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(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(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 - - /* 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 - server->on(WM_G(R_root), std::bind(&WiFiManager::handleRoot, this)); - server->on(WM_G(R_wifi), std::bind(&WiFiManager::handleWifi, this, true)); - server->on(WM_G(R_wifinoscan), std::bind(&WiFiManager::handleWifi, this, false)); - server->on(WM_G(R_wifisave), std::bind(&WiFiManager::handleWifiSave, this)); - server->on(WM_G(R_info), std::bind(&WiFiManager::handleInfo, this)); - server->on(WM_G(R_param), std::bind(&WiFiManager::handleParam, this)); - server->on(WM_G(R_paramsave), std::bind(&WiFiManager::handleParamSave, this)); - server->on(WM_G(R_restart), std::bind(&WiFiManager::handleReset, this)); - server->on(WM_G(R_exit), std::bind(&WiFiManager::handleExit, this)); - server->on(WM_G(R_close), std::bind(&WiFiManager::handleClose, this)); - 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")); - #endif -} - -void WiFiManager::setupDNSD(){ - dnsServer.reset(new DNSServer()); - - /* Setup the DNS server redirecting all the domains to the apIP */ - dnsServer->setErrorReplyCode(DNSReplyCode::NoError); - #ifdef WM_DEBUG_LEVEL - // DEBUG_WM("dns server started port: ",DNS_PORT); - DEBUG_WM(WM_DEBUG_DEV,F("dns server started with ip: "),WiFi.softAPIP()); // @todo not showing ip - #endif - dnsServer->start(DNS_PORT, F("*"), WiFi.softAPIP()); -} - -void WiFiManager::setupConfigPortal() { - setupHTTPServer(); - _lastscan = 0; // reset network scan cache - if(_preloadwifiscan) WiFi_scanNetworks(true,true); // preload wifiscan , async -} - -boolean WiFiManager::startConfigPortal() { - String ssid = getDefaultAPName(); - return startConfigPortal(ssid.c_str(), NULL); -} - -/** - * [startConfigPortal description] - * @access public - * @param {[type]} char const *apName [description] - * @param {[type]} char const *apPassword [description] - * @return {[type]} [description] - */ -boolean WiFiManager::startConfigPortal(char const *apName, char const *apPassword) { - _begin(); - - if(configPortalActive){ - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("Starting Config Portal FAILED, is already running")); - #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 - - 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` - #ifdef WM_DISCONWORKAROUND - WiFi.mode(WIFI_AP_STA); - #endif - WiFi_Disconnect(); - WiFi_enableSTA(false); - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("Disabling STA")); - #endif - } - else { - // WiFi_enableSTA(true); - } - - // init configportal globals to known states - configPortalActive = true; - bool result = connect = abort = false; // loop flags, connect true success, abort true break - uint8_t state; - - _configPortalStart = millis(); - - // start access point - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("Enabling AP")); - #endif - startAP(); - WiFiSetCountry(); - - // do AP callback if set - if ( _apcallback != NULL) { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("[CB] _apcallback calling")); - #endif - _apcallback(this); - } - - // init configportal - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_DEV,F("setupConfigPortal")); - #endif - setupConfigPortal(); - - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_DEV,F("setupDNSD")); - #endif - setupDNSD(); - - - if(!_configPortalIsBlocking){ - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("Config Portal Running, non blocking (processing)")); - if(_configPortalTimeout > 0) DEBUG_WM(WM_DEBUG_VERBOSE,F("Portal Timeout In"),(String)(_configPortalTimeout/1000) + (String)F(" seconds")); - #endif - return result; // skip blocking loop - } - - // 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")); - #endif - - while(1){ - - // if timed out or abort, break - if(configPortalHasTimeout() || abort){ - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_DEV,F("configportal loop abort")); - #endif - shutdownConfigPortal(); - result = abort ? portalAbortResult : portalTimeoutResult; // false, false - if (_configportaltimeoutcallback != NULL) { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("[CB] config portal timeout callback")); - #endif - _configportaltimeoutcallback(); // @CALLBACK - } - break; - } - - 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 - if(state != WL_IDLE_STATUS){ - result = (state == WL_CONNECTED); // true if connected - DEBUG_WM(WM_DEBUG_DEV,F("configportal loop break")); - break; - } - - if(!configPortalActive) break; - - yield(); // watchdog - } - - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_NOTIFY,F("config portal exiting")); - #endif - return result; -} - -/** - * [process description] - * @access public - * @return bool connected - */ -boolean WiFiManager::process(){ - // process mdns, esp32 not required - #if defined(WM_MDNS) && defined(ESP8266) - MDNS.update(); - #endif - - if(webPortalActive || (configPortalActive && !_configPortalIsBlocking)){ - // if timed out or abort, break - if(_allowExit && (configPortalHasTimeout() || abort)){ - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_DEV,F("process loop abort")); - #endif - webPortalActive = false; - shutdownConfigPortal(); - if (_configportaltimeoutcallback != NULL) { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("[CB] config portal timeout callback")); - #endif - _configportaltimeoutcallback(); // @CALLBACK - } - return false; - } - - uint8_t state = processConfigPortal(); // state is WL_IDLE or WL_CONNECTED/FAILED - return state == WL_CONNECTED; - } - return false; -} - -/** - * [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 - dnsServer->processNextRequest(); - } - - //HTTP handler - server->handleClient(); - - // Waiting for save... - if(connect) { - connect = false; - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("processing save")); - #endif - if(_enableCaptivePortal) delay(_cpclosedelay); // keeps the captiveportal from closing to fast. - - // skip wifi if no ssid - if(_ssid == ""){ - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("No ssid, skipping wifi save")); - #endif - } - else{ - // attempt sta connection to submitted _ssid, _pass - uint8_t res = connectWifi(_ssid, _pass, _connectonsave) == WL_CONNECTED; - if (res || (!_connectonsave)) { - #ifdef WM_DEBUG_LEVEL - if(!_connectonsave){ - DEBUG_WM(F("SAVED with no connect to new AP")); - } else { - DEBUG_WM(F("Connect to new AP [SUCCESS]")); - DEBUG_WM(F("Got IP Address:")); - DEBUG_WM(WiFi.localIP()); - } - #endif - - if ( _savewificallback != NULL) { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("[CB] _savewificallback calling")); - #endif - _savewificallback(); // @CALLBACK - } - if(!_connectonsave) return WL_IDLE_STATUS; - if(_disableConfigPortal) shutdownConfigPortal(); - return WL_CONNECTED; // CONNECT SUCCESS - } - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_ERROR,F("[ERROR] Connect to new AP Failed")); - #endif - } - - if (_shouldBreakAfterConfig) { - - // do save callback - // @todo this is more of an exiting callback than a save, clarify when this should actually occur - // confirm or verify data was saved to make this more accurate callback - if ( _savewificallback != NULL) { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("[CB] WiFi/Param save callback")); - #endif - _savewificallback(); // @CALLBACK - } - if(_disableConfigPortal) shutdownConfigPortal(); - return WL_CONNECT_FAILED; // CONNECT FAIL - } - else if(_configPortalIsBlocking){ - // clear save strings - _ssid = ""; - _pass = ""; - // if connect fails, turn sta off to stabilize AP - WiFi_Disconnect(); - WiFi_enableSTA(false); - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("Processing - Disabling STA")); - #endif - } - else{ - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("Portal is non blocking - remaining open")); - #endif - } - } - - return WL_IDLE_STATUS; -} - -/** - * [shutdownConfigPortal description] - * @access public - * @return bool success (softapdisconnect) - */ -bool WiFiManager::shutdownConfigPortal(){ - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("shutdownConfigPortal")); - #endif - - if(webPortalActive) return false; - - if(configPortalActive && dnsServer){ - //DNS handler - dnsServer->processNextRequest(); - } - - //HTTP handler - server->handleClient(); - - // @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 - server->stop(); - server.reset(); - - WiFi.scanDelete(); // free wifi scan results - - if(!configPortalActive) return false; - - dnsServer->stop(); // free heap ? - dnsServer.reset(); - - // turn off AP - // @todo bug workaround - // https://github.com/esp8266/Arduino/issues/3793 - // [APdisconnect] set_config failed! *WM: disconnect configportal - softAPdisconnect failed - // still no way to reproduce reliably - - 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)); - #endif - delay(1000); - WiFi_Mode(_usermode); // restore users wifi mode, BUG https://github.com/esp8266/Arduino/issues/4372 - if(WiFi.status()==WL_IDLE_STATUS){ - WiFi.reconnect(); // restart wifi since we disconnected it in startconfigportal - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("WiFi Reconnect, was idle")); - #endif - } - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("wifi status:"),getWLStatusString(WiFi.status())); - DEBUG_WM(WM_DEBUG_VERBOSE,F("wifi mode:"),getModeString(WiFi.getMode())); - #endif - configPortalActive = false; - DEBUG_WM(WM_DEBUG_VERBOSE,F("configportal closed")); - _end(); - return ret; -} - -// @todo refactor this up into seperate functions -// one for connecting to flash , one for new client -// clean up, flow is convoluted, and causes bugs -uint8_t WiFiManager::connectWifi(String ssid, String pass, bool connect) { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("Connecting as wifi client...")); - #endif - uint8_t retry = 1; - uint8_t connRes = (uint8_t)WL_NO_SSID_AVAIL; - - 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 - // @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 - // [E][WiFiSTA.cpp:221] begin(): connect failed! - - while(retry <= _connectRetries && (connRes!=WL_CONNECTED)){ - 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); - #endif - } - // if ssid argument provided connect to that - // NOTE: this also catches preload() _defaultssid @todo rework - if (ssid != "") { - wifiConnectNew(ssid,pass,connect); - // @todo connect=false seems to disconnect sta in begin() so not sure if _connectonsave is useful at all - // skip wait if not connecting - // if(connect){ - if(_saveTimeout > 0){ - connRes = waitForConnectResult(_saveTimeout); // use default save timeout for saves to prevent bugs in esp->waitforconnectresult loop - } - else { - connRes = waitForConnectResult(); - } - // } - } - else { - // connect using saved ssid if there is one - if (WiFi_hasAutoConnect()) { - wifiConnectDefault(); - connRes = waitForConnectResult(); - } - else { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("No wifi saved, skipping")); - #endif - } - } - - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("Connection result:"),getWLStatusString(connRes)); - #endif - retry++; -} - -// WPS enabled? https://github.com/esp8266/Arduino/pull/4889 -#ifdef NO_EXTRA_4K_HEAP - // do WPS, if WPS options enabled and not connected and no password was supplied - // @todo this seems like wrong place for this, is it a fallback or option? - if (_tryWPS && connRes != WL_CONNECTED && pass == "") { - startWPS(); - // should be connected at the end of WPS - connRes = waitForConnectResult(); - } -#endif - - if(connRes != WL_SCAN_COMPLETED){ - updateConxResult(connRes); - } - - return connRes; -} - -/** - * connect to a new wifi ap - * @since $dev - * @param String ssid - * @param String pass - * @return bool success - * @return connect only save if false - */ -bool WiFiManager::wifiConnectNew(String ssid, String pass,bool connect){ - bool ret = false; - #ifdef WM_DEBUG_LEVEL - // DEBUG_WM(WM_DEBUG_DEV,F("CONNECTED: "),WiFi.status() == WL_CONNECTED ? "Y" : "NO"); - DEBUG_WM(F("Connecting to NEW AP:"),ssid); - DEBUG_WM(WM_DEBUG_DEV,F("Using Password:"),pass); - #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); - WiFi.persistent(false); - #ifdef WM_DEBUG_LEVEL - if(!ret) DEBUG_WM(WM_DEBUG_ERROR,F("[ERROR] wifi begin failed")); - #endif - return ret; -} - -/** - * connect to stored wifi - * @since dev - * @return bool success - */ -bool WiFiManager::wifiConnectDefault(){ - bool ret = false; - - #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)); - #endif - - ret = WiFi_enableSTA(true,storeSTAmode); - delay(500); // THIS DELAY ? - - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_DEV,F("Mode after delay: "),getModeString(WiFi.getMode())); - if(!ret) DEBUG_WM(WM_DEBUG_ERROR,F("[ERROR] wifi enableSta failed")); - #endif - - ret = WiFi.begin(); - - #ifdef WM_DEBUG_LEVEL - if(!ret) DEBUG_WM(WM_DEBUG_ERROR,F("[ERROR] wifi begin failed")); - #endif - - return ret; -} - - -/** - * set sta config if set - * @since $dev - * @return bool success - */ -bool WiFiManager::setSTAConfig(){ - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_DEV,F("STA static IP:"),_sta_static_ip); - #endif - bool ret = true; - if (_sta_static_ip) { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("Custom static IP/GW/Subnet/DNS")); - #endif - if(_sta_static_dns) { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("Custom static DNS")); - #endif - ret = WiFi.config(_sta_static_ip, _sta_static_gw, _sta_static_sn, _sta_static_dns); - } - else { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("Custom STA IP/GW/Subnet")); - #endif - ret = WiFi.config(_sta_static_ip, _sta_static_gw, _sta_static_sn); - } - - #ifdef WM_DEBUG_LEVEL - 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")); - #endif - } - return ret; -} - -// @todo change to getLastFailureReason and do not touch conxresult -void WiFiManager::updateConxResult(uint8_t status){ - // hack in wrong password detection - _lastconxresult = status; - #ifdef ESP8266 - if(_lastconxresult == WL_CONNECT_FAILED){ - if(wifi_station_get_connect_status() == STATION_WRONG_PASSWORD){ - _lastconxresult = WL_STATION_WRONG_PASSWORD; - } - } - #elif defined(ESP32) - // 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)); - #endif - if(_lastconxresulttmp != WL_IDLE_STATUS){ - _lastconxresult = _lastconxresulttmp; - // _lastconxresulttmp = WL_IDLE_STATUS; - } - } - DEBUG_WM(WM_DEBUG_DEV,F("lastconxresult:"),getWLStatusString(_lastconxresult)); - #endif -} - - -uint8_t WiFiManager::waitForConnectResult() { - #ifdef WM_DEBUG_LEVEL - if(_connectTimeout > 0) DEBUG_WM(WM_DEBUG_DEV,_connectTimeout,F("ms connectTimeout set")); - #endif - return waitForConnectResult(_connectTimeout); -} - -/** - * waitForConnectResult - * @param uint16_t timeout in seconds - * @return uint8_t WL Status - */ -uint8_t WiFiManager::waitForConnectResult(uint32_t timeout) { - if (timeout == 0){ - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("connectTimeout not set, ESP waitForConnectResult...")); - #endif - return WiFi.waitForConnectResult(); - } - - unsigned long timeoutmillis = millis() + timeout; - #ifdef WM_DEBUG_LEVEL - 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 - if (status == WL_CONNECTED || status == WL_CONNECT_FAILED) { - return status; - } - #ifdef WM_DEBUG_LEVEL - DEBUG_WM (WM_DEBUG_VERBOSE,F(".")); - #endif - delay(100); - } - return status; -} - -// WPS enabled? https://github.com/esp8266/Arduino/pull/4889 -#ifdef NO_EXTRA_4K_HEAP -void WiFiManager::startWPS() { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("START WPS")); - #endif - #ifdef ESP8266 - WiFi.beginWPSConfig(); - #else - // @todo - #endif - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("END WPS")); - #endif -} -#endif - -String WiFiManager::getHTTPHead(String title, String classes){ - String page; - page += FPSTR(HTTP_HEAD_START); - page.replace(FPSTR(T_v), title); - page += FPSTR(HTTP_SCRIPT); - page += FPSTR(HTTP_STYLE); - page += _customHeadElement; - - String p = FPSTR(HTTP_HEAD_END); - if (_bodyClass != "") { - if (classes != "") { - classes += " "; // add spacing, if necessary - } - classes += _bodyClass; // add class str - } - p.replace(FPSTR(T_c), classes); - page += p; - - if (_customBodyHeader) { - page += _customBodyHeader; - } - - return page; -} - -String WiFiManager::getHTTPEnd() { - String end = FPSTR(HTTP_END); - - if (_customBodyFooter) { - end = String(_customBodyFooter) + end; - } - - return end; -} - -void WiFiManager::HTTPSend(const String &content){ - server->send(200, FPSTR(HTTP_HEAD_CT), content); -} - -/** - * HTTPD handler for page requests - */ -void WiFiManager::handleRequest() { - _webPortalAccessed = millis(); - - // TESTING HTTPD AUTH RFC 2617 - // BASIC_AUTH will hold onto creds, hard to "logout", but convienent - // DIGEST_AUTH will require new auth often, and nonce is random - // bool authenticate(const char * username, const char * password); - // bool authenticateDigest(const String& username, const String& H1); - // void requestAuthentication(HTTPAuthMethod mode = BASIC_AUTH, const char* realm = NULL, const String& authFailMsg = String("") ); - - // 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){ - #ifndef WM_NOAUTH - server->requestAuthentication(HTTPAuthMethod::BASIC_AUTH); // DIGEST_AUTH - #endif - DEBUG_WM(WM_DEBUG_DEV,F("AUTH FAIL")); - } -} - -/** - * 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 (captivePortal()) return; // If captive portal redirect instead of displaying the page - handleRequest(); - String page = getHTTPHead(_title, FPSTR(C_root)); // @token options @todo replace options with title - String str = FPSTR(HTTP_ROOT_MAIN); // @todo custom title - str.replace(FPSTR(T_t),_title); - str.replace(FPSTR(T_v),configPortalActive ? _apName : (getWiFiHostname() + " - " + WiFi.localIP().toString())); // use ip if ap is not active for heading @todo use hostname? - page += str; - page += FPSTR(HTTP_PORTAL_OPTIONS); - page += getMenuOut(); - reportStatus(page); - page += getHTTPEnd(); - - HTTPSend(page); - if(_preloadwifiscan) WiFi_scanNetworks(_scancachetime,true); // preload wifiscan throttled, async - // @todo buggy, captive portals make a query on every page load, causing this to run every time in addition to the real page load - // I dont understand why, when you are already in the captive portal, I guess they want to know that its still up and not done or gone - // if we can detect these and ignore them that would be great, since they come from the captive portal redirect maybe there is a refferer -} - -/** - * HTTPD CALLBACK Wifi config page handler - */ -void WiFiManager::handleWifi(boolean scan) { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("<- HTTP Wifi")); - #endif - handleRequest(); - String page = getHTTPHead(FPSTR(S_titlewifi), FPSTR(C_wifi)); // @token titlewifi - if (scan) { - #ifdef WM_DEBUG_LEVEL - // DEBUG_WM(WM_DEBUG_DEV,"refresh flag:",server->hasArg(F("refresh"))); - #endif - WiFi_scanNetworks(server->hasArg(F("refresh")),false); //wifiscan, force if arg refresh - page += getScanItemOut(); - } - String pitem = ""; - - pitem = FPSTR(HTTP_FORM_START); - pitem.replace(FPSTR(T_v), F("wifisave")); // set form action - page += pitem; - - pitem = FPSTR(HTTP_FORM_WIFI); - pitem.replace(FPSTR(T_v), WiFi_SSID()); - - if(_showPassword){ - pitem.replace(FPSTR(T_p), WiFi_psk()); - } - else if(WiFi_psk() != ""){ - pitem.replace(FPSTR(T_p),FPSTR(S_passph)); - } - else { - pitem.replace(FPSTR(T_p),""); - } - - page += pitem; - - page += getStaticOut(); - page += FPSTR(HTTP_FORM_WIFI_END); - if(_paramsInWifi && _paramsCount>0){ - page += FPSTR(HTTP_FORM_PARAM_HEAD); - page += getParamOut(); - } - page += FPSTR(HTTP_FORM_END); - page += FPSTR(HTTP_SCAN_LINK); - if(_showBack) page += FPSTR(HTTP_BACKBTN); - reportStatus(page); - page += getHTTPEnd(); - - HTTPSend(page); - - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_DEV,F("Sent config page")); - #endif -} - -/** - * HTTPD CALLBACK Wifi param page handler - */ -void WiFiManager::handleParam(){ - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("<- HTTP Param")); - #endif - handleRequest(); - String page = getHTTPHead(FPSTR(S_titleparam), FPSTR(C_param)); // @token titlewifi - - String pitem = ""; - - pitem = FPSTR(HTTP_FORM_START); - pitem.replace(FPSTR(T_v), F("paramsave")); - page += pitem; - - page += getParamOut(); - page += FPSTR(HTTP_FORM_END); - if(_showBack) page += FPSTR(HTTP_BACKBTN); - reportStatus(page); - page += getHTTPEnd(); - - HTTPSend(page); - - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_DEV,F("Sent param page")); - #endif -} - - -String WiFiManager::getMenuOut(){ - 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? - if((String)_menutokens[menuId] == "custom" && _customMenuHTML!=NULL){ - page += _customMenuHTML; - continue; - } - page += HTTP_PORTAL_MENU[menuId]; - delay(0); - } - - return page; -} - -// // is it possible in softap mode to detect aps without scanning -// bool WiFiManager::WiFi_scanNetworksForAP(bool force){ -// WiFi_scanNetworks(force); -// } - -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 found:"),_numNetworks); - #endif -} - -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); -} -bool WiFiManager::WiFi_scanNetworks(unsigned int cachetime){ - return WiFi_scanNetworks(millis()-_lastscan > cachetime,false); -} -bool WiFiManager::WiFi_scanNetworks(bool force,bool async){ - #ifdef WM_DEBUG_LEVEL - // DEBUG_WM(WM_DEBUG_DEV,"scanNetworks async:",async == true); - // DEBUG_WM(WM_DEBUG_DEV,_numNetworks,(millis()-_lastscan )); - // DEBUG_WM(WM_DEBUG_DEV,"scanNetworks force:",force == true); - #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? - if(_numNetworks == 0 && _autoforcerescan){ - DEBUG_WM(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; - } - - if(force){ - int8_t res; - _startscan = millis(); - if(async && _asyncScan){ - #ifdef ESP8266 - #ifndef WM_NOASYNC // no async available < 2.4.0 - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("WiFi Scan ASYNC started")); - #endif - using namespace std::placeholders; // for `_1` - WiFi.scanNetworksAsync(std::bind(&WiFiManager::WiFi_scanComplete,this,_1)); - #else - DEBUG_WM(WM_DEBUG_VERBOSE,F("WiFi Scan SYNC started")); - res = WiFi.scanNetworks(); - #endif - #else - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("WiFi Scan ASYNC started")); - #endif - res = WiFi.scanNetworks(true); - #endif - return false; - } - else{ - DEBUG_WM(WM_DEBUG_VERBOSE,F("WiFi Scan SYNC started")); - res = WiFi.scanNetworks(); - } - if(res == WIFI_SCAN_FAILED){ - #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")); - #endif - while(WiFi.scanComplete() == WIFI_SCAN_RUNNING){ - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_ERROR,"."); - #endif - delay(100); - } - _numNetworks = WiFi.scanComplete(); - } - else if(res >=0 ) _numNetworks = res; - _lastscan = millis(); - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("WiFi Scan completed"), "in "+(String)(_lastscan - _startscan)+" ms"); - #endif - return true; - } - else { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("Scan is cached"),(String)(millis()-_lastscan )+" ms ago"); - #endif - } - return false; -} - -String WiFiManager::WiFiManager::getScanItemOut(){ - String page; - - 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 - page += FPSTR(S_nonetworks); // @token nonetworks - page += F("

"); - } - else { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(n,F("networks found")); - #endif - //sort networks - int indices[n]; - for (int i = 0; i < n; i++) { - indices[i] = i; - } - - // RSSI SORT - for (int i = 0; i < n; i++) { - for (int j = i + 1; j < n; j++) { - if (WiFi.RSSI(indices[j]) > WiFi.RSSI(indices[i])) { - std::swap(indices[i], indices[j]); - } - } - } - - /* test std:sort - std::sort(indices, indices + n, [](const int & a, const int & b) -> bool - { - return WiFi.RSSI(a) > WiFi.RSSI(b); - }); - */ - - // remove duplicates ( must be RSSI sorted ) - if (_removeDuplicateAPs) { - String cssid; - for (int i = 0; i < n; i++) { - if (indices[i] == -1) continue; - cssid = WiFi.SSID(indices[i]); - for (int j = i + 1; j < n; j++) { - if (cssid == WiFi.SSID(indices[j])) { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("DUP AP:"),WiFi.SSID(indices[j])); - #endif - indices[j] = -1; // set dup aps to index -1 - } - } - } - } - - // token precheck, to speed up replacements on large ap lists - String HTTP_ITEM_STR = FPSTR(HTTP_ITEM); - - // toggle icons with percentage - HTTP_ITEM_STR.replace("{qp}", FPSTR(HTTP_ITEM_QP)); - 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 - - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("AP: "),(String)WiFi.RSSI(indices[i]) + " " + (String)WiFi.SSID(indices[i])); - #endif - - int rssiperc = getRSSIasQuality(WiFi.RSSI(indices[i])); - uint8_t enc_type = WiFi.encryptionType(indices[i]); - - if (_minimumQuality == -1 || _minimumQuality < rssiperc) { - String item = HTTP_ITEM_STR; - if(WiFi.SSID(indices[i]) == ""){ - // 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]),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 - if(tok_q) item.replace(FPSTR(T_q), (String)int(round(map(rssiperc,0,100,1,4)))); //quality icon 1-4 - if(tok_i){ - if (enc_type != WM_WIFIOPEN) { - item.replace(FPSTR(T_i), F("l")); - } else { - item.replace(FPSTR(T_i), ""); - } - } - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_DEV,item); - #endif - page += item; - delay(0); - } else { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("Skipping , does not meet _minimumQuality")); - #endif - } - - } - page += FPSTR(HTTP_BR); - } - - return page; -} - -String WiFiManager::getIpForm(String id, String title, String value){ - String item = FPSTR(HTTP_FORM_LABEL); - item += FPSTR(HTTP_FORM_PARAM); - item.replace(FPSTR(T_i), id); - item.replace(FPSTR(T_n), id); - item.replace(FPSTR(T_p), FPSTR(T_t)); - // item.replace(FPSTR(T_p), default); - item.replace(FPSTR(T_t), title); - item.replace(FPSTR(T_l), F("15")); - item.replace(FPSTR(T_v), value); - item.replace(FPSTR(T_c), ""); - return item; -} - -String WiFiManager::getStaticOut(){ - String page; - if ((_staShowStaticFields || _sta_static_ip) && _staShowStaticFields>=0) { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_DEV,F("_staShowStaticFields")); - #endif - page += FPSTR(HTTP_FORM_STATIC_HEAD); - // @todo how can we get these accurate settings from memory , wifi_get_ip_info does not seem to reveal if struct ip_info is static or not - page += getIpForm(FPSTR(S_ip),FPSTR(S_staticip),(_sta_static_ip ? _sta_static_ip.toString() : "")); // @token staticip - // WiFi.localIP().toString(); - page += getIpForm(FPSTR(S_gw),FPSTR(S_staticgw),(_sta_static_gw ? _sta_static_gw.toString() : "")); // @token staticgw - // WiFi.gatewayIP().toString(); - page += getIpForm(FPSTR(S_sn),FPSTR(S_subnet),(_sta_static_sn ? _sta_static_sn.toString() : "")); // @token subnet - // WiFi.subnetMask().toString(); - } - - if((_staShowDns || _sta_static_dns) && _staShowDns>=0){ - page += getIpForm(FPSTR(S_dns),FPSTR(S_staticdns),(_sta_static_dns ? _sta_static_dns.toString() : "")); // @token dns - } - - if(page!="") page += FPSTR(HTTP_BR); // @todo remove these, use css - - return page; -} - -String WiFiManager::getParamOut(){ - String page; - - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_DEV,F("getParamOut"),_paramsCount); - #endif - - if(_paramsCount > 0){ - - String HTTP_PARAM_temp = FPSTR(HTTP_FORM_LABEL); - HTTP_PARAM_temp += FPSTR(HTTP_FORM_PARAM); - bool tok_I = HTTP_PARAM_temp.indexOf(FPSTR(T_I)) > 0; - bool tok_i = HTTP_PARAM_temp.indexOf(FPSTR(T_i)) > 0; - bool tok_n = HTTP_PARAM_temp.indexOf(FPSTR(T_n)) > 0; - bool tok_p = HTTP_PARAM_temp.indexOf(FPSTR(T_p)) > 0; - bool tok_t = HTTP_PARAM_temp.indexOf(FPSTR(T_t)) > 0; - bool tok_l = HTTP_PARAM_temp.indexOf(FPSTR(T_l)) > 0; - bool tok_v = HTTP_PARAM_temp.indexOf(FPSTR(T_v)) > 0; - bool tok_c = HTTP_PARAM_temp.indexOf(FPSTR(T_c)) > 0; - - char valLength[5]; - - for (int i = 0; i < _paramsCount; i++) { - //Serial.println((String)_params[i]->_length); - if (_params[i] == NULL || _params[i]->_length > 99999) { - // try to detect param scope issues, doesnt always catch but works ok - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_ERROR,F("[ERROR] WiFiManagerParameter is out of scope")); - #endif - return ""; - } - } - - // add the extra parameters to the form - for (int i = 0; i < _paramsCount; i++) { - // label before or after, @todo this could be done via floats or CSS and eliminated - String pitem; - switch (_params[i]->getLabelPlacement()) { - case WFM_LABEL_BEFORE: - pitem = FPSTR(HTTP_FORM_LABEL); - pitem += FPSTR(HTTP_FORM_PARAM); - break; - case WFM_LABEL_AFTER: - pitem = FPSTR(HTTP_FORM_PARAM); - pitem += FPSTR(HTTP_FORM_LABEL); - break; - default: - // WFM_NO_LABEL - pitem = FPSTR(HTTP_FORM_PARAM); - break; - } - - // Input templating - // "
"; - // if no ID use customhtml for item, else generate from param string - if (_params[i]->getID() != NULL) { - if(tok_I)pitem.replace(FPSTR(T_I), (String)FPSTR(S_parampre)+(String)i); // T_I id number - if(tok_i)pitem.replace(FPSTR(T_i), _params[i]->getID()); // T_i id name - if(tok_n)pitem.replace(FPSTR(T_n), _params[i]->getID()); // T_n id name alias - if(tok_p)pitem.replace(FPSTR(T_p), FPSTR(T_t)); // T_p replace legacy placeholder token - if(tok_t)pitem.replace(FPSTR(T_t), _params[i]->getLabel()); // T_t title/label - snprintf(valLength, 5, "%d", _params[i]->getValueLength()); - if(tok_l)pitem.replace(FPSTR(T_l), valLength); // T_l value length - if(tok_v)pitem.replace(FPSTR(T_v), _params[i]->getValue()); // T_v value - if(tok_c)pitem.replace(FPSTR(T_c), _params[i]->getCustomHTML()); // T_c meant for additional attributes, not html, but can stuff - } else { - pitem = _params[i]->getCustomHTML(); - } - - page += pitem; - } - } - - return page; -} - -void WiFiManager::handleWiFiStatus(){ - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("<- HTTP WiFi status ")); - #endif - handleRequest(); - String page; - // String page = "{\"result\":true,\"count\":1}"; - #ifdef WM_JSTEST - page = FPSTR(HTTP_JS); - #endif - HTTPSend(page); -} - -/** - * HTTPD CALLBACK save form and redirect to WLAN config page again - */ -void WiFiManager::handleWifiSave() { - #ifdef WM_DEBUG_LEVEL - 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 - handleRequest(); - - //SAVE/connect here - _ssid = server->arg(F("s")).c_str(); - _pass = server->arg(F("p")).c_str(); - - if(_ssid == "" && _pass != ""){ - _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 - } - - #ifdef WM_DEBUG_LEVEL - String requestinfo = "SERVER_REQUEST\n----------------\n"; - requestinfo += "URI: "; - requestinfo += server->uri(); - requestinfo += "\nMethod: "; - requestinfo += (server->method() == HTTP_GET) ? "GET" : "POST"; - requestinfo += "\nArguments: "; - requestinfo += server->args(); - requestinfo += "\n"; - for (uint8_t i = 0; i < server->args(); i++) { - requestinfo += " " + server->argName(i) + ": " + server->arg(i) + "\n"; - } - - DEBUG_WM(WM_DEBUG_MAX,requestinfo); - #endif - - // set static ips from server args - if (server->arg(FPSTR(S_ip)) != "") { - //_sta_static_ip.fromString(server->arg(FPSTR(S_ip)); - String ip = server->arg(FPSTR(S_ip)); - optionalIPFromString(&_sta_static_ip, ip.c_str()); - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_DEV,F("static ip:"),ip); - #endif - } - if (server->arg(FPSTR(S_gw)) != "") { - String gw = server->arg(FPSTR(S_gw)); - optionalIPFromString(&_sta_static_gw, gw.c_str()); - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_DEV,F("static gateway:"),gw); - #endif - } - if (server->arg(FPSTR(S_sn)) != "") { - String sn = server->arg(FPSTR(S_sn)); - optionalIPFromString(&_sta_static_sn, sn.c_str()); - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_DEV,F("static netmask:"),sn); - #endif - } - if (server->arg(FPSTR(S_dns)) != "") { - String dns = server->arg(FPSTR(S_dns)); - optionalIPFromString(&_sta_static_dns, dns.c_str()); - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_DEV,F("static DNS:"),dns); - #endif - } - - if (_presavewificallback != NULL) { - _presavewificallback(); // @CALLBACK - } - - if(_paramsInWifi) doParamSave(); - - String page; - - if(_ssid == ""){ - page = getHTTPHead(FPSTR(S_titlewifisettings), FPSTR(C_wifi)); // @token titleparamsaved - page += FPSTR(HTTP_PARAMSAVED); - } - else { - page = getHTTPHead(FPSTR(S_titlewifisaved), FPSTR(C_wifi)); // @token titlewifisaved - page += FPSTR(HTTP_SAVED); - } - - if(_showBack) page += FPSTR(HTTP_BACKBTN); - page += getHTTPEnd(); - - server->sendHeader(FPSTR(HTTP_HEAD_CORS), FPSTR(HTTP_HEAD_CORS_ALLOW_ALL)); // @HTTPHEAD send cors - HTTPSend(page); - - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_DEV,F("Sent wifi save page")); - #endif - - connect = true; //signal ready to connect/reset process in processConfigPortal -} - -void WiFiManager::handleParamSave() { - - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("<- HTTP Param save ")); - #endif - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_DEV,F("Method:"),server->method() == HTTP_GET ? (String)FPSTR(S_GET) : (String)FPSTR(S_POST)); - #endif - handleRequest(); - - doParamSave(); - - String page = getHTTPHead(FPSTR(S_titleparamsaved), FPSTR(C_param)); // @token titleparamsaved - page += FPSTR(HTTP_PARAMSAVED); - if(_showBack) page += FPSTR(HTTP_BACKBTN); - page += getHTTPEnd(); - - HTTPSend(page); - - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_DEV,F("Sent param save page")); - #endif -} - -void WiFiManager::doParamSave(){ - // @todo use new callback for before paramsaves, is this really needed? - if ( _presaveparamscallback != NULL) { - _presaveparamscallback(); // @CALLBACK - } - - //parameters - if(_paramsCount > 0){ - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("Parameters")); - DEBUG_WM(WM_DEBUG_VERBOSE,FPSTR(D_HR)); - #endif - - for (int i = 0; i < _paramsCount; i++) { - if (_params[i] == NULL || _params[i]->_length > 99999) { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_ERROR,F("[ERROR] WiFiManagerParameter is out of scope")); - #endif - break; // @todo might not be needed anymore - } - //read parameter from server - String name = (String)FPSTR(S_parampre)+(String)i; - String value; - if(server->hasArg(name)) { - value = server->arg(name); - } else { - value = server->arg(_params[i]->getID()); - } - - //store it in params array - value.toCharArray(_params[i]->_value, _params[i]->_length+1); // length+1 null terminated - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,(String)_params[i]->getID() + ":",value); - #endif - } - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,FPSTR(D_HR)); - #endif - } - - 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 - handleRequest(); - String page = getHTTPHead(FPSTR(S_titleinfo), FPSTR(C_info)); // @token titleinfo - reportStatus(page); - - uint16_t infos = 0; - - //@todo convert to enum or refactor to strings - //@todo wrap in build flag to remove all info code for memory saving - #ifdef ESP8266 - infos = 28; - String infoids[] = { - F("esphead"), - F("uptime"), - F("chipid"), - F("fchipid"), - F("idesize"), - F("flashsize"), - F("corever"), - F("bootver"), - F("cpufreq"), - F("freeheap"), - F("memsketch"), - F("memsmeter"), - F("lastreset"), - F("wifihead"), - F("conx"), - F("stassid"), - F("staip"), - F("stagw"), - F("stasub"), - F("dnss"), - F("host"), - F("stamac"), - F("autoconx"), - F("wifiaphead"), - F("apssid"), - F("apip"), - F("apbssid"), - F("apmac") - }; - - #elif defined(ESP32) - // add esp_chip_info ? - infos = 27; - String infoids[] = { - F("esphead"), - F("uptime"), - F("chipid"), - F("chiprev"), - F("idesize"), - F("flashsize"), - F("cpufreq"), - F("freeheap"), - F("memsketch"), - F("memsmeter"), - F("lastreset"), - F("temp"), - // F("hall"), - F("wifihead"), - F("conx"), - F("stassid"), - F("staip"), - F("stagw"), - F("stasub"), - F("dnss"), - F("host"), - F("stamac"), - F("apssid"), - F("wifiaphead"), - F("apip"), - F("apmac"), - F("aphost"), - F("apbssid") - }; - #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]; - } - if(_showInfoErase) page += FPSTR(HTTP_ERASEBTN); - if(_showBack) page += FPSTR(HTTP_BACKBTN); - page += FPSTR(HTTP_HELP); - page += getHTTPEnd(); - - HTTPSend(page); - - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_DEV,F("Sent info page")); - #endif -} - -String WiFiManager::getInfoData(String id){ - - String p; - 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); - p.replace(FPSTR(T_1),(String)(millis() / 1000 / 60)); - p.replace(FPSTR(T_2),(String)((millis() / 1000) % 60)); - } - else if(id==F("chipid")){ - p = FPSTR(HTTP_INFO_chipid); - p.replace(FPSTR(T_1),String(WIFI_getChipId(),HEX)); - } - #ifdef ESP32 - else if(id==F("chiprev")){ - p = FPSTR(HTTP_INFO_chiprev); - String rev = (String)ESP.getChipRevision(); - #ifdef _SOC_EFUSE_REG_H_ - String revb = (String)(REG_READ(EFUSE_BLK0_RDATA3_REG) >> (EFUSE_RD_CHIP_VER_RESERVE_S)&&EFUSE_RD_CHIP_VER_RESERVE_V); - p.replace(FPSTR(T_1),rev+"
"+revb); - #else - p.replace(FPSTR(T_1),rev); - #endif - } - #endif - #ifdef ESP8266 - else if(id==F("fchipid")){ - p = FPSTR(HTTP_INFO_fchipid); - p.replace(FPSTR(T_1),(String)ESP.getFlashChipId()); - } - #endif - else if(id==F("idesize")){ - p = FPSTR(HTTP_INFO_idesize); - p.replace(FPSTR(T_1),(String)ESP.getFlashChipSize()); - } - else if(id==F("flashsize")){ - #ifdef ESP8266 - p = FPSTR(HTTP_INFO_flashsize); - p.replace(FPSTR(T_1),(String)ESP.getFlashChipRealSize()); - #elif defined ESP32 - p = FPSTR(HTTP_INFO_psrsize); - 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 - } - #ifdef ESP8266 - else if(id==F("bootver")){ - p = FPSTR(HTTP_INFO_bootver); - p.replace(FPSTR(T_1),(String)system_get_boot_version()); - } - #endif - else if(id==F("cpufreq")){ - p = FPSTR(HTTP_INFO_cpufreq); - p.replace(FPSTR(T_1),(String)ESP.getCpuFreqMHz()); - } - else if(id==F("freeheap")){ - p = FPSTR(HTTP_INFO_freeheap); - p.replace(FPSTR(T_1),(String)ESP.getFreeHeap()); - } - else if(id==F("memsketch")){ - p = FPSTR(HTTP_INFO_memsketch); - p.replace(FPSTR(T_1),(String)(ESP.getSketchSize())); - p.replace(FPSTR(T_2),(String)(ESP.getSketchSize()+ESP.getFreeSketchSpace())); - } - else if(id==F("memsmeter")){ - p = FPSTR(HTTP_INFO_memsmeter); - p.replace(FPSTR(T_1),(String)(ESP.getSketchSize())); - p.replace(FPSTR(T_2),(String)(ESP.getSketchSize()+ESP.getFreeSketchSpace())); - } - else if(id==F("lastreset")){ - #ifdef ESP8266 - p = FPSTR(HTTP_INFO_lastreset); - p.replace(FPSTR(T_1),(String)ESP.getResetReason()); - #elif defined(ESP32) && defined(_ROM_RTC_H_) - // requires #include - p = FPSTR(HTTP_INFO_lastreset); - for(int i=0;i<2;i++){ - int reason = rtc_get_reset_reason(i); - String tok = (String)T_ss+(String)(i+1)+(String)T_es; - switch (reason) - { - //@todo move to array - case 1 : p.replace(tok,F("Vbat power on reset"));break; - case 3 : p.replace(tok,F("Software reset digital core"));break; - case 4 : p.replace(tok,F("Legacy watch dog reset digital core"));break; - case 5 : p.replace(tok,F("Deep Sleep reset digital core"));break; - case 6 : p.replace(tok,F("Reset by SLC module, reset digital core"));break; - case 7 : p.replace(tok,F("Timer Group0 Watch dog reset digital core"));break; - case 8 : p.replace(tok,F("Timer Group1 Watch dog reset digital core"));break; - case 9 : p.replace(tok,F("RTC Watch dog Reset digital core"));break; - case 10 : p.replace(tok,F("Instrusion tested to reset CPU"));break; - case 11 : p.replace(tok,F("Time Group reset CPU"));break; - case 12 : p.replace(tok,F("Software reset CPU"));break; - case 13 : p.replace(tok,F("RTC Watch dog Reset CPU"));break; - case 14 : p.replace(tok,F("for APP CPU, reseted by PRO CPU"));break; - case 15 : p.replace(tok,F("Reset when the vdd voltage is not stable"));break; - case 16 : p.replace(tok,F("RTC Watch dog reset digital core and rtc module"));break; - default : p.replace(tok,F("NO_MEAN")); - } - } - #endif - } - else if(id==F("apip")){ - p = FPSTR(HTTP_INFO_apip); - p.replace(FPSTR(T_1),WiFi.softAPIP().toString()); - } - else if(id==F("apmac")){ - p = FPSTR(HTTP_INFO_apmac); - p.replace(FPSTR(T_1),(String)WiFi.softAPmacAddress()); - } - #ifdef ESP32 - else if(id==F("aphost")){ - p = FPSTR(HTTP_INFO_aphost); - 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()); - } - // softAPgetHostname // esp32 - // softAPSubnetCIDR - // softAPNetworkID - // softAPBroadcastIP - - else if(id==F("stassid")){ - p = FPSTR(HTTP_INFO_stassid); - p.replace(FPSTR(T_1),htmlEntities((String)WiFi_SSID())); - } - else if(id==F("staip")){ - p = FPSTR(HTTP_INFO_staip); - p.replace(FPSTR(T_1),WiFi.localIP().toString()); - } - else if(id==F("stagw")){ - p = FPSTR(HTTP_INFO_stagw); - p.replace(FPSTR(T_1),WiFi.gatewayIP().toString()); - } - else if(id==F("stasub")){ - p = FPSTR(HTTP_INFO_stasub); - p.replace(FPSTR(T_1),WiFi.subnetMask().toString()); - } - else if(id==F("dnss")){ - p = FPSTR(HTTP_INFO_dnss); - p.replace(FPSTR(T_1),WiFi.dnsIP().toString()); - } - else if(id==F("host")){ - p = FPSTR(HTTP_INFO_host); - #ifdef ESP32 - p.replace(FPSTR(T_1),WiFi.getHostname()); - #else - p.replace(FPSTR(T_1),WiFi.hostname()); - #endif - } - else if(id==F("stamac")){ - p = FPSTR(HTTP_INFO_stamac); - p.replace(FPSTR(T_1),WiFi.macAddress()); - } - else if(id==F("conx")){ - p = FPSTR(HTTP_INFO_conx); - p.replace(FPSTR(T_1),WiFi.isConnected() ? FPSTR(S_y) : FPSTR(S_n)); - } - #ifdef ESP8266 - else if(id==F("autoconx")){ - p = FPSTR(HTTP_INFO_autoconx); - p.replace(FPSTR(T_1),WiFi.getAutoConnect() ? FPSTR(S_enable) : FPSTR(S_disable)); - } - #endif - #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.8f)); - } - // 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 - // } - #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; -} - -/** - * 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 - handleRequest(); - String page = getHTTPHead(FPSTR(S_titleexit), FPSTR(C_exit)); // @token titleexit - page += FPSTR(S_exiting); // @token exiting - page += getHTTPEnd(); - // ('Logout', 401, {'WWW-Authenticate': 'Basic realm="Login required"'}) - server->sendHeader(F("Cache-Control"), F("no-cache, no-store, must-revalidate")); // @HTTPHEAD send cache - HTTPSend(page); - delay(2000); - abort = true; -} - -/** - * HTTPD CALLBACK reset page - */ -void WiFiManager::handleReset() { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("<- HTTP Reset")); - #endif - handleRequest(); - String page = getHTTPHead(FPSTR(S_titlereset), FPSTR(C_restart)); //@token titlereset - page += FPSTR(S_resetting); //@token resetting - page += getHTTPEnd(); - - HTTPSend(page); - - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("RESETTING ESP")); - #endif - delay(1000); - reboot(); -} - -/** - * HTTPD CALLBACK erase page - */ - -// void WiFiManager::handleErase() { -// handleErase(false); -// } -void WiFiManager::handleErase(boolean opt) { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_NOTIFY,F("<- HTTP Erase")); - #endif - handleRequest(); - String page = getHTTPHead(FPSTR(S_titleerase), FPSTR(C_erase)); // @token titleerase - - bool ret = erase(opt); - - if(ret) page += FPSTR(S_resetting); // @token resetting - else { - page += FPSTR(S_error); // @token erroroccur - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_ERROR,F("[ERROR] WiFi EraseConfig failed")); - #endif - } - - page += getHTTPEnd(); - HTTPSend(page); - - if(ret){ - delay(2000); - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("RESETTING ESP")); - #endif - reboot(); - } -} - -/** - * HTTPD CALLBACK 404 - */ -void WiFiManager::handleNotFound() { - if (captivePortal()) return; // If captive portal redirect instead of displaying the page - handleRequest(); - String message = FPSTR(S_notfound); // @token notfound - - bool verbose404 = false; // show info in 404 body, uri,method, args - if(verbose404){ - message += FPSTR(S_uri); // @token uri - message += server->uri(); - message += FPSTR(S_method); // @token method - message += ( server->method() == HTTP_GET ) ? FPSTR(S_GET) : FPSTR(S_POST); - message += FPSTR(S_args); // @token args - message += server->args(); - message += F("\n"); - - for ( uint8_t i = 0; i < server->args(); i++ ) { - message += " " + server->argName ( i ) + ": " + server->arg ( i ) + "\n"; - } - } - server->sendHeader(F("Cache-Control"), F("no-cache, no-store, must-revalidate")); // @HTTPHEAD send cache - server->sendHeader(F("Pragma"), F("no-cache")); - server->sendHeader(F("Expires"), F("-1")); - server->send ( 404, FPSTR(HTTP_HEAD_CT2), message ); -} - -/** - * 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. - */ -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()); - - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_DEV,"-> " + server->hostHeader()); - DEBUG_WM(WM_DEBUG_DEV,"serverLoc " + serverLoc); - #endif - - // fallback for ipv6 bug - if(serverLoc == "0.0.0.0"){ - if ((WiFi.status()) != WL_CONNECTED) - serverLoc = toStringIp(WiFi.softAPIP()); - 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")); - DEBUG_WM(WM_DEBUG_DEV,"serverLoc " + serverLoc); - #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 - return true; - } - return false; -} - -void WiFiManager::stopCaptivePortal(){ - _enableCaptivePortal= false; - // @todo maybe disable configportaltimeout(optional), or just provide callback for user -} - -// HTTPD CALLBACK, handle close, stop captive portal, if not enabled undefined -void WiFiManager::handleClose(){ - DEBUG_WM(WM_DEBUG_VERBOSE,F("Disabling Captive Portal")); - stopCaptivePortal(); - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("<- HTTP close")); - #endif - handleRequest(); - String page = getHTTPHead(FPSTR(S_titleclose), FPSTR(C_close)); // @token titleclose - page += FPSTR(S_closing); // @token closing - page += getHTTPEnd(); - HTTPSend(page); -} - -void WiFiManager::reportStatus(String &page){ - // updateConxResult(WiFi.status()); // @todo: this defeats the purpose of last result, update elsewhere or add logic here - DEBUG_WM(WM_DEBUG_DEV,F("[WIFI] reportStatus prev:"),getWLStatusString(_lastconxresult)); - DEBUG_WM(WM_DEBUG_DEV,F("[WIFI] reportStatus current:"),getWLStatusString(WiFi.status())); - String str; - if (WiFi_SSID() != ""){ - if (WiFi.status()==WL_CONNECTED){ - str = FPSTR(HTTP_STATUS_ON); - str.replace(FPSTR(T_i),WiFi.localIP().toString()); - str.replace(FPSTR(T_v),htmlEntities(WiFi_SSID())); - } - else { - str = FPSTR(HTTP_STATUS_OFF); - str.replace(FPSTR(T_v),htmlEntities(WiFi_SSID())); - if(_lastconxresult == WL_STATION_WRONG_PASSWORD){ - // wrong password - str.replace(FPSTR(T_c),"D"); // class - str.replace(FPSTR(T_r),FPSTR(HTTP_STATUS_OFFPW)); - } - else if(_lastconxresult == WL_NO_SSID_AVAIL){ - // connect failed, or ap not found - str.replace(FPSTR(T_c),"D"); - str.replace(FPSTR(T_r),FPSTR(HTTP_STATUS_OFFNOAP)); - } - else if(_lastconxresult == WL_CONNECT_FAILED){ - // connect failed - str.replace(FPSTR(T_c),"D"); - str.replace(FPSTR(T_r),FPSTR(HTTP_STATUS_OFFFAIL)); - } - else if(_lastconxresult == WL_CONNECTION_LOST){ - // connect failed, MOST likely 4WAY_HANDSHAKE_TIMEOUT/incorrect password, state is ambiguous however - str.replace(FPSTR(T_c),"D"); - str.replace(FPSTR(T_r),FPSTR(HTTP_STATUS_OFFFAIL)); - } - else{ - str.replace(FPSTR(T_c),""); - str.replace(FPSTR(T_r),""); - } - } - } - else { - str = FPSTR(HTTP_STATUS_NONE); - } - page += str; -} - -// PUBLIC - -// METHODS - -/** - * reset wifi settings, clean stored ap password - */ - -/** - * [stopConfigPortal description] - * @return {[type]} [description] - */ -bool WiFiManager::stopConfigPortal(){ - if(_configPortalIsBlocking){ - abort = true; - return true; - } - return shutdownConfigPortal(); -} - -/** - * disconnect - * @access public - * @since $dev - * @return bool success - */ -bool WiFiManager::disconnect(){ - if(WiFi.status() != WL_CONNECTED){ - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("Disconnecting: Not connected")); - #endif - return false; - } - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("Disconnecting")); - #endif - return WiFi_Disconnect(); -} - -/** - * reboot the device - * @access public - */ -void WiFiManager::reboot(){ - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("Restarting")); - #endif - ESP.restart(); -} - -/** - * reboot the device - * @access public - */ -bool WiFiManager::erase(){ - return erase(false); -} - -bool WiFiManager::erase(bool opt){ - #ifdef WM_DEBUG_LEVEL - DEBUG_WM("Erasing"); - #endif - - #if defined(ESP32) && ((defined(WM_ERASE_NVS) || defined(nvs_flash_h))) - // if opt true, do nvs erase - if(opt){ - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("Erasing NVS")); - #endif - esp_err_t err; - err = nvs_flash_init(); - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("nvs_flash_init: "),err!=ESP_OK ? (String)err : "Success"); - #endif - err = nvs_flash_erase(); - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("nvs_flash_erase: "), err!=ESP_OK ? (String)err : "Success"); - #endif - return err == ESP_OK; - } - #elif defined(ESP8266) && defined(spiffs_api_h) - if(opt){ - bool ret = false; - if(SPIFFS.begin()){ - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("Erasing SPIFFS")); - #endif - bool ret = SPIFFS.format(); - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("spiffs erase: "),ret ? "Success" : "ERROR"); - #endif - } else{ - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("[ERROR] Could not start SPIFFS")); - #endif - } - return ret; - } - #else - (void)opt; - #endif - - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("Erasing WiFi Config")); - #endif - return WiFi_eraseConfig(); -} - -/** - * [resetSettings description] - * ERASES STA CREDENTIALS - * @access public - */ -void WiFiManager::resetSettings() { -#ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("resetSettings")); - #endif - WiFi_enableSTA(true,true); // must be sta to disconnect erase - delay(500); // ensure sta is enabled - if (_resetcallback != NULL){ - _resetcallback(); // @CALLBACK - } - - #ifdef ESP32 - WiFi.disconnect(true,true); - #else - WiFi.persistent(true); - WiFi.disconnect(true); - WiFi.persistent(false); - #endif - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("SETTINGS ERASED")); - #endif -} - -// SETTERS - -/** - * [setTimeout description] - * @access public - * @param {[type]} unsigned long seconds [description] - */ -void WiFiManager::setTimeout(unsigned long seconds) { - setConfigPortalTimeout(seconds); -} - -/** - * [setConfigPortalTimeout description] - * @access public - * @param {[type]} unsigned long seconds [description] - */ -void WiFiManager::setConfigPortalTimeout(unsigned long seconds) { - _configPortalTimeout = seconds * 1000; -} - -/** - * [setConnectTimeout description] - * @access public - * @param {[type]} unsigned long seconds [description] - */ -void WiFiManager::setConnectTimeout(unsigned long seconds) { - _connectTimeout = seconds * 1000; -} - -/** - * [setConnectRetries description] - * @access public - * @param {[type]} uint8_t numRetries [description] - */ -void WiFiManager::setConnectRetries(uint8_t numRetries){ - _connectRetries = constrain(numRetries,1,10); -} - -/** - * toggle _cleanconnect, always disconnect before connecting - * @param {[type]} bool enable [description] - */ -void WiFiManager::setCleanConnect(bool enable){ - _cleanConnect = enable; -} - -/** - * [setConnectTimeout description - * @access public - * @param {[type]} unsigned long seconds [description] - */ -void WiFiManager::setSaveConnectTimeout(unsigned long seconds) { - _saveTimeout = seconds * 1000; -} - -/** - * Set save portal connect on save option, - * if false, will only save credentials not connect - * @access public - * @param {[type]} bool connect [description] - */ -void WiFiManager::setSaveConnect(bool connect) { - _connectonsave = connect; -} - -/** - * [setDebugOutput description] - * @access public - * @param {[type]} boolean debug [description] - */ -void WiFiManager::setDebugOutput(boolean debug) { - _debug = debug; - if(_debug && _debugLevel == WM_DEBUG_DEV) debugPlatformInfo(); - if(_debug && _debugLevel >= WM_DEBUG_NOTIFY)DEBUG_WM((__FlashStringHelper *)WM_VERSION_STR," D:"+String(_debugLevel)); -} - -void WiFiManager::setDebugOutput(boolean debug, String prefix) { - _debugPrefix = prefix; - setDebugOutput(debug); -} - -void WiFiManager::setDebugOutput(boolean debug, wm_debuglevel_t level) { - _debugLevel = level; - // _debugPrefix = prefix; - setDebugOutput(debug); -} - - -/** - * [setAPStaticIPConfig description] - * @access public - * @param {[type]} IPAddress ip [description] - * @param {[type]} IPAddress gw [description] - * @param {[type]} IPAddress sn [description] - */ -void WiFiManager::setAPStaticIPConfig(IPAddress ip, IPAddress gw, IPAddress sn) { - _ap_static_ip = ip; - _ap_static_gw = gw; - _ap_static_sn = sn; -} - -/** - * [setSTAStaticIPConfig description] - * @access public - * @param {[type]} IPAddress ip [description] - * @param {[type]} IPAddress gw [description] - * @param {[type]} IPAddress sn [description] - */ -void WiFiManager::setSTAStaticIPConfig(IPAddress ip, IPAddress gw, IPAddress sn) { - _sta_static_ip = ip; - _sta_static_gw = gw; - _sta_static_sn = sn; -} - -/** - * [setSTAStaticIPConfig description] - * @since $dev - * @access public - * @param {[type]} IPAddress ip [description] - * @param {[type]} IPAddress gw [description] - * @param {[type]} IPAddress sn [description] - * @param {[type]} IPAddress dns [description] - */ -void WiFiManager::setSTAStaticIPConfig(IPAddress ip, IPAddress gw, IPAddress sn, IPAddress dns) { - setSTAStaticIPConfig(ip,gw,sn); - _sta_static_dns = dns; -} - -/** - * [setMinimumSignalQuality description] - * @access public - * @param {[type]} int quality [description] - */ -void WiFiManager::setMinimumSignalQuality(int quality) { - _minimumQuality = quality; -} - -/** - * [setBreakAfterConfig description] - * @access public - * @param {[type]} boolean shouldBreak [description] - */ -void WiFiManager::setBreakAfterConfig(boolean shouldBreak) { - _shouldBreakAfterConfig = shouldBreak; -} - -/** - * setAPCallback, set a callback when softap is started - * @access public - * @param {[type]} void (*func)(WiFiManager* wminstance) - */ -void WiFiManager::setAPCallback( std::function func ) { - _apcallback = 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 - * @param {[type]} void (*func)(void) - */ -void WiFiManager::setWebServerCallback( std::function func ) { - _webservercallback = func; -} - -/** - * setSaveConfigCallback, set a save config callback after closing configportal - * @note calls only if wifi is saved or changed, or setBreakAfterConfig(true) - * @access public - * @param {[type]} void (*func)(void) - */ -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 - * @param {[type]} void(*func)(void) - */ -void WiFiManager::setConfigResetCallback( std::function func ) { - _resetcallback = func; -} - -/** - * setSaveParamsCallback, set a save params callback on params save in wifi or params pages - * @access public - * @param {[type]} void (*func)(void) - */ -void WiFiManager::setSaveParamsCallback( std::function func ) { - _saveparamscallback = func; -} - -/** - * setPreSaveParamsCallback, set a pre save params callback on params save prior to anything else - * @access public - * @param {[type]} void (*func)(void) - */ -void WiFiManager::setPreSaveParamsCallback( std::function func ) { - _presaveparamscallback = func; -} - -/** - * setPreOtaUpdateCallback, set a callback to fire before OTA update - * @access public - * @param {[type]} void (*func)(void) - */ -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 meta,style,script tag etc. - * @access public - * @param char element - */ -void WiFiManager::setCustomHeadElement(const char* html) { - _customHeadElement = html; -} - -/** - * set custom html at the top of the body - * custom element will be added after the body tag is opened, eg. to show a logo etc. - * @access public - * @param char element - */ -void WiFiManager::setCustomBodyHeader(const char* html) { - _customBodyHeader = html; -} - -/** - * set custom html at the bottom of the body - * custom element will be added before the body tag is closed - * @access public - * @param char element - */ -void WiFiManager::setCustomBodyFooter(const char* html) { - _customBodyFooter = 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; -} - -/** - * toggle wifiscan hiding of duplicate ssid names - * if this is false, wifiscan will remove duplicat Access Points - defaut true - * @access public - * @param boolean removeDuplicates [true] - */ -void WiFiManager::setRemoveDuplicateAPs(boolean removeDuplicates) { - _removeDuplicateAPs = removeDuplicates; -} - -/** - * toggle configportal blocking loop - * if enabled, then the configportal will enter a blocking loop and wait for configuration - * if disabled use with process() to manually process webserver - * @since $dev - * @access public - * @param boolean shoudlBlock [false] - */ -void WiFiManager::setConfigPortalBlocking(boolean shouldBlock) { - _configPortalIsBlocking = shouldBlock; -} - -/** - * toggle restore persistent, track internally - * sets ESP wifi.persistent so we can remember it and restore user preference on destruct - * there is no getter in esp8266 platform prior to https://github.com/esp8266/Arduino/pull/3857 - * @since $dev - * @access public - * @param boolean persistent [true] - */ -void WiFiManager::setRestorePersistent(boolean persistent) { - _userpersistent = persistent; - if(!persistent){ - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("persistent is off")); - #endif - } -} - -/** - * toggle showing static ip form fields - * if enabled, then the static ip, gateway, subnet fields will be visible, even if not set in code - * @since $dev - * @access public - * @param boolean alwaysShow [false] - */ -void WiFiManager::setShowStaticFields(boolean alwaysShow){ - if(_disableIpFields) _staShowStaticFields = alwaysShow ? 1 : -1; - else _staShowStaticFields = alwaysShow ? 1 : 0; -} - -/** - * toggle showing dns fields - * if enabled, then the dns1 field will be visible, even if not set in code - * @since $dev - * @access public - * @param boolean alwaysShow [false] - */ -void WiFiManager::setShowDnsFields(boolean alwaysShow){ - if(_disableIpFields) _staShowDns = alwaysShow ? 1 : -1; - else _staShowDns = alwaysShow ? 1 : 0; -} - -/** - * toggle showing password in wifi password field - * if not enabled, placeholder will be S_passph - * @since $dev - * @access public - * @param boolean alwaysShow [false] - */ -void WiFiManager::setShowPassword(boolean show){ - _showPassword = show; -} - -/** - * toggle captive portal - * if enabled, then devices that use captive portal checks will be redirected to root - * if not you will automatically have to navigate to ip [192.168.4.1] - * @since $dev - * @access public - * @param boolean enabled [true] - */ -void WiFiManager::setCaptivePortalEnable(boolean enabled){ - _enableCaptivePortal = enabled; -} - -/** - * toggle wifi autoreconnect policy - * if enabled, then wifi will autoreconnect automatically always - * On esp8266 we force this on when autoconnect is called, see notes - * On esp32 this is handled on SYSTEM_EVENT_STA_DISCONNECTED since it does not exist in core yet - * @since $dev - * @access public - * @param boolean enabled [true] - */ -void WiFiManager::setWiFiAutoReconnect(boolean enabled){ - _wifiAutoReconnect = enabled; -} - -/** - * toggle configportal timeout wait for station client - * if enabled, then the configportal will start timeout when no stations are connected to softAP - * disabled by default as rogue stations can keep it open if there is no auth - * @since $dev - * @access public - * @param boolean enabled [false] - */ -void WiFiManager::setAPClientCheck(boolean enabled){ - _apClientCheck = enabled; -} - -/** - * toggle configportal timeout wait for web client - * if enabled, then the configportal will restart timeout when client requests come in - * @since $dev - * @access public - * @param boolean enabled [true] - */ -void WiFiManager::setWebPortalClientCheck(boolean enabled){ - _webClientCheck = enabled; -} - -/** - * toggle wifiscan percentages or quality icons - * @since $dev - * @access public - * @param boolean enabled [false] - */ -void WiFiManager::setScanDispPerc(boolean enabled){ - _scanDispOptions = enabled; -} - -/** - * toggle configportal if autoconnect failed - * if enabled, then the configportal will be activated on autoconnect failure - * @since $dev - * @access public - * @param boolean enabled [true] - */ -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) - * @since $dev - * @access public - * @param char* hostname 32 character hostname to use for sta+ap in esp32, sta in esp8266 - * @return bool false if hostname is not valid - */ -bool WiFiManager::setHostname(const char * hostname){ - //@todo max length 32 - _hostname = String(hostname); - return true; -} - -bool WiFiManager::setHostname(String hostname){ - //@todo max length 32 - _hostname = hostname; - return true; -} - -/** - * set the soft ao channel, ignored if channelsync is true and connected - * @param int32_t wifi channel, 0 to disable - */ -void WiFiManager::setWiFiAPChannel(int32_t channel){ - _apChannel = channel; -} - -/** - * set the soft ap hidden - * @param bool wifi ap hidden, default is false - */ -void WiFiManager::setWiFiAPHidden(bool hidden){ - _apHidden = hidden; -} - - -/** - * toggle showing erase wifi config button on info page - * @param boolean enabled - */ -void WiFiManager::setShowInfoErase(boolean enabled){ - _showInfoErase = enabled; -} - -/** - * toggle showing update upload web ota button on info page - * @param boolean enabled - */ -void WiFiManager::setShowInfoUpdate(boolean enabled){ - _showInfoUpdate = enabled; -} - -/** - * check if the config portal is running - * @return bool true if active - */ -bool WiFiManager::getConfigPortalActive(){ - return configPortalActive; -} - -/** - * [getConfigPortalActive description] - * @return bool true if active - */ -bool WiFiManager::getWebPortalActive(){ - return webPortalActive; -} - - -String WiFiManager::getWiFiHostname(){ - #ifdef ESP32 - return (String)WiFi.getHostname(); - #else - return (String)WiFi.hostname(); - #endif -} - -/** - * [setTitle description] - * @param String title, set app title - */ -void WiFiManager::setTitle(String title){ - _title = title; -} - -/** - * set menu items and order - * if param is present in menu , params will be removed from wifi page automatically - * eg. - * const char * menu[] = {"wifi","setup","sep","info","exit"}; - * WiFiManager.setMenu(menu); - * @since $dev - * @param uint8_t menu[] array of menu ids - */ -void WiFiManager::setMenu(const char * menu[], uint8_t size){ -#ifdef WM_DEBUG_LEVEL - // DEBUG_WM(WM_DEBUG_DEV,"setmenu array"); - #endif - _menuIds.clear(); - for(size_t i = 0; i < size; i++){ - for(size_t j = 0; j < _nummenutokens; j++){ - if((String)menu[i] == (__FlashStringHelper *)(_menutokens[j])){ - if((String)menu[i] == "param") _paramsInWifi = false; // param auto flag - _menuIds.push_back(j); - } - delay(0); - } - delay(0); - } - #ifdef WM_DEBUG_LEVEL - // DEBUG_WM(getMenuOut()); - #endif -} - -/** - * setMenu with vector - * eg. - * std::vector menu = {"wifi","setup","sep","info","exit"}; - * WiFiManager.setMenu(menu); - * tokens can be found in _menutokens array in strings_en.h - * @shiftIncrement $dev - * @param {[type]} std::vector& menu [description] - */ -void WiFiManager::setMenu(std::vector& menu){ -#ifdef WM_DEBUG_LEVEL - // DEBUG_WM(WM_DEBUG_DEV,"setmenu vector"); - #endif - _menuIds.clear(); - for(auto menuitem : menu ){ - for(size_t j = 0; j < _nummenutokens; j++){ - if((String)menuitem == (__FlashStringHelper *)(_menutokens[j])){ - if((String)menuitem == "param") _paramsInWifi = false; // param auto flag - _menuIds.push_back(j); - } - } - } - #ifdef WM_DEBUG_LEVEL - // DEBUG_WM(WM_DEBUG_DEV,getMenuOut()); - #endif -} - - -/** - * set params as sperate page not in wifi - * NOT COMPATIBLE WITH setMenu! - * @todo scan menuids and insert param after wifi or something, same for ota - * @param bool enable - * @since $dev - */ -void WiFiManager::setParamsPage(bool enable){ - _paramsInWifi = !enable; - setMenu(enable ? _menuIdsParams : _menuIdsDefault); -} - -// GETTERS - -/** - * get config portal AP SSID - * @since 0.0.1 - * @access public - * @return String the configportal ap name - */ -String WiFiManager::getConfigPortalSSID() { - return _apName; -} - -/** - * return the last known connection result - * logged on autoconnect and wifisave, can be used to check why failed - * get as readable string with getWLStatusString(getLastConxResult); - * @since $dev - * @access public - * @return bool return wl_status codes - */ -uint8_t WiFiManager::getLastConxResult(){ - return _lastconxresult; -} - -/** - * check if wifi has a saved ap or not - * @since $dev - * @access public - * @return bool true if a saved ap config exists - */ -bool WiFiManager::getWiFiIsSaved(){ - return WiFi_hasAutoConnect(); -} - -/** - * getDefaultAPName - * @since $dev - * @return string - */ -String WiFiManager::getDefaultAPName(){ - String hostString = String(WIFI_getChipId(),HEX); - hostString.toUpperCase(); - // char hostString[16] = {0}; - // sprintf(hostString, "%06X", ESP.getChipId()); - return _wifissidprefix + "_" + hostString; -} - -/** - * setCountry - * @since $dev - * @param String cc country code, must be defined in WiFiSetCountry, US, JP, CN - */ -void WiFiManager::setCountry(String cc){ - _wificountry = cc; -} - -/** - * setClass - * @param String str body class string - */ -void WiFiManager::setClass(String str){ - _bodyClass = str; -} - -/** - * setDarkMode - * @param bool enable, enable dark mode via invert class - */ -void WiFiManager::setDarkMode(bool enable){ - _bodyClass = enable ? "invert" : ""; -} - -/** - * setHttpPort - * @param uint16_t port webserver port number default 80 - */ -void WiFiManager::setHttpPort(uint16_t port){ - _httpPort = port; -} - - -bool WiFiManager::preloadWiFi(String ssid, String pass){ - _defaultssid = ssid; - _defaultpass = pass; - return true; -} - -// HELPERS - -/** - * getWiFiSSID - * @since $dev - * @param bool persistent - * @return String - */ -String WiFiManager::getWiFiSSID(bool persistent){ - return WiFi_SSID(persistent); -} - -/** - * getWiFiPass - * @since $dev - * @param bool persistent - * @return String - */ -String WiFiManager::getWiFiPass(bool persistent){ - return WiFi_psk(persistent); -} - -// DEBUG -// @todo fix DEBUG_WM(0,0); -template -void WiFiManager::DEBUG_WM(Generic text) { - DEBUG_WM(WM_DEBUG_NOTIFY,text,""); -} - -template -void WiFiManager::DEBUG_WM(wm_debuglevel_t level,Generic text) { - if(_debugLevel >= level) DEBUG_WM(level,text,""); -} - -template -void WiFiManager::DEBUG_WM(Generic text,Genericb textb) { - DEBUG_WM(WM_DEBUG_NOTIFY,text,textb); -} - -template -void WiFiManager::DEBUG_WM(wm_debuglevel_t level,Generic text,Genericb textb) { - if(!_debug || _debugLevel < level) return; - - if(_debugLevel >= WM_DEBUG_MAX){ - #ifdef ESP8266 - // uint32_t free; - // 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); - #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. - // largest_free_block; ///< Size of largest free block in the heap. This is the largest malloc-able size. - // minimum_free_bytes; ///< Lifetime minimum free heap size. Equivalent to multi_minimum_free_heap_size(). - // allocated_blocks; ///< Number of (variable size) blocks allocated in the heap. - // free_blocks; ///< Number of (variable size) free blocks in the heap. - // total_blocks; ///< Total number of (variable size) blocks in the heap. - multi_heap_info_t info; - heap_caps_get_info(&info, MALLOC_CAP_INTERNAL); - 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: %5u | max: %5u | frag: %3u%% \n", free, max, frag); - #endif - } - - _debugPort.print(_debugPrefix); - if(_debugLevel >= debugLvlShow) _debugPort.print("["+(String)level+"] "); - _debugPort.print(text); - if(textb){ - _debugPort.print(" "); - _debugPort.print(textb); - } - _debugPort.println(); -} - -/** - * [debugSoftAPConfig description] - * @access public - * @return {[type]} [description] - */ -void WiFiManager::debugSoftAPConfig(){ - - #ifdef ESP8266 - softap_config config; - wifi_softap_get_config(&config); - #if !defined(WM_NOCOUNTRY) - wifi_country_t country; - wifi_get_country(&country); - #endif - #elif defined(ESP32) - wifi_country_t country; - wifi_config_t conf_config; - esp_wifi_get_config(WIFI_IF_AP, &conf_config); // == ESP_OK - wifi_ap_config_t config = conf_config.ap; - esp_wifi_get_country(&country); - #endif - - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("SoftAP Configuration")); - DEBUG_WM(FPSTR(D_HR)); - DEBUG_WM(F("ssid: "),(char *) config.ssid); - DEBUG_WM(F("password: "),(char *) config.password); - DEBUG_WM(F("ssid_len: "),config.ssid_len); - DEBUG_WM(F("channel: "),config.channel); - DEBUG_WM(F("authmode: "),config.authmode); - DEBUG_WM(F("ssid_hidden: "),config.ssid_hidden); - DEBUG_WM(F("max_connection: "),config.max_connection); - #endif - #if !defined(WM_NOCOUNTRY) - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("country: "),(String)country.cc); - #endif - DEBUG_WM(F("beacon_interval: "),(String)config.beacon_interval + "(ms)"); - DEBUG_WM(FPSTR(D_HR)); - #endif -} - -/** - * [debugPlatformInfo description] - * @access public - * @return {[type]} [description] - */ -void WiFiManager::debugPlatformInfo(){ - #ifdef ESP8266 - system_print_meminfo(); - #ifdef WM_DEBUG_LEVEL - 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("[SYS] WM version: "), String((__FlashStringHelper *)WM_VERSION_STR) +" D:"+String(_debugLevel)); - 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 - - #ifdef WM_DEBUG_LEVEL - 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 - #endif -} - -int WiFiManager::getRSSIasQuality(int RSSI) { - int quality = 0; - - if (RSSI <= -100) { - quality = 0; - } else if (RSSI >= -50) { - quality = 100; - } else { - quality = 2 * (RSSI + 100); - } - return quality; -} - -/** Is this an IP? */ -boolean WiFiManager::isIp(String str) { - for (size_t i = 0; i < str.length(); i++) { - int c = str.charAt(i); - if (c != '.' && (c < '0' || c > '9')) { - return false; - } - } - return true; -} - -/** IP to String? */ -String WiFiManager::toStringIp(IPAddress ip) { - String res = ""; - for (int i = 0; i < 3; i++) { - res += String((ip >> (8 * i)) & 0xFF) + "."; - } - res += String(((ip >> 8 * 3)) & 0xFF); - return res; -} - -boolean WiFiManager::validApPassword(){ - // check that ap password is valid, return false - 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 , currently fatal, fail secure. - } - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("AccessPoint set password is VALID")); - DEBUG_WM(WM_DEBUG_DEV,"ap pass",_apPassword); - #endif - } - return true; -} - -/** - * encode htmlentities - * @since $dev - * @param string str string to replace entities - * @return string encoded string - */ -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("/": "/"); - // str.replace("`": "`"); - // str.replace("=": "="); -return str; -} - -/** - * [getWLStatusString description] - * @access public - * @param {[type]} uint8_t status [description] - * @return {[type]} [description] - */ -String WiFiManager::getWLStatusString(uint8_t status){ - if(status <= 7) return WIFI_STA_STATUS[status]; - return FPSTR(S_NA); -} - -String WiFiManager::getWLStatusString(){ - uint8_t status = WiFi.status(); - if(status <= 7) return WIFI_STA_STATUS[status]; - return FPSTR(S_NA); -} - -String WiFiManager::encryptionTypeStr(uint8_t authmode) { -#ifdef WM_DEBUG_LEVEL - // DEBUG_WM("enc_tye: ",authmode); - #endif - return AUTH_MODE_NAMES[authmode]; -} - -String WiFiManager::getModeString(uint8_t mode){ - if(mode <= 3) return WIFI_MODES[mode]; - return FPSTR(S_NA); -} - -bool WiFiManager::WiFiSetCountry(){ - if(_wificountry == "") return false; // skip not set - - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("WiFiSetCountry to"),_wificountry); - #endif - -/* - * @return - * - ESP_OK: succeed - * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init - * - ESP_ERR_WIFI_IF: invalid interface - * - ESP_ERR_WIFI_ARG: invalid argument - * - others: refer to error codes in esp_err.h - */ - - // @todo move these definitions, and out of cpp `esp_wifi_set_country(&WM_COUNTRY_US)` - bool ret = true; - // 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 ( check again it might be now! ) - if(WiFi.getMode() == WIFI_MODE_NULL){ - 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", - // "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(WM_DEBUG_ERROR,"[ERROR] esp wifi set country is not available"); - err = true; - #endif - } - #ifdef WM_DEBUG_LEVEL - if(err){ - if(err == ESP_ERR_WIFI_NOT_INIT) DEBUG_WM(WM_DEBUG_ERROR,"[ERROR] ESP_ERR_WIFI_NOT_INIT"); - else if(err == ESP_ERR_INVALID_ARG) DEBUG_WM(WM_DEBUG_ERROR,"[ERROR] ESP_ERR_WIFI_ARG (invalid country code)"); - else if(err != ESP_OK)DEBUG_WM(WM_DEBUG_ERROR,"[ERROR] unknown error",(String)err); - } - #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); - else if(_wificountry == "JP") ret = wifi_set_country((wifi_country_t*)&WM_COUNTRY_JP); - else if(_wificountry == "CN") ret = wifi_set_country((wifi_country_t*)&WM_COUNTRY_CN); - #ifdef WM_DEBUG_LEVEL - 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")); - #endif - return ret; -} - -// set mode ignores WiFi.persistent -bool WiFiManager::WiFi_Mode(WiFiMode_t m,bool persistent) { - bool ret; - #ifdef ESP8266 - if((wifi_get_opmode() == (uint8) m ) && !persistent) { - return true; - } - ETS_UART_INTR_DISABLE(); - if(persistent) ret = wifi_set_opmode(m); - else ret = wifi_set_opmode_current(m); - ETS_UART_INTR_ENABLE(); - return ret; - #elif defined(ESP32) - if(persistent && esp32persistent) WiFi.persistent(true); - 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 -} -bool WiFiManager::WiFi_Mode(WiFiMode_t m) { - return WiFi_Mode(m,false); -} - -// sta disconnect without persistent -bool WiFiManager::WiFi_Disconnect() { - #ifdef ESP8266 - if((WiFi.getMode() & WIFI_STA) != 0) { - bool ret; - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_DEV,F("WiFi station disconnect")); - #endif - ETS_UART_INTR_DISABLE(); // @todo possibly not needed - ret = wifi_station_disconnect(); - ETS_UART_INTR_ENABLE(); - return ret; - } - #elif defined(ESP32) - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_DEV,F("WiFi station disconnect")); - #endif - return WiFi.disconnect(); // not persistent atm - #endif - return false; -} - -// toggle STA without persistent -bool WiFiManager::WiFi_enableSTA(bool enable,bool persistent) { -#ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_DEV,F("WiFi_enableSTA"),(String) enable? "enable" : "disable"); - #endif - #ifdef ESP8266 - WiFiMode_t newMode; - WiFiMode_t currentMode = WiFi.getMode(); - bool isEnabled = (currentMode & WIFI_STA) != 0; - if(enable) newMode = (WiFiMode_t)(currentMode | WIFI_STA); - else newMode = (WiFiMode_t)(currentMode & (~WIFI_STA)); - - if((isEnabled != enable) || persistent) { - if(enable) { - #ifdef WM_DEBUG_LEVEL - if(persistent) DEBUG_WM(WM_DEBUG_DEV,F("enableSTA PERSISTENT ON")); - #endif - return WiFi_Mode(newMode,persistent); - } - else { - return WiFi_Mode(newMode,persistent); - } - } else { - return true; - } - #elif defined(ESP32) - bool ret; - if(persistent && esp32persistent) WiFi.persistent(true); - ret = WiFi.enableSTA(enable); // @todo handle persistent when it is implemented in platform - if(persistent && esp32persistent) WiFi.persistent(false); - return ret; - #endif -} - -bool WiFiManager::WiFi_enableSTA(bool enable) { - return WiFi_enableSTA(enable,false); -} - -bool WiFiManager::WiFi_eraseConfig() { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_DEV,F("WiFi_eraseConfig")); - #endif - - #ifdef ESP8266 - #ifndef WM_FIXERASECONFIG - return ESP.eraseConfig(); - #else - // erase config BUG replacement - // https://github.com/esp8266/Arduino/pull/3635 - const size_t cfgSize = 0x4000; - size_t cfgAddr = ESP.getFlashChipSize() - cfgSize; - - for (size_t offset = 0; offset < cfgSize; offset += SPI_FLASH_SEC_SIZE) { - if (!ESP.flashEraseSector((cfgAddr + offset) / SPI_FLASH_SEC_SIZE)) { - return false; - } - } - return true; - #endif - #elif defined(ESP32) - - bool ret; - WiFi.mode(WIFI_AP_STA); // cannot erase if not in STA mode ! - WiFi.persistent(true); - ret = WiFi.disconnect(true,true); // disconnect(bool wifioff, bool eraseap) - delay(500); - WiFi.persistent(false); - return ret; - #endif -} - -uint8_t WiFiManager::WiFi_softap_num_stations(){ - #ifdef ESP8266 - return wifi_softap_get_station_num(); - #elif defined(ESP32) - return WiFi.softAPgetStationNum(); - #endif -} - -bool WiFiManager::WiFi_hasAutoConnect(){ - return WiFi_SSID(true) != ""; -} - -String WiFiManager::WiFi_SSID(bool persistent) const{ - - #ifdef ESP8266 - struct station_config conf; - if(persistent) wifi_station_get_config_default(&conf); - else wifi_station_get_config(&conf); - - char tmp[33]; //ssid can be up to 32chars, => plus null term - 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(); - if(persistent){ - wifi_config_t conf; - esp_wifi_get_config(WIFI_IF_STA, &conf); - return String(reinterpret_cast(conf.sta.ssid)); - } - else { - if(WiFiGenericClass::getMode() == WIFI_MODE_NULL){ - return String(); - } - wifi_ap_record_t info; - if(!esp_wifi_sta_get_ap_info(&info)) { - return String(reinterpret_cast(info.ssid)); - } - return String(); - } - #endif -} - -String WiFiManager::WiFi_psk(bool persistent) const { - #ifdef ESP8266 - struct station_config conf; - - if(persistent) wifi_station_get_config_default(&conf); - else wifi_station_get_config(&conf); - - char tmp[65]; //psk is 64 bytes hex => plus null term - 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){ - return String(); - } - wifi_config_t conf; - esp_wifi_get_config(WIFI_IF_STA, &conf); - return String(reinterpret_cast(conf.sta.password)); - #endif -} - -#ifdef ESP32 - #ifdef WM_ARDUINOEVENTS - void WiFiManager::WiFiEvent(WiFiEvent_t event,arduino_event_info_t info){ - #else - void WiFiManager::WiFiEvent(WiFiEvent_t event,system_event_info_t info){ - #define wifi_sta_disconnected disconnected - #define ARDUINO_EVENT_WIFI_STA_DISCONNECTED SYSTEM_EVENT_STA_DISCONNECTED - #define ARDUINO_EVENT_WIFI_SCAN_DONE SYSTEM_EVENT_SCAN_DONE - #endif - if(!_hasBegun){ - #ifdef WM_DEBUG_LEVEL - // DEBUG_WM(WM_DEBUG_VERBOSE,"[ERROR] WiFiEvent, not ready"); - #endif - // Serial.println(F("\n[EVENT] WiFiEvent logging (wm debug not available)")); - // Serial.print(F("[EVENT] ID: ")); - // Serial.println(event); - return; - } - #ifdef WM_DEBUG_LEVEL - // DEBUG_WM(WM_DEBUG_VERBOSE,"[EVENT]",event); - #endif - if(event == ARDUINO_EVENT_WIFI_STA_DISCONNECTED){ - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("[EVENT] WIFI_REASON: "),info.wifi_sta_disconnected.reason); - #endif - if(info.wifi_sta_disconnected.reason == WIFI_REASON_AUTH_EXPIRE || info.wifi_sta_disconnected.reason == WIFI_REASON_AUTH_FAIL){ - _lastconxresulttmp = 7; // hack in wrong password internally, sdk emit WIFI_REASON_AUTH_EXPIRE on some routers on auth_fail - } else _lastconxresulttmp = WiFi.status(); - #ifdef WM_DEBUG_LEVEL - if(info.wifi_sta_disconnected.reason == WIFI_REASON_NO_AP_FOUND) DEBUG_WM(WM_DEBUG_VERBOSE,F("[EVENT] WIFI_REASON: NO_AP_FOUND")); - 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 - DEBUG_WM(WM_DEBUG_VERBOSE,F("[Event] SYSTEM_EVENT_STA_DISCONNECTED, reconnecting")); - #endif - WiFi.reconnect(); - #endif - } - else if(event == ARDUINO_EVENT_WIFI_SCAN_DONE && _asyncScan){ - uint16_t scans = WiFi.scanComplete(); - WiFi_scanComplete(scans); - } -} -#endif - -void WiFiManager::WiFi_autoReconnect(){ - #ifdef ESP8266 - WiFi.setAutoReconnect(_wifiAutoReconnect); - #elif defined(ESP32) - // if(_wifiAutoReconnect){ - // @todo move to seperate method, used for event listener now - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("ESP32 event handler enabled")); - #endif - using namespace std::placeholders; - if(wm_event_id == 0) wm_event_id = WiFi.onEvent(std::bind(&WiFiManager::WiFiEvent,this,_1,_2)); - // } - #endif -} - -// Called when /update is requested -void WiFiManager::handleUpdate() { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("<- Handle update")); - #endif - if (captivePortal()) return; // If captive portal redirect instead of displaying the page - String page = getHTTPHead(_title, FPSTR(C_update)); // @token options - String str = FPSTR(HTTP_ROOT_MAIN); - str.replace(FPSTR(T_t), _title); - str.replace(FPSTR(T_v), configPortalActive ? _apName : (getWiFiHostname() + " - " + WiFi.localIP().toString())); // use ip if ap is not active for heading - page += str; - - page += FPSTR(HTTP_UPDATE); - page += getHTTPEnd(); - - HTTPSend(page); - -} - -// upload via /u POST -void WiFiManager::handleUpdating(){ - // @todo - // cannot upload files in captive portal, file select is not allowed, show message with link or hide - // cannot upload if softreset after upload, maybe check for hard reset at least for dev, ERROR[11]: Invalid bootstrapping state, reset ESP8266 before updating - // add upload status to webpage somehow - // abort upload if error detected ? - // [x] supress cp timeout on upload, so it doesnt keep uploading? - // add progress handler for debugging - // 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 - _configPortalTimeout = 0; // disable timeout - - // handler for the file upload, get's the sketch bytes, and writes - // them through the Update object - HTTPUpload& upload = server->upload(); - - // UPLOAD START - 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 - } - #ifdef ESP8266 - WiFiUDP::stopAll(); - maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000; - #elif defined(ESP32) - // Think we do not need to stop WiFIUDP because we haven't started a listener - // maxSketchSpace = (ESP.getFlashChipSize() - 0x1000) & 0xFFFFF000; - // #define UPDATE_SIZE_UNKNOWN 0xFFFFFFFF // include update.h - maxSketchSpace = UPDATE_SIZE_UNKNOWN; - #endif - - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,"[OTA] Update file: ", upload.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(WM_DEBUG_ERROR,F("[ERROR] OTA Update ERROR"), Update.getError()); - #endif - error = true; - Update.end(); // Not sure the best way to abort, I think client will keep sending.. - } - } - // UPLOAD WRITE - else if (upload.status == UPLOAD_FILE_WRITE) { - // Serial.print("."); - if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_ERROR,F("[ERROR] OTA Update WRITE ERROR"), Update.getError()); - //Update.printError(Serial); // write failure - #endif - error = true; - } - } - // UPLOAD FILE END - else if (upload.status == UPLOAD_FILE_END) { - if (Update.end(true)) { // true to set the size to the current progress - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("\n\n[OTA] OTA FILE END bytes: "), upload.totalSize); - // Serial.printf("Updated: %u bytes\r\nRebooting...\r\n", upload.totalSize); - #endif - } - else { - // Update.printError(Serial); - error = true; - } - } - // UPLOAD ABORT - else if (upload.status == UPLOAD_FILE_ABORTED) { - Update.end(); - DEBUG_WM(F("[OTA] Update was aborted")); - error = true; - } - if(error) _configPortalTimeout = _configPortalTimeoutSAV; - delay(0); -} - -// upload and ota done, show status -void WiFiManager::handleUpdateDone() { - DEBUG_WM(WM_DEBUG_VERBOSE, F("<- Handle update done")); - // if (captivePortal()) return; // If captive portal redirect instead of displaying the page - - String page = getHTTPHead(FPSTR(S_options), FPSTR(C_update)); // @token options - String str = FPSTR(HTTP_ROOT_MAIN); - str.replace(FPSTR(T_t),_title); - str.replace(FPSTR(T_v), configPortalActive ? _apName : WiFi.localIP().toString()); // use ip if ap is not active for heading - page += str; - - if (Update.hasError()) { - page += FPSTR(HTTP_UPDATE_FAIL); - #ifdef ESP32 - page += "OTA Error: " + (String)Update.errorString(); - #else - page += "OTA Error: " + (String)Update.getError(); - #endif - DEBUG_WM(F("[OTA] update failed")); - } - else { - page += FPSTR(HTTP_UPDATE_SUCCESS); - DEBUG_WM(F("[OTA] update ok")); - } - page += getHTTPEnd(); - - HTTPSend(page); - - delay(1000); // send page - if (!Update.hasError()) { - ESP.restart(); - } -} - -#endif diff --git a/library.json b/library.json deleted file mode 100644 index a04050af..00000000 --- a/library.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "WiFiManager", - "version": "2.0.17", - "keywords": "wifi,wi-fi,esp,esp8266,esp32,espressif8266,espressif32,nodemcu,wemos,arduino", - "description": "WiFi Configuration manager with web configuration portal for ESP boards", - "authors": - [ - { - "name": "tzapu", - "url": "https://github.com/tzapu" - }, - { - "name": "tablatronix", - "url": "https://github.com/tablatronix", - "maintainer": true - } - ], - "repository": - { - "type": "git", - "url": "https://github.com/tzapu/WiFiManager.git" - }, - "frameworks": "arduino", - "platforms": - [ - "espressif8266", - "espressif32" - ] -} \ No newline at end of file