Merge branch 'cleanup' into 'master'

Cleanup

Closes #2

See merge request 0x1d/illucat!4
This commit is contained in:
Patrick Balsiger
2018-11-05 16:15:22 +00:00
16 changed files with 415 additions and 325 deletions

View File

@@ -3,6 +3,10 @@
"text": "None", "text": "None",
"value": ["#000000", "#000000"] "value": ["#000000", "#000000"]
}, },
{
"text": "Stadler",
"value": ["#0B3F75", "#0B3F75"]
},
{ {
"text": "Blu", "text": "Blu",
"value": ["#00416A", "#E4E5E6"] "value": ["#00416A", "#E4E5E6"]

View File

@@ -39,7 +39,7 @@
data-name="pattern" data-name="pattern"
data-topic="pixels/pattern" data-topic="pixels/pattern"
data-default="0" data-default="0"
data-entries='[{"text": "None", "value": "0"}, {"text": "Rainbow", "value": "1"}, {"text": "TheaterChase", "value": "2"}, {"text": "Color Wipe", "value": "3"}, {"text": "Scanner", "value": "4"}, {"text": "Fade", "value": "5"}]' data-entries='[{"text": "None", "value": "0"}, {"text": "Rainbow", "value": "1"}, {"text": "TheaterChase", "value": "2"}, {"text": "Color Wipe", "value": "3"}, {"text": "Scanner", "value": "4"}, {"text": "Fade", "value": "5"}, {"text": "Fire", "value": "6"}]'
></li> ></li>
<li class="form-row ParamSlider" <li class="form-row ParamSlider"
data-name="brightness" data-name="brightness"

View File

@@ -10784,7 +10784,7 @@ Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
let endpoint = '/pixel'; let endpoint = '/ws';
// gradients // gradients
// https://uigradients.com // https://uigradients.com

39
include/readme.txt Normal file
View File

@@ -0,0 +1,39 @@
This directory is intended for project header files.
A header file is a file containing C declarations and macro definitions
to be shared between several project source files. You request the use of a
header file in your project source file (C, C++, etc) located in `src` folder
by including it, with the C preprocessing directive `#include'.
```src/main.c
#include "header.h"
int main (void)
{
...
}
```
Including a header file produces the same results as copying the header file
into each source file that needs it. Such copying would be time-consuming
and error-prone. With a header file, the related declarations appear
in only one place. If they need to be changed, they can be changed in one
place, and programs that include the header file will automatically use the
new version when next recompiled. The header file eliminates the labor of
finding and changing all the copies as well as the risk that a failure to
find one copy will result in inconsistencies within a program.
In C, the usual convention is to give header files names that end with `.h'.
It is most portable to use only letters, digits, dashes, and underscores in
header file names, and at most one dot.
Read more about using header files in official GCC documentation:
* Include Syntax
* Include Operation
* Once-Only Headers
* Computed Includes
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html

View File

@@ -26,7 +26,8 @@ enum pattern
THEATER_CHASE = 2, THEATER_CHASE = 2,
COLOR_WIPE = 3, COLOR_WIPE = 3,
SCANNER = 4, SCANNER = 4,
FADE = 5 FADE = 5,
FIRE = 6
}; };
// Patern directions supported: // Patern directions supported:
enum direction enum direction
@@ -62,16 +63,18 @@ class NeoPattern : public Adafruit_NeoPixel
NeoPattern(uint16_t pixels, uint8_t pin, uint8_t type, void (*callback)(int)) NeoPattern(uint16_t pixels, uint8_t pin, uint8_t type, void (*callback)(int))
: Adafruit_NeoPixel(pixels, pin, type) : Adafruit_NeoPixel(pixels, pin, type)
{ {
frameBuffer = (uint8_t*)malloc(768); frameBuffer = (uint8_t *)malloc(768);
OnComplete = callback; OnComplete = callback;
TotalSteps = numPixels(); TotalSteps = numPixels();
begin();
} }
NeoPattern(uint16_t pixels, uint8_t pin, uint8_t type) NeoPattern(uint16_t pixels, uint8_t pin, uint8_t type)
: Adafruit_NeoPixel(pixels, pin, type) : Adafruit_NeoPixel(pixels, pin, type)
{ {
frameBuffer = (uint8_t*)malloc(768); frameBuffer = (uint8_t *)malloc(768);
TotalSteps = numPixels(); TotalSteps = numPixels();
begin();
} }
void handleStream(uint8_t *data, size_t len) void handleStream(uint8_t *data, size_t len)
@@ -81,12 +84,14 @@ class NeoPattern : public Adafruit_NeoPixel
memcpy(frameBuffer, data, len); memcpy(frameBuffer, data, len);
} }
void drawFrameBuffer(int w, uint8_t *frame, int length){ void drawFrameBuffer(int w, uint8_t *frame, int length)
for (int i = 0; i < length; i++){ {
for (int i = 0; i < length; i++)
{
uint8_t r = frame[i]; uint8_t r = frame[i];
uint8_t g = frame[++i]; uint8_t g = frame[i + 1];
uint8_t b = frame[++i]; uint8_t b = frame[i + 2];
setPixelColor(i, r ,g, b); setPixelColor(i, r, g, b);
} }
} }
@@ -122,8 +127,12 @@ class NeoPattern : public Adafruit_NeoPixel
case FADE: case FADE:
FadeUpdate(); FadeUpdate();
break; break;
case FIRE:
Fire(50, 120);
break;
default: default:
if(bufferSize > 0){ if (bufferSize > 0)
{
drawFrameBuffer(TotalSteps, frameBuffer, bufferSize); drawFrameBuffer(TotalSteps, frameBuffer, bufferSize);
} }
break; break;
@@ -379,6 +388,84 @@ class NeoPattern : public Adafruit_NeoPixel
return Color(WheelPos * 3, 255 - WheelPos * 3, 0); return Color(WheelPos * 3, 255 - WheelPos * 3, 0);
} }
} }
/**
* Effects from https://www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/
*/
void Fire(int Cooling, int Sparking)
{
byte heat[numPixels()];
int cooldown;
// Step 1. Cool down every cell a little
for (int i = 0; i < numPixels(); i++)
{
cooldown = random(0, ((Cooling * 10) / numPixels()) + 2);
if (cooldown > heat[i])
{
heat[i] = 0;
}
else
{
heat[i] = heat[i] - cooldown;
}
}
// Step 2. Heat from each cell drifts 'up' and diffuses a little
for (int k = numPixels() - 1; k >= 2; k--)
{
heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2]) / 3;
}
// Step 3. Randomly ignite new 'sparks' near the bottom
if (random(255) < Sparking)
{
int y = random(7);
heat[y] = heat[y] + random(160, 255);
//heat[y] = random(160,255);
}
// Step 4. Convert heat to LED colors
for (int j = 0; j < numPixels(); j++)
{
setPixelHeatColor(j, heat[j]);
}
showStrip();
}
void setPixelHeatColor(int Pixel, byte temperature)
{
// Scale 'heat' down from 0-255 to 0-191
byte t192 = round((temperature / 255.0) * 191);
// calculate ramp up from
byte heatramp = t192 & 0x3F; // 0..63
heatramp <<= 2; // scale up to 0..252
// figure out which third of the spectrum we're in:
if (t192 > 0x80)
{ // hottest
setPixel(Pixel, 255, 255, heatramp);
}
else if (t192 > 0x40)
{ // middle
setPixel(Pixel, 255, heatramp, 0);
}
else
{ // coolest
setPixel(Pixel, heatramp, 0, 0);
}
}
void setPixel(int Pixel, byte red, byte green, byte blue)
{
setPixelColor(Pixel, Color(red, green, blue));
}
void showStrip()
{
show();
}
}; };
#endif #endif

