diff --git a/data/www/index.html b/data/www/index.html index 508a322..2862670 100644 --- a/data/www/index.html +++ b/data/www/index.html @@ -2,7 +2,7 @@ - ESP Kit + IlluCat diff --git a/data/www/script.js b/data/www/script.js index 424603a..15b4f74 100644 --- a/data/www/script.js +++ b/data/www/script.js @@ -10784,7 +10784,7 @@ Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); -let endpoint = '/pixel'; +let endpoint = '/ws'; // gradients // https://uigradients.com diff --git a/lib/NeoPattern/NeoPatternDto.h b/lib/NeoPattern/NeoPatternDto.h index 145d402..99a1e7a 100644 --- a/lib/NeoPattern/NeoPatternDto.h +++ b/lib/NeoPattern/NeoPatternDto.h @@ -11,11 +11,12 @@ #define ARRAY_LENGTH(array) sizeof(array)/sizeof(array[0]) struct NeoPixelConfig : public JsonStruct { - int pin; - int length; - int brightness; - int updateInterval; - int defaultColor; + // FIXME constants! + int pin = 4; + int length = 8; + int brightness = 100; + int updateInterval = 100; + int defaultColor = 100; // FIXME remove unused void mapJsonObject(JsonObject& root) { root["pin"] = pin; root["length"] = length; @@ -24,11 +25,11 @@ struct NeoPixelConfig : public JsonStruct { root["defaultColor"] = defaultColor; } void fromJsonObject(JsonObject& json) { - pin = getIntAttrFromJson(json, "pin"); - length = getIntAttrFromJson(json, "length"); - brightness = getIntAttrFromJson(json, "brightness"); - updateInterval = getIntAttrFromJson(json, "updateInterval"); - defaultColor = getIntAttrFromJson(json, "defaultColor"); + pin = getIntAttrFromJson(json, "pin", pin); + length = getIntAttrFromJson(json, "length", length); + brightness = getIntAttrFromJson(json, "brightness", brightness); + updateInterval = getIntAttrFromJson(json, "updateInterval", updateInterval); + defaultColor = getIntAttrFromJson(json, "defaultColor", defaultColor); } }; diff --git a/lib/sprocket-utils/utils_ws.h b/lib/sprocket-utils/utils_web.h similarity index 93% rename from lib/sprocket-utils/utils_ws.h rename to lib/sprocket-utils/utils_web.h index 33ea353..0ff8d4a 100644 --- a/lib/sprocket-utils/utils_ws.h +++ b/lib/sprocket-utils/utils_web.h @@ -1,13 +1,19 @@ -#ifndef __WSUTILS_H___ -#define __WSUTILS_H___ +#ifndef __WebUtils_H___ +#define __WebUtils_H___ #include #include #include #include -class WsUtils { +class WebUtils { public: + static String getRequestParameterOrDefault(AsyncWebServerRequest *request, String param, String defaultValue, bool isPost = true){ + if(request->hasParam(param, isPost)) { + return request->getParam(param, isPost)->value(); + } + return defaultValue; + } static String parseFrame(AwsEventType type, void * arg, uint8_t *data, size_t len) { String msg = ""; if(type == WS_EVT_DATA){ diff --git a/src/IlluCat.cpp_ b/src/IlluCat.cpp_ new file mode 100644 index 0000000..890fab4 --- /dev/null +++ b/src/IlluCat.cpp_ @@ -0,0 +1,126 @@ +#include "IlluCat.h" + +IlluCat::IlluCat(SprocketConfig cfg, OtaConfig otaCfg, WebServerConfig webCfg) : Sprocket(cfg) +{ + Serial.println("illucat ctr"); + sprocketConfig = cfg; + otaConfig = otaCfg; + webConfig = webCfg; + pixelConfig.pin = 4; + pixelConfig.length = 8; + pixelConfig.brightness = 32; + pixelConfig.updateInterval = 100; + pixelConfig.defaultColor = 100; + catScheduler = new Scheduler(); +} + +void IlluCat::scanningAnimation() +{ + pixels->Scanner(pixels->Wheel(COLOR_NOT_CONNECTED), pixelConfig.updateInterval); +} +void IlluCat::defaultAnimation() +{ + pixels->RainbowCycle(pixelConfig.updateInterval); +} + +/* Sprocket *IlluCat::activate(Scheduler *scheduler, Network *network) +{ + + // load config files from SPIFFS + if (SPIFFS.begin()) + { + pixelConfig.fromFile("/pixelConfig.json"); + defaultState.fromFile("/pixelState.json"); + state = defaultState; + } + + // initialize services + pixels = new NeoPattern(pixelConfig.length, pixelConfig.pin, NEO_GRB + NEO_KHZ800); + server = new AsyncWebServer(80); + ws = new AsyncWebSocket("/pixel"); + //wsStream = new AsyncWebSocket("/stream"); + defaultAnimation(); + + // add plugins + // TODO add HTTP OTA instead of TCP + //addPlugin(new OtaTcpPlugin(otaConfig)); + addPlugin(new WebServerPlugin(webConfig, server)); + addPlugin(new WebConfigPlugin(server)); + addPlugin(new PixelPlugin(pixelConfig, pixels)); + + // FIXME move to networking + //String softApPrt = "SoftAP IP: " + WiFi.softAPIP().toString(); + //PRINT_MSG(Serial, SPROCKET_TYPE, softApPrt.c_str()); + + // TODO move to plugin + // setup web stuff + server->serveStatic("/pixelConfig.json", SPIFFS, "pixelConfig.json"); + server->on("/pixel/api", HTTP_POST, bind(&IlluCat::patternWebRequestHandler, this, _1)); + ws->onEvent(bind(&IlluCat::onWsEvent, this, _1, _2, _3, _4, _5, _6)); + server->addHandler(ws); + //wsStream->onEvent(bind(&IlluCat::onStream, this, _1, _2, _3, _4, _5, _6)); + //server->addHandler(wsStream); + + return Sprocket::activate(scheduler, network); +} using Sprocket::activate; */ + +// TODO move to utils +/* String IlluCat::getRequestParameterOrDefault(AsyncWebServerRequest *request, String param, String defaultValue, bool isPost) +{ + if (request->hasParam(param, isPost)) + { + return request->getParam(param, isPost)->value(); + } + return defaultValue; +} + +void IlluCat::onStream(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) +{ + if (type == WS_EVT_DATA) + { + PRINT_MSG(Serial, SPROCKET_TYPE, WebUtils::parseFrameAsString(type, arg, data, len, 0).c_str()); + pixels->ActivePattern = NONE; + pixels->handleStream(data, len); + } +} + +void IlluCat::patternWebRequestHandler(AsyncWebServerRequest *request) +{ + PRINT_MSG(Serial, SPROCKET_TYPE, "POST /pixel/api"); + currentMessage.topic = getRequestParameterOrDefault(request, "topic", ""); + currentMessage.payload = getRequestParameterOrDefault(request, "payload", ""); + currentMessage.broadcast = atoi(getRequestParameterOrDefault(request, "broadcast", "0").c_str()); + String msg = currentMessage.toJsonString(); + publish(currentMessage.topic, currentMessage.payload); + if (currentMessage.broadcast) + { + network.broadcast(msg); + } + request->send(200, "text/plain", msg); +} + +void IlluCat::onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) +{ + if (type == WS_EVT_DATA) + { + String frame = WebUtils::parseFrameAsString(type, arg, data, len, 0); + dispatch(0, frame); + network.broadcast(frame); + } +} + +void IlluCat::dispatch(uint32_t from, String &msg) +{ + currentMessage.fromJsonString(msg); + if (currentMessage.valid) + { + currentMessage.from = from; + publish(currentMessage.topic, currentMessage.payload); + } +} + +void IlluCat::loop() +{ + Sprocket::loop(); + yield(); +} */ \ No newline at end of file diff --git a/src/IlluCat.h b/src/IlluCat.h index 9ab820d..4baadcf 100644 --- a/src/IlluCat.h +++ b/src/IlluCat.h @@ -11,11 +11,12 @@ #include "NeoPattern_api_json.h" #include "NeoPattern_api_modes.cpp" #include "utils_print.h" -#include "utils_ws.h" +#include "utils_web.h" #include #include #include #include +#include "WebApi.cpp" #include "PixelPlugin.h" using namespace std; @@ -28,8 +29,6 @@ class IlluCat : public Sprocket { NeoPatternDto defaultState; NeoPatternDto state; AsyncWebServer* server; - AsyncWebSocket* ws; - //AsyncWebSocket* wsStream; NeoPixelConfig pixelConfig; SprocketConfig sprocketConfig; @@ -42,24 +41,14 @@ class IlluCat : public Sprocket { sprocketConfig = cfg; otaConfig = otaCfg; webConfig = webCfg; - pixelConfig.pin = 4; - pixelConfig.length = 8; - pixelConfig.brightness = 32; - pixelConfig.updateInterval = 100; - pixelConfig.defaultColor = 100; } - virtual void scanningAnimation() { - pixels->Scanner(pixels->Wheel(COLOR_NOT_CONNECTED), pixelConfig.updateInterval); - } - virtual void defaultAnimation() { - pixels->RainbowCycle(pixelConfig.updateInterval); - } Sprocket* activate(Scheduler* scheduler, Network* network) { // load config files from SPIFFS if(SPIFFS.begin()){ pixelConfig.fromFile("/pixelConfig.json"); + // FIXME actualy store and load state to use as initial animation defaultState.fromFile("/pixelState.json"); state = defaultState; } @@ -67,72 +56,32 @@ class IlluCat : public Sprocket { // initialize services pixels = new NeoPattern(pixelConfig.length, pixelConfig.pin, NEO_GRB + NEO_KHZ800); server = new AsyncWebServer(80); - ws = new AsyncWebSocket("/pixel"); - //wsStream = new AsyncWebSocket("/stream"); defaultAnimation(); // add plugins + // TODO how can any type of API be linked to another one? // TODO add HTTP OTA instead of TCP //addPlugin(new OtaTcpPlugin(otaConfig)); addPlugin(new WebServerPlugin(webConfig, server)); addPlugin(new WebConfigPlugin(server)); + addPlugin(new WebApi(server, 1)); + // TODO pixel streaming addPlugin(new PixelPlugin(pixelConfig, pixels)); - - // FIXME move to networking - //String softApPrt = "SoftAP IP: " + WiFi.softAPIP().toString(); - //PRINT_MSG(Serial, SPROCKET_TYPE, softApPrt.c_str()); - - // TODO move to plugin // setup web stuff server->serveStatic("/pixelConfig.json", SPIFFS, "pixelConfig.json"); - server->on("/pixel/api", HTTP_POST, bind(&IlluCat::patternWebRequestHandler, this, _1)); - ws->onEvent(bind(&IlluCat::onWsEvent, this, _1, _2, _3, _4, _5, _6)); - server->addHandler(ws); - //wsStream->onEvent(bind(&IlluCat::onStream, this, _1, _2, _3, _4, _5, _6)); - //server->addHandler(wsStream); return Sprocket::activate(scheduler, network); } using Sprocket::activate; - // TODO move to utils - String getRequestParameterOrDefault(AsyncWebServerRequest *request, String param, String defaultValue, bool isPost = true){ - if(request->hasParam(param, isPost)) { - return request->getParam(param, isPost)->value(); - } - return defaultValue; - } - - - void onStream(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len) { - if(type == WS_EVT_DATA){ - PRINT_MSG(Serial, SPROCKET_TYPE, WsUtils::parseFrameAsString(type, arg, data, len, 0).c_str()); - pixels->ActivePattern = NONE; - pixels->handleStream(data, len); - } - } - - void patternWebRequestHandler(AsyncWebServerRequest *request) { - PRINT_MSG(Serial, SPROCKET_TYPE, "POST /pixel/api"); - currentMessage.topic = getRequestParameterOrDefault(request, "topic", ""); - currentMessage.payload = getRequestParameterOrDefault(request, "payload", ""); - currentMessage.broadcast = atoi(getRequestParameterOrDefault(request, "broadcast", "0").c_str()); - String msg = currentMessage.toJsonString(); - publish(currentMessage.topic, currentMessage.payload); - if(currentMessage.broadcast){ - network.broadcast(msg); - } - request->send(200, "text/plain", msg); - } - - virtual void onWsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len) { - if(type == WS_EVT_DATA){ - String frame = WsUtils::parseFrameAsString(type, arg, data, len, 0); - dispatch(0, frame); - network.broadcast(frame); - } + virtual void scanningAnimation() { + pixels->Scanner(pixels->Wheel(COLOR_NOT_CONNECTED), pixelConfig.updateInterval); + } + virtual void defaultAnimation() { + pixels->RainbowCycle(pixelConfig.updateInterval); } + // TODO move to Sprocket virtual void dispatch( uint32_t from, String &msg ) { currentMessage.fromJsonString(msg); if(currentMessage.valid){ @@ -141,10 +90,6 @@ class IlluCat : public Sprocket { } } - void loop(){ - Sprocket::loop(); - yield(); - } }; #endif \ No newline at end of file diff --git a/src/WebApi.cpp b/src/WebApi.cpp new file mode 100644 index 0000000..1c5860c --- /dev/null +++ b/src/WebApi.cpp @@ -0,0 +1,74 @@ +#ifndef __WEBAPI_PLUGIN__ +#define __WEBAPI_PLUGIN__ + +#include +#include + +#include "config.h" +#include "utils_print.h" +#include "utils_web.h" +#include +#include + +using namespace std; +using namespace std::placeholders; + +// TODO headerfile + +class WebApi : public Plugin { + private: + Network* network; + public: + AsyncWebServer* server; + AsyncWebSocket* ws; + SprocketMessage currentMessage; + + int broadcast; + + WebApi(AsyncWebServer* _server, int _broadcast = 0){ + server = _server; + broadcast = _broadcast; + } + + void activate(Scheduler* _scheduler, Network* _network) { + network = _network; + ws = new AsyncWebSocket("/ws"); // FIXME constant /ws + ws->onEvent(bind(&WebApi::onWsEvent, this, _1, _2, _3, _4, _5, _6)); + server->addHandler(ws); + server->on("/api", HTTP_POST, bind(&WebApi::postRequestHandler, this, _1)); + } + + void postRequestHandler(AsyncWebServerRequest *request) { + PRINT_MSG(Serial, SPROCKET_TYPE, "POST WebApi"); + currentMessage.topic = WebUtils::getRequestParameterOrDefault(request, "topic", ""); + currentMessage.payload = WebUtils::getRequestParameterOrDefault(request, "payload", ""); + currentMessage.broadcast = atoi(WebUtils::getRequestParameterOrDefault(request, "broadcast", "0").c_str()); + String msg = currentMessage.toJsonString(); + publish(currentMessage.topic, currentMessage.payload); + if(currentMessage.broadcast){ + network->broadcast(msg); + } + request->send(200, "text/plain", msg); + } + void onWsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len) { + // FIXME to limitted + if(type == WS_EVT_DATA){ + String frame = WebUtils::parseFrameAsString(type, arg, data, len, 0); + dispatch(0, frame); + } + } + + void dispatch( uint32_t from, String &msg ) { + currentMessage.fromJsonString(msg); + if(currentMessage.valid){ + currentMessage.from = from; + publish(currentMessage.topic, currentMessage.payload); + if(broadcast){ + network->broadcast(msg); + } + } + } + +}; + +#endif \ No newline at end of file diff --git a/src/wifi/WebCat.h_ b/src/wifi/WebCat.h_ index 54fb09d..83f6ee8 100644 --- a/src/wifi/WebCat.h_ +++ b/src/wifi/WebCat.h_ @@ -11,7 +11,7 @@ #include "NeoPattern_api_json.h" #include "NeoPattern_api_modes.cpp" #include "utils_print.h" -#include "utils_ws.h" +#include "utils_web.h" #include #include #include @@ -74,7 +74,7 @@ class WebCat : public IlluCat { void onStream(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len) { if(type == WS_EVT_DATA){ - PRINT_MSG(Serial, SPROCKET_TYPE, WsUtils::parseFrameAsString(type, arg, data, len, 0).c_str()); + PRINT_MSG(Serial, SPROCKET_TYPE, WebUtils::parseFrameAsString(type, arg, data, len, 0).c_str()); pixels->ActivePattern = NONE; pixels->handleStream(data, len); } @@ -95,7 +95,7 @@ class WebCat : public IlluCat { virtual void onWsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len) { if(type == WS_EVT_DATA){ - String frame = WsUtils::parseFrameAsString(type, arg, data, len, 0); + String frame = WebUtils::parseFrameAsString(type, arg, data, len, 0); dispatch(0, frame); network.broadcast(frame); }