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
|
||||
Wire
|
||||
NTPClient
|
||||
esp32_https_server @ 1.0.0
|
||||
|
||||
#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/FreeSansBold12pt7b.h>
|
||||
|
||||
#include "WebServer.h"
|
||||
#include "Config.h"
|
||||
|
||||
#include <epaper.h>
|
||||
|
@ -215,6 +216,7 @@ void setup(void)
|
|||
|
||||
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 uint32_t lastEPaperRefresh = 0;
|
||||
static uint32_t lastUpload = 0;
|
||||
uint32_t now = millis();
|
||||
|
||||
wiFiMulti.run(); // maintain the WiFi connection
|
||||
|
@ -372,18 +375,6 @@ void loop(void)
|
|||
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) {
|
||||
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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue