mirror of
https://github.com/esphome/esphome.git
synced 2024-12-24 14:34:54 +01:00
Implemented review comments.
This commit is contained in:
parent
761b0bf2dc
commit
1dc0f19854
11 changed files with 228 additions and 198 deletions
|
@ -41,9 +41,8 @@ APIConnection::APIConnection(std::unique_ptr<socket::Socket> sock, APIServer *pa
|
|||
#endif
|
||||
|
||||
#ifdef USE_CAMERA
|
||||
if (camera::Camera::global_camera != nullptr) {
|
||||
this->image_reader_ =
|
||||
std::unique_ptr<camera::CameraImageReader>{camera::Camera::global_camera->create_image_reader()};
|
||||
if (camera::Camera::instance() != nullptr) {
|
||||
this->image_reader_ = std::unique_ptr<camera::CameraImageReader>{camera::Camera::instance()->create_image_reader()};
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -161,7 +160,7 @@ void APIConnection::loop() {
|
|||
uint32_t to_send = std::min((size_t) 1024, this->image_reader_->available());
|
||||
auto buffer = this->create_buffer();
|
||||
// fixed32 key = 1;
|
||||
buffer.encode_fixed32(1, camera::Camera::global_camera->get_object_id_hash());
|
||||
buffer.encode_fixed32(1, camera::Camera::instance()->get_object_id_hash());
|
||||
// bytes data = 2;
|
||||
buffer.encode_bytes(2, this->image_reader_->peek_data_buffer(), to_send);
|
||||
// bool done = 3;
|
||||
|
@ -1092,16 +1091,16 @@ bool APIConnection::send_camera_info(camera::Camera *camera) {
|
|||
return this->send_list_entities_camera_response(msg);
|
||||
}
|
||||
void APIConnection::camera_image(const CameraImageRequest &msg) {
|
||||
if (camera::Camera::global_camera == nullptr)
|
||||
if (camera::Camera::instance() == nullptr)
|
||||
return;
|
||||
|
||||
if (msg.single)
|
||||
camera::Camera::global_camera->request_image(esphome::camera::API_REQUESTER);
|
||||
camera::Camera::instance()->request_image(esphome::camera::API_REQUESTER);
|
||||
if (msg.stream) {
|
||||
camera::Camera::global_camera->start_stream(esphome::camera::API_REQUESTER);
|
||||
camera::Camera::instance()->start_stream(esphome::camera::API_REQUESTER);
|
||||
|
||||
App.scheduler.set_timeout(this->parent_, "api_esp32_camera_stop_stream", ESP32_CAMERA_STOP_STREAM,
|
||||
[]() { camera::Camera::global_camera->stop_stream(esphome::camera::API_REQUESTER); });
|
||||
[]() { camera::Camera::instance()->stop_stream(esphome::camera::API_REQUESTER); });
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -81,8 +81,8 @@ void APIServer::setup() {
|
|||
this->last_connected_ = millis();
|
||||
|
||||
#ifdef USE_CAMERA
|
||||
if (camera::Camera::global_camera != nullptr && !camera::Camera::global_camera->is_internal()) {
|
||||
camera::Camera::global_camera->add_image_callback([this](const std::shared_ptr<camera::CameraImage> &image) {
|
||||
if (camera::Camera::instance() != nullptr && !camera::Camera::instance()->is_internal()) {
|
||||
camera::Camera::instance()->add_image_callback([this](const std::shared_ptr<camera::CameraImage> &image) {
|
||||
for (auto &c : this->clients_) {
|
||||
if (!c->remove_)
|
||||
c->send_camera_state(image);
|
||||
|
|
|
@ -1,10 +1,63 @@
|
|||
from esphome import automation
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_TRIGGER_ID
|
||||
|
||||
CODEOWNERS = ["@DT-art1"]
|
||||
|
||||
CONFIG_SCHEMA = cv.Schema({})
|
||||
CONF_ON_STREAM_START = "on_stream_start"
|
||||
CONF_ON_STREAM_STOP = "on_stream_stop"
|
||||
CONF_ON_IMAGE = "on_image"
|
||||
|
||||
camera_ns = cg.esphome_ns.namespace("camera")
|
||||
Camera = camera_ns.class_("Camera", cg.Component, cg.EntityBase)
|
||||
CameraImageData = camera_ns.struct("CameraImageData")
|
||||
CameraImageTrigger = camera_ns.class_(
|
||||
"CameraImageTrigger", automation.Trigger.template()
|
||||
)
|
||||
CameraStreamStartTrigger = camera_ns.class_(
|
||||
"CameraStreamStartTrigger",
|
||||
automation.Trigger.template(),
|
||||
)
|
||||
CameraStreamStopTrigger = camera_ns.class_(
|
||||
"CameraStreamStopTrigger",
|
||||
automation.Trigger.template(),
|
||||
)
|
||||
|
||||
CONFIG_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.Optional(CONF_ON_STREAM_START): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(CameraStreamStartTrigger),
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_ON_STREAM_STOP): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(CameraStreamStopTrigger),
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_ON_IMAGE): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(CameraImageTrigger),
|
||||
}
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
cg.add_define("USE_CAMERA")
|
||||
|
||||
|
||||
async def setup_camera(var, config):
|
||||
for conf in config.get(CONF_ON_STREAM_START, []):
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||
await automation.build_automation(trigger, [], conf)
|
||||
|
||||
for conf in config.get(CONF_ON_STREAM_STOP, []):
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||
await automation.build_automation(trigger, [], conf)
|
||||
|
||||
for conf in config.get(CONF_ON_IMAGE, []):
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||
await automation.build_automation(trigger, [(CameraImageData, "image")], conf)
|
||||
|
|
|
@ -3,10 +3,30 @@
|
|||
namespace esphome {
|
||||
namespace camera {
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
Camera *Camera::global_camera = nullptr;
|
||||
|
||||
Camera::Camera() { global_camera = this; }
|
||||
Camera::Camera() {
|
||||
if (global_camera != nullptr) {
|
||||
mark_failed();
|
||||
return;
|
||||
}
|
||||
|
||||
global_camera = this;
|
||||
}
|
||||
|
||||
void Camera::add_image_callback(std::function<void(std::shared_ptr<CameraImage>)> &&callback) {
|
||||
this->new_image_callback_.add(std::move(callback));
|
||||
}
|
||||
|
||||
void Camera::add_stream_start_callback(std::function<void()> &&callback) {
|
||||
this->stream_start_callback_.add(std::move(callback));
|
||||
}
|
||||
|
||||
void Camera::add_stream_stop_callback(std::function<void()> &&callback) {
|
||||
this->stream_stop_callback_.add(std::move(callback));
|
||||
}
|
||||
|
||||
Camera *Camera::instance() { return global_camera; }
|
||||
|
||||
} // namespace camera
|
||||
} // namespace esphome
|
||||
|
|
|
@ -54,11 +54,15 @@ class CameraImageReader {
|
|||
* 6) API connection consumes data from the image reader and returns the image when finished.
|
||||
* 7.a) Camera caputes new image and continues with 4) until start_stream is called.
|
||||
*/
|
||||
class Camera : public EntityBase {
|
||||
class Camera : public Component, public EntityBase {
|
||||
public:
|
||||
Camera();
|
||||
// Camera implementation invokes callback to publish a new image.
|
||||
virtual void add_image_callback(std::function<void(std::shared_ptr<CameraImage>)> &&callback) = 0;
|
||||
virtual void add_image_callback(std::function<void(std::shared_ptr<CameraImage>)> &&callback);
|
||||
// Camera implementation invokes callback when start_stream is called.
|
||||
virtual void add_stream_start_callback(std::function<void()> &&callback);
|
||||
// Camera implementation invokes callback when stop_stream is called.
|
||||
virtual void add_stream_stop_callback(std::function<void()> &&callback);
|
||||
/// Returns a new camera image reader that keeps track of the JPEG data in the camera image.
|
||||
virtual CameraImageReader *create_image_reader() = 0;
|
||||
// Connection, camera or web server requests one new JPEG image.
|
||||
|
@ -69,9 +73,55 @@ class Camera : public EntityBase {
|
|||
virtual void stop_stream(CameraRequester requester) = 0;
|
||||
virtual ~Camera() {}
|
||||
/// The singleton instance of the camera implementation.
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
static Camera *instance();
|
||||
|
||||
protected:
|
||||
CallbackManager<void(std::shared_ptr<camera::CameraImage>)> new_image_callback_{};
|
||||
CallbackManager<void()> stream_start_callback_{};
|
||||
CallbackManager<void()> stream_stop_callback_{};
|
||||
static Camera *global_camera;
|
||||
};
|
||||
|
||||
/** Struct that encapsulates the image data for the CameraImageTrigger */
|
||||
struct CameraImageData {
|
||||
uint8_t *data;
|
||||
size_t length;
|
||||
};
|
||||
|
||||
/** Class that installs a camera callback which is triggered
|
||||
* every time a new image is captured.
|
||||
*/
|
||||
class CameraImageTrigger : public Trigger<CameraImageData> {
|
||||
public:
|
||||
explicit CameraImageTrigger(Camera *camera) {
|
||||
camera->add_image_callback([this](const std::shared_ptr<camera::CameraImage> &image) {
|
||||
CameraImageData camera_image_data{};
|
||||
camera_image_data.length = image->get_data_length();
|
||||
camera_image_data.data = image->get_data_buffer();
|
||||
this->trigger(camera_image_data);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/** Class that installs a camera callback which is triggered
|
||||
* every time a new image stream is requested.
|
||||
*/
|
||||
class CameraStreamStartTrigger : public Trigger<> {
|
||||
public:
|
||||
explicit CameraStreamStartTrigger(Camera *camera) {
|
||||
camera->add_stream_start_callback([this]() { this->trigger(); });
|
||||
}
|
||||
};
|
||||
|
||||
/** Class that installs a camera callback which is triggered
|
||||
* every time a image stream is stopped.
|
||||
*/
|
||||
class CameraStreamStopTrigger : public Trigger<> {
|
||||
public:
|
||||
explicit CameraStreamStopTrigger(Camera *camera) {
|
||||
camera->add_stream_stop_callback([this]() { this->trigger(); });
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace camera
|
||||
} // namespace esphome
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
from esphome import automation, pins
|
||||
from esphome import pins
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import camera
|
||||
from esphome.components.esp32 import add_idf_component
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import (
|
||||
|
@ -13,7 +14,6 @@ from esphome.const import (
|
|||
CONF_RESOLUTION,
|
||||
CONF_SCL,
|
||||
CONF_SDA,
|
||||
CONF_TRIGGER_ID,
|
||||
CONF_VSYNC_PIN,
|
||||
)
|
||||
from esphome.core import CORE
|
||||
|
@ -25,19 +25,6 @@ AUTO_LOAD = ["psram", "camera"]
|
|||
|
||||
esp32_camera_ns = cg.esphome_ns.namespace("esp32_camera")
|
||||
ESP32Camera = esp32_camera_ns.class_("ESP32Camera", cg.PollingComponent, cg.EntityBase)
|
||||
ESP32CameraImageData = esp32_camera_ns.struct("CameraImageData")
|
||||
# Triggers
|
||||
ESP32CameraImageTrigger = esp32_camera_ns.class_(
|
||||
"ESP32CameraImageTrigger", automation.Trigger.template()
|
||||
)
|
||||
ESP32CameraStreamStartTrigger = esp32_camera_ns.class_(
|
||||
"ESP32CameraStreamStartTrigger",
|
||||
automation.Trigger.template(),
|
||||
)
|
||||
ESP32CameraStreamStopTrigger = esp32_camera_ns.class_(
|
||||
"ESP32CameraStreamStopTrigger",
|
||||
automation.Trigger.template(),
|
||||
)
|
||||
ESP32CameraFrameSize = esp32_camera_ns.enum("ESP32CameraFrameSize")
|
||||
FRAME_SIZES = {
|
||||
"160X120": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_160X120,
|
||||
|
@ -142,100 +129,82 @@ CONF_IDLE_FRAMERATE = "idle_framerate"
|
|||
# frame buffer
|
||||
CONF_FRAME_BUFFER_COUNT = "frame_buffer_count"
|
||||
|
||||
# stream trigger
|
||||
CONF_ON_STREAM_START = "on_stream_start"
|
||||
CONF_ON_STREAM_STOP = "on_stream_stop"
|
||||
CONF_ON_IMAGE = "on_image"
|
||||
|
||||
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)
|
||||
),
|
||||
cv.Required(CONF_VSYNC_PIN): pins.internal_gpio_input_pin_number,
|
||||
cv.Required(CONF_HREF_PIN): pins.internal_gpio_input_pin_number,
|
||||
cv.Required(CONF_PIXEL_CLOCK_PIN): pins.internal_gpio_input_pin_number,
|
||||
cv.Required(CONF_EXTERNAL_CLOCK): cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_PIN): pins.internal_gpio_input_pin_number,
|
||||
cv.Optional(CONF_FREQUENCY, default="20MHz"): cv.All(
|
||||
cv.frequency, cv.Range(min=8e6, max=20e6)
|
||||
),
|
||||
}
|
||||
),
|
||||
cv.Required(CONF_I2C_PINS): cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_SDA): pins.internal_gpio_output_pin_number,
|
||||
cv.Required(CONF_SCL): pins.internal_gpio_output_pin_number,
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_RESET_PIN): pins.internal_gpio_output_pin_number,
|
||||
cv.Optional(CONF_POWER_DOWN_PIN): pins.internal_gpio_output_pin_number,
|
||||
# image
|
||||
cv.Optional(CONF_RESOLUTION, default="640X480"): cv.enum(
|
||||
FRAME_SIZES, upper=True
|
||||
),
|
||||
cv.Optional(CONF_JPEG_QUALITY, default=10): cv.int_range(min=6, 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_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)
|
||||
),
|
||||
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(
|
||||
ESP32CameraStreamStartTrigger
|
||||
),
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_ON_STREAM_STOP): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(
|
||||
ESP32CameraStreamStopTrigger
|
||||
),
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_ON_IMAGE): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ESP32CameraImageTrigger),
|
||||
}
|
||||
),
|
||||
}
|
||||
).extend(cv.COMPONENT_SCHEMA)
|
||||
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)
|
||||
),
|
||||
cv.Required(CONF_VSYNC_PIN): pins.internal_gpio_input_pin_number,
|
||||
cv.Required(CONF_HREF_PIN): pins.internal_gpio_input_pin_number,
|
||||
cv.Required(CONF_PIXEL_CLOCK_PIN): pins.internal_gpio_input_pin_number,
|
||||
cv.Required(CONF_EXTERNAL_CLOCK): cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_PIN): pins.internal_gpio_input_pin_number,
|
||||
cv.Optional(CONF_FREQUENCY, default="20MHz"): cv.All(
|
||||
cv.frequency, cv.Range(min=8e6, max=20e6)
|
||||
),
|
||||
}
|
||||
),
|
||||
cv.Required(CONF_I2C_PINS): cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_SDA): pins.internal_gpio_output_pin_number,
|
||||
cv.Required(CONF_SCL): pins.internal_gpio_output_pin_number,
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_RESET_PIN): pins.internal_gpio_output_pin_number,
|
||||
cv.Optional(CONF_POWER_DOWN_PIN): pins.internal_gpio_output_pin_number,
|
||||
# image
|
||||
cv.Optional(CONF_RESOLUTION, default="640X480"): cv.enum(
|
||||
FRAME_SIZES, upper=True
|
||||
),
|
||||
cv.Optional(CONF_JPEG_QUALITY, default=10): cv.int_range(min=6, 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_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)
|
||||
),
|
||||
cv.Optional(CONF_FRAME_BUFFER_COUNT, default=1): cv.int_range(min=1, max=2),
|
||||
}
|
||||
)
|
||||
.extend(cv.COMPONENT_SCHEMA)
|
||||
.extend(camera.CONFIG_SCHEMA)
|
||||
)
|
||||
|
||||
SETTERS = {
|
||||
# pin assignment
|
||||
|
@ -273,6 +242,7 @@ async def to_code(config):
|
|||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
await setup_entity(var, config)
|
||||
await cg.register_component(var, config)
|
||||
await camera.setup_camera(var, config)
|
||||
|
||||
for key, setter in SETTERS.items():
|
||||
if key in config:
|
||||
|
@ -290,25 +260,9 @@ async def to_code(config):
|
|||
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_CAMERA")
|
||||
|
||||
if CORE.using_esp_idf:
|
||||
add_idf_component(
|
||||
name="esp32-camera",
|
||||
repo="https://github.com/espressif/esp32-camera.git",
|
||||
ref="v2.0.9",
|
||||
)
|
||||
|
||||
for conf in config.get(CONF_ON_STREAM_START, []):
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||
await automation.build_automation(trigger, [], conf)
|
||||
|
||||
for conf in config.get(CONF_ON_STREAM_STOP, []):
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||
await automation.build_automation(trigger, [], conf)
|
||||
|
||||
for conf in config.get(CONF_ON_IMAGE, []):
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||
await automation.build_automation(
|
||||
trigger, [(ESP32CameraImageData, "image")], conf
|
||||
)
|
||||
|
|
|
@ -339,17 +339,11 @@ void ESP32Camera::set_frame_buffer_count(uint8_t fb_count) {
|
|||
}
|
||||
|
||||
/* ---------------- public API (specific) ---------------- */
|
||||
void ESP32Camera::add_image_callback(std::function<void(std::shared_ptr<camera::CameraImage>)> &&callback) {
|
||||
this->new_image_callback_.add(std::move(callback));
|
||||
}
|
||||
void ESP32Camera::add_stream_start_callback(std::function<void()> &&callback) {
|
||||
this->stream_start_callback_.add(std::move(callback));
|
||||
}
|
||||
void ESP32Camera::add_stream_stop_callback(std::function<void()> &&callback) {
|
||||
this->stream_stop_callback_.add(std::move(callback));
|
||||
}
|
||||
camera::CameraImageReader *ESP32Camera::create_image_reader() { return new ESP32CameraImageReader; }
|
||||
void ESP32Camera::start_stream(camera::CameraRequester requester) {
|
||||
if (this->stream_requesters_ & (1U << requester))
|
||||
return;
|
||||
|
||||
this->stream_start_callback_.call();
|
||||
this->stream_requesters_ |= (1U << requester);
|
||||
}
|
||||
|
|
|
@ -83,11 +83,6 @@ class ESP32CameraImage : public camera::CameraImage {
|
|||
uint8_t requesters_;
|
||||
};
|
||||
|
||||
struct CameraImageData {
|
||||
uint8_t *data;
|
||||
size_t length;
|
||||
};
|
||||
|
||||
/* ---------------- CameraImageReader class ---------------- */
|
||||
class ESP32CameraImageReader : public camera::CameraImageReader {
|
||||
public:
|
||||
|
@ -103,7 +98,7 @@ class ESP32CameraImageReader : public camera::CameraImageReader {
|
|||
};
|
||||
|
||||
/* ---------------- ESP32Camera class ---------------- */
|
||||
class ESP32Camera : public Component, public camera::Camera {
|
||||
class ESP32Camera : public camera::Camera {
|
||||
public:
|
||||
ESP32Camera();
|
||||
|
||||
|
@ -157,9 +152,6 @@ class ESP32Camera : public Component, public camera::Camera {
|
|||
void request_image(camera::CameraRequester requester) override;
|
||||
void update_camera_parameters();
|
||||
|
||||
void add_image_callback(std::function<void(std::shared_ptr<camera::CameraImage>)> &&callback) override;
|
||||
void add_stream_start_callback(std::function<void()> &&callback);
|
||||
void add_stream_stop_callback(std::function<void()> &&callback);
|
||||
camera::CameraImageReader *create_image_reader() override;
|
||||
|
||||
protected:
|
||||
|
@ -202,43 +194,11 @@ class ESP32Camera : public Component, public camera::Camera {
|
|||
uint8_t stream_requesters_{0};
|
||||
QueueHandle_t framebuffer_get_queue_;
|
||||
QueueHandle_t framebuffer_return_queue_;
|
||||
CallbackManager<void(std::shared_ptr<camera::CameraImage>)> new_image_callback_{};
|
||||
CallbackManager<void()> stream_start_callback_{};
|
||||
CallbackManager<void()> stream_stop_callback_{};
|
||||
|
||||
uint32_t last_idle_request_{0};
|
||||
uint32_t last_update_{0};
|
||||
};
|
||||
|
||||
class ESP32CameraImageTrigger : public Trigger<CameraImageData> {
|
||||
public:
|
||||
explicit ESP32CameraImageTrigger(ESP32Camera *parent) {
|
||||
parent->add_image_callback([this](const std::shared_ptr<camera::CameraImage> &image) {
|
||||
CameraImageData camera_image_data{};
|
||||
camera_image_data.length = image->get_data_length();
|
||||
camera_image_data.data = image->get_data_buffer();
|
||||
this->trigger(camera_image_data);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
class ESP32CameraStreamStartTrigger : public Trigger<> {
|
||||
public:
|
||||
explicit ESP32CameraStreamStartTrigger(ESP32Camera *parent) {
|
||||
parent->add_stream_start_callback([this]() { this->trigger(); });
|
||||
}
|
||||
|
||||
protected:
|
||||
};
|
||||
class ESP32CameraStreamStopTrigger : public Trigger<> {
|
||||
public:
|
||||
explicit ESP32CameraStreamStopTrigger(ESP32Camera *parent) {
|
||||
parent->add_stream_stop_callback([this]() { this->trigger(); });
|
||||
}
|
||||
|
||||
protected:
|
||||
};
|
||||
|
||||
} // namespace esp32_camera
|
||||
} // namespace esphome
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ CameraWebServer::CameraWebServer() {}
|
|||
CameraWebServer::~CameraWebServer() {}
|
||||
|
||||
void CameraWebServer::setup() {
|
||||
if (!camera::Camera::global_camera) {
|
||||
if (!camera::Camera::instance() || camera::Camera::instance()->is_failed()) {
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ void CameraWebServer::setup() {
|
|||
|
||||
httpd_register_uri_handler(this->httpd_, &uri);
|
||||
|
||||
camera::Camera::global_camera->add_image_callback([this](std::shared_ptr<camera::CameraImage> image) {
|
||||
camera::Camera::instance()->add_image_callback([this](std::shared_ptr<camera::CameraImage> image) {
|
||||
if (this->running_ && image->was_requested_by(camera::WEB_REQUESTER)) {
|
||||
this->image_ = std::move(image);
|
||||
xSemaphoreGive(this->semaphore_);
|
||||
|
@ -170,7 +170,7 @@ esp_err_t CameraWebServer::streaming_handler_(struct httpd_req *req) {
|
|||
uint32_t last_frame = millis();
|
||||
uint32_t frames = 0;
|
||||
|
||||
camera::Camera::global_camera->start_stream(esphome::camera::WEB_REQUESTER);
|
||||
camera::Camera::instance()->start_stream(esphome::camera::WEB_REQUESTER);
|
||||
|
||||
while (res == ESP_OK && this->running_) {
|
||||
auto image = this->wait_for_image_();
|
||||
|
@ -203,7 +203,7 @@ esp_err_t CameraWebServer::streaming_handler_(struct httpd_req *req) {
|
|||
res = httpd_send_all(req, STREAM_ERROR, strlen(STREAM_ERROR));
|
||||
}
|
||||
|
||||
camera::Camera::global_camera->stop_stream(esphome::camera::WEB_REQUESTER);
|
||||
camera::Camera::instance()->stop_stream(esphome::camera::WEB_REQUESTER);
|
||||
|
||||
ESP_LOGI(TAG, "STREAM: closed. Frames: %" PRIu32, frames);
|
||||
|
||||
|
@ -213,7 +213,7 @@ esp_err_t CameraWebServer::streaming_handler_(struct httpd_req *req) {
|
|||
esp_err_t CameraWebServer::snapshot_handler_(struct httpd_req *req) {
|
||||
esp_err_t res = ESP_OK;
|
||||
|
||||
camera::Camera::global_camera->request_image(esphome::camera::WEB_REQUESTER);
|
||||
camera::Camera::instance()->request_image(esphome::camera::WEB_REQUESTER);
|
||||
|
||||
auto image = this->wait_for_image_();
|
||||
|
||||
|
|
|
@ -160,14 +160,14 @@ void ComponentIterator::advance() {
|
|||
#endif
|
||||
#ifdef USE_CAMERA
|
||||
case IteratorState::CAMERA:
|
||||
if (camera::Camera::global_camera == nullptr) {
|
||||
if (camera::Camera::instance() == nullptr) {
|
||||
advance_platform = true;
|
||||
} else {
|
||||
if (camera::Camera::global_camera->is_internal() && !this->include_internal_) {
|
||||
if (camera::Camera::instance()->is_internal() && !this->include_internal_) {
|
||||
advance_platform = success = true;
|
||||
break;
|
||||
} else {
|
||||
advance_platform = success = this->on_camera(camera::Camera::global_camera);
|
||||
advance_platform = success = this->on_camera(camera::Camera::instance());
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#define USE_API_PLAINTEXT
|
||||
#define USE_BINARY_SENSOR
|
||||
#define USE_BUTTON
|
||||
#define USE_CAMERA
|
||||
#define USE_CLIMATE
|
||||
#define USE_COVER
|
||||
#define USE_DATETIME
|
||||
|
@ -102,7 +103,6 @@
|
|||
#define USE_ESP32_BLE
|
||||
#define USE_ESP32_BLE_CLIENT
|
||||
#define USE_ESP32_BLE_SERVER
|
||||
#define USE_CAMERA
|
||||
#define USE_IMPROV
|
||||
#define USE_MICRO_WAKE_WORD_VAD
|
||||
#define USE_MICROPHONE
|
||||
|
|
Loading…
Reference in a new issue