separate declaration and implementation

This commit is contained in:
2018-11-15 16:38:09 +01:00
parent 09cd0b029a
commit 3f1803a005
11 changed files with 391 additions and 339 deletions

View File

@@ -23,6 +23,10 @@
<span class="heading">System</span>
<div class="content">
<div><label>Free Heap: </label><span class="js-heap"></span><span>&nbsp;bytes</span><br><br></div>
<form method='POST' action='/update' enctype='multipart/form-data'>
<input type='file' name='update'><input type='submit' value='Update'>
</form>
<br>
<button class="js-restart">Restart</button>
</div>
</div>

View File

@@ -31,7 +31,7 @@
.sui label {
color: #b3b2b2;
}
.sui button {
.sui button, .sui input[type=file] {
background: #097479;
color: #eeeeee;
font-size: 0.9em;

View File

@@ -1,54 +1,29 @@
#ifndef __WEBAPI_PLUGIN__
#define __WEBAPI_PLUGIN__
#include "WebApiPlugin.h"
#include <TaskSchedulerDeclarations.h>
#include <Sprocket.h>
#include <Updater.h>
#include "config.h"
#include "utils/utils_print.h"
#include "WebUtils.h"
#include "WebServerPlugin.cpp"
#include "WebConfigPlugin.cpp"
using namespace std;
using namespace std::placeholders;
// TODO headerfile
// FIXME constants
class WebApiPlugin : public Plugin
{
public:
AsyncWebServer *server;
AsyncWebSocket *ws;
SprocketMessage currentMessage;
WebApiPlugin(AsyncWebServer *_server)
WebApiPlugin::WebApiPlugin(AsyncWebServer *_server)
{
server = _server;
Update.runAsync(true);
}
void activate(Scheduler *_scheduler)
void WebApiPlugin::activate(Scheduler *_scheduler)
{
ws = new AsyncWebSocket("/ws");
ws->onEvent(bind(&WebApiPlugin::onWsEvent, this, _1, _2, _3, _4, _5, _6));
server->addHandler(ws);
server->on("/api", HTTP_POST, bind(&WebApiPlugin::postRequestHandler, this, _1));
server->on("/update", HTTP_GET, bind(&WebApiPlugin::simpleFirmwareUploadFormvoid, this, _1));
server->on("/update", HTTP_GET, bind(&WebApiPlugin::simpleFirmwareUploadForm, this, _1));
server->on("/update", HTTP_POST, bind(&WebApiPlugin::onFirmwareUpdateRequest, this, _1), bind(&WebApiPlugin::onFirmwareUpload, this, _1, _2, _3, _4, _5, _6));
subscribe("ws/broadcast", bind(&WebApiPlugin::wsBroadcast, this, _1));
PRINT_MSG(Serial, "WEB", "API activated");
}
void wsBroadcast(String msg)
void WebApiPlugin::wsBroadcast(String msg)
{
ws->textAll(msg);
}
void postRequestHandler(AsyncWebServerRequest *request)
void WebApiPlugin::postRequestHandler(AsyncWebServerRequest *request)
{
PRINT_MSG(Serial, "WEB", "POST WebApiPlugin");
currentMessage.topic = WebUtils::getRequestParameterOrDefault(request, "topic", "");
@@ -58,7 +33,7 @@ class WebApiPlugin : public Plugin
publish(currentMessage.topic, currentMessage.payload);
request->send(200, "text/plain", msg);
}
void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len)
void WebApiPlugin::onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len)
{
// FIXME to limitted
if (type == WS_EVT_DATA)
@@ -68,12 +43,12 @@ class WebApiPlugin : public Plugin
}
}
void simpleFirmwareUploadFormvoid(AsyncWebServerRequest *request)
void WebApiPlugin::simpleFirmwareUploadForm(AsyncWebServerRequest *request)
{
request->send(200, "text/html", "<form method='POST' action='/update' enctype='multipart/form-data'><input type='file' name='update'><input type='submit' value='Update'></form>");
}
void onFirmwareUpdateRequest(AsyncWebServerRequest *request)
void WebApiPlugin::onFirmwareUpdateRequest(AsyncWebServerRequest *request)
{
bool hasError = !Update.hasError();
AsyncWebServerResponse *response = request->beginResponse(200, "text/plain", hasError ? "OK" : "FAIL");
@@ -82,7 +57,7 @@ class WebApiPlugin : public Plugin
publish("esp/reboot", String(hasError));
}
void onFirmwareUpload(AsyncWebServerRequest *request, const String &filename, size_t index, uint8_t *data, size_t len, bool final)
void WebApiPlugin::onFirmwareUpload(AsyncWebServerRequest *request, const String &filename, size_t index, uint8_t *data, size_t len, bool final)
{
if (!index)
{
@@ -113,7 +88,7 @@ class WebApiPlugin : public Plugin
}
}
void dispatch(String &msg)
void WebApiPlugin::dispatch(String &msg)
{
currentMessage.fromJsonString(msg);
if (currentMessage.valid)
@@ -121,6 +96,3 @@ class WebApiPlugin : public Plugin
publish(currentMessage.topic, currentMessage.payload);
}
}
};
#endif

36
src/WebApiPlugin.h Normal file
View File

@@ -0,0 +1,36 @@
#ifndef __WEBAPI_PLUGIN__
#define __WEBAPI_PLUGIN__
#include <TaskSchedulerDeclarations.h>
#include <Sprocket.h>
#include <Updater.h>
#include "config.h"
#include "utils/utils_print.h"
#include "WebUtils.h"
#include "WebServerPlugin.h"
#include "WebConfigPlugin.h"
using namespace std;
using namespace std::placeholders;
class WebApiPlugin : public Plugin
{
public:
AsyncWebServer *server;
AsyncWebSocket *ws;
SprocketMessage currentMessage;
WebApiPlugin(AsyncWebServer *_server);
void activate(Scheduler *_scheduler);
void wsBroadcast(String msg);
void postRequestHandler(AsyncWebServerRequest *request);
void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len);
void simpleFirmwareUploadForm(AsyncWebServerRequest *request);
void onFirmwareUpdateRequest(AsyncWebServerRequest *request);
void onFirmwareUpload(AsyncWebServerRequest *request, const String &filename, size_t index, uint8_t *data, size_t len, bool final);
void dispatch(String &msg);
};
#endif

View File

@@ -1,28 +1,11 @@
#ifndef __WEB_CONFIG_PLUGIN_H__
#define __WEB_CONFIG_PLUGIN_H__
#include "WebConfigPlugin.h"
#include <FS.h>
#include <ESPAsyncWebServer.h>
#include <TaskSchedulerDeclarations.h>
#include "Plugin.h"
#include "WebServerConfig.h"
#include "utils/utils_print.h"
using namespace std;
using namespace std::placeholders;
class WebConfigPlugin : public Plugin
{
private:
AsyncWebServer *server;
public:
WebConfigPlugin(AsyncWebServer *webServer)
WebConfigPlugin::WebConfigPlugin(AsyncWebServer *webServer)
{
server = webServer;
server->serveStatic("/config.json", SPIFFS, "config.json");
}
void activate(Scheduler *userScheduler)
void WebConfigPlugin::activate(Scheduler *userScheduler)
{
server->on("/heap", HTTP_GET, [](AsyncWebServerRequest *request) {
PRINT_MSG(Serial, "WEB", "GET /heap");
@@ -51,6 +34,3 @@ class WebConfigPlugin : public Plugin
});
PRINT_MSG(Serial, "WEB", "WebConfig activated");
}
};
#endif

24
src/WebConfigPlugin.h Normal file
View File

@@ -0,0 +1,24 @@
#ifndef __WEB_CONFIG_PLUGIN_H__
#define __WEB_CONFIG_PLUGIN_H__
#include <FS.h>
#include <ESPAsyncWebServer.h>
#include <TaskSchedulerDeclarations.h>
#include "Plugin.h"
#include "WebServerConfig.h"
#include "utils/utils_print.h"
using namespace std;
using namespace std::placeholders;
class WebConfigPlugin : public Plugin
{
private:
AsyncWebServer *server;
public:
WebConfigPlugin(AsyncWebServer *webServer);
void activate(Scheduler *userScheduler);
};
#endif

View File

@@ -1,34 +1,16 @@
#ifndef __WEB_SERVER_PLUGIN__
#define __WEB_SERVER_PLUGIN__
#include "WebServerPlugin.h"
#include <FS.h>
#include <ESPAsyncWebServer.h>
#include "TaskSchedulerDeclarations.h"
#include "Plugin.h"
#include "WebServerConfig.h"
#include "utils/utils_print.h"
using namespace std;
using namespace std::placeholders;
class WebServerPlugin : public Plugin
{
private:
WebServerConfig config;
public:
AsyncWebServer *server;
WebServerPlugin(WebServerConfig cfg)
WebServerPlugin::WebServerPlugin(WebServerConfig cfg)
{
config = cfg;
server = new AsyncWebServer(config.port);
}
WebServerPlugin(WebServerConfig cfg, AsyncWebServer *webServer)
WebServerPlugin::WebServerPlugin(WebServerConfig cfg, AsyncWebServer *webServer)
{
config = cfg;
server = webServer;
}
void activate(Scheduler *userScheduler)
void WebServerPlugin::activate(Scheduler *userScheduler)
{
AsyncStaticWebHandler &staticWebHandler = server->serveStatic(config.contextPath, SPIFFS, config.docRoot).setDefaultFile(config.defaultFile);
if (config.useBasicAuth)
@@ -38,6 +20,3 @@ class WebServerPlugin : public Plugin
server->begin();
PRINT_MSG(Serial, "WEB", "Server activated");
}
};
#endif

26
src/WebServerPlugin.h Normal file
View File

@@ -0,0 +1,26 @@
#ifndef __WEB_SERVER_PLUGIN__
#define __WEB_SERVER_PLUGIN__
#include <FS.h>
#include <ESPAsyncWebServer.h>
#include "TaskSchedulerDeclarations.h"
#include "Plugin.h"
#include "WebServerConfig.h"
#include "utils/utils_print.h"
using namespace std;
using namespace std::placeholders;
class WebServerPlugin : public Plugin
{
private:
WebServerConfig config;
public:
AsyncWebServer *server;
WebServerPlugin(WebServerConfig cfg);
WebServerPlugin(WebServerConfig cfg, AsyncWebServer *webServer);
void activate(Scheduler *userScheduler);
};
#endif

160
src/WebUtils.cpp Normal file
View File

@@ -0,0 +1,160 @@
#include "WebUtils.h"
String WebUtils::getRequestParameterOrDefault(AsyncWebServerRequest *request, String param, String defaultValue, bool isPost)
{
if (request->hasParam(param, isPost))
{
return request->getParam(param, isPost)->value();
}
return defaultValue;
}
String WebUtils::parseFrame(AwsEventType type, void *arg, uint8_t *data, size_t len)
{
String msg = "";
if (type == WS_EVT_DATA)
{
AwsFrameInfo *info = (AwsFrameInfo *)arg;
if (info->opcode == WS_TEXT)
{
for (size_t i = 0; i < info->len; i++)
{
msg += (char)data[i];
}
}
else
{
char buff[3];
for (size_t i = 0; i < info->len; i++)
{
sprintf(buff, "%02x ", (uint8_t)data[i]);
msg += buff;
}
}
}
return msg;
}
String WebUtils::parseFrameAsString(AwsEventType type, void *arg, uint8_t *data, size_t len, int start)
{
String msg = "";
if (type == WS_EVT_DATA)
{
AwsFrameInfo *info = (AwsFrameInfo *)arg;
//if(info->final && info->index == 0 && info->len == len){
if (info->opcode == WS_TEXT)
{
for (size_t i = start; i < info->len; i++)
{
msg += (char)data[i];
}
}
else
{
char buff[3];
for (size_t i = start; i < info->len; i++)
{
sprintf(buff, "%02x ", (uint8_t)data[i]);
msg += buff;
}
}
//}
}
return msg;
}
void WebUtils::wsEventPrint(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len)
{
if (type == WS_EVT_CONNECT)
{
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)
{
Serial.printf("ws[%s][%u] disconnect: %u\n", server->url(), client->id());
}
else if (type == WS_EVT_ERROR)
{
Serial.printf("ws[%s][%u] error(%u): %s\n", server->url(), client->id(), *((uint16_t *)arg), (char *)data);
}
else if (type == WS_EVT_PONG)
{
Serial.printf("ws[%s][%u] pong[%u]: %s\n", server->url(), client->id(), len, (len) ? (char *)data : "");
}
else if (type == WS_EVT_DATA)
{
AwsFrameInfo *info = (AwsFrameInfo *)arg;
String msg = "";
//the whole message is in a single frame and we got all of it's data
if (info->final && info->index == 0 && info->len == len)
{
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)
{
for (size_t i = 0; i < info->len; i++)
{
msg += (char)data[i];
}
}
else
{
char buff[3];
for (size_t i = 0; i < info->len; i++)
{
sprintf(buff, "%02x ", (uint8_t)data[i]);
msg += buff;
}
}
Serial.printf("%s\n", msg.c_str());
if (info->opcode == WS_TEXT)
client->text("I got your text message");
else
client->binary("I got your binary message");
}
//message is comprised of multiple frames or the frame is split into multiple packets
else
{
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->opcode == WS_TEXT)
{
for (size_t i = 0; i < info->len; i++)
{
msg += (char)data[i];
}
}
else
{
char buff[3];
for (size_t i = 0; i < info->len; i++)
{
sprintf(buff, "%02x ", (uint8_t)data[i]);
msg += buff;
}
}
Serial.printf("%s\n", msg.c_str());
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)
{
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("I got your text message");
else
client->binary("I got your binary message");
}
}
}
}
}

View File

@@ -9,139 +9,10 @@
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)
{
AwsFrameInfo *info = (AwsFrameInfo *)arg;
if (info->opcode == WS_TEXT)
{
for (size_t i = 0; i < info->len; i++)
{
msg += (char)data[i];
}
}
else
{
char buff[3];
for (size_t i = 0; i < info->len; i++)
{
sprintf(buff, "%02x ", (uint8_t)data[i]);
msg += buff;
}
}
}
return msg;
}
static String parseFrameAsString(AwsEventType type, void *arg, uint8_t *data, size_t len, int start = 0)
{
String msg = "";
if (type == WS_EVT_DATA)
{
AwsFrameInfo *info = (AwsFrameInfo *)arg;
//if(info->final && info->index == 0 && info->len == len){
if (info->opcode == WS_TEXT)
{
for (size_t i = start; i < info->len; i++)
{
msg += (char)data[i];
}
}
else
{
char buff[3];
for (size_t i = start; i < info->len; i++)
{
sprintf(buff, "%02x ", (uint8_t)data[i]);
msg += buff;
}
}
//}
}
return msg;
}
/* static void onWsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len) {
if(type == WS_EVT_CONNECT){
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){
Serial.printf("ws[%s][%u] disconnect: %u\n", server->url(), client->id());
} else if(type == WS_EVT_ERROR){
Serial.printf("ws[%s][%u] error(%u): %s\n", server->url(), client->id(), *((uint16_t*)arg), (char*)data);
} else if(type == WS_EVT_PONG){
Serial.printf("ws[%s][%u] pong[%u]: %s\n", server->url(), client->id(), len, (len)?(char*)data:"");
} else if(type == WS_EVT_DATA){
AwsFrameInfo * info = (AwsFrameInfo*)arg;
String msg = "";
//the whole message is in a single frame and we got all of it's data
if(info->final && info->index == 0 && info->len == len){
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){
for(size_t i=0; i < info->len; i++) {
msg += (char) data[i];
}
} else {
char buff[3];
for(size_t i=0; i < info->len; i++) {
sprintf(buff, "%02x ", (uint8_t) data[i]);
msg += buff ;
}
}
Serial.printf("%s\n",msg.c_str());
if(info->opcode == WS_TEXT)
client->text("I got your text message");
else
client->binary("I got your binary message");
}
//message is comprised of multiple frames or the frame is split into multiple packets
else {
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->opcode == WS_TEXT){
for(size_t i=0; i < info->len; i++) {
msg += (char) data[i];
}
} else {
char buff[3];
for(size_t i=0; i < info->len; i++) {
sprintf(buff, "%02x ", (uint8_t) data[i]);
msg += buff ;
}
}
Serial.printf("%s\n",msg.c_str());
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){
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("I got your text message");
else
client->binary("I got your binary message");
}
}
}
}
} */
static String getRequestParameterOrDefault(AsyncWebServerRequest *request, String param, String defaultValue, bool isPost = true);
static String parseFrame(AwsEventType type, void *arg, uint8_t *data, size_t len);
static String parseFrameAsString(AwsEventType type, void *arg, uint8_t *data, size_t len, int start = 0);
static void wsEventPrint(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len);
};
#endif

View File

@@ -4,9 +4,9 @@
#include "ESPAsyncWebServer.h"
#include "WebServerConfig.h"
#include "WebServerPlugin.cpp"
#include "WebConfigPlugin.cpp"
#include "WebApiPlugin.cpp"
#include "WebServerPlugin.h"
#include "WebConfigPlugin.h"
#include "WebApiPlugin.h"
WiFiNet *network;
Sprocket *sprocket;