From 955a909846c45d93fa49e91079683a9eef053cdd Mon Sep 17 00:00:00 2001
From: ajwahab <1449672+ajwahab@users.noreply.github.com>
Date: Wed, 11 Sep 2024 01:20:30 -0400
Subject: [PATCH] User configurable frame buffer. (#7360)

---
 esphome/components/esp32_camera/__init__.py      |  4 ++++
 esphome/components/esp32_camera/esp32_camera.cpp | 10 +++++++++-
 esphome/components/esp32_camera/esp32_camera.h   |  3 +++
 3 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/esphome/components/esp32_camera/__init__.py b/esphome/components/esp32_camera/__init__.py
index 4187429412..2f1f9b90bb 100644
--- a/esphome/components/esp32_camera/__init__.py
+++ b/esphome/components/esp32_camera/__init__.py
@@ -140,6 +140,8 @@ CONF_TEST_PATTERN = "test_pattern"
 # framerates
 CONF_MAX_FRAMERATE = "max_framerate"
 CONF_IDLE_FRAMERATE = "idle_framerate"
+# frame buffer
+CONF_FRAME_BUFFER_COUNT = "frame_buffer_count"
 
 # stream trigger
 CONF_ON_STREAM_START = "on_stream_start"
@@ -213,6 +215,7 @@ CONFIG_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(
         cv.Optional(CONF_IDLE_FRAMERATE, default="0.1 fps"): cv.All(
             cv.framerate, cv.Range(min=0, max=1)
         ),
+        cv.Optional(CONF_FRAME_BUFFER_COUNT, default=1): cv.int_range(min=1, max=2),
         cv.Optional(CONF_ON_STREAM_START): automation.validate_automation(
             {
                 cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(
@@ -285,6 +288,7 @@ async def to_code(config):
         cg.add(var.set_idle_update_interval(0))
     else:
         cg.add(var.set_idle_update_interval(1000 / config[CONF_IDLE_FRAMERATE]))
+    cg.add(var.set_frame_buffer_count(config[CONF_FRAME_BUFFER_COUNT]))
     cg.add(var.set_frame_size(config[CONF_RESOLUTION]))
 
     cg.add_define("USE_ESP32_CAMERA")
diff --git a/esphome/components/esp32_camera/esp32_camera.cpp b/esphome/components/esp32_camera/esp32_camera.cpp
index 555f6ca5f1..e9e9d3cffb 100644
--- a/esphome/components/esp32_camera/esp32_camera.cpp
+++ b/esphome/components/esp32_camera/esp32_camera.cpp
@@ -127,7 +127,7 @@ void ESP32Camera::dump_config() {
   sensor_t *s = esp_camera_sensor_get();
   auto st = s->status;
   ESP_LOGCONFIG(TAG, "  JPEG Quality: %u", st.quality);
-  // ESP_LOGCONFIG(TAG, "  Framebuffer Count: %u", conf.fb_count);
+  ESP_LOGCONFIG(TAG, "  Framebuffer Count: %u", conf.fb_count);
   ESP_LOGCONFIG(TAG, "  Contrast: %d", st.contrast);
   ESP_LOGCONFIG(TAG, "  Brightness: %d", st.brightness);
   ESP_LOGCONFIG(TAG, "  Saturation: %d", st.saturation);
@@ -212,6 +212,8 @@ ESP32Camera::ESP32Camera() {
   this->config_.frame_size = FRAMESIZE_VGA;  // 640x480
   this->config_.jpeg_quality = 10;
   this->config_.fb_count = 1;
+  this->config_.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
+  this->config_.fb_location = CAMERA_FB_IN_PSRAM;
 
   global_esp32_camera = this;
 }
@@ -333,6 +335,12 @@ void ESP32Camera::set_max_update_interval(uint32_t max_update_interval) {
 void ESP32Camera::set_idle_update_interval(uint32_t idle_update_interval) {
   this->idle_update_interval_ = idle_update_interval;
 }
+/* set frame buffer parameters */
+void ESP32Camera::set_frame_buffer_mode(camera_grab_mode_t mode) { this->config_.grab_mode = mode; }
+void ESP32Camera::set_frame_buffer_count(uint8_t fb_count) {
+  this->config_.fb_count = fb_count;
+  this->set_frame_buffer_mode(fb_count > 1 ? CAMERA_GRAB_LATEST : CAMERA_GRAB_WHEN_EMPTY);
+}
 
 /* ---------------- public API (specific) ---------------- */
 void ESP32Camera::add_image_callback(std::function<void(std::shared_ptr<CameraImage>)> &&callback) {
diff --git a/esphome/components/esp32_camera/esp32_camera.h b/esphome/components/esp32_camera/esp32_camera.h
index 0c25381039..71f47d3c06 100644
--- a/esphome/components/esp32_camera/esp32_camera.h
+++ b/esphome/components/esp32_camera/esp32_camera.h
@@ -145,6 +145,9 @@ class ESP32Camera : public Component, public EntityBase {
   /* -- framerates */
   void set_max_update_interval(uint32_t max_update_interval);
   void set_idle_update_interval(uint32_t idle_update_interval);
+  /* -- frame buffer */
+  void set_frame_buffer_mode(camera_grab_mode_t mode);
+  void set_frame_buffer_count(uint8_t fb_count);
 
   /* public API (derivated) */
   void setup() override;