View File

@@ -11,11 +11,12 @@
#define ARRAY_LENGTH(array) sizeof(array)/sizeof(array[0]) #define ARRAY_LENGTH(array) sizeof(array)/sizeof(array[0])
struct NeoPixelConfig : public JsonStruct { struct NeoPixelConfig : public JsonStruct {
int pin; // FIXME constants!
int length; int pin = 4;
int brightness; int length = 8;
int updateInterval; int brightness = 100;
int defaultColor; int updateInterval = 100;
int defaultColor = 100; // FIXME remove unused
void mapJsonObject(JsonObject& root) { void mapJsonObject(JsonObject& root) {
root["pin"] = pin; root["pin"] = pin;
root["length"] = length; root["length"] = length;
@@ -24,11 +25,11 @@ struct NeoPixelConfig : public JsonStruct {
root["defaultColor"] = defaultColor; root["defaultColor"] = defaultColor;
} }
void fromJsonObject(JsonObject& json) { void fromJsonObject(JsonObject& json) {
pin = getIntAttrFromJson(json, "pin"); pin = getIntAttrFromJson(json, "pin", pin);
length = getIntAttrFromJson(json, "length"); length = getIntAttrFromJson(json, "length", length);
brightness = getIntAttrFromJson(json, "brightness"); brightness = getIntAttrFromJson(json, "brightness", brightness);
updateInterval = getIntAttrFromJson(json, "updateInterval"); updateInterval = getIntAttrFromJson(json, "updateInterval", updateInterval);
defaultColor = getIntAttrFromJson(json, "defaultColor"); defaultColor = getIntAttrFromJson(json, "defaultColor", defaultColor);
} }
}; };

View File

@@ -1,13 +1,19 @@
#ifndef __WSUTILS_H___ #ifndef __WebUtils_H___
#define __WSUTILS_H___ #define __WebUtils_H___
#include <Arduino.h> #include <Arduino.h>
#include <ESPAsyncWebServer.h> #include <ESPAsyncWebServer.h>
#include <AsyncWebSocket.h> #include <AsyncWebSocket.h>
#include <ESPAsyncTCP.h> #include <ESPAsyncTCP.h>
class WsUtils { class WebUtils {
public: 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) { static String parseFrame(AwsEventType type, void * arg, uint8_t *data, size_t len) {
String msg = ""; String msg = "";
if(type == WS_EVT_DATA){ if(type == WS_EVT_DATA){

18
src/IlluCat.cpp_ Normal file
View File

@@ -0,0 +1,18 @@
#include "IlluCat.h"
IlluCat::IlluCat(SprocketConfig cfg, OtaConfig otaCfg, WebServerConfig webCfg) : Sprocket(cfg)
{
sprocketConfig = cfg;
otaConfig = otaCfg;
webConfig = webCfg;
server = new AsyncWebServer(80);
server->serveStatic(PIXEL_CONFIG_FILE, SPIFFS, "pixelConfig.json");
}
void IlluCat::setup()
{
addPlugin(new PixelPlugin());
addPlugin(new WebServerPlugin(webConfig, server));
addPlugin(new WebConfigPlugin(server));
addPlugin(new WebApi(server, 1));
}

View File

@@ -1,5 +1,5 @@
#ifndef __MESH_APP__ #ifndef __ILLUCAT__
#define __MESH_APP__ #define __ILLUCAT__
#include <TaskScheduler.h> #include <TaskScheduler.h>
#include <MeshNet.h> #include <MeshNet.h>
@@ -8,14 +8,11 @@
#include "config.h" #include "config.h"
#include "NeoPattern.cpp" #include "NeoPattern.cpp"
#include "NeoPatternDto.h" #include "NeoPatternDto.h"
#include "NeoPattern_api_json.h"
#include "NeoPattern_api_modes.cpp"
#include "utils_print.h"
#include "utils_ws.h"
#include <plugins/WebSO.h> #include <plugins/WebSO.h>
#include <plugins/OtaTcpPlugin.cpp> #include <plugins/OtaTcpPlugin.cpp>
#include <plugins/WebServerPlugin.cpp> #include <plugins/WebServerPlugin.cpp>
#include <plugins/WebConfigPlugin.cpp> #include <plugins/WebConfigPlugin.cpp>
#include "WebApi.cpp"
#include "PixelPlugin.h" #include "PixelPlugin.h"
using namespace std; using namespace std;
@@ -24,127 +21,26 @@ using namespace std::placeholders;
class IlluCat : public Sprocket { class IlluCat : public Sprocket {
public: public:
NeoPattern* pixels;
NeoPatternDto defaultState;
NeoPatternDto state;
AsyncWebServer* server; AsyncWebServer* server;
AsyncWebSocket* ws;
//AsyncWebSocket* wsStream;
NeoPixelConfig pixelConfig;
SprocketConfig sprocketConfig; SprocketConfig sprocketConfig;
OtaConfig otaConfig; OtaConfig otaConfig;
WebServerConfig webConfig; WebServerConfig webConfig;
SprocketMessage currentMessage;
IlluCat(SprocketConfig cfg, OtaConfig otaCfg, WebServerConfig webCfg) : Sprocket(cfg) { IlluCat(SprocketConfig cfg, OtaConfig otaCfg, WebServerConfig webCfg) : Sprocket(cfg) {
sprocketConfig = cfg; sprocketConfig = cfg;
otaConfig = otaCfg; otaConfig = otaCfg;
webConfig = webCfg; 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");
defaultState.fromFile("/pixelState.json");
state = defaultState;
}
// initialize services
pixels = new NeoPattern(pixelConfig.length, pixelConfig.pin, NEO_GRB + NEO_KHZ800);
server = new AsyncWebServer(80); server = new AsyncWebServer(80);
ws = new AsyncWebSocket("/pixel"); server->serveStatic(PIXEL_CONFIG_FILE, SPIFFS, "pixelConfig.json");
//wsStream = new AsyncWebSocket("/stream"); }
defaultAnimation();
// add plugins void setup(){
// TODO add HTTP OTA instead of TCP addPlugin(new PixelPlugin());
//addPlugin(new OtaTcpPlugin(otaConfig));
addPlugin(new WebServerPlugin(webConfig, server)); addPlugin(new WebServerPlugin(webConfig, server));
addPlugin(new WebConfigPlugin(server)); addPlugin(new WebConfigPlugin(server));
addPlugin(new PixelPlugin(pixelConfig, pixels)); addPlugin(new WebApi(server, 1));
// 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 dispatch( uint32_t from, String &msg ) {
currentMessage.fromJsonString(msg);
if(currentMessage.valid){
currentMessage.from = from;
publish(currentMessage.topic, currentMessage.payload);
}
}
void loop(){
Sprocket::loop();
yield();
}
}; };
#endif #endif

127
src/PixelPlugin.cpp Normal file
View File

@@ -0,0 +1,127 @@
#include "PixelPlugin.h"
PixelPlugin::PixelPlugin(NeoPixelConfig cfg, NeoPattern *neoPattern)
{
pixelConfig = cfg;
pixels = neoPattern;
applyConfig(pixelConfig);
defaultAnimation();
}
PixelPlugin::PixelPlugin(NeoPattern *neoPattern)
{
pixels = neoPattern;
loadConfigFromFile();
applyConfig(pixelConfig);
defaultAnimation();
}
PixelPlugin::PixelPlugin()
{
loadConfigFromFile();
pixels = new NeoPattern(pixelConfig.length, pixelConfig.pin, NEO_GRB + NEO_KHZ800);
applyConfig(pixelConfig);
defaultAnimation();
}
void PixelPlugin::loadConfigFromFile(){
if (SPIFFS.begin()){
pixelConfig.fromFile(PIXEL_CONFIG_FILE);
}
}
void PixelPlugin::applyConfig(NeoPixelConfig cfg)
{
pixels->setBrightness(pixelConfig.brightness);
}
void PixelPlugin::defaultAnimation() {
pixels->RainbowCycle(pixelConfig.updateInterval);
animate();
}
void PixelPlugin::activate(Scheduler *userScheduler, Network *network)
{
animation.set(TASK_MILLISECOND * pixelConfig.updateInterval, TASK_FOREVER, bind(&PixelPlugin::animate, this));
userScheduler->addTask(animation);
animation.enable();
subscribe("pixels/colorWheel", bind(&PixelPlugin::colorWheel, this, _1));
subscribe("pixels/color", bind(&PixelPlugin::setColor, this, _1));
subscribe("pixels/color2", bind(&PixelPlugin::setColor2, this, _1));
subscribe("pixels/pattern", bind(&PixelPlugin::setPattern, this, _1));
subscribe("pixels/totalSteps", bind(&PixelPlugin::setTotalSteps, this, _1));
subscribe("pixels/brightness", bind(&PixelPlugin::setBrightness, this, _1));
subscribe("pixels/state", bind(&PixelPlugin::setState, this, _1));
PRINT_MSG(Serial, SPROCKET_TYPE, "NeoPixels activated");
}
void PixelPlugin::setState(String msg)
{
PRINT_MSG(Serial, SPROCKET_TYPE, msg.c_str());
state.fromJsonString(msg);
//pixels->setBrightness(state.brightness);
//pixels->ColorSet(state.color);
pixels->Index = 0;
pixels->Color1 = state.color;
pixels->Color2 = state.color2;
pixels->TotalSteps = state.totalSteps;
pixels->ActivePattern = (pattern)state.pattern;
pixels->Direction = FORWARD;
}
void PixelPlugin::colorWheel(String msg)
{
int color = atoi(msg.c_str());
pixels->ActivePattern = NONE;
pixels->ColorSet(pixels->Wheel(color));
}
void PixelPlugin::setTotalSteps(String msg)
{
pixels->TotalSteps = atoi(msg.c_str());
}
void PixelPlugin::setBrightness(String msg)
{
int inVal = atoi(msg.c_str());
pixels->setBrightness(inVal);
pixels->show();
}
void PixelPlugin::setColor(String msg)
{
pixels->ActivePattern = NONE;
pixels->Color1 = atoi(msg.c_str());
//if(pixels->ActivePattern == NONE){
pixels->ColorSet(pixels->Color1);
//}
}
void PixelPlugin::setColor2(String msg)
{
pixels->Color2 = atoi(msg.c_str());
}
void PixelPlugin::setPattern(String msg)
{
pixels->Index = 0;
pixels->Direction = FORWARD;
pixels->ActivePattern = (pattern)atoi(msg.c_str());
}
void PixelPlugin::animate()
{
pixels->Update();
}
void PixelPlugin::enable()
{
animation.enable();
}
void PixelPlugin::disable()
{
animation.disable();
}

View File

@@ -9,10 +9,15 @@
#include "Plugin.h" #include "Plugin.h"
#include "NeoPatternDto.h" #include "NeoPatternDto.h"
#include "NeoPattern.cpp" #include "NeoPattern.cpp"
#include "config.h"
using namespace std; using namespace std;
using namespace std::placeholders; using namespace std::placeholders;
#ifndef PIXEL_CONFIG_FILE
#define PIXEL_CONFIG_FILE "/pixelConfig.json"
#endif
class PixelPlugin : public Plugin { class PixelPlugin : public Plugin {
private: private:
NeoPixelConfig pixelConfig; NeoPixelConfig pixelConfig;
@@ -20,77 +25,24 @@ class PixelPlugin : public Plugin {
NeoPatternState state; NeoPatternState state;
public: public:
Task animation; Task animation;
PixelPlugin(NeoPixelConfig cfg, NeoPattern* neoPattern){ PixelPlugin(NeoPixelConfig cfg, NeoPattern* neoPattern);
pixelConfig = cfg; PixelPlugin(NeoPattern *neoPattern);
pixels = neoPattern; PixelPlugin();
pixels->begin(); void loadConfigFromFile();
pixels->setBrightness(pixelConfig.brightness); void applyConfig(NeoPixelConfig cfg);
void applyConfigFromFile();
} void activate(Scheduler* userScheduler, Network* network);
void activate(Scheduler* userScheduler, Network* network){ void defaultAnimation();
subscribe("pixels/colorWheel", bind(&PixelPlugin::colorWheel, this, _1)); void setState(String msg);
subscribe("pixels/color", bind(&PixelPlugin::setColor, this, _1)); void colorWheel(String msg);
subscribe("pixels/color2", bind(&PixelPlugin::setColor2, this, _1)); void setTotalSteps(String msg);
subscribe("pixels/pattern", bind(&PixelPlugin::setPattern, this, _1)); void setBrightness(String msg);
subscribe("pixels/totalSteps", bind(&PixelPlugin::setTotalSteps, this, _1)); void setColor(String msg);
subscribe("pixels/brightness", bind(&PixelPlugin::setBrightness, this, _1)); void setColor2(String msg);
subscribe("pixels/state", bind(&PixelPlugin::setState, this, _1)); void setPattern(String msg);
void animate();
animation.set(TASK_MILLISECOND * pixelConfig.updateInterval, TASK_FOREVER, bind(&PixelPlugin::animate, this)); void enable();
userScheduler->addTask(animation); void disable();
animation.enable();
PRINT_MSG(Serial, SPROCKET_TYPE, "NeoPixels activated");
}
void setState(String msg) {
PRINT_MSG(Serial, SPROCKET_TYPE, msg.c_str());
state.fromJsonString(msg);
//pixels->setBrightness(state.brightness);
//pixels->ColorSet(state.color);
pixels->Index = 0;
pixels->Color1 = state.color;
pixels->Color2 = state.color2;
pixels->TotalSteps = state.totalSteps;
pixels->ActivePattern = (pattern) state.pattern;
pixels->Direction = FORWARD;
}
void colorWheel(String msg){
int color = atoi(msg.c_str());
pixels->ActivePattern = NONE;
pixels->ColorSet(pixels->Wheel(color));
}
void setTotalSteps(String msg){
pixels->TotalSteps = atoi(msg.c_str());
}
void setBrightness(String msg){
int inVal = atoi(msg.c_str());
pixels->setBrightness(inVal);
pixels->show();
}
void setColor(String msg){
pixels->ActivePattern = NONE;
pixels->Color1 = atoi(msg.c_str());
//if(pixels->ActivePattern == NONE){
pixels->ColorSet(pixels->Color1);
//}
}
void setColor2(String msg){
pixels->Color2 = atoi(msg.c_str());
}
void setPattern(String msg){
pixels->Index = 0;
pixels->Direction = FORWARD;
pixels->ActivePattern = (pattern)atoi(msg.c_str());
}
void animate(){
pixels->Update();
}
void enable(){
animation.enable();
}
void disable(){
animation.disable();
}
}; };
#endif #endif

74
src/WebApi.cpp Normal file
View File

@@ -0,0 +1,74 @@
#ifndef __WEBAPI_PLUGIN__
#define __WEBAPI_PLUGIN__
#include <TaskSchedulerDeclarations.h>
#include <Sprocket.h>
#include "config.h"
#include "utils_print.h"
#include "utils_web.h"
#include <plugins/WebServerPlugin.cpp>
#include <plugins/WebConfigPlugin.cpp>
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

View File

@@ -25,6 +25,8 @@
#define MESH_DEBUG_TYPES ERROR | STARTUP | CONNECTION #define MESH_DEBUG_TYPES ERROR | STARTUP | CONNECTION
//ERROR | MESH_STATUS | CONNECTION | SYNC | COMMUNICATION | GENERAL | MSG_TYPES | REMOTE //ERROR | MESH_STATUS | CONNECTION | SYNC | COMMUNICATION | GENERAL | MSG_TYPES | REMOTE
#define PIXEL_CONFIG_FILE "/pixelConfig.json"
// OTA config // OTA config
#define OTA_PORT 8266 #define OTA_PORT 8266
#define OTA_PASSWORD "" #define OTA_PASSWORD ""

View File

@@ -1,118 +0,0 @@
#ifndef __WEB_CAT__
#define __WEB_CAT__
#include <TaskScheduler.h>
#include <MeshNet.h>
#include <Sprocket.h>
#include "config.h"
#include "NeoPattern.cpp"
#include "NeoPatternDto.h"
#include "NeoPattern_api_json.h"
#include "NeoPattern_api_modes.cpp"
#include "utils_print.h"
#include "utils_ws.h"
#include <plugins/WebSO.h>
#include <plugins/OtaTcpPlugin.cpp>
#include <plugins/WebServerPlugin.cpp>
#include <plugins/WebConfigPlugin.cpp>
#include "PixelPlugin.h"
#include "IlluCat.h"
using namespace std;
using namespace std::placeholders;
class WebCat : public IlluCat {
public:
AsyncWebServer* server;
AsyncWebSocket* ws;
//AsyncWebSocket* wsStream;
WebServerConfig webConfig;
SprocketMessage currentMessage;
WebCat(SprocketConfig cfg, OtaConfig otaCfg, WebServerConfig webCfg) : IlluCat(cfg, otaCfg, webCfg) {
webConfig = webCfg;
}
Sprocket* activate(Scheduler* scheduler, Network* network) {
Serial.println("SETUP SERVER");
// initialize services
server = new AsyncWebServer(80);
ws = new AsyncWebSocket("/pixel");
//wsStream = new AsyncWebSocket("/stream");
Serial.println("init handlers");
// TODO move to plugin
// setup web stuff
server->serveStatic("/pixelConfig.json", SPIFFS, "pixelConfig.json");
server->on("/pixel/api", HTTP_POST, bind(&WebCat::patternWebRequestHandler, this, _1));
ws->onEvent(bind(&WebCat::onWsEvent, this, _1, _2, _3, _4, _5, _6));
server->addHandler(ws);
//wsStream->onEvent(bind(&WebCat::onStream, this, _1, _2, _3, _4, _5, _6));
//server->addHandler(wsStream);
Serial.println("add plugins");
// add plugins
// TODO add HTTP OTA instead of TCP
//addPlugin(new OtaTcpPlugin(otaConfig));
addPlugin(new WebServerPlugin(webConfig, server));
addPlugin(new WebConfigPlugin(server));
return IlluCat::activate(scheduler, network);;
};
// 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 dispatch( uint32_t from, String &msg ) {
currentMessage.fromJsonString(msg);
if(currentMessage.valid){
currentMessage.from = from;
publish(currentMessage.topic, currentMessage.payload);
}
}
void loop(){
Sprocket::loop();
yield();
}
};
#endif

View File

@@ -18,6 +18,7 @@ IlluCat sprocket(
); );
void setup() { void setup() {
sprocket.setup();
sprocket.join(net); sprocket.join(net);
} }

View File

@@ -15,6 +15,7 @@ MeshCat sprocket(
); );
void setup() { void setup() {
sprocket.setup();
sprocket.join(net); sprocket.join(net);
} }