Migrated webserver to ESP Async Webserver

* Integrate IotWebConf as local library
* Add support for ESP Async Webserver to IotWebConf
* Changed application to work with Async Webserver
This commit is contained in:
Thomas Basler 2019-11-14 19:55:11 +01:00
parent 7575dae14f
commit 6050fb6956
24 changed files with 3957 additions and 17 deletions

View File

@ -0,0 +1,5 @@
BasedOnStyle: LLVM
PointerAlignment: Left
AllowShortFunctionsOnASingleLine: InlineOnly
AlignAfterOpenBracket: AlwaysBreak
BreakBeforeBraces: Allman

1
lib/IotWebConf/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
.vscode

View File

@ -0,0 +1,40 @@
{
"name": "IotWebConf",
"version": "2.3.0",
"keywords": [
"communication"
],
"description": "ESP8266/ESP32 non-blocking WiFi/AP web configuration.",
"frameworks": [
"arduino"
],
"platforms": [
"espressif8266",
"espressif32"
],
"authors": [
{
"email": "prampec+arduino@gmail.com",
"url": null,
"maintainer": true,
"name": "Balazs Kelemen"
}
],
"repository": {
"type": "git",
"url": "https://github.com/prampec/IotWebConf"
},
"homepage": null,
"export": {
"include": null,
"exclude": [
"extras",
"docs",
"tests",
"test",
"*.doxyfile",
"*.pdf"
]
},
"id": 5676
}

View File

@ -0,0 +1,41 @@
language: c
env:
global:
- ARDUINO_VERSION=1.8.9
matrix:
- BOARD="esp8266:esp8266:d1_mini:xtal=80,eesz=4M3M,ip=lm2f,exception=disabled"
- BOARD="esp32:esp32:widora-air:FlashFreq=80"
before_install:
- "/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_1.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :1 -ac -screen 0 1280x1024x16"
- sleep 3
- export DISPLAY=:1.0
- wget http://downloads.arduino.cc/arduino-$ARDUINO_VERSION-linux64.tar.xz
- tar xf arduino-$ARDUINO_VERSION-linux64.tar.xz
- sudo mv arduino-$ARDUINO_VERSION /usr/local/share/arduino
- sudo ln -s /usr/local/share/arduino/arduino /usr/local/bin/arduino
install:
- ln -s $PWD /usr/local/share/arduino/libraries/IotWebConf
- arduino --install-library "MQTT"
- arduino --pref "boardsmanager.additional.urls=http://arduino.esp8266.com/stable/package_esp8266com_index.json,https://dl.espressif.com/dl/package_esp32_index.json" --save-prefs
- if [[ "$BOARD" =~ "esp8266:esp8266:" ]]; then
arduino --install-boards esp8266:esp8266;
fi
- if [[ "$BOARD" =~ "esp32:esp32:" ]]; then
arduino --install-boards esp32:esp32;
fi
script:
- arduino --verify --board $BOARD examples/IotWebConf01Minimal/IotWebConf01Minimal.ino
- arduino --verify --board $BOARD examples/IotWebConf02StatusAndReset/IotWebConf02StatusAndReset.ino
- arduino --verify --board $BOARD examples/IotWebConf03CustomParameters/IotWebConf03CustomParameters.ino
- arduino --verify --board $BOARD examples/IotWebConf04UpdateServer/IotWebConf04UpdateServer.ino
- arduino --verify --board $BOARD examples/IotWebConf05Callbacks/IotWebConf05Callbacks.ino
- arduino --verify --board $BOARD examples/IotWebConf06MqttApp/IotWebConf06MqttApp.ino
- arduino --verify --board $BOARD examples/IotWebConf07MqttRelay/IotWebConf07MqttRelay.ino
- arduino --verify --board $BOARD examples/IotWebConf08WebRelay/IotWebConf08WebRelay.ino
- arduino --verify --board $BOARD examples/IotWebConf09CustomConnection/IotWebConf09CustomConnection.ino
after_success:
- bash <(curl -s https://codecov.io/bash)
notifications:
email:
on_success: change
on_failure: change

View File

@ -0,0 +1,9 @@
The MIT License (MIT)
Copyright 2018 Balazs Kelemen <prampec+arduino@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

79
lib/IotWebConf/README.md Normal file
View File

@ -0,0 +1,79 @@
# IotWebConf [![Build Status](https://travis-ci.org/prampec/IotWebConf.svg?branch=master)](https://travis-ci.org/prampec/IotWebConf)
## Summary
IotWebConf is an Arduino library for ESP8266/ESP32 to provide a non-blocking standalone WiFi/AP web configuration portal.
**For ESP8266, IotWebConf requires the esp8266 board package version 2.4.2 or later!**
Please subscribe to the [discussion forum](https://groups.google.com/forum/#!forum/iotwebconf), if you want to be informed on the latest news.
## Highlights
- Manages WiFi connection settings,
- Provides a config portal user interface,
- You can extend the configuration with your own property items, that are stored automatically,
- HTML customization,
- Validation support for the configuration property items,
- User code will be notified of status changes with callback methods,
- Configuration (including your custom items) stored in the EEPROM,
- Firmware OTA update support,
- Config portal remains available even after WiFi is connected,
- Automatic "Sign in to network" pop up in your browser (captive portal),
- Non-blocking - Your custom code will not be blocked in the whole process.
- Well documented header file, and examples from simple to complex levels.
![Screenshot](https://sharedinventions.com/wp-content/uploads/2018/11/Screenshot_20181105-191748a.png)
![Screenshot](https://sharedinventions.com/wp-content/uploads/2019/02/Screenshot-from-2019-02-03-22-16-51b.png)
## How it works
The idea is that the Thing will provide a web interface to allow modifying its configuration. E.g. for connecting to a local WiFi network, it needs the SSID and the password.
When no WiFi is configured, or the configured network is unavailable it creates its own AP (access point), and lets clients connect to it directly to make the configuration.
Furthermore there is a button (or let's say a Pin), that when pressed on startup will cause a default password to be used instead of the configured (forgotten) one.
You can find the default password in the sources. :)
IotWebConf saves configuration in the "EEPROM". You can extend the config portal with your custom configuration items. Those items will be also maintained by IotWebConf.
## Use cases
1. **You turn on your IoT the first time** - It turns into AP (access point) mode, and waits for you on the 192.168.4.1 address with a web interface to set up your local network (and other configurations). For the first time a default password is used when you connect to the AP. When you connect to the AP, your device will likely automatically pop up the portal page. (We call this a Captive Portal.) When configuration is done, you must leave the AP. The device detects that no one is connected, and continues with normal operation.
1. **WiFi configuration is changed, e.g. the Thing is moved to another location** - When the Thing cannot connect to the configured WiFi, it falls back to AP mode, and waits for you to change the network configuration. When no configuration was made, then it keeps trying to connect with the already configured settings. The Thing will not switch off the AP while anyone is connected to it, so you must leave the AP when finished with the configuration.
1. **You want to connect to the AP, but have forgotten the configured AP WiFi password you set up previously** - Connect the appropriate pin on the Arduino to ground with a push button. Holding the button pressed while powering up the device causes the Thing to start the AP mode with the default password. (See Case 1. The pin is configured in the code.)
1. **You want to change the configuration before the Thing connects to the Internet** - Fine! The Thing always starts up in AP mode and provides you a time frame to connect to it and make any modification to the configuration. Any time one is connected to the AP (provided by the device) the AP will stay on until the connection is closed. So take your time for the changes, the Thing will wait for you while you are connected to it.
1. **You want to change the configuration at runtime** - No problem. IotWebConf keeps the config portal up and running even after the WiFi connection is finished. In this scenario you must enter username "admin" and password (already configured) to enter the config portal. Note, that the password provided for the authentication is not hidden from devices connected to the same WiFi network. You might want to force rebooting of the Thing to apply your changes.
## IotWebConf vs. WiFiManager
tzapu's WiFiManager is a great library. The features of IotWebConf may appear very similar to WiFiManager. However, IotWebConf tries to be different.
- WiFiManager does not manages your custom properties. IotWebConf stores your configuration in "EEPROM".
- WiFiManager does not do validation. IotWebConf allow you to validate your property changes made in the config portal.
- With WiFiManager you cannot use both startup and on-demand configuration. With IotWebConf the config portal remains available via the connected local WiFi.
- WiFiManager provides list of available networks and also an information page, while these features are cool, IotWebConf tries to keep the code simple. So these features are not (yet) provided by IotWebConf.
- IotWebConf is fitted for more advanced users. You can keep control of the web server setup, configuration item input field behavior, and validation.
## Security aspects
- The initial system password must be modified by the user, so there is no build-in password.
- When connecting in AP mode, the WiFi provides an encryption layer, so all you communication here is known to be safe.
- When connecting through a WiFi router (WiFi mode), the Thing will ask for authentication when someone requests the config portal. This is required as the Thing will be visible for all devices sharing the same network. But be warned by the following note...
- NOTE: **When connecting through a WiFi router (WiFi mode), your communication is not hidden from devices connecting to the same network.** So either: Do not allow ambiguous devices connecting to your WiFi router, or configure your Thing only in AP mode!
- However IotWebConf has a detailed debug output, passwords are not shown in this log by default. You have
to enable password visibility manually in the IotWebConf.h with the IOTWEBCONF_DEBUG_PWD_TO_SERIAL
if it is needed.
## Compatibility
IotWebConf is primary built for ESP8266. But meanwhile it was discovered, that the code can be adopted
to ESP32. There are two major problems.
- ESP8266 uses specific naming for it's classes (e.g. ESP8266WebServer). However ESP32 uses a more generic naming (e.g. WebServer). The idea here is to use the generic naming hoping that ESP8266 will adopt these "standards" sooner or later.
- ESP32 does not provides an HTTPUpdateServer implementation. So in this project we have implemented one. Whenever ESP32 provides an official HTTPUpdateServer, this local implementation will be removed.
## TODO / Feature requests
- We might want to add a "verify password" field.
- Possibility to organize blocks of config items to lists. (E.g. provide more SSIDs with passwords as a connection option.)
- Option the configure multiply WiFi connections. Try next when the last used one is just not available.
## Known issues
- It is reported, that there might be unstable working with different lwIP variants. If you experiment serious problems, try to select another lwIP variant for your board in the Tools menu! (Tested with "v2 Lower Memory" version.)
## Credits
Although IotWebConf started without being influenced by any other solutions, in the final code you can find some segments borrowed from the WiFiManager library.
- https://github.com/tzapu/WiFiManager
Thanks to [all contributors](/prampec/IotWebConf/graphs/contributors) providing patches for the library!

View File

@ -0,0 +1,86 @@
/**
* IotWebConf01Minimal.ino -- IotWebConf is an ESP8266/ESP32
* non blocking WiFi/AP web configuration library for Arduino.
* https://github.com/prampec/IotWebConf
*
* Copyright (C) 2018 Balazs Kelemen <prampec+arduino@gmail.com>
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
/**
* Example: Minimal
* Description:
* This example will shows the bare minimum required for IotWeConf to start up.
* After starting up the thing, please search for WiFi access points e.g. with
* your phone. Use password provided in the code!
* After connecting to the access point the root page will automatically appears.
* We call this "captive portal".
*
* Please set a new password for the Thing (for the access point) as well as
* the SSID and password of your local WiFi. You cannot move on without these steps.
*
* You have to leave the access point before to let the Thing continue operation
* with connecting to configured WiFi.
*
* Note that you can find detailed debug information in the serial console depending
* on the settings IOTWEBCONF_DEBUG_TO_SERIAL, IOTWEBCONF_DEBUG_PWD_TO_SERIAL set
* in the IotWebConf.h .
*/
#include <IotWebConf.h>
// -- Initial name of the Thing. Used e.g. as SSID of the own Access Point.
const char thingName[] = "testThing";
// -- Initial password to connect to the Thing, when it creates an own Access Point.
const char wifiInitialApPassword[] = "smrtTHNG8266";
DNSServer dnsServer;
WebServer server(80);
IotWebConf iotWebConf(thingName, &dnsServer, &server, wifiInitialApPassword);
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.println("Starting up...");
// -- Initializing the configuration.
iotWebConf.init();
// -- Set up required URL handlers on the web server.
server.on("/", handleRoot);
server.on("/config", []{ iotWebConf.handleConfig(); });
server.onNotFound([](){ iotWebConf.handleNotFound(); });
Serial.println("Ready.");
}
void loop()
{
// -- doLoop should be called as frequently as possible.
iotWebConf.doLoop();
}
/**
* Handle web requests to "/" path.
*/
void handleRoot()
{
// -- Let IotWebConf test and handle captive portal requests.
if (iotWebConf.handleCaptivePortal())
{
// -- Captive portal request were already served.
return;
}
String s = "<!DOCTYPE html><html lang=\"en\"><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\"/>";
s += "<title>IotWebConf 01 Minimal</title></head><body>Hello world!";
s += "Go to <a href='config'>configure page</a> to change settings.";
s += "</body></html>\n";
server.send(200, "text/html", s);
}

View File

@ -0,0 +1,96 @@
/**
* IotWebConf02StatusAndReset.ino -- IotWebConf is an ESP8266/ESP32
* non blocking WiFi/AP web configuration library for Arduino.
* https://github.com/prampec/IotWebConf
*
* Copyright (C) 2018 Balazs Kelemen <prampec+arduino@gmail.com>
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
/**
* Example: Status and Reset
* Description:
* This example is very similar to the "mininal" example.
* But here we provide a status indicator LED, to get feedback
* of the thing state.
* Further more we set up a push button. If push button is detected
* to be pressed at boot time, the thing will use the initial
* password for accepting connections in Access Point mode. This
* is usefull e.g. when custom password was lost.
* (See previous examples for more details!)
*
* Hardware setup for this example:
* - An LED is attached to LED_BUILTIN pin with setup On=LOW.
* This is hopefully already attached by default.
* - A push button is attached to pin D2, the other leg of the
* button should be attached to GND.
*/
#include <IotWebConf.h>
// -- Initial name of the Thing. Used e.g. as SSID of the own Access Point.
const char thingName[] = "testThing";
// -- Initial password to connect to the Thing, when it creates an own Access Point.
const char wifiInitialApPassword[] = "smrtTHNG8266";
// -- When CONFIG_PIN is pulled to ground on startup, the Thing will use the initial
// password to buld an AP. (E.g. in case of lost password)
#define CONFIG_PIN D2
// -- Status indicator pin.
// First it will light up (kept LOW), on Wifi connection it will blink,
// when connected to the Wifi it will turn off (kept HIGH).
#define STATUS_PIN LED_BUILTIN
DNSServer dnsServer;
WebServer server(80);
IotWebConf iotWebConf(thingName, &dnsServer, &server, wifiInitialApPassword);
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.println("Starting up...");
// -- Initializing the configuration.
iotWebConf.setStatusPin(STATUS_PIN);
iotWebConf.setConfigPin(CONFIG_PIN);
iotWebConf.init();
// -- Set up required URL handlers on the web server.
server.on("/", handleRoot);
server.on("/config", []{ iotWebConf.handleConfig(); });
server.onNotFound([](){ iotWebConf.handleNotFound(); });
Serial.println("Ready.");
}
void loop()
{
// -- doLoop should be called as frequently as possible.
iotWebConf.doLoop();
}
/**
* Handle web requests to "/" path.
*/
void handleRoot()
{
// -- Let IotWebConf test and handle captive portal requests.
if (iotWebConf.handleCaptivePortal())
{
// -- Captive portal request were already served.
return;
}
String s = "<!DOCTYPE html><html lang=\"en\"><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\"/>";
s += "<title>IotWebConf 02 Status and Reset</title></head><body>Hello world!";
s += "Go to <a href='config'>configure page</a> to change settings.";
s += "</body></html>\n";
server.send(200, "text/html", s);
}

View File

@ -0,0 +1,150 @@
/**
* IotWebConf03CustomParameters.ino -- IotWebConf is an ESP8266/ESP32
* non blocking WiFi/AP web configuration library for Arduino.
* https://github.com/prampec/IotWebConf
*
* Copyright (C) 2018 Balazs Kelemen <prampec+arduino@gmail.com>
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
/**
* Example: Custom parameters
* Description:
* In this example it is shown how to attach your custom parameters
* to the config portal. Your parameters will be maintained by
* IotWebConf. This means, they will be loaded from/saved to EEPROM,
* and will appear in the config portal.
* Note the configSaved and formValidator callbacks!
* (See previous examples for more details!)
*
* Hardware setup for this example:
* - An LED is attached to LED_BUILTIN pin with setup On=LOW.
* - [Optional] A push button is attached to pin D2, the other leg of the
* button should be attached to GND.
*/
#include <IotWebConf.h>
// -- Initial name of the Thing. Used e.g. as SSID of the own Access Point.
const char thingName[] = "testThing";
// -- Initial password to connect to the Thing, when it creates an own Access Point.
const char wifiInitialApPassword[] = "smrtTHNG8266";
#define STRING_LEN 128
#define NUMBER_LEN 32
// -- Configuration specific key. The value should be modified if config structure was changed.
#define CONFIG_VERSION "dem2"
// -- When CONFIG_PIN is pulled to ground on startup, the Thing will use the initial
// password to buld an AP. (E.g. in case of lost password)
#define CONFIG_PIN D2
// -- Status indicator pin.
// First it will light up (kept LOW), on Wifi connection it will blink,
// when connected to the Wifi it will turn off (kept HIGH).
#define STATUS_PIN LED_BUILTIN
// -- Callback method declarations.
void configSaved();
boolean formValidator();
DNSServer dnsServer;
WebServer server(80);
char stringParamValue[STRING_LEN];
char intParamValue[NUMBER_LEN];
char floatParamValue[NUMBER_LEN];
IotWebConf iotWebConf(thingName, &dnsServer, &server, wifiInitialApPassword, CONFIG_VERSION);
IotWebConfParameter stringParam = IotWebConfParameter("String param", "stringParam", stringParamValue, STRING_LEN);
IotWebConfSeparator separator1 = IotWebConfSeparator();
IotWebConfParameter intParam = IotWebConfParameter("Int param", "intParam", intParamValue, NUMBER_LEN, "number", "1..100", NULL, "min='1' max='100' step='1'");
// -- We can add a legend to the separator
IotWebConfSeparator separator2 = IotWebConfSeparator("Calibration factor");
IotWebConfParameter floatParam = IotWebConfParameter("Float param", "floatParam", floatParamValue, NUMBER_LEN, "number", "e.g. 23.4", NULL, "step='0.1'");
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.println("Starting up...");
iotWebConf.setStatusPin(STATUS_PIN);
iotWebConf.setConfigPin(CONFIG_PIN);
iotWebConf.addParameter(&stringParam);
iotWebConf.addParameter(&separator1);
iotWebConf.addParameter(&intParam);
iotWebConf.addParameter(&separator2);
iotWebConf.addParameter(&floatParam);
iotWebConf.setConfigSavedCallback(&configSaved);
iotWebConf.setFormValidator(&formValidator);
iotWebConf.getApTimeoutParameter()->visible = true;
// -- Initializing the configuration.
iotWebConf.init();
// -- Set up required URL handlers on the web server.
server.on("/", handleRoot);
server.on("/config", []{ iotWebConf.handleConfig(); });
server.onNotFound([](){ iotWebConf.handleNotFound(); });
Serial.println("Ready.");
}
void loop()
{
// -- doLoop should be called as frequently as possible.
iotWebConf.doLoop();
}
/**
* Handle web requests to "/" path.
*/
void handleRoot()
{
// -- Let IotWebConf test and handle captive portal requests.
if (iotWebConf.handleCaptivePortal())
{
// -- Captive portal request were already served.
return;
}
String s = "<!DOCTYPE html><html lang=\"en\"><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\"/>";
s += "<title>IotWebConf 03 Custom Parameters</title></head><body>Hello world!";
s += "<ul>";
s += "<li>String param value: ";
s += stringParamValue;
s += "<li>Int param value: ";
s += atoi(intParamValue);
s += "<li>Float param value: ";
s += atof(floatParamValue);
s += "</ul>";
s += "Go to <a href='config'>configure page</a> to change values.";
s += "</body></html>\n";
server.send(200, "text/html", s);
}
void configSaved()
{
Serial.println("Configuration was updated.");
}
boolean formValidator()
{
Serial.println("Validating form.");
boolean valid = true;
int l = server.arg(stringParam.getId()).length();
if (l < 3)
{
stringParam.errorMessage = "Please provide at least 3 characters for this test!";
valid = false;
}
return valid;
}

View File

@ -0,0 +1,99 @@
/**
* IotWebConf04UpdateServer.ino -- IotWebConf is an ESP8266/ESP32
* non blocking WiFi/AP web configuration library for Arduino.
* https://github.com/prampec/IotWebConf
*
* Copyright (C) 2018 Balazs Kelemen <prampec+arduino@gmail.com>
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
/**
* Example: Update Server
* Description:
* In this example we will provide a "firmware update" link in the
* config portal.
* (See ESP8266 ESP8266HTTPUpdateServer examples
* to understand UpdateServer!)
* (ESP32: HTTPUpdateServer library is ported for ESP32 in this project.)
* (See previous examples for more details!)
*
* Hardware setup for this example:
* - An LED is attached to LED_BUILTIN pin with setup On=LOW.
* - [Optional] A push button is attached to pin D2, the other leg of the
* button should be attached to GND.
*/
#include <IotWebConf.h>
// -- Initial name of the Thing. Used e.g. as SSID of the own Access Point.
const char thingName[] = "testThing";
// -- Initial password to connect to the Thing, when it creates an own Access Point.
const char wifiInitialApPassword[] = "smrtTHNG8266";
// -- Configuration specific key. The value should be modified if config structure was changed.
#define CONFIG_VERSION "dem1"
// -- When CONFIG_PIN is pulled to ground on startup, the Thing will use the initial
// password to buld an AP. (E.g. in case of lost password)
#define CONFIG_PIN D2
// -- Status indicator pin.
// First it will light up (kept LOW), on Wifi connection it will blink,
// when connected to the Wifi it will turn off (kept HIGH).
#define STATUS_PIN LED_BUILTIN
DNSServer dnsServer;
WebServer server(80);
HTTPUpdateServer httpUpdater;
IotWebConf iotWebConf(thingName, &dnsServer, &server, wifiInitialApPassword, CONFIG_VERSION);
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.println("Starting up...");
iotWebConf.setStatusPin(STATUS_PIN);
iotWebConf.setConfigPin(CONFIG_PIN);
iotWebConf.setupUpdateServer(&httpUpdater);
// -- Initializing the configuration.
iotWebConf.init();
// -- Set up required URL handlers on the web server.
server.on("/", handleRoot);
server.on("/config", []{ iotWebConf.handleConfig(); });
server.onNotFound([](){ iotWebConf.handleNotFound(); });
Serial.println("Ready.");
}
void loop()
{
// -- doLoop should be called as frequently as possible.
iotWebConf.doLoop();
}
/**
* Handle web requests to "/" path.
*/
void handleRoot()
{
// -- Let IotWebConf test and handle captive portal requests.
if (iotWebConf.handleCaptivePortal())
{
// -- Captive portal request were already served.
return;
}
String s = "<!DOCTYPE html><html lang=\"en\"><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\"/>";
s += "<title>IotWebConf 04 Update Server</title></head><body>Hello world!";
s += "Go to <a href='config'>configure page</a> to change values.";
s += "</body></html>\n";
server.send(200, "text/html", s);
}

View File

@ -0,0 +1,142 @@
/**
* IotWebConf05Callbacks.ino -- IotWebConf is an ESP8266/ESP32
* non blocking WiFi/AP web configuration library for Arduino.
* https://github.com/prampec/IotWebConf
*
* Copyright (C) 2018 Balazs Kelemen <prampec+arduino@gmail.com>
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
/**
* Example: Callbacks
* Description:
* This example shows, what callbacks IotWebConf provides.
* (See previous examples for more details!)
*
* Hardware setup for this example:
* - An LED is attached to LED_BUILTIN pin with setup On=LOW.
* - [Optional] A push button is attached to pin D2, the other leg of the
* button should be attached to GND.
*/
#include <IotWebConf.h>
// -- Initial name of the Thing. Used e.g. as SSID of the own Access Point.
const char thingName[] = "testThing";
// -- Initial password to connect to the Thing, when it creates an own Access Point.
const char wifiInitialApPassword[] = "smrtTHNG8266";
#define STRING_LEN 128
// -- Configuration specific key. The value should be modified if config structure was changed.
#define CONFIG_VERSION "dem3"
// -- When CONFIG_PIN is pulled to ground on startup, the Thing will use the initial
// password to buld an AP. (E.g. in case of lost password)
#define CONFIG_PIN D2
// -- Status indicator pin.
// First it will light up (kept LOW), on Wifi connection it will blink,
// when connected to the Wifi it will turn off (kept HIGH).
#define STATUS_PIN LED_BUILTIN
// -- Callback method declarations.
void wifiConnected();
void configSaved();
boolean formValidator();
void messageReceived(String &topic, String &payload);
DNSServer dnsServer;
WebServer server(80);
HTTPUpdateServer httpUpdater;
char stringParamValue[STRING_LEN];
IotWebConf iotWebConf(thingName, &dnsServer, &server, wifiInitialApPassword, CONFIG_VERSION);
IotWebConfParameter stringParam = IotWebConfParameter("String param", "stringParam", stringParamValue, STRING_LEN);
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.println("Starting up...");
iotWebConf.setStatusPin(STATUS_PIN);
iotWebConf.setConfigPin(CONFIG_PIN);
iotWebConf.addParameter(&stringParam);
iotWebConf.setConfigSavedCallback(&configSaved);
iotWebConf.setFormValidator(&formValidator);
iotWebConf.setWifiConnectionCallback(&wifiConnected);
// -- Initializing the configuration.
boolean validConfig = iotWebConf.init();
if (!validConfig)
{
stringParamValue[0] = '\0';
}
// -- Set up required URL handlers on the web server.
server.on("/", handleRoot);
server.on("/config", []{ iotWebConf.handleConfig(); });
server.onNotFound([](){ iotWebConf.handleNotFound(); });
Serial.println("Ready.");
}
void loop()
{
// -- doLoop should be called as frequently as possible.
iotWebConf.doLoop();
}
/**
* Handle web requests to "/" path.
*/
void handleRoot()
{
// -- Let IotWebConf test and handle captive portal requests.
if (iotWebConf.handleCaptivePortal())
{
// -- Captive portal request were already served.
return;
}
String s = "<!DOCTYPE html><html lang=\"en\"><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\"/>";
s += "<title>IotWebConf 05 Callbacks</title></head><body>Hello world!";
s += "<ul>";
s += "<li>String param value: ";
s += stringParamValue;
s += "</ul>";
s += "Go to <a href='config'>configure page</a> to change values.";
s += "</body></html>\n";
server.send(200, "text/html", s);
}
void wifiConnected()
{
Serial.println("WiFi was connected.");
}
void configSaved()
{
Serial.println("Configuration was updated.");
}
boolean formValidator()
{
Serial.println("Validating form.");
boolean valid = true;
int l = server.arg(stringParam.getId()).length();
if (l < 3)
{
stringParam.errorMessage = "Please provide at least 3 characters for this test!";
valid = false;
}
return valid;
}

