Add webserver including calibration API endpoint
This commit is contained in:
parent
b417554444
commit
1c30b20d2a
38
include/WebServer.h
Normal file
38
include/WebServer.h
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Adafruit_SCD30.h>
|
||||||
|
|
||||||
|
#include <HTTPRequest.hpp>
|
||||||
|
#include <HTTPResponse.hpp>
|
||||||
|
#include <HTTPServer.hpp>
|
||||||
|
|
||||||
|
#include <freertos/FreeRTOS.h>
|
||||||
|
#include <freertos/semphr.h>
|
||||||
|
|
||||||
|
class WebServer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool start(Adafruit_SCD30 *scd30);
|
||||||
|
|
||||||
|
static WebServer &instance(void)
|
||||||
|
{
|
||||||
|
static WebServer theInstance;
|
||||||
|
return theInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
httpsserver::HTTPServer *m_server;
|
||||||
|
|
||||||
|
Adafruit_SCD30 *m_scd30;
|
||||||
|
|
||||||
|
WebServer(void);
|
||||||
|
|
||||||
|
static void serverTask(void *arg);
|
||||||
|
|
||||||
|
static bool serveFile(String filename, httpsserver::HTTPResponse *res);
|
||||||
|
|
||||||
|
// handlers
|
||||||
|
static void handleRoot(httpsserver::HTTPRequest *req, httpsserver::HTTPResponse *res);
|
||||||
|
static void handleCalibrate(httpsserver::HTTPRequest *req, httpsserver::HTTPResponse *res);
|
||||||
|
static void handleStatic(httpsserver::HTTPRequest *req, httpsserver::HTTPResponse *res);
|
||||||
|
};
|
|
@ -22,6 +22,7 @@ lib_deps =
|
||||||
SPI
|
SPI
|
||||||
Wire
|
Wire
|
||||||
NTPClient
|
NTPClient
|
||||||
|
esp32_https_server @ 1.0.0
|
||||||
|
|
||||||
#esp32_https_server
|
#esp32_https_server
|
||||||
|
|
||||||
|
|
155
src/WebServer.cpp
Normal file
155
src/WebServer.cpp
Normal file
|
@ -0,0 +1,155 @@
|
||||||
|
/* HTTP Server setup and handler functions */
|
||||||
|
|
||||||
|
#include <LittleFS.h>
|
||||||
|
#include <mbedtls/sha256.h>
|
||||||
|
|
||||||
|
#include "WebServer.h"
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
WebServer::WebServer(void)
|
||||||
|
{
|
||||||
|
m_server = new httpsserver::HTTPServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WebServer::serveFile(String filename, httpsserver::HTTPResponse *res)
|
||||||
|
{
|
||||||
|
uint8_t buf[1024];
|
||||||
|
|
||||||
|
bool exists = LittleFS.exists(filename);
|
||||||
|
|
||||||
|
if(!exists) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
File f = LittleFS.open(filename.c_str(), "r");
|
||||||
|
|
||||||
|
if(!f) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
res->setHeader("Content-Length", httpsserver::intToString(f.size()));
|
||||||
|
|
||||||
|
size_t nread = 1;
|
||||||
|
while(nread > 0) {
|
||||||
|
nread = f.readBytes(reinterpret_cast<char*>(buf), 1024);
|
||||||
|
|
||||||
|
if(nread <= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
res->write(buf, nread);
|
||||||
|
}
|
||||||
|
|
||||||
|
f.close();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebServer::handleRoot(httpsserver::HTTPRequest *req, httpsserver::HTTPResponse *res)
|
||||||
|
{
|
||||||
|
serveFile("/htdocs/index.html", res);
|
||||||
|
res->setHeader("Content-Type", "text/html");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void error400(httpsserver::HTTPResponse *res, const std::string &reason)
|
||||||
|
{
|
||||||
|
res->println("Error 400: Bad Request");
|
||||||
|
res->println(reason.c_str());
|
||||||
|
|
||||||
|
res->setStatusCode(400);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebServer::handleCalibrate(httpsserver::HTTPRequest *req, httpsserver::HTTPResponse *res)
|
||||||
|
{
|
||||||
|
res->setHeader("Content-Type", "text/plain");
|
||||||
|
|
||||||
|
httpsserver::ResourceParameters * params = req->getParams();
|
||||||
|
|
||||||
|
std::string ppmstr;
|
||||||
|
if(!params->getQueryParameter("ppm", ppmstr)) {
|
||||||
|
error400(res, "Parameter 'ppm' not set.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ppmvalue = String(ppmstr.c_str()).toInt();
|
||||||
|
if(ppmvalue < 0 || ppmvalue > 65535) {
|
||||||
|
error400(res, "Parameter 'ppm' out of range [0 .. 65535].");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
res->setStatusCode(200);
|
||||||
|
res->print("Recalibrating SCD30 to ");
|
||||||
|
res->print(ppmvalue);
|
||||||
|
res->println(" ppm");
|
||||||
|
|
||||||
|
WebServer::instance().m_scd30->forceRecalibrationWithReference((uint16_t)ppmvalue);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebServer::handleStatic(httpsserver::HTTPRequest *req, httpsserver::HTTPResponse *res)
|
||||||
|
{
|
||||||
|
std::string filename = "/htdocs" + req->getRequestString();
|
||||||
|
|
||||||
|
if(*(filename.end()-1) == '/') {
|
||||||
|
// looks like a directory name, so append 'index.html'
|
||||||
|
filename.append("index.html");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!serveFile(filename.c_str(), res)) {
|
||||||
|
req->discardRequestBody();
|
||||||
|
|
||||||
|
res->setStatusCode(404);
|
||||||
|
res->setHeader("Content-Type", "text/plain");
|
||||||
|
|
||||||
|
res->println("Error 404: Not found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebServer::serverTask(void *arg)
|
||||||
|
{
|
||||||
|
httpsserver::ResourceNode *nodeRoot =
|
||||||
|
new httpsserver::ResourceNode("/", "GET", WebServer::handleRoot);
|
||||||
|
httpsserver::ResourceNode *nodeAPICalibrate =
|
||||||
|
new httpsserver::ResourceNode("/api/calibrate", "GET", WebServer::handleCalibrate);
|
||||||
|
|
||||||
|
// handle all remaining requests by trying to serve static files. If no file is found, 404 is generated.
|
||||||
|
httpsserver::ResourceNode *nodeStatic =
|
||||||
|
new httpsserver::ResourceNode("", "GET", WebServer::handleStatic);
|
||||||
|
|
||||||
|
WebServer &server = WebServer::instance();
|
||||||
|
|
||||||
|
server.m_server->registerNode(nodeRoot);
|
||||||
|
server.m_server->registerNode(nodeAPICalibrate);
|
||||||
|
server.m_server->setDefaultNode(nodeStatic);
|
||||||
|
|
||||||
|
Serial.println("[server] Starting HTTP Server...");
|
||||||
|
server.m_server->start();
|
||||||
|
if (server.m_server->isRunning())
|
||||||
|
{
|
||||||
|
Serial.println("[server] Server ready.");
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
server.m_server->loop();
|
||||||
|
delay(10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.println("[server] Server died?! This should never happen.");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WebServer::start(Adafruit_SCD30 *scd30)
|
||||||
|
{
|
||||||
|
m_scd30 = scd30;
|
||||||
|
|
||||||
|
xTaskCreatePinnedToCore(
|
||||||
|
WebServer::serverTask, /* Task function. */
|
||||||
|
"HTTP Server Task", /* name of task. */
|
||||||
|
6144, /* Stack size of task */
|
||||||
|
NULL, /* parameter of the task */
|
||||||
|
1, /* priority of the task */
|
||||||
|
NULL, /* Task handle to keep track of created task */
|
||||||
|
1);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
30
src/main.cpp
30
src/main.cpp
|
@ -13,6 +13,7 @@
|
||||||
#include <Fonts/FreeSans12pt7b.h>
|
#include <Fonts/FreeSans12pt7b.h>
|
||||||
#include <Fonts/FreeSansBold12pt7b.h>
|
#include <Fonts/FreeSansBold12pt7b.h>
|
||||||
|
|
||||||
|
#include "WebServer.h"
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
#include <epaper.h>
|
#include <epaper.h>
|
||||||
|
@ -215,6 +216,7 @@ void setup(void)
|
||||||
|
|
||||||
epaper_draw_and_hibernate(draw_epaper_initial_callback, false);
|
epaper_draw_and_hibernate(draw_epaper_initial_callback, false);
|
||||||
|
|
||||||
|
WebServer::instance().start(&scd30);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -341,6 +343,7 @@ void loop(void)
|
||||||
{
|
{
|
||||||
static bool first_scd30_readout = true;
|
static bool first_scd30_readout = true;
|
||||||
static uint32_t lastEPaperRefresh = 0;
|
static uint32_t lastEPaperRefresh = 0;
|
||||||
|
static uint32_t lastUpload = 0;
|
||||||
uint32_t now = millis();
|
uint32_t now = millis();
|
||||||
|
|
||||||
wiFiMulti.run(); // maintain the WiFi connection
|
wiFiMulti.run(); // maintain the WiFi connection
|
||||||
|
@ -372,18 +375,6 @@ void loop(void)
|
||||||
Serial.println(" %");
|
Serial.println(" %");
|
||||||
Serial.println("");
|
Serial.println("");
|
||||||
|
|
||||||
Serial.println("\nUploading...");
|
|
||||||
upload_data();
|
|
||||||
|
|
||||||
if((now - lastEPaperRefresh) >= 60000) {
|
|
||||||
Serial.println("Rendering display...");
|
|
||||||
lastEPaperRefresh = now;
|
|
||||||
epaper_draw_and_hibernate(draw_epaper_callback, false);
|
|
||||||
Serial.println("Display updated.");
|
|
||||||
|
|
||||||
timeseries_prune(&ts_scd30_humidity, 3600); // keep the last hour
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
if(!calibrationDone && now >= 300000) {
|
if(!calibrationDone && now >= 300000) {
|
||||||
uint16_t calValue = scd30.getForcedCalibrationReference();
|
uint16_t calValue = scd30.getForcedCalibrationReference();
|
||||||
|
@ -400,5 +391,20 @@ void loop(void)
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!first_scd30_readout && (now - lastUpload) >= 30000) {
|
||||||
|
lastUpload = now;
|
||||||
|
Serial.println("\nUploading...");
|
||||||
|
upload_data();
|
||||||
|
}
|
||||||
|
|
||||||
|
if((now - lastEPaperRefresh) >= 60000) {
|
||||||
|
Serial.println("Rendering display...");
|
||||||
|
lastEPaperRefresh = now;
|
||||||
|
epaper_draw_and_hibernate(draw_epaper_callback, false);
|
||||||
|
Serial.println("Display updated.");
|
||||||
|
|
||||||
|
timeseries_prune(&ts_scd30_humidity, 3600); // keep the last hour
|
||||||
|
}
|
||||||
|
|
||||||
delay(1000);
|
delay(1000);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue