Browse Source

Using HTTPS protocol for ESP32 web server, and implemented POST /api/info handler

master
Youen 5 months ago
parent
commit
6c40ba4e1f
  1. 5
      ESP32/.cproject
  2. 9
      ESP32/src/Info.h
  3. 2
      ESP32/src/Status.h
  4. 88
      ESP32/src/WebServer.cpp
  5. 7
      ESP32/src/WebServer.h
  6. 29
      ESP32/src/utils.cpp
  7. 3
      ESP32/src/utils.h
  8. 10
      ESP32/src/vehicle-monitor.cpp
  9. 10
      WebApp/src/monitor-api.ts

5
ESP32/.cproject

@ -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="&quot;${workspace_loc:/ESP32/src}&quot;"/> <listOptionValue builtIn="false" value="&quot;${workspace_loc:/ESP32/src}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/ESP32/lib/AsyncTCP/src}&quot;"/> <listOptionValue builtIn="false" value="&quot;${workspace_loc:/ESP32/lib/AsyncTCP/src}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/ESP32/lib/DigitalPressureSensor/src}&quot;"/> <listOptionValue builtIn="false" value="&quot;${workspace_loc:/ESP32/lib/DigitalPressureSensor/src}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${HOME}/.platformio/packages/toolchain-xtensa-esp32/xtensa-esp32-elf/include/c++/8.4.0&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/ESP32/.pio/libdeps/nodemcu-32s/esp32_https_server/src}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${HOME}/.platformio/packages/toolchain-xtensa-esp32/xtensa-esp32-elf/include&quot;"/>
</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

@ -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
};

2
ESP32/src/Status.h

@ -1,6 +1,6 @@
#pragma once #pragma once
#include <cstdint> #include <stdint.h>
struct Status struct Status
{ {

88
ESP32/src/WebServer.cpp

@ -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));

7
ESP32/src/WebServer.h

@ -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;
}; };
} }

29
ESP32/src/utils.cpp

@ -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;
}
}
} }

3
ESP32/src/utils.h

@ -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);
} }

10
ESP32/src/vehicle-monitor.cpp

@ -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){

10
WebApp/src/monitor-api.ts

@ -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…
Cancel
Save