Compare commits

..
35 Commits
Author SHA1 Message Date
Alex Tudorache a0237d80f6 updated readme 2015-12-19 21:25:06 +02:00
tzapu 41990177ce Merge pull request #23 from j0hnlittle/master
Added password option to AP wifiManager.autoConnect("apname","password")
thank you j0hnlittle
2015-12-19 13:41:25 +02:00
Alex Tudorache acc6624406 information about access point callback 2015-12-17 19:14:50 +02:00
John Little c2f11e8bd9 Synced my changes with tzapu's 2015-12-17 14:59:56 +00:00
John Little c44d3643a8 Added password option to AP wifiManager.autoConnect("apname","password") 2015-12-17 14:05:20 +00:00
Alex Tudorache e9dd81d163 cleanup 2015-12-17 15:30:19 +02:00
Alex Tudorache 6ff9712b65 added config mode callback 2015-12-17 09:25:09 +02:00
tzapu f9b6db797f Merge pull request #20 from alltheblinkythings/for-upstream
Allocate the DNSServer and ESP8266WebServer on the heap at begin() time and free them when autoConnect() terminates. thanks @alltheblinkythings ;)
2015-12-15 18:25:22 +02:00
Christopher Pascoe d3274bc5b9 Allocate the DNSServer and ESP8266WebServer on the heap at begin() time and free them when autoConnect() terminates.
This reduces the likelihood of a stack overflow when WifiManager is instantiated in setup(),
and lowers memory usage (after wifi is connected) when it's instantiated globally.
2015-12-13 16:03:13 -08:00
Alex Tudorache e36f7959c7 examples updated 2015-12-09 09:37:23 +02:00
Alex Tudorache 614516596b readme update 2015-12-09 09:26:35 +02:00
Alex Tudorache e09c5803b2 even more readme 2015-12-08 08:33:05 +02:00
Alex Tudorache a95000e91a more readme updates 2015-12-08 08:32:18 +02:00
Alex Tudorache 070448db4e updated Readme 2015-12-08 08:30:45 +02:00
Alex Tudorache 659df9cb27 removed EEPROM dependencies
removed need to reset on save
2015-12-05 09:52:32 +02:00
Alex Tudorache c03570faba fixed setTimeout 2015-12-02 17:38:52 +02:00
Alex Tudorache 3d550ab78f Merge branch 'master' of https://github.com/tzapu/WiFiManager
# Conflicts:
#	README.md
2015-11-19 09:54:43 +02:00
Alex Tudorache ec23ed45b0 added staging version notice 2015-11-19 09:53:29 +02:00
Alex Tudorache faed661d25 added staging version notice 2015-11-19 09:52:49 +02:00
Alex Tudorache 0ead57671c added how it works 2015-11-19 08:25:23 +02:00
Alex Tudorache e55057f686 auto generated AP name
pretty buttons
2015-11-10 11:04:01 +02:00
Alex Tudorache 87911808ab added ability to set custom config for access point 2015-11-10 08:46:38 +02:00
Alex Tudorache 8f38a0fbaf added no scan option 2015-11-10 08:20:53 +02:00
tzapu 5ef78c6938 Merge pull request #9 from zaporylie/ip-address
Show local IP address in STA mode thanks to @zaporylie
2015-11-02 17:37:53 +02:00
zaporylie 57d9d1f33e Show local IP address in STA mode 2015-11-01 21:02:05 +01:00
Alex Tudorache ce8c9fea61 added initialisation to setup so wifi is no longer global and it gets cleaned
dnsServer and webServer are also no longer global
readme updated
2015-10-09 18:33:41 +03:00
Alex Tudorache 97b74f2b19 added debug messages enable/disable 2015-10-08 16:42:43 +03:00
tzapu 413959df5a Merge pull request #7 from niklaswall/master
Improved support for Android and Chrome OS Captive Portal detection thanks to niklaswall
2015-09-18 15:29:50 +03:00
Niklas Wall 12dfccf9e3 Merge pull request #1 from niklaswall/android-captive-portal-improvements
Improved support for Android and Chrome OS CP detection
2015-09-18 14:22:41 +02:00
Niklas Wall 72aaccf4e5 Improved support for Android and Chrome OS CP detection
Improved the support for Android and Chrome OS “Captive
Portal”detection. By returning a correct 204 status page when
/generate_204 is requested we prevent the device from disabling the
Wifi and roaming over to mobile data.
2015-09-18 14:21:33 +02:00
Alex Tudorache cac2d9973b updated readme.md 2015-09-11 18:54:18 +03:00
Alex Tudorache d2bd81121d added captive portal
removed mdsn lib
changed dependencies and constructor
2015-09-11 18:51:21 +03:00
tzapu 20dbfed7c6 Update README.md 2015-08-28 14:51:09 +03:00
tzapu e74b39d833 Update README.md 2015-08-28 14:48:39 +03:00
tzapu 50e8b1d278 Update README.md 2015-08-28 14:47:20 +03:00
6 changed files with 597 additions and 286 deletions
+116 -19
View File
@@ -1,39 +1,136 @@
# WiFiManager
ESP8266 WiFi Connection manager with save to EEPROM and web config portal
ESP8266 WiFi Connection manager with fallback web configuration portal
First attempt at a library. Lots more changes and fixes to do. Adding examples also needs doing.
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.
This works with the ESP8266 Arduino platform https://github.com/esp8266/Arduino
First attempt at a library. Lots more changes and fixes to do. Contributions are welcome.
#### This works with the ESP8266 Arduino platform with a recent stable release(2.0.0 or newer) https://github.com/esp8266/Arduino
## How It works
- when your ESP starts up, it sets it up in Station mode and tries to connect to a previously saved Access Point
- if this is unsuccessful (or no previous network saved) it moves the ESP into Access Point mode and spins up a DNS and WebServer (default ip 192.168.4.1)
- using any wifi enabled device with a browser (computer, phone, tablet) connect to the newly created Access Point
- because of the Captive Portal and the DNS server you will either get a 'Join to network' type of popup or get any domain you try to access redirected to the configuration portal
- choose one of the access points scanned, enter password, click save
- ESP will try to connect. If successful, it relinquishes control back to your app. If not, reconnect to AP and reconfigure.
## Still left to do
- ~~remove dependency on EEPROM library~~
- move HTML Strings to PROGMEM
- cleanup and streamline code
- if timeout is set, extend it when a page is fetched in AP mode
- add ability to configure more parameters than ssid/password
- maybe allow setting ip of ESP after reboot
## Releases
#### v0.4 - user contributed changes - Thank you
- added ability to password protect the configuration Access Point
- callback for enter configuration mode
- memory allocation improvements
##### v0.3
- removed the need for EEPROM and works with the 2.0.0 and above stable release of the ESP8266 for Arduino IDE package
- removed restart on save of credentials
- updated examples
##### v0.2
needs the latest staging version (or at least a recent release of the staging version) to work
##### v0.1
works with the staging release ver. 1.6.5-1044-g170995a, built on Aug 10, 2015 of the ESP8266 Arduino library.
## Quick Start
- Make sure you have a recent package of the ESP8266 for Arduino IDE
####Quick Start
- Checkout library to your Arduino libraries folder
- Include in your sketch
```Arduino
#include <WiFiClient.h>
#include <EEPROM.h>
#include <ESP8266mDNS.h>
```cpp
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h>
```
- Initialise library, the paramater is the Acces Point Name
```
//parameter is eeprom start
WiFiManager wifi(0);
- Initialise library, in your setup function add
```cpp
WiFiManager wifiManager;
```
- In your setup function add
- Also in the setup function add
```cpp
//first parameter is name of access point, second is the password
wifiManager.autoConnect("AP-NAME", "AP-PASSWORD");
```
//parameter is name of access point
wifi.autoConnect("AP-NAME");
if you just want an unsecured access point
```cpp
wifiManager.autoConnect("AP-NAME");
```
or if you want to use and auto generated name from 'ESP' and the esp's Chip ID use
```cpp
wifiManager.autoConnect();
```
After you write your sketch and start the ESP, it will try to connect to WiFi. If it fails it starts in Access Point mode.
While in AP mode, connect to it then open a browser to the gateway IP, default 192.168.4.1, configure wifi, save and it should reboot and connect.
Also see examples.
####Inspiration
### Password protect the configuration Access Point
You can and should password protect the configuration access point. Simply add the password as a second parameter to `autoConnect`.
A short password seems to have unpredictable results so use one that's around 8 characters or more in length.
```
wifiManager.autoConnect("AutoConnectAP", "password")
```
### Callbacks
##### Enter Config mode
Use this if you need to do something when your device enters configuration mode on failed WiFi connection attempt.
Before `autoConnect()`
```cpp
wifiManager.setAPCallback(configModeCallback);
```
`configModeCallback` declaration and example
```cpp
void configModeCallback () {
Serial.println("Entered config mode");
Serial.println(WiFi.softAPIP());
}
```
### Timeout
If you need to set a timeout so the ESP doesn't hang waiting to be configured, for instance after a power failure, you can add
```cpp
wifiManager.setTimeout(180);
```
which will wait 3 minutes (180 seconds). When the time passes, the autoConnect function will return, no matter the outcome.
Check for connection and if it's still not established do whatever is needed (on some modules I restart them to retry, on others I enter deep sleep)
### Debug
Debug is enabled by default on Serial. To disable add before autoConnect
```cpp
wifiManager.setDebugOutput(false);
```
### Custom IP Configuration
This will set your captive portal to a specific IP should you need/want such a feature. Add the following snippet before `autoConnect()`
```cpp
//set custom ip for portal
wifiManager.setAPConfig(IPAddress(10,0,1,1), IPAddress(10,0,1,1), IPAddress(255,255,255,0));
```
### Contributions and thanks
[alltheblinkythings](https://github.com/alltheblinkythings)
[Niklas Wall](https://github.com/niklaswall)
[Jakub Piasecki](https://github.com/zaporylie)
[Maximiliano Duarte](https://github.com/domonetic)
[Peter Allan](https://github.com/alwynallan)
[John Little](https://github.com/j0hnlittle)
#### Inspiration
- http://www.esp8266.com/viewtopic.php?f=29&t=2520
To be continued...
Regular → Executable
+336 -206
View File
@@ -3,21 +3,17 @@
* (https://github.com/esp8266/Arduino) to enable easy
* configuration and reconfiguration of WiFi credentials and
* store them in EEPROM.
* inspired by http://www.esp8266.com/viewtopic.php?f=29&t=2520
* inspired by:
* http://www.esp8266.com/viewtopic.php?f=29&t=2520
* https://github.com/chriscook8/esp-arduino-apboot
* https://github.com/esp8266/Arduino/tree/esp8266/hardware/esp8266com/esp8266/libraries/DNSServer/examples/CaptivePortalAdvanced
* Built by AlexT https://github.com/tzapu
* Licensed under MIT license
**************************************************************/
#include "WiFiManager.h"
MDNSResponder mdns;
WiFiServer server(80);
WiFiManager::WiFiManager(int eepromStart)
{
_eepromStart = eepromStart;
WiFiManager::WiFiManager() {
}
void WiFiManager::begin() {
@@ -25,46 +21,146 @@ void WiFiManager::begin() {
}
void WiFiManager::begin(char const *apName) {
begin(apName,NULL);
}
void WiFiManager::begin(char const *apName, char const *apPasswd) {
dnsServer.reset(new DNSServer());
server.reset(new ESP8266WebServer(80));
DEBUG_PRINT("");
_apName = apName;
_apPasswd = apPasswd;
start = millis();
EEPROM.begin(512);
delay(10);
DEBUG_PRINT("Configuring access point... ");
DEBUG_PRINT(_apName);
if (_apPasswd != NULL)
DEBUG_PRINT(_apPasswd);
//optional soft ip config
if (_ip) {
DEBUG_PRINT("Custom IP/GW/Subnet");
WiFi.softAPConfig(_ip, _gw, _sn);
}
if (_apPasswd != NULL)
WiFi.softAP(_apName, _apPasswd);//password option
else
WiFi.softAP(_apName);
delay(500); // Without delay I've seen the IP address blank
DEBUG_PRINT("AP IP address: ");
DEBUG_PRINT(WiFi.softAPIP());
/* Setup the DNS server redirecting all the domains to the apIP */
dnsServer->setErrorReplyCode(DNSReplyCode::NoError);
dnsServer->start(DNS_PORT, "*", WiFi.softAPIP());
/* Setup web pages: root, wifi config pages, SO captive portal detectors and not found. */
server->on("/", std::bind(&WiFiManager::handleRoot, this));
server->on("/wifi", std::bind(&WiFiManager::handleWifi, this, true));
server->on("/0wifi", std::bind(&WiFiManager::handleWifi, this, false));
server->on("/wifisave", std::bind(&WiFiManager::handleWifiSave, this));
server->on("/generate_204", std::bind(&WiFiManager::handle204, this)); //Android/Chrome OS captive portal check.
server->on("/fwlink", std::bind(&WiFiManager::handleRoot, this)); //Microsoft captive portal. Maybe not needed. Might be handled by notFound handler.
server->onNotFound (std::bind(&WiFiManager::handleNotFound, this));
server->begin(); // Web server start
DEBUG_PRINT("HTTP server started");
}
boolean WiFiManager::autoConnect() {
return autoConnect("NoNetESP");
String ssid = "ESP" + String(ESP.getChipId());
return autoConnect(ssid.c_str(),NULL);
}
boolean WiFiManager::autoConnect(char const *apName) {
begin(apName);
return autoConnect(apName,NULL);
}
boolean WiFiManager::autoConnect(char const *apName, char const *apPasswd) {
DEBUG_PRINT("");
DEBUG_PRINT("AutoConnect");
// read eeprom for ssid and pass
String ssid = getSSID();
String pass = getPassword();
if ( ssid.length() > 1 ) {
DEBUG_PRINT("Waiting for Wifi to connect");
WiFi.mode(WIFI_STA);
WiFi.begin(ssid.c_str(), pass.c_str());
if ( hasConnected() ) {
return true;
}
//use SDK functions to get SSID and pass
//String ssid = WiFi.SSID();
//String pass = WiFi.psk();
WiFi.mode(WIFI_STA);
connectWifi(ssid, pass);
int s = WiFi.status();
if (s == WL_CONNECTED) {
DEBUG_PRINT("IP Address:");
DEBUG_PRINT(WiFi.localIP());
//connected
return true;
}
//not connected
//setup AP
beginConfigMode();
//start portal and loop
startWebConfig();
return false;
WiFi.mode(WIFI_AP);
//notify we entered AP mode
if( _apcallback != NULL) {
_apcallback();
}
connect = false;
begin(apName,apPasswd);
bool looping = true;
while(timeout == 0 || millis() < start + timeout) {
//DNS
dnsServer->processNextRequest();
//HTTP
server->handleClient();
if(connect) {
delay(2000);
DEBUG_PRINT("Connecting to new AP");
connect = false;
//ssid = getSSID();
//pass = getPassword();
connectWifi(_ssid, _pass);
int s = WiFi.status();
if (s != WL_CONNECTED) {
DEBUG_PRINT("Failed to connect.");
//not connected, should retry everything
//ESP.reset();
//delay(1000);
//return false;
} else {
//connected
WiFi.mode(WIFI_STA);
break;
}
}
yield();
}
server.reset();
dnsServer.reset();
return WiFi.status() == WL_CONNECTED;
}
void WiFiManager::connectWifi(String ssid, String pass) {
DEBUG_PRINT("Connecting as wifi client...");
//WiFi.disconnect();
WiFi.begin(ssid.c_str(), pass.c_str());
int connRes = WiFi.waitForConnectResult();
DEBUG_PRINT ("Connection result: ");
DEBUG_PRINT ( connRes );
}
String WiFiManager::getSSID() {
if (_ssid == "") {
DEBUG_PRINT("Reading EEPROM SSID");
_ssid = getEEPROMString(0, 32);
_ssid = WiFi.SSID();//getEEPROMString(0, 32);
DEBUG_PRINT("SSID: ");
DEBUG_PRINT(_ssid);
}
@@ -74,204 +170,46 @@ String WiFiManager::getSSID() {
String WiFiManager::getPassword() {
if (_pass == "") {
DEBUG_PRINT("Reading EEPROM Password");
_pass = getEEPROMString(32, 64);
DEBUG_PRINT("Password: ");
DEBUG_PRINT(_pass);
_pass = WiFi.psk();//getEEPROMString(32, 64);
DEBUG_PRINT("Password: " + _pass);
//DEBUG_PRINT(_pass);
}
return _pass;
}
/*
String WiFiManager::getEEPROMString(int start, int len) {
EEPROM.begin(512);
delay(10);
String string = "";
for (int i = _eepromStart + start; i < _eepromStart + start + len; i++) {
//DEBUG_PRINT(i);
string += char(EEPROM.read(i));
}
EEPROM.end();
return string;
}
*/
/*
void WiFiManager::setEEPROMString(int start, int len, String string) {
EEPROM.begin(512);
delay(10);
int si = 0;
for (int i = _eepromStart + start; i < _eepromStart + start + len; i++) {
char c;
if (si < string.length()) {
c = string[si];
DEBUG_PRINT("Wrote: ");
DEBUG_PRINT(c);
//DEBUG_PRINT("Wrote: ");
//DEBUG_PRINT(c);
} else {
c = 0;
}
EEPROM.write(i, c);
si++;
}
}
boolean WiFiManager::hasConnected(void) {
int c = 0;
while ( c < 50 ) {
if (WiFi.status() == WL_CONNECTED) {
return true;
}
delay(200);
DEBUG_PRINT(".");
c++;
}
DEBUG_PRINT("");
DEBUG_PRINT("Could not connect to WiFi");
return false;
}
void WiFiManager::startWebConfig() {
DEBUG_PRINT("");
DEBUG_PRINT("WiFi connected");
DEBUG_PRINT(WiFi.localIP());
DEBUG_PRINT(WiFi.softAPIP());
if (!mdns.begin(_apName, WiFi.localIP())) {
DEBUG_PRINT("Error setting up MDNS responder!");
while (1) {
delay(1000);
}
}
DEBUG_PRINT("mDNS responder started");
// Start the server
server.begin();
DEBUG_PRINT("Server started");
while (serverLoop() == WM_WAIT) {
//looping
if(timeout > 0 && start + timeout < millis()) {
//we passed timeout value, release
DEBUG_PRINT("timeout reached");
return;
}
}
DEBUG_PRINT("Setup done");
delay(5000);
ESP.reset();
}
String WiFiManager::beginConfigMode(void) {
WiFi.softAP(_apName);
DEBUG_PRINT("Started Soft Access Point");
IPAddress apIp = WiFi.softAPIP();
char ip[24];
sprintf(ip, "%d.%d.%d.%d", apIp[0], apIp[1], apIp[2], apIp[3]);
return ip;
}
int WiFiManager::serverLoop()
{
// Check for any mDNS queries and send responses
mdns.update();
// Check if a client has connected
WiFiClient client = server.available();
if (!client) {
return (WM_WAIT);
}
DEBUG_PRINT("New client");
// Wait for data from client to become available
while (client.connected() && !client.available()) {
delay(1);
}
// Read the first line of HTTP request
String req = client.readStringUntil('\r');
// First line of HTTP request looks like "GET /path HTTP/1.1"
// Retrieve the "/path" part by finding the spaces
int addr_start = req.indexOf(' ');
int addr_end = req.indexOf(' ', addr_start + 1);
if (addr_start == -1 || addr_end == -1) {
DEBUG_PRINT("Invalid request: ");
DEBUG_PRINT(req);
return (WM_WAIT);
}
req = req.substring(addr_start + 1, addr_end);
DEBUG_PRINT("Request: ");
DEBUG_PRINT(req);
client.flush();
String s;
if (req == "/")
{
s = HTTP_200;
String head = HTTP_HEAD;
head.replace("{v}", "Config ESP");
s += head;
s += HTTP_SCRIPT;
s += HTTP_STYLE;
s += HTTP_HEAD_END;
int n = WiFi.scanNetworks();
DEBUG_PRINT("scan done");
if (n == 0) {
DEBUG_PRINT("no networks found");
s += "<div>No networks found. Refresh to scan again.</div>";
}
else {
for (int i = 0; i < n; ++i)
{
DEBUG_PRINT(WiFi.SSID(i));
DEBUG_PRINT(WiFi.RSSI(i));
String item = HTTP_ITEM;
item.replace("{v}", WiFi.SSID(i));
s += item;
delay(10);
}
}
s += HTTP_FORM;
s += HTTP_END;
DEBUG_PRINT("Sending config page");
}
else if ( req.startsWith("/s") ) {
String qssid;
qssid = urldecode(req.substring(8, req.indexOf('&')).c_str());
DEBUG_PRINT(qssid);
DEBUG_PRINT("");
String qpass;
qpass = urldecode(req.substring(req.lastIndexOf('=') + 1).c_str());
DEBUG_PRINT(qpass);
DEBUG_PRINT("");
setEEPROMString(0, 32, qssid);
setEEPROMString(32, 64, qpass);
EEPROM.commit();
s = HTTP_200;
String head = HTTP_HEAD;
head.replace("{v}", "Saved config");
s += HTTP_STYLE;
s += HTTP_HEAD_END;
s += "saved to eeprom...<br/>resetting in 10 seconds";
s += HTTP_END;
client.print(s);
client.flush();
DEBUG_PRINT("Saved WiFiConfig...restarting.");
return WM_DONE;
}
else
{
s = HTTP_404;
DEBUG_PRINT("Sending 404");
}
client.print(s);
DEBUG_PRINT("Done with client");
return (WM_WAIT);
}
EEPROM.end();
DEBUG_PRINT("Wrote " + string);
}*/
String WiFiManager::urldecode(const char *src)
{
@@ -311,16 +249,208 @@ String WiFiManager::urldecode(const char *src)
void WiFiManager::resetSettings() {
//need to call it only after lib has been started with autoConnect or begin
setEEPROMString(0, 32, "-");
setEEPROMString(32, 64, "-");
EEPROM.commit();
DEBUG_PRINT("settings invalidated");
delay(200);
WiFi.disconnect();
delay(200);
}
void WiFiManager::setTimeout(unsigned long seconds) {
timeout = seconds * 1000;
}
void WiFiManager::setDebugOutput(boolean debug) {
_debug = debug;
}
void WiFiManager::setAPConfig(IPAddress ip, IPAddress gw, IPAddress sn) {
_ip = ip;
_gw = gw;
_sn = sn;
}
/** Handle root or redirect to captive portal */
void WiFiManager::handleRoot() {
DEBUG_PRINT("Handle root");
if (captivePortal()) { // If caprive portal redirect instead of displaying the page.
return;
}
server->sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
server->sendHeader("Pragma", "no-cache");
server->sendHeader("Expires", "-1");
server->send(200, "text/html", ""); // Empty content inhibits Content-length header so we have to close the socket ourselves.
String head = HTTP_HEAD;
head.replace("{v}", "Options");
server->sendContent(head);
server->sendContent(HTTP_SCRIPT);
server->sendContent(HTTP_STYLE);
server->sendContent(HTTP_HEAD_END);
server->sendContent(
"<form action=\"/wifi\" method=\"get\"><button>Configure WiFi</button></form><br/>"
);
server->sendContent(
"<form action=\"/0wifi\" method=\"get\"><button>Configure WiFi (No Scan)</button></form>"
);
server->sendContent(HTTP_END);
server->client().stop(); // Stop is needed because we sent no content length
}
/** Wifi config page handler */
void WiFiManager::handleWifi(bool scan) {
server->sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
server->sendHeader("Pragma", "no-cache");
server->sendHeader("Expires", "-1");
server->send(200, "text/html", ""); // Empty content inhibits Content-length header so we have to close the socket ourselves.
String head = HTTP_HEAD;
head.replace("{v}", "Config ESP");
server->sendContent(head);
server->sendContent(HTTP_SCRIPT);
server->sendContent(HTTP_STYLE);
server->sendContent(HTTP_HEAD_END);
if (scan) {
int n = WiFi.scanNetworks();
DEBUG_PRINT("Scan done");
if (n == 0) {
DEBUG_PRINT("No networks found");
server->sendContent("<div>No networks found. Refresh to scan again.</div>");
}
else {
for (int i = 0; i < n; ++i)
{
DEBUG_PRINT(WiFi.SSID(i));
DEBUG_PRINT(WiFi.RSSI(i));
String item = HTTP_ITEM;
item.replace("{v}", WiFi.SSID(i));
server->sendContent(item);
yield();
}
}
}
server->sendContent(HTTP_FORM);
server->sendContent(HTTP_END);
server->client().stop();
DEBUG_PRINT("Sent config page");
}
/** Handle the WLAN save form and redirect to WLAN config page again */
void WiFiManager::handleWifiSave() {
DEBUG_PRINT("WiFi save");
//SAVE/connect here
_ssid = urldecode(server->arg("s").c_str());
_pass = urldecode(server->arg("p").c_str());
server->sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
server->sendHeader("Pragma", "no-cache");
server->sendHeader("Expires", "-1");
server->send(200, "text/html", ""); // Empty content inhibits Content-length header so we have to close the socket ourselves.
String head = HTTP_HEAD;
head.replace("{v}", "Credentials Saved");
server->sendContent(head);
server->sendContent(HTTP_SCRIPT);
server->sendContent(HTTP_STYLE);
server->sendContent(HTTP_HEAD_END);
server->sendContent(HTTP_SAVED);
server->sendContent(HTTP_END);
server->client().stop();
DEBUG_PRINT("Sent wifi save page");
connect = true; //signal ready to connect/reset
}
void WiFiManager::handle204() {
DEBUG_PRINT("204 No Response");
server->sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
server->sendHeader("Pragma", "no-cache");
server->sendHeader("Expires", "-1");
server->send ( 204, "text/plain", "");
}
void WiFiManager::handleNotFound() {
if (captivePortal()) { // If captive portal redirect instead of displaying the error page.
return;
}
String message = "File Not Found\n\n";
message += "URI: ";
message += server->uri();
message += "\nMethod: ";
message += ( server->method() == HTTP_GET ) ? "GET" : "POST";
message += "\nArguments: ";
message += server->args();
message += "\n";
for ( uint8_t i = 0; i < server->args(); i++ ) {
message += " " + server->argName ( i ) + ": " + server->arg ( i ) + "\n";
}
server->sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
server->sendHeader("Pragma", "no-cache");
server->sendHeader("Expires", "-1");
server->send ( 404, "text/plain", message );
}
/** Redirect to captive portal if we got a request for another domain. Return true in that case so the page handler do not try to handle the request again. */
boolean WiFiManager::captivePortal() {
if (!isIp(server->hostHeader()) ) {
DEBUG_PRINT("Request redirected to captive portal");
server->sendHeader("Location", String("http://") + toStringIp(server->client().localIP()), true);
server->send ( 302, "text/plain", ""); // Empty content inhibits Content-length header so we have to close the socket ourselves.
server->client().stop(); // Stop is needed because we sent no content length
return true;
}
return false;
}
//start up config portal callback
void WiFiManager::setAPCallback( void (*func)(void) ) {
_apcallback = func;
}
template <typename Generic>
void WiFiManager::DEBUG_PRINT(Generic text) {
if(_debug) {
Serial.print("*WM: ");
Serial.println(text);
}
}
/** Is this an IP? */
boolean WiFiManager::isIp(String str) {
for (int i = 0; i < str.length(); i++) {
int c = str.charAt(i);
if (c != '.' && (c < '0' || c > '9')) {
return false;
}
}
return true;
}
/** IP to String? */
String WiFiManager::toStringIp(IPAddress ip) {
String res = "";
for (int i = 0; i < 3; i++) {
res += String((ip >> (8 * i)) & 0xFF) + ".";
}
res += String(((ip >> 8 * 3)) & 0xFF);
return res;
}
Regular → Executable
+62 -33
View File
@@ -14,72 +14,101 @@
#include <ESP8266WiFi.h>
#include <EEPROM.h>
#include <ESP8266mDNS.h>
#include <WiFiClient.h>
#define DEBUG //until arduino ide can include defines at compile time from main sketch
#ifdef DEBUG
#define DEBUG_PRINT(x) Serial.println(x)
#else
#define DEBUG_PRINT(x)
#endif
//#include <EEPROM.h>
//#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <DNSServer.h>
#include <memory>
class WiFiManager
{
public:
WiFiManager(int eepromStart);
void begin();
void begin(char const *apName);
WiFiManager();
boolean autoConnect();
boolean autoConnect(char const *apName);
boolean hasConnected();
String beginConfigMode(void);
void startWebConfig();
String getSSID();
String getPassword();
void resetSettings();
//for conveniennce
String urldecode(const char*);
boolean autoConnect(char const *apName, char const *apPasswd);
String getSSID();
String getPassword();
void resetSettings();
//for convenience
String urldecode(const char*);
//sets timeout before webserver loop ends and exits even if there has been no setup.
//usefully for devices that failed to connect at some point and got stuck in a webserver loop
//in seconds
void setTimeout(unsigned long seconds);
void setTimeout(unsigned long seconds);
void setDebugOutput(boolean debug);
//sets a custom ip /gateway /subnet configuration
void setAPConfig(IPAddress ip, IPAddress gw, IPAddress sn);
void setAPCallback( void (*func)(void) );
private:
std::unique_ptr<DNSServer> dnsServer;
std::unique_ptr<ESP8266WebServer> server;
const int WM_DONE = 0;
const int WM_WAIT = 10;
const String HTTP_404 = "HTTP/1.1 404 Not Found\r\n\r\n";
const String HTTP_200 = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n";
const String HTTP_HEAD = "<!DOCTYPE html><html lang=\"en\"><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"/><title>{v}</title>";
const String HTTP_STYLE = "<style>div,input {margin-bottom: 5px;}body{width:200px;display:block;margin-left:auto;margin-right:auto;}</style>";
const String HTTP_STYLE = "<style>div,input {margin-bottom: 5px;} body{width:200px;display:block;margin-left:auto;margin-right:auto;} button{padding:0.75rem 1rem;border:0;border-radius:0.317rem;background-color:#1fa3ec;color:#fff;line-height:1.5;cursor:pointer;}</style>";
const String HTTP_SCRIPT = "<script>function c(l){document.getElementById('s').value=l.innerText||l.textContent;document.getElementById('p').focus();}</script>";
const String HTTP_HEAD_END = "</head><body>";
const String HTTP_ITEM = "<div><a href='#' onclick='c(this)'>{v}</a></div>";
const String HTTP_FORM = "<form method='get' action='s'><input id='s' name='ssid' length=32 placeholder='SSID'><input id='p' name='pass' length=64 placeholder='password'><br/><input type='submit'></form>";
const String HTTP_FORM = "<form method='get' action='wifisave'><input id='s' name='s' length=32 placeholder='SSID'><input id='p' name='p' length=64 placeholder='password'><br/><button type='submit'>save</button></form>";
const String HTTP_SAVED = "<div>Credentials Saved<br />Trying to connect ESP to network.<br />If it fails reconnect to AP to try again</div>";
const String HTTP_END = "</body></html>";
//const char HTTP_END[] PROGMEM = R"=====(
//</body></html>
//)=====";
void begin();
void begin(char const *apName);
void begin(char const *apName, char const *apPasswd);
int _eepromStart;
const char* _apName = "no-net";
const char* _apPasswd = "no-net";
String _ssid = "";
String _pass = "";
unsigned long timeout = 0;
unsigned long start = 0;
IPAddress _ip;
IPAddress _gw;
IPAddress _sn;
String getEEPROMString(int start, int len);
void setEEPROMString(int start, int len, String string);
int serverLoop();
bool keepLooping = true;
int status = WL_IDLE_STATUS;
void connectWifi(String ssid, String pass);
void handleRoot();
void handleWifi(bool scan);
void handleWifiSave();
void handleNotFound();
void handle204();
boolean captivePortal();
// DNS server
const byte DNS_PORT = 53;
boolean isIp(String str);
String toStringIp(IPAddress ip);
boolean connect;
boolean _debug = true;
void (*_apcallback)(void) = NULL;
template <typename Generic>
void DEBUG_PRINT(Generic text);
};
+26 -18
View File
@@ -1,30 +1,38 @@
#include <ESP8266WiFi.h> //https://github.com/esp8266/Arduino
//needed for library
#include <EEPROM.h>
#include <ESP8266mDNS.h>
#include <WiFiManager.h> //https://github.com/tzapu/WiFiManager
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h> //https://github.com/tzapu/WiFiManager
//this intitilises the library, parameter is eeprom start
WiFiManager wifi(0);
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
// put your setup code here, to run once:
Serial.begin(115200);
//WiFiManager
//fetches ssid and pass from eeprom and tries to connect
//if it does not connect it starts an access point with the specified name
//here "AutoConnectAP"
//and goes into a blocking loop awaiting configuration
wifi.autoConnect("AutoConnectAP");
//WiFiManager
//Local intialization. Once its business is done, there is no need to keep it around
WiFiManager wifiManager;
//reset saved settings
//wifiManager.resetSettings();
//set custom ip for portal
//wifiManager.setAPConfig(IPAddress(10,0,1,1), IPAddress(10,0,1,1), IPAddress(255,255,255,0));
//if you get here you have connected to the WiFi
Serial.println("connected...yeey :)");
//fetches ssid and pass from eeprom and tries to connect
//if it does not connect it starts an access point with the specified name
//here "AutoConnectAP"
//and goes into a blocking loop awaiting configuration
wifiManager.autoConnect("AutoConnectAP");
//or use this for auto generated name ESP + ChipID
//wifiManager.autoConnect();
//if you get here you have connected to the WiFi
Serial.println("connected...yeey :)");
}
void loop() {
// put your main code here, to run repeatedly:
// put your main code here, to run repeatedly:
}
@@ -0,0 +1,44 @@
#include <ESP8266WiFi.h> //https://github.com/esp8266/Arduino
//needed for library
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h> //https://github.com/tzapu/WiFiManager
void configModeCallback () {
Serial.println("Entered config mode");
Serial.println(WiFi.softAPIP());
}
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
//WiFiManager
//Local intialization. Once its business is done, there is no need to keep it around
WiFiManager wifiManager;
//reset settings - for testing
//wifiManager.resetSettings();
//set callback that gets called when connecting to previous WiFi fails, and enters Access Point mode
wifiManager.setAPCallback(configModeCallback);
//fetches ssid and pass and tries to connect
//if it does not connect it starts an access point with the specified name
//here "AutoConnectAP"
//and goes into a blocking loop awaiting configuration
if(!wifiManager.autoConnect("AutoConnectAP")) {
Serial.println("failed to connect and hit timeout");
//reset and try again, or maybe put it to deep sleep
ESP.reset();
delay(1000);
}
//if you get here you have connected to the WiFi
Serial.println("connected...yeey :)");
}
void loop() {
// put your main code here, to run repeatedly:
}
@@ -1,31 +1,34 @@
#include <ESP8266WiFi.h> //https://github.com/esp8266/Arduino
//needed for library
#include <EEPROM.h>
#include <ESP8266mDNS.h>
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h> //https://github.com/tzapu/WiFiManager
//this intitilises the library, parameter is eeprom start
WiFiManager wifi(0);
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
//WiFiManager
//Local intialization. Once its business is done, there is no need to keep it around
WiFiManager wifiManager;
//reset settings - for testing
//wifiManager.resetSettings();
//sets timeout until configuration portal gets turned off
//useful to make it all retry or go to sleep
//in seconds
wifi.setTimeout(120);
wifiManager.setTimeout(180);
//fetches ssid and pass from eeprom and tries to connect
//fetches ssid and pass and tries to connect
//if it does not connect it starts an access point with the specified name
//here "AutoConnectAP"
//and goes into a blocking loop awaiting configuration
if(!wifi.autoConnect("AutoConnectAP")) {
if(!wifiManager.autoConnect("AutoConnectAP")) {
Serial.println("failed to connect and hit timeout");
delay(5000);
delay(3000);
//reset and try again, or maybe put it to deep sleep
ESP.reset();
delay(5000);