View File

@ -0,0 +1,265 @@
/**
* IotWebConf06MqttApp.ino -- IotWebConf is an ESP8266/ESP32
* non blocking WiFi/AP web configuration library for Arduino.
* https://github.com/prampec/IotWebConf
*
* Copyright (C) 2018 Balazs Kelemen <prampec+arduino@gmail.com>
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
/**
* Example: MQTT Demo Application
* Description:
* All IotWebConf specific aspects of this example are described in
* previous examples, so please get familiar with IotWebConf before
* starting this example. So nothing new will be explained here,
* but a complete demo application will be build.
* It is also expected from the reader to have a basic knowledge over
* MQTT to understand this code.
*
* This example starts an MQTT client with the configured
* connection settings.
* Will post the status changes of the D2 pin in channel "/test/status".
* Receives messages appears in channel "/test/action", and writes them to serial.
* This example also provides the firmware update option.
* (See previous examples for more details!)
*
* Software setup for this example:
* This example utilizes Joel Gaehwiler's MQTT library.
* https://github.com/256dpi/arduino-mqtt
*
* Hardware setup for this example:
* - An LED is attached to LED_BUILTIN pin with setup On=LOW.
* - [Optional] A push button is attached to pin D2, the other leg of the
* button should be attached to GND.
*/
#include <MQTT.h>
#include <IotWebConf.h>
// -- Initial name of the Thing. Used e.g. as SSID of the own Access Point.
const char thingName[] = "testThing";
// -- Initial password to connect to the Thing, when it creates an own Access Point.
const char wifiInitialApPassword[] = "smrtTHNG8266";
#define STRING_LEN 128
// -- Configuration specific key. The value should be modified if config structure was changed.
#define CONFIG_VERSION "mqt1"
// -- When CONFIG_PIN is pulled to ground on startup, the Thing will use the initial
// password to buld an AP. (E.g. in case of lost password)
#define CONFIG_PIN D2
// -- Status indicator pin.
// First it will light up (kept LOW), on Wifi connection it will blink,
// when connected to the Wifi it will turn off (kept HIGH).
#define STATUS_PIN LED_BUILTIN
// -- Callback method declarations.
void wifiConnected();
void configSaved();
boolean formValidator();
void mqttMessageReceived(String &topic, String &payload);
DNSServer dnsServer;
WebServer server(80);
HTTPUpdateServer httpUpdater;
WiFiClient net;
MQTTClient mqttClient;
char mqttServerValue[STRING_LEN];
char mqttUserNameValue[STRING_LEN];
char mqttUserPasswordValue[STRING_LEN];
IotWebConf iotWebConf(thingName, &dnsServer, &server, wifiInitialApPassword, CONFIG_VERSION);
IotWebConfParameter mqttServerParam = IotWebConfParameter("MQTT server", "mqttServer", mqttServerValue, STRING_LEN);
IotWebConfParameter mqttUserNameParam = IotWebConfParameter("MQTT user", "mqttUser", mqttUserNameValue, STRING_LEN);
IotWebConfParameter mqttUserPasswordParam = IotWebConfParameter("MQTT password", "mqttPass", mqttUserPasswordValue, STRING_LEN, "password");
boolean needMqttConnect = false;
boolean needReset = false;
int pinState = HIGH;
unsigned long lastReport = 0;
unsigned long lastMqttConnectionAttempt = 0;
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.println("Starting up...");
iotWebConf.setStatusPin(STATUS_PIN);
iotWebConf.setConfigPin(CONFIG_PIN);
iotWebConf.addParameter(&mqttServerParam);
iotWebConf.addParameter(&mqttUserNameParam);
iotWebConf.addParameter(&mqttUserPasswordParam);
iotWebConf.setConfigSavedCallback(&configSaved);
iotWebConf.setFormValidator(&formValidator);
iotWebConf.setWifiConnectionCallback(&wifiConnected);
iotWebConf.setupUpdateServer(&httpUpdater);
// -- Initializing the configuration.
boolean validConfig = iotWebConf.init();
if (!validConfig)
{
mqttServerValue[0] = '\0';
mqttUserNameValue[0] = '\0';
mqttUserPasswordValue[0] = '\0';
}
// -- Set up required URL handlers on the web server.
server.on("/", handleRoot);
server.on("/config", []{ iotWebConf.handleConfig(); });
server.onNotFound([](){ iotWebConf.handleNotFound(); });
mqttClient.begin(mqttServerValue, net);
mqttClient.onMessage(mqttMessageReceived);
Serial.println("Ready.");
}
void loop()
{
// -- doLoop should be called as frequently as possible.
iotWebConf.doLoop();
mqttClient.loop();
if (needMqttConnect)
{
if (connectMqtt())
{
needMqttConnect = false;
}
}
else if ((iotWebConf.getState() == IOTWEBCONF_STATE_ONLINE) && (!mqttClient.connected()))
{
Serial.println("MQTT reconnect");
connectMqtt();
}
if (needReset)
{
Serial.println("Rebooting after 1 second.");
iotWebConf.delay(1000);
ESP.restart();
}
unsigned long now = millis();
if ((500 < now - lastReport) && (pinState != digitalRead(CONFIG_PIN)))
{
pinState = 1 - pinState; // invert pin state as it is changed
lastReport = now;
Serial.print("Sending on MQTT channel '/test/status' :");
Serial.println(pinState == LOW ? "ON" : "OFF");
mqttClient.publish("/test/status", pinState == LOW ? "ON" : "OFF");
}
}
/**
* Handle web requests to "/" path.
*/
void handleRoot()
{
// -- Let IotWebConf test and handle captive portal requests.
if (iotWebConf.handleCaptivePortal())
{
// -- Captive portal request were already served.
return;
}
String s = "<!DOCTYPE html><html lang=\"en\"><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\"/>";
s += "<title>IotWebConf 06 MQTT App</title></head><body>MQTT App demo";
s += "<ul>";
s += "<li>MQTT server: ";
s += mqttServerValue;
s += "</ul>";
s += "Go to <a href='config'>configure page</a> to change values.";
s += "</body></html>\n";
server.send(200, "text/html", s);
}
void wifiConnected()
{
needMqttConnect = true;
}
void configSaved()
{
Serial.println("Configuration was updated.");
needReset = true;
}
boolean formValidator()
{
Serial.println("Validating form.");
boolean valid = true;
int l = server.arg(mqttServerParam.getId()).length();
if (l < 3)
{
mqttServerParam.errorMessage = "Please provide at least 3 characters!";
valid = false;
}
return valid;
}
boolean connectMqtt() {
unsigned long now = millis();
if (1000 > now - lastMqttConnectionAttempt)
{
// Do not repeat within 1 sec.
return false;
}
Serial.println("Connecting to MQTT server...");
if (!connectMqttOptions()) {
lastMqttConnectionAttempt = now;
return false;
}
Serial.println("Connected!");
mqttClient.subscribe("/test/action");
return true;
}
/*
// -- This is an alternative MQTT connection method.
boolean connectMqtt() {
Serial.println("Connecting to MQTT server...");
while (!connectMqttOptions()) {
iotWebConf.delay(1000);
}
Serial.println("Connected!");
mqttClient.subscribe("/test/action");
return true;
}
*/
boolean connectMqttOptions()
{
boolean result;
if (mqttUserPasswordValue[0] != '\0')
{
result = mqttClient.connect(iotWebConf.getThingName(), mqttUserNameValue, mqttUserPasswordValue);
}
else if (mqttUserNameValue[0] != '\0')
{
result = mqttClient.connect(iotWebConf.getThingName(), mqttUserNameValue);
}
else
{
result = mqttClient.connect(iotWebConf.getThingName());
}
return result;
}
void mqttMessageReceived(String &topic, String &payload)
{
Serial.println("Incoming: " + topic + " - " + payload);
}

View File

