├── .travis.yml ├── LICENSE ├── README.md ├── WiFiManager.cpp ├── WiFiManager.h ├── examples ├── AutoConnect │ └── AutoConnect.ino ├── AutoConnectWithFSParameters │ └── AutoConnectWithFSParameters.ino ├── AutoConnectWithFSParametersAndCustomIP │ └── AutoConnectWithFSParametersAndCustomIP.ino ├── AutoConnectWithFeedback │ └── AutoConnectWithFeedback.ino ├── AutoConnectWithFeedbackLED │ └── AutoConnectWithFeedbackLED.ino ├── AutoConnectWithReset │ └── AutoConnectWithReset.ino ├── AutoConnectWithStaticIP │ └── AutoConnectWithStaticIP.ino ├── AutoConnectWithTimeout │ └── AutoConnectWithTimeout.ino └── OnDemandConfigPortal │ └── OnDemandConfigPortal.ino ├── extras ├── WiFiManager.template.html ├── parse.js └── template.h ├── keywords.txt ├── library.json ├── library.properties └── travis └── common.sh /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | before_install: 3 | - "/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_1.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :1 -ac -screen 0 1280x1024x16" 4 | - sleep 3 5 | - export DISPLAY=:1.0 6 | - wget http://downloads.arduino.cc/arduino-1.6.5-linux64.tar.xz 7 | - tar xf arduino-1.6.5-linux64.tar.xz 8 | - sudo mv arduino-1.6.5 /usr/local/share/arduino 9 | - sudo ln -s /usr/local/share/arduino/arduino /usr/local/bin/arduino 10 | install: 11 | - ln -s $PWD /usr/local/share/arduino/libraries/WiFiManager 12 | # boards manager not working on 1.6.7 - 1.6.8 13 | - arduino --pref "boardsmanager.additional.urls=http://arduino.esp8266.com/stable/package_esp8266com_index.json" --save-prefs 14 | # install lib arduino json not working in 1.6.5 15 | # - arduino --install-library "ArduinoJson" 16 | - git clone https://github.com/bblanchon/ArduinoJson /usr/local/share/arduino/libraries/ArduinoJson 17 | - arduino --install-boards esp8266:esp8266 18 | - arduino --board esp8266:esp8266:generic --save-prefs 19 | - arduino --pref "compiler.warning_level=all" --save-prefs 20 | script: 21 | - "echo $PWD" 22 | - "echo $HOME" 23 | - "ls $PWD" 24 | - source $TRAVIS_BUILD_DIR/travis/common.sh 25 | - build_examples 26 | # - "cat $PWD/examples/AutoConnect/AutoConnect.ino" 27 | # - arduino -v --verbose-build --verify $PWD/examples/AutoConnect/AutoConnect.ino 28 | # - arduino --verify --board arduino:avr:uno $PWD/examples/IncomingCall/IncomingCall.ino 29 | # - arduino --verify --board arduino:avr:uno $PWD/examples/AdafruitIO_GPS/AdafruitIO_GPS.ino 30 | after_success: 31 | - bash <(curl -s https://codecov.io/bash) 32 | notifications: 33 | email: 34 | on_success: change 35 | on_failure: change 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 tzapu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WiFiManager 2 | ESP8266 WiFi Connection manager with fallback web configuration portal 3 | 4 | [![Build Status](https://travis-ci.org/tzapu/WiFiManager.svg?branch=master)](https://travis-ci.org/tzapu/WiFiManager) 5 | 6 | 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. 7 | 8 | First attempt at a library. Lots more changes and fixes to do. Contributions are welcome. 9 | 10 | #### This works with the ESP8266 Arduino platform with a recent stable release(2.0.0 or newer) https://github.com/esp8266/Arduino 11 | 12 | ## Contents 13 | - [How it works](#how-it-works) 14 | - [Wishlist](#wishlist) 15 | - [Quick start](#quick-start) 16 | - Installing 17 | - [Through Library Manager](#install-through-library-manager) 18 | - [From Github](#checkout-from-github) 19 | - [Using](#using) 20 | - [Documentation](#documentation) 21 | - [Access Point Password](#password-protect-the-configuration-access-point) 22 | - [Callbacks](#callbacks) 23 | - [Configuration Portal Timeout](#configuration-portal-timeout) 24 | - [On Demand Configuration](#on-demand-configuration-portal) 25 | - [Custom Parameters](#custom-parameters) 26 | - [Custom IP Configuration](#custom-ip-configuration) 27 | - [Filter Low Quality Networks](#filter-networks) 28 | - [Debug Output](#debug) 29 | - [Troubleshooting](#troubleshooting) 30 | - [Releases](#releases) 31 | - [Contributors](#contributions-and-thanks) 32 | 33 | 34 | ## How It Works 35 | - when your ESP starts up, it sets it up in Station mode and tries to connect to a previously saved Access Point 36 | - 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) 37 | - using any wifi enabled device with a browser (computer, phone, tablet) connect to the newly created Access Point 38 | - 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 39 | - choose one of the access points scanned, enter password, click save 40 | - ESP will try to connect. If successful, it relinquishes control back to your app. If not, reconnect to AP and reconfigure. 41 | 42 | ## How It Looks 43 | ![ESP8266 WiFi Captive Portal Homepage](http://i.imgur.com/YPvW9eql.png) ![ESP8266 WiFi Captive Portal Configuration](http://i.imgur.com/oicWJ4gl.png) 44 | 45 | ## Wishlist 46 | - ~~remove dependency on EEPROM library~~ 47 | - ~~move HTML Strings to PROGMEM~~ 48 | - ~~cleanup and streamline code~~ (although this is ongoing) 49 | - if timeout is set, extend it when a page is fetched in AP mode 50 | - ~~add ability to configure more parameters than ssid/password~~ 51 | - ~~maybe allow setting ip of ESP after reboot~~ 52 | - ~~add to Arduino Library Manager~~ 53 | - ~~add to PlatformIO~~ 54 | - add multiple sets of network credentials 55 | - ~~allow users to customize CSS~~ 56 | 57 | ## Quick Start 58 | 59 | ### Installing 60 | You can either install through the Arduino Library Manager or checkout the latest changes or a release from github 61 | 62 | #### Install through Library Manager 63 | __Currently version 0.8+ works with release 2.0.0 or newer of the [ESP8266 core for Arduino](https://github.com/esp8266/Arduino)__ 64 | - in Arduino IDE got to Sketch/Include Library/Manage Libraries 65 | ![Manage Libraries](http://i.imgur.com/9BkEBkR.png) 66 | 67 | - search for WiFiManager 68 | ![WiFiManager package](http://i.imgur.com/18yIai8.png) 69 | 70 | - click Install and start [using it](#using) 71 | 72 | #### Checkout from github 73 | __Github version works with release 2.0.0 or newer of the [ESP8266 core for Arduino](https://github.com/esp8266/Arduino)__ 74 | - Checkout library to your Arduino libraries folder 75 | 76 | ### Using 77 | - Include in your sketch 78 | ```cpp 79 | #include //ESP8266 Core WiFi Library (you most likely already have this in your sketch) 80 | 81 | #include //Local DNS Server used for redirecting all requests to the configuration portal 82 | #include //Local WebServer used to serve the configuration portal 83 | #include //https://github.com/tzapu/WiFiManager WiFi Configuration Magic 84 | ``` 85 | 86 | - Initialize library, in your setup function add 87 | ```cpp 88 | WiFiManager wifiManager; 89 | ``` 90 | 91 | - Also in the setup function add 92 | ```cpp 93 | //first parameter is name of access point, second is the password 94 | wifiManager.autoConnect("AP-NAME", "AP-PASSWORD"); 95 | ``` 96 | if you just want an unsecured access point 97 | ```cpp 98 | wifiManager.autoConnect("AP-NAME"); 99 | ``` 100 | or if you want to use and auto generated name from 'ESP' and the esp's Chip ID use 101 | ```cpp 102 | wifiManager.autoConnect(); 103 | ``` 104 | 105 | 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. 106 | 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. 107 | 108 | Also see [examples](https://github.com/tzapu/WiFiManager/tree/master/examples). 109 | 110 | ## Documentation 111 | 112 | #### Password protect the configuration Access Point 113 | You can and should password protect the configuration access point. Simply add the password as a second parameter to `autoConnect`. 114 | A short password seems to have unpredictable results so use one that's around 8 characters or more in length. 115 | The guidelines are that a wifi password must consist of 8 to 63 ASCII-encoded characters in the range of 32 to 126 (decimal) 116 | ```cpp 117 | wifiManager.autoConnect("AutoConnectAP", "password") 118 | ``` 119 | 120 | #### Callbacks 121 | ##### Enter Config mode 122 | Use this if you need to do something when your device enters configuration mode on failed WiFi connection attempt. 123 | Before `autoConnect()` 124 | ```cpp 125 | wifiManager.setAPCallback(configModeCallback); 126 | ``` 127 | `configModeCallback` declaration and example 128 | ```cpp 129 | void configModeCallback (WiFiManager *myWiFiManager) { 130 | Serial.println("Entered config mode"); 131 | Serial.println(WiFi.softAPIP()); 132 | 133 | Serial.println(myWiFiManager->getConfigPortalSSID()); 134 | } 135 | ``` 136 | 137 | ##### Save settings 138 | 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. 139 | 140 | See [AutoConnectWithFSParameters Example](https://github.com/tzapu/WiFiManager/tree/master/examples/AutoConnectWithFSParameters). 141 | ```cpp 142 | wifiManager.setSaveConfigCallback(saveConfigCallback); 143 | ``` 144 | `saveConfigCallback` declaration and example 145 | ```cpp 146 | //flag for saving data 147 | bool shouldSaveConfig = false; 148 | 149 | //callback notifying us of the need to save config 150 | void saveConfigCallback () { 151 | Serial.println("Should save config"); 152 | shouldSaveConfig = true; 153 | } 154 | ``` 155 | 156 | #### Configuration Portal Timeout 157 | 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 158 | ```cpp 159 | wifiManager.setConfigPortalTimeout(180); 160 | ``` 161 | which will wait 3 minutes (180 seconds). When the time passes, the autoConnect function will return, no matter the outcome. 162 | 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) 163 | 164 | #### On Demand Configuration Portal 165 | If you would rather start the configuration portal on demand rather than automatically on a failed connection attempt, then this is for you. 166 | 167 | 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.__ 168 | 169 | Example usage 170 | ```cpp 171 | void loop() { 172 | // is configuration portal requested? 173 | if ( digitalRead(TRIGGER_PIN) == LOW ) { 174 | WiFiManager wifiManager; 175 | wifiManager.startConfigPortal("OnDemandAP"); 176 | Serial.println("connected...yeey :)"); 177 | } 178 | } 179 | ``` 180 | See example for a more complex version. [OnDemandConfigPortal](https://github.com/tzapu/WiFiManager/tree/master/examples/OnDemandConfigPortal) 181 | 182 | #### Custom Parameters 183 | You can use WiFiManager to collect more parameters than just SSID and password. 184 | 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. 185 | **You are responsible for saving and loading these custom values.** The library just collects and displays the data for you as a convenience. 186 | Usage scenario would be: 187 | - load values from somewhere (EEPROM/FS) or generate some defaults 188 | - add the custom parameters to WiFiManager using 189 | ```cpp 190 | // id/name, placeholder/prompt, default, length 191 | WiFiManagerParameter custom_mqtt_server("server", "mqtt server", mqtt_server, 40); 192 | wifiManager.addParameter(&custom_mqtt_server); 193 | 194 | ``` 195 | - if connection to AP fails, configuration portal starts and you can set /change the values (or use on demand configuration portal) 196 | - once configuration is done and connection is established [save config callback]() is called 197 | - once WiFiManager returns control to your application, read and save the new values using the `WiFiManagerParameter` object. 198 | ```cpp 199 | mqtt_server = custom_mqtt_server.getValue(); 200 | ``` 201 | This feature is a lot more involved than all the others, so here are some examples to fully show how it is done. 202 | You should also take a look at adding custom HTML to your form. 203 | 204 | - Save and load custom parameters to file system in json form [AutoConnectWithFSParameters](https://github.com/tzapu/WiFiManager/tree/master/examples/AutoConnectWithFSParameters) 205 | - *Save and load custom parameters to EEPROM* (not done yet) 206 | 207 | #### Custom IP Configuration 208 | You can set a custom IP for both AP (access point, config mode) and STA (station mode, client mode, normal project state) 209 | 210 | ##### Custom Access Point IP Configuration 211 | This will set your captive portal to a specific IP should you need/want such a feature. Add the following snippet before `autoConnect()` 212 | ```cpp 213 | //set custom ip for portal 214 | wifiManager.setAPStaticIPConfig(IPAddress(10,0,1,1), IPAddress(10,0,1,1), IPAddress(255,255,255,0)); 215 | ``` 216 | 217 | ##### Custom Station (client) Static IP Configuration 218 | This will make use the specified IP configuration instead of using DHCP in station mode. 219 | ```cpp 220 | wifiManager.setSTAStaticIPConfig(IPAddress(192,168,0,99), IPAddress(192,168,0,1), IPAddress(255,255,255,0)); 221 | ``` 222 | 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. 223 | 224 | #### Custom HTML, CSS, Javascript 225 | There are various ways in which you can inject custom HTML, CSS or Javascript into the configuration portal. 226 | The options are: 227 | - inject custom head element 228 | You can use this to any html bit to the head of the configuration portal. If you add a `"); 231 | ``` 232 | - inject a custom bit of html in the configuration form 233 | ```cpp 234 | WiFiManagerParameter custom_text("

This is just a text paragraph

"); 235 | wifiManager.addParameter(&custom_text); 236 | ``` 237 | - inject a custom bit of html in a configuration form element 238 | Just add the bit you want added as the last parameter to the custom parameter constructor. 239 | ```cpp 240 | WiFiManagerParameter custom_mqtt_server("server", "mqtt server", "iot.eclipse", 40, " readonly"); 241 | ``` 242 | 243 | #### Filter Networks 244 | You can filter networks based on signal quality and show/hide duplicate networks. 245 | 246 | - If you would like to filter low signal quality networks you can tell WiFiManager to not show networks below an arbitrary quality %; 247 | ```cpp 248 | wifiManager.setMinimumSignalQuality(10); 249 | ``` 250 | will not show networks under 10% signal quality. If you omit the parameter it defaults to 8%; 251 | 252 | - You can also remove or show duplicate networks (default is remove). 253 | Use this function to show (or hide) all networks. 254 | ```cpp 255 | wifiManager.setRemoveDuplicateAPs(false); 256 | ``` 257 | 258 | #### Debug 259 | Debug is enabled by default on Serial. To disable add before autoConnect 260 | ```cpp 261 | wifiManager.setDebugOutput(false); 262 | ``` 263 | 264 | ## Troubleshooting 265 | If you get compilation errors, more often than not, you may need to install a newer version of the ESP8266 core for Arduino. 266 | 267 | 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** 268 | 269 | 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. 270 | 271 | 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`. 272 | 273 | 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. 274 | 275 | ## Releases 276 | #### 0.12 277 | - removed 204 header response 278 | - fixed incompatibility with other libs using isnan and other std:: functions without namespace 279 | 280 | ##### 0.11 281 | - a lot more reliable reconnecting to networks 282 | - custom html in custom parameters (for read only params) 283 | - custom html in custom parameter form (like labels) 284 | - custom head element (like custom css) 285 | - sort networks based on signal quality 286 | - remove duplicate networks 287 | 288 | ##### 0.10 289 | - some css changes 290 | - bug fixes and speed improvements 291 | - added an alternative to waitForConnectResult() for debugging 292 | - changed `setTimeout(seconds)` to `setConfigPortalTimeout(seconds)` 293 | 294 | ##### 0.9 295 | - fixed support for encoded characters in ssid/pass 296 | 297 | ##### 0.8 298 | - made it compile on older versions of ESP8266 core as well, tested down to 2.0.0 299 | - added simple example for Custom IP 300 | 301 | ##### 0.7 302 | - added static IP in station mode 303 | - added example of persisting custom IP to FS config.json 304 | - more option on portal homepage 305 | - added on PlatformIO 306 | 307 | ##### 0.6 308 | - custom parameters 309 | - prettier 310 | - on demand config portal 311 | - commit #100 :D 312 | 313 | ##### 0.5 314 | - Added to Arduino Boards Manager - Thanks Max 315 | - moved most stuff to PROGMEM 316 | - added signal quality and a nice little padlock to show which networks are encrypted 317 | 318 | ##### v0.4 - all of it user contributed changes - Thank you 319 | - added ability to password protect the configuration Access Point 320 | - callback for enter configuration mode 321 | - memory allocation improvements 322 | 323 | ##### v0.3 324 | - removed the need for EEPROM and works with the 2.0.0 and above stable release of the ESP8266 for Arduino IDE package 325 | - removed restart on save of credentials 326 | - updated examples 327 | 328 | ##### v0.2 329 | needs the latest staging version (or at least a recent release of the staging version) to work 330 | 331 | ##### v0.1 332 | works with the staging release ver. 1.6.5-1044-g170995a, built on Aug 10, 2015 of the ESP8266 Arduino library. 333 | 334 | 335 | ### Contributions and thanks 336 | 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. 337 | 338 | __THANK YOU__ 339 | 340 | [Shawn A](https://github.com/tablatronix) 341 | 342 | [Maximiliano Duarte](https://github.com/domonetic) 343 | 344 | [alltheblinkythings](https://github.com/alltheblinkythings) 345 | 346 | [Niklas Wall](https://github.com/niklaswall) 347 | 348 | [Jakub Piasecki](https://github.com/zaporylie) 349 | 350 | [Peter Allan](https://github.com/alwynallan) 351 | 352 | [John Little](https://github.com/j0hnlittle) 353 | 354 | [markaswift](https://github.com/markaswift) 355 | 356 | [franklinvv](https://github.com/franklinvv) 357 | 358 | [Alberto Ricci Bitti](https://github.com/riccibitti) 359 | 360 | [SebiPanther](https://github.com/SebiPanther) 361 | 362 | [jonathanendersby](https://github.com/jonathanendersby) 363 | 364 | [walthercarsten](https://github.com/walthercarsten) 365 | 366 | Sorry if i have missed anyone. 367 | 368 | #### Inspiration 369 | - http://www.esp8266.com/viewtopic.php?f=29&t=2520 370 | -------------------------------------------------------------------------------- /WiFiManager.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************** 2 | WiFiManager is a library for the ESP8266/Arduino platform 3 | (https://github.com/esp8266/Arduino) to enable easy 4 | configuration and reconfiguration of WiFi credentials using a Captive Portal 5 | inspired by: 6 | http://www.esp8266.com/viewtopic.php?f=29&t=2520 7 | https://github.com/chriscook8/esp-arduino-apboot 8 | https://github.com/esp8266/Arduino/tree/esp8266/hardware/esp8266com/esp8266/libraries/DNSServer/examples/CaptivePortalAdvanced 9 | Built by AlexT https://github.com/tzapu 10 | Licensed under MIT license 11 | **************************************************************/ 12 | 13 | #include "WiFiManager.h" 14 | 15 | WiFiManagerParameter::WiFiManagerParameter(const char *custom) { 16 | _id = NULL; 17 | _placeholder = NULL; 18 | _length = 0; 19 | _value = NULL; 20 | 21 | _customHTML = custom; 22 | } 23 | 24 | WiFiManagerParameter::WiFiManagerParameter(const char *id, const char *placeholder, const char *defaultValue, int length) { 25 | init(id, placeholder, defaultValue, length, ""); 26 | } 27 | 28 | WiFiManagerParameter::WiFiManagerParameter(const char *id, const char *placeholder, const char *defaultValue, int length, const char *custom) { 29 | init(id, placeholder, defaultValue, length, custom); 30 | } 31 | 32 | void WiFiManagerParameter::init(const char *id, const char *placeholder, const char *defaultValue, int length, const char *custom) { 33 | _id = id; 34 | _placeholder = placeholder; 35 | _length = length; 36 | _value = new char[length + 1]; 37 | for (int i = 0; i < length; i++) { 38 | _value[i] = 0; 39 | } 40 | if (defaultValue != NULL) { 41 | strncpy(_value, defaultValue, length); 42 | } 43 | 44 | _customHTML = custom; 45 | } 46 | 47 | const char* WiFiManagerParameter::getValue() { 48 | return _value; 49 | } 50 | const char* WiFiManagerParameter::getID() { 51 | return _id; 52 | } 53 | const char* WiFiManagerParameter::getPlaceholder() { 54 | return _placeholder; 55 | } 56 | int WiFiManagerParameter::getValueLength() { 57 | return _length; 58 | } 59 | const char* WiFiManagerParameter::getCustomHTML() { 60 | return _customHTML; 61 | } 62 | 63 | WiFiManager::WiFiManager() { 64 | } 65 | 66 | void WiFiManager::addParameter(WiFiManagerParameter *p) { 67 | _params[_paramsCount] = p; 68 | _paramsCount++; 69 | DEBUG_WM("Adding parameter"); 70 | DEBUG_WM(p->getID()); 71 | } 72 | 73 | void WiFiManager::setupConfigPortal() { 74 | dnsServer.reset(new DNSServer()); 75 | server.reset(new ESP8266WebServer(80)); 76 | 77 | DEBUG_WM(F("")); 78 | _configPortalStart = millis(); 79 | 80 | DEBUG_WM(F("Configuring access point... ")); 81 | DEBUG_WM(_apName); 82 | if (_apPassword != NULL) { 83 | if (strlen(_apPassword) < 8 || strlen(_apPassword) > 63) { 84 | // fail passphrase to short or long! 85 | DEBUG_WM(F("Invalid AccessPoint password. Ignoring")); 86 | _apPassword = NULL; 87 | } 88 | DEBUG_WM(_apPassword); 89 | } 90 | 91 | //optional soft ip config 92 | if (_ap_static_ip) { 93 | DEBUG_WM(F("Custom AP IP/GW/Subnet")); 94 | WiFi.softAPConfig(_ap_static_ip, _ap_static_gw, _ap_static_sn); 95 | } 96 | 97 | if (_apPassword != NULL) { 98 | WiFi.softAP(_apName, _apPassword);//password option 99 | } else { 100 | WiFi.softAP(_apName); 101 | } 102 | 103 | delay(500); // Without delay I've seen the IP address blank 104 | DEBUG_WM(F("AP IP address: ")); 105 | DEBUG_WM(WiFi.softAPIP()); 106 | 107 | /* Setup the DNS server redirecting all the domains to the apIP */ 108 | dnsServer->setErrorReplyCode(DNSReplyCode::NoError); 109 | dnsServer->start(DNS_PORT, "*", WiFi.softAPIP()); 110 | 111 | /* Setup web pages: root, wifi config pages, SO captive portal detectors and not found. */ 112 | server->on("/", std::bind(&WiFiManager::handleRoot, this)); 113 | server->on("/wifi", std::bind(&WiFiManager::handleWifi, this, true)); 114 | server->on("/0wifi", std::bind(&WiFiManager::handleWifi, this, false)); 115 | server->on("/wifisave", std::bind(&WiFiManager::handleWifiSave, this)); 116 | server->on("/i", std::bind(&WiFiManager::handleInfo, this)); 117 | server->on("/r", std::bind(&WiFiManager::handleReset, this)); 118 | //server->on("/generate_204", std::bind(&WiFiManager::handle204, this)); //Android/Chrome OS captive portal check. 119 | server->on("/fwlink", std::bind(&WiFiManager::handleRoot, this)); //Microsoft captive portal. Maybe not needed. Might be handled by notFound handler. 120 | server->onNotFound (std::bind(&WiFiManager::handleNotFound, this)); 121 | server->begin(); // Web server start 122 | DEBUG_WM(F("HTTP server started")); 123 | 124 | } 125 | 126 | boolean WiFiManager::autoConnect() { 127 | String ssid = "ESP" + String(ESP.getChipId()); 128 | return autoConnect(ssid.c_str(), NULL); 129 | } 130 | 131 | boolean WiFiManager::autoConnect(char const *apName, char const *apPassword) { 132 | DEBUG_WM(F("")); 133 | DEBUG_WM(F("AutoConnect")); 134 | 135 | // read eeprom for ssid and pass 136 | //String ssid = getSSID(); 137 | //String pass = getPassword(); 138 | 139 | // attempt to connect; should it fail, fall back to AP 140 | WiFi.mode(WIFI_STA); 141 | 142 | if (connectWifi("", "") == WL_CONNECTED) { 143 | DEBUG_WM(F("IP Address:")); 144 | DEBUG_WM(WiFi.localIP()); 145 | //connected 146 | return true; 147 | } 148 | 149 | return startConfigPortal(apName, apPassword); 150 | } 151 | 152 | boolean WiFiManager::startConfigPortal() { 153 | String ssid = "ESP" + String(ESP.getChipId()); 154 | return startConfigPortal(ssid.c_str(), NULL); 155 | } 156 | 157 | boolean WiFiManager::startConfigPortal(char const *apName, char const *apPassword) { 158 | //setup AP 159 | WiFi.mode(WIFI_AP_STA); 160 | DEBUG_WM("SET AP STA"); 161 | 162 | _apName = apName; 163 | _apPassword = apPassword; 164 | 165 | //notify we entered AP mode 166 | if ( _apcallback != NULL) { 167 | _apcallback(this); 168 | } 169 | 170 | connect = false; 171 | setupConfigPortal(); 172 | 173 | while (_configPortalTimeout == 0 || millis() < _configPortalStart + _configPortalTimeout) { 174 | //DNS 175 | dnsServer->processNextRequest(); 176 | //HTTP 177 | server->handleClient(); 178 | 179 | 180 | if (connect) { 181 | connect = false; 182 | delay(2000); 183 | DEBUG_WM(F("Connecting to new AP")); 184 | 185 | // using user-provided _ssid, _pass in place of system-stored ssid and pass 186 | if (connectWifi(_ssid, _pass) != WL_CONNECTED) { 187 | DEBUG_WM(F("Failed to connect.")); 188 | } else { 189 | //connected 190 | WiFi.mode(WIFI_STA); 191 | //notify that configuration has changed and any optional parameters should be saved 192 | if ( _savecallback != NULL) { 193 | //todo: check if any custom parameters actually exist, and check if they really changed maybe 194 | _savecallback(); 195 | } 196 | break; 197 | } 198 | 199 | if (_shouldBreakAfterConfig) { 200 | //flag set to exit after config after trying to connect 201 | //notify that configuration has changed and any optional parameters should be saved 202 | if ( _savecallback != NULL) { 203 | //todo: check if any custom parameters actually exist, and check if they really changed maybe 204 | _savecallback(); 205 | } 206 | break; 207 | } 208 | } 209 | yield(); 210 | } 211 | 212 | server.reset(); 213 | dnsServer.reset(); 214 | 215 | return WiFi.status() == WL_CONNECTED; 216 | } 217 | 218 | 219 | int WiFiManager::connectWifi(String ssid, String pass) { 220 | DEBUG_WM(F("Connecting as wifi client...")); 221 | 222 | // check if we've got static_ip settings, if we do, use those. 223 | if (_sta_static_ip) { 224 | DEBUG_WM(F("Custom STA IP/GW/Subnet")); 225 | WiFi.config(_sta_static_ip, _sta_static_gw, _sta_static_sn); 226 | DEBUG_WM(WiFi.localIP()); 227 | } 228 | //fix for auto connect racing issue 229 | if (WiFi.status() == WL_CONNECTED) { 230 | DEBUG_WM("Already connected. Bailing out."); 231 | return WL_CONNECTED; 232 | } 233 | //check if we have ssid and pass and force those, if not, try with last saved values 234 | if (ssid != "") { 235 | WiFi.begin(ssid.c_str(), pass.c_str()); 236 | } else { 237 | if (WiFi.SSID()) { 238 | DEBUG_WM("Using last saved values, should be faster"); 239 | //trying to fix connection in progress hanging 240 | ETS_UART_INTR_DISABLE(); 241 | wifi_station_disconnect(); 242 | ETS_UART_INTR_ENABLE(); 243 | 244 | WiFi.begin(); 245 | } else { 246 | DEBUG_WM("No saved credentials"); 247 | } 248 | } 249 | 250 | int connRes = waitForConnectResult(); 251 | DEBUG_WM ("Connection result: "); 252 | DEBUG_WM ( connRes ); 253 | //not connected, WPS enabled, no pass - first attempt 254 | if (_tryWPS && connRes != WL_CONNECTED && pass == "") { 255 | startWPS(); 256 | //should be connected at the end of WPS 257 | connRes = waitForConnectResult(); 258 | } 259 | return connRes; 260 | } 261 | 262 | uint8_t WiFiManager::waitForConnectResult() { 263 | if (_connectTimeout == 0) { 264 | return WiFi.waitForConnectResult(); 265 | } else { 266 | DEBUG_WM (F("Waiting for connection result with time out")); 267 | unsigned long start = millis(); 268 | boolean keepConnecting = true; 269 | uint8_t status; 270 | while (keepConnecting) { 271 | status = WiFi.status(); 272 | if (millis() > start + _connectTimeout) { 273 | keepConnecting = false; 274 | DEBUG_WM (F("Connection timed out")); 275 | } 276 | if (status == WL_CONNECTED || status == WL_CONNECT_FAILED) { 277 | keepConnecting = false; 278 | } 279 | delay(100); 280 | } 281 | return status; 282 | } 283 | } 284 | 285 | void WiFiManager::startWPS() { 286 | DEBUG_WM("START WPS"); 287 | WiFi.beginWPSConfig(); 288 | DEBUG_WM("END WPS"); 289 | } 290 | /* 291 | String WiFiManager::getSSID() { 292 | if (_ssid == "") { 293 | DEBUG_WM(F("Reading SSID")); 294 | _ssid = WiFi.SSID(); 295 | DEBUG_WM(F("SSID: ")); 296 | DEBUG_WM(_ssid); 297 | } 298 | return _ssid; 299 | } 300 | 301 | String WiFiManager::getPassword() { 302 | if (_pass == "") { 303 | DEBUG_WM(F("Reading Password")); 304 | _pass = WiFi.psk(); 305 | DEBUG_WM("Password: " + _pass); 306 | //DEBUG_WM(_pass); 307 | } 308 | return _pass; 309 | } 310 | */ 311 | String WiFiManager::getConfigPortalSSID() { 312 | return _apName; 313 | } 314 | 315 | void WiFiManager::resetSettings() { 316 | DEBUG_WM(F("settings invalidated")); 317 | DEBUG_WM(F("THIS MAY CAUSE AP NOT TO START UP PROPERLY. YOU NEED TO COMMENT IT OUT AFTER ERASING THE DATA.")); 318 | WiFi.disconnect(true); 319 | //delay(200); 320 | } 321 | void WiFiManager::setTimeout(unsigned long seconds) { 322 | setConfigPortalTimeout(seconds); 323 | } 324 | 325 | void WiFiManager::setConfigPortalTimeout(unsigned long seconds) { 326 | _configPortalTimeout = seconds * 1000; 327 | } 328 | 329 | void WiFiManager::setConnectTimeout(unsigned long seconds) { 330 | _connectTimeout = seconds * 1000; 331 | } 332 | 333 | void WiFiManager::setDebugOutput(boolean debug) { 334 | _debug = debug; 335 | } 336 | 337 | void WiFiManager::setAPStaticIPConfig(IPAddress ip, IPAddress gw, IPAddress sn) { 338 | _ap_static_ip = ip; 339 | _ap_static_gw = gw; 340 | _ap_static_sn = sn; 341 | } 342 | 343 | void WiFiManager::setSTAStaticIPConfig(IPAddress ip, IPAddress gw, IPAddress sn) { 344 | _sta_static_ip = ip; 345 | _sta_static_gw = gw; 346 | _sta_static_sn = sn; 347 | } 348 | 349 | void WiFiManager::setMinimumSignalQuality(int quality) { 350 | _minimumQuality = quality; 351 | } 352 | 353 | void WiFiManager::setBreakAfterConfig(boolean shouldBreak) { 354 | _shouldBreakAfterConfig = shouldBreak; 355 | } 356 | 357 | /** Handle root or redirect to captive portal */ 358 | void WiFiManager::handleRoot() { 359 | DEBUG_WM(F("Handle root")); 360 | if (captivePortal()) { // If caprive portal redirect instead of displaying the page. 361 | return; 362 | } 363 | 364 | String page = FPSTR(HTTP_HEAD); 365 | page.replace("{v}", "Options"); 366 | page += FPSTR(HTTP_SCRIPT); 367 | page += FPSTR(HTTP_STYLE); 368 | page += _customHeadElement; 369 | page += FPSTR(HTTP_HEAD_END); 370 | page += "

