Implemented review comments.

This commit is contained in:
Dieter Tschanz 2024-11-07 16:56:50 +01:00
parent 761b0bf2dc
commit 1dc0f19854
11 changed files with 228 additions and 198 deletions

View file

@ -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

View file

@ -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);

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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
)

View file

@ -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);
}

View file

@ -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

View file

@ -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_();

View file

@ -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;

View file

@ -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