@ -0,0 +1,299 @@
/**
* IotWebConf07MqttRelay.ino -- IotWebConf is an ESP8266/ESP32
* non blocking WiFi/AP web configuration library for Arduino.
* https://github.com/prampec/IotWebConf
*
* Copyright (C) 2018 Balazs Kelemen <prampec+arduino@gmail.com>
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
/**
* Example: MQTT Relay Demo
* Description:
* All IotWebConf specific aspects of this example are described in
* previous examples, so please get familiar with IotWebConf before
* starting this example. So nothing new will be explained here,
* but a complete demo application will be built.
* It is also expected from the reader to have a basic knowledge over
* MQTT to understand this code.
*
* This example starts an MQTT client with the configured
* connection settings.
* Will receives messages appears in channel "/devices/[thingName]/action"
* with payload ON/OFF, and reports current state in channel
* "/devices/[thingName]/status" (ON/OFF). Where the thingName can be
* configured in the portal. A relay will be switched on/off
* corresponding to the received action. The relay can be also controlled
* by the push button.
* The thing will delay actions arriving within 7 seconds.
*
* This example also provides the firmware update option.
* (See previous examples for more details!)
*
* Software setup for this example:
* This example utilizes Joel Gaehwiler's MQTT library.
* https://github.com/256dpi/arduino-mqtt
*
* Hardware setup for this example:
* - A Relay is attached to the D5 pin (On=HIGH). Note on relay pin!
* - An LED is attached to LED_BUILTIN pin with setup On=LOW.
* - A push button is attached to pin D2, the other leg of the
* button should be attached to GND.
*
* Note on relay pin
* Some people might want to use Wemos Relay Shield to test this example.
* Now Wemos Relay Shield connects the relay to pin D1.
* However, when using D1 as output, Serial communication will be blocked.
* So you will either keep on using D1 and miss the Serial monitor
* feedback, or connect your relay to another digital pin (e.g. D5).
* (You can modify your Wemos Relay Shield for that, as I show it in this
* video: https://youtu.be/GykA_7QmoXE)
*/
#include <MQTT.h>
#include <IotWebConf.h>
// -- Initial name of the Thing. Used e.g. as SSID of the own Access Point.
const char thingName[] = "testThing";
// -- Initial password to connect to the Thing, when it creates an own Access Point.
const char wifiInitialApPassword[] = "smrtTHNG8266";
#define STRING_LEN 128
// -- Configuration specific key. The value should be modified if config structure was changed.
#define CONFIG_VERSION "mqt2"
// -- When BUTTON_PIN is pulled to ground on startup, the Thing will use the initial
// password to buld an AP. (E.g. in case of lost password)
#define BUTTON_PIN D2
// -- Status indicator pin.
// First it will light up (kept LOW), on Wifi connection it will blink,
// when connected to the Wifi it will turn off (kept HIGH).
#define STATUS_PIN LED_BUILTIN
// -- Connected ouput pin. See "Note on relay pin"!
#define RELAY_PIN D5
#define MQTT_TOPIC_PREFIX "/devices/"
// -- Ignore/limit status changes more frequent than the value below (milliseconds).
#define ACTION_FEQ_LIMIT 7000
#define NO_ACTION -1
// -- Callback method declarations.
void wifiConnected();
void configSaved();
boolean formValidator();
void mqttMessageReceived(String &topic, String &payload);
DNSServer dnsServer;
WebServer server(80);
HTTPUpdateServer httpUpdater;
WiFiClient net;
MQTTClient mqttClient;
char mqttServerValue[STRING_LEN];
IotWebConf iotWebConf(thingName, &dnsServer, &server, wifiInitialApPassword, CONFIG_VERSION);
IotWebConfParameter mqttServerParam = IotWebConfParameter("MQTT server", "mqttServer", mqttServerValue, STRING_LEN);
boolean needMqttConnect = false;
boolean needReset = false;
unsigned long lastMqttConnectionAttempt = 0;
int needAction = NO_ACTION;
int state = LOW;
unsigned long lastAction = 0;
char mqttActionTopic[STRING_LEN];
char mqttStatusTopic[STRING_LEN];
void setup()
{
Serial.begin(115200); // See "Note on relay pin"!
Serial.println();
Serial.println("Starting up...");
pinMode(RELAY_PIN, OUTPUT);
iotWebConf.setStatusPin(STATUS_PIN);
iotWebConf.setConfigPin(BUTTON_PIN);
iotWebConf.addParameter(&mqttServerParam);
iotWebConf.setConfigSavedCallback(&configSaved);
iotWebConf.setFormValidator(&formValidator);
iotWebConf.setWifiConnectionCallback(&wifiConnected);
iotWebConf.setupUpdateServer(&httpUpdater);
// -- Initializing the configuration.
boolean validConfig = iotWebConf.init();
if (!validConfig)
{
mqttServerValue[0] = '\0';
}
// -- Set up required URL handlers on the web server.
server.on("/", handleRoot);
server.on("/config", []{ iotWebConf.handleConfig(); });
server.onNotFound([](){ iotWebConf.handleNotFound(); });
// -- Prepare dynamic topic names
String temp = String(MQTT_TOPIC_PREFIX);
temp += iotWebConf.getThingName();
temp += "/action";
temp.toCharArray(mqttActionTopic, STRING_LEN);
temp = String(MQTT_TOPIC_PREFIX);
temp += iotWebConf.getThingName();
temp += "/status";
temp.toCharArray(mqttStatusTopic, STRING_LEN);
mqttClient.begin(mqttServerValue, net);
mqttClient.onMessage(mqttMessageReceived);
Serial.println("Ready.");
}
void loop()
{
// -- doLoop should be called as frequently as possible.
iotWebConf.doLoop();
mqttClient.loop();
if (needMqttConnect)
{
if (connectMqtt())
{
needMqttConnect = false;
}
}
else if ((iotWebConf.getState() == IOTWEBCONF_STATE_ONLINE) && (!mqttClient.connected()))
{
Serial.println("MQTT reconnect");
connectMqtt();
}
if (needReset)
{
Serial.println("Rebooting after 1 second.");
iotWebConf.delay(1000);
ESP.restart();
}
unsigned long now = millis();
// -- Check for button push
if ((digitalRead(BUTTON_PIN) == LOW)
&& ( ACTION_FEQ_LIMIT < now - lastAction))
{
needAction = 1 - state; // -- Invert the state
}
if ((needAction != NO_ACTION)
&& ( ACTION_FEQ_LIMIT < now - lastAction))
{
state = needAction;
digitalWrite(RELAY_PIN, state);
if (state == HIGH)
{
iotWebConf.blink(5000, 95);
}
else
{
iotWebConf.stopCustomBlink();
}
mqttClient.publish(mqttStatusTopic, state == HIGH ? "ON" : "OFF", true, 1);
mqttClient.publish(mqttActionTopic, state == HIGH ? "ON" : "OFF", true, 1);
Serial.print("Switched ");
Serial.println(state == HIGH ? "ON" : "OFF");
needAction = NO_ACTION;
lastAction = now;
}
}
/**
* Handle web requests to "/" path.
*/
void handleRoot()
{
// -- Let IotWebConf test and handle captive portal requests.
if (iotWebConf.handleCaptivePortal())
{
// -- Captive portal request were already served.
return;
}
String s = F("<!DOCTYPE html><html lang=\"en\"><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\"/>");
s += iotWebConf.getHtmlFormatProvider()->getStyle();
s += "<title>IotWebConf 07 MQTT Relay</title></head><body>";
s += iotWebConf.getThingName();
s += "<div>State: ";
s += (state == HIGH ? "ON" : "OFF");
s += "</div>";
s += "<button type='button' onclick=\"location.href='';\" >Refresh</button>";
s += "<div>Go to <a href='config'>configure page</a> to change values.</div>";
s += "</body></html>\n";
server.send(200, "text/html", s);
}
void wifiConnected()
{
needMqttConnect = true;
}
void configSaved()
{
Serial.println("Configuration was updated.");
needReset = true;
}
boolean formValidator()
{
Serial.println("Validating form.");
boolean valid = true;
int l = server.arg(mqttServerParam.getId()).length();
if (l < 3)
{
mqttServerParam.errorMessage = "Please provide at least 3 characters!";
valid = false;
}
return valid;
}
boolean connectMqtt() {
unsigned long now = millis();
if (1000 > now - lastMqttConnectionAttempt)
{
// Do not repeat within 1 sec.
return false;
}
Serial.println("Connecting to MQTT server...");
if (!mqttClient.connect(iotWebConf.getThingName())) {
lastMqttConnectionAttempt = now;
return false;
}
Serial.println("Connected!");
mqttClient.subscribe(mqttActionTopic);
mqttClient.publish(mqttStatusTopic, state == HIGH ? "ON" : "OFF", true, 1);
mqttClient.publish(mqttActionTopic, state == HIGH ? "ON" : "OFF", true, 1);
return true;
}
void mqttMessageReceived(String &topic, String &payload)
{
Serial.println("Incoming: " + topic + " - " + payload);
if (topic.endsWith("action"))
{
needAction = payload.equals("ON") ? HIGH : LOW;
if (needAction == state)
{
needAction = NO_ACTION;
}
}
}

View File

@ -0,0 +1,196 @@
/**
* IotWebConf08WebRelay.ino -- IotWebConf is an ESP8266/ESP32
* non blocking WiFi/AP web configuration library for Arduino.
* https://github.com/prampec/IotWebConf
*
* Copyright (C) 2018 Balazs Kelemen <prampec+arduino@gmail.com>
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
/**
* Example: Web Relay Demo
* Description:
* All IotWebConf specific aspects of this example are described in
* previous examples, so please get familiar with IotWebConf before
* starting this example. So nothing new will be explained here,
* but a complete demo application will be built.
* It is also expected from the reader to have a basic knowledge over
* HTML to understand this code.
*
* This example stets up a web page, where switch action can take place.
* The repay can be also altered with the push button.
* The thing will delay actions arriving within 10 seconds.
*
* This example also provides the firmware update option.
* (See previous examples for more details!)
*
* Hardware setup for this example:
* - A Relay is attached to the D1 pin (On=HIGH)
* - An LED is attached to LED_BUILTIN pin with setup On=LOW.
* - A push button is attached to pin D2, the other leg of the
* button should be attached to GND.
*/
#include <IotWebConf.h>
// -- Initial name of the Thing. Used e.g. as SSID of the own Access Point.
const char thingName[] = "testThing";
// -- Initial password to connect to the Thing, when it creates an own Access Point.
const char wifiInitialApPassword[] = "smrtTHNG8266";
#define STRING_LEN 128
// -- Configuration specific key. The value should be modified if config structure was changed.
#define CONFIG_VERSION "web1"
// -- When BUTTON_PIN is pulled to ground on startup, the Thing will use the initial
// password to buld an AP. (E.g. in case of lost password)
#define BUTTON_PIN D2
// -- Status indicator pin.
// First it will light up (kept LOW), on Wifi connection it will blink,
// when connected to the Wifi it will turn off (kept HIGH).
#define STATUS_PIN LED_BUILTIN
// -- Connected ouput pin.
#define RELAY_PIN D1
#define ACTION_FEQ_LIMIT 10000
#define NO_ACTION -1
// -- Callback method declarations.
void configSaved();
DNSServer dnsServer;
WebServer server(80);
HTTPUpdateServer httpUpdater;
IotWebConf iotWebConf(thingName, &dnsServer, &server, wifiInitialApPassword, CONFIG_VERSION);
boolean needReset = false;
int needAction = NO_ACTION;
int state = LOW;
unsigned long lastAction = 0;
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.println("Starting up...");
pinMode(RELAY_PIN, OUTPUT);
iotWebConf.setStatusPin(STATUS_PIN);
iotWebConf.setConfigPin(BUTTON_PIN);
iotWebConf.setConfigSavedCallback(&configSaved);
iotWebConf.setupUpdateServer(&httpUpdater);
// -- Initializing the configuration.
iotWebConf.init();
// -- Set up required URL handlers on the web server.
server.on("/", handleRoot);
server.on("/config", []{ iotWebConf.handleConfig(); });
server.onNotFound([](){ iotWebConf.handleNotFound(); });
Serial.println("Ready.");
}
void loop()
{
// -- doLoop should be called as frequently as possible.
iotWebConf.doLoop();
if (needReset)
{
Serial.println("Rebooting after 1 second.");
iotWebConf.delay(1000);
ESP.restart();
}
unsigned long now = millis();
// -- Check for button push
if ((digitalRead(BUTTON_PIN) == LOW)
&& (ACTION_FEQ_LIMIT < now - lastAction))
{
needAction = 1 - state; // -- Invert the state
}
applyAction(now);
}
void applyAction(unsigned long now)
{
if ((needAction != NO_ACTION)
&& (ACTION_FEQ_LIMIT < now - lastAction))
{
state = needAction;
digitalWrite(RELAY_PIN, state);
if (state == HIGH)
{
iotWebConf.blink(5000, 95);
}
else
{
iotWebConf.stopCustomBlink();
}
Serial.print("Switched ");
Serial.println(state == HIGH ? "ON" : "OFF");
needAction = NO_ACTION;
lastAction = now;
}
}
/**
* Handle web requests to "/" path.
*/
void handleRoot()
{
// -- Let IotWebConf test and handle captive portal requests.
if (iotWebConf.handleCaptivePortal())
{
// -- Captive portal request were already served.
return;
}
if (server.hasArg("action"))
{
String action = server.arg("action");
if (action.equals("on"))
{
needAction = HIGH;
}
else if (action.equals("off"))
{
needAction = LOW;
}
applyAction(millis());
}
String s = F("<!DOCTYPE html><html lang=\"en\"><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\"/>");
s += iotWebConf.getHtmlFormatProvider()->getStyle();
s += "<title>IotWebConf 08 Web Relay</title></head><body>";
s += iotWebConf.getThingName();
s += "<div>State: ";
s += (state == HIGH ? "ON" : "OFF");
s += "</div>";
s += "<div>";
s += "<button type='button' onclick=\"location.href='?action=on';\" >Turn ON</button>";
s += "<button type='button' onclick=\"location.href='?action=off';\" >Turn OFF</button>";
s += "<button type='button' onclick=\"location.href='?';\" >Refresh</button>";
s += "</div>";
s += "<div>Go to <a href='config'>configure page</a> to change values.</div>";
s += "</body></html>\n";
server.send(200, "text/html", s);
}
void configSaved()
{
Serial.println("Configuration was updated.");
needReset = true;
}

View File

@ -0,0 +1,179 @@
/**
* IotWebConf09CustomConnection.ino -- IotWebConf is an ESP8266/ESP32
* non blocking WiFi/AP web configuration library for Arduino.
* https://github.com/prampec/IotWebConf
*
* Copyright (C) 2018 Balazs Kelemen <prampec+arduino@gmail.com>
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
/**
* Example: Custom connection
* Description:
* This example is for advanced users only!
* In this example custom connection handler methods are defined
* to override the default connecting behavior.
* Also, three custom parameters are introduced, that are used
* at the connection.
* (See previous examples for more details!)
*
* Hardware setup for this example:
* - An LED is attached to LED_BUILTIN pin with setup On=LOW.
* - [Optional] A push button is attached to pin D2, the other leg of the
* button should be attached to GND.
*/
#include <IotWebConf.h>
// -- Initial name of the Thing. Used e.g. as SSID of the own Access Point.
const char thingName[] = "testThing";
// -- Initial password to connect to the Thing, when it creates an own Access Point.
const char wifiInitialApPassword[] = "smrtTHNG8266";
#define STRING_LEN 128
#define NUMBER_LEN 32
// -- Configuration specific key. The value should be modified if config structure was changed.
#define CONFIG_VERSION "dem9"
// -- When CONFIG_PIN is pulled to ground on startup, the Thing will use the initial
// password to buld an AP. (E.g. in case of lost password)
#define CONFIG_PIN 2
// -- Status indicator pin.
// First it will light up (kept LOW), on Wifi connection it will blink,
// when connected to the Wifi it will turn off (kept HIGH).
#define STATUS_PIN LED_BUILTIN
// -- Callback method declarations.
void configSaved();
boolean formValidator();
boolean connectAp(const char* apName, const char* password);
void connectWifi(const char* ssid, const char* password);
DNSServer dnsServer;
WebServer server(80);
char ipAddressValue[STRING_LEN];
char gatewayValue[STRING_LEN];
char netmaskValue[STRING_LEN];
IotWebConf iotWebConf(thingName, &dnsServer, &server, wifiInitialApPassword, CONFIG_VERSION);
IotWebConfParameter ipAddressParam = IotWebConfParameter("IP address", "ipAddress", ipAddressValue, STRING_LEN, "text", NULL, "192.168.3.222");
IotWebConfParameter gatewayParam = IotWebConfParameter("Gateway", "gateway", gatewayValue, STRING_LEN, "text", NULL, "192.168.3.0");
IotWebConfParameter netmaskParam = IotWebConfParameter("Subnet mask", "netmask", netmaskValue, STRING_LEN, "text", NULL, "255.255.255.0");
IPAddress ipAddress;
IPAddress gateway;
IPAddress netmask;
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.println("Starting up...");
iotWebConf.setStatusPin(STATUS_PIN);
iotWebConf.setConfigPin(CONFIG_PIN);
iotWebConf.addParameter(&ipAddressParam);
iotWebConf.addParameter(&gatewayParam);
iotWebConf.addParameter(&netmaskParam);
iotWebConf.setConfigSavedCallback(&configSaved);
iotWebConf.setFormValidator(&formValidator);
iotWebConf.setApConnectionHandler(&connectAp);
iotWebConf.setWifiConnectionHandler(&connectWifi);
// -- Initializing the configuration.
boolean validConfig = iotWebConf.init();
// -- Set up required URL handlers on the web server.
server.on("/", handleRoot);
server.on("/config", []{ iotWebConf.handleConfig(); });
server.onNotFound([](){ iotWebConf.handleNotFound(); });
Serial.println("Ready.");
}
void loop()
{
// -- doLoop should be called as frequently as possible.
iotWebConf.doLoop();
}
/**
* Handle web requests to "/" path.
*/
void handleRoot()
{
// -- Let IotWebConf test and handle captive portal requests.
if (iotWebConf.handleCaptivePortal())
{
// -- Captive portal request were already served.
return;
}
String s = "<!DOCTYPE html><html lang=\"en\"><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\"/>";
s += "<title>IotWebConf 09 Custom Connection</title></head><body>Hello world!";
s += "<ul>";
s += "<li>IP address: ";
s += ipAddressValue;
s += "</ul>";
s += "Go to <a href='config'>configure page</a> to change values.";
s += "</body></html>\n";
server.send(200, "text/html", s);
}
void configSaved()
{
Serial.println("Configuration was updated.");
}
boolean formValidator()
{
Serial.println("Validating form.");
boolean valid = true;
if (!ipAddress.fromString(server.arg(ipAddressParam.getId())))
{
ipAddressParam.errorMessage = "Please provide a valid IP address!";
valid = false;
}
if (!netmask.fromString(server.arg(netmaskParam.getId())))
{
netmaskParam.errorMessage = "Please provide a valid netmask!";
valid = false;
}
if (!gateway.fromString(server.arg(gatewayParam.getId())))
{
gatewayParam.errorMessage = "Please provide a valid gateway address!";
valid = false;
}
return valid;
}
boolean connectAp(const char* apName, const char* password)
{
// -- Custom AP settings
return WiFi.softAP(apName, password, 4);
}
void connectWifi(const char* ssid, const char* password)
{
ipAddress.fromString(String(ipAddressValue));
netmask.fromString(String(netmaskValue));
gateway.fromString(String(gatewayValue));
if (!WiFi.config(ipAddress, gateway, netmask)) {
Serial.println("STA Failed to configure");
}
Serial.print("ip: ");
Serial.println(ipAddress);
Serial.print("gw: ");
Serial.println(gateway);
Serial.print("net: ");
Serial.println(netmask);
WiFi.begin(ssid, password);
}

View File

@ -0,0 +1,116 @@
/**
* IotWebConf01Minimal.ino -- IotWebConf is an ESP8266/ESP32
* non blocking WiFi/AP web configuration library for Arduino.
* https://github.com/prampec/IotWebConf
*
* Copyright (C) 2018 Balazs Kelemen <prampec+arduino@gmail.com>
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
/**
* Example: Custom HTML
* Description:
* This example demostrates how to override the default look and feel of the
* config portal.
*
* The first customalization is to add a logo to the config page.
*
* The second customalization is a special javascript, that detects all
* password fields, and adds a small button after each of them with a
* lock on it. By pressing the lock the password became visible/hidden.
*/
#include <IotWebConf.h>
// -- Initial name of the Thing. Used e.g. as SSID of the own Access Point.
const char thingName[] = "testThing";
// -- Initial password to connect to the Thing, when it creates an own Access Point.
const char wifiInitialApPassword[] = "smrtTHNG8266";
DNSServer dnsServer;
WebServer server(80);
IotWebConf iotWebConf(thingName, &dnsServer, &server, wifiInitialApPassword);
// -- Javascript block will be added to the header.
const char CUSTOMHTML_SCRIPT_INNER[] PROGMEM = "\n\
document.addEventListener('DOMContentLoaded', function(event) {\n\
let elements = document.querySelectorAll('input[type=\"password\"]');\n\
for (let p of elements) {\n\
let btn = document.createElement('INPUT'); btn.type = 'button'; btn.value = '🔓'; btn.style.width = 'auto'; p.style.width = '83%'; p.parentNode.insertBefore(btn,p.nextSibling);\n\
btn.onclick = function() { if (p.type === 'password') { p.type = 'text'; btn.value = '🔒'; } else { p.type = 'password'; btn.value = '🔓'; } }\n\
};\n\
});\n";
// -- HTML element will be added inside the body element.
const char CUSTOMHTML_BODY_INNER[] PROGMEM = "<div><img src='data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAAS8AAABaBAMAAAAbaM0tAAAAMFBMVEUAAQATFRIcHRsmKCUuLy3TCAJnaWbmaWiHiYYkquKsqKWH0vDzurrNzsvg5+j9//wjKRqOAAAAAWJLR0QAiAUdSAAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB+MHBhYoILXXEeAAAAewSURBVGje7ZrBaxtXEIfHjlmEwJFOvbXxKbc2/gfa6FRyKTkJX1KyIRCCIfXJ+BLI0gYTAknOwhA7FxMKts7GEJ9CLmmtlmKMCZZzKbGdZBXiOIqc3e2bmfd232pXalabalXwg4jNWm/1aWbeb+bNE3iDORpwDHYMdgz2fwBbsQcVbO0YLBnY7vyAgn2YzzzgOoDdD67dSrZgRxqLdzSnQc5l68oPlQ5gK13iDSDRRxV6AXMr87r7unnSmQW4umT3Cczb1U1W6eJJxwQchX6BhUwWmCnqyRr0FyxkMl9hjyKedAHyde/Vw/N9AwuZrLMnW2D0Nfjbo0xZLAJ7CKP9BgtM5m7dmr31q/2vzxdgLdOo0vXeLHyxrN6wWCrQ6jWW+XmzcLXeO5i3y37buszhDbl67IyTGpgj3kau3aQZ9xjsL1wbrqnueAv4sBRgrFk3wR/Dd7W/ripX6jG2oz6cJxhMTouWV2+OwhKH1TuYty/+XQJ9/KRFILu2KT5s2wezll2LTAiTtrtJjA3IGeINbhGu2XsAVRQYo47q1zuYGA+I5wRcuQJFcTFU9XXjvi8XQviXJVgeTShevLsscSfxkWTCJhmL7ph4o5kOjFxjLDHC4hjAiPLyXFhgrzHYFDoqF0hJnsD4SVOEl/ccvpEKzBEoUNU0C+A7VtxAaIXvgsCqogmNQHxz+Mg8Bzw+xxF3mupGCrA/hLl0lXBKMFynANOL7U1cb3kCa0vlyNhgoTPpb54wuVS+WgowR4QVcnycmVlXaxC+1AJMjS2TmJSPpI7h8PWkpNaPurGTAuxA6s77clmCCQcM214lJjHhOzWwpsJQCgwaWCGd8qP5KRp8sGfraMSz3m40CSxgbGtg1mcHc229cMCAvb7+rlxGx5bLFzHsjLiJ5JgATFjwjvStBChCW65I6soPlbk1Txd1wVMuT7DdbuC6gnqnlBmAsZi5GpjpT+sx+I8qlcqcLf9zhnnEmHnqvWOHWsKXcRY7pYMxjaOBLfiy06tcuKuI9oimYui/K8sxTQ5VutQ9xthdhxpYzU/2KQRWorEsPS4H4zr550SoHqvLD6tGXbmggTVZEZ2pdClpX5B5Y/yfpzNhNDMUZA24ve29sigcAzDxscveZk4D4xJ8yyykTeL7867vMxH80xJsQmW9YAaPkyEwSu3wlQambVqaKcseR0XFR1yOzxjtR7Um2sBydgiMMAxbB+OcatTTF4otNZP1VSyCmWkUjKZWs2LZPWuCcdv2wmDeInxf1XUMq5PxEX6fk660bsJ5H4wWgXDj03W05Gi23Z6m+kos/NPlCyoh5AcGbIJWwEVVzGQMxjHmoBMvyBUgLTZ6VFldtTMDcyj3PMaQv6CXPg6C4VjLCMwli5FKTFz/jQONXXzKe726UqnMZwTmjYvV5waiP1EP771fZ2UxzzRUbaHQbnAhcS/j5nBtGKvWJ9MBGa1LC+yMwd5yCfWeJJ8GWswtGpm20/dRL874wv/eB2uEMlL/2+m4ox3L+fqKLy+fcAX7mUPsk7pqCuyIyusa+ZLAHquE1OryHICEVigkBXMr1ALg6vzl7yRnMiFZ8E12YO6KVHXTd9vMzA25xRmqZwemuHA3EcZojcPX3mcG+/TgX6k8CjY/ubZOAIrY/YzAdoMPdk34IfjrYpFaFEed0vd/DebqDR/fZO5Dv9e5MtcFLGhdmyzQtOXEXtWkrZrYMBnsFuTXaYlyu9re+t70q/boeeWOrAoXikF3ONKGCoOp1jUTMd/fqjMswHCjMtUG5oyLy5F6uPW94R8GxYDVcmoZwFDO9jvDa13AVOt6h3KEi2HpgGo7chObW40a2AJd50PzXegG9ielbKc0PDKpLdB4Z0ow1bpmGaSe7HMwtt0Fbsnm8vYLWkOaXDjYxd0gDdDni12zuzUVD9YiKWtttx3dxFaJEky1rh1qJR/gporymIM4DWomkHs1sENys8UNEDX/jbYdi4AdlrTmsH5qstYZzG9dkwWw3SQbxpZ4VkOG370QGPekqF0bzNdXbRQMTteTpWOtdU12wpcWb6xq4pKbRTsc/T6YRV+fzgKC+QfadizqytJ5LymYHfQJCmy2Qy6VGmILzVUTMWlg3KhxECeYL+T8tt0J7MW4kRjMv8Sv3MJAO1AN2IKkaQcrEg11uLT5ppCNOx3AAE73DoaHrIfydKQ7mMwZwaWcLyUkBqyWZNfdDoYStiPPk3oB85xFdZIYAUv0g7J2MFQFkv83wfpK4kpEs9hk7RzuL1BPASaoSLG08+l4sFDwh+oBeeYePX07UU0BJrRBBku+O1hILkJgrnpS+KPeDtXTuLIpM7cDYHcFCwlsuIKKB3OgmgYMc/coaz7VSxshMOngSEryb9Y7u7JVPJsGzFPFgSgYlnCNhcCa3JGNJHH/sMBYsl/FB79TTLS7jYJZcrU7bWde9Op2KHuCUwwasdXFWKJ2axSspnYzL9QBtQbGNLJQLAaFol8LWaq6jII9h3RgwY8f9i7DueVw8HvuYikorW/CuWpb69t9WOJ6PCbGyBMbXuYjIvRWXh12DRjYG9j+GZKof7/AdtQxy8C5EgCy/6V1bD0GA/GD9QjY3qVw92JgwIRWfDugYIMxjsESg/0DuDZiWzBJr80AAAAASUVORK5CYII='/></div>\n";
// -- This is an OOP technique to override behaviour of the existing
// IotWebConfHtmlFormatProvider. Here two method are overriden from
// the original class. See IotWebConf.h for all potentially overridable
// methods of IotWebConfHtmlFormatProvider .
class CustomHtmlFormatProvider : public IotWebConfHtmlFormatProvider
{
protected:
String getScriptInner() override
{
return
IotWebConfHtmlFormatProvider::getScriptInner() +
String(FPSTR(CUSTOMHTML_SCRIPT_INNER));
}
String getBodyInner() override
{
return
String(FPSTR(CUSTOMHTML_BODY_INNER)) +
IotWebConfHtmlFormatProvider::getBodyInner();
}
};
// -- An instance must be created from the class defined above.
CustomHtmlFormatProvider customHtmlFormatProvider;
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.println("Starting up...");
// -- Applying the new HTML format to IotWebConf.
iotWebConf.setHtmlFormatProvider(&customHtmlFormatProvider);
iotWebConf.init();
// -- Set up required URL handlers on the web server.
server.on("/", handleRoot);
server.on("/config", []{ iotWebConf.handleConfig(); });
server.onNotFound([](){ iotWebConf.handleNotFound(); });
Serial.println("Ready.");
}
void loop()
{
// -- doLoop should be called as frequently as possible.
iotWebConf.doLoop();
}
/**
* Handle web requests to "/" path.
*/
void handleRoot()
{
// -- Let IotWebConf test and handle captive portal requests.
if (iotWebConf.handleCaptivePortal())
{
// -- Captive portal request were already served.
return;
}
String s = "<!DOCTYPE html><html lang=\"en\"><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\"/>";
s += "<title>IotWebConf 10 Custom HTML</title></head><body>";
s += FPSTR(CUSTOMHTML_BODY_INNER);
s += "Go to <a href='config'>configure page</a> to change settings.";
s += "</body></html>\n";
server.send(200, "text/html; charset=UTF-8", s);
}

