mirror of
https://github.com/esphome/esphome.git
synced 2025-09-07 05:42:20 +01:00
🏗 Merge C++ into python codebase (#504)
## Description: Move esphome-core codebase into esphome (and a bunch of other refactors). See https://github.com/esphome/feature-requests/issues/97 Yes this is a shit ton of work and no there's no way to automate it :( But it will be worth it 👍 Progress: - Core support (file copy etc): 80% - Base Abstractions (light, switch): ~50% - Integrations: ~10% - Working? Yes, (but only with ported components). Other refactors: - Moves all codegen related stuff into a single class: `esphome.codegen` (imported as `cg`) - Rework coroutine syntax - Move from `component/platform.py` to `domain/component.py` structure as with HA - Move all defaults out of C++ and into config validation. - Remove `make_...` helpers from Application class. Reason: Merge conflicts with every single new integration. - Pointer Variables are stored globally instead of locally in setup(). Reason: stack size limit. Future work: - Rework const.py - Move all `CONF_...` into a conf class (usage `conf.UPDATE_INTERVAL` vs `CONF_UPDATE_INTERVAL`). Reason: Less convoluted import block - Enable loading from `custom_components` folder. **Related issue (if applicable):** https://github.com/esphome/feature-requests/issues/97 **Pull request in [esphome-docs](https://github.com/esphome/esphome-docs) with documentation (if applicable):** esphome/esphome-docs#<esphome-docs PR number goes here> ## Checklist: - [ ] The code change is tested and works locally. - [ ] Tests have been added to verify that the new code works (under `tests/` folder). If user exposed functionality or configuration variables are added/changed: - [ ] Documentation added/updated in [esphomedocs](https://github.com/OttoWinter/esphomedocs).
This commit is contained in:
130
esphome/components/esp32_camera/__init__.py
Normal file
130
esphome/components/esp32_camera/__init__.py
Normal file
@@ -0,0 +1,130 @@
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome import pins
|
||||
from esphome.const import CONF_FREQUENCY, CONF_ID, CONF_NAME, CONF_PIN, CONF_SCL, CONF_SDA, \
|
||||
ESP_PLATFORM_ESP32
|
||||
|
||||
ESP_PLATFORMS = [ESP_PLATFORM_ESP32]
|
||||
DEPENDENCIES = ['api']
|
||||
|
||||
esp32_camera_ns = cg.esphome_ns.namespace('esp32_camera')
|
||||
ESP32Camera = esp32_camera_ns.class_('ESP32Camera', cg.PollingComponent, cg.Nameable)
|
||||
ESP32CameraFrameSize = esp32_camera_ns.enum('ESP32CameraFrameSize')
|
||||
FRAME_SIZES = {
|
||||
'160X120': ESP32CameraFrameSize.ESP32_CAMERA_SIZE_160X120,
|
||||
'QQVGA': ESP32CameraFrameSize.ESP32_CAMERA_SIZE_160X120,
|
||||
'128X160': ESP32CameraFrameSize.ESP32_CAMERA_SIZE_128X160,
|
||||
'QQVGA2': ESP32CameraFrameSize.ESP32_CAMERA_SIZE_128X160,
|
||||
'176X144': ESP32CameraFrameSize.ESP32_CAMERA_SIZE_176X144,
|
||||
'QCIF': ESP32CameraFrameSize.ESP32_CAMERA_SIZE_176X144,
|
||||
'240X176': ESP32CameraFrameSize.ESP32_CAMERA_SIZE_240X176,
|
||||
'HQVGA': ESP32CameraFrameSize.ESP32_CAMERA_SIZE_240X176,
|
||||
'320X240': ESP32CameraFrameSize.ESP32_CAMERA_SIZE_320X240,
|
||||
'QVGA': ESP32CameraFrameSize.ESP32_CAMERA_SIZE_320X240,
|
||||
'400X296': ESP32CameraFrameSize.ESP32_CAMERA_SIZE_400X296,
|
||||
'CIF': ESP32CameraFrameSize.ESP32_CAMERA_SIZE_400X296,
|
||||
'640X480': ESP32CameraFrameSize.ESP32_CAMERA_SIZE_640X480,
|
||||
'VGA': ESP32CameraFrameSize.ESP32_CAMERA_SIZE_640X480,
|
||||
'800X600': ESP32CameraFrameSize.ESP32_CAMERA_SIZE_800X600,
|
||||
'SVGA': ESP32CameraFrameSize.ESP32_CAMERA_SIZE_800X600,
|
||||
'1024X768': ESP32CameraFrameSize.ESP32_CAMERA_SIZE_1024X768,
|
||||
'XGA': ESP32CameraFrameSize.ESP32_CAMERA_SIZE_1024X768,
|
||||
'1280X1024': ESP32CameraFrameSize.ESP32_CAMERA_SIZE_1280X1024,
|
||||
'SXGA': ESP32CameraFrameSize.ESP32_CAMERA_SIZE_1280X1024,
|
||||
'1600X1200': ESP32CameraFrameSize.ESP32_CAMERA_SIZE_1600X1200,
|
||||
'UXGA': ESP32CameraFrameSize.ESP32_CAMERA_SIZE_1600X1200,
|
||||
}
|
||||
|
||||
CONF_DATA_PINS = 'data_pins'
|
||||
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_RESET_PIN = 'reset_pin'
|
||||
CONF_POWER_DOWN_PIN = 'power_down_pin'
|
||||
|
||||
CONF_MAX_FRAMERATE = 'max_framerate'
|
||||
CONF_IDLE_FRAMERATE = 'idle_framerate'
|
||||
CONF_RESOLUTION = 'resolution'
|
||||
CONF_JPEG_QUALITY = 'jpeg_quality'
|
||||
CONF_VERTICAL_FLIP = 'vertical_flip'
|
||||
CONF_HORIZONTAL_MIRROR = 'horizontal_mirror'
|
||||
CONF_CONTRAST = 'contrast'
|
||||
CONF_BRIGHTNESS = 'brightness'
|
||||
CONF_SATURATION = 'saturation'
|
||||
CONF_TEST_PATTERN = 'test_pattern'
|
||||
|
||||
camera_range_param = cv.All(cv.int_, cv.Range(min=-2, max=2))
|
||||
|
||||
CONFIG_SCHEMA = cv.Schema({
|
||||
cv.GenerateID(): cv.declare_variable_id(ESP32Camera),
|
||||
cv.Required(CONF_NAME): cv.string,
|
||||
cv.Required(CONF_DATA_PINS): cv.All([pins.input_pin], cv.Length(min=8, max=8)),
|
||||
cv.Required(CONF_VSYNC_PIN): pins.input_pin,
|
||||
cv.Required(CONF_HREF_PIN): pins.input_pin,
|
||||
cv.Required(CONF_PIXEL_CLOCK_PIN): pins.input_pin,
|
||||
cv.Required(CONF_EXTERNAL_CLOCK): cv.Schema({
|
||||
cv.Required(CONF_PIN): pins.output_pin,
|
||||
cv.Optional(CONF_FREQUENCY, default='20MHz'): cv.All(cv.frequency, cv.one_of(20e6, 10e6)),
|
||||
}),
|
||||
cv.Required(CONF_I2C_PINS): cv.Schema({
|
||||
cv.Required(CONF_SDA): pins.output_pin,
|
||||
cv.Required(CONF_SCL): pins.output_pin,
|
||||
}),
|
||||
cv.Optional(CONF_RESET_PIN): pins.output_pin,
|
||||
cv.Optional(CONF_POWER_DOWN_PIN): pins.output_pin,
|
||||
|
||||
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)),
|
||||
cv.Optional(CONF_RESOLUTION, default='640X480'): cv.one_of(*FRAME_SIZES, upper=True),
|
||||
cv.Optional(CONF_JPEG_QUALITY, default=10): cv.All(cv.int_, cv.Range(min=10, max=63)),
|
||||
cv.Optional(CONF_CONTRAST, default=0): camera_range_param,
|
||||
cv.Optional(CONF_BRIGHTNESS, default=0): camera_range_param,
|
||||
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_TEST_PATTERN, default=False): cv.boolean,
|
||||
}).extend(cv.COMPONENT_SCHEMA)
|
||||
|
||||
SETTERS = {
|
||||
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',
|
||||
CONF_JPEG_QUALITY: 'set_jpeg_quality',
|
||||
CONF_VERTICAL_FLIP: 'set_vertical_flip',
|
||||
CONF_HORIZONTAL_MIRROR: 'set_horizontal_mirror',
|
||||
CONF_CONTRAST: 'set_contrast',
|
||||
CONF_BRIGHTNESS: 'set_brightness',
|
||||
CONF_SATURATION: 'set_saturation',
|
||||
CONF_TEST_PATTERN: 'set_test_pattern',
|
||||
}
|
||||
|
||||
|
||||
def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME])
|
||||
yield cg.register_component(var, config)
|
||||
|
||||
for key, setter in SETTERS.items():
|
||||
if key in config:
|
||||
cg.add(getattr(var, setter)(config[key]))
|
||||
|
||||
extclk = config[CONF_EXTERNAL_CLOCK]
|
||||
cg.add(var.set_external_clock(extclk[CONF_PIN], extclk[CONF_FREQUENCY]))
|
||||
i2c_pins = config[CONF_I2C_PINS]
|
||||
cg.add(var.set_i2c_pins(i2c_pins[CONF_SDA], i2c_pins[CONF_SCL]))
|
||||
cg.add(var.set_max_update_interval(1000 / config[CONF_MAX_FRAMERATE]))
|
||||
if config[CONF_IDLE_FRAMERATE] == 0:
|
||||
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_size(FRAME_SIZES[config[CONF_RESOLUTION]]))
|
||||
|
||||
cg.add_define('USE_ESP32_CAMERA')
|
||||
cg.add_build_flag('-DBOARD_HAS_PSRAM')
|
306
esphome/components/esp32_camera/esp32_camera.cpp
Normal file
306
esphome/components/esp32_camera/esp32_camera.cpp
Normal file
@@ -0,0 +1,306 @@
|
||||
#include "esp32_camera.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
|
||||
namespace esphome {
|
||||
namespace esp32_camera {
|
||||
|
||||
static const char *TAG = "esp32_camera";
|
||||
|
||||
void ESP32Camera::setup() {
|
||||
global_esp32_camera = this;
|
||||
|
||||
this->last_update_ = millis();
|
||||
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));
|
||||
this->init_error_ = err;
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
|
||||
sensor_t *s = esp_camera_sensor_get();
|
||||
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_colorbar(s, this->test_pattern_);
|
||||
this->framebuffer_get_queue_ = xQueueCreate(1, sizeof(camera_fb_t *));
|
||||
this->framebuffer_return_queue_ = xQueueCreate(1, sizeof(camera_fb_t *));
|
||||
xTaskCreatePinnedToCore(&ESP32Camera::framebuffer_task,
|
||||
"framebuffer_task", // name
|
||||
1024, // stack size
|
||||
nullptr, // task pv params
|
||||
0, // priority
|
||||
nullptr, // handle
|
||||
1 // core
|
||||
);
|
||||
}
|
||||
void ESP32Camera::dump_config() {
|
||||
auto conf = this->config_;
|
||||
ESP_LOGCONFIG(TAG, "ESP32 Camera:");
|
||||
ESP_LOGCONFIG(TAG, " Name: %s", this->name_.c_str());
|
||||
ESP_LOGCONFIG(TAG, " Board Has PSRAM: %s", YESNO(psramFound()));
|
||||
ESP_LOGCONFIG(TAG, " Data Pins: D0:%d D1:%d D2:%d D3:%d D4:%d D5:%d D6:%d D7:%d", conf.pin_d0, conf.pin_d1,
|
||||
conf.pin_d2, conf.pin_d3, conf.pin_d4, conf.pin_d5, conf.pin_d6, conf.pin_d7);
|
||||
ESP_LOGCONFIG(TAG, " VSYNC Pin: %d", conf.pin_vsync);
|
||||
ESP_LOGCONFIG(TAG, " HREF Pin: %d", conf.pin_href);
|
||||
ESP_LOGCONFIG(TAG, " Pixel Clock Pin: %d", conf.pin_pclk);
|
||||
ESP_LOGCONFIG(TAG, " External Clock: Pin:%d Frequency:%u", conf.pin_xclk, conf.xclk_freq_hz);
|
||||
ESP_LOGCONFIG(TAG, " I2C Pins: SDA:%d SCL:%d", conf.pin_sscb_sda, conf.pin_sscb_scl);
|
||||
ESP_LOGCONFIG(TAG, " Reset Pin: %d", conf.pin_reset);
|
||||
switch (this->config_.frame_size) {
|
||||
case FRAMESIZE_QQVGA:
|
||||
ESP_LOGCONFIG(TAG, " Resolution: 160x120 (QQVGA)");
|
||||
break;
|
||||
case FRAMESIZE_QQVGA2:
|
||||
ESP_LOGCONFIG(TAG, " Resolution: 128x160 (QQVGA2)");
|
||||
break;
|
||||
case FRAMESIZE_QCIF:
|
||||
ESP_LOGCONFIG(TAG, " Resolution: 176x155 (QCIF)");
|
||||
break;
|
||||
case FRAMESIZE_HQVGA:
|
||||
ESP_LOGCONFIG(TAG, " Resolution: 240x176 (HQVGA)");
|
||||
break;
|
||||
case FRAMESIZE_QVGA:
|
||||
ESP_LOGCONFIG(TAG, " Resolution: 320x240 (QVGA)");
|
||||
break;
|
||||
case FRAMESIZE_CIF:
|
||||
ESP_LOGCONFIG(TAG, " Resolution: 400x296 (CIF)");
|
||||
break;
|
||||
case FRAMESIZE_VGA:
|
||||
ESP_LOGCONFIG(TAG, " Resolution: 640x480 (VGA)");
|
||||
break;
|
||||
case FRAMESIZE_SVGA:
|
||||
ESP_LOGCONFIG(TAG, " Resolution: 800x600 (SVGA)");
|
||||
break;
|
||||
case FRAMESIZE_XGA:
|
||||
ESP_LOGCONFIG(TAG, " Resolution: 1024x768 (XGA)");
|
||||
break;
|
||||
case FRAMESIZE_SXGA:
|
||||
ESP_LOGCONFIG(TAG, " Resolution: 1280x1024 (SXGA)");
|
||||
break;
|
||||
case FRAMESIZE_UXGA:
|
||||
ESP_LOGCONFIG(TAG, " Resolution: 1600x1200 (UXGA)");
|
||||
break;
|
||||
}
|
||||
|
||||
if (this->is_failed()) {
|
||||
ESP_LOGE(TAG, " Setup Failed: %s", esp_err_to_name(this->init_error_));
|
||||
return;
|
||||
}
|
||||
|
||||
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, " Contrast: %d", st.contrast);
|
||||
ESP_LOGCONFIG(TAG, " Brightness: %d", st.brightness);
|
||||
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, " 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 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, " BPC: %u", st.bpc);
|
||||
// ESP_LOGCONFIG(TAG, " WPC: %u", st.wpc);
|
||||
// ESP_LOGCONFIG(TAG, " RAW_GMA: %u", st.raw_gma);
|
||||
// ESP_LOGCONFIG(TAG, " Lens Correction: %u", st.lenc);
|
||||
// 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_()) {
|
||||
// return image
|
||||
auto *fb = this->current_image_->get_raw_buffer();
|
||||
xQueueSend(this->framebuffer_return_queue_, &fb, portMAX_DELAY);
|
||||
this->current_image_.reset();
|
||||
}
|
||||
|
||||
// Check if we should fetch a new image
|
||||
if (!this->has_requested_image_())
|
||||
return;
|
||||
if (this->current_image_.use_count() > 1) {
|
||||
// image is still in use
|
||||
return;
|
||||
}
|
||||
const uint32_t now = millis();
|
||||
if (now - this->last_update_ <= this->max_update_interval_)
|
||||
return;
|
||||
|
||||
// request new image
|
||||
camera_fb_t *fb;
|
||||
if (xQueueReceive(this->framebuffer_get_queue_, &fb, 0L) != pdTRUE) {
|
||||
// no frame ready
|
||||
ESP_LOGVV(TAG, "No frame ready");
|
||||
return;
|
||||
}
|
||||
|
||||
if (fb == nullptr) {
|
||||
ESP_LOGW(TAG, "Got invalid frame from camera!");
|
||||
xQueueSend(this->framebuffer_return_queue_, &fb, portMAX_DELAY);
|
||||
return;
|
||||
}
|
||||
this->current_image_ = std::make_shared<CameraImage>(fb);
|
||||
|
||||
ESP_LOGD(TAG, "Got Image: len=%u", fb->len);
|
||||
this->new_image_callback_.call(this->current_image_);
|
||||
this->last_update_ = now;
|
||||
this->single_requester_ = false;
|
||||
}
|
||||
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::ESP32Camera(const std::string &name) : Nameable(name) {
|
||||
this->config_.pin_pwdn = -1;
|
||||
this->config_.pin_reset = -1;
|
||||
this->config_.pin_xclk = -1;
|
||||
this->config_.ledc_timer = LEDC_TIMER_0;
|
||||
this->config_.ledc_channel = LEDC_CHANNEL_0;
|
||||
this->config_.pixel_format = PIXFORMAT_JPEG;
|
||||
this->config_.frame_size = FRAMESIZE_VGA; // 640x480
|
||||
this->config_.jpeg_quality = 10;
|
||||
this->config_.fb_count = 1;
|
||||
|
||||
global_esp32_camera = this;
|
||||
}
|
||||
void ESP32Camera::set_data_pins(std::array<uint8_t, 8> pins) {
|
||||
this->config_.pin_d0 = pins[0];
|
||||
this->config_.pin_d1 = pins[1];
|
||||
this->config_.pin_d2 = pins[2];
|
||||
this->config_.pin_d3 = pins[3];
|
||||
this->config_.pin_d4 = pins[4];
|
||||
this->config_.pin_d5 = pins[5];
|
||||
this->config_.pin_d6 = pins[6];
|
||||
this->config_.pin_d7 = pins[7];
|
||||
}
|
||||
void ESP32Camera::set_vsync_pin(uint8_t pin) { this->config_.pin_vsync = pin; }
|
||||
void ESP32Camera::set_href_pin(uint8_t pin) { this->config_.pin_href = pin; }
|
||||
void ESP32Camera::set_pixel_clock_pin(uint8_t pin) { this->config_.pin_pclk = pin; }
|
||||
void ESP32Camera::set_external_clock(uint8_t pin, uint32_t frequency) {
|
||||
this->config_.pin_xclk = pin;
|
||||
this->config_.xclk_freq_hz = frequency;
|
||||
}
|
||||
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_frame_size(ESP32CameraFrameSize size) {
|
||||
switch (size) {
|
||||
case ESP32_CAMERA_SIZE_160X120:
|
||||
this->config_.frame_size = FRAMESIZE_QQVGA;
|
||||
break;
|
||||
case ESP32_CAMERA_SIZE_128X160:
|
||||
this->config_.frame_size = FRAMESIZE_QQVGA2;
|
||||
break;
|
||||
case ESP32_CAMERA_SIZE_176X144:
|
||||
this->config_.frame_size = FRAMESIZE_QCIF;
|
||||
break;
|
||||
case ESP32_CAMERA_SIZE_240X176:
|
||||
this->config_.frame_size = FRAMESIZE_HQVGA;
|
||||
break;
|
||||
case ESP32_CAMERA_SIZE_320X240:
|
||||
this->config_.frame_size = FRAMESIZE_QVGA;
|
||||
break;
|
||||
case ESP32_CAMERA_SIZE_400X296:
|
||||
this->config_.frame_size = FRAMESIZE_CIF;
|
||||
break;
|
||||
case ESP32_CAMERA_SIZE_640X480:
|
||||
this->config_.frame_size = FRAMESIZE_VGA;
|
||||
break;
|
||||
case ESP32_CAMERA_SIZE_800X600:
|
||||
this->config_.frame_size = FRAMESIZE_SVGA;
|
||||
break;
|
||||
case ESP32_CAMERA_SIZE_1024X768:
|
||||
this->config_.frame_size = FRAMESIZE_XGA;
|
||||
break;
|
||||
case ESP32_CAMERA_SIZE_1280X1024:
|
||||
this->config_.frame_size = FRAMESIZE_SXGA;
|
||||
break;
|
||||
case ESP32_CAMERA_SIZE_1600X1200:
|
||||
this->config_.frame_size = FRAMESIZE_UXGA;
|
||||
break;
|
||||
}
|
||||
}
|
||||
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_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() { this->single_requester_ = true; }
|
||||
void ESP32Camera::request_stream() { this->last_stream_request_ = millis(); }
|
||||
bool ESP32Camera::has_requested_image_() const {
|
||||
if (this->single_requester_)
|
||||
// single request
|
||||
return true;
|
||||
|
||||
uint32_t now = millis();
|
||||
if (now - this->last_stream_request_ < 5000)
|
||||
// stream request
|
||||
return true;
|
||||
|
||||
if (this->idle_update_interval_ != 0 && now - this->last_update_ > this->idle_update_interval_)
|
||||
// idle update
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
bool ESP32Camera::can_return_image_() const { return this->current_image_.use_count() == 1; }
|
||||
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; }
|
||||
|
||||
ESP32Camera *global_esp32_camera;
|
||||
|
||||
void CameraImageReader::set_image(std::shared_ptr<CameraImage> image) {
|
||||
this->image_ = image;
|
||||
this->offset_ = 0;
|
||||
}
|
||||
size_t CameraImageReader::available() const {
|
||||
if (!this->image_)
|
||||
return 0;
|
||||
|
||||
return this->image_->get_data_length() - this->offset_;
|
||||
}
|
||||
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_; }
|
||||
|
||||
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; }
|
||||
CameraImage::CameraImage(camera_fb_t *buffer) : buffer_(buffer) {}
|
||||
|
||||
} // namespace esp32_camera
|
||||
} // namespace esphome
|
||||
|
||||
#endif
|
113
esphome/components/esp32_camera/esp32_camera.h
Normal file
113
esphome/components/esp32_camera/esp32_camera.h
Normal file
@@ -0,0 +1,113 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include <esp_camera.h>
|
||||
|
||||
namespace esphome {
|
||||
namespace esp32_camera {
|
||||
|
||||
class ESP32Camera;
|
||||
|
||||
class CameraImage {
|
||||
public:
|
||||
CameraImage(camera_fb_t *buffer);
|
||||
camera_fb_t *get_raw_buffer();
|
||||
uint8_t *get_data_buffer();
|
||||
size_t get_data_length();
|
||||
|
||||
protected:
|
||||
camera_fb_t *buffer_;
|
||||
};
|
||||
|
||||
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_128X160, // QQVGA2
|
||||
ESP32_CAMERA_SIZE_176X144, // QCIF
|
||||
ESP32_CAMERA_SIZE_240X176, // HQVGA
|
||||
ESP32_CAMERA_SIZE_320X240, // QVGA
|
||||
ESP32_CAMERA_SIZE_400X296, // CIF
|
||||
ESP32_CAMERA_SIZE_640X480, // VGA
|
||||
ESP32_CAMERA_SIZE_800X600, // SVGA
|
||||
ESP32_CAMERA_SIZE_1024X768, // XGA
|
||||
ESP32_CAMERA_SIZE_1280X1024, // SXGA
|
||||
ESP32_CAMERA_SIZE_1600X1200, // UXGA
|
||||
};
|
||||
|
||||
class ESP32Camera : public Component, public Nameable {
|
||||
public:
|
||||
ESP32Camera(const std::string &name);
|
||||
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);
|
||||
void set_vertical_flip(bool vertical_flip);
|
||||
void set_horizontal_mirror(bool horizontal_mirror);
|
||||
void set_contrast(int contrast);
|
||||
void set_brightness(int brightness);
|
||||
void set_saturation(int saturation);
|
||||
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);
|
||||
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;
|
||||
void request_stream();
|
||||
void request_image();
|
||||
|
||||
protected:
|
||||
uint32_t hash_base() override;
|
||||
bool has_requested_image_() const;
|
||||
bool can_return_image_() const;
|
||||
|
||||
static void framebuffer_task(void *pv);
|
||||
|
||||
camera_config_t config_{};
|
||||
bool vertical_flip_{true};
|
||||
bool horizontal_mirror_{true};
|
||||
int contrast_{0};
|
||||
int brightness_{0};
|
||||
int saturation_{0};
|
||||
bool test_pattern_{false};
|
||||
|
||||
esp_err_t init_error_{ESP_OK};
|
||||
std::shared_ptr<CameraImage> current_image_;
|
||||
uint32_t last_stream_request_{0};
|
||||
bool single_requester_{false};
|
||||
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_update_{0};
|
||||
};
|
||||
|
||||
extern ESP32Camera *global_esp32_camera;
|
||||
|
||||
} // namespace esp32_camera
|
||||
} // namespace esphome
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user