Commit 208eadd3 authored by Eric Duminil's avatar Eric Duminil
Browse files

Merge branch 'develop'

parents b48d4d18 a9b0db5d
Pipeline #3221 passed with stage
in 1 minute and 40 seconds
...@@ -22,6 +22,7 @@ namespace web_server { ...@@ -22,6 +22,7 @@ namespace web_server {
const char *script_template; const char *script_template;
void handleWebServerRoot(); void handleWebServerRoot();
void handlePageNotFound(); void handlePageNotFound();
void handleWebServerCommand();
#ifdef AMPEL_CSV #ifdef AMPEL_CSV
void handleDeleteCSV(); void handleDeleteCSV();
...@@ -64,7 +65,7 @@ namespace web_server { ...@@ -64,7 +65,7 @@ namespace web_server {
#ifdef AMPEL_CSV #ifdef AMPEL_CSV
"<li class='pure-menu-item'><a href='#graph' class='pure-menu-link'>Graph</a></li>\n" "<li class='pure-menu-item'><a href='#graph' class='pure-menu-link'>Graph</a></li>\n"
"<li class='pure-menu-item'><a href='#log' class='pure-menu-link'>Log</a></li>\n" "<li class='pure-menu-item'><a href='#log' class='pure-menu-link'>Log</a></li>\n"
"<li class='pure-menu-item'><a href='./%s' class='pure-menu-link'>Download CSV</a></li>\n" "<li class='pure-menu-item'><a href='%s' class='pure-menu-link'>Download CSV</a></li>\n"
#endif #endif
"<li class='pure-menu-item' id='led'>&#11044;</li>\n" // LED "<li class='pure-menu-item' id='led'>&#11044;</li>\n" // LED
"</ul></div></div>\n" "</ul></div></div>\n"
...@@ -72,16 +73,15 @@ namespace web_server { ...@@ -72,16 +73,15 @@ namespace web_server {
// Show a colored dot on the webpage, with a similar color than on LED Ring. // Show a colored dot on the webpage, with a similar color than on LED Ring.
"hue=(1-(Math.min(Math.max(parseInt(document.title),500),1600)-500)/1100)*120;\n" "hue=(1-(Math.min(Math.max(parseInt(document.title),500),1600)-500)/1100)*120;\n"
"document.getElementById('led').style.color=['hsl(',hue,',100%%,50%%)'].join('');\n" "document.getElementById('led').style.color=['hsl(',hue,',100%%,50%%)'].join('');\n"
"</script>\n"); "</script>\n"
"<div class='pure-g'>\n"
body_template = "<div class='pure-u-1' id='graph'></div>\n"// Graph placeholder
PSTR("<div class='pure-g'>\n"
"<div class='pure-u-1' id='graph'></div>\n" // Graph placeholder
"</div>\n" "</div>\n"
"<div class='pure-g'>\n" "<div class='pure-g'>\n"
//Sensor table "<table id='table' class='pure-table-striped pure-u-1 pure-u-md-1-2'>\n");
"<table id='table' class='pure-table-striped pure-u-1 pure-u-md-1-2'>\n"
"<tr><th colspan='2'>%s</th></tr>\n" body_template =
PSTR("<tr><th colspan='2'>%s</th></tr>\n"
"<tr><td>CO<sub>2</sub> concentration</td><td>%5d ppm</td></tr>\n" "<tr><td>CO<sub>2</sub> concentration</td><td>%5d ppm</td></tr>\n"
"<tr><td>Temperature</td><td>%.1f&#8451;</td></tr>\n" "<tr><td>Temperature</td><td>%.1f&#8451;</td></tr>\n"
"<tr><td>Humidity</td><td>%.1f%%</td></tr>\n" "<tr><td>Humidity</td><td>%.1f%%</td></tr>\n"
...@@ -108,14 +108,17 @@ namespace web_server { ...@@ -108,14 +108,17 @@ namespace web_server {
#endif #endif
"<tr><th colspan='2'>Sensor</th></tr>\n" "<tr><th colspan='2'>Sensor</th></tr>\n"
"<tr><td>Temperature offset</td><td>%.1fK</td></tr>\n" //TODO: Read it from sensor? "<tr><td>Temperature offset</td><td>%.1fK</td></tr>\n" //TODO: Read it from sensor?
"<tr><td>Auto-calibration?</td><td>%s</td></tr>\n"
"<tr><td>Local address</td><td><a href='http://%s.local/'>%s.local</a></td></tr>\n" "<tr><td>Local address</td><td><a href='http://%s.local/'>%s.local</a></td></tr>\n"
"<tr><td>Local IP</td><td><a href='http://%s'>%s</a></td></tr>\n" "<tr><td>Local IP</td><td><a href='http://%s'>%s</a></td></tr>\n"
"<tr><td>Free heap space</td><td>%6d bytes</td></tr>\n" "<tr><td>Free heap space</td><td>%6d bytes</td></tr>\n"
"<tr><td>Largest heap block</td><td>%6d bytes</td></tr>\n"
"<tr><td>Max loop duration</td><td>%5d ms</td></tr>\n" "<tr><td>Max loop duration</td><td>%5d ms</td></tr>\n"
"<tr><td>Board</td><td>%s</td></tr>\n" "<tr><td>Board</td><td>%s</td></tr>\n"
"<tr><td>Uptime</td><td>%2d d %4d h %02d min %02d s</td></tr>\n" "<tr><td>Uptime</td><td>%2d d %4d h %02d min %02d s</td></tr>\n"
"</table>\n" "</table>\n"
"<div id='log' class='pure-u-1 pure-u-md-1-2'></div>\n" "<div id='log' class='pure-u-1 pure-u-md-1-2'></div>\n"
"<form action='/command'><input type='text' id='send' name='send'><input type='submit' value='Send'></form>\n"
#ifdef AMPEL_CSV #ifdef AMPEL_CSV
"<form action='/delete_csv' method='POST' onsubmit=\"return confirm('Are you really sure you want to delete all data?') && (document.body.style.cursor = 'wait');\">" "<form action='/delete_csv' method='POST' onsubmit=\"return confirm('Are you really sure you want to delete all data?') && (document.body.style.cursor = 'wait');\">"
"<input type='submit' value='Delete CSV'/>" "<input type='submit' value='Delete CSV'/>"
...@@ -130,7 +133,7 @@ namespace web_server { ...@@ -130,7 +133,7 @@ namespace web_server {
#ifdef AMPEL_CSV #ifdef AMPEL_CSV
"<script>\n" "<script>\n"
"document.body.style.cursor = 'default';\n" "document.body.style.cursor = 'default';\n"
"fetch('./%s',{credentials:'include'})\n" "fetch('%s',{credentials:'include'})\n"
".then(response=>response.text())\n" ".then(response=>response.text())\n"
".then(csvText=>csvToTable(csvText))\n" ".then(csvText=>csvToTable(csvText))\n"
".then(htmlTable=>addLogTableToPage(htmlTable))\n" ".then(htmlTable=>addLogTableToPage(htmlTable))\n"
...@@ -173,15 +176,16 @@ namespace web_server { ...@@ -173,15 +176,16 @@ namespace web_server {
// Web-server // Web-server
http.on("/", handleWebServerRoot); http.on("/", handleWebServerRoot);
http.on("/command", handleWebServerCommand);
#ifdef AMPEL_CSV #ifdef AMPEL_CSV
http.on("/" + csv_writer::filename, handleWebServerCSV); http.on(csv_writer::filename, handleWebServerCSV); //NOTE: csv_writer should have been initialized first.
http.on("/delete_csv", HTTP_POST, handleDeleteCSV); http.on("/delete_csv", HTTP_POST, handleDeleteCSV);
#endif #endif
http.onNotFound(handlePageNotFound); http.onNotFound(handlePageNotFound);
http.begin(); http.begin();
Serial.print(F("You can access this sensor via http://")); Serial.print(F("You can access this sensor via http://"));
Serial.print(SENSOR_ID); Serial.print(ampel.sensorId);
Serial.print(F(".local (might be unstable) or http://")); Serial.print(F(".local (might be unstable) or http://"));
Serial.println(WiFi.localIP()); Serial.println(WiFi.localIP());
} }
...@@ -207,44 +211,49 @@ namespace web_server { ...@@ -207,44 +211,49 @@ namespace web_server {
//NOTE: Splitting in multiple parts in order to use less RAM //NOTE: Splitting in multiple parts in order to use less RAM
char content[2000]; // Update if needed char content[2000]; // Update if needed
// Header size : 1611 - Body size : 1800 - Script size : 1920 // INFO - Header size : 1767 - Body size : 1812 - Script size : 1909
// Header snprintf_P(content, sizeof(content), header_template, sensor::co2, ampel.sensorId, wifi::local_ip
snprintf_P(content, sizeof(content), header_template, sensor::co2, SENSOR_ID.c_str(),
WiFi.localIP().toString().c_str()
#ifdef AMPEL_CSV #ifdef AMPEL_CSV
, csv_writer::filename.c_str() , csv_writer::filename
#endif #endif
); );
Serial.print(F("INFO - Header size : "));
Serial.print(strlen(content));
http.setContentLength(CONTENT_LENGTH_UNKNOWN); http.setContentLength(CONTENT_LENGTH_UNKNOWN);
http.send_P(200, PSTR("text/html"), content); http.send_P(200, PSTR("text/html"), content);
// Body // Body
snprintf_P(content, sizeof(content), body_template, SENSOR_ID.c_str(), sensor::co2, sensor::temperature, snprintf_P(content, sizeof(content), body_template, ampel.sensorId, sensor::co2, sensor::temperature,
sensor::humidity, sensor::timestamp.c_str(), config::measurement_timestep, sensor::humidity, sensor::timestamp, config::measurement_timestep,
#ifdef AMPEL_CSV #ifdef AMPEL_CSV
csv_writer::last_successful_write.c_str(), config::csv_interval, csv_writer::getAvailableSpace() / 1024, csv_writer::last_successful_write, config::csv_interval, csv_writer::getAvailableSpace() / 1024,
#endif #endif
#ifdef AMPEL_MQTT #ifdef AMPEL_MQTT
mqtt::connected ? "Yes" : "No", mqtt::last_successful_publish.c_str(), config::sending_interval, mqtt::connected ? "Yes" : "No", mqtt::last_successful_publish, config::mqtt_sending_interval,
#endif #endif
#if defined(AMPEL_LORAWAN) && defined(ESP32) #if defined(AMPEL_LORAWAN) && defined(ESP32)
lorawan::connected ? "Yes" : "No", LMIC_FREQUENCY_PLAN, lorawan::last_transmission.c_str(), lorawan::connected ? "Yes" : "No", LMIC_FREQUENCY_PLAN, lorawan::last_transmission,
config::lorawan_sending_interval, config::lorawan_sending_interval,
#endif #endif
config::temperature_offset, SENSOR_ID.c_str(), SENSOR_ID.c_str(), WiFi.localIP().toString().c_str(), config::temperature_offset, config::auto_calibrate_sensor ? "Yes" : "No", ampel.sensorId, ampel.sensorId,
WiFi.localIP().toString().c_str(), get_free_heap_size(), max_loop_duration, BOARD, dd, hh, mm, ss); wifi::local_ip, wifi::local_ip, ESP.getFreeHeap(), esp_get_max_free_block_size(), ampel.max_loop_duration,
ampel.board, dd, hh, mm, ss);
Serial.print(F(" - Body size : "));
http.sendContent(content); http.sendContent(content);
Serial.print(strlen(content));
// Script // Script
snprintf_P(content, sizeof(content), script_template snprintf_P(content, sizeof(content), script_template
#ifdef AMPEL_CSV #ifdef AMPEL_CSV
, csv_writer::filename.c_str(), SENSOR_ID.c_str() , csv_writer::filename, ampel.sensorId
#endif #endif
); );
Serial.print(F(" - Script size : "));
Serial.println(strlen(content));
http.sendContent(content); http.sendContent(content);
} }
...@@ -255,7 +264,9 @@ namespace web_server { ...@@ -255,7 +264,9 @@ namespace web_server {
} }
if (FS_LIB.exists(csv_writer::filename)) { if (FS_LIB.exists(csv_writer::filename)) {
fs::File csv_file = FS_LIB.open(csv_writer::filename, "r"); fs::File csv_file = FS_LIB.open(csv_writer::filename, "r");
http.sendHeader("Content-Length", String(csv_file.size())); 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")); http.streamFile(csv_file, F("text/csv"));
csv_file.close(); csv_file.close();
} else { } else {
...@@ -267,14 +278,23 @@ namespace web_server { ...@@ -267,14 +278,23 @@ namespace web_server {
if (!shouldBeAllowed()) { if (!shouldBeAllowed()) {
return http.requestAuthentication(DIGEST_AUTH); return http.requestAuthentication(DIGEST_AUTH);
} }
Serial.print("Removing CSV file..."); Serial.print(F("Removing CSV file..."));
FS_LIB.remove(csv_writer::filename); FS_LIB.remove(csv_writer::filename);
Serial.println(" Done!"); Serial.println(F(" Done!"));
http.sendHeader("Location", "/"); http.sendHeader("Location", "/");
http.send(303); http.send(303);
} }
#endif #endif
void handleWebServerCommand() {
if (!shouldBeAllowed()) {
return http.requestAuthentication(DIGEST_AUTH);
}
http.sendHeader("Location", "/");
http.send(303);
sensor_console::runCommand(http.arg("send").c_str());
}
void handlePageNotFound() { void handlePageNotFound() {
http.send(404, F("text/plain"), F("404: Not found")); http.send(404, F("text/plain"), F("404: Not found"));
} }
......
#ifndef WEB_SERVER_H_ #ifndef WEB_SERVER_H_
#define WEB_SERVER_H_ #define WEB_SERVER_H_
#if defined(ESP8266) #if defined(ESP8266)
# include <ESP8266WebServer.h> # include <ESP8266WebServer.h>
#elif defined(ESP32) #elif defined(ESP32)
...@@ -8,7 +9,9 @@ ...@@ -8,7 +9,9 @@
#include "config.h" #include "config.h"
#include "util.h" #include "util.h"
#include "wifi_util.h"
#include "co2_sensor.h" #include "co2_sensor.h"
#include "sensor_console.h"
#ifdef AMPEL_CSV #ifdef AMPEL_CSV
# include "csv_writer.h" # include "csv_writer.h"
#endif #endif
......
...@@ -12,34 +12,39 @@ namespace config { ...@@ -12,34 +12,39 @@ namespace config {
#endif #endif
} }
// Initialize Wi-Fi namespace wifi {
void WiFiConnect(const String &hostname) { char local_ip[16]; // "255.255.255.255\0"
//NOTE: WiFi Multi could allow multiple SSID and passwords. // Initialize Wi-Fi
WiFi.persistent(false); // Don't write user & password to Flash. void connect(const char *hostname) {
WiFi.mode(WIFI_STA); // Set ESP to be a WiFi-client only //NOTE: WiFi Multi could allow multiple SSID and passwords.
WiFi.persistent(false); // Don't write user & password to Flash.
WiFi.mode(WIFI_STA); // Set ESP to be a WiFi-client only
#if defined(ESP8266) #if defined(ESP8266)
WiFi.hostname(hostname); WiFi.hostname(hostname);
#elif defined(ESP32) #elif defined(ESP32)
WiFi.setHostname(hostname.c_str()); WiFi.setHostname(hostname);
#endif #endif
Serial.print(F("WiFi - Connecting to ")); Serial.print(F("WiFi - Connecting to "));
Serial.println(config::wifi_ssid); Serial.println(config::wifi_ssid);
WiFi.begin(config::wifi_ssid, config::wifi_password); WiFi.begin(config::wifi_ssid, config::wifi_password);
// Wait for connection, at most wifi_timeout seconds // Wait for connection, at most wifi_timeout seconds
for (int i = 0; i <= config::wifi_timeout && (WiFi.status() != WL_CONNECTED); i++) { for (int i = 0; i <= config::wifi_timeout && (WiFi.status() != WL_CONNECTED); i++) {
led_effects::showRainbowWheel(); led_effects::showRainbowWheel();
Serial.print("."); Serial.print(".");
} }
if (WiFi.status() == WL_CONNECTED) { if (WiFi.status() == WL_CONNECTED) {
led_effects::showKITTWheel(color::green); led_effects::showKITTWheel(color::green);
Serial.println(); Serial.println();
Serial.print(F("WiFi - Connected! IP address: ")); Serial.print(F("WiFi - Connected! IP address: "));
Serial.println(WiFi.localIP()); IPAddress address = WiFi.localIP();
} else { snprintf(local_ip, sizeof(local_ip), "%d.%d.%d.%d", address[0], address[1], address[2], address[3]);
//TODO: Allow sensor to work as an Access Point, in order to define SSID & password? Serial.println(local_ip);
led_effects::showKITTWheel(color::red); } else {
Serial.println(F("Connection to WiFi failed")); //TODO: Allow sensor to work as an Access Point, in order to define SSID & password?
led_effects::showKITTWheel(color::red);
Serial.println(F("Connection to WiFi failed"));
}
} }
} }
...@@ -5,6 +5,9 @@ ...@@ -5,6 +5,9 @@
#include "util.h" #include "util.h"
#include "led_effects.h" #include "led_effects.h"
void WiFiConnect(const String &hostname); namespace wifi {
extern char local_ip[];
void connect(const char *hostname);
}
#endif #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