View File

@ -0,0 +1,43 @@
# Datatypes (KEYWORD1)
# Methods and Functions (KEYWORD2)
# Constants (LITERAL1)
IotWebConfParameter KEYWORD1
label KEYWORD3
id KEYWORD3
valueBuffer KEYWORD3
length KEYWORD3
type KEYWORD3
placeholder KEYWORD3
defaultValue KEYWORD3
customHtml KEYWORD3
visible KEYWORD3
IotWebConfSeparator KEYWORD1
IotWebConf KEYWORD1
setConfigPin KEYWORD2
setStatusPin KEYWORD2
setupUpdateServer KEYWORD2
init KEYWORD2
doLoop KEYWORD2
handleCaptivePortal KEYWORD2
handleConfig KEYWORD2
handleNotFound KEYWORD2
setWifiConnectionCallback KEYWORD2
setConfigSavedCallback KEYWORD2
setFormValidator KEYWORD2
addParameter KEYWORD2
getThingName KEYWORD2
delay KEYWORD2
setWifiConnectionTimeoutMs KEYWORD2
blink KEYWORD2
getState KEYWORD2
setApTimeoutMs KEYWORD2
getApTimeoutMs KEYWORD2
getThingNameParameter KEYWORD2
getApPasswordParameter KEYWORD2
getWifiSsidParameter KEYWORD2
getWifiPasswordParameter KEYWORD2
getApTimeoutParameter KEYWORD2
configSave KEYWORD2

View File

