mirror of
https://github.com/esphome/esphome.git
synced 2024-11-10 09:17:46 +01:00
Esp32cam full control (#3090)
This commit is contained in:
parent
28b65cb810
commit
1de941e837
3 changed files with 293 additions and 93 deletions
|
@ -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",
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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};
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue