Esp32cam full control (#3090)

This commit is contained in:
Dav-id 2022-01-24 23:53:47 +01:00 committed by GitHub
parent 28b65cb810
commit 1de941e837
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 293 additions and 93 deletions

View File

@ -23,6 +23,7 @@ AUTO_LOAD = ["psram"]
esp32_camera_ns = cg.esphome_ns.namespace("esp32_camera")
ESP32Camera = esp32_camera_ns.class_("ESP32Camera", cg.PollingComponent, cg.EntityBase)
ESP32CameraFrameSize = esp32_camera_ns.enum("ESP32CameraFrameSize")
FRAME_SIZES = {
"160X120": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_160X120,
@ -46,30 +47,76 @@ FRAME_SIZES = {
"1600X1200": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_1600X1200,
"UXGA": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_1600X1200,
}
ESP32GainControlMode = esp32_camera_ns.enum("ESP32GainControlMode")
ENUM_GAIN_CONTROL_MODE = {
"MANUAL": ESP32GainControlMode.ESP32_GC_MODE_MANU,
"AUTO": ESP32GainControlMode.ESP32_GC_MODE_AUTO,
}
ESP32AgcGainCeiling = esp32_camera_ns.enum("ESP32AgcGainCeiling")
ENUM_GAIN_CEILING = {
"2X": ESP32AgcGainCeiling.ESP32_GAINCEILING_2X,
"4X": ESP32AgcGainCeiling.ESP32_GAINCEILING_4X,
"8X": ESP32AgcGainCeiling.ESP32_GAINCEILING_8X,
"16X": ESP32AgcGainCeiling.ESP32_GAINCEILING_16X,
"32X": ESP32AgcGainCeiling.ESP32_GAINCEILING_32X,
"64X": ESP32AgcGainCeiling.ESP32_GAINCEILING_64X,
"128X": ESP32AgcGainCeiling.ESP32_GAINCEILING_128X,
}
ESP32WhiteBalanceMode = esp32_camera_ns.enum("ESP32WhiteBalanceMode")
ENUM_WB_MODE = {
"AUTO": ESP32WhiteBalanceMode.ESP32_WB_MODE_AUTO,
"SUNNY": ESP32WhiteBalanceMode.ESP32_WB_MODE_SUNNY,
"CLOUDY": ESP32WhiteBalanceMode.ESP32_WB_MODE_CLOUDY,
"OFFICE": ESP32WhiteBalanceMode.ESP32_WB_MODE_OFFICE,
"HOME": ESP32WhiteBalanceMode.ESP32_WB_MODE_HOME,
}
ESP32SpecialEffect = esp32_camera_ns.enum("ESP32SpecialEffect")
ENUM_SPECIAL_EFFECT = {
"NONE": ESP32SpecialEffect.ESP32_SPECIAL_EFFECT_NONE,
"NEGATIVE": ESP32SpecialEffect.ESP32_SPECIAL_EFFECT_NEGATIVE,
"GRAYSCALE": ESP32SpecialEffect.ESP32_SPECIAL_EFFECT_GRAYSCALE,
"RED_TINT": ESP32SpecialEffect.ESP32_SPECIAL_EFFECT_RED_TINT,
"GREEN_TINT": ESP32SpecialEffect.ESP32_SPECIAL_EFFECT_GREEN_TINT,
"BLUE_TINT": ESP32SpecialEffect.ESP32_SPECIAL_EFFECT_BLUE_TINT,
"SEPIA": ESP32SpecialEffect.ESP32_SPECIAL_EFFECT_SEPIA,
}
# pin assignment
CONF_VSYNC_PIN = "vsync_pin"
CONF_HREF_PIN = "href_pin"
CONF_PIXEL_CLOCK_PIN = "pixel_clock_pin"
CONF_EXTERNAL_CLOCK = "external_clock"
CONF_I2C_PINS = "i2c_pins"
CONF_POWER_DOWN_PIN = "power_down_pin"
CONF_MAX_FRAMERATE = "max_framerate"
CONF_IDLE_FRAMERATE = "idle_framerate"
# image
CONF_JPEG_QUALITY = "jpeg_quality"
CONF_VERTICAL_FLIP = "vertical_flip"
CONF_HORIZONTAL_MIRROR = "horizontal_mirror"
CONF_SATURATION = "saturation"
CONF_SPECIAL_EFFECT = "special_effect"
# exposure
CONF_AEC_MODE = "aec_mode"
CONF_AEC2 = "aec2"
CONF_AE_LEVEL = "ae_level"
CONF_AEC_VALUE = "aec_value"
CONF_SATURATION = "saturation"
# gains
CONF_AGC_MODE = "agc_mode"
CONF_AGC_VALUE = "agc_value"
CONF_AGC_GAIN_CEILING = "agc_gain_ceiling"
# white balance
CONF_WB_MODE = "wb_mode"
# test pattern
CONF_TEST_PATTERN = "test_pattern"
# framerates
CONF_MAX_FRAMERATE = "max_framerate"
CONF_IDLE_FRAMERATE = "idle_framerate"
camera_range_param = cv.int_range(min=-2, max=2)
CONFIG_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(
{
cv.GenerateID(): cv.declare_id(ESP32Camera),
# pin assignment
cv.Required(CONF_DATA_PINS): cv.All(
[pins.internal_gpio_input_pin_number], cv.Length(min=8, max=8)
),
@ -92,12 +139,7 @@ CONFIG_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(
),
cv.Optional(CONF_RESET_PIN): pins.internal_gpio_output_pin_number,
cv.Optional(CONF_POWER_DOWN_PIN): pins.internal_gpio_output_pin_number,
cv.Optional(CONF_MAX_FRAMERATE, default="10 fps"): cv.All(
cv.framerate, cv.Range(min=0, min_included=False, max=60)
),
cv.Optional(CONF_IDLE_FRAMERATE, default="0.1 fps"): cv.All(
cv.framerate, cv.Range(min=0, max=1)
),
# image
cv.Optional(CONF_RESOLUTION, default="640X480"): cv.enum(
FRAME_SIZES, upper=True
),
@ -107,29 +149,66 @@ CONFIG_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(
cv.Optional(CONF_SATURATION, default=0): camera_range_param,
cv.Optional(CONF_VERTICAL_FLIP, default=True): cv.boolean,
cv.Optional(CONF_HORIZONTAL_MIRROR, default=True): cv.boolean,
cv.Optional(CONF_SPECIAL_EFFECT, default="NONE"): cv.enum(
ENUM_SPECIAL_EFFECT, upper=True
),
# exposure
cv.Optional(CONF_AGC_MODE, default="AUTO"): cv.enum(
ENUM_GAIN_CONTROL_MODE, upper=True
),
cv.Optional(CONF_AEC2, default=False): cv.boolean,
cv.Optional(CONF_AE_LEVEL, default=0): camera_range_param,
cv.Optional(CONF_AEC_VALUE, default=300): cv.int_range(min=0, max=1200),
# gains
cv.Optional(CONF_AEC_MODE, default="AUTO"): cv.enum(
ENUM_GAIN_CONTROL_MODE, upper=True
),
cv.Optional(CONF_AGC_VALUE, default=0): cv.int_range(min=0, max=30),
cv.Optional(CONF_AGC_GAIN_CEILING, default="2X"): cv.enum(
ENUM_GAIN_CEILING, upper=True
),
# white balance
cv.Optional(CONF_WB_MODE, default="AUTO"): cv.enum(ENUM_WB_MODE, upper=True),
# test pattern
cv.Optional(CONF_TEST_PATTERN, default=False): cv.boolean,
# framerates
cv.Optional(CONF_MAX_FRAMERATE, default="10 fps"): cv.All(
cv.framerate, cv.Range(min=0, min_included=False, max=60)
),
cv.Optional(CONF_IDLE_FRAMERATE, default="0.1 fps"): cv.All(
cv.framerate, cv.Range(min=0, max=1)
),
}
).extend(cv.COMPONENT_SCHEMA)
SETTERS = {
# pin assignment
CONF_DATA_PINS: "set_data_pins",
CONF_VSYNC_PIN: "set_vsync_pin",
CONF_HREF_PIN: "set_href_pin",
CONF_PIXEL_CLOCK_PIN: "set_pixel_clock_pin",
CONF_RESET_PIN: "set_reset_pin",
CONF_POWER_DOWN_PIN: "set_power_down_pin",
# image
CONF_JPEG_QUALITY: "set_jpeg_quality",
CONF_VERTICAL_FLIP: "set_vertical_flip",
CONF_HORIZONTAL_MIRROR: "set_horizontal_mirror",
CONF_AEC2: "set_aec2",
CONF_AE_LEVEL: "set_ae_level",
CONF_AEC_VALUE: "set_aec_value",
CONF_CONTRAST: "set_contrast",
CONF_BRIGHTNESS: "set_brightness",
CONF_SATURATION: "set_saturation",
CONF_SPECIAL_EFFECT: "set_special_effect",
# exposure
CONF_AEC_MODE: "set_aec_mode",
CONF_AEC2: "set_aec2",
CONF_AE_LEVEL: "set_ae_level",
CONF_AEC_VALUE: "set_aec_value",
# gains
CONF_AGC_MODE: "set_agc_mode",
CONF_AGC_VALUE: "set_agc_value",
CONF_AGC_GAIN_CEILING: "set_agc_gain_ceiling",
# white balance
CONF_WB_MODE: "set_wb_mode",
# test pattern
CONF_TEST_PATTERN: "set_test_pattern",
}

View File

@ -11,10 +11,14 @@ namespace esp32_camera {
static const char *const TAG = "esp32_camera";
/* ---------------- public API (derivated) ---------------- */
void ESP32Camera::setup() {
global_esp32_camera = this;
/* initialize time to now */
this->last_update_ = millis();
/* initialize camera */
esp_err_t err = esp_camera_init(&this->config_);
if (err != ESP_OK) {
ESP_LOGE(TAG, "esp_camera_init failed: %s", esp_err_to_name(err));
@ -23,16 +27,10 @@ void ESP32Camera::setup() {
return;
}
sensor_t *s = esp_camera_sensor_get();
s->set_vflip(s, this->vertical_flip_);
s->set_hmirror(s, this->horizontal_mirror_);
s->set_aec2(s, this->aec2_); // 0 = disable , 1 = enable
s->set_ae_level(s, this->ae_level_); // -2 to 2
s->set_aec_value(s, this->aec_value_); // 0 to 1200
s->set_contrast(s, this->contrast_);
s->set_brightness(s, this->brightness_);
s->set_saturation(s, this->saturation_);
s->set_colorbar(s, this->test_pattern_);
/* initialize camera parameters */
this->update_camera_parameters();
/* initialize RTOS */
this->framebuffer_get_queue_ = xQueueCreate(1, sizeof(camera_fb_t *));
this->framebuffer_return_queue_ = xQueueCreate(1, sizeof(camera_fb_t *));
xTaskCreatePinnedToCore(&ESP32Camera::framebuffer_task,
@ -44,6 +42,7 @@ void ESP32Camera::setup() {
1 // core
);
}
void ESP32Camera::dump_config() {
auto conf = this->config_;
ESP_LOGCONFIG(TAG, "ESP32 Camera:");
@ -106,17 +105,17 @@ void ESP32Camera::dump_config() {
ESP_LOGCONFIG(TAG, " Saturation: %d", st.saturation);
ESP_LOGCONFIG(TAG, " Vertical Flip: %s", ONOFF(st.vflip));
ESP_LOGCONFIG(TAG, " Horizontal Mirror: %s", ONOFF(st.hmirror));
// ESP_LOGCONFIG(TAG, " Special Effect: %u", st.special_effect);
// ESP_LOGCONFIG(TAG, " White Balance Mode: %u", st.wb_mode);
ESP_LOGCONFIG(TAG, " Special Effect: %u", st.special_effect);
ESP_LOGCONFIG(TAG, " White Balance Mode: %u", st.wb_mode);
// ESP_LOGCONFIG(TAG, " Auto White Balance: %u", st.awb);
// ESP_LOGCONFIG(TAG, " Auto White Balance Gain: %u", st.awb_gain);
// ESP_LOGCONFIG(TAG, " Auto Exposure Control: %u", st.aec);
ESP_LOGCONFIG(TAG, " Auto Exposure Control: %u", st.aec);
ESP_LOGCONFIG(TAG, " Auto Exposure Control 2: %u", st.aec2);
ESP_LOGCONFIG(TAG, " Auto Exposure Level: %d", st.ae_level);
ESP_LOGCONFIG(TAG, " Auto Exposure Value: %u", st.aec_value);
// ESP_LOGCONFIG(TAG, " AGC: %u", st.agc);
// ESP_LOGCONFIG(TAG, " AGC Gain: %u", st.agc_gain);
// ESP_LOGCONFIG(TAG, " Gain Ceiling: %u", st.gainceiling);
ESP_LOGCONFIG(TAG, " AGC: %u", st.agc);
ESP_LOGCONFIG(TAG, " AGC Gain: %u", st.agc_gain);
ESP_LOGCONFIG(TAG, " Gain Ceiling: %u", st.gainceiling);
// ESP_LOGCONFIG(TAG, " BPC: %u", st.bpc);
// ESP_LOGCONFIG(TAG, " WPC: %u", st.wpc);
// ESP_LOGCONFIG(TAG, " RAW_GMA: %u", st.raw_gma);
@ -124,6 +123,7 @@ void ESP32Camera::dump_config() {
// ESP_LOGCONFIG(TAG, " DCW: %u", st.dcw);
ESP_LOGCONFIG(TAG, " Test Pattern: %s", YESNO(st.colorbar));
}
void ESP32Camera::loop() {
// check if we can return the image
if (this->can_return_image_()) {
@ -170,15 +170,10 @@ void ESP32Camera::loop() {
this->last_update_ = now;
this->single_requesters_ = 0;
}
void ESP32Camera::framebuffer_task(void *pv) {
while (true) {
camera_fb_t *framebuffer = esp_camera_fb_get();
xQueueSend(global_esp32_camera->framebuffer_get_queue_, &framebuffer, portMAX_DELAY);
// return is no-op for config with 1 fb
xQueueReceive(global_esp32_camera->framebuffer_return_queue_, &framebuffer, portMAX_DELAY);
esp_camera_fb_return(framebuffer);
}
}
float ESP32Camera::get_setup_priority() const { return setup_priority::DATA; }
/* ---------------- constructors ---------------- */
ESP32Camera::ESP32Camera(const std::string &name) : EntityBase(name) {
this->config_.pin_pwdn = -1;
this->config_.pin_reset = -1;
@ -193,6 +188,9 @@ ESP32Camera::ESP32Camera(const std::string &name) : EntityBase(name) {
global_esp32_camera = this;
}
ESP32Camera::ESP32Camera() : ESP32Camera("") {}
/* ---------------- setters ---------------- */
/* set pin assignment */
void ESP32Camera::set_data_pins(std::array<uint8_t, 8> pins) {
this->config_.pin_d0 = pins[0];
this->config_.pin_d1 = pins[1];
@ -214,6 +212,10 @@ void ESP32Camera::set_i2c_pins(uint8_t sda, uint8_t scl) {
this->config_.pin_sscb_sda = sda;
this->config_.pin_sscb_scl = scl;
}
void ESP32Camera::set_reset_pin(uint8_t pin) { this->config_.pin_reset = pin; }
void ESP32Camera::set_power_down_pin(uint8_t pin) { this->config_.pin_pwdn = pin; }
/* set image parameters */
void ESP32Camera::set_frame_size(ESP32CameraFrameSize size) {
switch (size) {
case ESP32_CAMERA_SIZE_160X120:
@ -249,36 +251,81 @@ void ESP32Camera::set_frame_size(ESP32CameraFrameSize size) {
}
}
void ESP32Camera::set_jpeg_quality(uint8_t quality) { this->config_.jpeg_quality = quality; }
void ESP32Camera::set_reset_pin(uint8_t pin) { this->config_.pin_reset = pin; }
void ESP32Camera::set_power_down_pin(uint8_t pin) { this->config_.pin_pwdn = pin; }
void ESP32Camera::add_image_callback(std::function<void(std::shared_ptr<CameraImage>)> &&f) {
this->new_image_callback_.add(std::move(f));
}
void ESP32Camera::set_vertical_flip(bool vertical_flip) { this->vertical_flip_ = vertical_flip; }
void ESP32Camera::set_horizontal_mirror(bool horizontal_mirror) { this->horizontal_mirror_ = horizontal_mirror; }
void ESP32Camera::set_aec2(bool aec2) { this->aec2_ = aec2; }
void ESP32Camera::set_ae_level(int ae_level) { this->ae_level_ = ae_level; }
void ESP32Camera::set_aec_value(uint32_t aec_value) { this->aec_value_ = aec_value; }
void ESP32Camera::set_contrast(int contrast) { this->contrast_ = contrast; }
void ESP32Camera::set_brightness(int brightness) { this->brightness_ = brightness; }
void ESP32Camera::set_saturation(int saturation) { this->saturation_ = saturation; }
float ESP32Camera::get_setup_priority() const { return setup_priority::DATA; }
uint32_t ESP32Camera::hash_base() { return 3010542557UL; }
void ESP32Camera::request_image(CameraRequester requester) { this->single_requesters_ |= 1 << requester; }
void ESP32Camera::start_stream(CameraRequester requester) { this->stream_requesters_ |= 1 << requester; }
void ESP32Camera::stop_stream(CameraRequester requester) { this->stream_requesters_ &= ~(1 << requester); }
bool ESP32Camera::has_requested_image_() const { return this->single_requesters_ || this->stream_requesters_; }
bool ESP32Camera::can_return_image_() const { return this->current_image_.use_count() == 1; }
void ESP32Camera::set_special_effect(ESP32SpecialEffect effect) { this->special_effect_ = effect; }
/* set exposure parameters */
void ESP32Camera::set_aec_mode(ESP32GainControlMode mode) { this->aec_mode_ = mode; }
void ESP32Camera::set_aec2(bool aec2) { this->aec2_ = aec2; }
void ESP32Camera::set_ae_level(int ae_level) { this->ae_level_ = ae_level; }
void ESP32Camera::set_aec_value(uint32_t aec_value) { this->aec_value_ = aec_value; }
/* set gains parameters */
void ESP32Camera::set_agc_mode(ESP32GainControlMode mode) { this->agc_mode_ = mode; }
void ESP32Camera::set_agc_value(uint8_t agc_value) { this->agc_value_ = agc_value; }
void ESP32Camera::set_agc_gain_ceiling(ESP32AgcGainCeiling gain_ceiling) { this->agc_gain_ceiling_ = gain_ceiling; }
/* set white balance */
void ESP32Camera::set_wb_mode(ESP32WhiteBalanceMode mode) { this->wb_mode_ = mode; }
/* set test mode */
void ESP32Camera::set_test_pattern(bool test_pattern) { this->test_pattern_ = test_pattern; }
/* set fps */
void ESP32Camera::set_max_update_interval(uint32_t max_update_interval) {
this->max_update_interval_ = max_update_interval;
}
void ESP32Camera::set_idle_update_interval(uint32_t idle_update_interval) {
this->idle_update_interval_ = idle_update_interval;
}
void ESP32Camera::set_test_pattern(bool test_pattern) { this->test_pattern_ = test_pattern; }
/* ---------------- public API (specific) ---------------- */
void ESP32Camera::add_image_callback(std::function<void(std::shared_ptr<CameraImage>)> &&f) {
this->new_image_callback_.add(std::move(f));
}
void ESP32Camera::start_stream(CameraRequester requester) { this->stream_requesters_ |= (1U << requester); }
void ESP32Camera::stop_stream(CameraRequester requester) { this->stream_requesters_ &= ~(1U << requester); }
void ESP32Camera::request_image(CameraRequester requester) { this->single_requesters_ |= (1U << requester); }
void ESP32Camera::update_camera_parameters() {
sensor_t *s = esp_camera_sensor_get();
/* update image */
s->set_vflip(s, this->vertical_flip_);
s->set_hmirror(s, this->horizontal_mirror_);
s->set_contrast(s, this->contrast_);
s->set_brightness(s, this->brightness_);
s->set_saturation(s, this->saturation_);
s->set_special_effect(s, (int) this->special_effect_); // 0 to 6
/* update exposure */
s->set_exposure_ctrl(s, (bool) this->aec_mode_);
s->set_aec2(s, this->aec2_); // 0 = disable , 1 = enable
s->set_ae_level(s, this->ae_level_); // -2 to 2
s->set_aec_value(s, this->aec_value_); // 0 to 1200
/* update gains */
s->set_gain_ctrl(s, (bool) this->agc_mode_);
s->set_agc_gain(s, (int) this->agc_value_); // 0 to 30
s->set_gainceiling(s, (gainceiling_t) this->agc_gain_ceiling_);
/* update white balance mode */
s->set_wb_mode(s, (int) this->wb_mode_); // 0 to 4
/* update test patern */
s->set_colorbar(s, this->test_pattern_);
}
/* ---------------- Internal methods ---------------- */
uint32_t ESP32Camera::hash_base() { return 3010542557UL; }
bool ESP32Camera::has_requested_image_() const { return this->single_requesters_ || this->stream_requesters_; }
bool ESP32Camera::can_return_image_() const { return this->current_image_.use_count() == 1; }
void ESP32Camera::framebuffer_task(void *pv) {
while (true) {
camera_fb_t *framebuffer = esp_camera_fb_get();
xQueueSend(global_esp32_camera->framebuffer_get_queue_, &framebuffer, portMAX_DELAY);
// return is no-op for config with 1 fb
xQueueReceive(global_esp32_camera->framebuffer_return_queue_, &framebuffer, portMAX_DELAY);
esp_camera_fb_return(framebuffer);
}
}
ESP32Camera *global_esp32_camera; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
/* ---------------- CameraImageReader class ---------------- */
void CameraImageReader::set_image(std::shared_ptr<CameraImage> image) {
this->image_ = std::move(image);
this->offset_ = 0;
@ -293,13 +340,15 @@ void CameraImageReader::return_image() { this->image_.reset(); }
void CameraImageReader::consume_data(size_t consumed) { this->offset_ += consumed; }
uint8_t *CameraImageReader::peek_data_buffer() { return this->image_->get_data_buffer() + this->offset_; }
/* ---------------- CameraImage class ---------------- */
CameraImage::CameraImage(camera_fb_t *buffer, uint8_t requesters) : buffer_(buffer), requesters_(requesters) {}
camera_fb_t *CameraImage::get_raw_buffer() { return this->buffer_; }
uint8_t *CameraImage::get_data_buffer() { return this->buffer_->buf; }
size_t CameraImage::get_data_length() { return this->buffer_->len; }
bool CameraImage::was_requested_by(CameraRequester requester) const {
return (this->requesters_ & (1 << requester)) != 0;
}
CameraImage::CameraImage(camera_fb_t *buffer, uint8_t requesters) : buffer_(buffer), requesters_(requesters) {}
} // namespace esp32_camera
} // namespace esphome

View File

@ -14,34 +14,9 @@ namespace esp32_camera {
class ESP32Camera;
/* ---------------- enum classes ---------------- */
enum CameraRequester { IDLE, API_REQUESTER, WEB_REQUESTER };
class CameraImage {
public:
CameraImage(camera_fb_t *buffer, uint8_t requester);
camera_fb_t *get_raw_buffer();
uint8_t *get_data_buffer();
size_t get_data_length();
bool was_requested_by(CameraRequester requester) const;
protected:
camera_fb_t *buffer_;
uint8_t requesters_;
};
class CameraImageReader {
public:
void set_image(std::shared_ptr<CameraImage> image);
size_t available() const;
uint8_t *peek_data_buffer();
void consume_data(size_t consumed);
void return_image();
protected:
std::shared_ptr<CameraImage> image_;
size_t offset_{0};
};
enum ESP32CameraFrameSize {
ESP32_CAMERA_SIZE_160X120, // QQVGA
ESP32_CAMERA_SIZE_176X144, // QCIF
@ -55,57 +30,155 @@ enum ESP32CameraFrameSize {
ESP32_CAMERA_SIZE_1600X1200, // UXGA
};
enum ESP32AgcGainCeiling {
ESP32_GAINCEILING_2X = GAINCEILING_2X,
ESP32_GAINCEILING_4X = GAINCEILING_4X,
ESP32_GAINCEILING_8X = GAINCEILING_8X,
ESP32_GAINCEILING_16X = GAINCEILING_16X,
ESP32_GAINCEILING_32X = GAINCEILING_32X,
ESP32_GAINCEILING_64X = GAINCEILING_64X,
ESP32_GAINCEILING_128X = GAINCEILING_128X,
};
enum ESP32GainControlMode {
ESP32_GC_MODE_MANU = false,
ESP32_GC_MODE_AUTO = true,
};
enum ESP32WhiteBalanceMode {
ESP32_WB_MODE_AUTO = 0U,
ESP32_WB_MODE_SUNNY = 1U,
ESP32_WB_MODE_CLOUDY = 2U,
ESP32_WB_MODE_OFFICE = 3U,
ESP32_WB_MODE_HOME = 4U,
};
enum ESP32SpecialEffect {
ESP32_SPECIAL_EFFECT_NONE = 0U,
ESP32_SPECIAL_EFFECT_NEGATIVE = 1U,
ESP32_SPECIAL_EFFECT_GRAYSCALE = 2U,
ESP32_SPECIAL_EFFECT_RED_TINT = 3U,
ESP32_SPECIAL_EFFECT_GREEN_TINT = 4U,
ESP32_SPECIAL_EFFECT_BLUE_TINT = 5U,
ESP32_SPECIAL_EFFECT_SEPIA = 6U,
};
/* ---------------- CameraImage class ---------------- */
class CameraImage {
public:
CameraImage(camera_fb_t *buffer, uint8_t requester);
camera_fb_t *get_raw_buffer();
uint8_t *get_data_buffer();
size_t get_data_length();
bool was_requested_by(CameraRequester requester) const;
protected:
camera_fb_t *buffer_;
uint8_t requesters_;
};
/* ---------------- CameraImageReader class ---------------- */
class CameraImageReader {
public:
void set_image(std::shared_ptr<CameraImage> image);
size_t available() const;
uint8_t *peek_data_buffer();
void consume_data(size_t consumed);
void return_image();
protected:
std::shared_ptr<CameraImage> image_;
size_t offset_{0};
};
/* ---------------- ESP32Camera class ---------------- */
class ESP32Camera : public Component, public EntityBase {
public:
ESP32Camera(const std::string &name);
ESP32Camera();
/* setters */
/* -- pin assignment */
void set_data_pins(std::array<uint8_t, 8> pins);
void set_vsync_pin(uint8_t pin);
void set_href_pin(uint8_t pin);
void set_pixel_clock_pin(uint8_t pin);
void set_external_clock(uint8_t pin, uint32_t frequency);
void set_i2c_pins(uint8_t sda, uint8_t scl);
void set_frame_size(ESP32CameraFrameSize size);
void set_jpeg_quality(uint8_t quality);
void set_reset_pin(uint8_t pin);
void set_power_down_pin(uint8_t pin);
/* -- image */
void set_frame_size(ESP32CameraFrameSize size);
void set_jpeg_quality(uint8_t quality);
void set_vertical_flip(bool vertical_flip);
void set_horizontal_mirror(bool horizontal_mirror);
void set_aec2(bool aec2);
void set_ae_level(int ae_level);
void set_aec_value(uint32_t aec_value);
void set_contrast(int contrast);
void set_brightness(int brightness);
void set_saturation(int saturation);
void set_special_effect(ESP32SpecialEffect effect);
/* -- exposure */
void set_aec_mode(ESP32GainControlMode mode);
void set_aec2(bool aec2);
void set_ae_level(int ae_level);
void set_aec_value(uint32_t aec_value);
/* -- gains */
void set_agc_mode(ESP32GainControlMode mode);
void set_agc_value(uint8_t agc_value);
void set_agc_gain_ceiling(ESP32AgcGainCeiling gain_ceiling);
/* -- white balance */
void set_wb_mode(ESP32WhiteBalanceMode mode);
/* -- test */
void set_test_pattern(bool test_pattern);
/* -- framerates */
void set_max_update_interval(uint32_t max_update_interval);
void set_idle_update_interval(uint32_t idle_update_interval);
void set_test_pattern(bool test_pattern);
/* public API (derivated) */
void setup() override;
void loop() override;
void dump_config() override;
void add_image_callback(std::function<void(std::shared_ptr<CameraImage>)> &&f);
float get_setup_priority() const override;
/* public API (specific) */
void add_image_callback(std::function<void(std::shared_ptr<CameraImage>)> &&f);
void start_stream(CameraRequester requester);
void stop_stream(CameraRequester requester);
void request_image(CameraRequester requester);
void update_camera_parameters();
protected:
/* internal methods */
uint32_t hash_base() override;
bool has_requested_image_() const;
bool can_return_image_() const;
static void framebuffer_task(void *pv);
/* attributes */
/* camera configuration */
camera_config_t config_{};
/* -- image */
bool vertical_flip_{true};
bool horizontal_mirror_{true};
bool aec2_{false};
int ae_level_{0};
uint32_t aec_value_{300};
int contrast_{0};
int brightness_{0};
int saturation_{0};
ESP32SpecialEffect special_effect_{ESP32_SPECIAL_EFFECT_NONE};
/* -- exposure */
ESP32GainControlMode aec_mode_{ESP32_GC_MODE_AUTO};
bool aec2_{false};
int ae_level_{0};
uint32_t aec_value_{300};
/* -- gains */
ESP32GainControlMode agc_mode_{ESP32_GC_MODE_AUTO};
uint8_t agc_value_{0};
ESP32AgcGainCeiling agc_gain_ceiling_{ESP32_GAINCEILING_2X};
/* -- white balance */
ESP32WhiteBalanceMode wb_mode_{ESP32_WB_MODE_AUTO};
/* -- Test */
bool test_pattern_{false};
/* -- framerates */
uint32_t max_update_interval_{1000};
uint32_t idle_update_interval_{15000};
esp_err_t init_error_{ESP_OK};
std::shared_ptr<CameraImage> current_image_;
@ -114,8 +187,7 @@ class ESP32Camera : public Component, public EntityBase {
QueueHandle_t framebuffer_get_queue_;
QueueHandle_t framebuffer_return_queue_;
CallbackManager<void(std::shared_ptr<CameraImage>)> new_image_callback_;
uint32_t max_update_interval_{1000};
uint32_t idle_update_interval_{15000};
uint32_t last_idle_request_{0};
uint32_t last_update_{0};
};