"; 371 | page += _apName; 372 | page += "

"; 373 | page += F("

WiFiManager

"); 374 | page += FPSTR(HTTP_PORTAL_OPTIONS); 375 | page += FPSTR(HTTP_END); 376 | 377 | server->send(200, "text/html", page); 378 | 379 | } 380 | 381 | /** Wifi config page handler */ 382 | void WiFiManager::handleWifi(boolean scan) { 383 | 384 | String page = FPSTR(HTTP_HEAD); 385 | page.replace("{v}", "Config ESP"); 386 | page += FPSTR(HTTP_SCRIPT); 387 | page += FPSTR(HTTP_STYLE); 388 | page += _customHeadElement; 389 | page += FPSTR(HTTP_HEAD_END); 390 | 391 | if (scan) { 392 | int n = WiFi.scanNetworks(); 393 | DEBUG_WM(F("Scan done")); 394 | if (n == 0) { 395 | DEBUG_WM(F("No networks found")); 396 | page += F("No networks found. Refresh to scan again."); 397 | } else { 398 | 399 | //sort networks 400 | int indices[n]; 401 | for (int i = 0; i < n; i++) { 402 | indices[i] = i; 403 | } 404 | 405 | // RSSI SORT 406 | 407 | // old sort 408 | for (int i = 0; i < n; i++) { 409 | for (int j = i + 1; j < n; j++) { 410 | if (WiFi.RSSI(indices[j]) > WiFi.RSSI(indices[i])) { 411 | std::swap(indices[i], indices[j]); 412 | } 413 | } 414 | } 415 | 416 | /*std::sort(indices, indices + n, [](const int & a, const int & b) -> bool 417 | { 418 | return WiFi.RSSI(a) > WiFi.RSSI(b); 419 | });*/ 420 | 421 | // remove duplicates ( must be RSSI sorted ) 422 | if (_removeDuplicateAPs) { 423 | String cssid; 424 | for (int i = 0; i < n; i++) { 425 | if (indices[i] == -1) continue; 426 | cssid = WiFi.SSID(indices[i]); 427 | for (int j = i + 1; j < n; j++) { 428 | if (cssid == WiFi.SSID(indices[j])) { 429 | DEBUG_WM("DUP AP: " + WiFi.SSID(indices[j])); 430 | indices[j] = -1; // set dup aps to index -1 431 | } 432 | } 433 | } 434 | } 435 | 436 | //display networks in page 437 | for (int i = 0; i < n; i++) { 438 | if (indices[i] == -1) continue; // skip dups 439 | DEBUG_WM(WiFi.SSID(indices[i])); 440 | DEBUG_WM(WiFi.RSSI(indices[i])); 441 | int quality = getRSSIasQuality(WiFi.RSSI(indices[i])); 442 | 443 | if (_minimumQuality == -1 || _minimumQuality < quality) { 444 | String item = FPSTR(HTTP_ITEM); 445 | String rssiQ; 446 | rssiQ += quality; 447 | item.replace("{v}", WiFi.SSID(indices[i])); 448 | item.replace("{r}", rssiQ); 449 | if (WiFi.encryptionType(indices[i]) != ENC_TYPE_NONE) { 450 | item.replace("{i}", "l"); 451 | } else { 452 | item.replace("{i}", ""); 453 | } 454 | //DEBUG_WM(item); 455 | page += item; 456 | delay(0); 457 | } else { 458 | DEBUG_WM(F("Skipping due to quality")); 459 | } 460 | 461 | } 462 | page += "
"; 463 | } 464 | } 465 | 466 | page += FPSTR(HTTP_FORM_START); 467 | char parLength[2]; 468 | // add the extra parameters to the form 469 | for (int i = 0; i < _paramsCount; i++) { 470 | if (_params[i] == NULL) { 471 | break; 472 | } 473 | 474 | String pitem = FPSTR(HTTP_FORM_PARAM); 475 | if (_params[i]->getID() != NULL) { 476 | pitem.replace("{i}", _params[i]->getID()); 477 | pitem.replace("{n}", _params[i]->getID()); 478 | pitem.replace("{p}", _params[i]->getPlaceholder()); 479 | snprintf(parLength, 2, "%d", _params[i]->getValueLength()); 480 | pitem.replace("{l}", parLength); 481 | pitem.replace("{v}", _params[i]->getValue()); 482 | pitem.replace("{c}", _params[i]->getCustomHTML()); 483 | } else { 484 | pitem = _params[i]->getCustomHTML(); 485 | } 486 | 487 | page += pitem; 488 | } 489 | if (_params[0] != NULL) { 490 | page += "
"; 491 | } 492 | 493 | if (_sta_static_ip) { 494 | 495 | String item = FPSTR(HTTP_FORM_PARAM); 496 | item.replace("{i}", "ip"); 497 | item.replace("{n}", "ip"); 498 | item.replace("{p}", "Static IP"); 499 | item.replace("{l}", "15"); 500 | item.replace("{v}", _sta_static_ip.toString()); 501 | 502 | page += item; 503 | 504 | item = FPSTR(HTTP_FORM_PARAM); 505 | item.replace("{i}", "gw"); 506 | item.replace("{n}", "gw"); 507 | item.replace("{p}", "Static Gateway"); 508 | item.replace("{l}", "15"); 509 | item.replace("{v}", _sta_static_gw.toString()); 510 | 511 | page += item; 512 | 513 | item = FPSTR(HTTP_FORM_PARAM); 514 | item.replace("{i}", "sn"); 515 | item.replace("{n}", "sn"); 516 | item.replace("{p}", "Subnet"); 517 | item.replace("{l}", "15"); 518 | item.replace("{v}", _sta_static_sn.toString()); 519 | 520 | page += item; 521 | 522 | page += "
"; 523 | } 524 | 525 | page += FPSTR(HTTP_FORM_END); 526 | page += FPSTR(HTTP_SCAN_LINK); 527 | 528 | page += FPSTR(HTTP_END); 529 | 530 | server->send(200, "text/html", page); 531 | 532 | 533 | DEBUG_WM(F("Sent config page")); 534 | } 535 | 536 | /** Handle the WLAN save form and redirect to WLAN config page again */ 537 | void WiFiManager::handleWifiSave() { 538 | DEBUG_WM(F("WiFi save")); 539 | 540 | //SAVE/connect here 541 | _ssid = server->arg("s").c_str(); 542 | _pass = server->arg("p").c_str(); 543 | 544 | //parameters 545 | for (int i = 0; i < _paramsCount; i++) { 546 | if (_params[i] == NULL) { 547 | break; 548 | } 549 | //read parameter 550 | String value = server->arg(_params[i]->getID()).c_str(); 551 | //store it in array 552 | value.toCharArray(_params[i]->_value, _params[i]->_length); 553 | DEBUG_WM(F("Parameter")); 554 | DEBUG_WM(_params[i]->getID()); 555 | DEBUG_WM(value); 556 | } 557 | 558 | if (server->arg("ip") != "") { 559 | DEBUG_WM(F("static ip")); 560 | DEBUG_WM(server->arg("ip")); 561 | //_sta_static_ip.fromString(server->arg("ip")); 562 | String ip = server->arg("ip"); 563 | optionalIPFromString(&_sta_static_ip, ip.c_str()); 564 | } 565 | if (server->arg("gw") != "") { 566 | DEBUG_WM(F("static gateway")); 567 | DEBUG_WM(server->arg("gw")); 568 | String gw = server->arg("gw"); 569 | optionalIPFromString(&_sta_static_gw, gw.c_str()); 570 | } 571 | if (server->arg("sn") != "") { 572 | DEBUG_WM(F("static netmask")); 573 | DEBUG_WM(server->arg("sn")); 574 | String sn = server->arg("sn"); 575 | optionalIPFromString(&_sta_static_sn, sn.c_str()); 576 | } 577 | 578 | String page = FPSTR(HTTP_HEAD); 579 | page.replace("{v}", "Credentials Saved"); 580 | page += FPSTR(HTTP_SCRIPT); 581 | page += FPSTR(HTTP_STYLE); 582 | page += _customHeadElement; 583 | page += FPSTR(HTTP_HEAD_END); 584 | page += FPSTR(HTTP_SAVED); 585 | page += FPSTR(HTTP_END); 586 | 587 | server->send(200, "text/html", page); 588 | 589 | DEBUG_WM(F("Sent wifi save page")); 590 | 591 | connect = true; //signal ready to connect/reset 592 | } 593 | 594 | /** Handle the info page */ 595 | void WiFiManager::handleInfo() { 596 | DEBUG_WM(F("Info")); 597 | 598 | String page = FPSTR(HTTP_HEAD); 599 | page.replace("{v}", "Info"); 600 | page += FPSTR(HTTP_SCRIPT); 601 | page += FPSTR(HTTP_STYLE); 602 | page += _customHeadElement; 603 | page += FPSTR(HTTP_HEAD_END); 604 | page += F("
"); 605 | page += F("
Chip ID
"); 606 | page += ESP.getChipId(); 607 | page += F("
"); 608 | page += F("
Flash Chip ID
"); 609 | page += ESP.getFlashChipId(); 610 | page += F("
"); 611 | page += F("
IDE Flash Size
"); 612 | page += ESP.getFlashChipSize(); 613 | page += F(" bytes
"); 614 | page += F("
Real Flash Size
"); 615 | page += ESP.getFlashChipRealSize(); 616 | page += F(" bytes
"); 617 | page += F("
Soft AP IP
"); 618 | page += WiFi.softAPIP().toString(); 619 | page += F("
"); 620 | page += F("
Soft AP MAC
"); 621 | page += WiFi.softAPmacAddress(); 622 | page += F("
"); 623 | page += F("
Station MAC
"); 624 | page += WiFi.macAddress(); 625 | page += F("
"); 626 | page += F("
"); 627 | page += FPSTR(HTTP_END); 628 | 629 | server->send(200, "text/html", page); 630 | 631 | DEBUG_WM(F("Sent info page")); 632 | } 633 | 634 | /** Handle the reset page */ 635 | void WiFiManager::handleReset() { 636 | DEBUG_WM(F("Reset")); 637 | 638 | String page = FPSTR(HTTP_HEAD); 639 | page.replace("{v}", "Info"); 640 | page += FPSTR(HTTP_SCRIPT); 641 | page += FPSTR(HTTP_STYLE); 642 | page += _customHeadElement; 643 | page += FPSTR(HTTP_HEAD_END); 644 | page += F("Module will reset in a few seconds."); 645 | page += FPSTR(HTTP_END); 646 | server->send(200, "text/html", page); 647 | 648 | DEBUG_WM(F("Sent reset page")); 649 | delay(5000); 650 | ESP.reset(); 651 | delay(2000); 652 | } 653 | 654 | 655 | 656 | //removed as mentioned here https://github.com/tzapu/WiFiManager/issues/114 657 | /*void WiFiManager::handle204() { 658 | DEBUG_WM(F("204 No Response")); 659 | server->sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); 660 | server->sendHeader("Pragma", "no-cache"); 661 | server->sendHeader("Expires", "-1"); 662 | server->send ( 204, "text/plain", ""); 663 | }*/ 664 | 665 | void WiFiManager::handleNotFound() { 666 | if (captivePortal()) { // If captive portal redirect instead of displaying the error page. 667 | return; 668 | } 669 | String message = "File Not Found\n\n"; 670 | message += "URI: "; 671 | message += server->uri(); 672 | message += "\nMethod: "; 673 | message += ( server->method() == HTTP_GET ) ? "GET" : "POST"; 674 | message += "\nArguments: "; 675 | message += server->args(); 676 | message += "\n"; 677 | 678 | for ( uint8_t i = 0; i < server->args(); i++ ) { 679 | message += " " + server->argName ( i ) + ": " + server->arg ( i ) + "\n"; 680 | } 681 | server->sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); 682 | server->sendHeader("Pragma", "no-cache"); 683 | server->sendHeader("Expires", "-1"); 684 | server->send ( 404, "text/plain", message ); 685 | } 686 | 687 | 688 | /** 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. */ 689 | boolean WiFiManager::captivePortal() { 690 | if (!isIp(server->hostHeader()) ) { 691 | DEBUG_WM(F("Request redirected to captive portal")); 692 | server->sendHeader("Location", String("http://") + toStringIp(server->client().localIP()), true); 693 | server->send ( 302, "text/plain", ""); // Empty content inhibits Content-length header so we have to close the socket ourselves. 694 | server->client().stop(); // Stop is needed because we sent no content length 695 | return true; 696 | } 697 | return false; 698 | } 699 | 700 | //start up config portal callback 701 | void WiFiManager::setAPCallback( void (*func)(WiFiManager* myWiFiManager) ) { 702 | _apcallback = func; 703 | } 704 | 705 | //start up save config callback 706 | void WiFiManager::setSaveConfigCallback( void (*func)(void) ) { 707 | _savecallback = func; 708 | } 709 | 710 | //sets a custom element to add to head, like a new style tag 711 | void WiFiManager::setCustomHeadElement(const char* element) { 712 | _customHeadElement = element; 713 | } 714 | 715 | //if this is true, remove duplicated Access Points - defaut true 716 | void WiFiManager::setRemoveDuplicateAPs(boolean removeDuplicates) { 717 | _removeDuplicateAPs = removeDuplicates; 718 | } 719 | 720 | 721 | 722 | template 723 | void WiFiManager::DEBUG_WM(Generic text) { 724 | if (_debug) { 725 | Serial.print("*WM: "); 726 | Serial.println(text); 727 | } 728 | } 729 | 730 | int WiFiManager::getRSSIasQuality(int RSSI) { 731 | int quality = 0; 732 | 733 | if (RSSI <= -100) { 734 | quality = 0; 735 | } else if (RSSI >= -50) { 736 | quality = 100; 737 | } else { 738 | quality = 2 * (RSSI + 100); 739 | } 740 | return quality; 741 | } 742 | 743 | /** Is this an IP? */ 744 | boolean WiFiManager::isIp(String str) { 745 | for (int i = 0; i < str.length(); i++) { 746 | int c = str.charAt(i); 747 | if (c != '.' && (c < '0' || c > '9')) { 748 | return false; 749 | } 750 | } 751 | return true; 752 | } 753 | 754 | /** IP to String? */ 755 | String WiFiManager::toStringIp(IPAddress ip) { 756 | String res = ""; 757 | for (int i = 0; i < 3; i++) { 758 | res += String((ip >> (8 * i)) & 0xFF) + "."; 759 | } 760 | res += String(((ip >> 8 * 3)) & 0xFF); 761 | return res; 762 | } 763 | -------------------------------------------------------------------------------- /WiFiManager.h: -------------------------------------------------------------------------------- 1 | /************************************************************** 2 | WiFiManager is a library for the ESP8266/Arduino platform 3 | (https://github.com/esp8266/Arduino) to enable easy 4 | configuration and reconfiguration of WiFi credentials using a Captive Portal 5 | inspired by: 6 | http://www.esp8266.com/viewtopic.php?f=29&t=2520 7 | https://github.com/chriscook8/esp-arduino-apboot 8 | https://github.com/esp8266/Arduino/tree/esp8266/hardware/esp8266com/esp8266/libraries/DNSServer/examples/CaptivePortalAdvanced 9 | Built by AlexT https://github.com/tzapu 10 | Licensed under MIT license 11 | **************************************************************/ 12 | 13 | #ifndef WiFiManager_h 14 | #define WiFiManager_h 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | extern "C" { 22 | #include "user_interface.h" 23 | } 24 | 25 | const char HTTP_HEAD[] PROGMEM = "{v}"; 26 | const char HTTP_STYLE[] PROGMEM = ""; 27 | const char HTTP_SCRIPT[] PROGMEM = ""; 28 | const char HTTP_HEAD_END[] PROGMEM = "
"; 29 | const char HTTP_PORTAL_OPTIONS[] PROGMEM = "



"; 30 | const char HTTP_ITEM[] PROGMEM = "
{v} {r}%
"; 31 | const char HTTP_FORM_START[] PROGMEM = "


"; 32 | const char HTTP_FORM_PARAM[] PROGMEM = "
"; 33 | const char HTTP_FORM_END[] PROGMEM = "
"; 34 | const char HTTP_SCAN_LINK[] PROGMEM = "
"; 35 | const char HTTP_SAVED[] PROGMEM = "
Credentials Saved
Trying to connect ESP to network.
If it fails reconnect to AP to try again
"; 36 | const char HTTP_END[] PROGMEM = "
"; 37 | 38 | #define WIFI_MANAGER_MAX_PARAMS 10 39 | 40 | class WiFiManagerParameter { 41 | public: 42 | WiFiManagerParameter(const char *custom); 43 | WiFiManagerParameter(const char *id, const char *placeholder, const char *defaultValue, int length); 44 | WiFiManagerParameter(const char *id, const char *placeholder, const char *defaultValue, int length, const char *custom); 45 | 46 | const char *getID(); 47 | const char *getValue(); 48 | const char *getPlaceholder(); 49 | int getValueLength(); 50 | const char *getCustomHTML(); 51 | private: 52 | const char *_id; 53 | const char *_placeholder; 54 | char *_value; 55 | int _length; 56 | const char *_customHTML; 57 | 58 | void init(const char *id, const char *placeholder, const char *defaultValue, int length, const char *custom); 59 | 60 | friend class WiFiManager; 61 | }; 62 | 63 | 64 | class WiFiManager 65 | { 66 | public: 67 | WiFiManager(); 68 | 69 | boolean autoConnect(); 70 | boolean autoConnect(char const *apName, char const *apPassword = NULL); 71 | 72 | //if you want to always start the config portal, without trying to connect first 73 | boolean startConfigPortal(); 74 | boolean startConfigPortal(char const *apName, char const *apPassword = NULL); 75 | 76 | // get the AP name of the config portal, so it can be used in the callback 77 | String getConfigPortalSSID(); 78 | 79 | void resetSettings(); 80 | 81 | //sets timeout before webserver loop ends and exits even if there has been no setup. 82 | //usefully for devices that failed to connect at some point and got stuck in a webserver loop 83 | //in seconds setConfigPortalTimeout is a new name for setTimeout 84 | void setConfigPortalTimeout(unsigned long seconds); 85 | void setTimeout(unsigned long seconds); 86 | 87 | //sets timeout for which to attempt connecting, usefull if you get a lot of failed connects 88 | void setConnectTimeout(unsigned long seconds); 89 | 90 | 91 | void setDebugOutput(boolean debug); 92 | //defaults to not showing anything under 8% signal quality if called 93 | void setMinimumSignalQuality(int quality = 8); 94 | //sets a custom ip /gateway /subnet configuration 95 | void setAPStaticIPConfig(IPAddress ip, IPAddress gw, IPAddress sn); 96 | //sets config for a static IP 97 | void setSTAStaticIPConfig(IPAddress ip, IPAddress gw, IPAddress sn); 98 | //called when AP mode and config portal is started 99 | void setAPCallback( void (*func)(WiFiManager*) ); 100 | //called when settings have been changed and connection was successful 101 | void setSaveConfigCallback( void (*func)(void) ); 102 | //adds a custom parameter 103 | void addParameter(WiFiManagerParameter *p); 104 | //if this is set, it will exit after config, even if connection is unsucessful. 105 | void setBreakAfterConfig(boolean shouldBreak); 106 | //if this is set, try WPS setup when starting (this will delay config portal for up to 2 mins) 107 | //TODO 108 | //if this is set, customise style 109 | void setCustomHeadElement(const char* element); 110 | //if this is true, remove duplicated Access Points - defaut true 111 | void setRemoveDuplicateAPs(boolean removeDuplicates); 112 | 113 | private: 114 | std::unique_ptr dnsServer; 115 | std::unique_ptr server; 116 | 117 | //const int WM_DONE = 0; 118 | //const int WM_WAIT = 10; 119 | 120 | //const String HTTP_HEAD = "{v}"; 121 | 122 | void setupConfigPortal(); 123 | void startWPS(); 124 | 125 | const char* _apName = "no-net"; 126 | const char* _apPassword = NULL; 127 | String _ssid = ""; 128 | String _pass = ""; 129 | unsigned long _configPortalTimeout = 0; 130 | unsigned long _connectTimeout = 0; 131 | unsigned long _configPortalStart = 0; 132 | 133 | IPAddress _ap_static_ip; 134 | IPAddress _ap_static_gw; 135 | IPAddress _ap_static_sn; 136 | IPAddress _sta_static_ip; 137 | IPAddress _sta_static_gw; 138 | IPAddress _sta_static_sn; 139 | 140 | int _paramsCount = 0; 141 | int _minimumQuality = -1; 142 | boolean _removeDuplicateAPs = true; 143 | boolean _shouldBreakAfterConfig = false; 144 | boolean _tryWPS = false; 145 | 146 | const char* _customHeadElement = ""; 147 | 148 | //String getEEPROMString(int start, int len); 149 | //void setEEPROMString(int start, int len, String string); 150 | 151 | int status = WL_IDLE_STATUS; 152 | int connectWifi(String ssid, String pass); 153 | uint8_t waitForConnectResult(); 154 | 155 | void handleRoot(); 156 | void handleWifi(boolean scan); 157 | void handleWifiSave(); 158 | void handleInfo(); 159 | void handleReset(); 160 | void handleNotFound(); 161 | void handle204(); 162 | boolean captivePortal(); 163 | 164 | // DNS server 165 | const byte DNS_PORT = 53; 166 | 167 | //helpers 168 | int getRSSIasQuality(int RSSI); 169 | boolean isIp(String str); 170 | String toStringIp(IPAddress ip); 171 | 172 | boolean connect; 173 | boolean _debug = true; 174 | 175 | void (*_apcallback)(WiFiManager*) = NULL; 176 | void (*_savecallback)(void) = NULL; 177 | 178 | WiFiManagerParameter* _params[WIFI_MANAGER_MAX_PARAMS]; 179 | 180 | template 181 | void DEBUG_WM(Generic text); 182 | 183 | template 184 | auto optionalIPFromString(T *obj, const char *s) -> decltype( obj->fromString(s) ) { 185 | return obj->fromString(s); 186 | } 187 | auto optionalIPFromString(...) -> bool { 188 | DEBUG_WM("NO fromString METHOD ON IPAddress, you need ESP8266 core 2.1.0 or newer for Custom IP configuration to work."); 189 | return false; 190 | } 191 | }; 192 | 193 | #endif 194 | -------------------------------------------------------------------------------- /examples/AutoConnect/AutoConnect.ino: -------------------------------------------------------------------------------- 1 | #include //https://github.com/esp8266/Arduino 2 | 3 | //needed for library 4 | #include 5 | #include 6 | #include //https://github.com/tzapu/WiFiManager 7 | 8 | 9 | void setup() { 10 | // put your setup code here, to run once: 11 | Serial.begin(115200); 12 | 13 | //WiFiManager 14 | //Local intialization. Once its business is done, there is no need to keep it around 15 | WiFiManager wifiManager; 16 | //reset saved settings 17 | //wifiManager.resetSettings(); 18 | 19 | //set custom ip for portal 20 | //wifiManager.setAPConfig(IPAddress(10,0,1,1), IPAddress(10,0,1,1), IPAddress(255,255,255,0)); 21 | 22 | //fetches ssid and pass from eeprom and tries to connect 23 | //if it does not connect it starts an access point with the specified name 24 | //here "AutoConnectAP" 25 | //and goes into a blocking loop awaiting configuration 26 | wifiManager.autoConnect("AutoConnectAP"); 27 | //or use this for auto generated name ESP + ChipID 28 | //wifiManager.autoConnect(); 29 | 30 | 31 | //if you get here you have connected to the WiFi 32 | Serial.println("connected...yeey :)"); 33 | } 34 | 35 | void loop() { 36 | // put your main code here, to run repeatedly: 37 | 38 | } 39 | -------------------------------------------------------------------------------- /examples/AutoConnectWithFSParameters/AutoConnectWithFSParameters.ino: -------------------------------------------------------------------------------- 1 | #include //this needs to be first, or it all crashes and burns... 2 | 3 | #include //https://github.com/esp8266/Arduino 4 | 5 | //needed for library 6 | #include 7 | #include 8 | #include //https://github.com/tzapu/WiFiManager 9 | 10 | #include //https://github.com/bblanchon/ArduinoJson 11 | 12 | //define your default values here, if there are different values in config.json, they are overwritten. 13 | char mqtt_server[40]; 14 | char mqtt_port[6] = "8080"; 15 | char blynk_token[34] = "YOUR_BLYNK_TOKEN"; 16 | 17 | //flag for saving data 18 | bool shouldSaveConfig = false; 19 | 20 | //callback notifying us of the need to save config 21 | void saveConfigCallback () { 22 | Serial.println("Should save config"); 23 | shouldSaveConfig = true; 24 | } 25 | 26 | 27 | void setup() { 28 | // put your setup code here, to run once: 29 | Serial.begin(115200); 30 | Serial.println(); 31 | 32 | //clean FS, for testing 33 | //SPIFFS.format(); 34 | 35 | //read configuration from FS json 36 | Serial.println("mounting FS..."); 37 | 38 | if (SPIFFS.begin()) { 39 | Serial.println("mounted file system"); 40 | if (SPIFFS.exists("/config.json")) { 41 | //file exists, reading and loading 42 | Serial.println("reading config file"); 43 | File configFile = SPIFFS.open("/config.json", "r"); 44 | if (configFile) { 45 | Serial.println("opened config file"); 46 | size_t size = configFile.size(); 47 | // Allocate a buffer to store contents of the file. 48 | std::unique_ptr buf(new char[size]); 49 | 50 | configFile.readBytes(buf.get(), size); 51 | DynamicJsonBuffer jsonBuffer; 52 | JsonObject& json = jsonBuffer.parseObject(buf.get()); 53 | json.printTo(Serial); 54 | if (json.success()) { 55 | Serial.println("\nparsed json"); 56 | 57 | strcpy(mqtt_server, json["mqtt_server"]); 58 | strcpy(mqtt_port, json["mqtt_port"]); 59 | strcpy(blynk_token, json["blynk_token"]); 60 | 61 | } else { 62 | Serial.println("failed to load json config"); 63 | } 64 | } 65 | } 66 | } else { 67 | Serial.println("failed to mount FS"); 68 | } 69 | //end read 70 | 71 | 72 | 73 | // The extra parameters to be configured (can be either global or just in the setup) 74 | // After connecting, parameter.getValue() will get you the configured value 75 | // id/name placeholder/prompt default length 76 | WiFiManagerParameter custom_mqtt_server("server", "mqtt server", mqtt_server, 40); 77 | WiFiManagerParameter custom_mqtt_port("port", "mqtt port", mqtt_port, 6); 78 | WiFiManagerParameter custom_blynk_token("blynk", "blynk token", blynk_token, 32); 79 | 80 | //WiFiManager 81 | //Local intialization. Once its business is done, there is no need to keep it around 82 | WiFiManager wifiManager; 83 | 84 | //set config save notify callback 85 | wifiManager.setSaveConfigCallback(saveConfigCallback); 86 | 87 | //set static ip 88 | wifiManager.setSTAStaticIPConfig(IPAddress(10,0,1,99), IPAddress(10,0,1,1), IPAddress(255,255,255,0)); 89 | 90 | //add all your parameters here 91 | wifiManager.addParameter(&custom_mqtt_server); 92 | wifiManager.addParameter(&custom_mqtt_port); 93 | wifiManager.addParameter(&custom_blynk_token); 94 | 95 | //reset settings - for testing 96 | //wifiManager.resetSettings(); 97 | 98 | //set minimu quality of signal so it ignores AP's under that quality 99 | //defaults to 8% 100 | //wifiManager.setMinimumSignalQuality(); 101 | 102 | //sets timeout until configuration portal gets turned off 103 | //useful to make it all retry or go to sleep 104 | //in seconds 105 | //wifiManager.setTimeout(120); 106 | 107 | //fetches ssid and pass and tries to connect 108 | //if it does not connect it starts an access point with the specified name 109 | //here "AutoConnectAP" 110 | //and goes into a blocking loop awaiting configuration 111 | if (!wifiManager.autoConnect("AutoConnectAP", "password")) { 112 | Serial.println("failed to connect and hit timeout"); 113 | delay(3000); 114 | //reset and try again, or maybe put it to deep sleep 115 | ESP.reset(); 116 | delay(5000); 117 | } 118 | 119 | //if you get here you have connected to the WiFi 120 | Serial.println("connected...yeey :)"); 121 | 122 | //read updated parameters 123 | strcpy(mqtt_server, custom_mqtt_server.getValue()); 124 | strcpy(mqtt_port, custom_mqtt_port.getValue()); 125 | strcpy(blynk_token, custom_blynk_token.getValue()); 126 | 127 | //save the custom parameters to FS 128 | if (shouldSaveConfig) { 129 | Serial.println("saving config"); 130 | DynamicJsonBuffer jsonBuffer; 131 | JsonObject& json = jsonBuffer.createObject(); 132 | json["mqtt_server"] = mqtt_server; 133 | json["mqtt_port"] = mqtt_port; 134 | json["blynk_token"] = blynk_token; 135 | 136 | File configFile = SPIFFS.open("/config.json", "w"); 137 | if (!configFile) { 138 | Serial.println("failed to open config file for writing"); 139 | } 140 | 141 | json.printTo(Serial); 142 | json.printTo(configFile); 143 | configFile.close(); 144 | //end save 145 | } 146 | 147 | Serial.println("local ip"); 148 | Serial.println(WiFi.localIP()); 149 | 150 | } 151 | 152 | void loop() { 153 | // put your main code here, to run repeatedly: 154 | 155 | 156 | } 157 | -------------------------------------------------------------------------------- /examples/AutoConnectWithFSParametersAndCustomIP/AutoConnectWithFSParametersAndCustomIP.ino: -------------------------------------------------------------------------------- 1 | #include //this needs to be first, or it all crashes and burns... 2 | 3 | #include //https://github.com/esp8266/Arduino 4 | 5 | //needed for library 6 | #include 7 | #include 8 | #include //https://github.com/tzapu/WiFiManager 9 | 10 | #include //https://github.com/bblanchon/ArduinoJson 11 | 12 | //define your default values here, if there are different values in config.json, they are overwritten. 13 | //length should be max size + 1 14 | char mqtt_server[40]; 15 | char mqtt_port[6] = "8080"; 16 | char blynk_token[33] = "YOUR_BLYNK_TOKEN"; 17 | //default custom static IP 18 | char static_ip[16] = "10.0.1.56"; 19 | char static_gw[16] = "10.0.1.1"; 20 | char static_sn[16] = "255.255.255.0"; 21 | 22 | //flag for saving data 23 | bool shouldSaveConfig = false; 24 | 25 | //callback notifying us of the need to save config 26 | void saveConfigCallback () { 27 | Serial.println("Should save config"); 28 | shouldSaveConfig = true; 29 | } 30 | 31 | void setup() { 32 | // put your setup code here, to run once: 33 | Serial.begin(115200); 34 | Serial.println(); 35 | 36 | //clean FS, for testing 37 | //SPIFFS.format(); 38 | 39 | //read configuration from FS json 40 | Serial.println("mounting FS..."); 41 | 42 | if (SPIFFS.begin()) { 43 | Serial.println("mounted file system"); 44 | if (SPIFFS.exists("/config.json")) { 45 | //file exists, reading and loading 46 | Serial.println("reading config file"); 47 | File configFile = SPIFFS.open("/config.json", "r"); 48 | if (configFile) { 49 | Serial.println("opened config file"); 50 | size_t size = configFile.size(); 51 | // Allocate a buffer to store contents of the file. 52 | std::unique_ptr buf(new char[size]); 53 | 54 | configFile.readBytes(buf.get(), size); 55 | DynamicJsonBuffer jsonBuffer; 56 | JsonObject& json = jsonBuffer.parseObject(buf.get()); 57 | json.printTo(Serial); 58 | if (json.success()) { 59 | Serial.println("\nparsed json"); 60 | 61 | strcpy(mqtt_server, json["mqtt_server"]); 62 | strcpy(mqtt_port, json["mqtt_port"]); 63 | strcpy(blynk_token, json["blynk_token"]); 64 | 65 | if(json["ip"]) { 66 | Serial.println("setting custom ip from config"); 67 | //static_ip = json["ip"]; 68 | strcpy(static_ip, json["ip"]); 69 | strcpy(static_gw, json["gateway"]); 70 | strcpy(static_sn, json["subnet"]); 71 | //strcat(static_ip, json["ip"]); 72 | //static_gw = json["gateway"]; 73 | //static_sn = json["subnet"]; 74 | Serial.println(static_ip); 75 | /* Serial.println("converting ip"); 76 | IPAddress ip = ipFromCharArray(static_ip); 77 | Serial.println(ip);*/ 78 | } else { 79 | Serial.println("no custom ip in config"); 80 | } 81 | } else { 82 | Serial.println("failed to load json config"); 83 | } 84 | } 85 | } 86 | } else { 87 | Serial.println("failed to mount FS"); 88 | } 89 | //end read 90 | Serial.println(static_ip); 91 | Serial.println(blynk_token); 92 | Serial.println(mqtt_server); 93 | 94 | 95 | // The extra parameters to be configured (can be either global or just in the setup) 96 | // After connecting, parameter.getValue() will get you the configured value 97 | // id/name placeholder/prompt default length 98 | WiFiManagerParameter custom_mqtt_server("server", "mqtt server", mqtt_server, 40); 99 | WiFiManagerParameter custom_mqtt_port("port", "mqtt port", mqtt_port, 5); 100 | WiFiManagerParameter custom_blynk_token("blynk", "blynk token", blynk_token, 34); 101 | 102 | //WiFiManager 103 | //Local intialization. Once its business is done, there is no need to keep it around 104 | WiFiManager wifiManager; 105 | 106 | //set config save notify callback 107 | wifiManager.setSaveConfigCallback(saveConfigCallback); 108 | 109 | //set static ip 110 | IPAddress _ip,_gw,_sn; 111 | _ip.fromString(static_ip); 112 | _gw.fromString(static_gw); 113 | _sn.fromString(static_sn); 114 | 115 | wifiManager.setSTAStaticIPConfig(_ip, _gw, _sn); 116 | 117 | //add all your parameters here 118 | wifiManager.addParameter(&custom_mqtt_server); 119 | wifiManager.addParameter(&custom_mqtt_port); 120 | wifiManager.addParameter(&custom_blynk_token); 121 | 122 | //reset settings - for testing 123 | //wifiManager.resetSettings(); 124 | 125 | //set minimu quality of signal so it ignores AP's under that quality 126 | //defaults to 8% 127 | wifiManager.setMinimumSignalQuality(); 128 | 129 | //sets timeout until configuration portal gets turned off 130 | //useful to make it all retry or go to sleep 131 | //in seconds 132 | //wifiManager.setTimeout(120); 133 | 134 | //fetches ssid and pass and tries to connect 135 | //if it does not connect it starts an access point with the specified name 136 | //here "AutoConnectAP" 137 | //and goes into a blocking loop awaiting configuration 138 | if (!wifiManager.autoConnect("AutoConnectAP", "password")) { 139 | Serial.println("failed to connect and hit timeout"); 140 | delay(3000); 141 | //reset and try again, or maybe put it to deep sleep 142 | ESP.reset(); 143 | delay(5000); 144 | } 145 | 146 | //if you get here you have connected to the WiFi 147 | Serial.println("connected...yeey :)"); 148 | 149 | //read updated parameters 150 | strcpy(mqtt_server, custom_mqtt_server.getValue()); 151 | strcpy(mqtt_port, custom_mqtt_port.getValue()); 152 | strcpy(blynk_token, custom_blynk_token.getValue()); 153 | 154 | //save the custom parameters to FS 155 | if (shouldSaveConfig) { 156 | Serial.println("saving config"); 157 | DynamicJsonBuffer jsonBuffer; 158 | JsonObject& json = jsonBuffer.createObject(); 159 | json["mqtt_server"] = mqtt_server; 160 | json["mqtt_port"] = mqtt_port; 161 | json["blynk_token"] = blynk_token; 162 | 163 | json["ip"] = WiFi.localIP().toString(); 164 | json["gateway"] = WiFi.gatewayIP().toString(); 165 | json["subnet"] = WiFi.subnetMask().toString(); 166 | 167 | File configFile = SPIFFS.open("/config.json", "w"); 168 | if (!configFile) { 169 | Serial.println("failed to open config file for writing"); 170 | } 171 | 172 | json.prettyPrintTo(Serial); 173 | json.printTo(configFile); 174 | configFile.close(); 175 | //end save 176 | } 177 | 178 | Serial.println("local ip"); 179 | Serial.println(WiFi.localIP()); 180 | Serial.println(WiFi.gatewayIP()); 181 | Serial.println(WiFi.subnetMask()); 182 | } 183 | 184 | void loop() { 185 | // put your main code here, to run repeatedly: 186 | 187 | 188 | } 189 | -------------------------------------------------------------------------------- /examples/AutoConnectWithFeedback/AutoConnectWithFeedback.ino: -------------------------------------------------------------------------------- 1 | #include //https://github.com/esp8266/Arduino 2 | 3 | //needed for library 4 | #include 5 | #include 6 | #include "WiFiManager.h" //https://github.com/tzapu/WiFiManager 7 | 8 | void configModeCallback (WiFiManager *myWiFiManager) { 9 | Serial.println("Entered config mode"); 10 | Serial.println(WiFi.softAPIP()); 11 | //if you used auto generated SSID, print it 12 | Serial.println(myWiFiManager->getConfigPortalSSID()); 13 | } 14 | 15 | void setup() { 16 | // put your setup code here, to run once: 17 | Serial.begin(115200); 18 | 19 | //WiFiManager 20 | //Local intialization. Once its business is done, there is no need to keep it around 21 | WiFiManager wifiManager; 22 | //reset settings - for testing 23 | //wifiManager.resetSettings(); 24 | 25 | //set callback that gets called when connecting to previous WiFi fails, and enters Access Point mode 26 | wifiManager.setAPCallback(configModeCallback); 27 | 28 | //fetches ssid and pass and tries to connect 29 | //if it does not connect it starts an access point with the specified name 30 | //here "AutoConnectAP" 31 | //and goes into a blocking loop awaiting configuration 32 | if(!wifiManager.autoConnect()) { 33 | Serial.println("failed to connect and hit timeout"); 34 | //reset and try again, or maybe put it to deep sleep 35 | ESP.reset(); 36 | delay(1000); 37 | } 38 | 39 | //if you get here you have connected to the WiFi 40 | Serial.println("connected...yeey :)"); 41 | 42 | } 43 | 44 | void loop() { 45 | // put your main code here, to run repeatedly: 46 | 47 | } 48 | -------------------------------------------------------------------------------- /examples/AutoConnectWithFeedbackLED/AutoConnectWithFeedbackLED.ino: -------------------------------------------------------------------------------- 1 | #include //https://github.com/esp8266/Arduino 2 | 3 | //needed for library 4 | #include 5 | #include 6 | #include //https://github.com/tzapu/WiFiManager 7 | 8 | //for LED status 9 | #include 10 | Ticker ticker; 11 | 12 | void tick() 13 | { 14 | //toggle state 15 | int state = digitalRead(BUILTIN_LED); // get the current state of GPIO1 pin 16 | digitalWrite(BUILTIN_LED, !state); // set pin to the opposite state 17 | } 18 | 19 | //gets called when WiFiManager enters configuration mode 20 | void configModeCallback (WiFiManager *myWiFiManager) { 21 | Serial.println("Entered config mode"); 22 | Serial.println(WiFi.softAPIP()); 23 | //if you used auto generated SSID, print it 24 | Serial.println(myWiFiManager->getConfigPortalSSID()); 25 | //entered config mode, make led toggle faster 26 | ticker.attach(0.2, tick); 27 | } 28 | 29 | void setup() { 30 | // put your setup code here, to run once: 31 | Serial.begin(115200); 32 | 33 | //set led pin as output 34 | pinMode(BUILTIN_LED, OUTPUT); 35 | // start ticker with 0.5 because we start in AP mode and try to connect 36 | ticker.attach(0.6, tick); 37 | 38 | //WiFiManager 39 | //Local intialization. Once its business is done, there is no need to keep it around 40 | WiFiManager wifiManager; 41 | //reset settings - for testing 42 | //wifiManager.resetSettings(); 43 | 44 | //set callback that gets called when connecting to previous WiFi fails, and enters Access Point mode 45 | wifiManager.setAPCallback(configModeCallback); 46 | 47 | //fetches ssid and pass and tries to connect 48 | //if it does not connect it starts an access point with the specified name 49 | //here "AutoConnectAP" 50 | //and goes into a blocking loop awaiting configuration 51 | if (!wifiManager.autoConnect()) { 52 | Serial.println("failed to connect and hit timeout"); 53 | //reset and try again, or maybe put it to deep sleep 54 | ESP.reset(); 55 | delay(1000); 56 | } 57 | 58 | //if you get here you have connected to the WiFi 59 | Serial.println("connected...yeey :)"); 60 | ticker.detach(); 61 | //keep LED on 62 | digitalWrite(BUILTIN_LED, LOW); 63 | } 64 | 65 | void loop() { 66 | // put your main code here, to run repeatedly: 67 | 68 | } 69 | -------------------------------------------------------------------------------- /examples/AutoConnectWithReset/AutoConnectWithReset.ino: -------------------------------------------------------------------------------- 1 | #include //this needs to be first, or it all crashes and burns... 2 | 3 | #include //https://github.com/esp8266/Arduino 4 | 5 | //needed for library 6 | #include 7 | #include 8 | #include //https://github.com/tzapu/WiFiManager 9 | 10 | void setup() { 11 | // put your setup code here, to run once: 12 | Serial.begin(115200); 13 | Serial.println(); 14 | 15 | //WiFiManager 16 | //Local intialization. Once its business is done, there is no need to keep it around 17 | WiFiManager wifiManager; 18 | 19 | //exit after config instead of connecting 20 | wifiManager.setBreakAfterConfig(true); 21 | 22 | //reset settings - for testing 23 | //wifiManager.resetSettings(); 24 | 25 | 26 | //tries to connect to last known settings 27 | //if it does not connect it starts an access point with the specified name 28 | //here "AutoConnectAP" with password "password" 29 | //and goes into a blocking loop awaiting configuration 30 | if (!wifiManager.autoConnect("AutoConnectAP", "password")) { 31 | Serial.println("failed to connect, we should reset as see if it connects"); 32 | delay(3000); 33 | ESP.reset(); 34 | delay(5000); 35 | } 36 | 37 | //if you get here you have connected to the WiFi 38 | Serial.println("connected...yeey :)"); 39 | 40 | 41 | Serial.println("local ip"); 42 | Serial.println(WiFi.localIP()); 43 | } 44 | 45 | void loop() { 46 | // put your main code here, to run repeatedly: 47 | 48 | 49 | } 50 | -------------------------------------------------------------------------------- /examples/AutoConnectWithStaticIP/AutoConnectWithStaticIP.ino: -------------------------------------------------------------------------------- 1 | #include //this needs to be first, or it all crashes and burns... 2 | 3 | #include //https://github.com/esp8266/Arduino 4 | 5 | //needed for library 6 | #include 7 | #include 8 | #include //https://github.com/tzapu/WiFiManager 9 | 10 | 11 | /************************************************************************************** 12 | * this example shows how to set a static IP configuration for the ESP 13 | * although the IP shows in the config portal, the changes will revert 14 | * to the IP set in the source file. 15 | * if you want the ability to configure and persist the new IP configuration 16 | * look at the FS examples, which save the config to file 17 | *************************************************************************************/ 18 | 19 | 20 | 21 | //default custom static IP 22 | //char static_ip[16] = "10.0.1.59"; 23 | //char static_gw[16] = "10.0.1.1"; 24 | //char static_sn[16] = "255.255.255.0"; 25 | 26 | void setup() { 27 | // put your setup code here, to run once: 28 | Serial.begin(115200); 29 | Serial.println(); 30 | 31 | //WiFiManager 32 | //Local intialization. Once its business is done, there is no need to keep it around 33 | WiFiManager wifiManager; 34 | 35 | //reset settings - for testing 36 | //wifiManager.resetSettings(); 37 | 38 | //set static ip 39 | //block1 should be used for ESP8266 core 2.1.0 or newer, otherwise use block2 40 | 41 | //start-block1 42 | //IPAddress _ip,_gw,_sn; 43 | //_ip.fromString(static_ip); 44 | //_gw.fromString(static_gw); 45 | //_sn.fromString(static_sn); 46 | //end-block1 47 | 48 | //start-block2 49 | IPAddress _ip = IPAddress(10, 0, 1, 78); 50 | IPAddress _gw = IPAddress(10, 0, 1, 1); 51 | IPAddress _sn = IPAddress(255, 255, 255, 0); 52 | //end-block2 53 | 54 | wifiManager.setSTAStaticIPConfig(_ip, _gw, _sn); 55 | 56 | 57 | //tries to connect to last known settings 58 | //if it does not connect it starts an access point with the specified name 59 | //here "AutoConnectAP" with password "password" 60 | //and goes into a blocking loop awaiting configuration 61 | if (!wifiManager.autoConnect("AutoConnectAP", "password")) { 62 | Serial.println("failed to connect, we should reset as see if it connects"); 63 | delay(3000); 64 | ESP.reset(); 65 | delay(5000); 66 | } 67 | 68 | //if you get here you have connected to the WiFi 69 | Serial.println("connected...yeey :)"); 70 | 71 | 72 | Serial.println("local ip"); 73 | Serial.println(WiFi.localIP()); 74 | } 75 | 76 | void loop() { 77 | // put your main code here, to run repeatedly: 78 | 79 | 80 | } 81 | -------------------------------------------------------------------------------- /examples/AutoConnectWithTimeout/AutoConnectWithTimeout.ino: -------------------------------------------------------------------------------- 1 | #include //https://github.com/esp8266/Arduino 2 | 3 | //needed for library 4 | #include 5 | #include 6 | #include //https://github.com/tzapu/WiFiManager 7 | 8 | 9 | 10 | void setup() { 11 | // put your setup code here, to run once: 12 | Serial.begin(115200); 13 | 14 | //WiFiManager 15 | //Local intialization. Once its business is done, there is no need to keep it around 16 | WiFiManager wifiManager; 17 | //reset settings - for testing 18 | //wifiManager.resetSettings(); 19 | 20 | //sets timeout until configuration portal gets turned off 21 | //useful to make it all retry or go to sleep 22 | //in seconds 23 | wifiManager.setTimeout(180); 24 | 25 | //fetches ssid and pass and tries to connect 26 | //if it does not connect it starts an access point with the specified name 27 | //here "AutoConnectAP" 28 | //and goes into a blocking loop awaiting configuration 29 | if(!wifiManager.autoConnect("AutoConnectAP")) { 30 | Serial.println("failed to connect and hit timeout"); 31 | delay(3000); 32 | //reset and try again, or maybe put it to deep sleep 33 | ESP.reset(); 34 | delay(5000); 35 | } 36 | 37 | //if you get here you have connected to the WiFi 38 | Serial.println("connected...yeey :)"); 39 | 40 | } 41 | 42 | void loop() { 43 | // put your main code here, to run repeatedly: 44 | 45 | } 46 | -------------------------------------------------------------------------------- /examples/OnDemandConfigPortal/OnDemandConfigPortal.ino: -------------------------------------------------------------------------------- 1 | #include //https://github.com/esp8266/Arduino 2 | 3 | //needed for library 4 | #include 5 | #include 6 | #include //https://github.com/tzapu/WiFiManager 7 | 8 | // select wich pin will trigger the configuraton portal when set to LOW 9 | // ESP-01 users please note: the only pins available (0 and 2), are shared 10 | // with the bootloader, so always set them HIGH at power-up 11 | #define TRIGGER_PIN 0 12 | 13 | 14 | void setup() { 15 | // put your setup code here, to run once: 16 | Serial.begin(115200); 17 | Serial.println("\n Starting"); 18 | 19 | pinMode(TRIGGER_PIN, INPUT); 20 | } 21 | 22 | 23 | void loop() { 24 | // is configuration portal requested? 25 | if ( digitalRead(TRIGGER_PIN) == LOW ) { 26 | //WiFiManager 27 | //Local intialization. Once its business is done, there is no need to keep it around 28 | WiFiManager wifiManager; 29 | 30 | //reset settings - for testing 31 | //wifiManager.resetSettings(); 32 | 33 | //sets timeout until configuration portal gets turned off 34 | //useful to make it all retry or go to sleep 35 | //in seconds 36 | //wifiManager.setTimeout(120); 37 | 38 | //it starts an access point with the specified name 39 | //here "AutoConnectAP" 40 | //and goes into a blocking loop awaiting configuration 41 | 42 | //WITHOUT THIS THE AP DOES NOT SEEM TO WORK PROPERLY WITH SDK 1.5 , update to at least 1.5.1 43 | //WiFi.mode(WIFI_STA); 44 | 45 | if (!wifiManager.startConfigPortal("OnDemandAP")) { 46 | Serial.println("failed to connect and hit timeout"); 47 | delay(3000); 48 | //reset and try again, or maybe put it to deep sleep 49 | ESP.reset(); 50 | delay(5000); 51 | } 52 | 53 | //if you get here you have connected to the WiFi 54 | Serial.println("connected...yeey :)"); 55 | } 56 | 57 | 58 | // put your main code here, to run repeatedly: 59 | 60 | } 61 | -------------------------------------------------------------------------------- /extras/WiFiManager.template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {v} 7 | 8 | 9 | 18 | 19 | 20 | 23 | 24 | 25 | 26 | 27 |
28 | 29 | 30 | 38 | 39 | 43 | 44 | 45 | 46 |



47 | 48 | 49 |
{v} {r}%
50 |
PMisa 100%
51 | 52 |
PMisa 8%
53 | 54 | 55 |
{v} {r}%
56 | 57 | 58 |


59 | 60 | 61 |
62 | 63 | 64 |
65 | 66 | 67 |
68 | 69 | 70 |
Credentials Saved
Trying to connect ESP to network.
If it fails reconnect to AP to try again
71 | 72 | 73 | 74 | 75 | 76 | 77 |
78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /extras/parse.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'); 4 | 5 | console.log('starting'); 6 | 7 | const inFile = 'WiFiManager.template.html'; 8 | const outFile = 'template.h'; 9 | 10 | const defineRegEx = //gm; 11 | console.log('parsing', inFile); 12 | 13 | fs.readFile(inFile, 'utf8', function (err,data) { 14 | if (err) { 15 | return console.log(err); 16 | } 17 | //console.log(data); 18 | 19 | let defines = data.match(defineRegEx); 20 | 21 | //console.log(defines); 22 | var stream = fs.createWriteStream(outFile); 23 | stream.once('open', function(fd) { 24 | for (const i in defines) { 25 | 26 | const start = defines[i]; 27 | const end = start.replace('