Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Auto enable ap #67

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ Debug/
__vm/
.vs/
*.sln
.vscode/
184 changes: 104 additions & 80 deletions src/FSWebServerLib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,17 @@ void AsyncFSWebServer::s_secondTick(void* arg) {
if (self->_evs.count() > 0) {
self->sendTimeData();
}

//Check connection timeout if enabled
//TODO: as soon as ESP8266Wifi allows setting a timeout on waitForConnectResult use this instead of our own timeout mechanism
#if (AP_ENABLE_TIMEOUT > 0)
if (self->wifiStatus == FS_STAT_CONNECTING) {
if (++self->connectionTimout >= AP_ENABLE_TIMEOUT){
DBG_OUTPUT_PORT.printf("Connection Timeout, switching to AP Mode.\r\n");
self->configureWifiAP();
}
}
#endif //AP_ENABLE_TIMEOUT
}

void AsyncFSWebServer::sendTimeData() {
Expand Down Expand Up @@ -87,6 +98,9 @@ void flashLED(int pin, int times, int delayTime) {

void AsyncFSWebServer::begin(FS* fs) {
_fs = fs;

connectionTimout = 0;

DBG_OUTPUT_PORT.begin(115200);
DBG_OUTPUT_PORT.print("\n\n");
#ifndef RELEASE
Expand Down Expand Up @@ -204,38 +218,37 @@ bool AsyncFSWebServer::load_config() {
configFile.readBytes(buf.get(), size);
configFile.close();
DEBUGLOG("191 JSON file size: %d bytes\r\n", size);
DynamicJsonBuffer jsonBuffer(1024);
//StaticJsonBuffer<1024> jsonBuffer;
JsonObject& json = jsonBuffer.parseObject(buf.get());

if (!json.success()) {
DEBUGLOG("Failed to parse config file\r\n");
DynamicJsonDocument jsonDoc(1024);
auto error = deserializeJson(jsonDoc, buf.get());
if (error) {
DEBUGLOG("Failed to parse config file. Error: %s\r\n", error.c_str());
return false;
}

#ifndef RELEASE
String temp;
json.prettyPrintTo(temp);
serializeJsonPretty(jsonDoc, temp);
Serial.println(temp);
#endif

_config.ssid = json["ssid"].as<const char *>();
_config.ssid = jsonDoc["ssid"].as<const char *>();

_config.password = json["pass"].as<const char *>();
_config.password = jsonDoc["pass"].as<const char *>();

_config.ip = IPAddress(json["ip"][0], json["ip"][1], json["ip"][2], json["ip"][3]);
_config.netmask = IPAddress(json["netmask"][0], json["netmask"][1], json["netmask"][2], json["netmask"][3]);
_config.gateway = IPAddress(json["gateway"][0], json["gateway"][1], json["gateway"][2], json["gateway"][3]);
_config.dns = IPAddress(json["dns"][0], json["dns"][1], json["dns"][2], json["dns"][3]);
_config.ip = IPAddress(jsonDoc["ip"][0], jsonDoc["ip"][1], jsonDoc["ip"][2], jsonDoc["ip"][3]);
_config.netmask = IPAddress(jsonDoc["netmask"][0], jsonDoc["netmask"][1], jsonDoc["netmask"][2], jsonDoc["netmask"][3]);
_config.gateway = IPAddress(jsonDoc["gateway"][0], jsonDoc["gateway"][1], jsonDoc["gateway"][2], jsonDoc["gateway"][3]);
_config.dns = IPAddress(jsonDoc["dns"][0], jsonDoc["dns"][1], jsonDoc["dns"][2], jsonDoc["dns"][3]);

_config.dhcp = json["dhcp"].as<bool>();
_config.dhcp = jsonDoc["dhcp"].as<bool>();

_config.ntpServerName = json["ntp"].as<const char *>();
_config.updateNTPTimeEvery = json["NTPperiod"].as<long>();
_config.timezone = json["timeZone"].as<long>();
_config.daylight = json["daylight"].as<long>();
_config.deviceName = json["deviceName"].as<const char *>();
_config.ntpServerName = jsonDoc["ntp"].as<const char *>();
_config.updateNTPTimeEvery = jsonDoc["NTPperiod"].as<long>();
_config.timezone = jsonDoc["timeZone"].as<long>();
_config.daylight = jsonDoc["daylight"].as<long>();
_config.deviceName = jsonDoc["deviceName"].as<const char *>();

//config.connectionLed = json["led"];
//config.connectionLed = jsonDoc["led"];

DEBUGLOG("Data initialized.\r\n");
DEBUGLOG("SSID: %s ", _config.ssid.c_str());
Expand Down Expand Up @@ -271,44 +284,43 @@ void AsyncFSWebServer::defaultConfig() {
bool AsyncFSWebServer::save_config() {
//flag_config = false;
DEBUGLOG("Save config\r\n");
DynamicJsonBuffer jsonBuffer(512);
//StaticJsonBuffer<1024> jsonBuffer;
JsonObject& json = jsonBuffer.createObject();
json["ssid"] = _config.ssid;
json["pass"] = _config.password;
DynamicJsonDocument jsonDoc(512);

jsonDoc["ssid"] = _config.ssid;
jsonDoc["pass"] = _config.password;

JsonArray& jsonip = json.createNestedArray("ip");
JsonArray jsonip = jsonDoc.createNestedArray("ip");
jsonip.add(_config.ip[0]);
jsonip.add(_config.ip[1]);
jsonip.add(_config.ip[2]);
jsonip.add(_config.ip[3]);

JsonArray& jsonNM = json.createNestedArray("netmask");
JsonArray jsonNM = jsonDoc.createNestedArray("netmask");
jsonNM.add(_config.netmask[0]);
jsonNM.add(_config.netmask[1]);
jsonNM.add(_config.netmask[2]);
jsonNM.add(_config.netmask[3]);

JsonArray& jsonGateway = json.createNestedArray("gateway");
JsonArray jsonGateway = jsonDoc.createNestedArray("gateway");
jsonGateway.add(_config.gateway[0]);
jsonGateway.add(_config.gateway[1]);
jsonGateway.add(_config.gateway[2]);
jsonGateway.add(_config.gateway[3]);

JsonArray& jsondns = json.createNestedArray("dns");
JsonArray jsondns = jsonDoc.createNestedArray("dns");
jsondns.add(_config.dns[0]);
jsondns.add(_config.dns[1]);
jsondns.add(_config.dns[2]);
jsondns.add(_config.dns[3]);

json["dhcp"] = _config.dhcp;
json["ntp"] = _config.ntpServerName;
json["NTPperiod"] = _config.updateNTPTimeEvery;
json["timeZone"] = _config.timezone;
json["daylight"] = _config.daylight;
json["deviceName"] = _config.deviceName;
jsonDoc["dhcp"] = _config.dhcp;
jsonDoc["ntp"] = _config.ntpServerName;
jsonDoc["NTPperiod"] = _config.updateNTPTimeEvery;
jsonDoc["timeZone"] = _config.timezone;
jsonDoc["daylight"] = _config.daylight;
jsonDoc["deviceName"] = _config.deviceName;

//json["led"] = config.connectionLed;
//jsonDoc["led"] = config.connectionLed;

//TODO add AP data to html
File configFile = _fs->open(CONFIG_FILE, "w");
Expand All @@ -320,11 +332,10 @@ bool AsyncFSWebServer::save_config() {

#ifndef RELEASE
String temp;
json.prettyPrintTo(temp);
serializeJsonPretty(jsonDoc, temp);
Serial.println(temp);
#endif

json.printTo(configFile);
serializeJson(jsonDoc, configFile);
configFile.flush();
configFile.close();
return true;
Expand Down Expand Up @@ -353,21 +364,20 @@ bool AsyncFSWebServer::load_user_config(String name, String &value) {
configFile.readBytes(buf.get(), size);
configFile.close();
DEBUGLOG("340 JSON file size: %d bytes\r\n", size);
DynamicJsonBuffer jsonBuffer(1024);
//StaticJsonBuffer<1024> jsonBuffer;
JsonObject& json = jsonBuffer.parseObject(buf.get());

if (!json.success()) {
DEBUGLOG("Failed to parse config file\r\n");
DynamicJsonDocument jsonDoc(1024);
auto error = deserializeJson(jsonDoc, buf.get());
if (error) {
DEBUGLOG("Failed to parse config file. Error: %s\r\n", error.c_str());
return false;
}

#ifndef RELEASE
String temp;
json.prettyPrintTo(temp);
serializeJsonPretty(jsonDoc, temp);
Serial.println(temp);
#endif

value = json[name].asString();
value = jsonDoc[name].as<char*>();

DEBUGLOG("Data initialized.\r\n");
DEBUGLOG("SSID: %s ", _config.ssid.c_str());
Expand Down Expand Up @@ -422,20 +432,19 @@ bool AsyncFSWebServer::save_user_config(String name, String value) {
configFile.readBytes(buf.get(), size);
configFile.close();
DEBUGLOG("Read JSON file size: %d bytes\r\n", size);
DynamicJsonBuffer jsonBuffer(1024);
//StaticJsonBuffer<1024> jsonBuffer;
JsonObject& json = jsonBuffer.parseObject(buf.get());
DynamicJsonDocument jsonDoc(1024);
auto error = deserializeJson(jsonDoc, buf.get());

if (!json.success()) {
DEBUGLOG("Failed to parse config file\r\n");
if (error) {
DEBUGLOG("Failed to parse config file. Error: %s\r\n", error.c_str());
return false;
}
else
{
DEBUGLOG("Parse User config file\r\n");
}

json[name] = value;
jsonDoc[name] = value;

configFile = _fs->open(USER_CONFIG_FILE, "w");
if (!configFile) {
Expand All @@ -447,11 +456,10 @@ bool AsyncFSWebServer::save_user_config(String name, String value) {
#ifndef RELEASE
DEBUGLOG("Save user config \r\n");
String temp;
json.prettyPrintTo(temp);
serializeJsonPretty(jsonDoc, temp);
Serial.println(temp);
#endif

json.printTo(configFile);
serializeJson(jsonDoc, configFile);
configFile.flush();
configFile.close();
return true;
Expand Down Expand Up @@ -518,29 +526,29 @@ bool AsyncFSWebServer::loadHTTPAuth() {
configFile.readBytes(buf.get(), size);
configFile.close();
DEBUGLOG("JSON secret file size: %d bytes\n", size);
DynamicJsonBuffer jsonBuffer(256);
//StaticJsonBuffer<256> jsonBuffer;
JsonObject& json = jsonBuffer.parseObject(buf.get());

if (!json.success()) {
DynamicJsonDocument jsonDoc(256);
auto error = deserializeJson(jsonDoc, buf.get());

if (error) {
#ifndef RELEASE
String temp;
json.prettyPrintTo(temp);
serializeJsonPretty(jsonDoc, temp);
DBG_OUTPUT_PORT.println(temp);
DBG_OUTPUT_PORT.println("Failed to parse secret file");
DBG_OUTPUT_PORT.println("Failed to parse secret file. Error: ");
DBG_OUTPUT_PORT.println(error.c_str());
#endif // RELEASE
_httpAuth.auth = false;
return false;
}
#ifndef RELEASE
String temp;
json.prettyPrintTo(temp);
serializeJsonPretty(jsonDoc, temp);
DBG_OUTPUT_PORT.println(temp);
#endif // RELEASE

_httpAuth.auth = json["auth"];
_httpAuth.wwwUsername = json["user"].as<String>();
_httpAuth.wwwPassword = json["pass"].as<String>();
_httpAuth.auth = jsonDoc["auth"];
_httpAuth.wwwUsername = jsonDoc["user"].as<String>();
_httpAuth.wwwPassword = jsonDoc["pass"].as<String>();

DEBUGLOG(_httpAuth.auth ? "Secret initialized.\r\n" : "Auth disabled.\r\n");
if (_httpAuth.auth) {
Expand All @@ -566,8 +574,16 @@ void AsyncFSWebServer::handle() {
void AsyncFSWebServer::configureWifiAP() {
DEBUGLOG(__PRETTY_FUNCTION__);
DEBUGLOG("\r\n");
//WiFi.disconnect();

if (WiFi.status() == WL_CONNECTED) {
WiFi.disconnect();
}

WiFi.mode(WIFI_AP);

wifiStatus = FS_STAT_APMODE;
connectionTimout = 0;

String APname = _apConfig.APssid + (String)ESP.getChipId();
if (_httpAuth.auth) {
WiFi.softAP(APname.c_str(), _httpAuth.wwwPassword.c_str());
Expand All @@ -580,6 +596,8 @@ void AsyncFSWebServer::configureWifiAP() {
if (CONNECTION_LED >= 0) {
flashLED(CONNECTION_LED, 3, 250);
}

DBG_OUTPUT_PORT.printf("AP Mode enabled. SSID: %s IP: %s\r\n", WiFi.softAPSSID().c_str(), WiFi.softAPIP().toString().c_str());
}

void AsyncFSWebServer::configureWifi() {
Expand All @@ -599,10 +617,15 @@ void AsyncFSWebServer::configureWifi() {
DEBUGLOG("NO DHCP\r\n");
WiFi.config(_config.ip, _config.gateway, _config.netmask, _config.dns);
}

connectionTimout = 0;
wifiStatus = FS_STAT_CONNECTING;

//Only usw wait waitForConnectResult if the timeout is not enabled to not mess with the timeout
//TODO: as soon as ESP8266Wifi allows setting a timeout on waitForConnectResult use this instead of our own timeout mechanism
#if (AP_ENABLE_TIMEOUT <= 0)
WiFi.waitForConnectResult();


#endif //AP_ENABLE_TIMEOUT
}

void AsyncFSWebServer::ConfigureOTA(String password) {
Expand Down Expand Up @@ -666,6 +689,9 @@ void AsyncFSWebServer::onWiFiConnectedGotIP(WiFiEventStationModeGotIP data) {
if (_config.updateNTPTimeEvery > 0) { // Enable NTP sync
updateTimeFromNTP = true;
}

connectionTimout = 0;
wifiStatus = FS_STAT_CONNECTED;
}


Expand Down Expand Up @@ -1176,12 +1202,11 @@ void AsyncFSWebServer::send_wwwauth_configuration_html(AsyncWebServerRequest *re
bool AsyncFSWebServer::saveHTTPAuth() {
//flag_config = false;
DEBUGLOG("Save secret\r\n");
DynamicJsonBuffer jsonBuffer(256);
//StaticJsonBuffer<256> jsonBuffer;
JsonObject& json = jsonBuffer.createObject();
json["auth"] = _httpAuth.auth;
json["user"] = _httpAuth.wwwUsername;
json["pass"] = _httpAuth.wwwPassword;
DynamicJsonDocument jsonDoc(256);

jsonDoc["auth"] = _httpAuth.auth;
jsonDoc["user"] = _httpAuth.wwwUsername;
jsonDoc["pass"] = _httpAuth.wwwPassword;

//TODO add AP data to html
File configFile = _fs->open(SECRET_FILE, "w");
Expand All @@ -1193,11 +1218,10 @@ bool AsyncFSWebServer::saveHTTPAuth() {

#ifndef RELEASE
String temp;
json.prettyPrintTo(temp);
serializeJsonPretty(jsonDoc, temp);
Serial.println(temp);
#endif // RELEASE

json.printTo(configFile);
serializeJson(jsonDoc, configFile);
configFile.flush();
configFile.close();
return true;
Expand Down
10 changes: 10 additions & 0 deletions src/FSWebServerLib.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
#define CONNECTION_LED -1 // Connection LED pin (Built in). -1 to disable
#define AP_ENABLE_BUTTON 5 // Button pin to enable AP during startup for configuration. -1 to disable

#define AP_ENABLE_TIMEOUT 90 // (Seconds, max 255) If the device can not connect to WiFi it will switch to AP mode after this time. -1 to disable

// #define HIDE_CONFIG
#define CONFIG_FILE "/config.json"
#define USER_CONFIG_FILE "/userconfig.json"
Expand Down Expand Up @@ -71,6 +73,12 @@ typedef struct {
String wwwPassword;
} strHTTPAuth;

typedef enum {
FS_STAT_CONNECTING,
FS_STAT_CONNECTED,
FS_STAT_APMODE
} enWifiStatus;

class AsyncFSWebServer : public AsyncWebServer {
public:
AsyncFSWebServer(uint16_t port);
Expand Down Expand Up @@ -112,6 +120,8 @@ class AsyncFSWebServer : public AsyncWebServer {
WiFiEventHandler onStationModeConnectedHandler, onStationModeDisconnectedHandler, onStationModeGotIPHandler;

//uint currentWifiStatus;
enWifiStatus wifiStatus;
uint8_t connectionTimout;

Ticker _secondTk;
bool _secondFlag;
Expand Down