├── .gitattributes ├── 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 /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto -------------------------------------------------------------------------------- /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 | ESP32&&ESP8266 WiFi Connection manager with fallback web configuration portal 3 | 4 | 5 | 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. 6 | 7 | First attempt at a library. Lots more changes and fixes to do. Contributions are welcome. 8 | 9 | ## Libray 10 | [WebServer https://github.com/zhouhan0126/WebServer-esp32](https://github.com/zhouhan0126/WebServer-esp32) 11 | 12 | [DNSServer https://github.com/zhouhan0126/DNSServer---esp32](https://github.com/zhouhan0126/DNSServer---esp32) 13 | 14 | ## How It Looks 15 | ![ESP8266 WiFi Captive Portal Homepage](http://i.imgur.com/YPvW9eql.png) ![ESP8266 WiFi Captive Portal Configuration](http://i.imgur.com/oicWJ4gl.png) 16 | 17 | 18 | ### Using 19 | - Include in your sketch 20 | ```cpp 21 | #if defined(ESP8266) 22 | #include 23 | #else 24 | #include 25 | #endif 26 | 27 | //needed for library 28 | #include 29 | #if defined(ESP8266) 30 | #include 31 | #else 32 | #include 33 | #endif 34 | #include 35 | 36 | ``` 37 | 38 | - Initialize library, in your setup function add 39 | ```cpp 40 | WiFiManager wifiManager; 41 | ``` 42 | 43 | - Also in the setup function add 44 | ```cpp 45 | //first parameter is name of access point, second is the password 46 | wifiManager.autoConnect("AP-NAME", "AP-PASSWORD"); 47 | ``` 48 | if you just want an unsecured access point 49 | ```cpp 50 | wifiManager.autoConnect("AP-NAME"); 51 | ``` 52 | or if you want to use and auto generated name from 'ESP' and the esp's Chip ID use 53 | ```cpp 54 | wifiManager.autoConnect(); 55 | ``` 56 | 57 | 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. 58 | 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. 59 | 60 | Also see [examples](https://github.com/tzapu/WiFiManager/tree/master/examples). 61 | 62 | ## Documentation 63 | 64 | #### Password protect the configuration Access Point 65 | You can and should password protect the configuration access point. Simply add the password as a second parameter to `autoConnect`. 66 | A short password seems to have unpredictable results so use one that's around 8 characters or more in length. 67 | The guidelines are that a wifi password must consist of 8 to 63 ASCII-encoded characters in the range of 32 to 126 (decimal) 68 | ```cpp 69 | wifiManager.autoConnect("AutoConnectAP", "password") 70 | ``` 71 | 72 | #### Callbacks 73 | ##### Enter Config mode 74 | Use this if you need to do something when your device enters configuration mode on failed WiFi connection attempt. 75 | Before `autoConnect()` 76 | ```cpp 77 | wifiManager.setAPCallback(configModeCallback); 78 | ``` 79 | `configModeCallback` declaration and example 80 | ```cpp 81 | void configModeCallback (WiFiManager *myWiFiManager) { 82 | Serial.println("Entered config mode"); 83 | Serial.println(WiFi.softAPIP()); 84 | 85 | Serial.println(myWiFiManager->getConfigPortalSSID()); 86 | } 87 | ``` 88 | 89 | ##### Save settings 90 | 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. 91 | 92 | See [AutoConnectWithFSParameters Example](https://github.com/tzapu/WiFiManager/tree/master/examples/AutoConnectWithFSParameters). 93 | ```cpp 94 | wifiManager.setSaveConfigCallback(saveConfigCallback); 95 | ``` 96 | `saveConfigCallback` declaration and example 97 | ```cpp 98 | //flag for saving data 99 | bool shouldSaveConfig = false; 100 | 101 | //callback notifying us of the need to save config 102 | void saveConfigCallback () { 103 | Serial.println("Should save config"); 104 | shouldSaveConfig = true; 105 | } 106 | ``` 107 | 108 | #### Configuration Portal Timeout 109 | 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 110 | ```cpp 111 | wifiManager.setConfigPortalTimeout(180); 112 | ``` 113 | which will wait 3 minutes (180 seconds). When the time passes, the autoConnect function will return, no matter the outcome. 114 | 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) 115 | 116 | #### On Demand Configuration Portal 117 | If you would rather start the configuration portal on demand rather than automatically on a failed connection attempt, then this is for you. 118 | 119 | 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.__ 120 | 121 | Example usage 122 | ```cpp 123 | void loop() { 124 | // is configuration portal requested? 125 | if ( digitalRead(TRIGGER_PIN) == LOW ) { 126 | WiFiManager wifiManager; 127 | wifiManager.startConfigPortal("OnDemandAP"); 128 | Serial.println("connected...yeey :)"); 129 | } 130 | } 131 | ``` 132 | See example for a more complex version. [OnDemandConfigPortal](https://github.com/tzapu/WiFiManager/tree/master/examples/OnDemandConfigPortal) 133 | 134 | #### Custom Parameters 135 | You can use WiFiManager to collect more parameters than just SSID and password. 136 | 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. 137 | **You are responsible for saving and loading these custom values.** The library just collects and displays the data for you as a convenience. 138 | Usage scenario would be: 139 | - load values from somewhere (EEPROM/FS) or generate some defaults 140 | - add the custom parameters to WiFiManager using 141 | ```cpp 142 | // id/name, placeholder/prompt, default, length 143 | WiFiManagerParameter custom_mqtt_server("server", "mqtt server", mqtt_server, 40); 144 | wifiManager.addParameter(&custom_mqtt_server); 145 | 146 | ``` 147 | - if connection to AP fails, configuration portal starts and you can set /change the values (or use on demand configuration portal) 148 | - once configuration is done and connection is established [save config callback]() is called 149 | - once WiFiManager returns control to your application, read and save the new values using the `WiFiManagerParameter` object. 150 | ```cpp 151 | mqtt_server = custom_mqtt_server.getValue(); 152 | ``` 153 | This feature is a lot more involved than all the others, so here are some examples to fully show how it is done. 154 | You should also take a look at adding custom HTML to your form. 155 | 156 | - Save and load custom parameters to file system in json form [AutoConnectWithFSParameters](https://github.com/tzapu/WiFiManager/tree/master/examples/AutoConnectWithFSParameters) 157 | - *Save and load custom parameters to EEPROM* (not done yet) 158 | 159 | #### Custom IP Configuration 160 | You can set a custom IP for both AP (access point, config mode) and STA (station mode, client mode, normal project state) 161 | 162 | ##### Custom Access Point IP Configuration 163 | This will set your captive portal to a specific IP should you need/want such a feature. Add the following snippet before `autoConnect()` 164 | ```cpp 165 | //set custom ip for portal 166 | wifiManager.setAPStaticIPConfig(IPAddress(10,0,1,1), IPAddress(10,0,1,1), IPAddress(255,255,255,0)); 167 | ``` 168 | 169 | ##### Custom Station (client) Static IP Configuration 170 | This will make use the specified IP configuration instead of using DHCP in station mode. 171 | ```cpp 172 | wifiManager.setSTAStaticIPConfig(IPAddress(192,168,0,99), IPAddress(192,168,0,1), IPAddress(255,255,255,0)); 173 | ``` 174 | 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. 175 | 176 | #### Custom HTML, CSS, Javascript 177 | There are various ways in which you can inject custom HTML, CSS or Javascript into the configuration portal. 178 | The options are: 179 | - inject custom head element 180 | You can use this to any html bit to the head of the configuration portal. If you add a `"); 183 | ``` 184 | - inject a custom bit of html in the configuration form 185 | ```cpp 186 | WiFiManagerParameter custom_text("