@ -0,0 +1,10 @@
name=IotWebConf
version=2.3.0
author=Balazs Kelemen <prampec+arduino@gmail.com>
maintainer=Balazs Kelemen <prampec+arduino@gmail.com>
sentence=ESP8266/ESP32 non-blocking WiFi/AP web configuration.
paragraph=IotWebConf will start up in AP (access point) mode, and provide a config portal for entering WiFi connection and other user-settings. The configuration is persisted in EEPROM. The config portal will stay available after WiFi connection was made. A WiFiManager alternative.
category=Communication
url=https://github.com/prampec/IotWebConf
architectures=esp8266,esp32
includes=IotWebConf.h

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,589 @@
/**
* IotWebConf.h -- IotWebConf is an ESP8266/ESP32
* non blocking WiFi/AP web configuration library for Arduino.
* https://github.com/prampec/IotWebConf
*
* Copyright (C) 2018 Balazs Kelemen <prampec+arduino@gmail.com>
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
#ifndef IotWebConf_h
#define IotWebConf_h
#ifndef USE_ESPASYNCWEBSERVER
#include <IotWebConfCompatibility.h>
#ifdef ESP8266
# include <ESP8266WiFi.h>
# include <ESP8266WebServer.h>
# include <ESP8266HTTPUpdateServer.h>
#elif defined(ESP32)
# include <WiFi.h>
# include <WebServer.h>
#endif
#else
#include <ESPAsyncWebServer.h>
#endif
#include <DNSServer.h> // -- For captive portal
// -- We might want to place the config in the EEPROM in an offset.
#define IOTWEBCONF_CONFIG_START 0
// -- Maximal length of any string used in IotWebConfig configuration (e.g.
// ssid, password).
#define IOTWEBCONF_WORD_LEN 33
// -- IotWebConf tries to connect to the local network for an amount of time
// before falling back to AP mode.
#define IOTWEBCONF_DEFAULT_WIFI_CONNECTION_TIMEOUT_MS 30000
// -- Thing will stay in AP mode for an amount of time on boot, before retrying
// to connect to a WiFi network.
#define IOTWEBCONF_DEFAULT_AP_MODE_TIMEOUT_MS 30000
// -- mDNS should allow you to connect to this device with a hostname provided
// by the device. E.g. mything.local
#define IOTWEBCONF_CONFIG_USE_MDNS
// -- Logs progress information to Serial if enabled.
#define IOTWEBCONF_DEBUG_TO_SERIAL
// -- Logs passwords to Serial if enabled.
//#define IOTWEBCONF_DEBUG_PWD_TO_SERIAL
// -- Helper define for serial debug
#ifdef IOTWEBCONF_DEBUG_TO_SERIAL
# define IOTWEBCONF_DEBUG_LINE(MSG) Serial.println(MSG)
#else
# define IOTWEBCONF_DEBUG_LINE(MSG)
#endif
// -- EEPROM config starts with a special prefix of length defined here.
#define IOTWEBCONF_CONFIG_VESION_LENGTH 4
#define IOTWEBCONF_DNS_PORT 53
// -- HTML page fragments
const char IOTWEBCONF_HTML_HEAD[] PROGMEM = "<!DOCTYPE html><html lang=\"en\"><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\"/><title>{v}</title>";
const char IOTWEBCONF_HTML_STYLE_INNER[] PROGMEM = ".de{background-color:#ffaaaa;} .em{font-size:0.8em;color:#bb0000;padding-bottom:0px;} .c{text-align: center;} div,input{padding:5px;font-size:1em;} input{width:95%;} body{text-align: center;font-family:verdana;} button{border:0;border-radius:0.3rem;background-color:#16A1E7;color:#fff;line-height:2.4rem;font-size:1.2rem;width:100%;} fieldset{border-radius:0.3rem;margin: 0px;}";
const char IOTWEBCONF_HTML_SCRIPT_INNER[] PROGMEM = "function c(l){document.getElementById('s').value=l.innerText||l.textContent;document.getElementById('p').focus();}";
const char IOTWEBCONF_HTML_HEAD_END[] PROGMEM = "</head><body>";
const char IOTWEBCONF_HTML_BODY_INNER[] PROGMEM = "<div style='text-align:left;display:inline-block;min-width:260px;'>";
const char IOTWEBCONF_HTML_FORM_START[] PROGMEM = "<form action='' method='post'><fieldset><input type='hidden' name='iotSave' value='true'>";
const char IOTWEBCONF_HTML_FORM_PARAM[] PROGMEM = "<div class='{s}'><label for='{i}'>{b}</label><input type='{t}' id='{i}' name='{i}' maxlength={l} placeholder='{p}' value='{v}' {c}/><div class='em'>{e}</div></div>";
const char IOTWEBCONF_HTML_FORM_END[] PROGMEM = "</fieldset><button type='submit'>Apply</button></form>";
const char IOTWEBCONF_HTML_SAVED[] PROGMEM = "<div>Condiguration saved<br />Return to <a href='/'>home page</a>.</div>";
const char IOTWEBCONF_HTML_END[] PROGMEM = "</div></body></html>";
const char IOTWEBCONF_HTML_UPDATE[] PROGMEM = "<div style='padding-top:25px;'><a href='{u}'>Firmware update</a></div>";
const char IOTWEBCONF_HTML_CONFIG_VER[] PROGMEM = "<div style='font-size: .6em;'>Firmware config version '{v}'</div>";
// -- State of the Thing
#define IOTWEBCONF_STATE_BOOT 0
#define IOTWEBCONF_STATE_NOT_CONFIGURED 1
#define IOTWEBCONF_STATE_AP_MODE 2
#define IOTWEBCONF_STATE_CONNECTING 3
#define IOTWEBCONF_STATE_ONLINE 4
// -- AP connection state
// -- No connection on AP.
#define IOTWEBCONF_AP_CONNECTION_STATE_NC 0
// -- Has connection on AP.
#define IOTWEBCONF_AP_CONNECTION_STATE_C 1
// -- All previous connection on AP was disconnected.
#define IOTWEBCONF_AP_CONNECTION_STATE_DC 2
// -- Status indicator output logical levels.
#define IOTWEBCONF_STATUS_ON LOW
#define IOTWEBCONF_STATUS_OFF HIGH
// -- User name on login.
#define IOTWEBCONF_ADMIN_USER_NAME "admin"
typedef struct IotWebConfWifiAuthInfo
{
const char* ssid;
const char* password;
} IotWebConfWifiAuthInfo;
/**
* IotWebConfParameters is a configuration item of the config portal.
* The parameter will have its input field on the configuration page,
* and the provided value will be saved to the EEPROM.
*/
class IotWebConfParameter
{
public:
/**
* Create a parameter for the config portal.
*
* @label - Displayable label at the config portal.
* @id - Identifier used for HTTP queries and as configuration key. Must not contain spaces nor other special characters.
* @valueBuffer - Configuration value will be loaded to this buffer from the EEPROM.
* @length - The buffer should have a length provided here.
* @type (optional, default="text") - The type of the html input field.
* The type="password" has a special handling, as the value will be overwritten in the EEPROM
* only if value was provided on the config portal. Because of this logic, "password" type field with
* length more then IOTWEBCONF_WORD_LEN characters are not supported.
* @placeholder (optional) - Text appear in an empty input box.
* @defaultValue (optional) - Value should be pre-filled if none was specified before.
* @customHtml (optional) - The text of this parameter will be added into the HTML INPUT field.
*/
IotWebConfParameter(
const char* label, const char* id, char* valueBuffer, int length,
const char* type = "text", const char* placeholder = NULL,
const char* defaultValue = NULL, const char* customHtml = NULL,
boolean visible = true);
/**
* Same as normal constructor, but config portal does not render a default
* input field for the item, instead uses the customHtml provided. Note the
* @type parameter description above!
*/
IotWebConfParameter(
const char* id, char* valueBuffer, int length, const char* customHtml,
const char* type = "text");
/**
* For internal use only.
*/
IotWebConfParameter();
const char* label;
char* valueBuffer;
const char* type;
const char* placeholder;
const char* defaultValue;
const char* customHtml;
boolean visible;
const char* errorMessage;
// -- For internal use only
IotWebConfParameter* _nextParameter = NULL;
const char* getId() { return this->_id; }
int getLength() { return this->_length; }
private:
const char* _id = 0;
int _length;
};
/**
* A separator for separating field sets.
*/
class IotWebConfSeparator : public IotWebConfParameter
{
public:
IotWebConfSeparator();
/**
* Create a seperator with a label (legend tag)
*/
IotWebConfSeparator(const char* label);
};
/**
* Class for providing HTML format segments.
*/
class IotWebConfHtmlFormatProvider
{
public:
virtual String getHead() { return FPSTR(IOTWEBCONF_HTML_HEAD); }
virtual String getStyle() { return "<style>" + getStyleInner() + "</style>"; }
virtual String getScript() { return "<script>" + getScriptInner() + "</script>"; }
virtual String getHeadExtension() { return ""; }
virtual String getHeadEnd() { return String(FPSTR(IOTWEBCONF_HTML_HEAD_END)) + getBodyInner(); }
virtual String getFormStart() { return FPSTR(IOTWEBCONF_HTML_FORM_START); }
virtual String getFormParam(const char* type) { return FPSTR(IOTWEBCONF_HTML_FORM_PARAM); }
virtual String getFormEnd() { return FPSTR(IOTWEBCONF_HTML_FORM_END); }
virtual String getFormSaved() { return FPSTR(IOTWEBCONF_HTML_SAVED); }
virtual String getEnd() { return FPSTR(IOTWEBCONF_HTML_END); }
virtual String getUpdate() { return FPSTR(IOTWEBCONF_HTML_UPDATE); }
virtual String getConfigVer() { return FPSTR(IOTWEBCONF_HTML_CONFIG_VER); }
protected:
virtual String getStyleInner() { return FPSTR(IOTWEBCONF_HTML_STYLE_INNER); }
virtual String getScriptInner() { return FPSTR(IOTWEBCONF_HTML_SCRIPT_INNER); }
virtual String getBodyInner() { return FPSTR(IOTWEBCONF_HTML_BODY_INNER); }
};
/**
* Main class of the module.
*/
class IotWebConf
{
public:
/**
* Create a new configuration handler.
* @thingName - Initial value for the thing name. Used in many places like AP name, can be changed by the user.
* @dnsServer - A created DNSServer, that can be configured for captive portal.
* @server - A created web server. Will be started upon connection success.
* @initialApPassword - Initial value for AP mode. Can be changed by the user.
* @configVersion - When the software is updated and the configuration is changing, this key should also be changed,
* so that the config portal will force the user to reenter all the configuration values.
*/
#ifndef USE_ESPASYNCWEBSERVER
IotWebConf(
const char* thingName, DNSServer* dnsServer, WebServer* server,
const char* initialApPassword, const char* configVersion = "init");
#else
IotWebConf(
const char* thingName, DNSServer* dnsServer, AsyncWebServer* server,
const char* initialApPassword, const char* configVersion = "init");
#endif
/**
* Provide an Arduino pin here, that has a button connected to it with the other end of the pin is connected to GND.
* The button pin is queried at for input on boot time (init time).
* If the button was pressed, the thing will enter AP mode with the initial password.
* Must be called before init()!
* @configPin - An Arduino pin. Will be configured as INPUT_PULLUP!
*/
void setConfigPin(int configPin);
/**
* Provide an Arduino pin for status indicator (LOW = on). Blink codes:
* - Rapid blinks - The thing is in AP mode with default password.
* - Rapid blinks, but mostly on - AP mode, waiting for configuration changes.
* - Normal blinks - Connecting to WiFi.
* - Mostly off with rare rapid blinks - WiFi is connected performing normal operation.
* User can also apply custom blinks. See blink() method!
* Must be called before init()!
* @statusPin - An Arduino pin. Will be configured as OUTPUT!
*/
void setStatusPin(int statusPin);
/**
* Add an UpdateServer instance to the system. The firmware update link will appear on the config portal.
* The UpdateServer will be added to the WebServer with the path provided here (or with "firmware",
* if none was provided).
* Login user will be IOTWEBCONF_ADMIN_USER_NAME, password is the password provided in the config portal.
* Should be called before init()!
* @updateServer - An uninitialized UpdateServer instance.
* @updatePath - (Optional) The path to set up the UpdateServer with. Will be also used in the config portal.
*/
#ifndef USE_ESPASYNCWEBSERVER
void setupUpdateServer(
HTTPUpdateServer* updateServer, const char* updatePath = "/firmware");
#endif
/**
* Start up the IotWebConf module.
* Loads all configuration from the EEPROM, and initialize the system.
* Will return false, if no configuration (with specified config version) was found in the EEPROM.
*/
boolean init();
/**
* IotWebConf is a non-blocking, state controlled system. Therefor it should be
* regularly triggered from the user code.
* So call this method any time you can.
*/
void doLoop();
/**
* Each WebServer URL handler method should start with calling this method.
* If this method return true, the request was already served by it.
*/
#ifndef USE_ESPASYNCWEBSERVER
boolean handleCaptivePortal();
#else
boolean handleCaptivePortal(AsyncWebServerRequest *request);
#endif
/**
* Config URL web request handler. Call this method to handle config request.
*/
#ifndef USE_ESPASYNCWEBSERVER
void handleConfig()
#else
void handleConfig(AsyncWebServerRequest *request);
#endif
/**
* URL-not-found web request handler. Used for handling captive portal request.
*/
#ifndef USE_ESPASYNCWEBSERVER
void handleNotFound();
#else
void handleNotFound(AsyncWebServerRequest *request);
#endif
/**
* Specify a callback method, that will be called upon WiFi connection success.
* Should be called before init()!
*/
void setWifiConnectionCallback(std::function<void()> func);
/**
* Specify a callback method, that will be called when settings have been changed.
* Should be called before init()!
*/
void setConfigSavedCallback(std::function<void()> func);
/**
* Specify a callback method, that will be called when form validation is required.
* If the method will return false, the configuration will not be saved.
* Should be called before init()!
*/
void setFormValidator(std::function<boolean()> func);
/**
* Specify your custom Access Point connection handler. Please use IotWebConf::connectAp() as
* reference when implementing your custom solution.
*/
void setApConnectionHandler(
std::function<boolean(const char* apName, const char* password)> func)
{
_apConnectionHandler = func;
}
/**
* Specify your custom WiFi connection handler. Please use IotWebConf::connectWifi() as
* reference when implementing your custom solution.
*/
void setWifiConnectionHandler(
std::function<void(const char* ssid, const char* password)> func)
{
_wifiConnectionHandler = func;
}
/**
* With this method you can specify your custom WiFi timeout handler.
* This hander can manage what should happen, when WiFi connection timed out.
* By default the handler implementation returns with NULL, as seen on reference implementation
* IotWebConf::handleConnectWifiFailure(). This means we need to fall back to AP mode.
* If it method returns with a (new) WiFi settings, it is used as a next try.
* Note, that this feature is provided because of a possible future option of providing multiply
* WiFi settings.
*/
void setWifiConnectionFailedHandler( std::function<IotWebConfWifiAuthInfo*()> func )
{
_wifiConnectionFailureHandler = func;
}
/**
* Add a custom parameter, that will be handled by the IotWebConf module.
* The parameter will be saved to/loaded from EEPROM automatically,
* and will appear on the config portal.
* Will return false, if adding was not successful.
* Must be called before init()!
*/
bool addParameter(IotWebConfParameter* parameter);
/**
* Getter for the actually configured thing name.
*/
char* getThingName();
/**
* Use this delay, to prevent blocking IotWebConf.
*/
void delay(unsigned long millis);
/**
* IotWebConf tries to connect to the local network for an amount of time before falling back to AP mode.
* The default amount can be updated with this setter.
* Should be called before init()!
*/
void setWifiConnectionTimeoutMs(unsigned long millis);
/**
* Interrupts internal blinking cycle and applies new values for
* blinking the status LED (if one configured with setStatusPin() prior init()
* ).
* @repeatMs - Defines the the period of one on-off cycle in milliseconds.
* @dutyCyclePercent - LED on/off percent. 100 means always on, 0 means
* always off. When called with repeatMs = 0, then internal blink cycle will
* be continued.
*/
void blink(unsigned long repeatMs, byte dutyCyclePercent);
/**
* Similar to blink, but here we define exact on and off times for more
* precise timings.
* @onMs - Milliseconds for the LED tudned on.
* @offMs - Milliseconds for the LED tudned off.
*/
void fineBlink(unsigned long onMs, unsigned long offMs);
/**
* Stop custom blinking defined by blink() or fineBlink() and continues with
* the internal blink cycle.
*/
void stopCustomBlink();
/**
* Return the current state, that will be a value from the IOTWEBCONF_STATE_* constants.
*/
byte getState() { return this->_state; };
/**
* This method can be used to set the AP timeout directly without modifying the apTimeoutParameter.
* Note, that apTimeoutMs value will be reset to the value of apTimeoutParameter on init and on config save.
*/
void setApTimeoutMs(unsigned long apTimeoutMs)
{
this->_apTimeoutMs = apTimeoutMs;
};
/**
* Returns the actual value of the AP timeout in use.
*/
unsigned long getApTimeoutMs() { return this->_apTimeoutMs; };
/**
* Resets the authentication credentials for WiFi connection to the configured one.
* With the return value of setWifiConnectionFailedHandler() one can provide alternative connection settings,
* that can be reset with resetWifiAuthInfo().
*/
void resetWifiAuthInfo()
{
_wifiAuthInfo = {this->_wifiSsid, this->_wifiPassword};
};
/**
* By default IotWebConf starts up in AP mode. Calling this method before the init will force IotWebConf
* to connect immediatelly to the configured WiFi network.
* Note, this method only takes effect, when WiFi mode is enabled, thus when a valid WiFi connection is
* set up, and AP mode is not forced by ConfigPin (see setConfigPin() for details).
*/
void skipApStartup() { this->_skipApStartup = true; }
/**
* Get internal parameters, for manual handling.
* Normally you don't need to access these parameters directly.
* Note, that changing valueBuffer of these parameters should be followed by configSave()!
*/
IotWebConfParameter* getThingNameParameter()
{
return &this->_thingNameParameter;
};
IotWebConfParameter* getApPasswordParameter()
{
return &this->_apPasswordParameter;
};
IotWebConfParameter* getWifiSsidParameter()
{
return &this->_wifiSsidParameter;
};
IotWebConfParameter* getWifiPasswordParameter()
{
return &this->_wifiPasswordParameter;
};
IotWebConfParameter* getApTimeoutParameter()
{
return &this->_apTimeoutParameter;
};
/**
* If config parameters are modified directly, the new values can be saved by this method.
* Note, that init() must pretend configSave()!
* Also note, that configSave writes to EEPROM, and EEPROM can be written only some thousand times
* in the lifetime of an ESP8266 module.
*/
void configSave();
/**
* With this method you can override the default HTML format provider to
* provide custom HTML segments.
*/
void
setHtmlFormatProvider(IotWebConfHtmlFormatProvider* customHtmlFormatProvider)
{
this->htmlFormatProvider = customHtmlFormatProvider;
}
IotWebConfHtmlFormatProvider* getHtmlFormatProvider()
{
return this->htmlFormatProvider;
}
private:
const char* _initialApPassword = NULL;
const char* _configVersion;
DNSServer* _dnsServer;
#ifndef USE_ESPASYNCWEBSERVER
WebServer* _server;
HTTPUpdateServer* _updateServer = NULL;
#else
AsyncWebServer* _server;
#endif
int _configPin = -1;
int _statusPin = -1;
const char* _updatePath = NULL;
boolean _forceDefaultPassword = false;
boolean _skipApStartup = false;
IotWebConfParameter* _firstParameter = NULL;
IotWebConfParameter _thingNameParameter;
IotWebConfParameter _apPasswordParameter;
IotWebConfParameter _wifiSsidParameter;
IotWebConfParameter _wifiPasswordParameter;
IotWebConfParameter _apTimeoutParameter;
char _thingName[IOTWEBCONF_WORD_LEN];
char _apPassword[IOTWEBCONF_WORD_LEN];
char _wifiSsid[IOTWEBCONF_WORD_LEN];
char _wifiPassword[IOTWEBCONF_WORD_LEN];
char _apTimeoutStr[IOTWEBCONF_WORD_LEN];
unsigned long _apTimeoutMs = IOTWEBCONF_DEFAULT_AP_MODE_TIMEOUT_MS;
unsigned long _wifiConnectionTimeoutMs =
IOTWEBCONF_DEFAULT_WIFI_CONNECTION_TIMEOUT_MS;
byte _state = IOTWEBCONF_STATE_BOOT;
unsigned long _apStartTimeMs = 0;
byte _apConnectionStatus = IOTWEBCONF_AP_CONNECTION_STATE_NC;
std::function<void()> _wifiConnectionCallback = NULL;
std::function<void()> _configSavedCallback = NULL;
std::function<boolean()> _formValidator = NULL;
std::function<void(const char*, const char*)> _apConnectionHandler =
&(IotWebConf::connectAp);
std::function<void(const char*, const char*)> _wifiConnectionHandler =
&(IotWebConf::connectWifi);
std::function<IotWebConfWifiAuthInfo*()> _wifiConnectionFailureHandler =
&(IotWebConf::handleConnectWifiFailure);
unsigned long _internalBlinkOnMs = 500;
unsigned long _internalBlinkOffMs = 500;
unsigned long _blinkOnMs = 500;
unsigned long _blinkOffMs = 500;
byte _blinkState = IOTWEBCONF_STATUS_ON;
unsigned long _lastBlinkTime = 0;
unsigned long _wifiConnectionStart = 0;
IotWebConfWifiAuthInfo _wifiAuthInfo = {_wifiSsid, _wifiPassword};
IotWebConfHtmlFormatProvider htmlFormatProviderInstance;
IotWebConfHtmlFormatProvider* htmlFormatProvider = &htmlFormatProviderInstance;
void configInit();
boolean configLoad();
boolean configTestVersion();
void configSaveConfigVersion();
void readEepromValue(int start, char* valueBuffer, int length);
void writeEepromValue(int start, char* valueBuffer, int length);
#ifndef USE_ESPASYNCWEBSERVER
void readParamValue(const char* paramName, char* target, unsigned int len);
boolean validateForm();
#else
void readParamValue(AsyncWebServerRequest* request, const char* paramName, char* target, unsigned int len);
boolean validateForm(AsyncWebServerRequest* request);
#endif
void changeState(byte newState);
void stateChanged(byte oldState, byte newState);
boolean isWifiModePossible()
{
return this->_forceDefaultPassword || (this->_apPassword[0] == '\0');
}
boolean isIp(String str);
String toStringIp(IPAddress ip);
void doBlink();
void blinkInternal(unsigned long repeatMs, byte dutyCyclePercent);
void checkApTimeout();
void checkConnection();
boolean checkWifiConnection();
void setupAp();
void stopAp();
static boolean connectAp(const char* apName, const char* password);
static void connectWifi(const char* ssid, const char* password);
static IotWebConfWifiAuthInfo* handleConnectWifiFailure();
};
#endif

View File

@ -0,0 +1,120 @@
/**
* IotWebConfCompatibility.cpp -- IotWebConf is an ESP8266/ESP32
* non blocking WiFi/AP web configuration library for Arduino.
* https://github.com/prampec/IotWebConf
*
* Copyright (C) 2018 Balazs Kelemen <prampec+arduino@gmail.com>
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*
* Notes on IotWebConfCompatibility:
* This file contains workarounds, and borrowed codes from other projects,
* to keep IotWebConf code more simple and more general. See details
* in comments for code segments in IotWebConfCompatibility.h .
*
*/
#ifdef ESP32
/**
* NOTE: Lines starting with /// are changed by IotWebConf
*/
#include "IotWebConfCompatibility.h"
static const char serverIndex[] PROGMEM =
R"(<html><body><form method='POST' action='' enctype='multipart/form-data'>
<input type='file' name='update'>
<input type='submit' value='Update'>
</form>
</body></html>)";
static const char successResponse[] PROGMEM =
"<META http-equiv=\"refresh\" content=\"15;URL=/\">Update Success! Rebooting...\n";
HTTPUpdateServer::HTTPUpdateServer(bool serial_debug)
{
_serial_output = serial_debug;
_server = NULL;
_username = emptyString;
_password = emptyString;
_authenticated = false;
}
void HTTPUpdateServer::setup(WebServer *server, const String& path, const String& username, const String& password)
{
_server = server;
_username = username;
_password = password;
// handler for the /update form page
_server->on(path.c_str(), HTTP_GET, [&](){
if(_username != emptyString && _password != emptyString && !_server->authenticate(_username.c_str(), _password.c_str()))
return _server->requestAuthentication();
_server->send_P(200, PSTR("text/html"), serverIndex);
});
// handler for the /update form POST (once file upload finishes)
_server->on(path.c_str(), HTTP_POST, [&](){
if(!_authenticated)
return _server->requestAuthentication();
if (Update.hasError()) {
_server->send(200, F("text/html"), String(F("Update error: ")) + _updaterError);
} else {
_server->client().setNoDelay(true);
_server->send_P(200, PSTR("text/html"), successResponse);
delay(100);
_server->client().stop();
ESP.restart();
}
},[&](){
// handler for the file upload, get's the sketch bytes, and writes
// them through the Update object
HTTPUpload& upload = _server->upload();
if(upload.status == UPLOAD_FILE_START){
_updaterError = String();
if (_serial_output)
Serial.setDebugOutput(true);
_authenticated = (_username == emptyString || _password == emptyString || _server->authenticate(_username.c_str(), _password.c_str()));
if(!_authenticated){
if (_serial_output)
Serial.printf("Unauthenticated Update\n");
return;
}
/// WiFiUDP::stopAll();
if (_serial_output)
Serial.printf("Update: %s\n", upload.filename.c_str());
/// uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
/// if(!Update.begin(maxSketchSpace)){//start with max available size
if(!Update.begin(UPDATE_SIZE_UNKNOWN)){//start with max available size
_setUpdaterError();
}
} else if(_authenticated && upload.status == UPLOAD_FILE_WRITE && !_updaterError.length()){
if (_serial_output) Serial.printf(".");
if(Update.write(upload.buf, upload.currentSize) != upload.currentSize){
_setUpdaterError();
}
} else if(_authenticated && upload.status == UPLOAD_FILE_END && !_updaterError.length()){
if(Update.end(true)){ //true to set the size to the current progress
if (_serial_output) Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize);
} else {
_setUpdaterError();
}
if (_serial_output) Serial.setDebugOutput(false);
} else if(_authenticated && upload.status == UPLOAD_FILE_ABORTED){
Update.end();
if (_serial_output) Serial.println("Update was aborted");
}
delay(0);
});
}
void HTTPUpdateServer::_setUpdaterError()
{
if (_serial_output) Update.printError(Serial);
StreamString str;
Update.printError(str);
_updaterError = str.c_str();
}
#endif

View File

@ -0,0 +1,94 @@
/**
* IotWebConfCompatibility.h -- IotWebConf is an ESP8266/ESP32
* non blocking WiFi/AP web configuration library for Arduino.
* https://github.com/prampec/IotWebConf
*
* Copyright (C) 2018 Balazs Kelemen <prampec+arduino@gmail.com>
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*
* Notes on IotWebConfCompatibility:
* This file contains workarounds, and borrowed codes from other projects,
* to keep IotWebConf code more simple and more general. See details
* in comments for code segments bellow this file.
*
*/
/**
* ESP8266 still uses these special naming for their classes, while
* ESP32 uses a more general one. So for the time being, we are
* creating local aliases for those.
*/
#ifdef ESP8266
# define WebServer ESP8266WebServer
# define HTTPUpdateServer ESP8266HTTPUpdateServer
#endif
/**
* ESP32 doesn't implement a HTTPUpdateServer. However it seams, that to code
* from ESP8266 covers nearly all the same functionality.
* So we need to implement our own HTTPUpdateServer for ESP32, and code is
* reused from
* https://github.com/esp8266/Arduino/blob/master/libraries/ESP8266HTTPUpdateServer/src/
* version: 41de43a26381d7c9d29ce879dd5d7c027528371b
*/
#ifdef ESP32
#ifndef __HTTP_UPDATE_SERVER_H
#define __HTTP_UPDATE_SERVER_H
#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
#include <StreamString.h>
#include <Update.h>
#define emptyString F("")
class WebServer;
class HTTPUpdateServer
{
public:
HTTPUpdateServer(bool serial_debug=false);
void setup(WebServer *server)
{
setup(server, emptyString, emptyString);
}
void setup(WebServer *server, const String& path)
{
setup(server, path, emptyString, emptyString);
}
void setup(WebServer *server, const String& username, const String& password)
{
setup(server, "/update", username, password);
}
void setup(WebServer *server, const String& path, const String& username, const String& password);
void updateCredentials(const String& username, const String& password)
{
_username = username;
_password = password;
}
protected:
void _setUpdaterError();
private:
bool _serial_output;
WebServer *_server;
String _username;
String _password;
bool _authenticated;
String _updaterError;
};
#endif
#endif

View File

@ -16,8 +16,11 @@ upload_port = COM11
board_build.partitions = no_ota.csv board_build.partitions = no_ota.csv
lib_deps = lib_deps =
IotWebConf ESPAsyncTCP
ESP Async WebServer
ArduinoJson ArduinoJson
BH1750 BH1750
Adafruit Unified Sensor Adafruit Unified Sensor
DHT sensor library DHT sensor library
build_flags = -D USE_ESPASYNCWEBSERVER

View File

@ -4,6 +4,7 @@
#include <DHT.h> #include <DHT.h>
#include <DHT_U.h> #include <DHT_U.h>
#include <IotWebConf.h> #include <IotWebConf.h>
#include <ESPAsyncWebServer.h>
#define I2C_SDA 25 #define I2C_SDA 25
#define I2C_SCL 26 #define I2C_SCL 26
@ -22,16 +23,13 @@ const char thingName[] = "hiGrow";
const char wifiInitialApPassword[] = "test1234"; const char wifiInitialApPassword[] = "test1234";
DNSServer dnsServer; DNSServer dnsServer;
WebServer server(80); AsyncWebServer server(80);
IotWebConf iotWebConf(thingName, &dnsServer, &server, wifiInitialApPassword); IotWebConf iotWebConf(thingName, &dnsServer, &server, wifiInitialApPassword);
BH1750 lightMeter(0x23); //0x23 BH1750 lightMeter;
DHT_Unified dht(DHT12_PIN, DHT11); DHT_Unified dht(DHT12_PIN, DHT11);
void wifiConnected(); void wifiConnected();
void handleRoot();
void handleValues();
uint16_t soil = 0; uint16_t soil = 0;
uint32_t salt = 0; uint32_t salt = 0;
@ -43,10 +41,9 @@ float lux = 0;
/** /**
* Handle web requests to "/" path. * Handle web requests to "/" path.
*/ */
void handleRoot() void handleRoot(AsyncWebServerRequest *request){
{
// -- Let IotWebConf test and handle captive portal requests. // -- Let IotWebConf test and handle captive portal requests.
if (iotWebConf.handleCaptivePortal()) { if (iotWebConf.handleCaptivePortal(request)) {
// -- Captive portal request were already served. // -- Captive portal request were already served.
return; return;
} }
@ -55,10 +52,10 @@ void handleRoot()
s += F("Go to <a href='config'>configure page</a> to change settings."); s += F("Go to <a href='config'>configure page</a> to change settings.");
s += F("</body></html>\n"); s += F("</body></html>\n");
server.send(200, "text/html", s); request->send(200, "text/html", s);
} }
void handleValues() void handleValues(AsyncWebServerRequest *request)
{ {
StaticJsonDocument<200> doc; StaticJsonDocument<200> doc;
doc[F("temperature")] = temperature; doc[F("temperature")] = temperature;
@ -71,7 +68,7 @@ void handleValues()
String output; String output;
serializeJson(doc, output); serializeJson(doc, output);
server.send(200, "application/json", output); request->send(200, "application/json", output);
} }
void wifiConnected() void wifiConnected()
@ -121,10 +118,13 @@ void setup()
iotWebConf.setWifiConnectionCallback(&wifiConnected); iotWebConf.setWifiConnectionCallback(&wifiConnected);
iotWebConf.init(); iotWebConf.init();
server.on("/", handleRoot); iotWebConf.doLoop();
server.on("/config", [] { iotWebConf.handleConfig(); });
server.on("/values", handleValues); server.on("/", HTTP_GET, handleRoot);
server.onNotFound([]() { iotWebConf.handleNotFound(); }); server.on("/config", HTTP_GET, [](AsyncWebServerRequest *request) { iotWebConf.handleConfig(request); });
server.on("/values", HTTP_GET, handleValues);
server.onNotFound([](AsyncWebServerRequest *request) { iotWebConf.handleNotFound(request); });
server.begin();
Wire.begin(I2C_SDA, I2C_SCL); Wire.begin(I2C_SDA, I2C_SCL);
dht.begin(); dht.begin();