diff --git a/examples/AsyncCam/handlers.cpp b/examples/AsyncCam/handlers.cpp index 60ef5dc..b080339 100644 --- a/examples/AsyncCam/handlers.cpp +++ b/examples/AsyncCam/handlers.cpp @@ -7,10 +7,12 @@ static const char FRONTPAGE[] = R"EOT(

esp32cam AsyncCam example

- + %brightness% %contrast% %saturation% + + %hmirror% %vflip% @@ -38,7 +40,7 @@ const $display = document.querySelector("#display"); try { await fetchText("/update.cgi", { method: "POST", - body: new URLSearchParams(new FormData($update)), + body: new FormData($update), }); } catch (err) { $display.textContent = err.toString(); @@ -79,30 +81,52 @@ rewriteFrontpage(const esp32cam::Settings& s, const String& var) { b.print(r); b.print(""); } + } else if (var == "lightMode") { +#define SHOW_LM(MODE, SYMBOL) \ + b.printf("", \ + static_cast(esp32cam::LightMode::MODE), #MODE, \ + s.lightMode == esp32cam::LightMode::MODE ? " selected" : "", SYMBOL) + SHOW_LM(AUTO, "⭕"); + SHOW_LM(SUNNY, "☀️"); + SHOW_LM(CLOUDY, "☁️"); + SHOW_LM(OFFICE, "🏢"); + SHOW_LM(HOME, "🏠"); +#undef SHOW_LM + } else if (var == "specialEffect") { +#define SHOW_SE(MODE, SYMBOL) \ + b.printf("", \ + static_cast(esp32cam::SpecialEffect::MODE), #MODE, \ + s.specialEffect == esp32cam::SpecialEffect::MODE ? " selected" : "", SYMBOL) + SHOW_SE(NONE, "🚫"); + SHOW_SE(NEGATIVE, "⬜"); + SHOW_SE(BLACKWHITE, "⬛"); + SHOW_SE(REDDISH, "🟥"); + SHOW_SE(GREENISH, "🟩"); + SHOW_SE(BLUISH, "🟦"); + SHOW_SE(ANTIQUE, "🖼️"); +#undef SHOW_SE } -#define SETTING_INT(MEM, MIN, MAX) \ +#define SHOW_INT(MEM, MIN, MAX) \ else if (var == #MEM) { \ b.printf("", \ s.MEM, MIN, MAX); \ } -#define SETTING_BOOL(MEM) \ +#define SHOW_BOOL(MEM) \ else if (var == #MEM) { \ b.printf("", \ s.MEM ? " checked" : ""); \ } - SETTING_INT(brightness, -2, 2) - SETTING_INT(contrast, -2, 2) - SETTING_INT(saturation, -2, 2) - SETTING_BOOL(hmirror) - SETTING_BOOL(vflip) - -#undef SETTING_INT -#undef SETTING_BOOL - + SHOW_INT(brightness, -2, 2) + SHOW_INT(contrast, -2, 2) + SHOW_INT(saturation, -2, 2) + SHOW_BOOL(hmirror) + SHOW_BOOL(vflip) +#undef SHOW_INT +#undef SHOW_BOOL return b; } @@ -116,22 +140,18 @@ handleFrontpage(AsyncWebServerRequest* req) { static void handleUpdate(AsyncWebServerRequest* req) { bool ok = esp32cam::Camera.update([=](esp32cam::Settings& s) { -#define UPDATE(MEM) \ - do { \ - if constexpr (std::is_same_v) { \ - s.MEM = req->hasArg(#MEM); \ - } else { \ - s.MEM = static_cast(req->arg(#MEM).toInt()); \ - } \ - } while (false) - s.resolution = esp32cam::Resolution(static_cast(req->arg("resolution").toInt())); - UPDATE(brightness); - UPDATE(contrast); - UPDATE(saturation); - UPDATE(hmirror); - UPDATE(vflip); - -#undef UPDATE +#define SAVE_BOOL(MEM) s.MEM = req->hasArg(#MEM) +#define SAVE_INT(MEM) s.MEM = decltype(s.MEM)(req->arg(#MEM).toInt()) + SAVE_INT(resolution); + SAVE_INT(brightness); + SAVE_INT(contrast); + SAVE_INT(saturation); + SAVE_INT(lightMode); + SAVE_INT(specialEffect); + SAVE_BOOL(hmirror); + SAVE_BOOL(vflip); +#undef SAVE_BOOL +#undef SAVE_INT }); if (!ok) { diff --git a/src/esp32cam/config.cpp b/src/esp32cam/config.cpp index 21fefb7..f80490e 100644 --- a/src/esp32cam/config.cpp +++ b/src/esp32cam/config.cpp @@ -104,6 +104,8 @@ CameraClass::status() const { result.brightness = sensor->status.brightness; result.contrast = sensor->status.contrast; result.saturation = sensor->status.saturation; + result.lightMode = static_cast(sensor->status.wb_mode); + result.specialEffect = static_cast(sensor->status.special_effect); result.hmirror = sensor->status.hmirror != 0; result.vflip = sensor->status.vflip != 0; return result; @@ -118,20 +120,21 @@ CameraClass::update(const Settings& settings, int sleepFor) { #define CHECK_RANGE(MEM, MIN, MAX) \ do { \ - if (!(settings.MEM >= MIN && settings.MEM <= MAX)) { \ - ESP32CAM_LOG("update " #MEM " %d out of range [%d,%d]", static_cast(settings.MEM), MIN, \ - MAX); \ + int next = static_cast(settings.MEM); \ + if (!(next >= MIN && next <= MAX)) { \ + ESP32CAM_LOG("update " #MEM " %d out of range [%d,%d]", next, MIN, MAX); \ return false; \ } \ } while (false) #define UPDATE(STATUS_MEM, SETTING_MEM, SETTER_TYP) \ do { \ - auto prev = sensor->status.STATUS_MEM; \ - if (prev != static_cast(settings.SETTING_MEM)) { \ - int res = sensor->set_##STATUS_MEM(sensor, static_cast(settings.SETTING_MEM)); \ - ESP32CAM_LOG("update " #STATUS_MEM " %d => %d %s", static_cast(prev), \ - static_cast(settings.SETTING_MEM), res == 0 ? "success" : "failure"); \ + int prev = static_cast(sensor->status.STATUS_MEM); \ + int next = static_cast(settings.SETTING_MEM); \ + if (prev != static_cast(settings.SETTING_MEM)) { \ + int res = sensor->set_##STATUS_MEM(sensor, static_cast(next)); \ + ESP32CAM_LOG("update " #STATUS_MEM " %d => %d %s", prev, next, \ + res == 0 ? "success" : "failure"); \ if (res != 0) { \ return false; \ } \ @@ -142,11 +145,15 @@ CameraClass::update(const Settings& settings, int sleepFor) { CHECK_RANGE(brightness, -2, 2); CHECK_RANGE(contrast, -2, 2); CHECK_RANGE(saturation, -2, 2); + CHECK_RANGE(lightMode, 0, 4); + CHECK_RANGE(specialEffect, 0, 6); UPDATE(framesize, resolution.as(), framesize_t); UPDATE1(brightness); UPDATE1(contrast); UPDATE1(saturation); + UPDATE(wb_mode, lightMode, int); + UPDATE(special_effect, specialEffect, int); UPDATE1(hmirror); UPDATE1(vflip); diff --git a/src/esp32cam/config.hpp b/src/esp32cam/config.hpp index 8f28366..6d90330 100644 --- a/src/esp32cam/config.hpp +++ b/src/esp32cam/config.hpp @@ -52,6 +52,26 @@ class Config { friend class CameraClass; }; +/** @brief Light mode / white balance values. */ +enum class LightMode { + AUTO = 0, + SUNNY = 1, + CLOUDY = 2, + OFFICE = 3, + HOME = 4, +}; + +/** @brief Special effect values. */ +enum class SpecialEffect { + NONE = 0, + NEGATIVE = 1, + BLACKWHITE = 2, + REDDISH = 3, + GREENISH = 4, + BLUISH = 5, + ANTIQUE = 6, +}; + /** @brief Camera runtime settings. */ struct Settings { /** @brief Picture resolution. */ @@ -66,6 +86,12 @@ struct Settings { /** @brief Image saturation, between -2 and +2. */ int8_t saturation; + /** @brief Image light mode. */ + LightMode lightMode; + + /** @brief Image special effect. */ + SpecialEffect specialEffect; + /** @brief Horizontal flip. */ bool hmirror = false;