Commit 8c4fc341 authored by Eric Duminil's avatar Eric Duminil
Browse files

IotWebConf in src, not in platformio

parent 9d0a0e38
set(COMPONENT_SRCS
src/IotWebConf.cpp
src/IotWebConfMultipleWifi.cpp
src/IotWebConfOptionalGroup.cpp
src/IotWebConfParameter.cpp
src/IotWebConfESP32HTTPUpdateServer.cpp
)
set(COMPONENT_ADD_INCLUDEDIRS
src/
)
list(APPEND COMPONENT_REQUIRES "arduino")
register_component()
#ADD_DEFINITIONS(-DESP32)
list(APPEND DEFINITIONS "ESP32")
{
"folders": [
{
"path": "."
},
{
"path": "../IotWebConf-examples/IotWebConf01Minimal"
},
{
"path": "../IotWebConf-examples/IotWebConf02StatusAndReset"
},
{
"path": "../IotWebConf-examples/IotWebConf03CustomParameters"
},
{
"path": "../IotWebConf-examples/IotWebConf03TypedParameters"
},
{
"path": "../IotWebConf-examples/IotWebConf04UpdateServer"
},
{
"path": "../IotWebConf-examples/IotWebConf05Callbacks"
},
{
"path": "../IotWebConf-examples/IotWebConf06MqttApp"
},
{
"path": "../IotWebConf-examples/IotWebConf07MqttRelay"
},
{
"path": "../IotWebConf-examples/IotWebConf08WebRelay"
},
{
"path": "../IotWebConf-examples/IotWebConf09CustomConnection"
},
{
"path": "../IotWebConf-examples/IotWebConf10CustomHtml"
},
{
"path": "../IotWebConf-examples/IotWebConf11AdvancedRuntime"
},
{
"path": "../IotWebConf-examples/IotWebConf12CustomParameterType"
},
{
"path": "../IotWebConf-examples/IotWebConf13OptionalGroup"
},
{
"path": "../IotWebConf-examples/IotWebConf14GroupChain"
},
{
"path": "../IotWebConf-examples/IotWebConf15MultipleWifi"
},
{
"path": "../IotWebConf-examples/IotWebConf16OffLineMode"
},
{
"path": "../IotWebConf-examples/IotWebConf17JsonConfig"
}
],
"settings": {
"workbench.tree.indent": 16
}
}
<?xml version="1.0" encoding="UTF-8"?>
<module version="4">
<component name="CheckStyle-IDEA-Module">
<option name="configuration">
<map />
</option>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="sonarModuleSettings">
<option name="alternativeWorkingDirPath" value="" />
<option name="localAnalysisScripName" value="&lt;PROJECT&gt;" />
<option name="serverName" value="&lt;PROJECT&gt;" />
<option name="useAlternativeWorkingDir" value="false" />
<option name="workingDirSelection" value="&lt;MODULE&gt;" />
</component>
</module>
\ No newline at end of file
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.
# IotWebConf [![Build Status](https://github.com/prampec/IotWebConf/workflows/PlatformIO%20CI/badge.svg?branch=master)](https://github.com/prampec/IotWebConf/actions/workflows/test.platformio.yml)
## Upgrading to v3.0.0
Lately version 3.0.0 is released. This release is not backward compatible with
older versions, and some modification have to be done on existing codes.
**Please visit [Migration Guide](doc/MigrationGuide-v3.0.0.md) for
details!**
## 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.
Also visit experimental [Discord server](https://discord.gg/GR3uQeD).
**HELP WANTED!** If you are testing any GIT branches, please give me feedback to provide stable releases for the public.
## Highlights
- Manages WiFi connection settings,
- Provides a config portal user interface,
- You can extend the configuration with your own sophisticated propery structure, that is stored automatically,
- Option to configure multiple WiFi connections. (Try next when the
last used one is just not available.)
- 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.
Visit [Users Manual](doc/UsersManual.md) for detailed description!
## 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.
## User notes
- In the config portal you can double-tap on a password to reveal what
you have typed in. (Double-tap again to hide revealed text.)
- When accessing the config portal via connected WiFi network a dialog
with user-name and password will pop up. The password is the one you
have configured for "AP password". The user name is "admin".
- Consult [Users Manual](doc/UsersManual.md) for more details!
## 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 allow you to configure **mutiple WiFi** connections. In IotWebConf there is a way to define more connections: if one is not available, the next is tried automatically.
- ~~WiFiManager does not manage 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.
- ~~WiFiManager does not support ESP32.~~
- ~~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 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 (WPA/WPA2), so all your communication here is known to be safe. (The exact wifi encryption depends on the used board/chipset and implementation in the related esp/arduino framework.)
- 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.** It communicates over unencrypted HTTP. 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 provide an HTTPUpdateServer implementation. So in this project we have implemented one. Whenever ESP32 provides an official HTTPUpdateServer, this local implementation will be removed.
## Customizing and extending functionality
IotWebConf is ment to be developer friendly by providing lots
of customization options. See [HackingGuide](doc/HackingGuide.md) for
details.
## TODO / Feature requests
- We might want to add a "verify password" field.
- Provide an option, where IotWebConf renders HTML-response,
handles HTTP-request for a specific branch of groups.
- Separate WiFi management from the code, so config portal can also
be a standalone solution without any WiFi.
## 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](https://github.com/prampec/IotWebConf/graphs/contributors) providing patches for the library!
# IotWebConf hacking guide
IotWebConf comes with a lot of examples. These examples are intended
to be easy to use, with clear goals. While IotWebConf is also ment to be
developer friendly, providing lots of customization options.
This documentation will try to explain features where you can customize
IotWebConf on your need, or where a feature explanation might be out of the
scope of regular examples.
Please note, that header files are full of
documentation, so please heavily consult ```IotWebConf.h``` header file
while/beside reading this documentation.
__Contents__:
- [PlatformIO](#using-iotwebconf-with-platformio)
- [Compile time configuration](#compile-time-configuration)
- [Groups and Parameters](#groups-and-parameters)
- [Optional and chained groups](#optional-and-chained-groups)
- [Using System parameter-group](#using-system-parameter-group)
- [Alternative WiFi connection](#alternative-wifi-connection)
- [Accessing system properties](#accessing-system-properties)
- [Use custom style](#use-custom-style)
- [Create your property class](#create-your-property-class)
- [Typed parameters](#typed-parameters-experimental)
- [Control on WiFi connection status change](#control-on-wifi-connection-status-change)
- [Use alternative WebServer](#use-alternative-webserver)
## Using IotWebConf with PlatformIO
It is recommended to use PlatformIO instead of the Arduino environment.
With v3.0.0, a folder ```pio``` is provided with scripts that transforms
examples to PlatformIO compatible format. You can use these as templates
for your project. (On the other hand, these scripts creating soft-link
loops, and having soft link loops in these folders might cause Arduino
and other environment to fail. Just keep in mind, if something goes
wrong with your IDE, then examples-pio is likely the corporate.)
## Compile time configuration
IotWebConf includes a configuration file named IotWebConfSettings.h.
This configuration file works on C pre-compiler mechanism. This means
you cannot use it in Arduino environment, so I encourage everyone to
switch to PlatformIO.
In the PlatformIO you can do configuration changes by adding lines to
platformio.ini like this:
```
build_flags =
-DIOTWEBCONF_DEFAULT_WIFI_CONNECTION_TIMEOUT_MS="60000"
-DIOTWEBCONF_DEBUG_DISABLED
```
**Note:** You must not use ```#define IOTWEBCONF_CONFIG_START 20```, or
similar defines in your .ino file (e.g. before the includes). It will eventually
just not work, as all .cpp files are compiled separately for each other.
Thus, you must use the ```-D``` compiler flag for the job.
## Groups and Parameters
With version 3.0.0 IotWebConf introduces individual parameter classes for
each type, and you can organize your parameters into groups.
You can also free to add groups into groups to make a tree hierarchy.
## Optional and chained groups
With ```OptionalParameterGroup```, the group you have defined will have
a special appearance in the config portal, as the fieldset in which the
group items are shown can be hidden (inactive) / shown (active).
E.g you want to create a group with property items, that are not mandatory,
so you can hide these options in the config portal by default, and
only reveal the contents, when it is strictly requested.
There is a specific example covering this very feature under
```IotWebConf13OptionalGroup```.
```ChainedParameterGroup```s can be linked. One after another. The
property sets will reveal on after another, when user requests is. The
difference between ```OptionalParameterGroup``` and ```ChainedParameterGroup```
is that second group item in a chained list can only be added, when
the first item is already visible.
There is a specific example covering this very feature under
```IotWebConf14GroupChain```.
## Using system parameter-group
By default, you should add your own parameter group, that will appear as
a new field-set on the Config Portal. However, there is a special group
maintained by IotWebConf called the System group, where you are also
allowed to add your own custom properties.
Example:
```
iotWebConf.addSystemParameter(&stringParam);
```
You can directly access system-parameter group by calling
```getSystemParameterGroup()```.
Example:
```
ParameterGroup* systemParameters = iotWebConf.getSystemParameterGroup();
systemParameters.label = "My Custom Label";
```
There is another group "WiFi parameters" managed by IotWebConf, that
can be retrieved by getWifiParameterGroup().
## Alternative WiFi connection
With v3.0.0 you can set up multiple WiFi connection by utilizing the
MultipleWifiAddition class can be found in IotWebConfMultipleWifi.h .
This class basically set up some handlers in iotWebConf to
1. display optional WiFi settings in admin GUI,
2. use these alternative settings in case previous WiFi connection
attempts fails.
The maximal number of connection settings are determined compile-time,
as we want to avoid any dynamic memory allocations in Arduino.
There is a complete example covering this topic, please visit example
```IotWebConf15MultipleWifi```!
## Accessing system properties
IotWebConf comes with some parameters, that are required for the basic
functionality. You can retrieve these parameter by getters, e.g.
```getThingNameParameter()```. You can directly modify these items as
seen in the code block below.
There is a dedicated example covering this topic, so please visit
example ```IotWebConf11AdvancedRuntime```!
```
// -- Update Thing name
strncpy(
iotWebConf.getThingNameParameter()->valueBuffer,
"My changed name",
iotWebConf.getThingNameParameter()->getLength());
iotWebConf.saveConfig();
```
Here is list of some of the system parameter-acccessors, please consult
IotWebConf.h for further details.
- getSystemParameterGroup()
- getThingNameParameter()
- getApPasswordParameter()
- getWifiParameterGroup()
- getWifiSsidParameter()
- getWifiPasswordParameter()
- getApTimeoutParameter()
## Use custom style
You can provide your own custom HTML template by updating default
HTML format provider. For this you should utilize the
```setHtmlFormatProvider()``` method.
There is a complete example about this topic, so please visit example
```IotWebConf10CustomHtml```!
## Create your property class
With version 3.0.0 you are free to create your own property class.
It is done by inheriting the iotwebconf::Parameter C++ class. You can use
other property types e.g. PasswordProperty as a template for this.
Now, custom properties are mainly handy, when you would like to create
some special HTML form item. But eventually you can change the whole
behaviour of your parameter handling. E.g. by overriding ```storeValue()```
and ```loadValue()``` you can basically convert your internal data format
to whatever you like. The [Typed parameters](#typed-parameters-experimental)
approach is just an excellent example for this option.
You can also override ParameterGroup class in case you need some special
group appearance.
There is a complete example about this topic, so please visit example
```IotWebConf12CustomParameterType```!
## Typed parameters (experimental)
A new parameter structure is introduced, where the parameters does not
require a "valueBuffer" anymore. Storing the parameter is done in a
native format, e.g. a 8-bit integers are stored in one byte of EEPROM.
This was achieved by utilizing the ```template``` technology of C++.
While the result is spectacular, the ```template``` makes thing very
complicated under the hood.
Builder pattern is also introduced for the typed parameters. See example
```IotWebConf03TypedParameters``` for details. Please compare example
IotWebConf03TypedParameters and IotWebConf03TypedParameters for the
difference in the usage of the two different approach.
**Please note, that Typed Parameters are very experimental, and the
interface might be a subject of change in the future.**
![UML diagram of the Typed Parameters approach.](TParameter.png)
(This image was created by PlantUML, the source file is generate with command
```hpp2plantuml -i src/IotWebConfTParameter.h -o doc/TParameter.plantuml```)
## Control on WiFi connection status change
IotWebConf provides a feature to control WiFi connection events by defining
your custom handler event handler.
With ```setWifiConnectionFailedHandler()``` you can set up a handler, that
will be called, when a connection to a WiFi network failed (most likely
timed out). Now, when you return with a new valid connection-info from
your callback, IotWebConf will not fall back to AP mode, but try the
connection you have just provided. With this method you can theoretically
set up multiple WiFi networks for IotWebConf to try connect to after
one-by-one if the previous one fails. Some days IotWebConf might also
provide this feature out of the box.
There is a second method, where you can define a specific handler, this
is the ```setWifiConnectionHandler()```. Your method will be called when
IotWebConf trying to establish connection to a WiFi network.
For details please consult ```IotWebConf.h``` header file!
## Use alternative WebServer
There was an expressed need from your side for supporting specific types of
Web servers. (E.g https
web server or async web server.) So, with v3.0.0 there is an option to
use web server of your choice. To achieve this, you will call IotWebConf
constructor, that accepts a ```WebServerWrapper``` pointer.
In the WebServerWrapper you have the implement all expected web server
functionalities (as seen in the header file). You can use
the ```StandardWebServerWrapper``` as a template for that.
Further more, you also need to provide your custom ```WebRequestWrapper```
instances when calling ```handleCaptivePortal()```, ```handleConfig()``` and
```handleNotFound()```.
Unfortunately I currently do not have the time to implement solutions
for Async Web Server os Secure Web Server. If you can do that with the
instruction above, please provide me the pull request!
# Migration guide to v3.0.0
In v3.0.0 some changes were introduced, that are not backward
compatible with v2.x.x versions.
This guide contains all modifications that should be done in existing
codes, to reflect the changes.
For better understanding some code examples are also shown here, but
I would recommend comparing git changes in the examples.
## Changes introduced in v3.0.0
- [Namespaces](#namespaces)
- [Parameter classes](#parameter-classes)
- [Parameter grouping](#grouping-parameters)
- [Default value handling](#default-value-handling)
- [Hidden parameters](#hidden-parameters)
- [UpdateServer changes](#updateserver-changes)
- [configSave](#configsave)
- [formValidator](#formvalidator)
## Namespaces
With v3.0.0, IotWebConf library started to use namespaces. Namespace
is a C++ technique, where to goal is to avoid name collision over
different libraries.
The namespace for IotWebConf become ```iotwebconf::```. From now on
you should use this prefix for each type defined by the library
except for the IotWebConf class itself.
There are more ways to update your code. Let's see some variations!
### Migration steps: easy way
For easy migration IotWebConf has provided a header file prepared
with predefined aliases to hide namespaces, so you can still use
the legacy types.
Include helper header file as follows.
Code before:
```C++
#include <IotWebConf.h>
```
Code after:
```C++
#include <IotWebConf.h>
#include <IotWebConfUsing.h>
```
### Migration steps: proper way
Use namespace prefixes before every type name.
Code before:
```C++
IotWebConfParameter mqttServerParam =
IotWebConfParameter("MQTT server", "mqttServer", mqttServerValue, STRING_LEN);
```
Code after:
```C++
iotwebconf::Parameter mqttServerParam =
iotwebconf::Parameter("MQTT server", "mqttServer", mqttServerValue, STRING_LEN);
```
### Migration steps: optimist way
Define namespaces at the beginning of the code and use simple type name.
Everywhere later on. This works only until name-collision with other
library occur.
Code after:
```C++
using namespace iotwebconf;
...
Parameter mqttServerParam =
Parameter("MQTT server", "mqttServer", mqttServerValue, STRING_LEN);
```
## Parameter classes
Previously there was just the ```IotWebConfParameter``` and the
actual type was provided as an argument of this one-and-only type.
Now it turned out, that it is a better idea to use specific classes
for each individual types. So from now on you must specify the type
of the parameter by creating that very type e.g. using
```IotWebConfTextParameter```.
For compatibility reasons the signature is the same before, except
the type string should not be provided anymore.
New parameter types are also introduced (e.g.
```IotWebConfSelectParameter```),
and it is very likely that with newer versions, more and more types will
arrive.
Creating your custom parameter is now become much more easy as well.
### Migrations steps
Replace IotWebConfParameter types with specific parameter type.
Code before:
```C++
IotWebConfParameter mqttServerParam =
IotWebConfParameter("MQTT server", "mqttServer", mqttServerValue , STRING_LEN);
IotWebConfParameter mqttUserPasswordParam =
IotWebConfParameter("MQTT password", "mqttPass", mqttUserPasswordValue , STRING_LEN, "password");
```
Code after:
```C++
IotWebConfTextParameter mqttServerParam =
IotWebConfTextParameter("MQTT server", "mqttServer", mqttServerValue , STRING_LEN);
IotWebConfPasswordParameter mqttUserPasswordParam =
IotWebConfPasswordParameter("MQTT password", "mqttPass ", mqttUserPasswordValue, STRING_LEN);
```
Note, that ```IotWebConfTextParameter``` and
```IotWebConfPasswordParameter``` words are just aliases and eventually you
should use ```iotwebconf::TextParameter```,
```iotwebconf::PasswordParameter```, etc.
_Note, that with version 3.0.0 a new typed parameter approach is introduced,
you might want to immediately migrate to this parameter types, but
typed-parameters are still in testing phase and might be a subject of
change._
## Grouping parameters
With v3.0.0 "separator" disappears. Separators were used to create
field sets in the rendered HTML. Now you must directly define connected
items by adding them to specific parameter groups.
(It is also possible to add a group within a group.)
You need to add prepared groups to IotWebConf instead of individual
parameters. (However there is a specific group created by IotWebConf for
storing system parameters, you can also add your
properties into the system group.)
Code before:
```C++
IotWebConfSeparator separator1 =
IotWebConfSeparator();
IotWebConfParameter intParam =