Commit 56f99df8 authored by Eric Duminil's avatar Eric Duminil
Browse files

Web server refactor

parent 077b4e74
......@@ -20,5 +20,11 @@ namespace web_config {
void setWifiConnectionCallback(void (*function)());
void setWifiConnectionFailedCallback(void (*function)());
void update();
#if defined(ESP8266)
extern ESP8266WebServer http;
#elif defined(ESP32)
extern WebServer http;
#endif
}
#endif
......@@ -8,6 +8,7 @@
# include <ESPmDNS.h>
#endif
#include "web_config.h"
#include "config.h"
#include "util.h"
#include "ntp.h"
......@@ -56,135 +57,7 @@ namespace web_server {
void handleWebServerCSV();
#endif
#if defined(ESP8266)
ESP8266WebServer http(80); // Create a webserver object that listens for HTTP request on port 80
#elif defined(ESP32)
WebServer http(80);
#endif
DNSServer dnsServer;
IotWebConf *iotWebConf;
#define STRING_LEN 64
// -- Configuration specific key. The value should be modified if config structure was changed.
const char config_version[] = "ampel_test_v3";
static const char chooserValues[][STRING_LEN] = { "red", "blue", "darkYellow" };
static const char chooserNames[][STRING_LEN] = { "Red", "Blue", "Dark yellow" };
iotwebconf::TextTParameter<STRING_LEN> stringParam = iotwebconf::Builder<iotwebconf::TextTParameter< STRING_LEN>>(
"stringParam").label("String param").build();
iotwebconf::ParameterGroup group1 = iotwebconf::ParameterGroup("group1", "");
iotwebconf::IntTParameter<int16_t> intParam =
iotwebconf::Builder<iotwebconf::IntTParameter<int16_t>>("intParam").label("Int param").defaultValue(30).min(1).max(
100).step(1).placeholder("1..100").build();
// -- We can add a legend to the separator
iotwebconf::ParameterGroup group2 = iotwebconf::ParameterGroup("c_factor", "Calibration factor");
iotwebconf::FloatTParameter floatParam = iotwebconf::Builder<iotwebconf::FloatTParameter>("floatParam").label(
"Float param").defaultValue(0.0).step(0.1).placeholder("e.g. 23.4").build();
iotwebconf::CheckboxTParameter checkboxParam =
iotwebconf::Builder<iotwebconf::CheckboxTParameter>("checkParam").label("Check param").defaultValue(true).build();
iotwebconf::SelectTParameter<STRING_LEN> chooserParam =
iotwebconf::Builder<iotwebconf::SelectTParameter< STRING_LEN>>("chooseParam").label("Choose param").optionValues(
(const char*) chooserValues).optionNames((const char*) chooserNames).optionCount(
sizeof(chooserValues) / STRING_LEN).nameLength(STRING_LEN).build();
void update() {
iotWebConf->doLoop(); // Listen for HTTP requests from clients
}
void initialize() {
iotWebConf = new IotWebConf(ampel.sensorId, &dnsServer, &http, HTTP_PASSWORD, config_version);
const int ONBOARD_LED_PIN = 2;
# ifdef ESP8266
iotWebConf->setStatusPin(ONBOARD_LED_PIN, LOW);
# else
iotWebConf->setStatusPin(ONBOARD_LED_PIN, HIGH);
# endif
iotWebConf->setWifiConnectionTimeoutMs(1000UL * WIFI_TIMEOUT);
#if defined(ESP8266)
WiFi.hostname(ampel.sensorId);
#elif defined(ESP32)
WiFi.setHostname(ampel.sensorId);
#endif
group1.addItem(&intParam);
group2.addItem(&floatParam);
group2.addItem(&checkboxParam);
group2.addItem(&chooserParam);
iotWebConf->addSystemParameter(&stringParam);
iotWebConf->addParameterGroup(&group1);
iotWebConf->addParameterGroup(&group2);
iotWebConf->setWifiConnectionCallback([]() {
led_effects::showKITTWheel(color::green);
Serial.println();
Serial.print(F("WiFi - Connected! IP address: "));
IPAddress address = WiFi.localIP();
snprintf(wifi::local_ip, sizeof(wifi::local_ip), "%d.%d.%d.%d", address[0], address[1], address[2], address[3]);
ntp::initialize();
//FIXME: Somehow already started
// if (MDNS.begin(ampel.sensorId)) { // Start the mDNS responder for SENSOR_ID.local
// MDNS.addService("http", "tcp", 80);
// Serial.println(F("mDNS responder started"));
// } else {
// Serial.println(F("Error setting up MDNS responder!"));
// }
# ifdef AMPEL_MQTT
mqtt::initialize(ampel.sensorId);
# endif
Serial.println(wifi::local_ip);
Serial.print(F("You can access this sensor via http://"));
Serial.print(ampel.sensorId);
Serial.print(F(".local (might be unstable) or http://"));
Serial.println(WiFi.localIP());
});
iotWebConf->setWifiConnectionFailedHandler([]() -> iotwebconf::WifiAuthInfo* {
led_effects::showKITTWheel(color::red);
Serial.println(F("Connection to WiFi failed"));
return NULL;
});
iotWebConf->skipApStartup();
//TODO: Add callbacks
//TODO: Add LED effects
//TODO: Allow offline config loading
//TODO: Add default values for SSID/password
//TODO: Add other params
//TODO: Use HTTP_USER / HTTP_PASSWORD for config
//TODO: Move to own class
//TODO: Remove AP Password config?
//TODO: Save LoRaWAN key if possible?
//FIXME: Why does MQTT fail? (on ESP32)
// iotWebConf->loadConfig();
Serial.println("<<<<<<<<<<<<<<<");
Serial.println(stringParam.value());
Serial.println(intParam.value());
Serial.println(floatParam.value());
iotWebConf->init();
Serial.println(stringParam.value());
Serial.println(intParam.value());
Serial.println(floatParam.value());
Serial.println(">>>>>>>>>>>>>>>");
sensor_console::defineCommand("reset_config", []() {
Serial.println(F("Resetting config..."));
iotWebConf->getSystemParameterGroup()->applyDefaultValue();
iotWebConf->saveConfig();
Serial.println(F("Done!"));
}, F("(resets the complete IotWeb config)"));
void definePages() {
header_template =
PSTR("<!doctype html><html lang=en>"
"<head>\n"
......@@ -323,36 +196,27 @@ namespace web_server {
"</html>");
// Web-server
http.on("/", handleWebServerRoot);
http.on("/command", handleWebServerCommand);
web_config::http.on("/", handleWebServerRoot);
web_config::http.on("/command", handleWebServerCommand);
#ifdef AMPEL_CSV
http.on(csv_writer::filename, handleWebServerCSV); //NOTE: csv_writer should have been initialized first.
http.on("/delete_csv", HTTP_POST, handleDeleteCSV);
web_config::http.on(csv_writer::filename, handleWebServerCSV); //NOTE: csv_writer should have been initialized first.
web_config::http.on("/delete_csv", HTTP_POST, handleDeleteCSV);
#endif
http.on("/config", [] {
iotWebConf->handleConfig();
});
http.onNotFound([]() {
iotWebConf->handleNotFound();
});
//TODO: Only once wifi connected
}
// Allow access if http_user or http_password are empty, or if provided credentials match
bool shouldBeAllowed() {
return strcmp(config::http_user, "") == 0 || strcmp(config::http_password, "") == 0
|| http.authenticate(config::http_user, config::http_password);
|| web_config::http.authenticate(config::http_user, config::http_password);
}
void handleWebServerRoot() {
if (iotWebConf->handleCaptivePortal()) {
// -- Captive portal requests were already served.
return;
}
// if (web_config::handleCaptivePortal()) {
// // -- Captive portal requests were already served.
// return;
// }
if (!shouldBeAllowed()) {
return http.requestAuthentication(DIGEST_AUTH);
return web_config::http.requestAuthentication(DIGEST_AUTH);
}
unsigned long ss = seconds();
......@@ -375,8 +239,8 @@ namespace web_server {
// Serial.print(F("INFO - Header size : "));
// Serial.print(strlen(content));
http.setContentLength(CONTENT_LENGTH_UNKNOWN);
http.send_P(200, PSTR("text/html"), content);
web_config::http.setContentLength(CONTENT_LENGTH_UNKNOWN);
web_config::http.send_P(200, PSTR("text/html"), content);
// Body
snprintf_P(content, sizeof(content), body_template, ampel.sensorId, sensor::co2, sensor::temperature,
......@@ -397,7 +261,7 @@ namespace web_server {
// Serial.print(F(" - Body size : "));
// Serial.print(strlen(content));
http.sendContent(content);
web_config::http.sendContent(content);
// Script
snprintf_P(content, sizeof(content), script_template
......@@ -408,48 +272,48 @@ namespace web_server {
// Serial.print(F(" - Script size : "));
// Serial.println(strlen(content));
http.sendContent(content);
web_config::http.sendContent(content);
}
#ifdef AMPEL_CSV
void handleWebServerCSV() {
if (!shouldBeAllowed()) {
return http.requestAuthentication(DIGEST_AUTH);
return web_config::http.requestAuthentication(DIGEST_AUTH);
}
if (FS_LIB.exists(csv_writer::filename)) {
fs::File csv_file = FS_LIB.open(csv_writer::filename, "r");
char csv_size[10];
snprintf(csv_size, sizeof(csv_size), "%d", csv_file.size());
http.sendHeader("Content-Length", csv_size);
http.streamFile(csv_file, F("text/csv"));
web_config::http.sendHeader("Content-Length", csv_size);
web_config::http.streamFile(csv_file, F("text/csv"));
csv_file.close();
} else {
http.send(204, F("text/html"), F("No data available."));
web_config::http.send(204, F("text/html"), F("No data available."));
}
}
void handleDeleteCSV() {
if (!shouldBeAllowed()) {
return http.requestAuthentication(DIGEST_AUTH);
return web_config::http.requestAuthentication(DIGEST_AUTH);
}
Serial.print(F("Removing CSV file..."));
FS_LIB.remove(csv_writer::filename);
Serial.println(F(" Done!"));
http.sendHeader("Location", "/");
http.send(303);
web_config::http.sendHeader("Location", "/");
web_config::http.send(303);
}
#endif
void handleWebServerCommand() {
if (!shouldBeAllowed()) {
return http.requestAuthentication(DIGEST_AUTH);
return web_config::http.requestAuthentication(DIGEST_AUTH);
}
http.sendHeader("Location", "/");
http.send(303);
sensor_console::execute(http.arg("send").c_str());
web_config::http.sendHeader("Location", "/");
web_config::http.send(303);
sensor_console::execute(web_config::http.arg("send").c_str());
}
void handlePageNotFound() {
http.send(404, F("text/plain"), F("404: Not found"));
web_config::http.send(404, F("text/plain"), F("404: Not found"));
}
}
......@@ -2,7 +2,6 @@
#define WEB_SERVER_H_
namespace web_server {
void initialize();
void update();
void definePages();
}
#endif
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment