diff --git a/components/CommandManager/CMakeLists.txt b/components/CommandManager/CMakeLists.txt index 01d8032..7eb5c06 100644 --- a/components/CommandManager/CMakeLists.txt +++ b/components/CommandManager/CMakeLists.txt @@ -6,8 +6,9 @@ idf_component_register( "CommandManager/commands/wifi_commands.cpp" "CommandManager/commands/config_commands.cpp" "CommandManager/commands/mdns_commands.cpp" + "CommandManager/commands/device_commands.cpp" INCLUDE_DIRS "CommandManager" "CommandManager/commands" - REQUIRES ProjectConfig cJSON + REQUIRES ProjectConfig cJSON CameraManager ) \ No newline at end of file diff --git a/components/CommandManager/CommandManager/CommandManager.cpp b/components/CommandManager/CommandManager/CommandManager.cpp index c3e2f13..f76bf72 100644 --- a/components/CommandManager/CommandManager/CommandManager.cpp +++ b/components/CommandManager/CommandManager/CommandManager.cpp @@ -29,10 +29,16 @@ std::unique_ptr CommandManager::createCommand(CommandType type) return std::make_unique(projectConfig); case CommandType::UPDATE_CAMERA: return std::make_unique(projectConfig); + case CommandType::RESTART_CAMERA: + return std::make_unique(cameraManager); case CommandType::GET_CONFIG: return std::make_unique(projectConfig); case CommandType::SAVE_CONFIG: return std::make_unique(projectConfig); + case CommandType::RESET_CONFIG: + return std::make_unique(projectConfig); + case CommandType::RESTART_DEVICE: + return std::make_unique(); default: return nullptr; } diff --git a/components/CommandManager/CommandManager/CommandManager.hpp b/components/CommandManager/CommandManager/CommandManager.hpp index 552e285..13e33ca 100644 --- a/components/CommandManager/CommandManager/CommandManager.hpp +++ b/components/CommandManager/CommandManager/CommandManager.hpp @@ -2,6 +2,7 @@ #define COMMANDMANAGER_HPP #include +#include #include #include #include @@ -14,6 +15,7 @@ #include "commands/config_commands.hpp" #include "commands/mdns_commands.hpp" #include "commands/wifi_commands.hpp" +#include "commands/device_commands.hpp" #include // mostlikely missing commands @@ -31,6 +33,7 @@ enum CommandType UPDATE_MDNS, SET_MDNS, UPDATE_CAMERA, + RESTART_CAMERA, SAVE_CONFIG, GET_CONFIG, RESET_CONFIG, @@ -41,9 +44,10 @@ class CommandManager { private: std::shared_ptr projectConfig; + std::shared_ptr cameraManager; public: - CommandManager(std::shared_ptr projectConfig) : projectConfig(projectConfig) {}; + CommandManager(std::shared_ptr projectConfig, std::shared_ptr cameraManager) : projectConfig(projectConfig), cameraManager(cameraManager) {}; std::unique_ptr createCommand(CommandType type); CommandResult executeFromJson(std::string_view json); diff --git a/components/CommandManager/CommandManager/CommandSchema.hpp b/components/CommandManager/CommandManager/CommandSchema.hpp index dbbe5e5..588d004 100644 --- a/components/CommandManager/CommandManager/CommandSchema.hpp +++ b/components/CommandManager/CommandManager/CommandSchema.hpp @@ -1,9 +1,6 @@ #ifndef COMMAND_SCHEMA_HPP #define COMMAND_SCHEMA_HPP -// this generally should be merged with ProjectConfig definitions -// and moved into a separate component -// and used as more or less models struct BasePayload { }; @@ -54,4 +51,13 @@ struct UpdateCameraConfigPayload : BasePayload // TODO add more options here }; +struct ResetConfigPayload : BasePayload +{ + std::string section; +}; + +struct RestartCameraPayload : BasePayload +{ + bool mode; +}; #endif \ No newline at end of file diff --git a/components/CommandManager/CommandManager/commands/camera_commands.cpp b/components/CommandManager/CommandManager/commands/camera_commands.cpp index 0a92144..07defb4 100644 --- a/components/CommandManager/CommandManager/commands/camera_commands.cpp +++ b/components/CommandManager/CommandManager/commands/camera_commands.cpp @@ -49,3 +49,37 @@ CommandResult updateCameraCommand::execute(std::string_view jsonPayload) return CommandResult::getSuccessResult("Config updated"); } + +std::optional restartCameraCommand::parsePayload(std::string_view jsonPayload) +{ + RestartCameraPayload payload; + cJSON *parsedJson = cJSON_Parse(jsonPayload.data()); + + if (parsedJson == nullptr) + return std::nullopt; + + cJSON *mode = cJSON_GetObjectItem(parsedJson, "mode"); + + if (mode == nullptr) + { + cJSON_Delete(parsedJson); + } + + payload.mode = (bool)mode->valueint; + + cJSON_Delete(parsedJson); + + return payload; +} + +CommandResult restartCameraCommand::execute(std::string_view jsonPayload) +{ + auto payload = parsePayload(jsonPayload); + if (!payload.has_value()) + { + return CommandResult::getErrorResult("Invalid payload"); + } + + this->cameraManager->resetCamera(payload.value().mode); + return CommandResult::getSuccessResult("Camera restarted"); +} \ No newline at end of file diff --git a/components/CommandManager/CommandManager/commands/camera_commands.hpp b/components/CommandManager/CommandManager/commands/camera_commands.hpp index f0139c0..9070132 100644 --- a/components/CommandManager/CommandManager/commands/camera_commands.hpp +++ b/components/CommandManager/CommandManager/commands/camera_commands.hpp @@ -1,4 +1,7 @@ +#ifndef CAMERA_COMMANDS_HPP +#define CAMERA_COMMANDS_HPP #include "BaseCommand.hpp" +#include class updateCameraCommand : public Command { @@ -10,4 +13,15 @@ public: std::optional parsePayload(std::string_view jsonPayload); }; +class restartCameraCommand : public Command +{ + std::shared_ptr cameraManager; + +public: + restartCameraCommand(std::shared_ptr cameraManager) : cameraManager(cameraManager) {}; + CommandResult execute(std::string_view jsonPayload) override; + std::optional parsePayload(std::string_view jsonPayload); +}; + +#endif // add cropping command \ No newline at end of file diff --git a/components/CommandManager/CommandManager/commands/config_commands.cpp b/components/CommandManager/CommandManager/commands/config_commands.cpp index e1ad844..8b49191 100644 --- a/components/CommandManager/CommandManager/commands/config_commands.cpp +++ b/components/CommandManager/CommandManager/commands/config_commands.cpp @@ -10,4 +10,50 @@ CommandResult getConfigCommand::execute(std::string_view jsonPayload) { auto configRepresentation = projectConfig->getTrackerConfig().toRepresentation(); return CommandResult::getSuccessResult(configRepresentation); +} + +std::optional resetConfigCommand::parsePayload(std::string_view jsonPayload) +{ + ResetConfigPayload payload; + cJSON *parsedJson = cJSON_Parse(jsonPayload.data()); + + if (parsedJson == nullptr) + return std::nullopt; + + cJSON *section = cJSON_GetObjectItem(parsedJson, "section"); + + if (section == nullptr) + { + cJSON_Delete(parsedJson); + return std::nullopt; + } + + payload.section = std::string(section->valuestring); + + cJSON_Delete(parsedJson); + return payload; +} + +CommandResult resetConfigCommand::execute(std::string_view jsonPayload) +{ + auto payload = parsePayload(jsonPayload); + + if (!payload.has_value()) + { + return CommandResult::getErrorResult("Invalid payload or missing section"); + } + + auto sectionPayload = payload.value(); + + if (std::find(this->supported_sections.begin(), this->supported_sections.end(), sectionPayload.section) == this->supported_sections.end()) + { + return CommandResult::getErrorResult("Selected section is unsupported"); + } + + // we cannot match on string, and making a map would be overkill right now, sooo + // todo, add more granual control for other sections, like only reset camera, or only reset wifi + if (sectionPayload.section == "all") + this->projectConfig->reset(); + + return CommandResult::getSuccessResult("Config reset"); } \ No newline at end of file diff --git a/components/CommandManager/CommandManager/commands/config_commands.hpp b/components/CommandManager/CommandManager/commands/config_commands.hpp index e615661..03229af 100644 --- a/components/CommandManager/CommandManager/commands/config_commands.hpp +++ b/components/CommandManager/CommandManager/commands/config_commands.hpp @@ -15,3 +15,16 @@ public: getConfigCommand(std::shared_ptr projectConfig) : projectConfig(projectConfig) {}; CommandResult execute(std::string_view jsonPayload) override; }; + +class resetConfigCommand : public Command +{ + std::array supported_sections = { + "all", + }; + +public: + std::shared_ptr projectConfig; + resetConfigCommand(std::shared_ptr projectConfig) : projectConfig(projectConfig) {}; + CommandResult execute(std::string_view jsonPayload) override; + std::optional parsePayload(std::string_view jsonPayload); +}; \ No newline at end of file diff --git a/components/CommandManager/CommandManager/commands/device_commands.cpp b/components/CommandManager/CommandManager/commands/device_commands.cpp new file mode 100644 index 0000000..6b356a3 --- /dev/null +++ b/components/CommandManager/CommandManager/commands/device_commands.cpp @@ -0,0 +1,8 @@ +#include "device_commands.hpp" + +CommandResult restartDeviceCommand::execute(std::string_view jsonPayload) +{ + // todo implement this: https://github.com/EyeTrackVR/OpenIris/blob/master/ESP/lib/src/tasks/tasks.cpp + // OpenIrisTasks::ScheduleRestart(2000); + return CommandResult::getSuccessResult("Device restarted"); +} \ No newline at end of file diff --git a/components/CommandManager/CommandManager/commands/device_commands.hpp b/components/CommandManager/CommandManager/commands/device_commands.hpp new file mode 100644 index 0000000..789e7c3 --- /dev/null +++ b/components/CommandManager/CommandManager/commands/device_commands.hpp @@ -0,0 +1,6 @@ +#include "BaseCommand.hpp" + +class restartDeviceCommand : public Command +{ + CommandResult execute(std::string_view jsonPayload) override; +}; \ No newline at end of file diff --git a/components/RestAPI/RestAPI/RestAPI.cpp b/components/RestAPI/RestAPI/RestAPI.cpp index 082be24..9667b1a 100644 --- a/components/RestAPI/RestAPI/RestAPI.cpp +++ b/components/RestAPI/RestAPI/RestAPI.cpp @@ -13,10 +13,6 @@ RestAPI::RestAPI(std::string url, std::shared_ptr commandManager // post will reset it // resets routes.emplace("/api/reset/config/", &RestAPI::handle_reset_config); - routes.emplace("/api/reset/wifi/", &RestAPI::handle_reset_wifi_config); - routes.emplace("/api/reset/txpower/", &RestAPI::handle_reset_txpower_config); - routes.emplace("/api/reset/camera/", &RestAPI::handle_reset_camera_config); - // gets routes.emplace("/api/get/config/", &RestAPI::handle_get_config); @@ -129,27 +125,21 @@ void RestAPI::handle_get_config(RequestContext *context) void RestAPI::handle_reset_config(RequestContext *context) { - mg_http_reply(context->connection, 200, JSON_RESPONSE, "{%m:%m}", MG_ESC("result"), "Config reset"); -} + if (context->method != POST_METHOD) + { + mg_http_reply(context->connection, 401, JSON_RESPONSE, "{%m:%m}", MG_ESC("error"), "Method not allowed"); + return; + } -void RestAPI::handle_reset_wifi_config(RequestContext *context) -{ - mg_http_reply(context->connection, 200, JSON_RESPONSE, "{%m:%m}", MG_ESC("result"), "WiFi Config reset"); -} - -void RestAPI::handle_reset_txpower_config(RequestContext *context) -{ - mg_http_reply(context->connection, 200, JSON_RESPONSE, "{%m:%m}", MG_ESC("result"), "TX Power Config reset"); -} - -void RestAPI::handle_reset_camera_config(RequestContext *context) -{ - mg_http_reply(context->connection, 200, JSON_RESPONSE, "{%m:%m}", MG_ESC("result"), "Camera Config reset"); + auto result = this->command_manager->executeFromType(CommandType::RESET_CONFIG, "{\"section\": \"all\"}"); + int code = result.isSuccess() ? 200 : 500; + mg_http_reply(context->connection, code, JSON_RESPONSE, "{%m:%m}", MG_ESC("result"), result.getResult()); } // reboots void RestAPI::handle_reboot(RequestContext *context) { + auto result = this->command_manager->executeFromType(CommandType::RESTART_DEVICE, ""); mg_http_reply(context->connection, 200, JSON_RESPONSE, "{%m:%m}", MG_ESC("result"), "Ok"); } diff --git a/components/RestAPI/RestAPI/RestAPI.hpp b/components/RestAPI/RestAPI/RestAPI.hpp index 69fc93b..1945648 100644 --- a/components/RestAPI/RestAPI/RestAPI.hpp +++ b/components/RestAPI/RestAPI/RestAPI.hpp @@ -39,9 +39,6 @@ private: // resets void handle_reset_config(RequestContext *context); - void handle_reset_wifi_config(RequestContext *context); - void handle_reset_txpower_config(RequestContext *context); - void handle_reset_camera_config(RequestContext *context); // reboots void handle_reboot(RequestContext *context); diff --git a/main/openiris_main.cpp b/main/openiris_main.cpp index 92d1421..56c1b3b 100644 --- a/main/openiris_main.cpp +++ b/main/openiris_main.cpp @@ -35,10 +35,10 @@ WebSocketLogger webSocketLogger; auto deviceConfig = std::make_shared("openiris", CONFIG_MDNS_HOSTNAME); WiFiManager wifiManager(deviceConfig); MDNSManager mdnsManager(deviceConfig); -CameraManager cameraHandler(deviceConfig); +auto cameraHandler = std::make_shared(deviceConfig); StreamServer streamServer(80); -auto commandManager = std::make_shared(deviceConfig); +auto commandManager = std::make_shared(deviceConfig, cameraHandler); RestAPI restAPI("http://0.0.0.0:81", commandManager); #ifdef CONFIG_WIRED_MODE @@ -103,7 +103,7 @@ extern "C" void app_main(void) wifiManager.Begin(); mdnsManager.start(); restAPI.begin(); - cameraHandler.setupCamera(); + cameraHandler->setupCamera(); streamServer.startStreamServer(); #ifdef CONFIG_WIRED_MODE