This is just a text paragraph

"); 187 | wifiManager.addParameter(&custom_text); 188 | ``` 189 | - inject a custom bit of html in a configuration form element 190 | Just add the bit you want added as the last parameter to the custom parameter constructor. 191 | ```cpp 192 | WiFiManagerParameter custom_mqtt_server("server", "mqtt server", "iot.eclipse", 40, " readonly"); 193 | ``` 194 | 195 | #### Filter Networks 196 | You can filter networks based on signal quality and show/hide duplicate networks. 197 | 198 | - If you would like to filter low signal quality networks you can tell WiFiManager to not show networks below an arbitrary quality %; 199 | ```cpp 200 | wifiManager.setMinimumSignalQuality(10); 201 | ``` 202 | will not show networks under 10% signal quality. If you omit the parameter it defaults to 8%; 203 | 204 | - You can also remove or show duplicate networks (default is remove). 205 | Use this function to show (or hide) all networks. 206 | ```cpp 207 | wifiManager.setRemoveDuplicateAPs(false); 208 | ``` 209 | 210 | #### Debug 211 | Debug is enabled by default on Serial. To disable add before autoConnect 212 | ```cpp 213 | wifiManager.setDebugOutput(false); 214 | ``` 215 | 216 | 217 | ### Contributions and thanks 218 | 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. 219 | 220 | __THANK YOU__ 221 | 222 | [Shawn A](https://github.com/tablatronix) 223 | 224 | [Maximiliano Duarte](https://github.com/domonetic) 225 | 226 | [alltheblinkythings](https://github.com/alltheblinkythings) 227 | 228 | [Niklas Wall](https://github.com/niklaswall) 229 | 230 | [Jakub Piasecki](https://github.com/zaporylie) 231 | 232 | [Peter Allan](https://github.com/alwynallan) 233 | 234 | [John Little](https://github.com/j0hnlittle) 235 | 236 | [markaswift](https://github.com/markaswift) 237 | 238 | [franklinvv](https://github.com/franklinvv) 239 | 240 | [Alberto Ricci Bitti](https://github.com/riccibitti) 241 | 242 | [SebiPanther](https://github.com/SebiPanther) 243 | 244 | [jonathanendersby](https://github.com/jonathanendersby) 245 | 246 | [walthercarsten](https://github.com/walthercarsten) 247 | 248 | Sorry if i have missed anyone. 249 | 250 | #### Inspiration 251 | - http://www.esp8266.com/viewtopic.php?f=29&t=2520 252 | -------------------------------------------------------------------------------- /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/master/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 | if(_paramsCount + 1 > WIFI_MANAGER_MAX_PARAMS) 68 | { 69 | //Max parameters exceeded! 70 | DEBUG_WM("WIFI_MANAGER_MAX_PARAMS exceeded, increase number (in WiFiManager.h) before adding more parameters!"); 71 | DEBUG_WM("Skipping parameter with ID:"); 72 | DEBUG_WM(p->getID()); 73 | return; 74 | } 75 | _params[_paramsCount] = p; 76 | _paramsCount++; 77 | DEBUG_WM("Adding parameter"); 78 | DEBUG_WM(p->getID()); 79 | } 80 | 81 | void WiFiManager::setupConfigPortal() { 82 | dnsServer.reset(new DNSServer()); 83 | #ifdef ESP8266 84 | server.reset(new ESP8266WebServer(80)); 85 | #else 86 | server.reset(new WebServer(80)); 87 | #endif 88 | 89 | DEBUG_WM(F("")); 90 | _configPortalStart = millis(); 91 | 92 | DEBUG_WM(F("Configuring access point... ")); 93 | DEBUG_WM(_apName); 94 | if (_apPassword != NULL) { 95 | if (strlen(_apPassword) < 8 || strlen(_apPassword) > 63) { 96 | // fail passphrase to short or long! 97 | DEBUG_WM(F("Invalid AccessPoint password. Ignoring")); 98 | _apPassword = NULL; 99 | } 100 | DEBUG_WM(_apPassword); 101 | } 102 | 103 | //optional soft ip config 104 | if (_ap_static_ip) { 105 | DEBUG_WM(F("Custom AP IP/GW/Subnet")); 106 | WiFi.softAPConfig(_ap_static_ip, _ap_static_gw, _ap_static_sn); 107 | } 108 | 109 | if (_apPassword != NULL) { 110 | WiFi.softAP(_apName, _apPassword);//password option 111 | } else { 112 | WiFi.softAP(_apName); 113 | } 114 | 115 | delay(500); // Without delay I've seen the IP address blank 116 | DEBUG_WM(F("AP IP address: ")); 117 | DEBUG_WM(WiFi.softAPIP()); 118 | 119 | /* Setup the DNS server redirecting all the domains to the apIP */ 120 | dnsServer->setErrorReplyCode(DNSReplyCode::NoError); 121 | dnsServer->start(DNS_PORT, "*", WiFi.softAPIP()); 122 | 123 | /* Setup web pages: root, wifi config pages, SO captive portal detectors and not found. */ 124 | server->on("/", std::bind(&WiFiManager::handleRoot, this)); 125 | server->on("/wifi", std::bind(&WiFiManager::handleWifi, this, true)); 126 | server->on("/0wifi", std::bind(&WiFiManager::handleWifi, this, false)); 127 | server->on("/wifisave", std::bind(&WiFiManager::handleWifiSave, this)); 128 | server->on("/i", std::bind(&WiFiManager::handleInfo, this)); 129 | server->on("/r", std::bind(&WiFiManager::handleReset, this)); 130 | //server->on("/generate_204", std::bind(&WiFiManager::handle204, this)); //Android/Chrome OS captive portal check. 131 | server->on("/fwlink", std::bind(&WiFiManager::handleRoot, this)); //Microsoft captive portal. Maybe not needed. Might be handled by notFound handler. 132 | server->onNotFound (std::bind(&WiFiManager::handleNotFound, this)); 133 | server->begin(); // Web server start 134 | DEBUG_WM(F("HTTP server started")); 135 | 136 | } 137 | 138 | boolean WiFiManager::autoConnect() { 139 | String ssid = "ESP" + String(ESP_getChipId()); 140 | return autoConnect(ssid.c_str(), NULL); 141 | } 142 | 143 | boolean WiFiManager::autoConnect(char const *apName, char const *apPassword) { 144 | DEBUG_WM(F("")); 145 | DEBUG_WM(F("AutoConnect")); 146 | 147 | // read eeprom for ssid and pass 148 | //String ssid = getSSID(); 149 | //String pass = getPassword(); 150 | 151 | // attempt to connect; should it fail, fall back to AP 152 | WiFi.mode(WIFI_STA); 153 | 154 | if (connectWifi("", "") == WL_CONNECTED) { 155 | DEBUG_WM(F("IP Address:")); 156 | DEBUG_WM(WiFi.localIP()); 157 | //connected 158 | return true; 159 | } 160 | 161 | return startConfigPortal(apName, apPassword); 162 | } 163 | 164 | boolean WiFiManager::configPortalHasTimeout(){ 165 | #if defined(ESP8266) 166 | if(_configPortalTimeout == 0 || wifi_softap_get_station_num() > 0){ 167 | #else 168 | if(_configPortalTimeout == 0){ // TODO 169 | #endif 170 | _configPortalStart = millis(); // kludge, bump configportal start time to skew timeouts 171 | return false; 172 | } 173 | return (millis() > _configPortalStart + _configPortalTimeout); 174 | } 175 | 176 | boolean WiFiManager::startConfigPortal() { 177 | String ssid = "ESP" + String(ESP_getChipId()); 178 | return startConfigPortal(ssid.c_str(), NULL); 179 | } 180 | 181 | boolean WiFiManager::startConfigPortal(char const *apName, char const *apPassword) { 182 | //setup AP 183 | WiFi.mode(WIFI_AP_STA); 184 | DEBUG_WM("SET AP STA"); 185 | 186 | _apName = apName; 187 | _apPassword = apPassword; 188 | 189 | //notify we entered AP mode 190 | if ( _apcallback != NULL) { 191 | _apcallback(this); 192 | } 193 | 194 | connect = false; 195 | setupConfigPortal(); 196 | 197 | while(1){ 198 | 199 | // check if timeout 200 | if(configPortalHasTimeout()) break; 201 | 202 | //DNS 203 | dnsServer->processNextRequest(); 204 | //HTTP 205 | server->handleClient(); 206 | 207 | 208 | if (connect) { 209 | connect = false; 210 | delay(2000); 211 | DEBUG_WM(F("Connecting to new AP")); 212 | 213 | // using user-provided _ssid, _pass in place of system-stored ssid and pass 214 | if (connectWifi(_ssid, _pass) != WL_CONNECTED) { 215 | DEBUG_WM(F("Failed to connect.")); 216 | } else { 217 | //connected 218 | WiFi.mode(WIFI_STA); 219 | //notify that configuration has changed and any optional parameters should be saved 220 | if ( _savecallback != NULL) { 221 | //todo: check if any custom parameters actually exist, and check if they really changed maybe 222 | _savecallback(); 223 | } 224 | break; 225 | } 226 | 227 | if (_shouldBreakAfterConfig) { 228 | //flag set to exit after config after trying to connect 229 | //notify that configuration has changed and any optional parameters should be saved 230 | if ( _savecallback != NULL) { 231 | //todo: check if any custom parameters actually exist, and check if they really changed maybe 232 | _savecallback(); 233 | } 234 | break; 235 | } 236 | } 237 | yield(); 238 | } 239 | 240 | server.reset(); 241 | dnsServer.reset(); 242 | 243 | return WiFi.status() == WL_CONNECTED; 244 | } 245 | 246 | 247 | int WiFiManager::connectWifi(String ssid, String pass) { 248 | DEBUG_WM(F("Connecting as wifi client...")); 249 | 250 | // check if we've got static_ip settings, if we do, use those. 251 | if (_sta_static_ip) { 252 | DEBUG_WM(F("Custom STA IP/GW/Subnet")); 253 | WiFi.config(_sta_static_ip, _sta_static_gw, _sta_static_sn); 254 | DEBUG_WM(WiFi.localIP()); 255 | } 256 | //fix for auto connect racing issue 257 | if (WiFi.status() == WL_CONNECTED) { 258 | DEBUG_WM("Already connected. Bailing out."); 259 | return WL_CONNECTED; 260 | } 261 | //check if we have ssid and pass and force those, if not, try with last saved values 262 | if (ssid != "") { 263 | WiFi.begin(ssid.c_str(), pass.c_str()); 264 | } else { 265 | if (WiFi.SSID()) { 266 | DEBUG_WM("Using last saved values, should be faster"); 267 | #if defined(ESP8266) 268 | //trying to fix connection in progress hanging 269 | ETS_UART_INTR_DISABLE(); 270 | wifi_station_disconnect(); 271 | ETS_UART_INTR_ENABLE(); 272 | #else 273 | esp_wifi_disconnect(); 274 | #endif 275 | 276 | WiFi.begin(); 277 | } else { 278 | DEBUG_WM("No saved credentials"); 279 | } 280 | } 281 | 282 | int connRes = waitForConnectResult(); 283 | DEBUG_WM ("Connection result: "); 284 | DEBUG_WM ( connRes ); 285 | //not connected, WPS enabled, no pass - first attempt 286 | if (_tryWPS && connRes != WL_CONNECTED && pass == "") { 287 | startWPS(); 288 | //should be connected at the end of WPS 289 | connRes = waitForConnectResult(); 290 | } 291 | return connRes; 292 | } 293 | 294 | uint8_t WiFiManager::waitForConnectResult() { 295 | if (_connectTimeout == 0) { 296 | return WiFi.waitForConnectResult(); 297 | } else { 298 | DEBUG_WM (F("Waiting for connection result with time out")); 299 | unsigned long start = millis(); 300 | boolean keepConnecting = true; 301 | uint8_t status; 302 | while (keepConnecting) { 303 | status = WiFi.status(); 304 | if (millis() > start + _connectTimeout) { 305 | keepConnecting = false; 306 | DEBUG_WM (F("Connection timed out")); 307 | } 308 | if (status == WL_CONNECTED || status == WL_CONNECT_FAILED) { 309 | keepConnecting = false; 310 | } 311 | delay(100); 312 | } 313 | return status; 314 | } 315 | } 316 | 317 | void WiFiManager::startWPS() { 318 | #if defined(ESP8266) 319 | DEBUG_WM("START WPS"); 320 | WiFi.beginWPSConfig(); 321 | DEBUG_WM("END WPS"); 322 | #else 323 | // TODO 324 | DEBUG_WM("ESP32 WPS TODO"); 325 | #endif 326 | } 327 | 328 | String WiFiManager::getSSID() { 329 | if (_ssid == "") { 330 | DEBUG_WM(F("Reading SSID")); 331 | _ssid = WiFi.SSID(); 332 | DEBUG_WM(F("SSID: ")); 333 | DEBUG_WM(_ssid); 334 | } 335 | return _ssid; 336 | } 337 | 338 | String WiFiManager::getPassword() { 339 | if (_pass == "") { 340 | DEBUG_WM(F("Reading Password")); 341 | _pass = WiFi.psk(); 342 | DEBUG_WM("Password: " + _pass); 343 | //DEBUG_WM(_pass); 344 | } 345 | return _pass; 346 | } 347 | 348 | String WiFiManager::getConfigPortalSSID() { 349 | return _apName; 350 | } 351 | 352 | void WiFiManager::resetSettings() { 353 | DEBUG_WM(F("settings invalidated")); 354 | DEBUG_WM(F("THIS MAY CAUSE AP NOT TO START UP PROPERLY. YOU NEED TO COMMENT IT OUT AFTER ERASING THE DATA.")); 355 | // TODO On ESP32 this does not erase the SSID and password. See 356 | // https://github.com/espressif/arduino-esp32/issues/400 357 | // For now, use "make erase_flash". 358 | WiFi.disconnect(true); 359 | //delay(200); 360 | } 361 | void WiFiManager::setTimeout(unsigned long seconds) { 362 | setConfigPortalTimeout(seconds); 363 | } 364 | 365 | void WiFiManager::setConfigPortalTimeout(unsigned long seconds) { 366 | _configPortalTimeout = seconds * 1000; 367 | } 368 | 369 | void WiFiManager::setConnectTimeout(unsigned long seconds) { 370 | _connectTimeout = seconds * 1000; 371 | } 372 | 373 | void WiFiManager::setDebugOutput(boolean debug) { 374 | _debug = debug; 375 | } 376 | 377 | void WiFiManager::setAPStaticIPConfig(IPAddress ip, IPAddress gw, IPAddress sn) { 378 | _ap_static_ip = ip; 379 | _ap_static_gw = gw; 380 | _ap_static_sn = sn; 381 | } 382 | 383 | void WiFiManager::setSTAStaticIPConfig(IPAddress ip, IPAddress gw, IPAddress sn) { 384 | _sta_static_ip = ip; 385 | _sta_static_gw = gw; 386 | _sta_static_sn = sn; 387 | } 388 | 389 | void WiFiManager::setMinimumSignalQuality(int quality) { 390 | _minimumQuality = quality; 391 | } 392 | 393 | void WiFiManager::setBreakAfterConfig(boolean shouldBreak) { 394 | _shouldBreakAfterConfig = shouldBreak; 395 | } 396 | 397 | /** Handle root or redirect to captive portal */ 398 | void WiFiManager::handleRoot() { 399 | DEBUG_WM(F("Handle root")); 400 | if (captivePortal()) { // If caprive portal redirect instead of displaying the page. 401 | return; 402 | } 403 | 404 | String page = FPSTR(HTTP_HEAD); 405 | page.replace("{v}", "Options"); 406 | page += FPSTR(HTTP_SCRIPT); 407 | page += FPSTR(HTTP_STYLE); 408 | page += _customHeadElement; 409 | page += FPSTR(HTTP_HEAD_END); 410 | page += "

"; 411 | page += _apName; 412 | page += "

"; 413 | page += F("

WiFiManager

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


"; 41 | //

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


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


62 | 63 | 64 |
65 | 66 | 67 |
68 | 69 | 70 |
71 | 72 | 73 |
Credentials Saved
Trying to connect ESP to network.
If it fails reconnect to AP to try again
74 | 75 | 76 | 77 | 78 | 79 | 80 |
81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /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('