Skip to content

Commit

Permalink
feat: added ability to handle JSON data POST and GET
Browse files Browse the repository at this point in the history
- use deviceJSON string to store data
- add custom handler method
- add custom routes to custom handler
- add GET endpoint to retrieve deviceJSON data
  • Loading branch information
ZanzyTHEbar committed Mar 31, 2024
1 parent 429d2b7 commit 53035ab
Show file tree
Hide file tree
Showing 10 changed files with 96 additions and 44 deletions.
4 changes: 2 additions & 2 deletions NetworkManager/include/api/asyncota.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
#include "data/config/project_config.hpp"
#include "utilities/api_utilities.hpp"

typedef std::function<void(void)> AsyncOTACustomHandlerFunction;
class AsyncOTA {
typedef std::function<void(void)> AsyncOTACustomHandlerFunction;
AsyncOTACustomHandlerFunction customHandlerFunction = NULL;
AsyncServer_t& async_server;

protected:
Expand All @@ -18,7 +19,6 @@ class AsyncOTA {
void checkAuthentication(AsyncWebServerRequest* request, const char* login,
const char* password);
void setOTAHandler(AsyncOTACustomHandlerFunction customHandlerFunction);
AsyncOTACustomHandlerFunction customHandlerFunction = NULL;

bool _authRequired;
};
9 changes: 7 additions & 2 deletions NetworkManager/include/api/base_api.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
#include <string>
#include <unordered_map>

#include <ArduinoJson.h>
#include <AsyncJson.h>

#include "data/config/project_config.hpp"
#include "utilities/api_utilities.hpp"
#include "utilities/helpers.hpp"
Expand All @@ -15,15 +18,17 @@ class BaseAPI : public API_Utilities {
/* Commands */
void setWiFi(AsyncWebServerRequest* request);
void setWiFiTXPower(AsyncWebServerRequest* request);
void handleJson(AsyncWebServerRequest* request);
void factoryReset(AsyncWebServerRequest* request);
void rebootDevice(AsyncWebServerRequest* request);
void removeRoute(AsyncWebServerRequest* request);
void getDeviceConfigData(AsyncWebServerRequest* request);
void getJsonConfig(AsyncWebServerRequest* request);
void ping(AsyncWebServerRequest* request);
void save(AsyncWebServerRequest* request);
void rssi(AsyncWebServerRequest* request);

void handleJson(AsyncWebServerRequest* request, JsonVariant& jsonData);

using route_method = void (BaseAPI::*)(AsyncWebServerRequest*);
using route_t = std::unordered_map<std::string, route_method>;
using route_map_t = std::unordered_map<std::string, route_t>;
Expand All @@ -35,7 +40,7 @@ class BaseAPI : public API_Utilities {
BaseAPI(ProjectConfig& configManager);
virtual ~BaseAPI();

std::unordered_map<std::string, ArRequestHandlerFunction> stateFunctionMap;
std::unordered_map<std::string, ArRequestHandlerFunction> useRouteHandler;
};

#endif // BASEAPI_HPP
23 changes: 19 additions & 4 deletions NetworkManager/include/api/rest_api_handler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,42 @@ class APIServer : public BaseAPI {
private:
/* Handlers */
void handleRequest(AsyncWebServerRequest* request);
void handleUserCommands(AsyncWebServerRequest* request);
void handleuser_commands(AsyncWebServerRequest* request);

public:
APIServer(ProjectConfig& configManager,
AsyncServer_t& async_server,
AsyncOTA* async_ota = nullptr);
APIServer(ProjectConfig& configManager, AsyncServer_t& async_server,
AsyncOTA* async_ota = nullptr);
virtual ~APIServer();
void begin();
void setupServer();

bool findParam(AsyncWebServerRequest* request, const std::string& param,
std::string& value);
void addAPICommand(const std::string& url, ArRequestHandlerFunction funct);
void addJSONHandler(const std::string& endpoint,
AsyncCallbackJsonWebHandler* handler);
void addRouteMap(const std::string& index, route_t route);
void setupCaptivePortal(bool apMode = false);

struct JSONRequest_t {
std::string endpoint;
AsyncCallbackJsonWebHandler* handler;

JSONRequest_t(const std::string& endpoint,
AsyncCallbackJsonWebHandler* handler)
: endpoint(endpoint), handler(handler) {}

virtual ~JSONRequest_t() {
delete handler;
}
};

public:
AsyncServer_t& async_server;
AsyncOTA* async_ota;

std::vector<std::string> indexes;
std::unordered_map<std::string, JSONRequest_t*> jsonRequestHandlers;
};

//* Captive Portal Handler
Expand Down
10 changes: 6 additions & 4 deletions NetworkManager/include/api/server.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@
#ifdef USE_WEBMANAGER
# include <data/webpage.h>
#endif // USE_WEBMANAGER

#include "data/config/project_config.hpp"
#include <data/config/project_config.hpp>

class AsyncServer_t : public API_Utilities {
/* Helpers */
Expand All @@ -26,7 +25,8 @@ class AsyncServer_t : public API_Utilities {
AsyncServer_t(const int CONTROL_PORT, ProjectConfig& configManager,
const std::string& api_url,
const std::string& wifimanager_url,
const std::string& userCommands);
const std::string& user_commands,
const std::string& json_url);
virtual ~AsyncServer_t();
virtual void begin();

Expand All @@ -40,12 +40,14 @@ class AsyncServer_t : public API_Utilities {
std::string file;
std::string method;
};

std::vector<UserRoutes_t> custom_html_files;

AsyncWebServer server;
bool spiffsMounted;

std::string api_url;
std::string wifimanager_url;
std::string userCommands;
std::string user_commands;
std::string json_url;
};
1 change: 1 addition & 0 deletions NetworkManager/ini/dev_config.ini
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ framework = arduino
lib_deps =
https://github.com/me-no-dev/ESPAsyncWebServer.git
https://github.com/me-no-dev/AsyncTCP.git
bblanchon/ArduinoJson@^7.0.4

monitor_speed = 115200
monitor_filters =
Expand Down
2 changes: 1 addition & 1 deletion NetworkManager/src/api/asyncota.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ void AsyncOTA::begin() {

String _id = String((uint32_t)ESP.getEfuseMac(), HEX);
_id.toUpperCase();
request->send(200, "application/json",
request->send(200, API_Utilities::MIMETYPE_JSON,
"{\"id\": \"" + _id + "\", \"hardware\": \"ESP32\"}");
});

Expand Down
47 changes: 27 additions & 20 deletions NetworkManager/src/api/base_api.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
#include <api/base_api.hpp>

// TODO: Implement proper JSON post and get
//?
// https://github.com/me-no-dev/ESPAsyncWebServer/tree/master#arduinojson-advanced-response
// TODO: Implement authentication
// TODO: Implement proper visitor pattern for JSON serialization and
// deserialization

BaseAPI::BaseAPI(ProjectConfig& configManager) : configManager(configManager) {}

Expand Down Expand Up @@ -115,26 +111,37 @@ void BaseAPI::setWiFiTXPower(AsyncWebServerRequest* request) {
}
}

void BaseAPI::handleJson(AsyncWebServerRequest* request) {
void BaseAPI::handleJson(AsyncWebServerRequest* request,
JsonVariant& jsonData) {
switch (_networkMethodsMap_enum[request->method()]) {
case GET: {
case POST: {
auto jsonObj = jsonData.as<JsonObject>();
std::string json;
serializeJson(jsonObj, json);
configManager.setDeviceDataJson(json, true);
request->send(200, MIMETYPE_JSON,
configManager.getDeviceDataJson().deviceJson.c_str());
"{\"msg\":\"Done. Device Data "
"has been set.\"}");
break;
}
case POST: {
if (request->hasParam("json", true)) {
AsyncWebParameter* param = request->getParam("json", true);
log_i("%s[%s]: %s\n",
_networkMethodsMap[request->method()].c_str(),
param->name().c_str(), param->value().c_str());
// configManager.setJsonConfig(param->value().c_str());
request->send(200, MIMETYPE_JSON,
"{\"msg\":\"Done. Config has been set.\"}");
} else {
request->send(400, MIMETYPE_JSON,
"{\"msg\":\"Invalid Request\"}");
}
default: {
request->send(400, MIMETYPE_JSON, "{\"msg\":\"Invalid Request\"}");
request->redirect("/");
break;
}
}
}

void BaseAPI::getDeviceConfigData(AsyncWebServerRequest* request) {
switch (_networkMethodsMap_enum[request->method()]) {
case GET: {
AsyncJsonResponse* response = new AsyncJsonResponse();
response->addHeader("EasyNetworkManager", "1.0");
auto root = response->getRoot();
root["deviceData"] =
configManager.getDeviceDataJson().deviceJson.c_str();
response->setLength();
request->send(response);
break;
}
default: {
Expand Down
34 changes: 27 additions & 7 deletions NetworkManager/src/api/rest_api_handler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,18 @@ void APIServer::begin() {
wifi_manager_url, HTTP_ANY,
[&](AsyncWebServerRequest* request) { handleRequest(request); });

//* Add default JSON handler

// create JSON route
const std::string json_url =
async_server.api_url.append(async_server.json_url);

async_server.server.addHandler(new AsyncCallbackJsonWebHandler(
json_url.c_str(),
[&](AsyncWebServerRequest* request, JsonVariant& json) {
handleJson(request, json);
}));

if (async_ota != nullptr)
async_ota->begin();
async_server.server.begin();
Expand All @@ -50,8 +62,8 @@ void APIServer::setupServer() {
// Set default routes
routes.reserve(10); // reserve enough memory for all routes
routes.emplace("wifi", &APIServer::setWiFi);
routes.emplace("json", &APIServer::handleJson);
routes.emplace("resetConfig", &APIServer::factoryReset);
routes.emplace("getDeviceConfigData", &APIServer::getDeviceConfigData);
routes.emplace("getConfig", &APIServer::getJsonConfig);
routes.emplace("deleteRoute", &APIServer::removeRoute);
routes.emplace("rebootDevice", &APIServer::rebootDevice);
Expand Down Expand Up @@ -108,10 +120,10 @@ void APIServer::addRouteMap(const std::string& index, route_t route) {

void APIServer::handleRequest(AsyncWebServerRequest* request) {
std::vector<std::string> temp =
Helpers::split(async_server.userCommands.c_str(), '/');
Helpers::split(async_server.user_commands.c_str(), '/');

if (strcmp(request->pathArg(0).c_str(), temp[1].c_str()) == 0) {
handleUserCommands(request);
handleuser_commands(request);
return;
}

Expand Down Expand Up @@ -143,7 +155,15 @@ void APIServer::handleRequest(AsyncWebServerRequest* request) {

void APIServer::addAPICommand(const std::string& url,
ArRequestHandlerFunction funct) {
stateFunctionMap.emplace(std::move(url), funct);
useRouteHandler.emplace(std::move(url), funct);
}

void APIServer::addJSONHandler(const std::string& endpoint,
AsyncCallbackJsonWebHandler* handler) {
static JSONRequest_t* jsonHandler = new JSONRequest_t(endpoint, handler);

jsonRequestHandlers.emplace(endpoint, jsonHandler);
async_server.server.addHandler(handler);
}

/**
Expand All @@ -156,10 +176,10 @@ void APIServer::addAPICommand(const std::string& url,
* parameter \c we need to fix this!! I need a better implemenation
*
*/
void APIServer::handleUserCommands(AsyncWebServerRequest* request) {
void APIServer::handleuser_commands(AsyncWebServerRequest* request) {
std::string url = request->pathArg(1).c_str();
auto it = stateFunctionMap.find(url);
if (it != stateFunctionMap.end()) {
auto it = useRouteHandler.find(url);
if (it != useRouteHandler.end()) {
log_d("[APIServer]: We are trying to execute the function");
it->second(request);
return;
Expand Down
6 changes: 4 additions & 2 deletions NetworkManager/src/api/server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ AsyncServer_t::AsyncServer_t(const int CONTROL_PORT,
ProjectConfig& configManager,
const std::string& api_url,
const std::string& wifimanager_url,
const std::string& userCommands)
const std::string& user_commands,
const std::string& json_url)
: server(CONTROL_PORT),
configManager(configManager),
api_url(std::move(api_url)),
wifimanager_url(std::move(wifimanager_url)),
userCommands(std::move(userCommands)),
user_commands(std::move(user_commands)),
json_url(std::move(json_url)),
spiffsMounted(false) {
spiffsMounted = initSPIFFS();
}
Expand Down
4 changes: 2 additions & 2 deletions NetworkManager/wokwi.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[wokwi]
version = 1
elf = ".pio/build/esp32s3_debug/EasyNetworkManager-v5.2.2-esp32s3_debug-340c4f4-main.elf"
firmware = ".pio/build/esp32s3_debug/EasyNetworkManager-v5.2.2-esp32s3_debug-340c4f4-main.bin"
elf = ".pio/build/esp32s3_debug/EasyNetworkManager-v5.2.2-esp32s3_debug-764f579-main.elf"
firmware = ".pio/build/esp32s3_debug/EasyNetworkManager-v5.2.2-esp32s3_debug-764f579-main.bin"
[[net.forward]]
from = "localhost:8180"
to = "target:80"

0 comments on commit 53035ab

Please sign in to comment.