Supports AutoConnectAux

pull/41/head
Hieromon Ikasamo 6 years ago
parent 4de6dfb101
commit dbbb220ffa
  1. 10
      README.md
  2. 8
      keywords.txt
  3. 20
      src/AutoConnect.cpp
  4. 6
      src/AutoConnect.h
  5. 54
      src/AutoConnectAux.cpp
  6. 48
      src/AutoConnectAux.h
  7. 6
      src/AutoConnectPage.cpp

@ -32,6 +32,10 @@ AutoConnect can be embedded easily into your sketch, just "**begin**" and "**han
The sketches which provide the web page using ESP8266WebServer/WebServer there is, AutoConnect will not disturb it. AutoConnect can use an already instantiated ESP8266WebServer object(ESP8266) or WebServer object(ESP32), or itself can assign it.
### Adding the user-owned web screen can easily
You can easily add your own web screen with sketch. It can be called from the AutoConnect menu and parameters can be passed.
## Supported hardware
Apply the [Arduino core](https://github.com/esp8266/Arduino) of the ESP8266 Community.
@ -81,7 +85,11 @@ Full documentation is available on https://Hieromon.github.io/AutoConnect, some
## Change log
### [0.9.6] Sep. 27, 2018
### [0.9.7] Nov. 11, 2018
- Supports addition of AutoConnect menu with user sketch by AutoConnectAux implementation.
- Supports AutoConnectConfig::immediateStart option, to start the portal immediately without first trying WiFi.begin.
### [0.9.6] Sept. 27, 2018
- Improvement of RSSI detection for saved SSIDs.
- Fixed disconnection SoftAP completely at the first connection phase of the AutoConnect::begin.

@ -9,10 +9,15 @@ AutoConnectText KEYWORD1
AutoConnectInput KEYWORD1
AutoConnectButon KEYWORD1
AutoConnectSubmit KEYWORD1
ACText KEYWORD1
ACInput KEYWORD1
ACButton KEYWORD1
ACSubmit KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
add KEYWORD2
config KEYWORD2
begin KEYWORD2
del KEYWORD2
@ -24,9 +29,12 @@ home KEYWORD2
host KEYWORD2
join KEYWORD2
load KEYWORD2
name KEYWORD2
on KEYWORD2
onDetect KEYWORD2
onNotFound KEYWORD2
save KEYWORD2
value KEYWORD2
#######################################
# Literals (KEYWORD3)

@ -111,6 +111,15 @@ bool AutoConnect::begin(const char* ssid, const char* passphrase, unsigned long
AC_DBG("DHCP client(%s)\n", wifi_station_dhcpc_status() == DHCP_STOPPED ? "STOPPED" : "STARTED");
#endif
// If the portal is requested promptly skip the first WiFi.begin and
// immediately start the portal.
if (_apConfig.immediateStart) {
cs = false;
_apConfig.autoReconnect = false;
_apConfig.autoRise = true;
AC_DBG("Start the portal immediately\n");
}
else {
// Try to connect by STA immediately.
if (ssid == nullptr && passphrase == nullptr)
WiFi.begin();
@ -118,6 +127,7 @@ bool AutoConnect::begin(const char* ssid, const char* passphrase, unsigned long
WiFi.begin(ssid, passphrase);
AC_DBG("WiFi.begin(%s%s%s)\n", ssid == nullptr ? "" : ssid, passphrase == nullptr ? "" : ",", passphrase == nullptr ? "" : passphrase);
cs = _waitForConnect(_portalTimeout) == WL_CONNECTED;
}
// Reconnect with a valid credential as the autoReconnect option is enabled.
if (!cs && _apConfig.autoReconnect && (ssid == nullptr && passphrase == nullptr)) {
@ -264,14 +274,12 @@ WebServerClass& AutoConnect::host() {
* the auxiliary page to be added.
*/
void AutoConnect::join(AutoConnectAux& aux) {
if (_aux) {
AutoConnectAux* addon = _aux.get();
addon->_append(aux);
}
aux._join(*this);
AC_DBG("%s on hands\n", aux.uri());
if (_aux)
_aux->_concat(aux);
else
_aux.reset(&aux);
aux._join(*this);
AC_DBG("%s contained\n", aux._uri);
}
/**

@ -132,6 +132,7 @@ class AutoConnectConfig {
autoRise(true),
autoReset(true),
autoReconnect(false),
immediateStart(false),
homeUri(AUTOCONNECT_HOMEURI),
staip(0U),
staGateway(0U),
@ -155,6 +156,7 @@ class AutoConnectConfig {
autoRise(true),
autoReset(true),
autoReconnect(false),
immediateStart(false),
homeUri(AUTOCONNECT_HOMEURI),
staip(0U),
staGateway(0U),
@ -178,6 +180,7 @@ class AutoConnectConfig {
autoRise = o.autoRise;
autoReset = o.autoReset;
autoReconnect = o.autoReconnect;
immediateStart = o.immediateStart;
homeUri = o.homeUri;
staip = o.staip;
staGateway = o.staGateway;
@ -200,6 +203,7 @@ class AutoConnectConfig {
bool autoRise; /**< Automatic starting the captive portal */
bool autoReset; /**< Reset ESP8266 module automatically when WLAN disconnected. */
bool autoReconnect; /**< Automatic reconnect with past SSID */
bool immediateStart; /**< Skips WiFi.begin(), start portal immediately */
String homeUri; /**< A URI of user site */
IPAddress staip; /**< Station static IP address */
IPAddress staGateway; /**< Station gateway address */
@ -208,8 +212,6 @@ class AutoConnectConfig {
IPAddress dns2; /**< Secondary DNS server */
};
class AutoConnectAux;
class AutoConnect {
public:
AutoConnect();

@ -10,7 +10,20 @@
#include "AutoConnect.h"
#include "AutoConnectAux.h"
/**
* Template for auxiliary page composed with AutoConnectAux of user sketch.
*
* The structure of the auxiliary page depends on this template for
* the purpose to be incorporated into the AutoConnect Menu.
* The page element implemented by AutoConnectElement is placed at the
* position of {{AUX_ELEMENT}} token. This token is contained in a
* <div> block with a class defined in 'base-panel' and is held by a
* <form> element with an ID '_aux'.
* The JavaScript that named 'sa' at the end of the template determines
* the behavior of AutoConnectSubmit.
*/
const char AutoConnectAux::_PAGE_AUX[] PROGMEM = {
"{{EXIT_HANDLE}}"
"{{HEAD}}"
"<title>{{AUX_TITLE}}</title>"
"<style type=\"text/css\">"
@ -57,7 +70,7 @@ AutoConnectAux::~AutoConnectAux() {
void AutoConnectAux::add(AutoConnectElement& addon) {
_addonElm.push_back(addon);
AC_DBG("ELM:%s placed\n", addon.name().c_str());
AC_DBG("%s placed in %s\n", addon.name().c_str(), uri());
}
void AutoConnectAux::add(AutoConnectElementVT addons) {
@ -65,21 +78,17 @@ void AutoConnectAux::add(AutoConnectElementVT addons) {
add(addons[n]);
}
void AutoConnectAux::_append(AutoConnectAux& aux) {
if (_next) {
AutoConnectAux* next = _next.get();
next->_append(aux);
}
void AutoConnectAux::_concat(AutoConnectAux& aux) {
if (_next)
_next->_concat(aux);
else
_next.reset(&aux);
}
void AutoConnectAux::_join(AutoConnect& ac) {
_ac.reset(&ac);
if (_next) {
AutoConnectAux *next = _next.get();
next->_join(ac);
}
if (_next)
_next->_join(ac);
}
const String AutoConnectAux::_insertElement(PageArgument& args) {
@ -105,10 +114,16 @@ PageElement* AutoConnectAux::_setupPage(String uri) {
elm = new PageElement();
// Overwrite the default menu title
if (_title.length()) {
mother->_menuTitle = _title;
_activeTitle = String();
}
else
_activeTitle = mother->_menuTitle;
// Construct the auxiliary page
elm->setMold(_PAGE_AUX);
elm->addToken(PSTR("EXIT_HANDLE"), std::bind(&AutoConnectAux::_exitHandle, this, std::placeholders::_1));
elm->addToken(PSTR("HEAD"), std::bind(&AutoConnect::_token_HEAD, mother, std::placeholders::_1));
elm->addToken(PSTR("AUX_TITLE"), std::bind(&AutoConnectAux::_injectTitle, this, std::placeholders::_1));
elm->addToken(PSTR("CSS_BASE"), std::bind(&AutoConnect::_token_CSS_BASE, mother, std::placeholders::_1));
@ -126,10 +141,19 @@ PageElement* AutoConnectAux::_setupPage(String uri) {
}
const String AutoConnectAux::_injectMenu(PageArgument& args) {
String menuItem = String(FPSTR("<li class=\"luxbar-item\"><a href=\"")) + String(_uri) + String("\">") + _title + String(FPSTR("</a></li>"));
if (_next) {
AutoConnectAux* next = _next.get();
menuItem += next->_injectMenu(args);
}
String menuItem;
if (_title.length())
menuItem = String(FPSTR("<li class=\"luxbar-item\"><a href=\"")) + String(_uri) + String("\">") + _title + String(FPSTR("</a></li>"));
if (_next)
menuItem += _next->_injectMenu(args);
return menuItem;
}
const String AutoConnectAux::_exitHandle(PageArgument& args) {
if (_handler) {
AC_DBG("CB %s\n", *this->uri());
(*_handler)(*this, args);
}
return "";
}

@ -20,11 +20,13 @@ class AutoConnect; // Reference to avoid circular
// Add-on element base class
class AutoConnectElement {
public:
explicit AutoConnectElement(const char* name = nullptr, const char* value = nullptr) : _name(String(name)), _value(String(value)) {}
explicit AutoConnectElement(const char* name, const char* value) : _name(String(name)), _value(String(value)) {}
virtual ~AutoConnectElement() {}
const String name(void) const { return _name; } /**< Element name */
const String value(void) const { return _value; } /**< Element value */
virtual const String toHTML(void) { return String(); }; /**< HTML code to be generated */
void setValue(const char* value) { _value = String(value); }
void setValue(const String value) { _value = value; }
protected:
String _name;
@ -42,9 +44,11 @@ class AutoConnectElement {
*/
class AutoConnectText : public AutoConnectElement {
public:
explicit AutoConnectText(const char* name = nullptr, const char* value = nullptr, const char* style = nullptr) : AutoConnectElement(name, value), _style(String(style)) {}
explicit AutoConnectText(const char* name = "", const char* value = "", const char* style = "") : AutoConnectElement(name, value), _style(String(style)) {}
~AutoConnectText() {}
const String style(void) const { return _style; } /**< A modify of HTML 'style' code */
void setStyle(const char* style) { _style = String(style); }
void setStyle(const String style) { _style = style; }
const String toHTML(void) {
return String(FPSTR("<div style=\"")) + _style + String("\">") + _value + String(FPSTR("</div>"));
}
@ -63,9 +67,11 @@ class AutoConnectText : public AutoConnectElement {
*/
class AutoConnectInput : public AutoConnectElement {
public:
explicit AutoConnectInput(const char* name = nullptr, const char* value = nullptr, const char* label = nullptr) : AutoConnectElement(name, value), _label(String(label)) {}
explicit AutoConnectInput(const char* name = "", const char* value = "", const char* label = "") : AutoConnectElement(name, value), _label(String(label)) {}
~AutoConnectInput() {}
const String label(void) const { return _label; }
void setLabel(const char* label) { _label = String(label); }
void setLabel(const String label) { _label = label; }
const String toHTML(void) {
return _label + String(FPSTR("<input type=\"text\" name=\"")) + _name + String(FPSTR("\" value=\"")) + _value + String("\"><br>");
}
@ -83,8 +89,10 @@ class AutoConnectInput : public AutoConnectElement {
*/
class AutoConnectButton : public AutoConnectElement {
public:
explicit AutoConnectButton(const char* name = nullptr, const char* value = nullptr, const String action = String()) : AutoConnectElement(name, value), _action(action) {}
explicit AutoConnectButton(const char* name = "", const char* value = "", const String action = String()) : AutoConnectElement(name, value), _action(action) {}
const String action(void) const { return _action; }
void setAction(const char* action) { _action = String(action); }
void setAction(const String action) { _action = action; }
const String toHTML(void) {
return String(FPSTR("<button type=\"button\" name=\"")) + _name + String(FPSTR("\" value=\"")) + _value + String(FPSTR("\" onclick=\"")) + _action + String("\">") + _value + String(FPSTR("</button>"));
}
@ -104,8 +112,10 @@ class AutoConnectButton : public AutoConnectElement {
*/
class AutoConnectSubmit : public AutoConnectElement {
public:
explicit AutoConnectSubmit(const char* name = nullptr, const char* value = nullptr, const char* uri = nullptr) : AutoConnectElement(name, value), _uri(String(uri)) {}
explicit AutoConnectSubmit(const char* name = "", const char* value = "", const char* uri = "") : AutoConnectElement(name, value), _uri(String(uri)) {}
const String uri(void) const { return _uri; }
void setUri(const char* uri) { _uri = String(uri); }
void setUri(const String uri) { _uri = uri; }
const String toHTML(void) {
return String(FPSTR("<button type=\"submit\" name=\"")) + _name + String(FPSTR("\" value=\"")) + _value + String(FPSTR("\" onclick=\"sa('")) + _uri + String("')\">") + _value + String(FPSTR("</button>"));
}
@ -114,9 +124,25 @@ class AutoConnectSubmit : public AutoConnectElement {
String _uri;
};
/**
* Support declare the AutoConnectElement variable with reducing the
* arguments. These macros declare the AutoConnectElement variable
* with the same name as a "name" argument.
*/
#define ACText(name, ...) AutoConnectText name(#name, ## __VA_ARGS__)
#define ACInput(name, ...) AutoConnectInput name(#name, ## __VA_ARGS__)
#define ACButton(name, ...) AutoConnectButton name(#name, ## __VA_ARGS__)
#define ACSubmit(name, ...) AutoConnectSubmit name(#name, ## __VA_ARGS__)
// Manage placed AutoConnectElement with a vector
typedef std::vector<std::reference_wrapper<AutoConnectElement>> AutoConnectElementVT;
// To solve the forward reference.
class AutoConnectAux;
// A type of callback function when AutoConnectAux page requested.
typedef std::function<void(AutoConnectAux&, PageArgument&)> AuxHandleFuncT;
/**
* A class that handles an auxiliary page with AutoConnectElement
* that placed on it by binding it to the AutoConnect menu.
@ -126,26 +152,30 @@ typedef std::vector<std::reference_wrapper<AutoConnectElement>> AutoConnectEleme
*/
class AutoConnectAux : public PageBuilder {
public:
explicit AutoConnectAux(const char* uri = nullptr, const char* title = nullptr, const AutoConnectElementVT addons = AutoConnectElementVT()) :
_title(String(title)), _addonElm(addons) { setUri(uri); _next.release(); _ac.release(); }
explicit AutoConnectAux(const char* uri = nullptr, const char* title = "", const AutoConnectElementVT addons = AutoConnectElementVT()) :
_title(String(title)), _addonElm(addons) { setUri(uri); _next.release(); _ac.release(); _handler = nullptr; }
~AutoConnectAux();
void add(AutoConnectElement& addon); /**< Add an element to the auxiliary page. */
void add(AutoConnectElementVT addons); /**< Add the element set to the auxiliary page. */
void setTitle(const char* title) { _title = String(title); } /**< Set a title of the auxiliary page. */
void on(const AuxHandleFuncT handler) { _handler = &handler; } /**< Set user handler */
protected:
void _append(AutoConnectAux& aux);
void _concat(AutoConnectAux& aux);
void _join(AutoConnect& ac);
PageElement* _setupPage(String uri);
const String _insertElement(PageArgument& args);
const String _injectTitle(PageArgument& args) { return _title; }
const String _injectTitle(PageArgument& args) { return _title.length() > 0 ? _title : _activeTitle; }
const String _injectMenu(PageArgument& args);
const String _exitHandle(PageArgument& args);
String _title; /**< A title of the page */
String _activeTitle; /**< Previous title of the page */
AutoConnectElementVT _addonElm; /**< A vector set of AutoConnectElements placed on this auxiliary page */
std::unique_ptr<AutoConnectAux> _next; /**< Auxiliary pages chain list */
std::unique_ptr<AutoConnect> _ac; /**< Hosted AutoConnect instance */
const AuxHandleFuncT* _handler; /**< User sketch callback function when AutoConnectAux page requested. */
static const char _PAGE_AUX[] PROGMEM; /**< Auxiliary page template */

@ -805,10 +805,8 @@ String AutoConnect::_token_MENU_PRE(PageArgument& args) {
String AutoConnect::_token_MENU_AUX(PageArgument& args) {
String menuItem;
if (_aux) {
AutoConnectAux* aux = _aux.get();
menuItem = aux->_injectMenu(args);
}
if (_aux)
menuItem = _aux->_injectMenu(args);
return menuItem;
}

Loading…
Cancel
Save