ESP-NOW packet modification

- include up to 5 segments in 1st packet
- header contains total number of packets (instead of segments)

web server code reorganise
This commit is contained in:
Blaz Kristan
2024-02-15 20:40:55 +01:00
parent 2d30535b69
commit 95e2e574b8
4 changed files with 189 additions and 169 deletions

View File

@@ -11,14 +11,6 @@
#endif
#include "html_cpal.h"
/*
* Integrated HTTP web server page declarations
*/
bool handleIfNoneMatchCacheHeader(AsyncWebServerRequest* request, int code, uint16_t eTagSuffix = 0);
void setStaticContentCacheHeaders(AsyncWebServerResponse *response, int code, uint16_t eTagSuffix = 0);
void handleStaticContent(AsyncWebServerRequest *request, const String &path, int code, const String &contentType, const uint8_t *content, size_t len, bool gzip = true, uint16_t eTagSuffix = 0);
// define flash strings once (saves flash memory)
static const char s_redirecting[] PROGMEM = "Redirecting...";
static const char s_content_enc[] PROGMEM = "Content-Encoding";
@@ -33,7 +25,7 @@ static const char s_plain[] PROGMEM = "text/plain";
static const char s_css[] PROGMEM = "text/css";
//Is this an IP?
bool isIp(String str) {
static bool isIp(String str) {
for (size_t i = 0; i < str.length(); i++) {
int c = str.charAt(i);
if (c != '.' && (c < '0' || c > '9')) {
@@ -43,7 +35,128 @@ bool isIp(String str) {
return true;
}
void handleUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final) {
/*
* Integrated HTTP web server page declarations
*/
static void generateEtag(char *etag, uint16_t eTagSuffix) {
sprintf_P(etag, PSTR("%7d-%02x-%04x"), VERSION, cacheInvalidate, eTagSuffix);
}
static void setStaticContentCacheHeaders(AsyncWebServerResponse *response, int code, uint16_t eTagSuffix = 0) {
// Only send ETag for 200 (OK) responses
if (code != 200) return;
// https://medium.com/@codebyamir/a-web-developers-guide-to-browser-caching-cc41f3b73e7c
#ifndef WLED_DEBUG
// this header name is misleading, "no-cache" will not disable cache,
// it just revalidates on every load using the "If-None-Match" header with the last ETag value
response->addHeader(F("Cache-Control"), F("no-cache"));
#else
response->addHeader(F("Cache-Control"), F("no-store,max-age=0")); // prevent caching if debug build
#endif
char etag[32];
generateEtag(etag, eTagSuffix);
response->addHeader(F("ETag"), etag);
}
static bool handleIfNoneMatchCacheHeader(AsyncWebServerRequest *request, int code, uint16_t eTagSuffix = 0) {
// Only send 304 (Not Modified) if response code is 200 (OK)
if (code != 200) return false;
AsyncWebHeader *header = request->getHeader(F("If-None-Match"));
char etag[32];
generateEtag(etag, eTagSuffix);
if (header && header->value() == etag) {
AsyncWebServerResponse *response = request->beginResponse(304);
setStaticContentCacheHeaders(response, code, eTagSuffix);
request->send(response);
return true;
}
return false;
}
/**
* Handles the request for a static file.
* If the file was found in the filesystem, it will be sent to the client.
* Otherwise it will be checked if the browser cached the file and if so, a 304 response will be sent.
* If the file was not found in the filesystem and not in the browser cache, the request will be handled as a 200 response with the content of the page.
*
* @param request The request object
* @param path If a file with this path exists in the filesystem, it will be sent to the client. Set to "" to skip this check.
* @param code The HTTP status code
* @param contentType The content type of the web page
* @param content Content of the web page
* @param len Length of the content
* @param gzip Optional. Defaults to true. If false, the gzip header will not be added.
* @param eTagSuffix Optional. Defaults to 0. A suffix that will be added to the ETag header. This can be used to invalidate the cache for a specific page.
*/
static void handleStaticContent(AsyncWebServerRequest *request, const String &path, int code, const String &contentType, const uint8_t *content, size_t len, bool gzip = true, uint16_t eTagSuffix = 0) {
if (path != "" && handleFileRead(request, path)) return;
if (handleIfNoneMatchCacheHeader(request, code, eTagSuffix)) return;
AsyncWebServerResponse *response = request->beginResponse_P(code, contentType, content, len);
if (gzip) response->addHeader(FPSTR(s_content_enc), F("gzip"));
setStaticContentCacheHeaders(response, code, eTagSuffix);
request->send(response);
}
#ifdef WLED_ENABLE_DMX
static String dmxProcessor(const String& var)
{
String mapJS;
if (var == F("DMXVARS")) {
mapJS += F("\nCN=");
mapJS += String(DMXChannels);
mapJS += F(";\nCS=");
mapJS += String(DMXStart);
mapJS += F(";\nCG=");
mapJS += String(DMXGap);
mapJS += F(";\nLC=");
mapJS += String(strip.getLengthTotal());
mapJS += F(";\nvar CH=[");
for (int i=0; i<15; i++) {
mapJS += String(DMXFixtureMap[i]) + ',';
}
mapJS += F("0];");
}
return mapJS;
}
#endif
static String msgProcessor(const String& var)
{
if (var == "MSG") {
String messageBody = messageHead;
messageBody += F("</h2>");
messageBody += messageSub;
uint32_t optt = optionType;
if (optt < 60) //redirect to settings after optionType seconds
{
messageBody += F("<script>setTimeout(RS,");
messageBody +=String(optt*1000);
messageBody += F(")</script>");
} else if (optt < 120) //redirect back after optionType-60 seconds, unused
{
//messageBody += "<script>setTimeout(B," + String((optt-60)*1000) + ")</script>";
} else if (optt < 180) //reload parent after optionType-120 seconds
{
messageBody += F("<script>setTimeout(RP,");
messageBody += String((optt-120)*1000);
messageBody += F(")</script>");
} else if (optt == 253)
{
messageBody += F("<br><br><form action=/settings><button class=\"bt\" type=submit>Back</button></form>"); //button to settings
} else if (optt == 254)
{
messageBody += F("<br><br><button type=\"button\" class=\"bt\" onclick=\"B()\">Back</button>");
}
return messageBody;
}
return String();
}
static void handleUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final) {
if (!correctPIN) {
if (final) request->send(401, FPSTR(s_plain), FPSTR(s_unlock_cfg));
return;
@@ -96,7 +209,7 @@ void createEditHandler(bool enable) {
}
}
bool captivePortal(AsyncWebServerRequest *request)
static bool captivePortal(AsyncWebServerRequest *request)
{
if (!apActive) return false; //only serve captive in AP mode
if (!request->hasHeader("Host")) return false;
@@ -368,102 +481,6 @@ void initServer()
});
}
void generateEtag(char *etag, uint16_t eTagSuffix) {
sprintf_P(etag, PSTR("%7d-%02x-%04x"), VERSION, cacheInvalidate, eTagSuffix);
}
bool handleIfNoneMatchCacheHeader(AsyncWebServerRequest *request, int code, uint16_t eTagSuffix) {
// Only send 304 (Not Modified) if response code is 200 (OK)
if (code != 200) return false;
AsyncWebHeader *header = request->getHeader(F("If-None-Match"));
char etag[32];
generateEtag(etag, eTagSuffix);
if (header && header->value() == etag) {
AsyncWebServerResponse *response = request->beginResponse(304);
setStaticContentCacheHeaders(response, code, eTagSuffix);
request->send(response);
return true;
}
return false;
}
void setStaticContentCacheHeaders(AsyncWebServerResponse *response, int code, uint16_t eTagSuffix) {
// Only send ETag for 200 (OK) responses
if (code != 200) return;
// https://medium.com/@codebyamir/a-web-developers-guide-to-browser-caching-cc41f3b73e7c
#ifndef WLED_DEBUG
// this header name is misleading, "no-cache" will not disable cache,
// it just revalidates on every load using the "If-None-Match" header with the last ETag value
response->addHeader(F("Cache-Control"), F("no-cache"));
#else
response->addHeader(F("Cache-Control"), F("no-store,max-age=0")); // prevent caching if debug build
#endif
char etag[32];
generateEtag(etag, eTagSuffix);
response->addHeader(F("ETag"), etag);
}
/**
* Handels the request for a static file.
* If the file was found in the filesystem, it will be sent to the client.
* Otherwise it will be checked if the browser cached the file and if so, a 304 response will be sent.
* If the file was not found in the filesystem and not in the browser cache, the request will be handled as a 200 response with the content of the page.
*
* @param request The request object
* @param path If a file with this path exists in the filesystem, it will be sent to the client. Set to "" to skip this check.
* @param code The HTTP status code
* @param contentType The content type of the web page
* @param content Content of the web page
* @param len Length of the content
* @param gzip Optional. Defaults to true. If false, the gzip header will not be added.
* @param eTagSuffix Optional. Defaults to 0. A suffix that will be added to the ETag header. This can be used to invalidate the cache for a specific page.
*/
void handleStaticContent(AsyncWebServerRequest *request, const String &path, int code, const String &contentType, const uint8_t *content, size_t len, bool gzip, uint16_t eTagSuffix) {
if (path != "" && handleFileRead(request, path)) return;
if (handleIfNoneMatchCacheHeader(request, code, eTagSuffix)) return;
AsyncWebServerResponse *response = request->beginResponse_P(code, contentType, content, len);
if (gzip) response->addHeader(FPSTR(s_content_enc), F("gzip"));
setStaticContentCacheHeaders(response, code, eTagSuffix);
request->send(response);
}
String msgProcessor(const String& var)
{
if (var == "MSG") {
String messageBody = messageHead;
messageBody += F("</h2>");
messageBody += messageSub;
uint32_t optt = optionType;
if (optt < 60) //redirect to settings after optionType seconds
{
messageBody += F("<script>setTimeout(RS,");
messageBody +=String(optt*1000);
messageBody += F(")</script>");
} else if (optt < 120) //redirect back after optionType-60 seconds, unused
{
//messageBody += "<script>setTimeout(B," + String((optt-60)*1000) + ")</script>";
} else if (optt < 180) //reload parent after optionType-120 seconds
{
messageBody += F("<script>setTimeout(RP,");
messageBody += String((optt-120)*1000);
messageBody += F(")</script>");
} else if (optt == 253)
{
messageBody += F("<br><br><form action=/settings><button class=\"bt\" type=submit>Back</button></form>"); //button to settings
} else if (optt == 254)
{
messageBody += F("<br><br><button type=\"button\" class=\"bt\" onclick=\"B()\">Back</button>");
}
return messageBody;
}
return String();
}
void serveMessage(AsyncWebServerRequest* request, uint16_t code, const String& headl, const String& subl, byte optionT)
{
@@ -487,29 +504,6 @@ void serveJsonError(AsyncWebServerRequest* request, uint16_t code, uint16_t erro
request->send(response);
}
#ifdef WLED_ENABLE_DMX
String dmxProcessor(const String& var)
{
String mapJS;
if (var == F("DMXVARS")) {
mapJS += F("\nCN=");
mapJS += String(DMXChannels);
mapJS += F(";\nCS=");
mapJS += String(DMXStart);
mapJS += F(";\nCG=");
mapJS += String(DMXGap);
mapJS += F(";\nLC=");
mapJS += String(strip.getLengthTotal());
mapJS += F(";\nvar CH=[");
for (int i=0; i<15; i++) {
mapJS += String(DMXFixtureMap[i]) + ',';
}
mapJS += F("0];");
}
return mapJS;
}
#endif
void serveSettingsJS(AsyncWebServerRequest* request)
{