1
0
mirror of https://github.com/esphome/esphome.git synced 2025-03-13 14:18:14 +00:00

Merge 6f02833e3a7d1f4a032db2a8cf891277b63f492e into 96682f5cbefe9cd38d76adac1dcef779ee25ff7e

This commit is contained in:
DT-art1 2025-02-24 19:36:19 +01:00 committed by GitHub
commit 2f0edf6e4c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 437 additions and 310 deletions

View File

@ -87,6 +87,7 @@ esphome/components/bp1658cj/* @Cossid
esphome/components/bp5758d/* @Cossid
esphome/components/button/* @esphome/core
esphome/components/bytebuffer/* @clydebarrow
esphome/components/camera/* @DT-art1
esphome/components/canbus/* @danielschramm @mvturnho
esphome/components/cap1188/* @mreditor97
esphome/components/captive_portal/* @OttoWinter

View File

@ -763,7 +763,7 @@ message ExecuteServiceRequest {
message ListEntitiesCameraResponse {
option (id) = 43;
option (source) = SOURCE_SERVER;
option (ifdef) = "USE_ESP32_CAMERA";
option (ifdef) = "USE_CAMERA";
string object_id = 1;
fixed32 key = 2;
@ -777,7 +777,7 @@ message ListEntitiesCameraResponse {
message CameraImageResponse {
option (id) = 44;
option (source) = SOURCE_SERVER;
option (ifdef) = "USE_ESP32_CAMERA";
option (ifdef) = "USE_CAMERA";
fixed32 key = 1;
bytes data = 2;
@ -786,7 +786,7 @@ message CameraImageResponse {
message CameraImageRequest {
option (id) = 45;
option (source) = SOURCE_CLIENT;
option (ifdef) = "USE_ESP32_CAMERA";
option (ifdef) = "USE_CAMERA";
option (no_delay) = true;
bool single = 1;

View File

@ -39,6 +39,12 @@ APIConnection::APIConnection(std::unique_ptr<socket::Socket> sock, APIServer *pa
#else
#error "No frame helper defined"
#endif
#ifdef USE_CAMERA
if (camera::Camera::instance() != nullptr) {
this->image_reader_ = std::unique_ptr<camera::CameraImageReader>{camera::Camera::instance()->create_image_reader()};
}
#endif
}
void APIConnection::start() {
this->last_traffic_ = millis();
@ -149,24 +155,24 @@ void APIConnection::loop() {
}
}
#ifdef USE_ESP32_CAMERA
if (this->image_reader_.available() && this->helper_->can_write_without_blocking()) {
uint32_t to_send = std::min((size_t) 1024, this->image_reader_.available());
#ifdef USE_CAMERA
if (this->image_reader_ && this->image_reader_->available() && this->helper_->can_write_without_blocking()) {
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, esp32_camera::global_esp32_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);
buffer.encode_bytes(2, this->image_reader_->peek_data_buffer(), to_send);
// bool done = 3;
bool done = this->image_reader_.available() == to_send;
bool done = this->image_reader_->available() == to_send;
buffer.encode_bool(3, done);
bool success = this->send_buffer(buffer, 44);
if (success) {
this->image_reader_.consume_data(to_send);
this->image_reader_->consume_data(to_send);
}
if (success && done) {
this->image_reader_.return_image();
this->image_reader_->return_image();
}
}
#endif
@ -1061,17 +1067,18 @@ void APIConnection::media_player_command(const MediaPlayerCommandRequest &msg) {
}
#endif
#ifdef USE_ESP32_CAMERA
void APIConnection::send_camera_state(std::shared_ptr<esp32_camera::CameraImage> image) {
#ifdef USE_CAMERA
void APIConnection::send_camera_state(std::shared_ptr<camera::CameraImage> image) {
if (!this->state_subscription_)
return;
if (this->image_reader_.available())
if (!this->image_reader_)
return;
if (image->was_requested_by(esphome::esp32_camera::API_REQUESTER) ||
image->was_requested_by(esphome::esp32_camera::IDLE))
this->image_reader_.set_image(std::move(image));
if (this->image_reader_->available())
return;
if (image->was_requested_by(esphome::camera::API_REQUESTER) || image->was_requested_by(esphome::camera::IDLE))
this->image_reader_->set_image(std::move(image));
}
bool APIConnection::send_camera_info(esp32_camera::ESP32Camera *camera) {
bool APIConnection::send_camera_info(camera::Camera *camera) {
ListEntitiesCameraResponse msg;
msg.key = camera->get_object_id_hash();
msg.object_id = camera->get_object_id();
@ -1084,17 +1091,16 @@ bool APIConnection::send_camera_info(esp32_camera::ESP32Camera *camera) {
return this->send_list_entities_camera_response(msg);
}
void APIConnection::camera_image(const CameraImageRequest &msg) {
if (esp32_camera::global_esp32_camera == nullptr)
if (camera::Camera::instance() == nullptr)
return;
if (msg.single)
esp32_camera::global_esp32_camera->request_image(esphome::esp32_camera::API_REQUESTER);
camera::Camera::instance()->request_image(esphome::camera::API_REQUESTER);
if (msg.stream) {
esp32_camera::global_esp32_camera->start_stream(esphome::esp32_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, []() {
esp32_camera::global_esp32_camera->stop_stream(esphome::esp32_camera::API_REQUESTER);
});
App.scheduler.set_timeout(this->parent_, "api_esp32_camera_stop_stream", ESP32_CAMERA_STOP_STREAM,
[]() { camera::Camera::instance()->stop_stream(esphome::camera::API_REQUESTER); });
}
}
#endif

View File

@ -58,9 +58,9 @@ class APIConnection : public APIServerConnection {
bool send_text_sensor_state(text_sensor::TextSensor *text_sensor, std::string state);
bool send_text_sensor_info(text_sensor::TextSensor *text_sensor);
#endif
#ifdef USE_ESP32_CAMERA
void send_camera_state(std::shared_ptr<esp32_camera::CameraImage> image);
bool send_camera_info(esp32_camera::ESP32Camera *camera);
#ifdef USE_CAMERA
void send_camera_state(std::shared_ptr<camera::CameraImage> image);
bool send_camera_info(camera::Camera *camera);
void camera_image(const CameraImageRequest &msg) override;
#endif
#ifdef USE_CLIMATE
@ -249,8 +249,8 @@ class APIConnection : public APIServerConnection {
std::string client_combined_info_;
uint32_t client_api_version_major_{0};
uint32_t client_api_version_minor_{0};
#ifdef USE_ESP32_CAMERA
esp32_camera::CameraImageReader image_reader_;
#ifdef USE_CAMERA
std::unique_ptr<camera::CameraImageReader> image_reader_;
#endif
bool state_subscription_{false};

View File

@ -210,7 +210,7 @@ bool APIServerConnectionBase::send_list_entities_services_response(const ListEnt
#endif
return this->send_message_<ListEntitiesServicesResponse>(msg, 41);
}
#ifdef USE_ESP32_CAMERA
#ifdef USE_CAMERA
bool APIServerConnectionBase::send_list_entities_camera_response(const ListEntitiesCameraResponse &msg) {
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "send_list_entities_camera_response: %s", msg.dump().c_str());
@ -218,7 +218,7 @@ bool APIServerConnectionBase::send_list_entities_camera_response(const ListEntit
return this->send_message_<ListEntitiesCameraResponse>(msg, 43);
}
#endif
#ifdef USE_ESP32_CAMERA
#ifdef USE_CAMERA
bool APIServerConnectionBase::send_camera_image_response(const CameraImageResponse &msg) {
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "send_camera_image_response: %s", msg.dump().c_str());
@ -226,7 +226,7 @@ bool APIServerConnectionBase::send_camera_image_response(const CameraImageRespon
return this->send_message_<CameraImageResponse>(msg, 44);
}
#endif
#ifdef USE_ESP32_CAMERA
#ifdef USE_CAMERA
#endif
#ifdef USE_CLIMATE
bool APIServerConnectionBase::send_list_entities_climate_response(const ListEntitiesClimateResponse &msg) {
@ -843,7 +843,7 @@ bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
break;
}
case 45: {
#ifdef USE_ESP32_CAMERA
#ifdef USE_CAMERA
CameraImageRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
@ -1363,7 +1363,7 @@ void APIServerConnection::on_switch_command_request(const SwitchCommandRequest &
this->switch_command(msg);
}
#endif
#ifdef USE_ESP32_CAMERA
#ifdef USE_CAMERA
void APIServerConnection::on_camera_image_request(const CameraImageRequest &msg) {
if (!this->is_connection_setup()) {
this->on_no_setup_connection();

View File

@ -94,13 +94,13 @@ class APIServerConnectionBase : public ProtoService {
virtual void on_get_time_response(const GetTimeResponse &value){};
bool send_list_entities_services_response(const ListEntitiesServicesResponse &msg);
virtual void on_execute_service_request(const ExecuteServiceRequest &value){};
#ifdef USE_ESP32_CAMERA
#ifdef USE_CAMERA
bool send_list_entities_camera_response(const ListEntitiesCameraResponse &msg);
#endif
#ifdef USE_ESP32_CAMERA
#ifdef USE_CAMERA
bool send_camera_image_response(const CameraImageResponse &msg);
#endif
#ifdef USE_ESP32_CAMERA
#ifdef USE_CAMERA
virtual void on_camera_image_request(const CameraImageRequest &value){};
#endif
#ifdef USE_CLIMATE
@ -361,7 +361,7 @@ class APIServerConnection : public APIServerConnectionBase {
#ifdef USE_SWITCH
virtual void switch_command(const SwitchCommandRequest &msg) = 0;
#endif
#ifdef USE_ESP32_CAMERA
#ifdef USE_CAMERA
virtual void camera_image(const CameraImageRequest &msg) = 0;
#endif
#ifdef USE_CLIMATE
@ -469,7 +469,7 @@ class APIServerConnection : public APIServerConnectionBase {
#ifdef USE_SWITCH
void on_switch_command_request(const SwitchCommandRequest &msg) override;
#endif
#ifdef USE_ESP32_CAMERA
#ifdef USE_CAMERA
void on_camera_image_request(const CameraImageRequest &msg) override;
#endif
#ifdef USE_CLIMATE

View File

@ -80,15 +80,14 @@ void APIServer::setup() {
this->last_connected_ = millis();
#ifdef USE_ESP32_CAMERA
if (esp32_camera::global_esp32_camera != nullptr && !esp32_camera::global_esp32_camera->is_internal()) {
esp32_camera::global_esp32_camera->add_image_callback(
[this](const std::shared_ptr<esp32_camera::CameraImage> &image) {
for (auto &c : this->clients_) {
if (!c->remove_)
c->send_camera_state(image);
}
});
#ifdef USE_CAMERA
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);
}
});
}
#endif
}

View File

@ -50,10 +50,8 @@ bool ListEntitiesIterator::on_service(UserServiceDescriptor *service) {
return this->client_->send_list_entities_services_response(resp);
}
#ifdef USE_ESP32_CAMERA
bool ListEntitiesIterator::on_camera(esp32_camera::ESP32Camera *camera) {
return this->client_->send_camera_info(camera);
}
#ifdef USE_CAMERA
bool ListEntitiesIterator::on_camera(camera::Camera *camera) { return this->client_->send_camera_info(camera); }
#endif
#ifdef USE_CLIMATE

View File

@ -37,8 +37,8 @@ class ListEntitiesIterator : public ComponentIterator {
bool on_text_sensor(text_sensor::TextSensor *text_sensor) override;
#endif
bool on_service(UserServiceDescriptor *service) override;
#ifdef USE_ESP32_CAMERA
bool on_camera(esp32_camera::ESP32Camera *camera) override;
#ifdef USE_CAMERA
bool on_camera(camera::Camera *camera) override;
#endif
#ifdef USE_CLIMATE
bool on_climate(climate::Climate *climate) override;

View File

@ -0,0 +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"]
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(),
)
CAMERA_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

@ -0,0 +1,33 @@
#include "camera.h"
namespace esphome {
namespace camera {
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Camera *Camera::global_camera = nullptr;
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

@ -0,0 +1,128 @@
#pragma once
#include "esphome/core/automation.h"
#include "esphome/core/component.h"
#include "esphome/core/entity_base.h"
#include "esphome/core/helpers.h"
namespace esphome {
namespace camera {
/** Different sources for filtering.
* IDLE: Camera requests to send an image to the API.
* API_REQUESTER: API requests a new image.
* WEB_REQUESTER: ESP32 web server request an image. Ignored by API.
*/
enum CameraRequester { IDLE, API_REQUESTER, WEB_REQUESTER };
/** Abstract camera image base class.
* Encapsulates the JPEG encoded data and it is shared among
* all connected clients.
*/
class CameraImage {
public:
virtual uint8_t *get_data_buffer() = 0;
virtual size_t get_data_length() = 0;
virtual bool was_requested_by(CameraRequester requester) const = 0;
virtual ~CameraImage() {}
};
/** Abstract image reader base class.
* Keeps track of the data offset of the camera image and
* how many bytes are remaining to read. When the image
* is returned, the shared_ptr is reset and the camera can
* reuse the memory of the camera image.
*/
class CameraImageReader {
public:
virtual void set_image(std::shared_ptr<CameraImage> image) = 0;
virtual size_t available() const = 0;
virtual uint8_t *peek_data_buffer() = 0;
virtual void consume_data(size_t consumed) = 0;
virtual void return_image() = 0;
virtual ~CameraImageReader() {}
};
/** Abstract camera base class. Collaborates with API.
* 1) API server starts and installs callback (add_image_callback)
* which is called by the camera when a new image is available.
* 2) New API client connects and creates a new image reader (create_image_reader).
* 3) API connection receives protobuf CameraImageRequest and calls request_image.
* 3.a) API connection receives protobuf CameraImageRequest and calls start_stream.
* 4) Camera implementation provides JPEG data in the CameraImage and calls callback.
* 5) API connection sets the image in the image reader.
* 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 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);
// 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.
virtual void request_image(CameraRequester requester) = 0;
// Connection, camera or web server requests a stream of images.
virtual void start_stream(CameraRequester requester) = 0;
// Connection or web server stops the previously started stream.
virtual void stop_stream(CameraRequester requester) = 0;
virtual ~Camera() {}
/// The singleton instance of the camera implementation.
static Camera *instance();
protected:
CallbackManager<void(std::shared_ptr<camera::CameraImage>)> new_image_callback_{};
CallbackManager<void()> stream_start_callback_{};
CallbackManager<void()> stream_stop_callback_{};
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
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,44 +1,30 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import automation
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 (
CONF_BRIGHTNESS,
CONF_CONTRAST,
CONF_DATA_PINS,
CONF_FREQUENCY,
CONF_ID,
CONF_PIN,
CONF_SCL,
CONF_SDA,
CONF_DATA_PINS,
CONF_RESET_PIN,
CONF_RESOLUTION,
CONF_BRIGHTNESS,
CONF_CONTRAST,
CONF_TRIGGER_ID,
CONF_SCL,
CONF_SDA,
CONF_VSYNC_PIN,
)
from esphome.core import CORE
from esphome.components.esp32 import add_idf_component
from esphome.cpp_helpers import setup_entity
DEPENDENCIES = ["esp32"]
AUTO_LOAD = ["psram"]
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,
@ -143,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.CAMERA_SCHEMA)
)
SETTERS = {
# pin assignment
@ -274,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:
@ -291,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_ESP32_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

@ -13,8 +13,6 @@ 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();
@ -36,7 +34,7 @@ void ESP32Camera::setup() {
xTaskCreatePinnedToCore(&ESP32Camera::framebuffer_task,
"framebuffer_task", // name
1024, // stack size
nullptr, // task pv params
this, // task pv params
1, // priority
nullptr, // handle
1 // core
@ -165,7 +163,7 @@ void ESP32Camera::loop() {
const uint32_t now = millis();
if (this->idle_update_interval_ != 0 && now - this->last_idle_request_ > this->idle_update_interval_) {
this->last_idle_request_ = now;
this->request_image(IDLE);
this->request_image(camera::IDLE);
}
// Check if we should fetch a new image
@ -191,7 +189,7 @@ void ESP32Camera::loop() {
xQueueSend(this->framebuffer_return_queue_, &fb, portMAX_DELAY);
return;
}
this->current_image_ = std::make_shared<CameraImage>(fb, this->single_requesters_ | this->stream_requesters_);
this->current_image_ = std::make_shared<ESP32CameraImage>(fb, this->single_requesters_ | this->stream_requesters_);
ESP_LOGD(TAG, "Got Image: len=%u", fb->len);
this->new_image_callback_.call(this->current_image_);
@ -214,8 +212,6 @@ ESP32Camera::ESP32Camera() {
this->config_.fb_count = 1;
this->config_.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
this->config_.fb_location = CAMERA_FB_IN_PSRAM;
global_esp32_camera = this;
}
/* ---------------- setters ---------------- */
@ -343,24 +339,19 @@ void ESP32Camera::set_frame_buffer_count(uint8_t fb_count) {
}
/* ---------------- public API (specific) ---------------- */
void ESP32Camera::add_image_callback(std::function<void(std::shared_ptr<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));
}
void ESP32Camera::start_stream(CameraRequester requester) {
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);
}
void ESP32Camera::stop_stream(CameraRequester requester) {
void ESP32Camera::stop_stream(camera::CameraRequester requester) {
this->stream_stop_callback_.call();
this->stream_requesters_ &= ~(1U << requester);
}
void ESP32Camera::request_image(CameraRequester requester) { this->single_requesters_ |= (1U << requester); }
void ESP32Camera::request_image(camera::CameraRequester requester) { this->single_requesters_ |= (1U << requester); }
void ESP32Camera::update_camera_parameters() {
sensor_t *s = esp_camera_sensor_get();
/* update image */
@ -389,39 +380,39 @@ void ESP32Camera::update_camera_parameters() {
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) {
ESP32Camera *that = (ESP32Camera *) pv;
while (true) {
camera_fb_t *framebuffer = esp_camera_fb_get();
xQueueSend(global_esp32_camera->framebuffer_get_queue_, &framebuffer, portMAX_DELAY);
xQueueSend(that->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);
xQueueReceive(that->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);
void ESP32CameraImageReader::set_image(std::shared_ptr<camera::CameraImage> image) {
this->image_ = std::static_pointer_cast<ESP32CameraImage>(image);
this->offset_ = 0;
}
size_t CameraImageReader::available() const {
size_t ESP32CameraImageReader::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_; }
void ESP32CameraImageReader::return_image() { this->image_.reset(); }
void ESP32CameraImageReader::consume_data(size_t consumed) { this->offset_ += consumed; }
uint8_t *ESP32CameraImageReader::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) {}
ESP32CameraImage::ESP32CameraImage(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 {
camera_fb_t *ESP32CameraImage::get_raw_buffer() { return this->buffer_; }
uint8_t *ESP32CameraImage::get_data_buffer() { return this->buffer_->buf; }
size_t ESP32CameraImage::get_data_length() { return this->buffer_->len; }
bool ESP32CameraImage::was_requested_by(camera::CameraRequester requester) const {
return (this->requesters_ & (1 << requester)) != 0;
}

View File

@ -4,7 +4,7 @@
#include "esphome/core/automation.h"
#include "esphome/core/component.h"
#include "esphome/core/entity_base.h"
#include "esphome/components/camera/camera.h"
#include "esphome/core/helpers.h"
#include <esp_camera.h>
#include <freertos/FreeRTOS.h>
@ -15,9 +15,6 @@ namespace esp32_camera {
class ESP32Camera;
/* ---------------- enum classes ---------------- */
enum CameraRequester { IDLE, API_REQUESTER, WEB_REQUESTER };
enum ESP32CameraFrameSize {
ESP32_CAMERA_SIZE_160X120, // QQVGA
ESP32_CAMERA_SIZE_176X144, // QCIF
@ -73,40 +70,35 @@ enum ESP32SpecialEffect {
};
/* ---------------- CameraImage class ---------------- */
class CameraImage {
class ESP32CameraImage : public camera::CameraImage {
public:
CameraImage(camera_fb_t *buffer, uint8_t requester);
ESP32CameraImage(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;
uint8_t *get_data_buffer() override;
size_t get_data_length() override;
bool was_requested_by(camera::CameraRequester requester) const override;
protected:
camera_fb_t *buffer_;
uint8_t requesters_;
};
struct CameraImageData {
uint8_t *data;
size_t length;
};
/* ---------------- CameraImageReader class ---------------- */
class CameraImageReader {
class ESP32CameraImageReader : public camera::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();
void set_image(std::shared_ptr<camera::CameraImage> image) override;
size_t available() const override;
uint8_t *peek_data_buffer() override;
void consume_data(size_t consumed) override;
void return_image() override;
protected:
std::shared_ptr<CameraImage> image_;
std::shared_ptr<ESP32CameraImage> image_;
size_t offset_{0};
};
/* ---------------- ESP32Camera class ---------------- */
class ESP32Camera : public Component, public EntityBase {
class ESP32Camera : public camera::Camera {
public:
ESP32Camera();
@ -155,14 +147,12 @@ class ESP32Camera : public Component, public EntityBase {
void dump_config() override;
float get_setup_priority() const override;
/* public API (specific) */
void start_stream(CameraRequester requester);
void stop_stream(CameraRequester requester);
void request_image(CameraRequester requester);
void start_stream(camera::CameraRequester requester) override;
void stop_stream(camera::CameraRequester requester) override;
void request_image(camera::CameraRequester requester) override;
void update_camera_parameters();
void add_image_callback(std::function<void(std::shared_ptr<CameraImage>)> &&callback);
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:
/* internal methods */
@ -199,51 +189,16 @@ class ESP32Camera : public Component, public EntityBase {
uint32_t idle_update_interval_{15000};
esp_err_t init_error_{ESP_OK};
std::shared_ptr<CameraImage> current_image_;
std::shared_ptr<ESP32CameraImage> current_image_;
uint8_t single_requesters_{0};
uint8_t stream_requesters_{0};
QueueHandle_t framebuffer_get_queue_;
QueueHandle_t framebuffer_return_queue_;
CallbackManager<void(std::shared_ptr<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};
};
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
extern ESP32Camera *global_esp32_camera;
class ESP32CameraImageTrigger : public Trigger<CameraImageData> {
public:
explicit ESP32CameraImageTrigger(ESP32Camera *parent) {
parent->add_image_callback([this](const std::shared_ptr<esp32_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

@ -1,9 +1,9 @@
import esphome.config_validation as cv
import esphome.codegen as cg
from esphome.const import CONF_ID, CONF_PORT, CONF_MODE
import esphome.config_validation as cv
from esphome.const import CONF_ID, CONF_MODE, CONF_PORT
CODEOWNERS = ["@ayufan"]
DEPENDENCIES = ["esp32_camera"]
AUTO_LOAD = ["camera"]
MULTI_CONF = True
esp32_camera_web_server_ns = cg.esphome_ns.namespace("esp32_camera_web_server")

View File

@ -40,7 +40,7 @@ CameraWebServer::CameraWebServer() {}
CameraWebServer::~CameraWebServer() {}
void CameraWebServer::setup() {
if (!esp32_camera::global_esp32_camera || esp32_camera::global_esp32_camera->is_failed()) {
if (!camera::Camera::instance() || camera::Camera::instance()->is_failed()) {
this->mark_failed();
return;
}
@ -67,8 +67,8 @@ void CameraWebServer::setup() {
httpd_register_uri_handler(this->httpd_, &uri);
esp32_camera::global_esp32_camera->add_image_callback([this](std::shared_ptr<esp32_camera::CameraImage> image) {
if (this->running_ && image->was_requested_by(esp32_camera::WEB_REQUESTER)) {
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_);
}
@ -106,8 +106,8 @@ void CameraWebServer::loop() {
}
}
std::shared_ptr<esphome::esp32_camera::CameraImage> CameraWebServer::wait_for_image_() {
std::shared_ptr<esphome::esp32_camera::CameraImage> image;
std::shared_ptr<esphome::camera::CameraImage> CameraWebServer::wait_for_image_() {
std::shared_ptr<esphome::camera::CameraImage> image;
image.swap(this->image_);
if (!image) {
@ -170,7 +170,7 @@ esp_err_t CameraWebServer::streaming_handler_(struct httpd_req *req) {
uint32_t last_frame = millis();
uint32_t frames = 0;
esp32_camera::global_esp32_camera->start_stream(esphome::esp32_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));
}
esp32_camera::global_esp32_camera->stop_stream(esphome::esp32_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;
esp32_camera::global_esp32_camera->request_image(esphome::esp32_camera::WEB_REQUESTER);
camera::Camera::instance()->request_image(esphome::camera::WEB_REQUESTER);
auto image = this->wait_for_image_();

View File

@ -6,7 +6,7 @@
#include <freertos/FreeRTOS.h>
#include <freertos/semphr.h>
#include "esphome/components/esp32_camera/esp32_camera.h"
#include "esphome/components/camera/camera.h"
#include "esphome/core/component.h"
#include "esphome/core/helpers.h"
#include "esphome/core/preferences.h"
@ -32,7 +32,7 @@ class CameraWebServer : public Component {
void loop() override;
protected:
std::shared_ptr<esphome::esp32_camera::CameraImage> wait_for_image_();
std::shared_ptr<camera::CameraImage> wait_for_image_();
esp_err_t handler_(struct httpd_req *req);
esp_err_t streaming_handler_(struct httpd_req *req);
esp_err_t snapshot_handler_(struct httpd_req *req);
@ -40,7 +40,7 @@ class CameraWebServer : public Component {
uint16_t port_{0};
void *httpd_{nullptr};
SemaphoreHandle_t semaphore_;
std::shared_ptr<esphome::esp32_camera::CameraImage> image_;
std::shared_ptr<camera::CameraImage> image_;
bool running_{false};
Mode mode_{STREAM};
};

View File

@ -158,16 +158,16 @@ void ComponentIterator::advance() {
}
break;
#endif
#ifdef USE_ESP32_CAMERA
#ifdef USE_CAMERA
case IteratorState::CAMERA:
if (esp32_camera::global_esp32_camera == nullptr) {
if (camera::Camera::instance() == nullptr) {
advance_platform = true;
} else {
if (esp32_camera::global_esp32_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(esp32_camera::global_esp32_camera);
advance_platform = success = this->on_camera(camera::Camera::instance());
}
}
break;
@ -386,8 +386,8 @@ bool ComponentIterator::on_begin() { return true; }
#ifdef USE_API
bool ComponentIterator::on_service(api::UserServiceDescriptor *service) { return true; }
#endif
#ifdef USE_ESP32_CAMERA
bool ComponentIterator::on_camera(esp32_camera::ESP32Camera *camera) { return true; }
#ifdef USE_CAMERA
bool ComponentIterator::on_camera(camera::Camera *camera) { return true; }
#endif
#ifdef USE_MEDIA_PLAYER
bool ComponentIterator::on_media_player(media_player::MediaPlayer *media_player) { return true; }

View File

@ -4,8 +4,8 @@
#include "esphome/core/controller.h"
#include "esphome/core/helpers.h"
#ifdef USE_ESP32_CAMERA
#include "esphome/components/esp32_camera/esp32_camera.h"
#ifdef USE_CAMERA
#include "esphome/components/camera/camera.h"
#endif
namespace esphome {
@ -48,8 +48,8 @@ class ComponentIterator {
#ifdef USE_API
virtual bool on_service(api::UserServiceDescriptor *service);
#endif
#ifdef USE_ESP32_CAMERA
virtual bool on_camera(esp32_camera::ESP32Camera *camera);
#ifdef USE_CAMERA
virtual bool on_camera(camera::Camera *camera);
#endif
#ifdef USE_CLIMATE
virtual bool on_climate(climate::Climate *climate) = 0;
@ -123,7 +123,7 @@ class ComponentIterator {
#ifdef USE_API
SERVICE,
#endif
#ifdef USE_ESP32_CAMERA
#ifdef USE_CAMERA
CAMERA,
#endif
#ifdef USE_CLIMATE

View File

@ -26,6 +26,7 @@
#define USE_API_PLAINTEXT
#define USE_BINARY_SENSOR
#define USE_BUTTON
#define USE_CAMERA
#define USE_CLIMATE
#define USE_COVER
#define USE_DATETIME
@ -108,7 +109,6 @@
#define USE_ESP32_BLE
#define USE_ESP32_BLE_CLIENT
#define USE_ESP32_BLE_SERVER
#define USE_ESP32_CAMERA
#define USE_IMPROV
#define USE_MICRO_WAKE_WORD_VAD
#define USE_MICROPHONE