PsychichHTTP v2-dev

This commit is contained in:
iranl
2024-12-30 14:37:09 +01:00
parent 2cf5201285
commit 78459c2d08
118 changed files with 5453 additions and 4972 deletions

View File

@@ -8,18 +8,18 @@
*/
#include <Arduino.h>
#include <WiFi.h>
#include <ArduinoJSON.h>
#include <LittleFS.h>
#include <MongooseCore.h>
#include <MongooseHttpServer.h>
#include <LittleFS.h>
#include <ArduinoJSON.h>
#include <WiFi.h>
const char *ssid = "";
const char *password = "";
const char* ssid = "";
const char* password = "";
MongooseHttpServer server;
const char *htmlContent = R"(
const char* htmlContent = R"(
<!DOCTYPE html>
<html>
<head>
@@ -154,25 +154,23 @@ void setup()
// To debug, please enable Core Debug Level to Verbose
if (connectToWifi())
{
if(!LittleFS.begin())
if (!LittleFS.begin())
{
Serial.println("LittleFS Mount Failed. Do Platform -> Build Filesystem Image and Platform -> Upload Filesystem Image from VSCode");
return;
}
//start our server
// start our server
Mongoose.begin();
server.begin(80);
//index file
server.on("/", HTTP_GET, [](MongooseHttpServerRequest *request)
{
request->send(200, "text/html", htmlContent);
});
// index file
server.on("/", HTTP_GET, [](MongooseHttpServerRequest* request)
{ request->send(200, "text/html", htmlContent); });
//api - parameters passed in via query eg. /api/endpoint?foo=bar
server.on("/api", HTTP_GET, [](MongooseHttpServerRequest *request)
{
// api - parameters passed in via query eg. /api/endpoint?foo=bar
server.on("/api", HTTP_GET, [](MongooseHttpServerRequest* request)
{
//create a response object
StaticJsonDocument<128> output;
output["msg"] = "status";
@@ -189,19 +187,18 @@ void setup()
//serialize and return
String jsonBuffer;
serializeJson(output, jsonBuffer);
request->send(200, "application/json", jsonBuffer.c_str());
});
request->send(200, "application/json", jsonBuffer.c_str()); });
//websocket
server.on("/ws$")->
onFrame([](MongooseHttpWebSocketConnection *connection, int flags, uint8_t *data, size_t len) {
connection->send(WEBSOCKET_OP_TEXT, data, len);
//server.sendAll(connection, (char *)data);
});
// websocket
server.on("/ws$")->onFrame([](MongooseHttpWebSocketConnection* connection, int flags, uint8_t* data, size_t len)
{
connection->send(WEBSOCKET_OP_TEXT, data, len);
// server.sendAll(connection, (char *)data);
});
//hack - no servestatic
server.on("/alien.png", HTTP_GET, [](MongooseHttpServerRequest *request)
{
// hack - no servestatic
server.on("/alien.png", HTTP_GET, [](MongooseHttpServerRequest* request)
{
//open our file
File fp = LittleFS.open("/www/alien.png");
size_t length = fp.size();
@@ -223,8 +220,7 @@ void setup()
free(data);
}
else
request->send(503);
});
request->send(503); });
}
}

View File

@@ -11,12 +11,31 @@
[env]
platform = espressif32
framework = arduino
board = esp32dev
; board = esp32dev
board = esp32-s3-devkitc-1
upload_port = /dev/ttyACM0
monitor_port = /dev/ttyACM1
monitor_speed = 115200
monitor_filters = esp32_exception_decoder
lib_deps =
https://github.com/me-no-dev/ESPAsyncWebServer
bblanchon/ArduinoJson
lib_compat_mode = strict
lib_ldf_mode = chain
lib_deps =
; mathieucarbou/AsyncTCP @ 3.2.10
https://github.com/mathieucarbou/AsyncTCPSock/archive/refs/tags/v1.0.3-dev.zip
mathieucarbou/ESPAsyncWebServer @ 3.3.16
bblanchon/ArduinoJson
lib_ignore =
AsyncTCP
mathieucarbou/AsyncTCP
board_build.filesystem = littlefs
build_flags =
-D CONFIG_ASYNC_TCP_MAX_ACK_TIME=3000
-D CONFIG_ASYNC_TCP_PRIORITY=10
-D CONFIG_ASYNC_TCP_QUEUE_SIZE=128
-D CONFIG_ASYNC_TCP_RUNNING_CORE=1
-D CONFIG_ASYNC_TCP_STACK_SIZE=4096
-D WS_MAX_QUEUED_MESSAGES=128
[env:default]

View File

@@ -7,19 +7,29 @@
CONDITIONS OF ANY KIND, either express or implied.
*/
#include "_secret.h"
#include <Arduino.h>
#include <WiFi.h>
#include <ArduinoJson.h>
#include <ESPAsyncWebServer.h>
#include <ESPmDNS.h>
#include <LittleFS.h>
#include <ArduinoJSON.h>
#include <WiFi.h>
const char *ssid = "";
const char *password = "";
#ifndef WIFI_SSID
#error "You need to enter your wifi credentials. Copy secret.h to _secret.h and enter your credentials there."
#endif
// Enter your WIFI credentials in secret.h
const char* ssid = WIFI_SSID;
const char* password = WIFI_PASS;
// hostname for mdns (psychic.local)
const char* local_hostname = "psychic";
AsyncWebServer server(80);
AsyncWebSocket ws("/ws");
const char *htmlContent = R"(
const char* htmlContent = R"(
<!DOCTYPE html>
<html>
<head>
@@ -79,14 +89,16 @@ const char *htmlContent = R"(
</html>
)";
const size_t htmlContentLen = strlen(htmlContent);
bool connectToWifi()
{
Serial.println();
Serial.print("[WiFi] Connecting to ");
Serial.println(ssid);
WiFi.setSleep(false);
WiFi.useStaticBuffers(true);
// WiFi.setSleep(false);
// WiFi.useStaticBuffers(true);
WiFi.begin(ssid, password);
@@ -95,10 +107,8 @@ bool connectToWifi()
int numberOfTries = 20;
// Wait for the WiFi event
while (true)
{
switch (WiFi.status())
{
while (true) {
switch (WiFi.status()) {
case WL_NO_SSID_AVAIL:
Serial.println("[WiFi] SSID not found");
break;
@@ -128,15 +138,12 @@ bool connectToWifi()
}
delay(tryDelay);
if (numberOfTries <= 0)
{
if (numberOfTries <= 0) {
Serial.print("[WiFi] Failed to connect to WiFi!");
// Use disconnect function to force stop trying to connect
WiFi.disconnect();
return false;
}
else
{
} else {
numberOfTries--;
}
}
@@ -144,28 +151,29 @@ bool connectToWifi()
return false;
}
void onEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len){
if(type == WS_EVT_CONNECT){
//client connected
// Serial.printf("ws[%s][%u] connect\n", server->url(), client->id());
// client->printf("Hello Client %u :)", client->id());
// client->ping();
} else if(type == WS_EVT_DISCONNECT){
//client disconnected
// Serial.printf("ws[%s][%u] disconnect: %u\n", server->url(), client->id());
} else if(type == WS_EVT_ERROR){
//error was received from the other end
// Serial.printf("ws[%s][%u] error(%u): %s\n", server->url(), client->id(), *((uint16_t*)arg), (char*)data);
} else if(type == WS_EVT_PONG){
//pong message was received (in response to a ping request maybe)
// Serial.printf("ws[%s][%u] pong[%u]: %s\n", server->url(), client->id(), len, (len)?(char*)data:"");
} else if(type == WS_EVT_DATA){
//data packet
AwsFrameInfo * info = (AwsFrameInfo*)arg;
if(info->final && info->index == 0 && info->len == len){
//the whole message is in a single frame and we got all of it's data
// Serial.printf("ws[%s][%u] %s-message[%llu]: ", server->url(), client->id(), (info->opcode == WS_TEXT)?"text":"binary", info->len);
if(info->opcode == WS_TEXT){
void onEvent(AsyncWebSocket* server, AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len)
{
if (type == WS_EVT_CONNECT) {
// client connected
// Serial.printf("ws[%s][%u] connect\n", server->url(), client->id());
// client->printf("Hello Client %u :)", client->id());
// client->ping();
} else if (type == WS_EVT_DISCONNECT) {
// client disconnected
// Serial.printf("ws[%s][%u] disconnect: %u\n", server->url(), client->id());
} else if (type == WS_EVT_ERROR) {
// error was received from the other end
// Serial.printf("ws[%s][%u] error(%u): %s\n", server->url(), client->id(), *((uint16_t*)arg), (char*)data);
} else if (type == WS_EVT_PONG) {
// pong message was received (in response to a ping request maybe)
// Serial.printf("ws[%s][%u] pong[%u]: %s\n", server->url(), client->id(), len, (len)?(char*)data:"");
} else if (type == WS_EVT_DATA) {
// data packet
AwsFrameInfo* info = (AwsFrameInfo*)arg;
if (info->final && info->index == 0 && info->len == len) {
// the whole message is in a single frame and we got all of it's data
// Serial.printf("ws[%s][%u] %s-message[%llu]: ", server->url(), client->id(), (info->opcode == WS_TEXT)?"text":"binary", info->len);
if (info->opcode == WS_TEXT) {
data[len] = 0;
// Serial.printf("%s\n", (char*)data);
} else {
@@ -174,22 +182,21 @@ void onEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp
// }
// Serial.printf("\n");
}
if(info->opcode == WS_TEXT)
{
client->text((char *)data, len);
if (info->opcode == WS_TEXT) {
client->text((char*)data, len);
}
// else
// client->binary("I got your binary message");
} else {
//message is comprised of multiple frames or the frame is split into multiple packets
if(info->index == 0){
// message is comprised of multiple frames or the frame is split into multiple packets
if (info->index == 0) {
// if(info->num == 0)
// Serial.printf("ws[%s][%u] %s-message start\n", server->url(), client->id(), (info->message_opcode == WS_TEXT)?"text":"binary");
// Serial.printf("ws[%s][%u] frame[%u] start[%llu]\n", server->url(), client->id(), info->num, info->len);
}
Serial.printf("ws[%s][%u] frame[%u] %s[%llu - %llu]: ", server->url(), client->id(), info->num, (info->message_opcode == WS_TEXT)?"text":"binary", info->index, info->index + len);
if(info->message_opcode == WS_TEXT){
Serial.printf("ws[%s][%u] frame[%u] %s[%llu - %llu]: ", server->url(), client->id(), info->num, (info->message_opcode == WS_TEXT) ? "text" : "binary", info->index, info->index + len);
if (info->message_opcode == WS_TEXT) {
data[len] = 0;
// Serial.printf("%s\n", (char*)data);
} else {
@@ -199,13 +206,12 @@ void onEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp
// Serial.printf("\n");
}
if((info->index + len) == info->len){
if ((info->index + len) == info->len) {
// Serial.printf("ws[%s][%u] frame[%u] end[%llu]\n", server->url(), client->id(), info->num, info->len);
if(info->final){
if (info->final) {
// Serial.printf("ws[%s][%u] %s-message end\n", server->url(), client->id(), (info->message_opcode == WS_TEXT)?"text":"binary");
if(info->message_opcode == WS_TEXT)
{
client->text((char *)data, info->len);
if (info->message_opcode == WS_TEXT) {
client->text((char*)data, info->len);
}
// else
// client->binary("I got your binary message");
@@ -223,40 +229,41 @@ void setup()
// We start by connecting to a WiFi network
// To debug, please enable Core Debug Level to Verbose
if (connectToWifi())
{
if(!LittleFS.begin())
{
if (connectToWifi()) {
// set up our esp32 to listen on the local_hostname.local domain
if (!MDNS.begin(local_hostname)) {
Serial.println("Error starting mDNS");
return;
}
MDNS.addService("http", "tcp", 80);
if (!LittleFS.begin()) {
Serial.println("LittleFS Mount Failed. Do Platform -> Build Filesystem Image and Platform -> Upload Filesystem Image from VSCode");
return;
}
//api - parameters passed in via query eg. /api/endpoint?foo=bar
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request)
{
request->send(200, "text/html", htmlContent);
// api - parameters passed in via query eg. /api/endpoint?foo=bar
server.on("/", HTTP_GET, [](AsyncWebServerRequest* request) {
// ESPAsyncWebServer, sending a char* does a buffer copy, unlike Psychic.
// Sending flash data is done with the uint8_t* overload.
request->send(200, "text/html", (uint8_t*)htmlContent, htmlContentLen);
});
//serve static files from LittleFS/www on /
server.serveStatic("/", LittleFS, "/www/");
//api - parameters passed in via query eg. /api/endpoint?foo=bar
server.on("/api", HTTP_GET, [](AsyncWebServerRequest *request)
{
//create a response object
StaticJsonDocument<128> output;
// api - parameters passed in via query eg. /api/endpoint?foo=bar
server.on("/api", HTTP_GET, [](AsyncWebServerRequest* request) {
// create a response object
JsonDocument output;
output["msg"] = "status";
output["status"] = "success";
output["millis"] = millis();
//work with some params
if (request->hasParam("foo"))
{
AsyncWebParameter* foo = request->getParam("foo");
// work with some params
if (request->hasParam("foo")) {
const AsyncWebParameter* foo = request->getParam("foo");
output["foo"] = foo->value();
}
//serialize and return
// serialize and return
String jsonBuffer;
serializeJson(output, jsonBuffer);
request->send(200, "application/json", jsonBuffer.c_str());
@@ -265,6 +272,10 @@ void setup()
ws.onEvent(onEvent);
server.addHandler(&ws);
// put this last, otherwise it clogs the other requests
// serve static files from LittleFS/www on /
server.serveStatic("/", LittleFS, "/www/");
server.begin();
}
}
@@ -272,5 +283,6 @@ void setup()
void loop()
{
ws.cleanupClients();
Serial.printf("Free Heap: %d\n", esp_get_free_heap_size());
delay(1000);
}

View File

@@ -0,0 +1,2 @@
#define WIFI_SSID "Your_SSID"
#define WIFI_PASS "Your_PASS"

View File

@@ -1,7 +1,8 @@
#!/usr/bin/env node
//stress test the client opening/closing code
const EventSource = require('eventsource');
const url = 'http://192.168.2.131/events';
const url = 'http://psychic.local/events';
async function eventSourceClient() {
console.log(`Starting test`);

View File

@@ -1,8 +1,9 @@
#!/usr/bin/env node
//stress test the http request code
const axios = require('axios');
const url = 'http://192.168.2.131/api';
const url = 'http://psychic.local/api';
const queryParams = {
foo: 'bar',
foo1: 'bar',

View File

@@ -1,37 +1,42 @@
#!/usr/bin/env bash
#Command to install the testers:
# npm install -g autocannon
# npm install
TEST_IP="192.168.2.131"
TEST_TIME=60
LOG_FILE=psychic-http-loadtest.log
TEST_IP="psychic.local"
TEST_TIME=10
#LOG_FILE=psychic-http-loadtest.log
LOG_FILE=_psychic-http-loadtest.json
RESULTS_FILE=http-loadtest-results.csv
TIMEOUT=10000
WORKERS=1
PROTOCOL=http
#PROTOCOL=https
if test -f "$LOG_FILE"; then
rm $LOG_FILE
fi
echo "url,connections,rps,latency,errors" > $RESULTS_FILE
for CONCURRENCY in 1 2 3 4 5 6 7 8 9 10 15 20
#for CONCURRENCY in 20
do
printf "\n\nCLIENTS: *** $CONCURRENCY ***\n\n" >> $LOG_FILE
echo "Testing $CONCURRENCY clients on $PROTOCOL://$TEST_IP/"
#loadtest -c $CONCURRENCY --cores 1 -t $TEST_TIME --timeout $TIMEOUT "$PROTOCOL://$TEST_IP/" --quiet >> $LOG_FILE
autocannon -c $CONCURRENCY -w 1 -d $TEST_TIME --renderStatusCodes "$PROTOCOL://$TEST_IP/" >> $LOG_FILE 2>&1
printf "\n\n----------------\n\n" >> $LOG_FILE
sleep 1
autocannon -c $CONCURRENCY -w $WORKERS -d $TEST_TIME -j "$PROTOCOL://$TEST_IP/" > $LOG_FILE
node parse-http-test.js $LOG_FILE $RESULTS_FILE
sleep 5
done
for CONCURRENCY in 1 2 3 4 5 6 7 8 9 10 15 20
do
echo "Testing $CONCURRENCY clients on $PROTOCOL://$TEST_IP/api"
#loadtest -c $CONCURRENCY --cores 1 -t $TEST_TIME --timeout $TIMEOUT "$PROTOCOL://$TEST_IP/api?foo=bar" --quiet >> $LOG_FILE
autocannon -c $CONCURRENCY -w 1 -d $TEST_TIME --renderStatusCodes "$PROTOCOL://$TEST_IP/api?foo=bar" >> $LOG_FILE 2>&1
printf "\n\n----------------\n\n" >> $LOG_FILE
sleep 1
autocannon -c $CONCURRENCY -w $WORKERS -d $TEST_TIME -j "$PROTOCOL://$TEST_IP/api?foo=bar" > $LOG_FILE
node parse-http-test.js $LOG_FILE $RESULTS_FILE
sleep 5
done
for CONCURRENCY in 1 2 3 4 5 6 7 8 9 10 15 20
do
echo "Testing $CONCURRENCY clients on $PROTOCOL://$TEST_IP/alien.png"
#loadtest -c $CONCURRENCY --cores 1 -t $TEST_TIME --timeout $TIMEOUT "$PROTOCOL://$TEST_IP/alien.png" --quiet >> $LOG_FILE
autocannon -c $CONCURRENCY -w 1 -d $TEST_TIME --renderStatusCodes "$PROTOCOL://$TEST_IP/alien.png" >> $LOG_FILE 2>&1
printf "\n\n----------------\n\n" >> $LOG_FILE
sleep 1
done
autocannon -c $CONCURRENCY -w $WORKERS -d $TEST_TIME -j "$PROTOCOL://$TEST_IP/alien.png" > $LOG_FILE
node parse-http-test.js $LOG_FILE $RESULTS_FILE
sleep 5
done
rm $LOG_FILE

View File

@@ -1,10 +1,11 @@
#!/usr/bin/env bash
#Command to install the testers:
# npm install -g loadtest
# npm install
TEST_IP="192.168.2.131"
TEST_IP="psychic.local"
TEST_TIME=60
LOG_FILE=psychic-websocket-loadtest.log
LOG_FILE=psychic-websocket-loadtest.json
RESULTS_FILE=websocket-loadtest-results.csv
PROTOCOL=ws
#PROTOCOL=wss
@@ -12,20 +13,33 @@ if test -f "$LOG_FILE"; then
rm $LOG_FILE
fi
for CONCURRENCY in 1 2 3 4 5 6 7
echo "url,clients,rps,latency,errors" > $RESULTS_FILE
CORES=1
for CONCURRENCY in 1 2 3 4 5
do
printf "\n\nCLIENTS: *** $CONCURRENCY ***\n\n" >> $LOG_FILE
echo "Testing $CONCURRENCY clients on $PROTOCOL://$TEST_IP/ws"
loadtest -c $CONCURRENCY --cores 1 -t $TEST_TIME --insecure $PROTOCOL://$TEST_IP/ws --quiet 2> /dev/null >> $LOG_FILE
sleep 1
loadtest -c $CONCURRENCY --cores $CORES -t $TEST_TIME --insecure $PROTOCOL://$TEST_IP/ws --quiet 2> /dev/null >> $LOG_FILE
node parse-websocket-test.js $LOG_FILE $RESULTS_FILE
sleep 2
done
for CONNECTIONS in 8 10 16 20
#for CONNECTIONS in 20
CORES=2
for CONNECTIONS in 6 8 10 12 14
do
CONCURRENCY=$((CONNECTIONS / 2))
printf "\n\nCLIENTS: *** $CONNECTIONS ***\n\n" >> $LOG_FILE
echo "Testing $CONNECTIONS clients on $PROTOCOL://$TEST_IP/ws"
loadtest -c $CONCURRENCY --cores 2 -t $TEST_TIME --insecure $PROTOCOL://$TEST_IP/ws --quiet 2> /dev/null >> $LOG_FILE
sleep 1
done
loadtest -c $CONCURRENCY --cores $CORES -t $TEST_TIME --insecure $PROTOCOL://$TEST_IP/ws --quiet 2> /dev/null >> $LOG_FILE
node parse-websocket-test.js $LOG_FILE $RESULTS_FILE
sleep 2
done
CORES=4
for CONNECTIONS in 16 20 24 28 32
do
CONCURRENCY=$((CONNECTIONS / CORES))
echo "Testing $CONNECTIONS clients on $PROTOCOL://$TEST_IP/ws"
loadtest -c $CONCURRENCY --cores $CORES -t $TEST_TIME --insecure $PROTOCOL://$TEST_IP/ws --quiet 2> /dev/null >> $LOG_FILE
node parse-websocket-test.js $LOG_FILE $RESULTS_FILE
sleep 2
done

View File

@@ -1,7 +1,10 @@
{
"dependencies": {
"autocannon": "^7.15.0",
"axios": "^1.6.2",
"csv-writer": "^1.6.0",
"eventsource": "^2.0.2",
"loadtest": "^8.0.9",
"ws": "^8.14.2"
}
}

View File

@@ -0,0 +1,55 @@
const fs = require('fs');
const createCsvWriter = require('csv-writer').createObjectCsvWriter;
// Get the input and output file paths from the command line arguments
const inputFilePath = process.argv[2];
const outputFilePath = process.argv[3];
if (!inputFilePath || !outputFilePath) {
console.error('Usage: node script.js <inputFilePath> <outputFilePath>');
process.exit(1);
}
// Read and parse the JSON file
fs.readFile(inputFilePath, 'utf8', (err, data) => {
if (err) {
console.error('Error reading the input file:', err);
return;
}
// Parse the JSON data
const jsonData = JSON.parse(data);
// Extract the desired fields
const { url, connections, latency, requests, errors } = jsonData;
const latencyMean = latency.mean;
const requestsMean = requests.mean;
// Set up the CSV writer
const csvWriter = createCsvWriter({
path: outputFilePath,
header: [
{id: 'url', title: 'URL'},
{id: 'connections', title: 'Connections'},
{id: 'requestsMean', title: 'Requests Mean'},
{id: 'latencyMean', title: 'Latency Mean'},
{id: 'errors', title: 'Errors'},
],
append: true // this will append to the existing file
});
// Prepare the data to be written
const records = [
{ url: url, connections: connections, latencyMean: latencyMean, requestsMean: requestsMean, errors: errors }
];
// Write the data to the CSV file
csvWriter.writeRecords(records)
.then(() => {
console.log('Data successfully appended to CSV file.');
})
.catch(err => {
console.error('Error writing to the CSV file:', err);
});
});

View File

@@ -0,0 +1,64 @@
const fs = require('fs');
const readline = require('readline');
if (process.argv.length !== 4) {
console.error('Usage: node parse-websocket-test.js <input_file> <output_file>');
process.exit(1);
}
const inputFile = process.argv[2];
const outputFile = process.argv[3];
async function parseFile() {
const fileStream = fs.createReadStream(inputFile);
const rl = readline.createInterface({
input: fileStream,
crlfDelay: Infinity
});
let targetUrl = null;
let totalErrors = null;
let meanLatency = null;
let effectiveRps = null;
let concurrentClients = null;
for await (const line of rl) {
if (line.startsWith('Target URL:')) {
targetUrl = line.split(':').slice(1).join(':').trim();
}
if (line.startsWith('Total errors:')) {
totalErrors = parseInt(line.split(':')[1].trim(), 10);
}
if (line.startsWith('Mean latency:')) {
meanLatency = parseFloat(line.split(':')[1].trim());
}
if (line.startsWith('Effective rps:')) {
effectiveRps = parseInt(line.split(':')[1].trim(), 10);
}
if (line.startsWith('Concurrent clients:')) {
concurrentClients = parseInt(line.split(':')[1].trim(), 10);
}
}
if (targetUrl === null || totalErrors === null || meanLatency === null || effectiveRps === null || concurrentClients === null) {
console.error('Failed to extract necessary data from the input file');
process.exit(1);
}
const csvLine = `${targetUrl},${concurrentClients},${effectiveRps},${meanLatency},${totalErrors}\n`;
fs.appendFile(outputFile, csvLine, (err) => {
if (err) {
console.error('Failed to append to CSV file:', err);
process.exit(1);
}
console.log('Data successfully appended to CSV file.');
});
}
parseFile().catch(err => {
console.error('Error reading file:', err);
process.exit(1);
});

View File

@@ -15,8 +15,14 @@ board = esp32dev
monitor_speed = 115200
monitor_filters = esp32_exception_decoder
lib_deps =
https://github.com/hoeken/PsychicHttp
bblanchon/ArduinoJson
board_build.filesystem = littlefs
[env:default]
lib_deps = https://github.com/hoeken/PsychicHttp
[env:v2-dev]
lib_deps = https://github.com/hoeken/PsychicHttp#v2-dev
board = esp32-s3-devkitc-1
upload_port = /dev/ttyACM0
monitor_port = /dev/ttyACM1

View File

@@ -7,26 +7,30 @@
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <Arduino.h>
#include <WiFi.h>
#include <PsychicHttp.h>
#include <LittleFS.h>
#include <ArduinoJSON.h>
#include "_secret.h"
#include <Arduino.h>
#include <ArduinoJson.h>
#include <ESPmDNS.h>
#include <LittleFS.h>
#include <PsychicHttp.h>
#include <WiFi.h>
#ifndef WIFI_SSID
#error "You need to enter your wifi credentials. Copy secret.h to _secret.h and enter your credentials there."
#endif
//Enter your WIFI credentials in secret.h
const char *ssid = WIFI_SSID;
const char *password = WIFI_PASS;
// Enter your WIFI credentials in secret.h
const char* ssid = WIFI_SSID;
const char* password = WIFI_PASS;
// hostname for mdns (psychic.local)
const char* local_hostname = "psychic";
PsychicHttpServer server;
PsychicWebSocketHandler websocketHandler;
PsychicEventSource eventSource;
const char *htmlContent = R"(
const char* htmlContent = R"(
<!DOCTYPE html>
<html>
<head>
@@ -92,8 +96,8 @@ bool connectToWifi()
Serial.print("[WiFi] Connecting to ");
Serial.println(ssid);
WiFi.setSleep(false);
WiFi.useStaticBuffers(true);
// WiFi.setSleep(false);
// WiFi.useStaticBuffers(true);
WiFi.begin(ssid, password);
@@ -102,10 +106,8 @@ bool connectToWifi()
int numberOfTries = 20;
// Wait for the WiFi event
while (true)
{
switch (WiFi.status())
{
while (true) {
switch (WiFi.status()) {
case WL_NO_SSID_AVAIL:
Serial.println("[WiFi] SSID not found");
break;
@@ -135,15 +137,12 @@ bool connectToWifi()
}
delay(tryDelay);
if (numberOfTries <= 0)
{
if (numberOfTries <= 0) {
Serial.print("[WiFi] Failed to connect to WiFi!");
// Use disconnect function to force stop trying to connect
WiFi.disconnect();
return false;
}
else
{
} else {
numberOfTries--;
}
}
@@ -157,47 +156,42 @@ void setup()
delay(10);
Serial.println("PsychicHTTP Benchmark");
if (connectToWifi())
{
if(!LittleFS.begin())
{
if (connectToWifi()) {
// set up our esp32 to listen on the local_hostname.local domain
if (!MDNS.begin(local_hostname)) {
Serial.println("Error starting mDNS");
return;
}
MDNS.addService("http", "tcp", 80);
if (!LittleFS.begin()) {
Serial.println("LittleFS Mount Failed. Do Platform -> Build Filesystem Image and Platform -> Upload Filesystem Image from VSCode");
return;
}
//start our server
server.listen(80);
// our index
server.on("/", HTTP_GET, [](PsychicRequest* request, PsychicResponse* response) { return response->send(200, "text/html", htmlContent); });
//our index
server.on("/", HTTP_GET, [](PsychicRequest *request)
{
return request->reply(200, "text/html", htmlContent);
});
//serve static files from LittleFS/www on /
// serve static files from LittleFS/www on /
server.serveStatic("/", LittleFS, "/www/");
//a websocket echo server
websocketHandler.onOpen([](PsychicWebSocketClient *client) {
client->sendMessage("Hello!");
});
websocketHandler.onFrame([](PsychicWebSocketRequest *request, httpd_ws_frame *frame) {
request->reply(frame);
return ESP_OK;
// a websocket echo server
websocketHandler.onOpen([](PsychicWebSocketClient* client) {
// client->sendMessage("Hello!");
});
websocketHandler.onFrame([](PsychicWebSocketRequest* request, httpd_ws_frame* frame) {
response->send(frame);
return ESP_OK; });
server.on("/ws", &websocketHandler);
//EventSource server
eventSource.onOpen([](PsychicEventSourceClient *client) {
client->send("Hello", NULL, millis(), 1000);
});
// EventSource server
eventSource.onOpen([](PsychicEventSourceClient* client) { client->send("Hello", NULL, millis(), 1000); });
server.on("/events", &eventSource);
//api - parameters passed in via query eg. /api/endpoint?foo=bar
server.on("/api", HTTP_GET, [](PsychicRequest *request)
{
// api - parameters passed in via query eg. /api/endpoint?foo=bar
server.on("/api", HTTP_GET, [](PsychicRequest* request, PsychicResponse* response) {
//create a response object
StaticJsonDocument<128> output;
JsonDocument output;
output["msg"] = "status";
output["status"] = "success";
output["millis"] = millis();
@@ -212,16 +206,16 @@ void setup()
//serialize and return
String jsonBuffer;
serializeJson(output, jsonBuffer);
return request->reply(200, "application/json", jsonBuffer.c_str());
});
return response->send(200, "application/json", jsonBuffer.c_str()); });
server.begin();
}
}
unsigned long last;
void loop()
{
if (millis() - last > 1000)
{
if (millis() - last > 1000) {
Serial.printf("Free Heap: %d\n", esp_get_free_heap_size());
last = millis();
}

View File

@@ -7,22 +7,21 @@
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <Arduino.h>
#include <WiFi.h>
#include <PsychicHttp.h>
#include <LittleFS.h>
#include <ArduinoJSON.h>
#include "_secret.h"
#include <Arduino.h>
#include <ArduinoJSON.h>
#include <LittleFS.h>
#include <PsychicHttp.h>
#include <PsychicHttpsServer.h>
#include <WiFi.h>
#ifndef WIFI_SSID
#error "You need to enter your wifi credentials. Rename secret.h to _secret.h and enter your credentials there."
#endif
//Enter your WIFI credentials in secret.h
const char *ssid = WIFI_SSID;
const char *password = WIFI_PASS;
// Enter your WIFI credentials in secret.h
const char* ssid = WIFI_SSID;
const char* password = WIFI_PASS;
PsychicHttpsServer server;
PsychicWebSocketHandler websocketHandler;
@@ -30,7 +29,7 @@ PsychicWebSocketHandler websocketHandler;
String server_cert;
String server_key;
const char *htmlContent = R"(
const char* htmlContent = R"(
<!DOCTYPE html>
<html>
<head>
@@ -162,52 +161,56 @@ void setup()
if (connectToWifi())
{
if(!LittleFS.begin())
if (!LittleFS.begin())
{
Serial.println("LittleFS Mount Failed. Do Platform -> Build Filesystem Image and Platform -> Upload Filesystem Image from VSCode");
return;
}
File fp = LittleFS.open("/server.crt");
if (fp) {
if (fp)
{
server_cert = fp.readString();
} else {
}
else
{
Serial.println("server.pem not found, SSL not available");
return;
}
fp.close();
File fp2 = LittleFS.open("/server.key");
if (fp2) {
if (fp2)
{
server_key = fp2.readString();
} else {
}
else
{
Serial.println("server.key not found, SSL not available");
return;
}
fp2.close();
//start our server
server.listen(443, server_cert.c_str(), server_key.c_str());
// start our server
server.setCertificate(server_cert.c_str(), server_key.c_str());
//our index
server.on("/", HTTP_GET, [](PsychicRequest *request)
{
return request->reply(200, "text/html", htmlContent);
});
// our index
server.on("/", HTTP_GET, [](PsychicRequest* request)
{ return response->send(200, "text/html", htmlContent); });
//serve static files from LittleFS/www on /
// serve static files from LittleFS/www on /
server.serveStatic("/", LittleFS, "/www/");
//a websocket echo server
websocketHandler.onFrame([](PsychicWebSocketRequest *request, httpd_ws_frame *frame) {
request->reply(frame);
return ESP_OK;
});
// a websocket echo server
websocketHandler.onFrame([](PsychicWebSocketRequest* request, httpd_ws_frame* frame)
{
response->send(frame);
return ESP_OK; });
server.on("/ws", &websocketHandler);
//api - parameters passed in via query eg. /api/endpoint?foo=bar
server.on("/api", HTTP_GET, [](PsychicRequest *request)
{
// api - parameters passed in via query eg. /api/endpoint?foo=bar
server.on("/api", HTTP_GET, [](PsychicRequest* request)
{
//create a response object
StaticJsonDocument<128> output;
output["msg"] = "status";
@@ -224,8 +227,7 @@ void setup()
//serialize and return
String jsonBuffer;
serializeJson(output, jsonBuffer);
return request->reply(200, "application/json", jsonBuffer.c_str());
});
return response->send(200, "application/json", jsonBuffer.c_str()); });
}
}

View File

@@ -1,8 +1,9 @@
#!/usr/bin/env node
//stress test the client open/close for websockets
const WebSocket = require('ws');
const uri = 'ws://192.168.2.131/ws';
const uri = 'ws://psychic.local/ws';
async function websocketClient() {
console.log(`Starting test`);