Using HTTPS protocol for ESP32 web server, and implemented POST /api/info handler
This commit is contained in:
parent
ee531c7ffe
commit
6c40ba4e1f
@ -15,7 +15,7 @@
|
|||||||
</extensions>
|
</extensions>
|
||||||
</storageModule>
|
</storageModule>
|
||||||
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
|
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
|
||||||
<configuration artifactName="ESP32" buildProperties="" description="" id="0.910961921" name="Default" parent="org.eclipse.cdt.build.core.prefbase.cfg">
|
<configuration artifactName="ESP32" buildProperties="" description="" id="0.910961921" name="Default" optionalBuildProperties="" parent="org.eclipse.cdt.build.core.prefbase.cfg">
|
||||||
<folderInfo id="0.910961921." name="/" resourcePath="">
|
<folderInfo id="0.910961921." name="/" resourcePath="">
|
||||||
<toolChain id="org.eclipse.cdt.build.core.prefbase.toolchain.952979152" name="No ToolChain" resourceTypeBasedDiscovery="false" superClass="org.eclipse.cdt.build.core.prefbase.toolchain">
|
<toolChain id="org.eclipse.cdt.build.core.prefbase.toolchain.952979152" name="No ToolChain" resourceTypeBasedDiscovery="false" superClass="org.eclipse.cdt.build.core.prefbase.toolchain">
|
||||||
<targetPlatform binaryParser="org.eclipse.cdt.core.ELF" id="org.eclipse.cdt.build.core.prefbase.toolchain.952979152.52310970" name=""/>
|
<targetPlatform binaryParser="org.eclipse.cdt.core.ELF" id="org.eclipse.cdt.build.core.prefbase.toolchain.952979152.52310970" name=""/>
|
||||||
@ -232,6 +232,9 @@
|
|||||||
<listOptionValue builtIn="false" value=""${workspace_loc:/ESP32/src}""/>
|
<listOptionValue builtIn="false" value=""${workspace_loc:/ESP32/src}""/>
|
||||||
<listOptionValue builtIn="false" value=""${workspace_loc:/ESP32/lib/AsyncTCP/src}""/>
|
<listOptionValue builtIn="false" value=""${workspace_loc:/ESP32/lib/AsyncTCP/src}""/>
|
||||||
<listOptionValue builtIn="false" value=""${workspace_loc:/ESP32/lib/DigitalPressureSensor/src}""/>
|
<listOptionValue builtIn="false" value=""${workspace_loc:/ESP32/lib/DigitalPressureSensor/src}""/>
|
||||||
|
<listOptionValue builtIn="false" value=""${HOME}/.platformio/packages/toolchain-xtensa-esp32/xtensa-esp32-elf/include/c++/8.4.0""/>
|
||||||
|
<listOptionValue builtIn="false" value=""${workspace_loc:/ESP32/.pio/libdeps/nodemcu-32s/esp32_https_server/src}""/>
|
||||||
|
<listOptionValue builtIn="false" value=""${HOME}/.platformio/packages/toolchain-xtensa-esp32/xtensa-esp32-elf/include""/>
|
||||||
</option>
|
</option>
|
||||||
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="org.eclipse.cdt.build.core.settings.holder.symbols.1198905600" name="Symbols" superClass="org.eclipse.cdt.build.core.settings.holder.symbols" valueType="definedSymbols">
|
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="org.eclipse.cdt.build.core.settings.holder.symbols.1198905600" name="Symbols" superClass="org.eclipse.cdt.build.core.settings.holder.symbols" valueType="definedSymbols">
|
||||||
<listOptionValue builtIn="false" value="PLATFORMIO=50205"/>
|
<listOptionValue builtIn="false" value="PLATFORMIO=50205"/>
|
||||||
|
9
ESP32/src/Info.h
Normal file
9
ESP32/src/Info.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
struct Info
|
||||||
|
{
|
||||||
|
char realtime[32] = {0}; // UTC date and time, in format YYYY-MM-DDTHH:mm:ss.sssZ
|
||||||
|
float latitude = -1000.0f; // in decimal degrees
|
||||||
|
float longitude = -1000.0f; // in decimal degrees
|
||||||
|
float gpsAltitude = -1000.0f; // in meters, above sea level
|
||||||
|
};
|
@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstdint>
|
#include <stdint.h>
|
||||||
|
|
||||||
struct Status
|
struct Status
|
||||||
{
|
{
|
||||||
|
@ -2,16 +2,23 @@
|
|||||||
|
|
||||||
#include "DebugLog.h"
|
#include "DebugLog.h"
|
||||||
#include "DataLogger.h"
|
#include "DataLogger.h"
|
||||||
|
#include "Info.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <SPIFFS.h>
|
#include <SPIFFS.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
#include "HTTPServer.hpp"
|
#include "HTTPSServer.hpp"
|
||||||
#include "SSLCert.hpp"
|
#include "SSLCert.hpp"
|
||||||
#include "HTTPRequest.hpp"
|
#include "HTTPRequest.hpp"
|
||||||
#include "HTTPResponse.hpp"
|
#include "HTTPResponse.hpp"
|
||||||
|
|
||||||
|
// generated certificate data
|
||||||
|
#include "cert.h"
|
||||||
|
#include "private_key.h"
|
||||||
|
|
||||||
/** Check if we have multiple cores */
|
/** Check if we have multiple cores */
|
||||||
#if CONFIG_FREERTOS_UNICORE
|
#if CONFIG_FREERTOS_UNICORE
|
||||||
#define WEBSERVER_RUNNING_CORE 0
|
#define WEBSERVER_RUNNING_CORE 0
|
||||||
@ -25,7 +32,13 @@ detail::WebServer WebServer;
|
|||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
HTTPServer httpServer;
|
// Create an SSL certificate object from the files included above
|
||||||
|
SSLCert cert = SSLCert(
|
||||||
|
crt_DER, crt_DER_len,
|
||||||
|
private_key_DER, private_key_DER_len
|
||||||
|
);
|
||||||
|
|
||||||
|
HTTPSServer httpServer = HTTPSServer(&cert);
|
||||||
|
|
||||||
WebServer::WebServer()
|
WebServer::WebServer()
|
||||||
{
|
{
|
||||||
@ -121,7 +134,76 @@ namespace detail
|
|||||||
|
|
||||||
void WebServer::HandlePostInfo_(httpsserver::HTTPRequest * request, httpsserver::HTTPResponse * response)
|
void WebServer::HandlePostInfo_(httpsserver::HTTPRequest * request, httpsserver::HTTPResponse * response)
|
||||||
{
|
{
|
||||||
|
char body[128]; // in current implementation, we expect the whole body to fit here
|
||||||
|
size_t bodySize = request->readChars(body, sizeof(body) - 1);
|
||||||
|
body[bodySize] = 0;
|
||||||
|
|
||||||
request->discardRequestBody();
|
request->discardRequestBody();
|
||||||
|
|
||||||
|
//::DebugLog.println(body.c_str());
|
||||||
|
|
||||||
|
Info receivedInfo;
|
||||||
|
|
||||||
|
char* nextParam = body;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
char* sepPos = strstr(nextParam, "&");
|
||||||
|
if(sepPos == nullptr) sepPos = &body[bodySize];
|
||||||
|
if(nextParam == sepPos)
|
||||||
|
break; // should happen only if body is an empty string or ends with an "&" character
|
||||||
|
|
||||||
|
*sepPos = 0; // split the string in-place, this overrides the separating character which is fine
|
||||||
|
//::DebugLog.println(nextParam);
|
||||||
|
|
||||||
|
char* eqPos = strstr(nextParam, "=");
|
||||||
|
if(eqPos != nullptr && eqPos != nextParam && *(eqPos+1) != 0)
|
||||||
|
{
|
||||||
|
*eqPos = 0; // split the string in-place, overriding the equal sign
|
||||||
|
|
||||||
|
char* paramName = nextParam;
|
||||||
|
char* paramValue = eqPos + 1;
|
||||||
|
utils::replaceString(paramValue, "%3A", ":");
|
||||||
|
//::DebugLog.print(paramName); ::DebugLog.print(" = "); ::DebugLog.println(paramValue);
|
||||||
|
|
||||||
|
if(strcmp(paramName, "lat") == 0)
|
||||||
|
{
|
||||||
|
char *ending = nullptr;
|
||||||
|
receivedInfo.latitude = strtof(paramValue, &ending);
|
||||||
|
if (*ending != 0)
|
||||||
|
receivedInfo.latitude = -1000.0f;
|
||||||
|
|
||||||
|
}
|
||||||
|
else if(strcmp(paramName, "lng") == 0)
|
||||||
|
{
|
||||||
|
char *ending = nullptr;
|
||||||
|
receivedInfo.longitude = strtof(paramValue, &ending);
|
||||||
|
if (*ending != 0)
|
||||||
|
receivedInfo.longitude = -1000.0f;
|
||||||
|
|
||||||
|
}
|
||||||
|
else if(strcmp(paramName, "alt") == 0)
|
||||||
|
{
|
||||||
|
char *ending = nullptr;
|
||||||
|
receivedInfo.gpsAltitude = strtof(paramValue, &ending);
|
||||||
|
if (*ending != 0)
|
||||||
|
receivedInfo.gpsAltitude = -1000.0f;
|
||||||
|
|
||||||
|
}
|
||||||
|
else if(strcmp(paramName, "time") == 0)
|
||||||
|
{
|
||||||
|
strncpy(receivedInfo.realtime, paramValue, sizeof(receivedInfo.realtime));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(sepPos == &body[bodySize])
|
||||||
|
break;
|
||||||
|
nextParam = sepPos + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(::WebServer.infoReceived_ != nullptr)
|
||||||
|
{
|
||||||
|
::WebServer.infoReceived_(receivedInfo);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebServer::HandleDefault_(HTTPRequest * request, HTTPResponse * response)
|
void WebServer::HandleDefault_(HTTPRequest * request, HTTPResponse * response)
|
||||||
@ -165,7 +247,7 @@ namespace detail
|
|||||||
|
|
||||||
void WebServer::SendContent_(Stream& stream, httpsserver::HTTPResponse * response)
|
void WebServer::SendContent_(Stream& stream, httpsserver::HTTPResponse * response)
|
||||||
{
|
{
|
||||||
uint8_t buffer[512];
|
uint8_t buffer[128];
|
||||||
while(stream.available())
|
while(stream.available())
|
||||||
{
|
{
|
||||||
size_t numBytes = stream.readBytes(buffer, sizeof(buffer));
|
size_t numBytes = stream.readBytes(buffer, sizeof(buffer));
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include "Status.h"
|
#include "Status.h"
|
||||||
|
|
||||||
class Stream;
|
class Stream;
|
||||||
|
struct Info;
|
||||||
|
|
||||||
namespace httpsserver
|
namespace httpsserver
|
||||||
{
|
{
|
||||||
@ -14,6 +15,9 @@ namespace detail
|
|||||||
{
|
{
|
||||||
class WebServer
|
class WebServer
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
typedef void (*InfoReceived)(const Info& info);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
WebServer();
|
WebServer();
|
||||||
~WebServer();
|
~WebServer();
|
||||||
@ -22,6 +26,8 @@ namespace detail
|
|||||||
|
|
||||||
void setStatus(const Status& status);
|
void setStatus(const Status& status);
|
||||||
|
|
||||||
|
void setInfoReceivedCallback(InfoReceived infoReceived) { infoReceived_ = infoReceived; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void ServerTask_(void* params);
|
static void ServerTask_(void* params);
|
||||||
static void HandleIndex_(httpsserver::HTTPRequest * request, httpsserver::HTTPResponse * response);
|
static void HandleIndex_(httpsserver::HTTPRequest * request, httpsserver::HTTPResponse * response);
|
||||||
@ -33,6 +39,7 @@ namespace detail
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
Status status_;
|
Status status_;
|
||||||
|
InfoReceived infoReceived_ = nullptr;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,4 +33,33 @@ namespace utils
|
|||||||
return (biggestValue - from) + to + 1;
|
return (biggestValue - from) + to + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void replaceString(char* str, char* searchStr, char* replacementStr)
|
||||||
|
{
|
||||||
|
size_t searchStrLen = strlen(searchStr);
|
||||||
|
size_t replacementStrLen = strlen(replacementStr);
|
||||||
|
|
||||||
|
char* newPos = str;
|
||||||
|
char* nextSearchPos = str;
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
char* p = strstr(nextSearchPos, searchStr);
|
||||||
|
if(p == nullptr) p = nextSearchPos + strlen(nextSearchPos);
|
||||||
|
|
||||||
|
size_t l = p - nextSearchPos;
|
||||||
|
if(newPos != nextSearchPos)
|
||||||
|
{
|
||||||
|
memcpy(newPos, nextSearchPos, l);
|
||||||
|
}
|
||||||
|
newPos += l;
|
||||||
|
|
||||||
|
if(*p == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
memcpy(newPos, replacementStr, replacementStrLen);
|
||||||
|
newPos += replacementStrLen;
|
||||||
|
|
||||||
|
nextSearchPos = p + searchStrLen;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
namespace utils
|
namespace utils
|
||||||
{
|
{
|
||||||
unsigned long elapsed(unsigned long from, unsigned long to);
|
unsigned long elapsed(unsigned long from, unsigned long to);
|
||||||
|
|
||||||
|
//! Replace all occurences of searchStr by remplacementStr, in-place within input str. This function can only be used if replacementStr is shorter or the same size as searchStr.
|
||||||
|
void replaceString(char* str, char* searchStr, char* replacementStr);
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include "DataLogger.h"
|
#include "DataLogger.h"
|
||||||
#include "WebServer.h"
|
#include "WebServer.h"
|
||||||
#include "Status.h"
|
#include "Status.h"
|
||||||
|
#include "Info.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
@ -151,6 +152,14 @@ void connectWifi()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void onInfoReceived(const Info& info)
|
||||||
|
{
|
||||||
|
if(info.latitude > -900.0f) status.latitude = info.latitude;
|
||||||
|
if(info.longitude > -900.0f) status.longitude = info.longitude;
|
||||||
|
if(info.gpsAltitude > -900.0f) status.gpsAltitude = info.gpsAltitude;
|
||||||
|
if(info.realtime[0] != 0) strncpy(status.realtime, info.realtime, sizeof(status.realtime));
|
||||||
|
}
|
||||||
|
|
||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
pinMode(debugLedPin, OUTPUT);
|
pinMode(debugLedPin, OUTPUT);
|
||||||
@ -198,6 +207,7 @@ void setup()
|
|||||||
|
|
||||||
//currentSensor2.begin(0x48, &Wire);
|
//currentSensor2.begin(0x48, &Wire);
|
||||||
|
|
||||||
|
WebServer.setInfoReceivedCallback(onInfoReceived);
|
||||||
WebServer.begin();
|
WebServer.begin();
|
||||||
|
|
||||||
/*server.on("/api/debug/log", HTTP_GET, [](AsyncWebServerRequest *request){
|
/*server.on("/api/debug/log", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||||
|
@ -50,6 +50,7 @@ export class MonitorApi {
|
|||||||
private mockServer: boolean;
|
private mockServer: boolean;
|
||||||
private lastStatus: Status = null;
|
private lastStatus: Status = null;
|
||||||
private lastKnownPosition: GeolocationPosition = null;
|
private lastKnownPosition: GeolocationPosition = null;
|
||||||
|
private watchingPosition: boolean = false;
|
||||||
private static api: MonitorApi = null;
|
private static api: MonitorApi = null;
|
||||||
|
|
||||||
private lastFetchTime = 0;
|
private lastFetchTime = 0;
|
||||||
@ -74,18 +75,19 @@ export class MonitorApi {
|
|||||||
getStatus() { return this.lastStatus; }
|
getStatus() { return this.lastStatus; }
|
||||||
|
|
||||||
async autoUpdateInfo(): Promise<void> {
|
async autoUpdateInfo(): Promise<void> {
|
||||||
if (navigator.geolocation) {
|
if (!this.watchingPosition && navigator.geolocation) {
|
||||||
let updatePosition = (position: GeolocationPosition) => {
|
let updatePosition = (position: GeolocationPosition) => {
|
||||||
this.lastKnownPosition = position;
|
this.lastKnownPosition = position;
|
||||||
};
|
};
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
enableHighAccuracy: true,
|
enableHighAccuracy: true,
|
||||||
timeout: 6000,
|
timeout: 10000,
|
||||||
maximumAge: 3000,
|
maximumAge: 5000,
|
||||||
};
|
};
|
||||||
|
|
||||||
navigator.geolocation.getCurrentPosition(updatePosition, () => updatePosition(null), options);
|
navigator.geolocation.watchPosition(updatePosition, () => updatePosition(null), options);
|
||||||
|
this.watchingPosition = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultPosition : GeolocationPosition = {
|
const defaultPosition : GeolocationPosition = {
|
||||||
|
Loading…
Reference in New Issue
Block a user