#include "HTTPServer.h" #include "Config.h" #include /// /// Constructs an HTTPServer instance using Config::HTTP_PORT. /// Creates a new AsyncWebServer instance but does not start it yet. /// HTTPServer::HTTPServer(IShutterController* controller) : shutterController(controller) { server = new AsyncWebServer(Config::HTTP_PORT); } /// /// Destructor that properly cleans up the AsyncWebServer instance. /// HTTPServer::~HTTPServer() { if (server) { delete server; } } /// /// Configures the ESP8266 as a WiFi access point using Config WiFi settings. /// Uses Config::WIFI_IP, Config::WIFI_GATEWAY, and Config::WIFI_SUBNET for softAPConfig. /// void HTTPServer::setupWiFiAP() { if (!WiFi.softAPConfig(Config::WIFI_IP, Config::WIFI_GATEWAY, Config::WIFI_SUBNET)) { Serial.println("Failed to config IP"); } WiFi.softAP(Config::WIFI_SSID, Config::WIFI_PASSWORD); Serial.println(WiFi.softAPIP()); Serial.println("AP Started - Waiting for connections"); } /// /// Registers all HTTP API routes and their corresponding handlers. /// Associates each route with its handler method using lambda expressions. /// void HTTPServer::setupRoutes() { // Root endpoint - serves home page server->on("/", HTTP_GET, [this](AsyncWebServerRequest *request) { handleRoot(request); }); // Focus endpoint server->on("/api/focus", HTTP_GET, [this](AsyncWebServerRequest *request) { handleFocus(request); }); // Take photo endpoint server->on("/api/takePhoto", HTTP_GET, [this](AsyncWebServerRequest *request) { handleTakePhoto(request); }); // Reset endpoint server->on("/api/reset", HTTP_GET, [this](AsyncWebServerRequest *request) { handleReset(request); }); // Multiple shoot endpoint server->on("/api/multiple", HTTP_GET, [this](AsyncWebServerRequest *request) { handleMultiple(request); }); // Health check endpoint server->on("/api/healthcheck", HTTP_GET, [this](AsyncWebServerRequest *request) { handleHealthCheck(request); }); } /// /// Handles GET / request to serve the home page. /// Returns a simple HTML interface for controlling the camera remote. /// Provides buttons for focus, photo capture, reset, and multiple shot controls. /// void HTTPServer::handleRoot(AsyncWebServerRequest *request) { const char* html = R"rawliteral( Minolta Remote Control

Minolta Remote

Basic Controls

Photo Hold Duration

Multiple Shots

)rawliteral"; request->send(200, "text/html", html); } /// /// Handles GET /api/focus request to perform a half press (focus) operation. /// Logs the request, activates the camera focus, and responds with success. /// void HTTPServer::handleFocus(AsyncWebServerRequest *request) { onRequestStart("api/focus"); shutterController->halfPress(); onRequestEnd("api/focus"); request->send(200, "application/json", "{\"result\":\"true\"}"); } /// /// Handles GET /api/takePhoto request to take a photograph. /// Supports optional "msec" query parameter to control the shutter hold duration (default: 1000ms). /// void HTTPServer::handleTakePhoto(AsyncWebServerRequest *request) { onRequestStart("api/takePhoto"); if (request->hasParam("msec")) { int ms = request->getParam("msec")->value().toInt(); shutterController->pressFullWithDelay(ms); } else { shutterController->pressFullWithDelay(1000); } onRequestEnd("api/takePhoto"); request->send(200, "application/json", "{\"result\":\"true\"}"); } /// /// Handles GET /api/reset request to release the shutter and return to neutral position. /// Logs the request, releases all controls, and responds with success. /// void HTTPServer::handleReset(AsyncWebServerRequest *request) { onRequestStart("api/reset"); shutterController->unPress(); onRequestEnd("api/reset"); request->send(200, "application/json", "{\"result\":\"true\"}"); } /// /// Handles GET /api/multiple request to take multiple photos in sequence. /// Requires query parameters: "count" (number of photos) and "delay" (ms between shots). /// Supports optional "msec" parameter for individual shot duration (default: 1000ms). /// void HTTPServer::handleMultiple(AsyncWebServerRequest *request) { onRequestStart("api/multiple"); if (request->hasParam("count") && request->hasParam("delay")) { int ms = 1000; int count = request->getParam("count")->value().toInt(); int delayMs = request->getParam("delay")->value().toInt(); if (request->hasParam("msec")) { ms = request->getParam("msec")->value().toInt(); } shutterController->multipleShoot(ms, count, delayMs); } onRequestEnd("api/multiple"); request->send(200, "application/json", "{\"result\":\"true\"}"); } /// /// Handles GET /api/healthcheck request as a simple health check endpoint. /// Returns a plain text "Is working" response to verify server connectivity. /// void HTTPServer::handleHealthCheck(AsyncWebServerRequest *request) { onRequestStart("api/healthcheck"); onRequestEnd("api/healthcheck"); request->send(200, "text/plain", "Is working"); } /// /// Logs the start of a request to the serial console and enables the status LED. /// Called at the beginning of each request handler. /// /// The name of the API endpoint being processed void HTTPServer::onRequestStart(const char* endpoint) { Serial.print("[REQUEST] "); Serial.println(endpoint); digitalWrite(LED_BUILTIN, HIGH); } /// /// Logs the completion of a request to the serial console and disables the status LED. /// Called at the end of each request handler. /// /// The name of the API endpoint that was processed void HTTPServer::onRequestEnd(const char* endpoint) { digitalWrite(LED_BUILTIN, LOW); Serial.print("[RESPONSE] "); Serial.println(endpoint); } /// /// Initializes the WiFi access point using Config settings and starts the HTTP server. /// Calls setupWiFiAP() to configure WiFi, then setupRoutes() to register API endpoints. /// void HTTPServer::begin() { setupWiFiAP(); setupRoutes(); server->begin(); Serial.println("HTTP Server started"); }