From dcfbba0996a8588b7902b6a2f3067a3eb52b0d1b Mon Sep 17 00:00:00 2001 From: Etienne M Date: Sun, 20 Mar 2022 22:47:28 +0100 Subject: [PATCH 1/4] working websockets basic implementation --- .github/workflows/main.yml | 3 ++ FirmwareModule.cpp | 2 +- README.md | 21 ++++++---- examples/firmware-main.cpp | 42 ++++++++++++++++++++ web-module.h | 79 +++++++++++++++++++++++++++----------- websocket-example.h | 68 ++++++++++++++++++++++++++++++++ 6 files changed, 184 insertions(+), 31 deletions(-) create mode 100644 examples/firmware-main.cpp create mode 100644 websocket-example.h diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 33adc94..28fc7c6 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -67,6 +67,7 @@ jobs: runs-on: ubuntu-latest env: PIO_ENV_CONF: esp32-latest + FIRMWARE_SRC: firmware-main.cpp # firmware source file to build steps: - name: Retrieve workspace artifact uses: actions/download-artifact@v2 @@ -80,6 +81,8 @@ jobs: pip install --upgrade platformio - name: Build project run: | + # link to correct source file + rm src/main.cpp && ln -s ../lib/$LIB_NAME/examples/$FIRMWARE_SRC src/main.cpp pio run -e $PIO_ENV_CONF - name: Firmware artifact uses: actions/upload-artifact@v2 diff --git a/FirmwareModule.cpp b/FirmwareModule.cpp index fa74c9e..53ff07e 100644 --- a/FirmwareModule.cpp +++ b/FirmwareModule.cpp @@ -47,7 +47,7 @@ void FirmwareModule::setupAll() int i = 0; for (auto module : *FirmwareModule::instances) { - logStr = "[Firmware] module " + std::to_string(i + 1) + " of " + std::to_string(total) + ": "; + logStr = "[Module " + std::to_string(i + 1) + "/" + std::to_string(total) + "] "; logStr += "*** " + module->moduleName + " ***"; Serial.println(logStr.c_str()); module->setup(); diff --git a/README.md b/README.md index 91cbc87..af3a84e 100644 --- a/README.md +++ b/README.md @@ -7,17 +7,22 @@ Aim is to provide useful features commonly used in ESP32 firmware development an Several other benefits among which: - no boilerplate code -- entirely automated build process -- ready to use workspace dev environment -- easy to maintain and evolve +- fully automated build process +- ready to code workspace (available as build artifacts) +- easy to maintain and customize ## Key features: - latest [arduino-esp32](https://github.com/espressif/arduino-esp32) framework ([docs](https://docs.espressif.com/projects/arduino-esp32/en/latest/)): mandatory to use littleFS (not available to date in PIO) - `littleFS` filesystem with strong advantage (over SPIFFS) to support directories. -## Predefined firmwares -A set of predefined firmwares is ready to be used: +## Predefined firmwares and build env +A set of predefined firmwares version is ready to be used: -- mini version -- base version: mini version + network + filesys + web server + web sockets + OTA -- full version: base version + json + +- `firmware-mini`: no deps +- `firmware-base`: `firmware-mini` + network + filesys + web server + web sockets + OTA +- `firmware-cust`: `firmware-base` + json + ... +- `firmware-full`: `firmware-base` + ... + +Customized PIO build environments: +- `legacy` +- `latest`: using latest `arduino-esp32` (v2) diff --git a/examples/firmware-main.cpp b/examples/firmware-main.cpp new file mode 100644 index 0000000..642d844 --- /dev/null +++ b/examples/firmware-main.cpp @@ -0,0 +1,42 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +NetworkModule networkModule; +FilesysModule filesysModule; +WebModule webModule; +TemplateModule testModule; + +/** + * setup + */ +void setup() +{ + Serial.begin(115200); + Serial.println("[ESP32] First log!"); + // AsyncWebSocket ws("/ws");// = new AsyncWebSocket(wsUrl.c_str()); + // // create and bind websocket event handler + // WebSocketImpl wsh(&ws); + // ws.onEvent(wsh.eventHandler); + // webModule.addWebSocket(&ws); + // bind websocket event handler + WebSocketTemplate::aws.onEvent(WebSocketTemplate::eventHandler); + webModule.addWebSocket(&WebSocketTemplate::aws); + // Init all modules + FirmwareModule::setupAll(); +} + +/** + * main loop + */ +void loop() +{ + WebSocketTemplate::aws.cleanupClients(); + // Refresh all modules + FirmwareModule::loopAll(); +} \ No newline at end of file diff --git a/web-module.h b/web-module.h index e63d991..9d3f2c3 100644 --- a/web-module.h +++ b/web-module.h @@ -4,43 +4,78 @@ #include #include #include +// #include +// #include // #include // #include - +/** + * One server per module providing services on specific port: + * http server routes, web sockets, OTA service + * + * WebServer + * -> List of available server routes + * -> List of Websockets implemented + * -> OTA service + */ class WebModule : public FirmwareModule { - static AsyncWebServer server; - static AsyncWebSocket ws; + AsyncWebServer *server; //@todo customize port from constructor + // std::vector *webSockets; public: - WebModule() : FirmwareModule("Web") + WebModule(int serverPort = 80) : FirmwareModule("WebServer") { + server = new AsyncWebServer(serverPort); + // webSockets = new std::vector(); } - void setup() + void loadServerRoutes() { - // WebSocketServerImpl::ws = &ws; - // bind websocket event handler - // ws.onEvent(WebSocketServerImpl::eventHandler); + Serial.println("[WebServer] loading server routes"); + // @todo provide routes as argument + initServerRoutes(server); + Serial.println("[WebServer] Done"); + } + + void addWebSocket(AsyncWebSocket *ws) + { + Serial.println("[WebServer] add web socket"); + // AsyncWebSocket ws(wsRoute); + // // bind websocket event handler + // ws.onEvent(eventHandler); // bind websocket to webserver - server.addHandler(&ws); - Serial.println("[Web - Server] loading server routes"); - initServerRoutes(&server); - Serial.println("[Web - Server] Done"); - // Serial.println(""); + server->addHandler(ws); + // webSockets->push_back(&ws); + Serial.println("[WebServer] Done"); + } - Serial.println("[Web - OTA] Begin serving"); - AsyncElegantOTA.begin(&server); - Serial.println("[Web - OTA] Ok"); + void startOTAService() + { + Serial.println("[WebServer] Starting OTA Update service"); + AsyncElegantOTA.begin(server); + Serial.println("[WebServer] Ok"); + } + + void setup() + { + // Serial.println(""); + // Loading services and routes + loadServerRoutes(); + startOTAService(); + // @todo create and assign websockets externally + // AsyncWebSocket ws("/ws"); + // addWebSocket("/ws"); // Start server - server.begin(); + Serial.println("[WebServer] Starting Server"); + server->begin(); + Serial.println("[WebServer] running!"); } void loop() { - WebModule::ws.cleanupClients(); + // for (auto ws : *webSockets) + // { + // ws->cleanupClients(); + // } } -}; - -AsyncWebServer WebModule::server(80); -AsyncWebSocket WebModule::ws("/ws"); \ No newline at end of file +}; \ No newline at end of file diff --git a/websocket-example.h b/websocket-example.h new file mode 100644 index 0000000..9fda814 --- /dev/null +++ b/websocket-example.h @@ -0,0 +1,68 @@ +#include +#include +#include + +class WebSocketTemplate : public FirmwareModule +{ +public: + static AsyncWebSocket aws; + + // WebSocketImpl(string awsUrl) : FirmwareModule("WebSocket") + // { + // Serial.printf("[WebSocket] creation"); + // aws = new AsyncWebSocket(awsUrl.c_str()); + // } + + static void processClientMessage(void *arg, uint8_t *data, size_t len) + { + Serial.printf("[WebSocket] processClientMessage"); + + AwsFrameInfo *info = (AwsFrameInfo *)arg; + if (info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT) + { + data[len] = 0; + // convert raw data input + std::string dataIn(data, data + len); + // do some process + String dataOut(dataIn.c_str()); + // notify server response to all clients + aws.textAll(dataOut); + } + } + + static void eventHandler(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, + void *arg, uint8_t *data, size_t len) + { + switch (type) + { + case WS_EVT_CONNECT: + Serial.printf("[WebSocket] client #%u connected from %s\n", client->id(), client->remoteIP().toString().c_str()); + break; + case WS_EVT_DISCONNECT: + Serial.printf("[WebSocket] client #%u disconnected\n", client->id()); + break; + case WS_EVT_DATA: + Serial.printf("[WebSocket] Data received"); + processClientMessage(arg, data, len); + break; + case WS_EVT_PONG: + case WS_EVT_ERROR: + break; + } + } + +}; + +AsyncWebSocket WebSocketTemplate::aws("/ws"); + +// static void parseInput(String dataIn); + +// Server response to clients +// @return: a jsonified string +// static String serverOutput() +// { +// // std::string jsonString = "a jsonified string"; +// JSONVar jsarr; +// jsarr["root"]["child"] = String("childValue"); +// String jsonStringOut = JSON.stringify(jsarr); +// return jsonStringOut; //sJsonOutput; \ No newline at end of file From 33d15aaca7a6962d79e761a07ba449ebe3d5c7b4 Mon Sep 17 00:00:00 2001 From: etienne1911 Date: Sun, 20 Mar 2022 22:53:03 +0100 Subject: [PATCH 2/4] fix build conf --- .github/workflows/main.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 28fc7c6..0036123 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -66,6 +66,7 @@ jobs: needs: workspace_setup runs-on: ubuntu-latest env: + LIB_NAME: esp32-toolkit-lib PIO_ENV_CONF: esp32-latest FIRMWARE_SRC: firmware-main.cpp # firmware source file to build steps: @@ -81,7 +82,7 @@ jobs: pip install --upgrade platformio - name: Build project run: | - # link to correct source file + # link to selected firmware source file rm src/main.cpp && ln -s ../lib/$LIB_NAME/examples/$FIRMWARE_SRC src/main.cpp pio run -e $PIO_ENV_CONF - name: Firmware artifact From fc9989fad432593ef0098e4b1bbd6d161cd66ec7 Mon Sep 17 00:00:00 2001 From: Etienne M Date: Wed, 23 Mar 2022 23:20:48 +0100 Subject: [PATCH 3/4] WebSocketService class with json support & service routing --- CamControls.h | 20 ++++++ FirmwareModule.h | 2 +- README.md | 57 +++++++++++------ RovControl.h | 20 ++++++ WebSocket.h | 81 ------------------------ WebSocketService.cpp | 123 +++++++++++++++++++++++++++++++++++++ WebSocketService.h | 30 +++++++++ examples/firmware-main.cpp | 13 ++-- websocket-example.h | 68 -------------------- 9 files changed, 242 insertions(+), 172 deletions(-) create mode 100644 CamControls.h create mode 100644 RovControl.h delete mode 100644 WebSocket.h create mode 100644 WebSocketService.cpp create mode 100644 WebSocketService.h delete mode 100644 websocket-example.h diff --git a/CamControls.h b/CamControls.h new file mode 100644 index 0000000..867b048 --- /dev/null +++ b/CamControls.h @@ -0,0 +1,20 @@ +#include +#include + +class CamControls : FirmwareModule, WebSocketService +{ +public: + CamControls() : FirmwareModule("CamControls"), WebSocketService("camcontrols"){}; + + void process() + { + Serial.println("[CamControls] process message"); + // Most of the time, you can rely on the implicit casts. + // In other case, you can do doc["time"].as(); + // const char *service = jsonMsg["service"]; + int count = jsonMsg["counter"]; + + // Print values. + Serial.println(count); + } +}; \ No newline at end of file diff --git a/FirmwareModule.h b/FirmwareModule.h index b974a74..898a57e 100644 --- a/FirmwareModule.h +++ b/FirmwareModule.h @@ -21,7 +21,7 @@ class FirmwareModule std::string moduleName; public: - FirmwareModule(std::string moduleName = "Default"); + FirmwareModule(std::string moduleName = "defaultmodule"); virtual void onCycle(); diff --git a/README.md b/README.md index af3a84e..58eec97 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,49 @@ # esp32-toolkit-lib -ESP32 firmware building lib +ESP32 firmware build lib -## Purpose +Aim is to provide core features to quickly develop ESP32 firmware for various diy projects, as well as a modular architecture to extend firmware's features . -Aim is to provide useful features commonly used in ESP32 firmware development and a flexible architecture to develop custom firmware modules. +# Quick start + +- Grab a workspace artifact which includes source and project configuration +- Customize wifi settings in `network-module.h`. +- Build one of the default firmware available in exemples by linking main.cpp to the chosen firmware source file. +- Upload to the board using serial interface. -Several other benefits among which: -- no boilerplate code -- fully automated build process -- ready to code workspace (available as build artifacts) -- easy to maintain and customize -## Key features: +## Included frameworks, librairies +The lib makes use of the following libs: - latest [arduino-esp32](https://github.com/espressif/arduino-esp32) framework ([docs](https://docs.espressif.com/projects/arduino-esp32/en/latest/)): mandatory to use littleFS (not available to date in PIO) - `littleFS` filesystem with strong advantage (over SPIFFS) to support directories. +- `ArduinoJson`: provide support for JSON + +# Architecture + +The firmware architecture is made of different modules and services. +A module inherits the `FirmwareModule` class and can overrides `setup`, `loop` methods to provide its own implementation. +In a similar way, a service provides a custom implementation of another service such as `WebSocketService`. + -## Predefined firmwares and build env -A set of predefined firmwares version is ready to be used: +## Core modules +The firmware can embedd several core modules which implements main device features: -- `firmware-mini`: no deps -- `firmware-base`: `firmware-mini` + network + filesys + web server + web sockets + OTA -- `firmware-cust`: `firmware-base` + json + ... -- `firmware-full`: `firmware-base` + ... +- network: provides wifi connectivity in both AP (Access Point) and STA (Client) modes +- filesystem: LittleFS +- webserver +- WebSockets Service +- OTA service -Customized PIO build environments: -- `legacy` -- `latest`: using latest `arduino-esp32` (v2) +## Custom modules +On top of these core modules, firmware can be easily extended through custom modules to provide additional features (such as specific sensor support, ...). +To get included in the main update loop, a custom module inherits the `FirmwareModule` class. +As C++ allows multiple inheritance, it can also inherit a service to make use of it. + +For instance a module requiring acceess to websockets, will inherit both `FirmwareModule` and `WebSocketService` which will forward +received message to process them. + +# Purpose of this project + +- as less as boilerplate code possible +- fully automated build process +- ready to code workspace (available as build artifacts) +- easy to maintain and customize \ No newline at end of file diff --git a/RovControl.h b/RovControl.h new file mode 100644 index 0000000..7b6de5d --- /dev/null +++ b/RovControl.h @@ -0,0 +1,20 @@ +#include +#include + +class RovControl : FirmwareModule, WebSocketService +{ +public: + RovControl() : FirmwareModule("RovControl"), WebSocketService("rovcontrol"){}; + + void process() + { + Serial.println("[RoverControl] process message"); + // Most of the time, you can rely on the implicit casts. + // In other case, you can do doc["time"].as(); + int time = jsonMsg["counter"]; + + // Print values. + // Serial.println(service); + Serial.println(time); + } +}; \ No newline at end of file diff --git a/WebSocket.h b/WebSocket.h deleted file mode 100644 index 501f83b..0000000 --- a/WebSocket.h +++ /dev/null @@ -1,81 +0,0 @@ -#include -#include -#include - -/** - * Websocket server static implementation example - * A client sends its data to the server. - * The server notify all connected clients to synchronize them - */ -class WebSocketServerImpl -{ -public: - // reference to the websocket object - static AsyncWebSocket *ws; - - // instances - static WebSocketServerImpl* instances; - - // WebSocketServerImplem(AsyncWebSocket *wsRef) - // { - // ws = wsRef; - // } - - // websocket event handler - static void eventHandler(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, - void *arg, uint8_t *data, size_t len); - - static void processClientMessage(void *arg, uint8_t *data, size_t len); - - static void parseInput(String dataIn); - - // Server response to clients - // @return: a jsonified string - static String serverOutput(); -}; - -AsyncWebSocket* WebSocketServerImpl::ws = null; - -void WebSocketServerImpl::eventHandler(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, - void *arg, uint8_t *data, size_t len) -{ - switch (type) - { - case WS_EVT_CONNECT: - Serial.printf("WebSocket client #%u connected from %s\n", client->id(), client->remoteIP().toString().c_str()); - break; - case WS_EVT_DISCONNECT: - Serial.printf("WebSocket client #%u disconnected\n", client->id()); - break; - case WS_EVT_DATA: - processClientMessage(arg, data, len); - break; - case WS_EVT_PONG: - case WS_EVT_ERROR: - break; - } -} - -void WebSocketServerImpl::processClientMessage(void *arg, uint8_t *data, size_t len) -{ - AwsFrameInfo *info = (AwsFrameInfo *)arg; - if (info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT) - { - data[len] = 0; - // convert raw data input - std::string dataIn(data, data + len); - // do some process - String dataOut(dataIn.c_str()); - // notify server response to all clients - ws->textAll(dataOut); - } -} - -String WebSocketServerImpl::serverOutput() -{ - // std::string jsonString = "a jsonified string"; - JSONVar jsarr; - jsarr["root"]["child"] = String("childValue"); - String jsonStringOut = JSON.stringify(jsarr); - return jsonStringOut; //sJsonOutput; -}; diff --git a/WebSocketService.cpp b/WebSocketService.cpp new file mode 100644 index 0000000..bcdb0ad --- /dev/null +++ b/WebSocketService.cpp @@ -0,0 +1,123 @@ +#include +#include +AsyncWebSocket WebSocketService::aws("/ws"); +std::vector *WebSocketService::instances = new std::vector(); + +// Allocate the JSON document +// +// Inside the brackets, 200 is the capacity of the memory pool in bytes. +// Don't forget to change this value to match your JSON document. +// Use arduinojson.org/v6/assistant to compute the capacity. +// StaticJsonDocument<200> doc; + +// StaticJsonDocument allocates memory on the stack, it can be +// replaced by DynamicJsonDocument which allocates in the heap. +// +// DynamicJsonDocument doc(200); +StaticJsonDocument<200> WebSocketService::jsonMsg; + +// JSON stub string. +// +// Using a char[], as shown here, enables the "zero-copy" mode. This mode uses +// the minimal amount of memory because the JsonDocument stores pointers to +// the input buffer. +// If you use another type of input, ArduinoJson must copy the strings from +// the input to the JsonDocument, so you need to increase the capacity of the +// JsonDocument. +char jsonDataStub[] = "{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}"; + +WebSocketService::WebSocketService(std::string name) : name(name) +{ + // register service instance + WebSocketService::instances->push_back(this); +} + +void WebSocketService::dispatch(void *arg, uint8_t *data, size_t len) +{ + AwsFrameInfo *info = (AwsFrameInfo *)arg; + if (info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT) + { + data[len] = 0; + // convert raw data input + std::string clientMsg(data, data + len); + std::string serverMsg(""); + + // convert to a json object + DeserializationError error = deserializeJson(jsonMsg, clientMsg); + + // Test if parsing succeeds. + if (!error) + { + // JsonObject jsonObj = jsonMsg.as(); + + // for (JsonPair kv : jsonObj) + // { + // std::string serviceName(kv.key().c_str()); + // JsonObject serviceData = kv.value().as(); + + // } + // dispatch message to corresponding service + std::string serviceName = jsonMsg["service"]; + Serial.println(serviceName.c_str()); + for (auto service : *WebSocketService::instances) + { + Serial.println(service->name.c_str()); + // match service name + if (service->name.compare(serviceName) == 0) + { + std::string log = "[WebSocket] message routed to service " + serviceName; + Serial.println(log.c_str()); + service->process(); + } + } + + serverMsg.append(clientMsg); + } + else + { + Serial.print(F("deserializeJson() failed: ")); + Serial.println(error.f_str()); + } + + // notify server response to all clients + String dataOut(serverMsg.c_str()); + aws.textAll(dataOut); + } +} + +void WebSocketService::eventHandler(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, + void *arg, uint8_t *data, size_t len) +{ + switch (type) + { + case WS_EVT_CONNECT: + Serial.printf("[WebSocket] client #%u connected from %s\n", client->id(), client->remoteIP().toString().c_str()); + break; + case WS_EVT_DISCONNECT: + Serial.printf("[WebSocket] client #%u disconnected\n", client->id()); + break; + case WS_EVT_DATA: + Serial.println("[WebSocket] Data received"); + dispatch(arg, data, len); + break; + case WS_EVT_PONG: + case WS_EVT_ERROR: + break; + } +} + +void WebSocketService::process() +{ + // Most of the time, you can rely on the implicit casts. + // In other case, you can do doc["time"].as(); + const char *sensor = jsonMsg["sensor"]; + long time = jsonMsg["time"]; + double latitude = jsonMsg["data"][0]; + double longitude = jsonMsg["data"][1]; + + // Print values. + Serial.println(sensor); + Serial.println(time); + Serial.println(latitude, 6); + Serial.println(longitude, 6); +} \ No newline at end of file diff --git a/WebSocketService.h b/WebSocketService.h new file mode 100644 index 0000000..0fe9e97 --- /dev/null +++ b/WebSocketService.h @@ -0,0 +1,30 @@ +#pragma once + +#include +#include +#include + +class WebSocketService +{ +public: + static AsyncWebSocket aws; + static std::vector *instances; // the components that will process json message + static StaticJsonDocument<200> jsonMsg; + std::string name = ""; + + // WebSocketImpl(string awsUrl) : FirmwareModule("WebSocket") + // { + // Serial.printf("[WebSocket] creation"); + // aws = new AsyncWebSocket(awsUrl.c_str()); + // } + WebSocketService(std::string name = "defaultservice"); + + static void eventHandler(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, + void *arg, uint8_t *data, size_t len); + + static void dispatch(void *arg, uint8_t *data, size_t len); + + static void parseJson(std::string jsonStr); + + virtual void process(); +}; \ No newline at end of file diff --git a/examples/firmware-main.cpp b/examples/firmware-main.cpp index 642d844..479cfd6 100644 --- a/examples/firmware-main.cpp +++ b/examples/firmware-main.cpp @@ -4,12 +4,17 @@ #include #include #include -#include +#include #include +#include +#include + NetworkModule networkModule; FilesysModule filesysModule; WebModule webModule; +RovControl rovcontrol; +CamControls camcontrols; TemplateModule testModule; /** @@ -25,8 +30,8 @@ void setup() // ws.onEvent(wsh.eventHandler); // webModule.addWebSocket(&ws); // bind websocket event handler - WebSocketTemplate::aws.onEvent(WebSocketTemplate::eventHandler); - webModule.addWebSocket(&WebSocketTemplate::aws); + WebSocketService::aws.onEvent(WebSocketService::eventHandler); + webModule.addWebSocket(&WebSocketService::aws); // Init all modules FirmwareModule::setupAll(); } @@ -36,7 +41,7 @@ void setup() */ void loop() { - WebSocketTemplate::aws.cleanupClients(); + WebSocketService::aws.cleanupClients(); // Refresh all modules FirmwareModule::loopAll(); } \ No newline at end of file diff --git a/websocket-example.h b/websocket-example.h deleted file mode 100644 index 9fda814..0000000 --- a/websocket-example.h +++ /dev/null @@ -1,68 +0,0 @@ -#include -#include -#include - -class WebSocketTemplate : public FirmwareModule -{ -public: - static AsyncWebSocket aws; - - // WebSocketImpl(string awsUrl) : FirmwareModule("WebSocket") - // { - // Serial.printf("[WebSocket] creation"); - // aws = new AsyncWebSocket(awsUrl.c_str()); - // } - - static void processClientMessage(void *arg, uint8_t *data, size_t len) - { - Serial.printf("[WebSocket] processClientMessage"); - - AwsFrameInfo *info = (AwsFrameInfo *)arg; - if (info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT) - { - data[len] = 0; - // convert raw data input - std::string dataIn(data, data + len); - // do some process - String dataOut(dataIn.c_str()); - // notify server response to all clients - aws.textAll(dataOut); - } - } - - static void eventHandler(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, - void *arg, uint8_t *data, size_t len) - { - switch (type) - { - case WS_EVT_CONNECT: - Serial.printf("[WebSocket] client #%u connected from %s\n", client->id(), client->remoteIP().toString().c_str()); - break; - case WS_EVT_DISCONNECT: - Serial.printf("[WebSocket] client #%u disconnected\n", client->id()); - break; - case WS_EVT_DATA: - Serial.printf("[WebSocket] Data received"); - processClientMessage(arg, data, len); - break; - case WS_EVT_PONG: - case WS_EVT_ERROR: - break; - } - } - -}; - -AsyncWebSocket WebSocketTemplate::aws("/ws"); - -// static void parseInput(String dataIn); - -// Server response to clients -// @return: a jsonified string -// static String serverOutput() -// { -// // std::string jsonString = "a jsonified string"; -// JSONVar jsarr; -// jsarr["root"]["child"] = String("childValue"); -// String jsonStringOut = JSON.stringify(jsarr); -// return jsonStringOut; //sJsonOutput; \ No newline at end of file From 6b66c962150be7e9588eef74400b2351b2467dc7 Mon Sep 17 00:00:00 2001 From: etienne1911 Date: Sun, 27 Mar 2022 12:30:48 +0000 Subject: [PATCH 4/4] add missing lib in pio conf --- .config/platformio.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/.config/platformio.ini b/.config/platformio.ini index 61fbbfd..7ef5fd3 100644 --- a/.config/platformio.ini +++ b/.config/platformio.ini @@ -45,6 +45,7 @@ lib_deps = me-no-dev/AsyncTCP@^1.1.1 https://github.com/me-no-dev/ESPAsyncWebServer.git ;use this lib instead of me-no-dev/ESP Async WebServer@^1.2.3 ayushsharma82/AsyncElegantOTA@^2.2.6 + bblanchon/ArduinoJson@^6.19.3 ; esp32m/ESP32 logger@^1.0.2 ; FS ; Wifi