Merge branch 'dev' into update_libsodium

This commit is contained in:
J. Nick Koston 2025-06-29 22:49:46 -05:00 committed by GitHub
commit 480ea54ee0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
200 changed files with 2778 additions and 1354 deletions

View File

@ -4,7 +4,7 @@
repos: repos:
- repo: https://github.com/astral-sh/ruff-pre-commit - repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version. # Ruff version.
rev: v0.12.0 rev: v0.12.1
hooks: hooks:
# Run the linter. # Run the linter.
- id: ruff - id: ruff

View File

@ -332,6 +332,7 @@ esphome/components/pca6416a/* @Mat931
esphome/components/pca9554/* @clydebarrow @hwstar esphome/components/pca9554/* @clydebarrow @hwstar
esphome/components/pcf85063/* @brogon esphome/components/pcf85063/* @brogon
esphome/components/pcf8563/* @KoenBreeman esphome/components/pcf8563/* @KoenBreeman
esphome/components/pi4ioe5v6408/* @jesserockz
esphome/components/pid/* @OttoWinter esphome/components/pid/* @OttoWinter
esphome/components/pipsolar/* @andreashergert1984 esphome/components/pipsolar/* @andreashergert1984
esphome/components/pm1006/* @habbie esphome/components/pm1006/* @habbie

View File

@ -28,19 +28,24 @@ static const adc_atten_t ADC_ATTEN_DB_12_COMPAT = ADC_ATTEN_DB_11;
#endif #endif
#endif // USE_ESP32 #endif // USE_ESP32
enum class SamplingMode : uint8_t { AVG = 0, MIN = 1, MAX = 2 }; enum class SamplingMode : uint8_t {
AVG = 0,
MIN = 1,
MAX = 2,
};
const LogString *sampling_mode_to_str(SamplingMode mode); const LogString *sampling_mode_to_str(SamplingMode mode);
class Aggregator { class Aggregator {
public: public:
Aggregator(SamplingMode mode);
void add_sample(uint32_t value); void add_sample(uint32_t value);
uint32_t aggregate(); uint32_t aggregate();
Aggregator(SamplingMode mode);
protected: protected:
SamplingMode mode_{SamplingMode::AVG};
uint32_t aggr_{0}; uint32_t aggr_{0};
uint32_t samples_{0}; uint32_t samples_{0};
SamplingMode mode_{SamplingMode::AVG};
}; };
class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage_sampler::VoltageSampler { class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage_sampler::VoltageSampler {
@ -81,9 +86,9 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage
#endif // USE_RP2040 #endif // USE_RP2040
protected: protected:
InternalGPIOPin *pin_;
bool output_raw_{false};
uint8_t sample_count_{1}; uint8_t sample_count_{1};
bool output_raw_{false};
InternalGPIOPin *pin_;
SamplingMode sampling_mode_{SamplingMode::AVG}; SamplingMode sampling_mode_{SamplingMode::AVG};
#ifdef USE_RP2040 #ifdef USE_RP2040

View File

@ -61,7 +61,7 @@ uint32_t Aggregator::aggregate() {
void ADCSensor::update() { void ADCSensor::update() {
float value_v = this->sample(); float value_v = this->sample();
ESP_LOGV(TAG, "'%s': Got voltage=%.4fV", this->get_name().c_str(), value_v); ESP_LOGV(TAG, "'%s': Voltage=%.4fV", this->get_name().c_str(), value_v);
this->publish_state(value_v); this->publish_state(value_v);
} }

View File

@ -55,32 +55,40 @@ void ADCSensor::setup() {
} }
void ADCSensor::dump_config() { void ADCSensor::dump_config() {
static const char *const ATTEN_AUTO_STR = "auto";
static const char *const ATTEN_0DB_STR = "0 db";
static const char *const ATTEN_2_5DB_STR = "2.5 db";
static const char *const ATTEN_6DB_STR = "6 db";
static const char *const ATTEN_12DB_STR = "12 db";
const char *atten_str = ATTEN_AUTO_STR;
LOG_SENSOR("", "ADC Sensor", this); LOG_SENSOR("", "ADC Sensor", this);
LOG_PIN(" Pin: ", this->pin_); LOG_PIN(" Pin: ", this->pin_);
if (this->autorange_) {
ESP_LOGCONFIG(TAG, " Attenuation: auto"); if (!this->autorange_) {
} else {
switch (this->attenuation_) { switch (this->attenuation_) {
case ADC_ATTEN_DB_0: case ADC_ATTEN_DB_0:
ESP_LOGCONFIG(TAG, " Attenuation: 0db"); atten_str = ATTEN_0DB_STR;
break; break;
case ADC_ATTEN_DB_2_5: case ADC_ATTEN_DB_2_5:
ESP_LOGCONFIG(TAG, " Attenuation: 2.5db"); atten_str = ATTEN_2_5DB_STR;
break; break;
case ADC_ATTEN_DB_6: case ADC_ATTEN_DB_6:
ESP_LOGCONFIG(TAG, " Attenuation: 6db"); atten_str = ATTEN_6DB_STR;
break; break;
case ADC_ATTEN_DB_12_COMPAT: case ADC_ATTEN_DB_12_COMPAT:
ESP_LOGCONFIG(TAG, " Attenuation: 12db"); atten_str = ATTEN_12DB_STR;
break; break;
default: // This is to satisfy the unused ADC_ATTEN_MAX default: // This is to satisfy the unused ADC_ATTEN_MAX
break; break;
} }
} }
ESP_LOGCONFIG(TAG, ESP_LOGCONFIG(TAG,
" Attenuation: %s\n"
" Samples: %i\n" " Samples: %i\n"
" Sampling mode: %s", " Sampling mode: %s",
this->sample_count_, LOG_STR_ARG(sampling_mode_to_str(this->sampling_mode_))); atten_str, this->sample_count_, LOG_STR_ARG(sampling_mode_to_str(this->sampling_mode_)));
LOG_UPDATE_INTERVAL(this); LOG_UPDATE_INTERVAL(this);
} }

View File

@ -85,8 +85,6 @@ class ADE7880 : public i2c::I2CDevice, public PollingComponent {
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
protected: protected:
ADE7880Store store_{}; ADE7880Store store_{};
InternalGPIOPin *irq0_pin_{nullptr}; InternalGPIOPin *irq0_pin_{nullptr};

View File

@ -49,7 +49,6 @@ class ADS1115Component : public Component, public i2c::I2CDevice {
void setup() override; void setup() override;
void dump_config() override; void dump_config() override;
/// HARDWARE_LATE setup priority /// HARDWARE_LATE setup priority
float get_setup_priority() const override { return setup_priority::DATA; }
void set_continuous_mode(bool continuous_mode) { continuous_mode_ = continuous_mode; } void set_continuous_mode(bool continuous_mode) { continuous_mode_ = continuous_mode; }
/// Helper method to request a measurement from a sensor. /// Helper method to request a measurement from a sensor.

View File

@ -34,7 +34,6 @@ class ADS1118 : public Component,
ADS1118() = default; ADS1118() = default;
void setup() override; void setup() override;
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
/// Helper method to request a measurement from a sensor. /// Helper method to request a measurement from a sensor.
float request_measurement(ADS1118Multiplexer multiplexer, ADS1118Gain gain, bool temperature_mode); float request_measurement(ADS1118Multiplexer multiplexer, ADS1118Gain gain, bool temperature_mode);

View File

@ -31,8 +31,6 @@ class AGS10Component : public PollingComponent, public i2c::I2CDevice {
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
/** /**
* Modifies target address of AGS10. * Modifies target address of AGS10.
* *

View File

@ -66,7 +66,6 @@ class AIC3204 : public audio_dac::AudioDac, public Component, public i2c::I2CDev
public: public:
void setup() override; void setup() override;
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
bool set_mute_off() override; bool set_mute_off() override;
bool set_mute_on() override; bool set_mute_on() override;

View File

@ -41,7 +41,6 @@ class Alpha3 : public esphome::ble_client::BLEClientNode, public PollingComponen
void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
esp_ble_gattc_cb_param_t *param) override; esp_ble_gattc_cb_param_t *param) override;
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void set_flow_sensor(sensor::Sensor *sensor) { this->flow_sensor_ = sensor; } void set_flow_sensor(sensor::Sensor *sensor) { this->flow_sensor_ = sensor; }
void set_head_sensor(sensor::Sensor *sensor) { this->head_sensor_ = sensor; } void set_head_sensor(sensor::Sensor *sensor) { this->head_sensor_ = sensor; }
void set_power_sensor(sensor::Sensor *sensor) { this->power_sensor_ = sensor; } void set_power_sensor(sensor::Sensor *sensor) { this->power_sensor_ = sensor; }

View File

@ -22,7 +22,6 @@ class Am43Component : public cover::Cover, public esphome::ble_client::BLEClient
void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
esp_ble_gattc_cb_param_t *param) override; esp_ble_gattc_cb_param_t *param) override;
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
cover::CoverTraits get_traits() override; cover::CoverTraits get_traits() override;
void set_pin(uint16_t pin) { this->pin_ = pin; } void set_pin(uint16_t pin) { this->pin_ = pin; }
void set_invert_position(bool invert_position) { this->invert_position_ = invert_position; } void set_invert_position(bool invert_position) { this->invert_position_ = invert_position; }

View File

@ -22,7 +22,6 @@ class Am43 : public esphome::ble_client::BLEClientNode, public PollingComponent
void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
esp_ble_gattc_cb_param_t *param) override; esp_ble_gattc_cb_param_t *param) override;
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void set_battery(sensor::Sensor *battery) { battery_ = battery; } void set_battery(sensor::Sensor *battery) { battery_ = battery; }
void set_illuminance(sensor::Sensor *illuminance) { illuminance_ = illuminance; } void set_illuminance(sensor::Sensor *illuminance) { illuminance_ = illuminance; }

View File

@ -12,8 +12,6 @@ class AnalogThresholdBinarySensor : public Component, public binary_sensor::Bina
void dump_config() override; void dump_config() override;
void setup() override; void setup() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void set_sensor(sensor::Sensor *analog_sensor); void set_sensor(sensor::Sensor *analog_sensor);
template<typename T> void set_upper_threshold(T upper_threshold) { this->upper_threshold_ = upper_threshold; } template<typename T> void set_upper_threshold(T upper_threshold) { this->upper_threshold_ = upper_threshold; }
template<typename T> void set_lower_threshold(T lower_threshold) { this->lower_threshold_ = lower_threshold; } template<typename T> void set_lower_threshold(T lower_threshold) { this->lower_threshold_ = lower_threshold; }

View File

@ -26,7 +26,6 @@ class Anova : public climate::Climate, public esphome::ble_client::BLEClientNode
void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
esp_ble_gattc_cb_param_t *param) override; esp_ble_gattc_cb_param_t *param) override;
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
climate::ClimateTraits traits() override { climate::ClimateTraits traits() override {
auto traits = climate::ClimateTraits(); auto traits = climate::ClimateTraits();
traits.set_supports_current_temperature(true); traits.set_supports_current_temperature(true);

View File

@ -110,9 +110,10 @@ CONFIG_SCHEMA = cv.All(
): ACTIONS_SCHEMA, ): ACTIONS_SCHEMA,
cv.Exclusive(CONF_ACTIONS, group_of_exclusion=CONF_ACTIONS): ACTIONS_SCHEMA, cv.Exclusive(CONF_ACTIONS, group_of_exclusion=CONF_ACTIONS): ACTIONS_SCHEMA,
cv.Optional(CONF_ENCRYPTION): _encryption_schema, cv.Optional(CONF_ENCRYPTION): _encryption_schema,
cv.Optional( cv.Optional(CONF_BATCH_DELAY, default="100ms"): cv.All(
CONF_BATCH_DELAY, default="100ms" cv.positive_time_period_milliseconds,
): cv.positive_time_period_milliseconds, cv.Range(max=cv.TimePeriod(milliseconds=65535)),
),
cv.Optional(CONF_ON_CLIENT_CONNECTED): automation.validate_automation( cv.Optional(CONF_ON_CLIENT_CONNECTED): automation.validate_automation(
single=True single=True
), ),
@ -135,23 +136,26 @@ async def to_code(config):
cg.add(var.set_reboot_timeout(config[CONF_REBOOT_TIMEOUT])) cg.add(var.set_reboot_timeout(config[CONF_REBOOT_TIMEOUT]))
cg.add(var.set_batch_delay(config[CONF_BATCH_DELAY])) cg.add(var.set_batch_delay(config[CONF_BATCH_DELAY]))
for conf in config.get(CONF_ACTIONS, []): if actions := config.get(CONF_ACTIONS, []):
template_args = [] cg.add_define("USE_API_YAML_SERVICES")
func_args = [] for conf in actions:
service_arg_names = [] template_args = []
for name, var_ in conf[CONF_VARIABLES].items(): func_args = []
native = SERVICE_ARG_NATIVE_TYPES[var_] service_arg_names = []
template_args.append(native) for name, var_ in conf[CONF_VARIABLES].items():
func_args.append((native, name)) native = SERVICE_ARG_NATIVE_TYPES[var_]
service_arg_names.append(name) template_args.append(native)
templ = cg.TemplateArguments(*template_args) func_args.append((native, name))
trigger = cg.new_Pvariable( service_arg_names.append(name)
conf[CONF_TRIGGER_ID], templ, conf[CONF_ACTION], service_arg_names templ = cg.TemplateArguments(*template_args)
) trigger = cg.new_Pvariable(
cg.add(var.register_user_service(trigger)) conf[CONF_TRIGGER_ID], templ, conf[CONF_ACTION], service_arg_names
await automation.build_automation(trigger, func_args, conf) )
cg.add(var.register_user_service(trigger))
await automation.build_automation(trigger, func_args, conf)
if CONF_ON_CLIENT_CONNECTED in config: if CONF_ON_CLIENT_CONNECTED in config:
cg.add_define("USE_API_CLIENT_CONNECTED_TRIGGER")
await automation.build_automation( await automation.build_automation(
var.get_client_connected_trigger(), var.get_client_connected_trigger(),
[(cg.std_string, "client_info"), (cg.std_string, "client_address")], [(cg.std_string, "client_info"), (cg.std_string, "client_address")],
@ -159,6 +163,7 @@ async def to_code(config):
) )
if CONF_ON_CLIENT_DISCONNECTED in config: if CONF_ON_CLIENT_DISCONNECTED in config:
cg.add_define("USE_API_CLIENT_DISCONNECTED_TRIGGER")
await automation.build_automation( await automation.build_automation(
var.get_client_disconnected_trigger(), var.get_client_disconnected_trigger(),
[(cg.std_string, "client_info"), (cg.std_string, "client_address")], [(cg.std_string, "client_info"), (cg.std_string, "client_address")],

View File

@ -65,10 +65,6 @@ uint32_t APIConnection::get_batch_delay_ms_() const { return this->parent_->get_
void APIConnection::start() { void APIConnection::start() {
this->last_traffic_ = App.get_loop_component_start_time(); this->last_traffic_ = App.get_loop_component_start_time();
// Set next_ping_retry_ to prevent immediate ping
// This ensures the first ping happens after the keepalive period
this->next_ping_retry_ = this->last_traffic_ + KEEPALIVE_TIMEOUT_MS;
APIError err = this->helper_->init(); APIError err = this->helper_->init();
if (err != APIError::OK) { if (err != APIError::OK) {
on_fatal_error(); on_fatal_error();
@ -94,11 +90,24 @@ APIConnection::~APIConnection() {
#endif #endif
} }
#ifdef HAS_PROTO_MESSAGE_DUMP
void APIConnection::log_batch_item_(const DeferredBatch::BatchItem &item) {
// Set log-only mode
this->flags_.log_only_mode = true;
// Call the creator - it will create the message and log it via encode_message_to_buffer
item.creator(item.entity, this, std::numeric_limits<uint16_t>::max(), true, item.message_type);
// Clear log-only mode
this->flags_.log_only_mode = false;
}
#endif
void APIConnection::loop() { void APIConnection::loop() {
if (this->next_close_) { if (this->flags_.next_close) {
// requested a disconnect // requested a disconnect
this->helper_->close(); this->helper_->close();
this->remove_ = true; this->flags_.remove = true;
return; return;
} }
@ -139,15 +148,14 @@ void APIConnection::loop() {
} else { } else {
this->read_message(0, buffer.type, nullptr); this->read_message(0, buffer.type, nullptr);
} }
if (this->remove_) if (this->flags_.remove)
return; return;
} }
} }
} }
// Process deferred batch if scheduled // Process deferred batch if scheduled
if (this->deferred_batch_.batch_scheduled && if (this->flags_.batch_scheduled && now - this->deferred_batch_.batch_start_time >= this->get_batch_delay_ms_()) {
now - this->deferred_batch_.batch_start_time >= this->get_batch_delay_ms_()) {
this->process_batch_(); this->process_batch_();
} }
@ -157,26 +165,21 @@ void APIConnection::loop() {
this->initial_state_iterator_.advance(); this->initial_state_iterator_.advance();
} }
if (this->sent_ping_) { if (this->flags_.sent_ping) {
// Disconnect if not responded within 2.5*keepalive // Disconnect if not responded within 2.5*keepalive
if (now - this->last_traffic_ > KEEPALIVE_DISCONNECT_TIMEOUT) { if (now - this->last_traffic_ > KEEPALIVE_DISCONNECT_TIMEOUT) {
on_fatal_error(); on_fatal_error();
ESP_LOGW(TAG, "%s is unresponsive; disconnecting", this->get_client_combined_info().c_str()); ESP_LOGW(TAG, "%s is unresponsive; disconnecting", this->get_client_combined_info().c_str());
} }
} else if (now - this->last_traffic_ > KEEPALIVE_TIMEOUT_MS && now > this->next_ping_retry_) { } else if (now - this->last_traffic_ > KEEPALIVE_TIMEOUT_MS) {
ESP_LOGVV(TAG, "Sending keepalive PING"); ESP_LOGVV(TAG, "Sending keepalive PING");
this->sent_ping_ = this->send_message(PingRequest()); this->flags_.sent_ping = this->send_message(PingRequest());
if (!this->sent_ping_) { if (!this->flags_.sent_ping) {
this->next_ping_retry_ = now + PING_RETRY_INTERVAL; // If we can't send the ping request directly (tx_buffer full),
this->ping_retries_++; // schedule it at the front of the batch so it will be sent with priority
if (this->ping_retries_ >= MAX_PING_RETRIES) { ESP_LOGW(TAG, "Buffer full, ping queued");
on_fatal_error(); this->schedule_message_front_(nullptr, &APIConnection::try_send_ping_request, PingRequest::MESSAGE_TYPE);
ESP_LOGE(TAG, "%s: Ping failed %u times", this->get_client_combined_info().c_str(), this->ping_retries_); this->flags_.sent_ping = true; // Mark as sent to avoid scheduling multiple pings
} else if (this->ping_retries_ >= 10) {
ESP_LOGW(TAG, "%s: Ping retry %u", this->get_client_combined_info().c_str(), this->ping_retries_);
} else {
ESP_LOGD(TAG, "%s: Ping retry %u", this->get_client_combined_info().c_str(), this->ping_retries_);
}
} }
} }
@ -236,19 +239,27 @@ DisconnectResponse APIConnection::disconnect(const DisconnectRequest &msg) {
// don't close yet, we still need to send the disconnect response // don't close yet, we still need to send the disconnect response
// close will happen on next loop // close will happen on next loop
ESP_LOGD(TAG, "%s disconnected", this->get_client_combined_info().c_str()); ESP_LOGD(TAG, "%s disconnected", this->get_client_combined_info().c_str());
this->next_close_ = true; this->flags_.next_close = true;
DisconnectResponse resp; DisconnectResponse resp;
return resp; return resp;
} }
void APIConnection::on_disconnect_response(const DisconnectResponse &value) { void APIConnection::on_disconnect_response(const DisconnectResponse &value) {
this->helper_->close(); this->helper_->close();
this->remove_ = true; this->flags_.remove = true;
} }
// Encodes a message to the buffer and returns the total number of bytes used, // Encodes a message to the buffer and returns the total number of bytes used,
// including header and footer overhead. Returns 0 if the message doesn't fit. // including header and footer overhead. Returns 0 if the message doesn't fit.
uint16_t APIConnection::encode_message_to_buffer(ProtoMessage &msg, uint16_t message_type, APIConnection *conn, uint16_t APIConnection::encode_message_to_buffer(ProtoMessage &msg, uint16_t message_type, APIConnection *conn,
uint32_t remaining_size, bool is_single) { uint32_t remaining_size, bool is_single) {
#ifdef HAS_PROTO_MESSAGE_DUMP
// If in log-only mode, just log and return
if (conn->flags_.log_only_mode) {
conn->log_send_message_(msg.message_name(), msg.dump());
return 1; // Return non-zero to indicate "success" for logging
}
#endif
// Calculate size // Calculate size
uint32_t calculated_size = 0; uint32_t calculated_size = 0;
msg.calculate_size(calculated_size); msg.calculate_size(calculated_size);
@ -276,11 +287,6 @@ uint16_t APIConnection::encode_message_to_buffer(ProtoMessage &msg, uint16_t mes
// Encode directly into buffer // Encode directly into buffer
msg.encode(buffer); msg.encode(buffer);
#ifdef HAS_PROTO_MESSAGE_DUMP
// Log the message for VV debugging
conn->log_send_message_(msg.message_name(), msg.dump());
#endif
// Calculate actual encoded size (not including header that was already added) // Calculate actual encoded size (not including header that was already added)
size_t actual_payload_size = shared_buf.size() - size_before_encode; size_t actual_payload_size = shared_buf.size() - size_before_encode;
@ -297,10 +303,6 @@ bool APIConnection::send_binary_sensor_state(binary_sensor::BinarySensor *binary
return this->schedule_message_(binary_sensor, &APIConnection::try_send_binary_sensor_state, return this->schedule_message_(binary_sensor, &APIConnection::try_send_binary_sensor_state,
BinarySensorStateResponse::MESSAGE_TYPE); BinarySensorStateResponse::MESSAGE_TYPE);
} }
void APIConnection::send_binary_sensor_info(binary_sensor::BinarySensor *binary_sensor) {
this->schedule_message_(binary_sensor, &APIConnection::try_send_binary_sensor_info,
ListEntitiesBinarySensorResponse::MESSAGE_TYPE);
}
uint16_t APIConnection::try_send_binary_sensor_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, uint16_t APIConnection::try_send_binary_sensor_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single) { bool is_single) {
@ -328,9 +330,6 @@ uint16_t APIConnection::try_send_binary_sensor_info(EntityBase *entity, APIConne
bool APIConnection::send_cover_state(cover::Cover *cover) { bool APIConnection::send_cover_state(cover::Cover *cover) {
return this->schedule_message_(cover, &APIConnection::try_send_cover_state, CoverStateResponse::MESSAGE_TYPE); return this->schedule_message_(cover, &APIConnection::try_send_cover_state, CoverStateResponse::MESSAGE_TYPE);
} }
void APIConnection::send_cover_info(cover::Cover *cover) {
this->schedule_message_(cover, &APIConnection::try_send_cover_info, ListEntitiesCoverResponse::MESSAGE_TYPE);
}
uint16_t APIConnection::try_send_cover_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, uint16_t APIConnection::try_send_cover_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single) { bool is_single) {
auto *cover = static_cast<cover::Cover *>(entity); auto *cover = static_cast<cover::Cover *>(entity);
@ -392,9 +391,6 @@ void APIConnection::cover_command(const CoverCommandRequest &msg) {
bool APIConnection::send_fan_state(fan::Fan *fan) { bool APIConnection::send_fan_state(fan::Fan *fan) {
return this->schedule_message_(fan, &APIConnection::try_send_fan_state, FanStateResponse::MESSAGE_TYPE); return this->schedule_message_(fan, &APIConnection::try_send_fan_state, FanStateResponse::MESSAGE_TYPE);
} }
void APIConnection::send_fan_info(fan::Fan *fan) {
this->schedule_message_(fan, &APIConnection::try_send_fan_info, ListEntitiesFanResponse::MESSAGE_TYPE);
}
uint16_t APIConnection::try_send_fan_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, uint16_t APIConnection::try_send_fan_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single) { bool is_single) {
auto *fan = static_cast<fan::Fan *>(entity); auto *fan = static_cast<fan::Fan *>(entity);
@ -454,9 +450,6 @@ void APIConnection::fan_command(const FanCommandRequest &msg) {
bool APIConnection::send_light_state(light::LightState *light) { bool APIConnection::send_light_state(light::LightState *light) {
return this->schedule_message_(light, &APIConnection::try_send_light_state, LightStateResponse::MESSAGE_TYPE); return this->schedule_message_(light, &APIConnection::try_send_light_state, LightStateResponse::MESSAGE_TYPE);
} }
void APIConnection::send_light_info(light::LightState *light) {
this->schedule_message_(light, &APIConnection::try_send_light_info, ListEntitiesLightResponse::MESSAGE_TYPE);
}
uint16_t APIConnection::try_send_light_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, uint16_t APIConnection::try_send_light_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single) { bool is_single) {
auto *light = static_cast<light::LightState *>(entity); auto *light = static_cast<light::LightState *>(entity);
@ -549,9 +542,6 @@ void APIConnection::light_command(const LightCommandRequest &msg) {
bool APIConnection::send_sensor_state(sensor::Sensor *sensor) { bool APIConnection::send_sensor_state(sensor::Sensor *sensor) {
return this->schedule_message_(sensor, &APIConnection::try_send_sensor_state, SensorStateResponse::MESSAGE_TYPE); return this->schedule_message_(sensor, &APIConnection::try_send_sensor_state, SensorStateResponse::MESSAGE_TYPE);
} }
void APIConnection::send_sensor_info(sensor::Sensor *sensor) {
this->schedule_message_(sensor, &APIConnection::try_send_sensor_info, ListEntitiesSensorResponse::MESSAGE_TYPE);
}
uint16_t APIConnection::try_send_sensor_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, uint16_t APIConnection::try_send_sensor_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single) { bool is_single) {
@ -584,9 +574,6 @@ uint16_t APIConnection::try_send_sensor_info(EntityBase *entity, APIConnection *
bool APIConnection::send_switch_state(switch_::Switch *a_switch) { bool APIConnection::send_switch_state(switch_::Switch *a_switch) {
return this->schedule_message_(a_switch, &APIConnection::try_send_switch_state, SwitchStateResponse::MESSAGE_TYPE); return this->schedule_message_(a_switch, &APIConnection::try_send_switch_state, SwitchStateResponse::MESSAGE_TYPE);
} }
void APIConnection::send_switch_info(switch_::Switch *a_switch) {
this->schedule_message_(a_switch, &APIConnection::try_send_switch_info, ListEntitiesSwitchResponse::MESSAGE_TYPE);
}
uint16_t APIConnection::try_send_switch_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, uint16_t APIConnection::try_send_switch_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single) { bool is_single) {
@ -625,10 +612,6 @@ bool APIConnection::send_text_sensor_state(text_sensor::TextSensor *text_sensor)
return this->schedule_message_(text_sensor, &APIConnection::try_send_text_sensor_state, return this->schedule_message_(text_sensor, &APIConnection::try_send_text_sensor_state,
TextSensorStateResponse::MESSAGE_TYPE); TextSensorStateResponse::MESSAGE_TYPE);
} }
void APIConnection::send_text_sensor_info(text_sensor::TextSensor *text_sensor) {
this->schedule_message_(text_sensor, &APIConnection::try_send_text_sensor_info,
ListEntitiesTextSensorResponse::MESSAGE_TYPE);
}
uint16_t APIConnection::try_send_text_sensor_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, uint16_t APIConnection::try_send_text_sensor_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single) { bool is_single) {
@ -689,9 +672,6 @@ uint16_t APIConnection::try_send_climate_state(EntityBase *entity, APIConnection
resp.target_humidity = climate->target_humidity; resp.target_humidity = climate->target_humidity;
return encode_message_to_buffer(resp, ClimateStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single); return encode_message_to_buffer(resp, ClimateStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
} }
void APIConnection::send_climate_info(climate::Climate *climate) {
this->schedule_message_(climate, &APIConnection::try_send_climate_info, ListEntitiesClimateResponse::MESSAGE_TYPE);
}
uint16_t APIConnection::try_send_climate_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, uint16_t APIConnection::try_send_climate_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single) { bool is_single) {
auto *climate = static_cast<climate::Climate *>(entity); auto *climate = static_cast<climate::Climate *>(entity);
@ -759,9 +739,6 @@ void APIConnection::climate_command(const ClimateCommandRequest &msg) {
bool APIConnection::send_number_state(number::Number *number) { bool APIConnection::send_number_state(number::Number *number) {
return this->schedule_message_(number, &APIConnection::try_send_number_state, NumberStateResponse::MESSAGE_TYPE); return this->schedule_message_(number, &APIConnection::try_send_number_state, NumberStateResponse::MESSAGE_TYPE);
} }
void APIConnection::send_number_info(number::Number *number) {
this->schedule_message_(number, &APIConnection::try_send_number_info, ListEntitiesNumberResponse::MESSAGE_TYPE);
}
uint16_t APIConnection::try_send_number_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, uint16_t APIConnection::try_send_number_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single) { bool is_single) {
@ -813,9 +790,6 @@ uint16_t APIConnection::try_send_date_state(EntityBase *entity, APIConnection *c
fill_entity_state_base(date, resp); fill_entity_state_base(date, resp);
return encode_message_to_buffer(resp, DateStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single); return encode_message_to_buffer(resp, DateStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
} }
void APIConnection::send_date_info(datetime::DateEntity *date) {
this->schedule_message_(date, &APIConnection::try_send_date_info, ListEntitiesDateResponse::MESSAGE_TYPE);
}
uint16_t APIConnection::try_send_date_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, uint16_t APIConnection::try_send_date_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single) { bool is_single) {
auto *date = static_cast<datetime::DateEntity *>(entity); auto *date = static_cast<datetime::DateEntity *>(entity);
@ -850,9 +824,6 @@ uint16_t APIConnection::try_send_time_state(EntityBase *entity, APIConnection *c
fill_entity_state_base(time, resp); fill_entity_state_base(time, resp);
return encode_message_to_buffer(resp, TimeStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single); return encode_message_to_buffer(resp, TimeStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
} }
void APIConnection::send_time_info(datetime::TimeEntity *time) {
this->schedule_message_(time, &APIConnection::try_send_time_info, ListEntitiesTimeResponse::MESSAGE_TYPE);
}
uint16_t APIConnection::try_send_time_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, uint16_t APIConnection::try_send_time_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single) { bool is_single) {
auto *time = static_cast<datetime::TimeEntity *>(entity); auto *time = static_cast<datetime::TimeEntity *>(entity);
@ -889,9 +860,6 @@ uint16_t APIConnection::try_send_datetime_state(EntityBase *entity, APIConnectio
fill_entity_state_base(datetime, resp); fill_entity_state_base(datetime, resp);
return encode_message_to_buffer(resp, DateTimeStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single); return encode_message_to_buffer(resp, DateTimeStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
} }
void APIConnection::send_datetime_info(datetime::DateTimeEntity *datetime) {
this->schedule_message_(datetime, &APIConnection::try_send_datetime_info, ListEntitiesDateTimeResponse::MESSAGE_TYPE);
}
uint16_t APIConnection::try_send_datetime_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, uint16_t APIConnection::try_send_datetime_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single) { bool is_single) {
auto *datetime = static_cast<datetime::DateTimeEntity *>(entity); auto *datetime = static_cast<datetime::DateTimeEntity *>(entity);
@ -915,9 +883,6 @@ void APIConnection::datetime_command(const DateTimeCommandRequest &msg) {
bool APIConnection::send_text_state(text::Text *text) { bool APIConnection::send_text_state(text::Text *text) {
return this->schedule_message_(text, &APIConnection::try_send_text_state, TextStateResponse::MESSAGE_TYPE); return this->schedule_message_(text, &APIConnection::try_send_text_state, TextStateResponse::MESSAGE_TYPE);
} }
void APIConnection::send_text_info(text::Text *text) {
this->schedule_message_(text, &APIConnection::try_send_text_info, ListEntitiesTextResponse::MESSAGE_TYPE);
}
uint16_t APIConnection::try_send_text_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, uint16_t APIConnection::try_send_text_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single) { bool is_single) {
@ -956,9 +921,6 @@ void APIConnection::text_command(const TextCommandRequest &msg) {
bool APIConnection::send_select_state(select::Select *select) { bool APIConnection::send_select_state(select::Select *select) {
return this->schedule_message_(select, &APIConnection::try_send_select_state, SelectStateResponse::MESSAGE_TYPE); return this->schedule_message_(select, &APIConnection::try_send_select_state, SelectStateResponse::MESSAGE_TYPE);
} }
void APIConnection::send_select_info(select::Select *select) {
this->schedule_message_(select, &APIConnection::try_send_select_info, ListEntitiesSelectResponse::MESSAGE_TYPE);
}
uint16_t APIConnection::try_send_select_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, uint16_t APIConnection::try_send_select_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single) { bool is_single) {
@ -992,9 +954,6 @@ void APIConnection::select_command(const SelectCommandRequest &msg) {
#endif #endif
#ifdef USE_BUTTON #ifdef USE_BUTTON
void esphome::api::APIConnection::send_button_info(button::Button *button) {
this->schedule_message_(button, &APIConnection::try_send_button_info, ListEntitiesButtonResponse::MESSAGE_TYPE);
}
uint16_t APIConnection::try_send_button_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, uint16_t APIConnection::try_send_button_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single) { bool is_single) {
auto *button = static_cast<button::Button *>(entity); auto *button = static_cast<button::Button *>(entity);
@ -1017,9 +976,6 @@ void esphome::api::APIConnection::button_command(const ButtonCommandRequest &msg
bool APIConnection::send_lock_state(lock::Lock *a_lock) { bool APIConnection::send_lock_state(lock::Lock *a_lock) {
return this->schedule_message_(a_lock, &APIConnection::try_send_lock_state, LockStateResponse::MESSAGE_TYPE); return this->schedule_message_(a_lock, &APIConnection::try_send_lock_state, LockStateResponse::MESSAGE_TYPE);
} }
void APIConnection::send_lock_info(lock::Lock *a_lock) {
this->schedule_message_(a_lock, &APIConnection::try_send_lock_info, ListEntitiesLockResponse::MESSAGE_TYPE);
}
uint16_t APIConnection::try_send_lock_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, uint16_t APIConnection::try_send_lock_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single) { bool is_single) {
@ -1073,9 +1029,6 @@ uint16_t APIConnection::try_send_valve_state(EntityBase *entity, APIConnection *
fill_entity_state_base(valve, resp); fill_entity_state_base(valve, resp);
return encode_message_to_buffer(resp, ValveStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single); return encode_message_to_buffer(resp, ValveStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
} }
void APIConnection::send_valve_info(valve::Valve *valve) {
this->schedule_message_(valve, &APIConnection::try_send_valve_info, ListEntitiesValveResponse::MESSAGE_TYPE);
}
uint16_t APIConnection::try_send_valve_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, uint16_t APIConnection::try_send_valve_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single) { bool is_single) {
auto *valve = static_cast<valve::Valve *>(entity); auto *valve = static_cast<valve::Valve *>(entity);
@ -1121,10 +1074,6 @@ uint16_t APIConnection::try_send_media_player_state(EntityBase *entity, APIConne
fill_entity_state_base(media_player, resp); fill_entity_state_base(media_player, resp);
return encode_message_to_buffer(resp, MediaPlayerStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single); return encode_message_to_buffer(resp, MediaPlayerStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
} }
void APIConnection::send_media_player_info(media_player::MediaPlayer *media_player) {
this->schedule_message_(media_player, &APIConnection::try_send_media_player_info,
ListEntitiesMediaPlayerResponse::MESSAGE_TYPE);
}
uint16_t APIConnection::try_send_media_player_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, uint16_t APIConnection::try_send_media_player_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single) { bool is_single) {
auto *media_player = static_cast<media_player::MediaPlayer *>(entity); auto *media_player = static_cast<media_player::MediaPlayer *>(entity);
@ -1168,7 +1117,7 @@ void APIConnection::media_player_command(const MediaPlayerCommandRequest &msg) {
#ifdef USE_ESP32_CAMERA #ifdef USE_ESP32_CAMERA
void APIConnection::set_camera_state(std::shared_ptr<esp32_camera::CameraImage> image) { void APIConnection::set_camera_state(std::shared_ptr<esp32_camera::CameraImage> image) {
if (!this->state_subscription_) if (!this->flags_.state_subscription)
return; return;
if (this->image_reader_.available()) if (this->image_reader_.available())
return; return;
@ -1176,9 +1125,6 @@ void APIConnection::set_camera_state(std::shared_ptr<esp32_camera::CameraImage>
image->was_requested_by(esphome::esp32_camera::IDLE)) image->was_requested_by(esphome::esp32_camera::IDLE))
this->image_reader_.set_image(std::move(image)); this->image_reader_.set_image(std::move(image));
} }
void APIConnection::send_camera_info(esp32_camera::ESP32Camera *camera) {
this->schedule_message_(camera, &APIConnection::try_send_camera_info, ListEntitiesCameraResponse::MESSAGE_TYPE);
}
uint16_t APIConnection::try_send_camera_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, uint16_t APIConnection::try_send_camera_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single) { bool is_single) {
auto *camera = static_cast<esp32_camera::ESP32Camera *>(entity); auto *camera = static_cast<esp32_camera::ESP32Camera *>(entity);
@ -1385,10 +1331,6 @@ uint16_t APIConnection::try_send_alarm_control_panel_state(EntityBase *entity, A
fill_entity_state_base(a_alarm_control_panel, resp); fill_entity_state_base(a_alarm_control_panel, resp);
return encode_message_to_buffer(resp, AlarmControlPanelStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single); return encode_message_to_buffer(resp, AlarmControlPanelStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
} }
void APIConnection::send_alarm_control_panel_info(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) {
this->schedule_message_(a_alarm_control_panel, &APIConnection::try_send_alarm_control_panel_info,
ListEntitiesAlarmControlPanelResponse::MESSAGE_TYPE);
}
uint16_t APIConnection::try_send_alarm_control_panel_info(EntityBase *entity, APIConnection *conn, uint16_t APIConnection::try_send_alarm_control_panel_info(EntityBase *entity, APIConnection *conn,
uint32_t remaining_size, bool is_single) { uint32_t remaining_size, bool is_single) {
auto *a_alarm_control_panel = static_cast<alarm_control_panel::AlarmControlPanel *>(entity); auto *a_alarm_control_panel = static_cast<alarm_control_panel::AlarmControlPanel *>(entity);
@ -1439,9 +1381,6 @@ void APIConnection::alarm_control_panel_command(const AlarmControlPanelCommandRe
void APIConnection::send_event(event::Event *event, const std::string &event_type) { void APIConnection::send_event(event::Event *event, const std::string &event_type) {
this->schedule_message_(event, MessageCreator(event_type), EventResponse::MESSAGE_TYPE); this->schedule_message_(event, MessageCreator(event_type), EventResponse::MESSAGE_TYPE);
} }
void APIConnection::send_event_info(event::Event *event) {
this->schedule_message_(event, &APIConnection::try_send_event_info, ListEntitiesEventResponse::MESSAGE_TYPE);
}
uint16_t APIConnection::try_send_event_response(event::Event *event, const std::string &event_type, APIConnection *conn, uint16_t APIConnection::try_send_event_response(event::Event *event, const std::string &event_type, APIConnection *conn,
uint32_t remaining_size, bool is_single) { uint32_t remaining_size, bool is_single) {
EventResponse resp; EventResponse resp;
@ -1487,9 +1426,6 @@ uint16_t APIConnection::try_send_update_state(EntityBase *entity, APIConnection
fill_entity_state_base(update, resp); fill_entity_state_base(update, resp);
return encode_message_to_buffer(resp, UpdateStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single); return encode_message_to_buffer(resp, UpdateStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
} }
void APIConnection::send_update_info(update::UpdateEntity *update) {
this->schedule_message_(update, &APIConnection::try_send_update_info, ListEntitiesUpdateResponse::MESSAGE_TYPE);
}
uint16_t APIConnection::try_send_update_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, uint16_t APIConnection::try_send_update_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single) { bool is_single) {
auto *update = static_cast<update::UpdateEntity *>(entity); auto *update = static_cast<update::UpdateEntity *>(entity);
@ -1522,7 +1458,7 @@ void APIConnection::update_command(const UpdateCommandRequest &msg) {
#endif #endif
bool APIConnection::try_send_log_message(int level, const char *tag, const char *line) { bool APIConnection::try_send_log_message(int level, const char *tag, const char *line) {
if (this->log_subscription_ < level) if (this->flags_.log_subscription < level)
return false; return false;
// Pre-calculate message size to avoid reallocations // Pre-calculate message size to avoid reallocations
@ -1563,7 +1499,7 @@ HelloResponse APIConnection::hello(const HelloRequest &msg) {
resp.server_info = App.get_name() + " (esphome v" ESPHOME_VERSION ")"; resp.server_info = App.get_name() + " (esphome v" ESPHOME_VERSION ")";
resp.name = App.get_name(); resp.name = App.get_name();
this->connection_state_ = ConnectionState::CONNECTED; this->flags_.connection_state = static_cast<uint8_t>(ConnectionState::CONNECTED);
return resp; return resp;
} }
ConnectResponse APIConnection::connect(const ConnectRequest &msg) { ConnectResponse APIConnection::connect(const ConnectRequest &msg) {
@ -1574,8 +1510,10 @@ ConnectResponse APIConnection::connect(const ConnectRequest &msg) {
resp.invalid_password = !correct; resp.invalid_password = !correct;
if (correct) { if (correct) {
ESP_LOGD(TAG, "%s connected", this->get_client_combined_info().c_str()); ESP_LOGD(TAG, "%s connected", this->get_client_combined_info().c_str());
this->connection_state_ = ConnectionState::AUTHENTICATED; this->flags_.connection_state = static_cast<uint8_t>(ConnectionState::AUTHENTICATED);
#ifdef USE_API_CLIENT_CONNECTED_TRIGGER
this->parent_->get_client_connected_trigger()->trigger(this->client_info_, this->client_peername_); this->parent_->get_client_connected_trigger()->trigger(this->client_info_, this->client_peername_);
#endif
#ifdef USE_HOMEASSISTANT_TIME #ifdef USE_HOMEASSISTANT_TIME
if (homeassistant::global_homeassistant_time != nullptr) { if (homeassistant::global_homeassistant_time != nullptr) {
this->send_time_request(); this->send_time_request();
@ -1688,7 +1626,7 @@ void APIConnection::subscribe_home_assistant_states(const SubscribeHomeAssistant
state_subs_at_ = 0; state_subs_at_ = 0;
} }
bool APIConnection::try_to_clear_buffer(bool log_out_of_space) { bool APIConnection::try_to_clear_buffer(bool log_out_of_space) {
if (this->remove_) if (this->flags_.remove)
return false; return false;
if (this->helper_->can_write_without_blocking()) if (this->helper_->can_write_without_blocking())
return true; return true;
@ -1738,7 +1676,7 @@ void APIConnection::on_no_setup_connection() {
} }
void APIConnection::on_fatal_error() { void APIConnection::on_fatal_error() {
this->helper_->close(); this->helper_->close();
this->remove_ = true; this->flags_.remove = true;
} }
void APIConnection::DeferredBatch::add_item(EntityBase *entity, MessageCreator creator, uint16_t message_type) { void APIConnection::DeferredBatch::add_item(EntityBase *entity, MessageCreator creator, uint16_t message_type) {
@ -1757,9 +1695,14 @@ void APIConnection::DeferredBatch::add_item(EntityBase *entity, MessageCreator c
items.emplace_back(entity, std::move(creator), message_type); items.emplace_back(entity, std::move(creator), message_type);
} }
void APIConnection::DeferredBatch::add_item_front(EntityBase *entity, MessageCreator creator, uint16_t message_type) {
// Insert at front for high priority messages (no deduplication check)
items.insert(items.begin(), BatchItem(entity, std::move(creator), message_type));
}
bool APIConnection::schedule_batch_() { bool APIConnection::schedule_batch_() {
if (!this->deferred_batch_.batch_scheduled) { if (!this->flags_.batch_scheduled) {
this->deferred_batch_.batch_scheduled = true; this->flags_.batch_scheduled = true;
this->deferred_batch_.batch_start_time = App.get_loop_component_start_time(); this->deferred_batch_.batch_start_time = App.get_loop_component_start_time();
} }
return true; return true;
@ -1768,14 +1711,14 @@ bool APIConnection::schedule_batch_() {
ProtoWriteBuffer APIConnection::allocate_single_message_buffer(uint16_t size) { return this->create_buffer(size); } ProtoWriteBuffer APIConnection::allocate_single_message_buffer(uint16_t size) { return this->create_buffer(size); }
ProtoWriteBuffer APIConnection::allocate_batch_message_buffer(uint16_t size) { ProtoWriteBuffer APIConnection::allocate_batch_message_buffer(uint16_t size) {
ProtoWriteBuffer result = this->prepare_message_buffer(size, this->batch_first_message_); ProtoWriteBuffer result = this->prepare_message_buffer(size, this->flags_.batch_first_message);
this->batch_first_message_ = false; this->flags_.batch_first_message = false;
return result; return result;
} }
void APIConnection::process_batch_() { void APIConnection::process_batch_() {
if (this->deferred_batch_.empty()) { if (this->deferred_batch_.empty()) {
this->deferred_batch_.batch_scheduled = false; this->flags_.batch_scheduled = false;
return; return;
} }
@ -1828,7 +1771,7 @@ void APIConnection::process_batch_() {
// Reserve based on estimated size (much more accurate than 24-byte worst-case) // Reserve based on estimated size (much more accurate than 24-byte worst-case)
this->parent_->get_shared_buffer_ref().reserve(total_estimated_size + total_overhead); this->parent_->get_shared_buffer_ref().reserve(total_estimated_size + total_overhead);
this->batch_first_message_ = true; this->flags_.batch_first_message = true;
size_t items_processed = 0; size_t items_processed = 0;
uint16_t remaining_size = std::numeric_limits<uint16_t>::max(); uint16_t remaining_size = std::numeric_limits<uint16_t>::max();
@ -1891,6 +1834,15 @@ void APIConnection::process_batch_() {
} }
} }
#ifdef HAS_PROTO_MESSAGE_DUMP
// Log messages after send attempt for VV debugging
// It's safe to use the buffer for logging at this point regardless of send result
for (size_t i = 0; i < items_processed; i++) {
const auto &item = this->deferred_batch_.items[i];
this->log_batch_item_(item);
}
#endif
// Handle remaining items more efficiently // Handle remaining items more efficiently
if (items_processed < this->deferred_batch_.items.size()) { if (items_processed < this->deferred_batch_.items.size()) {
// Remove processed items from the beginning // Remove processed items from the beginning
@ -1938,6 +1890,12 @@ uint16_t APIConnection::try_send_disconnect_request(EntityBase *entity, APIConne
return encode_message_to_buffer(req, DisconnectRequest::MESSAGE_TYPE, conn, remaining_size, is_single); return encode_message_to_buffer(req, DisconnectRequest::MESSAGE_TYPE, conn, remaining_size, is_single);
} }
uint16_t APIConnection::try_send_ping_request(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single) {
PingRequest req;
return encode_message_to_buffer(req, PingRequest::MESSAGE_TYPE, conn, remaining_size, is_single);
}
uint16_t APIConnection::get_estimated_message_size(uint16_t message_type) { uint16_t APIConnection::get_estimated_message_size(uint16_t message_type) {
// Use generated ESTIMATED_SIZE constants from each message type // Use generated ESTIMATED_SIZE constants from each message type
switch (message_type) { switch (message_type) {

View File

@ -22,6 +22,7 @@ static constexpr uint32_t KEEPALIVE_TIMEOUT_MS = 60000;
class APIConnection : public APIServerConnection { class APIConnection : public APIServerConnection {
public: public:
friend class APIServer; friend class APIServer;
friend class ListEntitiesIterator;
APIConnection(std::unique_ptr<socket::Socket> socket, APIServer *parent); APIConnection(std::unique_ptr<socket::Socket> socket, APIServer *parent);
virtual ~APIConnection(); virtual ~APIConnection();
@ -34,98 +35,79 @@ class APIConnection : public APIServerConnection {
} }
#ifdef USE_BINARY_SENSOR #ifdef USE_BINARY_SENSOR
bool send_binary_sensor_state(binary_sensor::BinarySensor *binary_sensor); bool send_binary_sensor_state(binary_sensor::BinarySensor *binary_sensor);
void send_binary_sensor_info(binary_sensor::BinarySensor *binary_sensor);
#endif #endif
#ifdef USE_COVER #ifdef USE_COVER
bool send_cover_state(cover::Cover *cover); bool send_cover_state(cover::Cover *cover);
void send_cover_info(cover::Cover *cover);
void cover_command(const CoverCommandRequest &msg) override; void cover_command(const CoverCommandRequest &msg) override;
#endif #endif
#ifdef USE_FAN #ifdef USE_FAN
bool send_fan_state(fan::Fan *fan); bool send_fan_state(fan::Fan *fan);
void send_fan_info(fan::Fan *fan);
void fan_command(const FanCommandRequest &msg) override; void fan_command(const FanCommandRequest &msg) override;
#endif #endif
#ifdef USE_LIGHT #ifdef USE_LIGHT
bool send_light_state(light::LightState *light); bool send_light_state(light::LightState *light);
void send_light_info(light::LightState *light);
void light_command(const LightCommandRequest &msg) override; void light_command(const LightCommandRequest &msg) override;
#endif #endif
#ifdef USE_SENSOR #ifdef USE_SENSOR
bool send_sensor_state(sensor::Sensor *sensor); bool send_sensor_state(sensor::Sensor *sensor);
void send_sensor_info(sensor::Sensor *sensor);
#endif #endif
#ifdef USE_SWITCH #ifdef USE_SWITCH
bool send_switch_state(switch_::Switch *a_switch); bool send_switch_state(switch_::Switch *a_switch);
void send_switch_info(switch_::Switch *a_switch);
void switch_command(const SwitchCommandRequest &msg) override; void switch_command(const SwitchCommandRequest &msg) override;
#endif #endif
#ifdef USE_TEXT_SENSOR #ifdef USE_TEXT_SENSOR
bool send_text_sensor_state(text_sensor::TextSensor *text_sensor); bool send_text_sensor_state(text_sensor::TextSensor *text_sensor);
void send_text_sensor_info(text_sensor::TextSensor *text_sensor);
#endif #endif
#ifdef USE_ESP32_CAMERA #ifdef USE_ESP32_CAMERA
void set_camera_state(std::shared_ptr<esp32_camera::CameraImage> image); void set_camera_state(std::shared_ptr<esp32_camera::CameraImage> image);
void send_camera_info(esp32_camera::ESP32Camera *camera);
void camera_image(const CameraImageRequest &msg) override; void camera_image(const CameraImageRequest &msg) override;
#endif #endif
#ifdef USE_CLIMATE #ifdef USE_CLIMATE
bool send_climate_state(climate::Climate *climate); bool send_climate_state(climate::Climate *climate);
void send_climate_info(climate::Climate *climate);
void climate_command(const ClimateCommandRequest &msg) override; void climate_command(const ClimateCommandRequest &msg) override;
#endif #endif
#ifdef USE_NUMBER #ifdef USE_NUMBER
bool send_number_state(number::Number *number); bool send_number_state(number::Number *number);
void send_number_info(number::Number *number);
void number_command(const NumberCommandRequest &msg) override; void number_command(const NumberCommandRequest &msg) override;
#endif #endif
#ifdef USE_DATETIME_DATE #ifdef USE_DATETIME_DATE
bool send_date_state(datetime::DateEntity *date); bool send_date_state(datetime::DateEntity *date);
void send_date_info(datetime::DateEntity *date);
void date_command(const DateCommandRequest &msg) override; void date_command(const DateCommandRequest &msg) override;
#endif #endif
#ifdef USE_DATETIME_TIME #ifdef USE_DATETIME_TIME
bool send_time_state(datetime::TimeEntity *time); bool send_time_state(datetime::TimeEntity *time);
void send_time_info(datetime::TimeEntity *time);
void time_command(const TimeCommandRequest &msg) override; void time_command(const TimeCommandRequest &msg) override;
#endif #endif
#ifdef USE_DATETIME_DATETIME #ifdef USE_DATETIME_DATETIME
bool send_datetime_state(datetime::DateTimeEntity *datetime); bool send_datetime_state(datetime::DateTimeEntity *datetime);
void send_datetime_info(datetime::DateTimeEntity *datetime);
void datetime_command(const DateTimeCommandRequest &msg) override; void datetime_command(const DateTimeCommandRequest &msg) override;
#endif #endif
#ifdef USE_TEXT #ifdef USE_TEXT
bool send_text_state(text::Text *text); bool send_text_state(text::Text *text);
void send_text_info(text::Text *text);
void text_command(const TextCommandRequest &msg) override; void text_command(const TextCommandRequest &msg) override;
#endif #endif
#ifdef USE_SELECT #ifdef USE_SELECT
bool send_select_state(select::Select *select); bool send_select_state(select::Select *select);
void send_select_info(select::Select *select);
void select_command(const SelectCommandRequest &msg) override; void select_command(const SelectCommandRequest &msg) override;
#endif #endif
#ifdef USE_BUTTON #ifdef USE_BUTTON
void send_button_info(button::Button *button);
void button_command(const ButtonCommandRequest &msg) override; void button_command(const ButtonCommandRequest &msg) override;
#endif #endif
#ifdef USE_LOCK #ifdef USE_LOCK
bool send_lock_state(lock::Lock *a_lock); bool send_lock_state(lock::Lock *a_lock);
void send_lock_info(lock::Lock *a_lock);
void lock_command(const LockCommandRequest &msg) override; void lock_command(const LockCommandRequest &msg) override;
#endif #endif
#ifdef USE_VALVE #ifdef USE_VALVE
bool send_valve_state(valve::Valve *valve); bool send_valve_state(valve::Valve *valve);
void send_valve_info(valve::Valve *valve);
void valve_command(const ValveCommandRequest &msg) override; void valve_command(const ValveCommandRequest &msg) override;
#endif #endif
#ifdef USE_MEDIA_PLAYER #ifdef USE_MEDIA_PLAYER
bool send_media_player_state(media_player::MediaPlayer *media_player); bool send_media_player_state(media_player::MediaPlayer *media_player);
void send_media_player_info(media_player::MediaPlayer *media_player);
void media_player_command(const MediaPlayerCommandRequest &msg) override; void media_player_command(const MediaPlayerCommandRequest &msg) override;
#endif #endif
bool try_send_log_message(int level, const char *tag, const char *line); bool try_send_log_message(int level, const char *tag, const char *line);
void send_homeassistant_service_call(const HomeassistantServiceResponse &call) { void send_homeassistant_service_call(const HomeassistantServiceResponse &call) {
if (!this->service_call_subscription_) if (!this->flags_.service_call_subscription)
return; return;
this->send_message(call); this->send_message(call);
} }
@ -167,26 +149,22 @@ class APIConnection : public APIServerConnection {
#ifdef USE_ALARM_CONTROL_PANEL #ifdef USE_ALARM_CONTROL_PANEL
bool send_alarm_control_panel_state(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel); bool send_alarm_control_panel_state(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel);
void send_alarm_control_panel_info(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel);
void alarm_control_panel_command(const AlarmControlPanelCommandRequest &msg) override; void alarm_control_panel_command(const AlarmControlPanelCommandRequest &msg) override;
#endif #endif
#ifdef USE_EVENT #ifdef USE_EVENT
void send_event(event::Event *event, const std::string &event_type); void send_event(event::Event *event, const std::string &event_type);
void send_event_info(event::Event *event);
#endif #endif
#ifdef USE_UPDATE #ifdef USE_UPDATE
bool send_update_state(update::UpdateEntity *update); bool send_update_state(update::UpdateEntity *update);
void send_update_info(update::UpdateEntity *update);
void update_command(const UpdateCommandRequest &msg) override; void update_command(const UpdateCommandRequest &msg) override;
#endif #endif
void on_disconnect_response(const DisconnectResponse &value) override; void on_disconnect_response(const DisconnectResponse &value) override;
void on_ping_response(const PingResponse &value) override { void on_ping_response(const PingResponse &value) override {
// we initiated ping // we initiated ping
this->ping_retries_ = 0; this->flags_.sent_ping = false;
this->sent_ping_ = false;
} }
void on_home_assistant_state_response(const HomeAssistantStateResponse &msg) override; void on_home_assistant_state_response(const HomeAssistantStateResponse &msg) override;
#ifdef USE_HOMEASSISTANT_TIME #ifdef USE_HOMEASSISTANT_TIME
@ -199,16 +177,16 @@ class APIConnection : public APIServerConnection {
DeviceInfoResponse device_info(const DeviceInfoRequest &msg) override; DeviceInfoResponse device_info(const DeviceInfoRequest &msg) override;
void list_entities(const ListEntitiesRequest &msg) override { this->list_entities_iterator_.begin(); } void list_entities(const ListEntitiesRequest &msg) override { this->list_entities_iterator_.begin(); }
void subscribe_states(const SubscribeStatesRequest &msg) override { void subscribe_states(const SubscribeStatesRequest &msg) override {
this->state_subscription_ = true; this->flags_.state_subscription = true;
this->initial_state_iterator_.begin(); this->initial_state_iterator_.begin();
} }
void subscribe_logs(const SubscribeLogsRequest &msg) override { void subscribe_logs(const SubscribeLogsRequest &msg) override {
this->log_subscription_ = msg.level; this->flags_.log_subscription = msg.level;
if (msg.dump_config) if (msg.dump_config)
App.schedule_dump_config(); App.schedule_dump_config();
} }
void subscribe_homeassistant_services(const SubscribeHomeassistantServicesRequest &msg) override { void subscribe_homeassistant_services(const SubscribeHomeassistantServicesRequest &msg) override {
this->service_call_subscription_ = true; this->flags_.service_call_subscription = true;
} }
void subscribe_home_assistant_states(const SubscribeHomeAssistantStatesRequest &msg) override; void subscribe_home_assistant_states(const SubscribeHomeAssistantStatesRequest &msg) override;
GetTimeResponse get_time(const GetTimeRequest &msg) override { GetTimeResponse get_time(const GetTimeRequest &msg) override {
@ -220,9 +198,12 @@ class APIConnection : public APIServerConnection {
NoiseEncryptionSetKeyResponse noise_encryption_set_key(const NoiseEncryptionSetKeyRequest &msg) override; NoiseEncryptionSetKeyResponse noise_encryption_set_key(const NoiseEncryptionSetKeyRequest &msg) override;
#endif #endif
bool is_authenticated() override { return this->connection_state_ == ConnectionState::AUTHENTICATED; } bool is_authenticated() override {
return static_cast<ConnectionState>(this->flags_.connection_state) == ConnectionState::AUTHENTICATED;
}
bool is_connection_setup() override { bool is_connection_setup() override {
return this->connection_state_ == ConnectionState ::CONNECTED || this->is_authenticated(); return static_cast<ConnectionState>(this->flags_.connection_state) == ConnectionState::CONNECTED ||
this->is_authenticated();
} }
void on_fatal_error() override; void on_fatal_error() override;
void on_unauthenticated_access() override; void on_unauthenticated_access() override;
@ -441,45 +422,32 @@ class APIConnection : public APIServerConnection {
// Helper function to get estimated message size for buffer pre-allocation // Helper function to get estimated message size for buffer pre-allocation
static uint16_t get_estimated_message_size(uint16_t message_type); static uint16_t get_estimated_message_size(uint16_t message_type);
// Pointers first (4 bytes each, naturally aligned) // Batch message method for ping requests
static uint16_t try_send_ping_request(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single);
// === Optimal member ordering for 32-bit systems ===
// Group 1: Pointers (4 bytes each on 32-bit)
std::unique_ptr<APIFrameHelper> helper_; std::unique_ptr<APIFrameHelper> helper_;
APIServer *parent_; APIServer *parent_;
// 4-byte aligned types // Group 2: Larger objects (must be 4-byte aligned)
uint32_t last_traffic_; // These contain vectors/pointers internally, so putting them early ensures good alignment
uint32_t next_ping_retry_{0};
int state_subs_at_ = -1;
// Strings (12 bytes each on 32-bit)
std::string client_info_;
std::string client_peername_;
// 2-byte aligned types
uint16_t client_api_version_major_{0};
uint16_t client_api_version_minor_{0};
// Group all 1-byte types together to minimize padding
enum class ConnectionState : uint8_t {
WAITING_FOR_HELLO,
CONNECTED,
AUTHENTICATED,
} connection_state_{ConnectionState::WAITING_FOR_HELLO};
uint8_t log_subscription_{ESPHOME_LOG_LEVEL_NONE};
bool remove_{false};
bool state_subscription_{false};
bool sent_ping_{false};
bool service_call_subscription_{false};
bool next_close_ = false;
uint8_t ping_retries_{0};
// 8 bytes used, no padding needed
// Larger objects at the end
InitialStateIterator initial_state_iterator_; InitialStateIterator initial_state_iterator_;
ListEntitiesIterator list_entities_iterator_; ListEntitiesIterator list_entities_iterator_;
#ifdef USE_ESP32_CAMERA #ifdef USE_ESP32_CAMERA
esp32_camera::CameraImageReader image_reader_; esp32_camera::CameraImageReader image_reader_;
#endif #endif
// Group 3: Strings (12 bytes each on 32-bit, 4-byte aligned)
std::string client_info_;
std::string client_peername_;
// Group 4: 4-byte types
uint32_t last_traffic_;
int state_subs_at_ = -1;
// Function pointer type for message encoding // Function pointer type for message encoding
using MessageCreatorPtr = uint16_t (*)(EntityBase *, APIConnection *, uint32_t remaining_size, bool is_single); using MessageCreatorPtr = uint16_t (*)(EntityBase *, APIConnection *, uint32_t remaining_size, bool is_single);
@ -589,7 +557,6 @@ class APIConnection : public APIServerConnection {
std::vector<BatchItem> items; std::vector<BatchItem> items;
uint32_t batch_start_time{0}; uint32_t batch_start_time{0};
bool batch_scheduled{false};
DeferredBatch() { DeferredBatch() {
// Pre-allocate capacity for typical batch sizes to avoid reallocation // Pre-allocate capacity for typical batch sizes to avoid reallocation
@ -598,15 +565,51 @@ class APIConnection : public APIServerConnection {
// Add item to the batch // Add item to the batch
void add_item(EntityBase *entity, MessageCreator creator, uint16_t message_type); void add_item(EntityBase *entity, MessageCreator creator, uint16_t message_type);
// Add item to the front of the batch (for high priority messages like ping)
void add_item_front(EntityBase *entity, MessageCreator creator, uint16_t message_type);
void clear() { void clear() {
items.clear(); items.clear();
batch_scheduled = false;
batch_start_time = 0; batch_start_time = 0;
} }
bool empty() const { return items.empty(); } bool empty() const { return items.empty(); }
}; };
// DeferredBatch here (16 bytes, 4-byte aligned)
DeferredBatch deferred_batch_; DeferredBatch deferred_batch_;
// ConnectionState enum for type safety
enum class ConnectionState : uint8_t {
WAITING_FOR_HELLO = 0,
CONNECTED = 1,
AUTHENTICATED = 2,
};
// Group 5: Pack all small members together to minimize padding
// This group starts at a 4-byte boundary after DeferredBatch
struct APIFlags {
// Connection state only needs 2 bits (3 states)
uint8_t connection_state : 2;
// Log subscription needs 3 bits (log levels 0-7)
uint8_t log_subscription : 3;
// Boolean flags (1 bit each)
uint8_t remove : 1;
uint8_t state_subscription : 1;
uint8_t sent_ping : 1;
uint8_t service_call_subscription : 1;
uint8_t next_close : 1;
uint8_t batch_scheduled : 1;
uint8_t batch_first_message : 1; // For batch buffer allocation
#ifdef HAS_PROTO_MESSAGE_DUMP
uint8_t log_only_mode : 1;
#endif
} flags_{}; // 2 bytes total
// 2-byte types immediately after flags_ (no padding between them)
uint16_t client_api_version_major_{0};
uint16_t client_api_version_minor_{0};
// Total: 2 (flags) + 2 + 2 = 6 bytes, then 2 bytes padding to next 4-byte boundary
uint32_t get_batch_delay_ms_() const; uint32_t get_batch_delay_ms_() const;
// Message will use 8 more bytes than the minimum size, and typical // Message will use 8 more bytes than the minimum size, and typical
// MTU is 1500. Sometimes users will see as low as 1460 MTU. // MTU is 1500. Sometimes users will see as low as 1460 MTU.
@ -624,8 +627,9 @@ class APIConnection : public APIServerConnection {
bool schedule_batch_(); bool schedule_batch_();
void process_batch_(); void process_batch_();
// State for batch buffer allocation #ifdef HAS_PROTO_MESSAGE_DUMP
bool batch_first_message_{false}; void log_batch_item_(const DeferredBatch::BatchItem &item);
#endif
// Helper function to schedule a deferred message with known message type // Helper function to schedule a deferred message with known message type
bool schedule_message_(EntityBase *entity, MessageCreator creator, uint16_t message_type) { bool schedule_message_(EntityBase *entity, MessageCreator creator, uint16_t message_type) {
@ -637,6 +641,12 @@ class APIConnection : public APIServerConnection {
bool schedule_message_(EntityBase *entity, MessageCreatorPtr function_ptr, uint16_t message_type) { bool schedule_message_(EntityBase *entity, MessageCreatorPtr function_ptr, uint16_t message_type) {
return schedule_message_(entity, MessageCreator(function_ptr), message_type); return schedule_message_(entity, MessageCreator(function_ptr), message_type);
} }
// Helper function to schedule a high priority message at the front of the batch
bool schedule_message_front_(EntityBase *entity, MessageCreatorPtr function_ptr, uint16_t message_type) {
this->deferred_batch_.add_item_front(entity, MessageCreator(function_ptr), message_type);
return this->schedule_batch_();
}
}; };
} // namespace api } // namespace api

View File

@ -14,7 +14,7 @@ void APIServerConnectionBase::log_send_message_(const char *name, const std::str
} }
#endif #endif
bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) { void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) {
switch (msg_type) { switch (msg_type) {
case 1: { case 1: {
HelloRequest msg; HelloRequest msg;
@ -106,50 +106,50 @@ bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
this->on_subscribe_logs_request(msg); this->on_subscribe_logs_request(msg);
break; break;
} }
case 30: {
#ifdef USE_COVER #ifdef USE_COVER
case 30: {
CoverCommandRequest msg; CoverCommandRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_cover_command_request: %s", msg.dump().c_str()); ESP_LOGVV(TAG, "on_cover_command_request: %s", msg.dump().c_str());
#endif #endif
this->on_cover_command_request(msg); this->on_cover_command_request(msg);
#endif
break; break;
} }
case 31: { #endif
#ifdef USE_FAN #ifdef USE_FAN
case 31: {
FanCommandRequest msg; FanCommandRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_fan_command_request: %s", msg.dump().c_str()); ESP_LOGVV(TAG, "on_fan_command_request: %s", msg.dump().c_str());
#endif #endif
this->on_fan_command_request(msg); this->on_fan_command_request(msg);
#endif
break; break;
} }
case 32: { #endif
#ifdef USE_LIGHT #ifdef USE_LIGHT
case 32: {
LightCommandRequest msg; LightCommandRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_light_command_request: %s", msg.dump().c_str()); ESP_LOGVV(TAG, "on_light_command_request: %s", msg.dump().c_str());
#endif #endif
this->on_light_command_request(msg); this->on_light_command_request(msg);
#endif
break; break;
} }
case 33: { #endif
#ifdef USE_SWITCH #ifdef USE_SWITCH
case 33: {
SwitchCommandRequest msg; SwitchCommandRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_switch_command_request: %s", msg.dump().c_str()); ESP_LOGVV(TAG, "on_switch_command_request: %s", msg.dump().c_str());
#endif #endif
this->on_switch_command_request(msg); this->on_switch_command_request(msg);
#endif
break; break;
} }
#endif
case 34: { case 34: {
SubscribeHomeassistantServicesRequest msg; SubscribeHomeassistantServicesRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
@ -204,395 +204,394 @@ bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
this->on_execute_service_request(msg); this->on_execute_service_request(msg);
break; break;
} }
case 45: {
#ifdef USE_ESP32_CAMERA #ifdef USE_ESP32_CAMERA
case 45: {
CameraImageRequest msg; CameraImageRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_camera_image_request: %s", msg.dump().c_str()); ESP_LOGVV(TAG, "on_camera_image_request: %s", msg.dump().c_str());
#endif #endif
this->on_camera_image_request(msg); this->on_camera_image_request(msg);
#endif
break; break;
} }
case 48: { #endif
#ifdef USE_CLIMATE #ifdef USE_CLIMATE
case 48: {
ClimateCommandRequest msg; ClimateCommandRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_climate_command_request: %s", msg.dump().c_str()); ESP_LOGVV(TAG, "on_climate_command_request: %s", msg.dump().c_str());
#endif #endif
this->on_climate_command_request(msg); this->on_climate_command_request(msg);
#endif
break; break;
} }
case 51: { #endif
#ifdef USE_NUMBER #ifdef USE_NUMBER
case 51: {
NumberCommandRequest msg; NumberCommandRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_number_command_request: %s", msg.dump().c_str()); ESP_LOGVV(TAG, "on_number_command_request: %s", msg.dump().c_str());
#endif #endif
this->on_number_command_request(msg); this->on_number_command_request(msg);
#endif
break; break;
} }
case 54: { #endif
#ifdef USE_SELECT #ifdef USE_SELECT
case 54: {
SelectCommandRequest msg; SelectCommandRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_select_command_request: %s", msg.dump().c_str()); ESP_LOGVV(TAG, "on_select_command_request: %s", msg.dump().c_str());
#endif #endif
this->on_select_command_request(msg); this->on_select_command_request(msg);
#endif
break; break;
} }
case 57: { #endif
#ifdef USE_SIREN #ifdef USE_SIREN
case 57: {
SirenCommandRequest msg; SirenCommandRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_siren_command_request: %s", msg.dump().c_str()); ESP_LOGVV(TAG, "on_siren_command_request: %s", msg.dump().c_str());
#endif #endif
this->on_siren_command_request(msg); this->on_siren_command_request(msg);
#endif
break; break;
} }
case 60: { #endif
#ifdef USE_LOCK #ifdef USE_LOCK
case 60: {
LockCommandRequest msg; LockCommandRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_lock_command_request: %s", msg.dump().c_str()); ESP_LOGVV(TAG, "on_lock_command_request: %s", msg.dump().c_str());
#endif #endif
this->on_lock_command_request(msg); this->on_lock_command_request(msg);
#endif
break; break;
} }
case 62: { #endif
#ifdef USE_BUTTON #ifdef USE_BUTTON
case 62: {
ButtonCommandRequest msg; ButtonCommandRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_button_command_request: %s", msg.dump().c_str()); ESP_LOGVV(TAG, "on_button_command_request: %s", msg.dump().c_str());
#endif #endif
this->on_button_command_request(msg); this->on_button_command_request(msg);
#endif
break; break;
} }
case 65: { #endif
#ifdef USE_MEDIA_PLAYER #ifdef USE_MEDIA_PLAYER
case 65: {
MediaPlayerCommandRequest msg; MediaPlayerCommandRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_media_player_command_request: %s", msg.dump().c_str()); ESP_LOGVV(TAG, "on_media_player_command_request: %s", msg.dump().c_str());
#endif #endif
this->on_media_player_command_request(msg); this->on_media_player_command_request(msg);
#endif
break; break;
} }
case 66: { #endif
#ifdef USE_BLUETOOTH_PROXY #ifdef USE_BLUETOOTH_PROXY
case 66: {
SubscribeBluetoothLEAdvertisementsRequest msg; SubscribeBluetoothLEAdvertisementsRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_subscribe_bluetooth_le_advertisements_request: %s", msg.dump().c_str()); ESP_LOGVV(TAG, "on_subscribe_bluetooth_le_advertisements_request: %s", msg.dump().c_str());
#endif #endif
this->on_subscribe_bluetooth_le_advertisements_request(msg); this->on_subscribe_bluetooth_le_advertisements_request(msg);
#endif
break; break;
} }
case 68: { #endif
#ifdef USE_BLUETOOTH_PROXY #ifdef USE_BLUETOOTH_PROXY
case 68: {
BluetoothDeviceRequest msg; BluetoothDeviceRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_bluetooth_device_request: %s", msg.dump().c_str()); ESP_LOGVV(TAG, "on_bluetooth_device_request: %s", msg.dump().c_str());
#endif #endif
this->on_bluetooth_device_request(msg); this->on_bluetooth_device_request(msg);
#endif
break; break;
} }
case 70: { #endif
#ifdef USE_BLUETOOTH_PROXY #ifdef USE_BLUETOOTH_PROXY
case 70: {
BluetoothGATTGetServicesRequest msg; BluetoothGATTGetServicesRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_bluetooth_gatt_get_services_request: %s", msg.dump().c_str()); ESP_LOGVV(TAG, "on_bluetooth_gatt_get_services_request: %s", msg.dump().c_str());
#endif #endif
this->on_bluetooth_gatt_get_services_request(msg); this->on_bluetooth_gatt_get_services_request(msg);
#endif
break; break;
} }
case 73: { #endif
#ifdef USE_BLUETOOTH_PROXY #ifdef USE_BLUETOOTH_PROXY
case 73: {
BluetoothGATTReadRequest msg; BluetoothGATTReadRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_bluetooth_gatt_read_request: %s", msg.dump().c_str()); ESP_LOGVV(TAG, "on_bluetooth_gatt_read_request: %s", msg.dump().c_str());
#endif #endif
this->on_bluetooth_gatt_read_request(msg); this->on_bluetooth_gatt_read_request(msg);
#endif
break; break;
} }
case 75: { #endif
#ifdef USE_BLUETOOTH_PROXY #ifdef USE_BLUETOOTH_PROXY
case 75: {
BluetoothGATTWriteRequest msg; BluetoothGATTWriteRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_bluetooth_gatt_write_request: %s", msg.dump().c_str()); ESP_LOGVV(TAG, "on_bluetooth_gatt_write_request: %s", msg.dump().c_str());
#endif #endif
this->on_bluetooth_gatt_write_request(msg); this->on_bluetooth_gatt_write_request(msg);
#endif
break; break;
} }
case 76: { #endif
#ifdef USE_BLUETOOTH_PROXY #ifdef USE_BLUETOOTH_PROXY
case 76: {
BluetoothGATTReadDescriptorRequest msg; BluetoothGATTReadDescriptorRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_bluetooth_gatt_read_descriptor_request: %s", msg.dump().c_str()); ESP_LOGVV(TAG, "on_bluetooth_gatt_read_descriptor_request: %s", msg.dump().c_str());
#endif #endif
this->on_bluetooth_gatt_read_descriptor_request(msg); this->on_bluetooth_gatt_read_descriptor_request(msg);
#endif
break; break;
} }
case 77: { #endif
#ifdef USE_BLUETOOTH_PROXY #ifdef USE_BLUETOOTH_PROXY
case 77: {
BluetoothGATTWriteDescriptorRequest msg; BluetoothGATTWriteDescriptorRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_bluetooth_gatt_write_descriptor_request: %s", msg.dump().c_str()); ESP_LOGVV(TAG, "on_bluetooth_gatt_write_descriptor_request: %s", msg.dump().c_str());
#endif #endif
this->on_bluetooth_gatt_write_descriptor_request(msg); this->on_bluetooth_gatt_write_descriptor_request(msg);
#endif
break; break;
} }
case 78: { #endif
#ifdef USE_BLUETOOTH_PROXY #ifdef USE_BLUETOOTH_PROXY
case 78: {
BluetoothGATTNotifyRequest msg; BluetoothGATTNotifyRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_bluetooth_gatt_notify_request: %s", msg.dump().c_str()); ESP_LOGVV(TAG, "on_bluetooth_gatt_notify_request: %s", msg.dump().c_str());
#endif #endif
this->on_bluetooth_gatt_notify_request(msg); this->on_bluetooth_gatt_notify_request(msg);
#endif
break; break;
} }
case 80: { #endif
#ifdef USE_BLUETOOTH_PROXY #ifdef USE_BLUETOOTH_PROXY
case 80: {
SubscribeBluetoothConnectionsFreeRequest msg; SubscribeBluetoothConnectionsFreeRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_subscribe_bluetooth_connections_free_request: %s", msg.dump().c_str()); ESP_LOGVV(TAG, "on_subscribe_bluetooth_connections_free_request: %s", msg.dump().c_str());
#endif #endif
this->on_subscribe_bluetooth_connections_free_request(msg); this->on_subscribe_bluetooth_connections_free_request(msg);
#endif
break; break;
} }
case 87: { #endif
#ifdef USE_BLUETOOTH_PROXY #ifdef USE_BLUETOOTH_PROXY
case 87: {
UnsubscribeBluetoothLEAdvertisementsRequest msg; UnsubscribeBluetoothLEAdvertisementsRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_unsubscribe_bluetooth_le_advertisements_request: %s", msg.dump().c_str()); ESP_LOGVV(TAG, "on_unsubscribe_bluetooth_le_advertisements_request: %s", msg.dump().c_str());
#endif #endif
this->on_unsubscribe_bluetooth_le_advertisements_request(msg); this->on_unsubscribe_bluetooth_le_advertisements_request(msg);
#endif
break; break;
} }
case 89: { #endif
#ifdef USE_VOICE_ASSISTANT #ifdef USE_VOICE_ASSISTANT
case 89: {
SubscribeVoiceAssistantRequest msg; SubscribeVoiceAssistantRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_subscribe_voice_assistant_request: %s", msg.dump().c_str()); ESP_LOGVV(TAG, "on_subscribe_voice_assistant_request: %s", msg.dump().c_str());
#endif #endif
this->on_subscribe_voice_assistant_request(msg); this->on_subscribe_voice_assistant_request(msg);
#endif
break; break;
} }
case 91: { #endif
#ifdef USE_VOICE_ASSISTANT #ifdef USE_VOICE_ASSISTANT
case 91: {
VoiceAssistantResponse msg; VoiceAssistantResponse msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_voice_assistant_response: %s", msg.dump().c_str()); ESP_LOGVV(TAG, "on_voice_assistant_response: %s", msg.dump().c_str());
#endif #endif
this->on_voice_assistant_response(msg); this->on_voice_assistant_response(msg);
#endif
break; break;
} }
case 92: { #endif
#ifdef USE_VOICE_ASSISTANT #ifdef USE_VOICE_ASSISTANT
case 92: {
VoiceAssistantEventResponse msg; VoiceAssistantEventResponse msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_voice_assistant_event_response: %s", msg.dump().c_str()); ESP_LOGVV(TAG, "on_voice_assistant_event_response: %s", msg.dump().c_str());
#endif #endif
this->on_voice_assistant_event_response(msg); this->on_voice_assistant_event_response(msg);
#endif
break; break;
} }
case 96: { #endif
#ifdef USE_ALARM_CONTROL_PANEL #ifdef USE_ALARM_CONTROL_PANEL
case 96: {
AlarmControlPanelCommandRequest msg; AlarmControlPanelCommandRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_alarm_control_panel_command_request: %s", msg.dump().c_str()); ESP_LOGVV(TAG, "on_alarm_control_panel_command_request: %s", msg.dump().c_str());
#endif #endif
this->on_alarm_control_panel_command_request(msg); this->on_alarm_control_panel_command_request(msg);
#endif
break; break;
} }
case 99: { #endif
#ifdef USE_TEXT #ifdef USE_TEXT
case 99: {
TextCommandRequest msg; TextCommandRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_text_command_request: %s", msg.dump().c_str()); ESP_LOGVV(TAG, "on_text_command_request: %s", msg.dump().c_str());
#endif #endif
this->on_text_command_request(msg); this->on_text_command_request(msg);
#endif
break; break;
} }
case 102: { #endif
#ifdef USE_DATETIME_DATE #ifdef USE_DATETIME_DATE
case 102: {
DateCommandRequest msg; DateCommandRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_date_command_request: %s", msg.dump().c_str()); ESP_LOGVV(TAG, "on_date_command_request: %s", msg.dump().c_str());
#endif #endif
this->on_date_command_request(msg); this->on_date_command_request(msg);
#endif
break; break;
} }
case 105: { #endif
#ifdef USE_DATETIME_TIME #ifdef USE_DATETIME_TIME
case 105: {
TimeCommandRequest msg; TimeCommandRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_time_command_request: %s", msg.dump().c_str()); ESP_LOGVV(TAG, "on_time_command_request: %s", msg.dump().c_str());
#endif #endif
this->on_time_command_request(msg); this->on_time_command_request(msg);
#endif
break; break;
} }
case 106: { #endif
#ifdef USE_VOICE_ASSISTANT #ifdef USE_VOICE_ASSISTANT
case 106: {
VoiceAssistantAudio msg; VoiceAssistantAudio msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_voice_assistant_audio: %s", msg.dump().c_str()); ESP_LOGVV(TAG, "on_voice_assistant_audio: %s", msg.dump().c_str());
#endif #endif
this->on_voice_assistant_audio(msg); this->on_voice_assistant_audio(msg);
#endif
break; break;
} }
case 111: { #endif
#ifdef USE_VALVE #ifdef USE_VALVE
case 111: {
ValveCommandRequest msg; ValveCommandRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_valve_command_request: %s", msg.dump().c_str()); ESP_LOGVV(TAG, "on_valve_command_request: %s", msg.dump().c_str());
#endif #endif
this->on_valve_command_request(msg); this->on_valve_command_request(msg);
#endif
break; break;
} }
case 114: { #endif
#ifdef USE_DATETIME_DATETIME #ifdef USE_DATETIME_DATETIME
case 114: {
DateTimeCommandRequest msg; DateTimeCommandRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_date_time_command_request: %s", msg.dump().c_str()); ESP_LOGVV(TAG, "on_date_time_command_request: %s", msg.dump().c_str());
#endif #endif
this->on_date_time_command_request(msg); this->on_date_time_command_request(msg);
#endif
break; break;
} }
case 115: { #endif
#ifdef USE_VOICE_ASSISTANT #ifdef USE_VOICE_ASSISTANT
case 115: {
VoiceAssistantTimerEventResponse msg; VoiceAssistantTimerEventResponse msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_voice_assistant_timer_event_response: %s", msg.dump().c_str()); ESP_LOGVV(TAG, "on_voice_assistant_timer_event_response: %s", msg.dump().c_str());
#endif #endif
this->on_voice_assistant_timer_event_response(msg); this->on_voice_assistant_timer_event_response(msg);
#endif
break; break;
} }
case 118: { #endif
#ifdef USE_UPDATE #ifdef USE_UPDATE
case 118: {
UpdateCommandRequest msg; UpdateCommandRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_update_command_request: %s", msg.dump().c_str()); ESP_LOGVV(TAG, "on_update_command_request: %s", msg.dump().c_str());
#endif #endif
this->on_update_command_request(msg); this->on_update_command_request(msg);
#endif
break; break;
} }
case 119: { #endif
#ifdef USE_VOICE_ASSISTANT #ifdef USE_VOICE_ASSISTANT
case 119: {
VoiceAssistantAnnounceRequest msg; VoiceAssistantAnnounceRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_voice_assistant_announce_request: %s", msg.dump().c_str()); ESP_LOGVV(TAG, "on_voice_assistant_announce_request: %s", msg.dump().c_str());
#endif #endif
this->on_voice_assistant_announce_request(msg); this->on_voice_assistant_announce_request(msg);
#endif
break; break;
} }
case 121: { #endif
#ifdef USE_VOICE_ASSISTANT #ifdef USE_VOICE_ASSISTANT
case 121: {
VoiceAssistantConfigurationRequest msg; VoiceAssistantConfigurationRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_voice_assistant_configuration_request: %s", msg.dump().c_str()); ESP_LOGVV(TAG, "on_voice_assistant_configuration_request: %s", msg.dump().c_str());
#endif #endif
this->on_voice_assistant_configuration_request(msg); this->on_voice_assistant_configuration_request(msg);
#endif
break; break;
} }
case 123: { #endif
#ifdef USE_VOICE_ASSISTANT #ifdef USE_VOICE_ASSISTANT
case 123: {
VoiceAssistantSetConfiguration msg; VoiceAssistantSetConfiguration msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_voice_assistant_set_configuration: %s", msg.dump().c_str()); ESP_LOGVV(TAG, "on_voice_assistant_set_configuration: %s", msg.dump().c_str());
#endif #endif
this->on_voice_assistant_set_configuration(msg); this->on_voice_assistant_set_configuration(msg);
#endif
break; break;
} }
case 124: { #endif
#ifdef USE_API_NOISE #ifdef USE_API_NOISE
case 124: {
NoiseEncryptionSetKeyRequest msg; NoiseEncryptionSetKeyRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_noise_encryption_set_key_request: %s", msg.dump().c_str()); ESP_LOGVV(TAG, "on_noise_encryption_set_key_request: %s", msg.dump().c_str());
#endif #endif
this->on_noise_encryption_set_key_request(msg); this->on_noise_encryption_set_key_request(msg);
#endif
break; break;
} }
case 127: { #endif
#ifdef USE_BLUETOOTH_PROXY #ifdef USE_BLUETOOTH_PROXY
case 127: {
BluetoothScannerSetModeRequest msg; BluetoothScannerSetModeRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_bluetooth_scanner_set_mode_request: %s", msg.dump().c_str()); ESP_LOGVV(TAG, "on_bluetooth_scanner_set_mode_request: %s", msg.dump().c_str());
#endif #endif
this->on_bluetooth_scanner_set_mode_request(msg); this->on_bluetooth_scanner_set_mode_request(msg);
#endif
break; break;
} }
#endif
default: default:
return false; break;
} }
return true;
} }
void APIServerConnection::on_hello_request(const HelloRequest &msg) { void APIServerConnection::on_hello_request(const HelloRequest &msg) {

View File

@ -199,7 +199,7 @@ class APIServerConnectionBase : public ProtoService {
virtual void on_update_command_request(const UpdateCommandRequest &value){}; virtual void on_update_command_request(const UpdateCommandRequest &value){};
#endif #endif
protected: protected:
bool read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) override; void read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) override;
}; };
class APIServerConnection : public APIServerConnectionBase { class APIServerConnection : public APIServerConnectionBase {

View File

@ -316,15 +316,13 @@ class ProtoSize {
/** /**
* @brief Calculates and adds the size of a nested message field to the total message size * @brief Calculates and adds the size of a nested message field to the total message size
* *
* This templated version directly takes a message object, calculates its size internally, * This version takes a ProtoMessage object, calculates its size internally,
* and updates the total_size reference. This eliminates the need for a temporary variable * and updates the total_size reference. This eliminates the need for a temporary variable
* at the call site. * at the call site.
* *
* @tparam MessageType The type of the nested message (inferred from parameter)
* @param message The nested message object * @param message The nested message object
*/ */
template<typename MessageType> static inline void add_message_object(uint32_t &total_size, uint32_t field_id_size, const ProtoMessage &message,
static inline void add_message_object(uint32_t &total_size, uint32_t field_id_size, const MessageType &message,
bool force = false) { bool force = false) {
uint32_t nested_size = 0; uint32_t nested_size = 0;
message.calculate_size(nested_size); message.calculate_size(nested_size);

View File

@ -104,7 +104,7 @@ void APIServer::setup() {
return; return;
} }
for (auto &c : this->clients_) { for (auto &c : this->clients_) {
if (!c->remove_) if (!c->flags_.remove)
c->try_send_log_message(level, tag, message); c->try_send_log_message(level, tag, message);
} }
}); });
@ -116,7 +116,7 @@ void APIServer::setup() {
esp32_camera::global_esp32_camera->add_image_callback( esp32_camera::global_esp32_camera->add_image_callback(
[this](const std::shared_ptr<esp32_camera::CameraImage> &image) { [this](const std::shared_ptr<esp32_camera::CameraImage> &image) {
for (auto &c : this->clients_) { for (auto &c : this->clients_) {
if (!c->remove_) if (!c->flags_.remove)
c->set_camera_state(image); c->set_camera_state(image);
} }
}); });
@ -176,7 +176,7 @@ void APIServer::loop() {
while (client_index < this->clients_.size()) { while (client_index < this->clients_.size()) {
auto &client = this->clients_[client_index]; auto &client = this->clients_[client_index];
if (!client->remove_) { if (!client->flags_.remove) {
// Common case: process active client // Common case: process active client
client->loop(); client->loop();
client_index++; client_index++;
@ -184,7 +184,9 @@ void APIServer::loop() {
} }
// Rare case: handle disconnection // Rare case: handle disconnection
#ifdef USE_API_CLIENT_DISCONNECTED_TRIGGER
this->client_disconnected_trigger_->trigger(client->client_info_, client->client_peername_); this->client_disconnected_trigger_->trigger(client->client_info_, client->client_peername_);
#endif
ESP_LOGV(TAG, "Remove connection %s", client->client_info_.c_str()); ESP_LOGV(TAG, "Remove connection %s", client->client_info_.c_str());
// Swap with the last element and pop (avoids expensive vector shifts) // Swap with the last element and pop (avoids expensive vector shifts)
@ -431,7 +433,7 @@ void APIServer::set_port(uint16_t port) { this->port_ = port; }
void APIServer::set_password(const std::string &password) { this->password_ = password; } void APIServer::set_password(const std::string &password) { this->password_ = password; }
void APIServer::set_batch_delay(uint32_t batch_delay) { this->batch_delay_ = batch_delay; } void APIServer::set_batch_delay(uint16_t batch_delay) { this->batch_delay_ = batch_delay; }
void APIServer::send_homeassistant_service_call(const HomeassistantServiceResponse &call) { void APIServer::send_homeassistant_service_call(const HomeassistantServiceResponse &call) {
for (auto &client : this->clients_) { for (auto &client : this->clients_) {
@ -502,7 +504,7 @@ bool APIServer::save_noise_psk(psk_t psk, bool make_active) {
#ifdef USE_HOMEASSISTANT_TIME #ifdef USE_HOMEASSISTANT_TIME
void APIServer::request_time() { void APIServer::request_time() {
for (auto &client : this->clients_) { for (auto &client : this->clients_) {
if (!client->remove_ && client->is_authenticated()) if (!client->flags_.remove && client->is_authenticated())
client->send_time_request(); client->send_time_request();
} }
} }
@ -526,8 +528,8 @@ void APIServer::on_shutdown() {
for (auto &c : this->clients_) { for (auto &c : this->clients_) {
if (!c->send_message(DisconnectRequest())) { if (!c->send_message(DisconnectRequest())) {
// If we can't send the disconnect request directly (tx_buffer full), // If we can't send the disconnect request directly (tx_buffer full),
// schedule it in the batch so it will be sent with the 5ms timer // schedule it at the front of the batch so it will be sent with priority
c->schedule_message_(nullptr, &APIConnection::try_send_disconnect_request, DisconnectRequest::MESSAGE_TYPE); c->schedule_message_front_(nullptr, &APIConnection::try_send_disconnect_request, DisconnectRequest::MESSAGE_TYPE);
} }
} }
} }

View File

@ -40,8 +40,8 @@ class APIServer : public Component, public Controller {
void set_port(uint16_t port); void set_port(uint16_t port);
void set_password(const std::string &password); void set_password(const std::string &password);
void set_reboot_timeout(uint32_t reboot_timeout); void set_reboot_timeout(uint32_t reboot_timeout);
void set_batch_delay(uint32_t batch_delay); void set_batch_delay(uint16_t batch_delay);
uint32_t get_batch_delay() const { return batch_delay_; } uint16_t get_batch_delay() const { return batch_delay_; }
// Get reference to shared buffer for API connections // Get reference to shared buffer for API connections
std::vector<uint8_t> &get_shared_buffer_ref() { return shared_write_buffer_; } std::vector<uint8_t> &get_shared_buffer_ref() { return shared_write_buffer_; }
@ -105,7 +105,18 @@ class APIServer : public Component, public Controller {
void on_media_player_update(media_player::MediaPlayer *obj) override; void on_media_player_update(media_player::MediaPlayer *obj) override;
#endif #endif
void send_homeassistant_service_call(const HomeassistantServiceResponse &call); void send_homeassistant_service_call(const HomeassistantServiceResponse &call);
void register_user_service(UserServiceDescriptor *descriptor) { this->user_services_.push_back(descriptor); } void register_user_service(UserServiceDescriptor *descriptor) {
#ifdef USE_API_YAML_SERVICES
// Vector is pre-allocated when services are defined in YAML
this->user_services_.push_back(descriptor);
#else
// Lazy allocate vector on first use for CustomAPIDevice
if (!this->user_services_) {
this->user_services_ = std::make_unique<std::vector<UserServiceDescriptor *>>();
}
this->user_services_->push_back(descriptor);
#endif
}
#ifdef USE_HOMEASSISTANT_TIME #ifdef USE_HOMEASSISTANT_TIME
void request_time(); void request_time();
#endif #endif
@ -134,35 +145,58 @@ class APIServer : public Component, public Controller {
void get_home_assistant_state(std::string entity_id, optional<std::string> attribute, void get_home_assistant_state(std::string entity_id, optional<std::string> attribute,
std::function<void(std::string)> f); std::function<void(std::string)> f);
const std::vector<HomeAssistantStateSubscription> &get_state_subs() const; const std::vector<HomeAssistantStateSubscription> &get_state_subs() const;
const std::vector<UserServiceDescriptor *> &get_user_services() const { return this->user_services_; } const std::vector<UserServiceDescriptor *> &get_user_services() const {
#ifdef USE_API_YAML_SERVICES
return this->user_services_;
#else
static const std::vector<UserServiceDescriptor *> EMPTY;
return this->user_services_ ? *this->user_services_ : EMPTY;
#endif
}
#ifdef USE_API_CLIENT_CONNECTED_TRIGGER
Trigger<std::string, std::string> *get_client_connected_trigger() const { return this->client_connected_trigger_; } Trigger<std::string, std::string> *get_client_connected_trigger() const { return this->client_connected_trigger_; }
#endif
#ifdef USE_API_CLIENT_DISCONNECTED_TRIGGER
Trigger<std::string, std::string> *get_client_disconnected_trigger() const { Trigger<std::string, std::string> *get_client_disconnected_trigger() const {
return this->client_disconnected_trigger_; return this->client_disconnected_trigger_;
} }
#endif
protected: protected:
void schedule_reboot_timeout_(); void schedule_reboot_timeout_();
// Pointers and pointer-like types first (4 bytes each) // Pointers and pointer-like types first (4 bytes each)
std::unique_ptr<socket::Socket> socket_ = nullptr; std::unique_ptr<socket::Socket> socket_ = nullptr;
#ifdef USE_API_CLIENT_CONNECTED_TRIGGER
Trigger<std::string, std::string> *client_connected_trigger_ = new Trigger<std::string, std::string>(); Trigger<std::string, std::string> *client_connected_trigger_ = new Trigger<std::string, std::string>();
#endif
#ifdef USE_API_CLIENT_DISCONNECTED_TRIGGER
Trigger<std::string, std::string> *client_disconnected_trigger_ = new Trigger<std::string, std::string>(); Trigger<std::string, std::string> *client_disconnected_trigger_ = new Trigger<std::string, std::string>();
#endif
// 4-byte aligned types // 4-byte aligned types
uint32_t reboot_timeout_{300000}; uint32_t reboot_timeout_{300000};
uint32_t batch_delay_{100};
// Vectors and strings (12 bytes each on 32-bit) // Vectors and strings (12 bytes each on 32-bit)
std::vector<std::unique_ptr<APIConnection>> clients_; std::vector<std::unique_ptr<APIConnection>> clients_;
std::string password_; std::string password_;
std::vector<uint8_t> shared_write_buffer_; // Shared proto write buffer for all connections std::vector<uint8_t> shared_write_buffer_; // Shared proto write buffer for all connections
std::vector<HomeAssistantStateSubscription> state_subs_; std::vector<HomeAssistantStateSubscription> state_subs_;
#ifdef USE_API_YAML_SERVICES
// When services are defined in YAML, we know at compile time that services will be registered
std::vector<UserServiceDescriptor *> user_services_; std::vector<UserServiceDescriptor *> user_services_;
#else
// Services can still be registered at runtime by CustomAPIDevice components even when not
// defined in YAML. Using unique_ptr allows lazy allocation, saving 12 bytes in the common
// case where no services (YAML or custom) are used.
std::unique_ptr<std::vector<UserServiceDescriptor *>> user_services_;
#endif
// Group smaller types together // Group smaller types together
uint16_t port_{6053}; uint16_t port_{6053};
uint16_t batch_delay_{100};
bool shutting_down_ = false; bool shutting_down_ = false;
// 3 bytes used, 1 byte padding // 5 bytes used, 3 bytes padding
#ifdef USE_API_NOISE #ifdef USE_API_NOISE
std::shared_ptr<APINoiseContext> noise_ctx_ = std::make_shared<APINoiseContext>(); std::shared_ptr<APINoiseContext> noise_ctx_ = std::make_shared<APINoiseContext>();

View File

@ -4,9 +4,15 @@ import asyncio
from datetime import datetime from datetime import datetime
import logging import logging
from typing import TYPE_CHECKING, Any from typing import TYPE_CHECKING, Any
import warnings
from aioesphomeapi import APIClient, parse_log_message # Suppress protobuf version warnings
from aioesphomeapi.log_runner import async_run with warnings.catch_warnings():
warnings.filterwarnings(
"ignore", category=UserWarning, message=".*Protobuf gencode version.*"
)
from aioesphomeapi import APIClient, parse_log_message
from aioesphomeapi.log_runner import async_run
from esphome.const import CONF_KEY, CONF_PASSWORD, CONF_PORT, __version__ from esphome.const import CONF_KEY, CONF_PASSWORD, CONF_PORT, __version__
from esphome.core import CORE from esphome.core import CORE
@ -29,8 +35,8 @@ async def async_run_logs(config: dict[str, Any], address: str) -> None:
port: int = int(conf[CONF_PORT]) port: int = int(conf[CONF_PORT])
password: str = conf[CONF_PASSWORD] password: str = conf[CONF_PASSWORD]
noise_psk: str | None = None noise_psk: str | None = None
if CONF_ENCRYPTION in conf: if (encryption := conf.get(CONF_ENCRYPTION)) and (key := encryption.get(CONF_KEY)):
noise_psk = conf[CONF_ENCRYPTION][CONF_KEY] noise_psk = key
_LOGGER.info("Starting log output from %s using esphome API", address) _LOGGER.info("Starting log output from %s using esphome API", address)
cli = APIClient( cli = APIClient(
address, address,

View File

@ -1,6 +1,7 @@
#include "list_entities.h" #include "list_entities.h"
#ifdef USE_API #ifdef USE_API
#include "api_connection.h" #include "api_connection.h"
#include "api_pb2.h"
#include "esphome/core/application.h" #include "esphome/core/application.h"
#include "esphome/core/log.h" #include "esphome/core/log.h"
#include "esphome/core/util.h" #include "esphome/core/util.h"
@ -8,155 +9,85 @@
namespace esphome { namespace esphome {
namespace api { namespace api {
// Generate entity handler implementations using macros
#ifdef USE_BINARY_SENSOR #ifdef USE_BINARY_SENSOR
bool ListEntitiesIterator::on_binary_sensor(binary_sensor::BinarySensor *binary_sensor) { LIST_ENTITIES_HANDLER(binary_sensor, binary_sensor::BinarySensor, ListEntitiesBinarySensorResponse)
this->client_->send_binary_sensor_info(binary_sensor);
return true;
}
#endif #endif
#ifdef USE_COVER #ifdef USE_COVER
bool ListEntitiesIterator::on_cover(cover::Cover *cover) { LIST_ENTITIES_HANDLER(cover, cover::Cover, ListEntitiesCoverResponse)
this->client_->send_cover_info(cover);
return true;
}
#endif #endif
#ifdef USE_FAN #ifdef USE_FAN
bool ListEntitiesIterator::on_fan(fan::Fan *fan) { LIST_ENTITIES_HANDLER(fan, fan::Fan, ListEntitiesFanResponse)
this->client_->send_fan_info(fan);
return true;
}
#endif #endif
#ifdef USE_LIGHT #ifdef USE_LIGHT
bool ListEntitiesIterator::on_light(light::LightState *light) { LIST_ENTITIES_HANDLER(light, light::LightState, ListEntitiesLightResponse)
this->client_->send_light_info(light);
return true;
}
#endif #endif
#ifdef USE_SENSOR #ifdef USE_SENSOR
bool ListEntitiesIterator::on_sensor(sensor::Sensor *sensor) { LIST_ENTITIES_HANDLER(sensor, sensor::Sensor, ListEntitiesSensorResponse)
this->client_->send_sensor_info(sensor);
return true;
}
#endif #endif
#ifdef USE_SWITCH #ifdef USE_SWITCH
bool ListEntitiesIterator::on_switch(switch_::Switch *a_switch) { LIST_ENTITIES_HANDLER(switch, switch_::Switch, ListEntitiesSwitchResponse)
this->client_->send_switch_info(a_switch);
return true;
}
#endif #endif
#ifdef USE_BUTTON #ifdef USE_BUTTON
bool ListEntitiesIterator::on_button(button::Button *button) { LIST_ENTITIES_HANDLER(button, button::Button, ListEntitiesButtonResponse)
this->client_->send_button_info(button);
return true;
}
#endif #endif
#ifdef USE_TEXT_SENSOR #ifdef USE_TEXT_SENSOR
bool ListEntitiesIterator::on_text_sensor(text_sensor::TextSensor *text_sensor) { LIST_ENTITIES_HANDLER(text_sensor, text_sensor::TextSensor, ListEntitiesTextSensorResponse)
this->client_->send_text_sensor_info(text_sensor);
return true;
}
#endif #endif
#ifdef USE_LOCK #ifdef USE_LOCK
bool ListEntitiesIterator::on_lock(lock::Lock *a_lock) { LIST_ENTITIES_HANDLER(lock, lock::Lock, ListEntitiesLockResponse)
this->client_->send_lock_info(a_lock);
return true;
}
#endif #endif
#ifdef USE_VALVE #ifdef USE_VALVE
bool ListEntitiesIterator::on_valve(valve::Valve *valve) { LIST_ENTITIES_HANDLER(valve, valve::Valve, ListEntitiesValveResponse)
this->client_->send_valve_info(valve); #endif
return true; #ifdef USE_ESP32_CAMERA
} LIST_ENTITIES_HANDLER(camera, esp32_camera::ESP32Camera, ListEntitiesCameraResponse)
#endif
#ifdef USE_CLIMATE
LIST_ENTITIES_HANDLER(climate, climate::Climate, ListEntitiesClimateResponse)
#endif
#ifdef USE_NUMBER
LIST_ENTITIES_HANDLER(number, number::Number, ListEntitiesNumberResponse)
#endif
#ifdef USE_DATETIME_DATE
LIST_ENTITIES_HANDLER(date, datetime::DateEntity, ListEntitiesDateResponse)
#endif
#ifdef USE_DATETIME_TIME
LIST_ENTITIES_HANDLER(time, datetime::TimeEntity, ListEntitiesTimeResponse)
#endif
#ifdef USE_DATETIME_DATETIME
LIST_ENTITIES_HANDLER(datetime, datetime::DateTimeEntity, ListEntitiesDateTimeResponse)
#endif
#ifdef USE_TEXT
LIST_ENTITIES_HANDLER(text, text::Text, ListEntitiesTextResponse)
#endif
#ifdef USE_SELECT
LIST_ENTITIES_HANDLER(select, select::Select, ListEntitiesSelectResponse)
#endif
#ifdef USE_MEDIA_PLAYER
LIST_ENTITIES_HANDLER(media_player, media_player::MediaPlayer, ListEntitiesMediaPlayerResponse)
#endif
#ifdef USE_ALARM_CONTROL_PANEL
LIST_ENTITIES_HANDLER(alarm_control_panel, alarm_control_panel::AlarmControlPanel,
ListEntitiesAlarmControlPanelResponse)
#endif
#ifdef USE_EVENT
LIST_ENTITIES_HANDLER(event, event::Event, ListEntitiesEventResponse)
#endif
#ifdef USE_UPDATE
LIST_ENTITIES_HANDLER(update, update::UpdateEntity, ListEntitiesUpdateResponse)
#endif #endif
// Special cases that don't follow the pattern
bool ListEntitiesIterator::on_end() { return this->client_->send_list_info_done(); } bool ListEntitiesIterator::on_end() { return this->client_->send_list_info_done(); }
ListEntitiesIterator::ListEntitiesIterator(APIConnection *client) : client_(client) {} ListEntitiesIterator::ListEntitiesIterator(APIConnection *client) : client_(client) {}
bool ListEntitiesIterator::on_service(UserServiceDescriptor *service) { bool ListEntitiesIterator::on_service(UserServiceDescriptor *service) {
auto resp = service->encode_list_service_response(); auto resp = service->encode_list_service_response();
return this->client_->send_message(resp); return this->client_->send_message(resp);
} }
#ifdef USE_ESP32_CAMERA
bool ListEntitiesIterator::on_camera(esp32_camera::ESP32Camera *camera) {
this->client_->send_camera_info(camera);
return true;
}
#endif
#ifdef USE_CLIMATE
bool ListEntitiesIterator::on_climate(climate::Climate *climate) {
this->client_->send_climate_info(climate);
return true;
}
#endif
#ifdef USE_NUMBER
bool ListEntitiesIterator::on_number(number::Number *number) {
this->client_->send_number_info(number);
return true;
}
#endif
#ifdef USE_DATETIME_DATE
bool ListEntitiesIterator::on_date(datetime::DateEntity *date) {
this->client_->send_date_info(date);
return true;
}
#endif
#ifdef USE_DATETIME_TIME
bool ListEntitiesIterator::on_time(datetime::TimeEntity *time) {
this->client_->send_time_info(time);
return true;
}
#endif
#ifdef USE_DATETIME_DATETIME
bool ListEntitiesIterator::on_datetime(datetime::DateTimeEntity *datetime) {
this->client_->send_datetime_info(datetime);
return true;
}
#endif
#ifdef USE_TEXT
bool ListEntitiesIterator::on_text(text::Text *text) {
this->client_->send_text_info(text);
return true;
}
#endif
#ifdef USE_SELECT
bool ListEntitiesIterator::on_select(select::Select *select) {
this->client_->send_select_info(select);
return true;
}
#endif
#ifdef USE_MEDIA_PLAYER
bool ListEntitiesIterator::on_media_player(media_player::MediaPlayer *media_player) {
this->client_->send_media_player_info(media_player);
return true;
}
#endif
#ifdef USE_ALARM_CONTROL_PANEL
bool ListEntitiesIterator::on_alarm_control_panel(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) {
this->client_->send_alarm_control_panel_info(a_alarm_control_panel);
return true;
}
#endif
#ifdef USE_EVENT
bool ListEntitiesIterator::on_event(event::Event *event) {
this->client_->send_event_info(event);
return true;
}
#endif
#ifdef USE_UPDATE
bool ListEntitiesIterator::on_update(update::UpdateEntity *update) {
this->client_->send_update_info(update);
return true;
}
#endif
} // namespace api } // namespace api
} // namespace esphome } // namespace esphome
#endif #endif

View File

@ -9,75 +9,83 @@ namespace api {
class APIConnection; class APIConnection;
// Macro for generating ListEntitiesIterator handlers
// Calls schedule_message_ with try_send_*_info
#define LIST_ENTITIES_HANDLER(entity_type, EntityClass, ResponseType) \
bool ListEntitiesIterator::on_##entity_type(EntityClass *entity) { /* NOLINT(bugprone-macro-parentheses) */ \
return this->client_->schedule_message_(entity, &APIConnection::try_send_##entity_type##_info, \
ResponseType::MESSAGE_TYPE); \
}
class ListEntitiesIterator : public ComponentIterator { class ListEntitiesIterator : public ComponentIterator {
public: public:
ListEntitiesIterator(APIConnection *client); ListEntitiesIterator(APIConnection *client);
#ifdef USE_BINARY_SENSOR #ifdef USE_BINARY_SENSOR
bool on_binary_sensor(binary_sensor::BinarySensor *binary_sensor) override; bool on_binary_sensor(binary_sensor::BinarySensor *entity) override;
#endif #endif
#ifdef USE_COVER #ifdef USE_COVER
bool on_cover(cover::Cover *cover) override; bool on_cover(cover::Cover *entity) override;
#endif #endif
#ifdef USE_FAN #ifdef USE_FAN
bool on_fan(fan::Fan *fan) override; bool on_fan(fan::Fan *entity) override;
#endif #endif
#ifdef USE_LIGHT #ifdef USE_LIGHT
bool on_light(light::LightState *light) override; bool on_light(light::LightState *entity) override;
#endif #endif
#ifdef USE_SENSOR #ifdef USE_SENSOR
bool on_sensor(sensor::Sensor *sensor) override; bool on_sensor(sensor::Sensor *entity) override;
#endif #endif
#ifdef USE_SWITCH #ifdef USE_SWITCH
bool on_switch(switch_::Switch *a_switch) override; bool on_switch(switch_::Switch *entity) override;
#endif #endif
#ifdef USE_BUTTON #ifdef USE_BUTTON
bool on_button(button::Button *button) override; bool on_button(button::Button *entity) override;
#endif #endif
#ifdef USE_TEXT_SENSOR #ifdef USE_TEXT_SENSOR
bool on_text_sensor(text_sensor::TextSensor *text_sensor) override; bool on_text_sensor(text_sensor::TextSensor *entity) override;
#endif #endif
bool on_service(UserServiceDescriptor *service) override; bool on_service(UserServiceDescriptor *service) override;
#ifdef USE_ESP32_CAMERA #ifdef USE_ESP32_CAMERA
bool on_camera(esp32_camera::ESP32Camera *camera) override; bool on_camera(esp32_camera::ESP32Camera *entity) override;
#endif #endif
#ifdef USE_CLIMATE #ifdef USE_CLIMATE
bool on_climate(climate::Climate *climate) override; bool on_climate(climate::Climate *entity) override;
#endif #endif
#ifdef USE_NUMBER #ifdef USE_NUMBER
bool on_number(number::Number *number) override; bool on_number(number::Number *entity) override;
#endif #endif
#ifdef USE_DATETIME_DATE #ifdef USE_DATETIME_DATE
bool on_date(datetime::DateEntity *date) override; bool on_date(datetime::DateEntity *entity) override;
#endif #endif
#ifdef USE_DATETIME_TIME #ifdef USE_DATETIME_TIME
bool on_time(datetime::TimeEntity *time) override; bool on_time(datetime::TimeEntity *entity) override;
#endif #endif
#ifdef USE_DATETIME_DATETIME #ifdef USE_DATETIME_DATETIME
bool on_datetime(datetime::DateTimeEntity *datetime) override; bool on_datetime(datetime::DateTimeEntity *entity) override;
#endif #endif
#ifdef USE_TEXT #ifdef USE_TEXT
bool on_text(text::Text *text) override; bool on_text(text::Text *entity) override;
#endif #endif
#ifdef USE_SELECT #ifdef USE_SELECT
bool on_select(select::Select *select) override; bool on_select(select::Select *entity) override;
#endif #endif
#ifdef USE_LOCK #ifdef USE_LOCK
bool on_lock(lock::Lock *a_lock) override; bool on_lock(lock::Lock *entity) override;
#endif #endif
#ifdef USE_VALVE #ifdef USE_VALVE
bool on_valve(valve::Valve *valve) override; bool on_valve(valve::Valve *entity) override;
#endif #endif
#ifdef USE_MEDIA_PLAYER #ifdef USE_MEDIA_PLAYER
bool on_media_player(media_player::MediaPlayer *media_player) override; bool on_media_player(media_player::MediaPlayer *entity) override;
#endif #endif
#ifdef USE_ALARM_CONTROL_PANEL #ifdef USE_ALARM_CONTROL_PANEL
bool on_alarm_control_panel(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) override; bool on_alarm_control_panel(alarm_control_panel::AlarmControlPanel *entity) override;
#endif #endif
#ifdef USE_EVENT #ifdef USE_EVENT
bool on_event(event::Event *event) override; bool on_event(event::Event *entity) override;
#endif #endif
#ifdef USE_UPDATE #ifdef USE_UPDATE
bool on_update(update::UpdateEntity *update) override; bool on_update(update::UpdateEntity *entity) override;
#endif #endif
bool on_end() override; bool on_end() override;
bool completed() { return this->state_ == IteratorState::NONE; } bool completed() { return this->state_ == IteratorState::NONE; }

View File

@ -364,7 +364,7 @@ class ProtoService {
*/ */
virtual ProtoWriteBuffer create_buffer(uint32_t reserve_size) = 0; virtual ProtoWriteBuffer create_buffer(uint32_t reserve_size) = 0;
virtual bool send_buffer(ProtoWriteBuffer buffer, uint16_t message_type) = 0; virtual bool send_buffer(ProtoWriteBuffer buffer, uint16_t message_type) = 0;
virtual bool read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) = 0; virtual void read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) = 0;
// Optimized method that pre-allocates buffer based on message size // Optimized method that pre-allocates buffer based on message size
bool send_message_(const ProtoMessage &msg, uint16_t message_type) { bool send_message_(const ProtoMessage &msg, uint16_t message_type) {

View File

@ -6,73 +6,67 @@
namespace esphome { namespace esphome {
namespace api { namespace api {
// Generate entity handler implementations using macros
#ifdef USE_BINARY_SENSOR #ifdef USE_BINARY_SENSOR
bool InitialStateIterator::on_binary_sensor(binary_sensor::BinarySensor *binary_sensor) { INITIAL_STATE_HANDLER(binary_sensor, binary_sensor::BinarySensor)
return this->client_->send_binary_sensor_state(binary_sensor);
}
#endif #endif
#ifdef USE_COVER #ifdef USE_COVER
bool InitialStateIterator::on_cover(cover::Cover *cover) { return this->client_->send_cover_state(cover); } INITIAL_STATE_HANDLER(cover, cover::Cover)
#endif #endif
#ifdef USE_FAN #ifdef USE_FAN
bool InitialStateIterator::on_fan(fan::Fan *fan) { return this->client_->send_fan_state(fan); } INITIAL_STATE_HANDLER(fan, fan::Fan)
#endif #endif
#ifdef USE_LIGHT #ifdef USE_LIGHT
bool InitialStateIterator::on_light(light::LightState *light) { return this->client_->send_light_state(light); } INITIAL_STATE_HANDLER(light, light::LightState)
#endif #endif
#ifdef USE_SENSOR #ifdef USE_SENSOR
bool InitialStateIterator::on_sensor(sensor::Sensor *sensor) { return this->client_->send_sensor_state(sensor); } INITIAL_STATE_HANDLER(sensor, sensor::Sensor)
#endif #endif
#ifdef USE_SWITCH #ifdef USE_SWITCH
bool InitialStateIterator::on_switch(switch_::Switch *a_switch) { return this->client_->send_switch_state(a_switch); } INITIAL_STATE_HANDLER(switch, switch_::Switch)
#endif #endif
#ifdef USE_TEXT_SENSOR #ifdef USE_TEXT_SENSOR
bool InitialStateIterator::on_text_sensor(text_sensor::TextSensor *text_sensor) { INITIAL_STATE_HANDLER(text_sensor, text_sensor::TextSensor)
return this->client_->send_text_sensor_state(text_sensor);
}
#endif #endif
#ifdef USE_CLIMATE #ifdef USE_CLIMATE
bool InitialStateIterator::on_climate(climate::Climate *climate) { return this->client_->send_climate_state(climate); } INITIAL_STATE_HANDLER(climate, climate::Climate)
#endif #endif
#ifdef USE_NUMBER #ifdef USE_NUMBER
bool InitialStateIterator::on_number(number::Number *number) { return this->client_->send_number_state(number); } INITIAL_STATE_HANDLER(number, number::Number)
#endif #endif
#ifdef USE_DATETIME_DATE #ifdef USE_DATETIME_DATE
bool InitialStateIterator::on_date(datetime::DateEntity *date) { return this->client_->send_date_state(date); } INITIAL_STATE_HANDLER(date, datetime::DateEntity)
#endif #endif
#ifdef USE_DATETIME_TIME #ifdef USE_DATETIME_TIME
bool InitialStateIterator::on_time(datetime::TimeEntity *time) { return this->client_->send_time_state(time); } INITIAL_STATE_HANDLER(time, datetime::TimeEntity)
#endif #endif
#ifdef USE_DATETIME_DATETIME #ifdef USE_DATETIME_DATETIME
bool InitialStateIterator::on_datetime(datetime::DateTimeEntity *datetime) { INITIAL_STATE_HANDLER(datetime, datetime::DateTimeEntity)
return this->client_->send_datetime_state(datetime);
}
#endif #endif
#ifdef USE_TEXT #ifdef USE_TEXT
bool InitialStateIterator::on_text(text::Text *text) { return this->client_->send_text_state(text); } INITIAL_STATE_HANDLER(text, text::Text)
#endif #endif
#ifdef USE_SELECT #ifdef USE_SELECT
bool InitialStateIterator::on_select(select::Select *select) { return this->client_->send_select_state(select); } INITIAL_STATE_HANDLER(select, select::Select)
#endif #endif
#ifdef USE_LOCK #ifdef USE_LOCK
bool InitialStateIterator::on_lock(lock::Lock *a_lock) { return this->client_->send_lock_state(a_lock); } INITIAL_STATE_HANDLER(lock, lock::Lock)
#endif #endif
#ifdef USE_VALVE #ifdef USE_VALVE
bool InitialStateIterator::on_valve(valve::Valve *valve) { return this->client_->send_valve_state(valve); } INITIAL_STATE_HANDLER(valve, valve::Valve)
#endif #endif
#ifdef USE_MEDIA_PLAYER #ifdef USE_MEDIA_PLAYER
bool InitialStateIterator::on_media_player(media_player::MediaPlayer *media_player) { INITIAL_STATE_HANDLER(media_player, media_player::MediaPlayer)
return this->client_->send_media_player_state(media_player);
}
#endif #endif
#ifdef USE_ALARM_CONTROL_PANEL #ifdef USE_ALARM_CONTROL_PANEL
bool InitialStateIterator::on_alarm_control_panel(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) { INITIAL_STATE_HANDLER(alarm_control_panel, alarm_control_panel::AlarmControlPanel)
return this->client_->send_alarm_control_panel_state(a_alarm_control_panel);
}
#endif #endif
#ifdef USE_UPDATE #ifdef USE_UPDATE
bool InitialStateIterator::on_update(update::UpdateEntity *update) { return this->client_->send_update_state(update); } INITIAL_STATE_HANDLER(update, update::UpdateEntity)
#endif #endif
// Special cases (button and event) are already defined inline in subscribe_state.h
InitialStateIterator::InitialStateIterator(APIConnection *client) : client_(client) {} InitialStateIterator::InitialStateIterator(APIConnection *client) : client_(client) {}
} // namespace api } // namespace api

View File

@ -10,71 +10,78 @@ namespace api {
class APIConnection; class APIConnection;
// Macro for generating InitialStateIterator handlers
// Calls send_*_state
#define INITIAL_STATE_HANDLER(entity_type, EntityClass) \
bool InitialStateIterator::on_##entity_type(EntityClass *entity) { /* NOLINT(bugprone-macro-parentheses) */ \
return this->client_->send_##entity_type##_state(entity); \
}
class InitialStateIterator : public ComponentIterator { class InitialStateIterator : public ComponentIterator {
public: public:
InitialStateIterator(APIConnection *client); InitialStateIterator(APIConnection *client);
#ifdef USE_BINARY_SENSOR #ifdef USE_BINARY_SENSOR
bool on_binary_sensor(binary_sensor::BinarySensor *binary_sensor) override; bool on_binary_sensor(binary_sensor::BinarySensor *entity) override;
#endif #endif
#ifdef USE_COVER #ifdef USE_COVER
bool on_cover(cover::Cover *cover) override; bool on_cover(cover::Cover *entity) override;
#endif #endif
#ifdef USE_FAN #ifdef USE_FAN
bool on_fan(fan::Fan *fan) override; bool on_fan(fan::Fan *entity) override;
#endif #endif
#ifdef USE_LIGHT #ifdef USE_LIGHT
bool on_light(light::LightState *light) override; bool on_light(light::LightState *entity) override;
#endif #endif
#ifdef USE_SENSOR #ifdef USE_SENSOR
bool on_sensor(sensor::Sensor *sensor) override; bool on_sensor(sensor::Sensor *entity) override;
#endif #endif
#ifdef USE_SWITCH #ifdef USE_SWITCH
bool on_switch(switch_::Switch *a_switch) override; bool on_switch(switch_::Switch *entity) override;
#endif #endif
#ifdef USE_BUTTON #ifdef USE_BUTTON
bool on_button(button::Button *button) override { return true; }; bool on_button(button::Button *button) override { return true; };
#endif #endif
#ifdef USE_TEXT_SENSOR #ifdef USE_TEXT_SENSOR
bool on_text_sensor(text_sensor::TextSensor *text_sensor) override; bool on_text_sensor(text_sensor::TextSensor *entity) override;
#endif #endif
#ifdef USE_CLIMATE #ifdef USE_CLIMATE
bool on_climate(climate::Climate *climate) override; bool on_climate(climate::Climate *entity) override;
#endif #endif
#ifdef USE_NUMBER #ifdef USE_NUMBER
bool on_number(number::Number *number) override; bool on_number(number::Number *entity) override;
#endif #endif
#ifdef USE_DATETIME_DATE #ifdef USE_DATETIME_DATE
bool on_date(datetime::DateEntity *date) override; bool on_date(datetime::DateEntity *entity) override;
#endif #endif
#ifdef USE_DATETIME_TIME #ifdef USE_DATETIME_TIME
bool on_time(datetime::TimeEntity *time) override; bool on_time(datetime::TimeEntity *entity) override;
#endif #endif
#ifdef USE_DATETIME_DATETIME #ifdef USE_DATETIME_DATETIME
bool on_datetime(datetime::DateTimeEntity *datetime) override; bool on_datetime(datetime::DateTimeEntity *entity) override;
#endif #endif
#ifdef USE_TEXT #ifdef USE_TEXT
bool on_text(text::Text *text) override; bool on_text(text::Text *entity) override;
#endif #endif
#ifdef USE_SELECT #ifdef USE_SELECT
bool on_select(select::Select *select) override; bool on_select(select::Select *entity) override;
#endif #endif
#ifdef USE_LOCK #ifdef USE_LOCK
bool on_lock(lock::Lock *a_lock) override; bool on_lock(lock::Lock *entity) override;
#endif #endif
#ifdef USE_VALVE #ifdef USE_VALVE
bool on_valve(valve::Valve *valve) override; bool on_valve(valve::Valve *entity) override;
#endif #endif
#ifdef USE_MEDIA_PLAYER #ifdef USE_MEDIA_PLAYER
bool on_media_player(media_player::MediaPlayer *media_player) override; bool on_media_player(media_player::MediaPlayer *entity) override;
#endif #endif
#ifdef USE_ALARM_CONTROL_PANEL #ifdef USE_ALARM_CONTROL_PANEL
bool on_alarm_control_panel(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) override; bool on_alarm_control_panel(alarm_control_panel::AlarmControlPanel *entity) override;
#endif #endif
#ifdef USE_EVENT #ifdef USE_EVENT
bool on_event(event::Event *event) override { return true; }; bool on_event(event::Event *event) override { return true; };
#endif #endif
#ifdef USE_UPDATE #ifdef USE_UPDATE
bool on_update(update::UpdateEntity *update) override; bool on_update(update::UpdateEntity *entity) override;
#endif #endif
bool completed() { return this->state_ == IteratorState::NONE; } bool completed() { return this->state_ == IteratorState::NONE; }

View File

@ -50,7 +50,6 @@ class AS5600Component : public Component, public i2c::I2CDevice {
void setup() override; void setup() override;
void dump_config() override; void dump_config() override;
/// HARDWARE_LATE setup priority /// HARDWARE_LATE setup priority
float get_setup_priority() const override { return setup_priority::DATA; }
// configuration setters // configuration setters
void set_dir_pin(InternalGPIOPin *pin) { this->dir_pin_ = pin; } void set_dir_pin(InternalGPIOPin *pin) { this->dir_pin_ = pin; }

View File

@ -25,7 +25,6 @@ class ATCMiThermometer : public Component, public esp32_ble_tracker::ESPBTDevice
bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override; bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override;
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void set_temperature(sensor::Sensor *temperature) { temperature_ = temperature; } void set_temperature(sensor::Sensor *temperature) { temperature_ = temperature; }
void set_humidity(sensor::Sensor *humidity) { humidity_ = humidity; } void set_humidity(sensor::Sensor *humidity) { humidity_ = humidity; }
void set_battery_level(sensor::Sensor *battery_level) { battery_level_ = battery_level; } void set_battery_level(sensor::Sensor *battery_level) { battery_level_ = battery_level; }

View File

@ -16,7 +16,6 @@ class BParasite : public Component, public esp32_ble_tracker::ESPBTDeviceListene
bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override; bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override;
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void set_battery_voltage(sensor::Sensor *battery_voltage) { battery_voltage_ = battery_voltage; } void set_battery_voltage(sensor::Sensor *battery_voltage) { battery_voltage_ = battery_voltage; }
void set_temperature(sensor::Sensor *temperature) { temperature_ = temperature; } void set_temperature(sensor::Sensor *temperature) { temperature_ = temperature; }

View File

@ -16,7 +16,6 @@ class BLEBinaryOutput : public output::BinaryOutput, public BLEClientNode, publi
public: public:
void dump_config() override; void dump_config() override;
void loop() override {} void loop() override {}
float get_setup_priority() const override { return setup_priority::DATA; }
void set_service_uuid16(uint16_t uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_uint16(uuid); } void set_service_uuid16(uint16_t uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_uint16(uuid); }
void set_service_uuid32(uint32_t uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_uint32(uuid); } void set_service_uuid32(uint32_t uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_uint32(uuid); }
void set_service_uuid128(uint8_t *uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_raw(uuid); } void set_service_uuid128(uint8_t *uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_raw(uuid); }

View File

@ -18,7 +18,6 @@ class BLEClientRSSISensor : public sensor::Sensor, public PollingComponent, publ
void loop() override; void loop() override;
void update() override; void update() override;
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) override; void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) override;

View File

@ -24,7 +24,6 @@ class BLESensor : public sensor::Sensor, public PollingComponent, public BLEClie
void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
esp_ble_gattc_cb_param_t *param) override; esp_ble_gattc_cb_param_t *param) override;
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void set_service_uuid16(uint16_t uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_uint16(uuid); } void set_service_uuid16(uint16_t uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_uint16(uuid); }
void set_service_uuid32(uint32_t uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_uint32(uuid); } void set_service_uuid32(uint32_t uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_uint32(uuid); }
void set_service_uuid128(uint8_t *uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_raw(uuid); } void set_service_uuid128(uint8_t *uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_raw(uuid); }

View File

@ -19,7 +19,6 @@ class BLEClientSwitch : public switch_::Switch, public Component, public BLEClie
void loop() override {} void loop() override {}
void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
esp_ble_gattc_cb_param_t *param) override; esp_ble_gattc_cb_param_t *param) override;
float get_setup_priority() const override { return setup_priority::DATA; }
protected: protected:
void write_state(bool state) override; void write_state(bool state) override;

View File

@ -20,7 +20,6 @@ class BLETextSensor : public text_sensor::TextSensor, public PollingComponent, p
void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
esp_ble_gattc_cb_param_t *param) override; esp_ble_gattc_cb_param_t *param) override;
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void set_service_uuid16(uint16_t uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_uint16(uuid); } void set_service_uuid16(uint16_t uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_uint16(uuid); }
void set_service_uuid32(uint32_t uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_uint32(uuid); } void set_service_uuid32(uint32_t uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_uint32(uuid); }
void set_service_uuid128(uint8_t *uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_raw(uuid); } void set_service_uuid128(uint8_t *uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_raw(uuid); }

View File

@ -105,7 +105,6 @@ class BLEPresenceDevice : public binary_sensor::BinarySensorInitiallyOff,
this->set_found_(false); this->set_found_(false);
} }
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
protected: protected:
void set_found_(bool state) { void set_found_(bool state) {

View File

@ -99,7 +99,6 @@ class BLERSSISensor : public sensor::Sensor, public esp32_ble_tracker::ESPBTDevi
return false; return false;
} }
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
protected: protected:
enum MatchType { MATCH_BY_MAC_ADDRESS, MATCH_BY_IRK, MATCH_BY_SERVICE_UUID, MATCH_BY_IBEACON_UUID }; enum MatchType { MATCH_BY_MAC_ADDRESS, MATCH_BY_IRK, MATCH_BY_SERVICE_UUID, MATCH_BY_IBEACON_UUID };

View File

@ -29,7 +29,6 @@ class BLEScanner : public text_sensor::TextSensor, public esp32_ble_tracker::ESP
return true; return true;
} }
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
}; };
} // namespace ble_scanner } // namespace ble_scanner

View File

@ -61,8 +61,6 @@ enum IIRFilter {
class BMP581Component : public PollingComponent, public i2c::I2CDevice { class BMP581Component : public PollingComponent, public i2c::I2CDevice {
public: public:
float get_setup_priority() const override { return setup_priority::DATA; }
void dump_config() override; void dump_config() override;
void setup() override; void setup() override;

View File

@ -46,7 +46,6 @@ class CAP1188Component : public Component, public i2c::I2CDevice {
void set_reset_pin(GPIOPin *reset_pin) { this->reset_pin_ = reset_pin; } void set_reset_pin(GPIOPin *reset_pin) { this->reset_pin_ = reset_pin; }
void setup() override; void setup() override;
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void loop() override; void loop() override;
protected: protected:

View File

@ -25,8 +25,6 @@ class CCS811Component : public PollingComponent, public i2c::I2CDevice {
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
protected: protected:
optional<uint8_t> read_status_() { return this->read_byte(0x00); } optional<uint8_t> read_status_() { return this->read_byte(0x00); }
bool status_has_error_() { return this->read_status_().value_or(1) & 1; } bool status_has_error_() { return this->read_status_().value_or(1) & 1; }

View File

@ -11,7 +11,6 @@ class CopyBinarySensor : public binary_sensor::BinarySensor, public Component {
void set_source(binary_sensor::BinarySensor *source) { source_ = source; } void set_source(binary_sensor::BinarySensor *source) { source_ = source; }
void setup() override; void setup() override;
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
protected: protected:
binary_sensor::BinarySensor *source_; binary_sensor::BinarySensor *source_;

View File

@ -10,7 +10,6 @@ class CopyButton : public button::Button, public Component {
public: public:
void set_source(button::Button *source) { source_ = source; } void set_source(button::Button *source) { source_ = source; }
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
protected: protected:
void press_action() override; void press_action() override;

View File

@ -11,7 +11,6 @@ class CopyCover : public cover::Cover, public Component {
void set_source(cover::Cover *source) { source_ = source; } void set_source(cover::Cover *source) { source_ = source; }
void setup() override; void setup() override;
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
cover::CoverTraits get_traits() override; cover::CoverTraits get_traits() override;

View File

@ -11,7 +11,6 @@ class CopyFan : public fan::Fan, public Component {
void set_source(fan::Fan *source) { source_ = source; } void set_source(fan::Fan *source) { source_ = source; }
void setup() override; void setup() override;
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
fan::FanTraits get_traits() override; fan::FanTraits get_traits() override;

View File

@ -11,7 +11,6 @@ class CopyLock : public lock::Lock, public Component {
void set_source(lock::Lock *source) { source_ = source; } void set_source(lock::Lock *source) { source_ = source; }
void setup() override; void setup() override;
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
protected: protected:
void control(const lock::LockCall &call) override; void control(const lock::LockCall &call) override;

View File

@ -11,7 +11,6 @@ class CopyNumber : public number::Number, public Component {
void set_source(number::Number *source) { source_ = source; } void set_source(number::Number *source) { source_ = source; }
void setup() override; void setup() override;
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
protected: protected:
void control(float value) override; void control(float value) override;

View File

@ -11,7 +11,6 @@ class CopySelect : public select::Select, public Component {
void set_source(select::Select *source) { source_ = source; } void set_source(select::Select *source) { source_ = source; }
void setup() override; void setup() override;
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
protected: protected:
void control(const std::string &value) override; void control(const std::string &value) override;

View File

@ -11,7 +11,6 @@ class CopySensor : public sensor::Sensor, public Component {
void set_source(sensor::Sensor *source) { source_ = source; } void set_source(sensor::Sensor *source) { source_ = source; }
void setup() override; void setup() override;
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
protected: protected:
sensor::Sensor *source_; sensor::Sensor *source_;

View File

@ -11,7 +11,6 @@ class CopySwitch : public switch_::Switch, public Component {
void set_source(switch_::Switch *source) { source_ = source; } void set_source(switch_::Switch *source) { source_ = source; }
void setup() override; void setup() override;
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
protected: protected:
void write_state(bool state) override; void write_state(bool state) override;

View File

@ -11,7 +11,6 @@ class CopyText : public text::Text, public Component {
void set_source(text::Text *source) { source_ = source; } void set_source(text::Text *source) { source_ = source; }
void setup() override; void setup() override;
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
protected: protected:
void control(const std::string &value) override; void control(const std::string &value) override;

View File

@ -11,7 +11,6 @@ class CopyTextSensor : public text_sensor::TextSensor, public Component {
void set_source(text_sensor::TextSensor *source) { source_ = source; } void set_source(text_sensor::TextSensor *source) { source_ = source; }
void setup() override; void setup() override;
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
protected: protected:
text_sensor::TextSensor *source_; text_sensor::TextSensor *source_;

View File

@ -77,7 +77,6 @@ class CS5460AComponent : public Component,
void setup() override; void setup() override;
void loop() override {} void loop() override {}
float get_setup_priority() const override { return setup_priority::DATA; }
void dump_config() override; void dump_config() override;
protected: protected:

View File

@ -19,7 +19,6 @@ class DutyTimeSensor : public sensor::Sensor, public PollingComponent {
void update() override; void update() override;
void loop() override; void loop() override;
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void start(); void start();
void stop(); void stop();

View File

@ -18,7 +18,6 @@ class ENS160Component : public PollingComponent, public sensor::Sensor {
void setup() override; void setup() override;
void update() override; void update() override;
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
protected: protected:
void send_env_data_(); void send_env_data_();

View File

@ -25,7 +25,6 @@ class ES7210 : public audio_adc::AudioAdc, public Component, public i2c::I2CDevi
*/ */
public: public:
void setup() override; void setup() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void dump_config() override; void dump_config() override;
void set_bits_per_sample(ES7210BitsPerSample bits_per_sample) { this->bits_per_sample_ = bits_per_sample; } void set_bits_per_sample(ES7210BitsPerSample bits_per_sample) { this->bits_per_sample_ = bits_per_sample; }

View File

@ -14,7 +14,6 @@ class ES7243E : public audio_adc::AudioAdc, public Component, public i2c::I2CDev
*/ */
public: public:
void setup() override; void setup() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void dump_config() override; void dump_config() override;
bool set_mic_gain(float mic_gain) override; bool set_mic_gain(float mic_gain) override;

View File

@ -14,7 +14,6 @@ class ES8156 : public audio_dac::AudioDac, public Component, public i2c::I2CDevi
///////////////////////// /////////////////////////
void setup() override; void setup() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void dump_config() override; void dump_config() override;
//////////////////////// ////////////////////////

View File

@ -50,7 +50,6 @@ class ES8311 : public audio_dac::AudioDac, public Component, public i2c::I2CDevi
///////////////////////// /////////////////////////
void setup() override; void setup() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void dump_config() override; void dump_config() override;
//////////////////////// ////////////////////////

View File

@ -38,7 +38,6 @@ class ES8388 : public audio_dac::AudioDac, public Component, public i2c::I2CDevi
///////////////////////// /////////////////////////
void setup() override; void setup() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void dump_config() override; void dump_config() override;
//////////////////////// ////////////////////////

View File

@ -341,6 +341,7 @@ SUPPORTED_PLATFORMIO_ESP_IDF_5X = [
# List based on https://github.com/pioarduino/esp-idf/releases # List based on https://github.com/pioarduino/esp-idf/releases
SUPPORTED_PIOARDUINO_ESP_IDF_5X = [ SUPPORTED_PIOARDUINO_ESP_IDF_5X = [
cv.Version(5, 5, 0), cv.Version(5, 5, 0),
cv.Version(5, 4, 2),
cv.Version(5, 4, 1), cv.Version(5, 4, 1),
cv.Version(5, 4, 0), cv.Version(5, 4, 0),
cv.Version(5, 3, 3), cv.Version(5, 3, 3),
@ -758,6 +759,9 @@ async def to_code(config):
add_idf_sdkconfig_option("CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0", False) add_idf_sdkconfig_option("CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0", False)
add_idf_sdkconfig_option("CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1", False) add_idf_sdkconfig_option("CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1", False)
# Disable dynamic log level control to save memory
add_idf_sdkconfig_option("CONFIG_LOG_DYNAMIC_LEVEL_CONTROL", False)
# Set default CPU frequency # Set default CPU frequency
add_idf_sdkconfig_option(f"CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_{freq}", True) add_idf_sdkconfig_option(f"CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_{freq}", True)

View File

@ -1,7 +1,6 @@
#ifdef USE_ESP32 #ifdef USE_ESP32
#include "ble.h" #include "ble.h"
#include "ble_event_pool.h"
#include "esphome/core/application.h" #include "esphome/core/application.h"
#include "esphome/core/helpers.h" #include "esphome/core/helpers.h"

View File

@ -12,8 +12,8 @@
#include "esphome/core/helpers.h" #include "esphome/core/helpers.h"
#include "ble_event.h" #include "ble_event.h"
#include "ble_event_pool.h" #include "esphome/core/lock_free_queue.h"
#include "queue.h" #include "esphome/core/event_pool.h"
#ifdef USE_ESP32 #ifdef USE_ESP32
@ -148,8 +148,8 @@ class ESP32BLE : public Component {
std::vector<BLEStatusEventHandler *> ble_status_event_handlers_; std::vector<BLEStatusEventHandler *> ble_status_event_handlers_;
BLEComponentState state_{BLE_COMPONENT_STATE_OFF}; BLEComponentState state_{BLE_COMPONENT_STATE_OFF};
LockFreeQueue<BLEEvent, MAX_BLE_QUEUE_SIZE> ble_events_; esphome::LockFreeQueue<BLEEvent, MAX_BLE_QUEUE_SIZE> ble_events_;
BLEEventPool<MAX_BLE_QUEUE_SIZE> ble_event_pool_; esphome::EventPool<BLEEvent, MAX_BLE_QUEUE_SIZE> ble_event_pool_;
BLEAdvertising *advertising_{}; BLEAdvertising *advertising_{};
esp_ble_io_cap_t io_cap_{ESP_IO_CAP_NONE}; esp_ble_io_cap_t io_cap_{ESP_IO_CAP_NONE};
uint32_t advertising_cycle_time_{}; uint32_t advertising_cycle_time_{};

View File

@ -134,13 +134,13 @@ class BLEEvent {
} }
// Destructor to clean up heap allocations // Destructor to clean up heap allocations
~BLEEvent() { this->cleanup_heap_data(); } ~BLEEvent() { this->release(); }
// Default constructor for pre-allocation in pool // Default constructor for pre-allocation in pool
BLEEvent() : type_(GAP) {} BLEEvent() : type_(GAP) {}
// Clean up any heap-allocated data // Invoked on return to EventPool - clean up any heap-allocated data
void cleanup_heap_data() { void release() {
if (this->type_ == GAP) { if (this->type_ == GAP) {
return; return;
} }
@ -161,19 +161,19 @@ class BLEEvent {
// Load new event data for reuse (replaces previous event data) // Load new event data for reuse (replaces previous event data)
void load_gap_event(esp_gap_ble_cb_event_t e, esp_ble_gap_cb_param_t *p) { void load_gap_event(esp_gap_ble_cb_event_t e, esp_ble_gap_cb_param_t *p) {
this->cleanup_heap_data(); this->release();
this->type_ = GAP; this->type_ = GAP;
this->init_gap_data_(e, p); this->init_gap_data_(e, p);
} }
void load_gattc_event(esp_gattc_cb_event_t e, esp_gatt_if_t i, esp_ble_gattc_cb_param_t *p) { void load_gattc_event(esp_gattc_cb_event_t e, esp_gatt_if_t i, esp_ble_gattc_cb_param_t *p) {
this->cleanup_heap_data(); this->release();
this->type_ = GATTC; this->type_ = GATTC;
this->init_gattc_data_(e, i, p); this->init_gattc_data_(e, i, p);
} }
void load_gatts_event(esp_gatts_cb_event_t e, esp_gatt_if_t i, esp_ble_gatts_cb_param_t *p) { void load_gatts_event(esp_gatts_cb_event_t e, esp_gatt_if_t i, esp_ble_gatts_cb_param_t *p) {
this->cleanup_heap_data(); this->release();
this->type_ = GATTS; this->type_ = GATTS;
this->init_gatts_data_(e, i, p); this->init_gatts_data_(e, i, p);
} }

View File

@ -1,72 +0,0 @@
#pragma once
#ifdef USE_ESP32
#include <atomic>
#include <cstddef>
#include "ble_event.h"
#include "queue.h"
#include "esphome/core/helpers.h"
namespace esphome {
namespace esp32_ble {
// BLE Event Pool - On-demand pool of BLEEvent objects to avoid heap fragmentation
// Events are allocated on first use and reused thereafter, growing to peak usage
template<uint8_t SIZE> class BLEEventPool {
public:
BLEEventPool() : total_created_(0) {}
~BLEEventPool() {
// Clean up any remaining events in the free list
BLEEvent *event;
while ((event = this->free_list_.pop()) != nullptr) {
delete event;
}
}
// Allocate an event from the pool
// Returns nullptr if pool is full
BLEEvent *allocate() {
// Try to get from free list first
BLEEvent *event = this->free_list_.pop();
if (event != nullptr)
return event;
// Need to create a new event
if (this->total_created_ >= SIZE) {
// Pool is at capacity
return nullptr;
}
// Use internal RAM for better performance
RAMAllocator<BLEEvent> allocator(RAMAllocator<BLEEvent>::ALLOC_INTERNAL);
event = allocator.allocate(1);
if (event == nullptr) {
// Memory allocation failed
return nullptr;
}
// Placement new to construct the object
new (event) BLEEvent();
this->total_created_++;
return event;
}
// Return an event to the pool for reuse
void release(BLEEvent *event) {
if (event != nullptr) {
this->free_list_.push(event);
}
}
private:
LockFreeQueue<BLEEvent, SIZE> free_list_; // Free events ready for reuse
uint8_t total_created_; // Total events created (high water mark)
};
} // namespace esp32_ble
} // namespace esphome
#endif

View File

@ -1,85 +0,0 @@
#pragma once
#ifdef USE_ESP32
#include <atomic>
#include <cstddef>
/*
* BLE events come in from a separate Task (thread) in the ESP32 stack. Rather
* than using mutex-based locking, this lock-free queue allows the BLE
* task to enqueue events without blocking. The main loop() then processes
* these events at a safer time.
*
* This is a Single-Producer Single-Consumer (SPSC) lock-free ring buffer.
* The BLE task is the only producer, and the main loop() is the only consumer.
*/
namespace esphome {
namespace esp32_ble {
template<class T, uint8_t SIZE> class LockFreeQueue {
public:
LockFreeQueue() : head_(0), tail_(0), dropped_count_(0) {}
bool push(T *element) {
if (element == nullptr)
return false;
uint8_t current_tail = tail_.load(std::memory_order_relaxed);
uint8_t next_tail = (current_tail + 1) % SIZE;
if (next_tail == head_.load(std::memory_order_acquire)) {
// Buffer full
dropped_count_.fetch_add(1, std::memory_order_relaxed);
return false;
}
buffer_[current_tail] = element;
tail_.store(next_tail, std::memory_order_release);
return true;
}
T *pop() {
uint8_t current_head = head_.load(std::memory_order_relaxed);
if (current_head == tail_.load(std::memory_order_acquire)) {
return nullptr; // Empty
}
T *element = buffer_[current_head];
head_.store((current_head + 1) % SIZE, std::memory_order_release);
return element;
}
size_t size() const {
uint8_t tail = tail_.load(std::memory_order_acquire);
uint8_t head = head_.load(std::memory_order_acquire);
return (tail - head + SIZE) % SIZE;
}
uint16_t get_and_reset_dropped_count() { return dropped_count_.exchange(0, std::memory_order_relaxed); }
void increment_dropped_count() { dropped_count_.fetch_add(1, std::memory_order_relaxed); }
bool empty() const { return head_.load(std::memory_order_acquire) == tail_.load(std::memory_order_acquire); }
bool full() const {
uint8_t next_tail = (tail_.load(std::memory_order_relaxed) + 1) % SIZE;
return next_tail == head_.load(std::memory_order_acquire);
}
protected:
T *buffer_[SIZE];
// Atomic: written by producer (push/increment), read+reset by consumer (get_and_reset)
std::atomic<uint16_t> dropped_count_; // 65535 max - more than enough for drop tracking
// Atomic: written by consumer (pop), read by producer (push) to check if full
std::atomic<uint8_t> head_;
// Atomic: written by producer (push), read by consumer (pop) to check if empty
std::atomic<uint8_t> tail_;
};
} // namespace esp32_ble
} // namespace esphome
#endif

View File

@ -52,7 +52,6 @@ class ESP32TouchComponent : public Component {
void setup() override; void setup() override;
void dump_config() override; void dump_config() override;
void loop() override; void loop() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void on_shutdown() override; void on_shutdown() override;

View File

@ -38,7 +38,6 @@ class EZOSensor : public sensor::Sensor, public PollingComponent, public i2c::I2
void loop() override; void loop() override;
void dump_config() override; void dump_config() override;
void update() override; void update() override;
float get_setup_priority() const override { return setup_priority::DATA; };
// I2C // I2C
void set_address(uint8_t address); void set_address(uint8_t address);

View File

@ -23,7 +23,6 @@ namespace ezo_pmp {
class EzoPMP : public PollingComponent, public i2c::I2CDevice { class EzoPMP : public PollingComponent, public i2c::I2CDevice {
public: public:
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; };
void loop() override; void loop() override;
void update() override; void update() override;

View File

@ -16,7 +16,6 @@ class FeedbackCover : public cover::Cover, public Component {
void setup() override; void setup() override;
void loop() override; void loop() override;
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; };
Trigger<> *get_open_trigger() const { return this->open_trigger_; } Trigger<> *get_open_trigger() const { return this->open_trigger_; }
Trigger<> *get_close_trigger() const { return this->close_trigger_; } Trigger<> *get_close_trigger() const { return this->close_trigger_; }

View File

@ -18,7 +18,6 @@ class FS3000Component : public PollingComponent, public i2c::I2CDevice, public s
void update() override; void update() override;
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void set_model(FS3000Model model) { this->model_ = model; } void set_model(FS3000Model model) { this->model_ = model; }

View File

@ -12,7 +12,6 @@ class GCJA5Component : public Component, public uart::UARTDevice {
public: public:
void dump_config() override; void dump_config() override;
void loop() override; void loop() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void set_pm_1_0_sensor(sensor::Sensor *pm_1_0) { pm_1_0_sensor_ = pm_1_0; } void set_pm_1_0_sensor(sensor::Sensor *pm_1_0) { pm_1_0_sensor_ = pm_1_0; }
void set_pm_2_5_sensor(sensor::Sensor *pm_2_5) { pm_2_5_sensor_ = pm_2_5; } void set_pm_2_5_sensor(sensor::Sensor *pm_2_5) { pm_2_5_sensor_ = pm_2_5; }

View File

@ -15,7 +15,6 @@ class GP8403 : public Component, public i2c::I2CDevice {
public: public:
void setup() override; void setup() override;
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void set_voltage(gp8403::GP8403Voltage voltage) { this->voltage_ = voltage; } void set_voltage(gp8403::GP8403Voltage voltage) { this->voltage_ = voltage; }

View File

@ -10,11 +10,24 @@ GPIOBinarySensor = gpio_ns.class_(
"GPIOBinarySensor", binary_sensor.BinarySensor, cg.Component "GPIOBinarySensor", binary_sensor.BinarySensor, cg.Component
) )
CONF_USE_INTERRUPT = "use_interrupt"
CONF_INTERRUPT_TYPE = "interrupt_type"
INTERRUPT_TYPES = {
"RISING": gpio_ns.INTERRUPT_RISING_EDGE,
"FALLING": gpio_ns.INTERRUPT_FALLING_EDGE,
"ANY": gpio_ns.INTERRUPT_ANY_EDGE,
}
CONFIG_SCHEMA = ( CONFIG_SCHEMA = (
binary_sensor.binary_sensor_schema(GPIOBinarySensor) binary_sensor.binary_sensor_schema(GPIOBinarySensor)
.extend( .extend(
{ {
cv.Required(CONF_PIN): pins.gpio_input_pin_schema, cv.Required(CONF_PIN): pins.gpio_input_pin_schema,
cv.Optional(CONF_USE_INTERRUPT, default=True): cv.boolean,
cv.Optional(CONF_INTERRUPT_TYPE, default="ANY"): cv.enum(
INTERRUPT_TYPES, upper=True
),
} }
) )
.extend(cv.COMPONENT_SCHEMA) .extend(cv.COMPONENT_SCHEMA)
@ -27,3 +40,7 @@ async def to_code(config):
pin = await cg.gpio_pin_expression(config[CONF_PIN]) pin = await cg.gpio_pin_expression(config[CONF_PIN])
cg.add(var.set_pin(pin)) cg.add(var.set_pin(pin))
cg.add(var.set_use_interrupt(config[CONF_USE_INTERRUPT]))
if config[CONF_USE_INTERRUPT]:
cg.add(var.set_interrupt_type(config[CONF_INTERRUPT_TYPE]))

View File

@ -6,17 +6,91 @@ namespace gpio {
static const char *const TAG = "gpio.binary_sensor"; static const char *const TAG = "gpio.binary_sensor";
void IRAM_ATTR GPIOBinarySensorStore::gpio_intr(GPIOBinarySensorStore *arg) {
bool new_state = arg->isr_pin_.digital_read();
if (new_state != arg->last_state_) {
arg->state_ = new_state;
arg->last_state_ = new_state;
arg->changed_ = true;
// Wake up the component from its disabled loop state
if (arg->component_ != nullptr) {
arg->component_->enable_loop_soon_any_context();
}
}
}
void GPIOBinarySensorStore::setup(InternalGPIOPin *pin, gpio::InterruptType type, Component *component) {
pin->setup();
this->isr_pin_ = pin->to_isr();
this->component_ = component;
// Read initial state
this->last_state_ = pin->digital_read();
this->state_ = this->last_state_;
// Attach interrupt - from this point on, any changes will be caught by the interrupt
pin->attach_interrupt(&GPIOBinarySensorStore::gpio_intr, this, type);
}
void GPIOBinarySensor::setup() { void GPIOBinarySensor::setup() {
this->pin_->setup(); if (this->use_interrupt_ && !this->pin_->is_internal()) {
this->publish_initial_state(this->pin_->digital_read()); ESP_LOGD(TAG, "GPIO is not internal, falling back to polling mode");
this->use_interrupt_ = false;
}
if (this->use_interrupt_) {
auto *internal_pin = static_cast<InternalGPIOPin *>(this->pin_);
this->store_.setup(internal_pin, this->interrupt_type_, this);
this->publish_initial_state(this->store_.get_state());
} else {
this->pin_->setup();
this->publish_initial_state(this->pin_->digital_read());
}
} }
void GPIOBinarySensor::dump_config() { void GPIOBinarySensor::dump_config() {
LOG_BINARY_SENSOR("", "GPIO Binary Sensor", this); LOG_BINARY_SENSOR("", "GPIO Binary Sensor", this);
LOG_PIN(" Pin: ", this->pin_); LOG_PIN(" Pin: ", this->pin_);
const char *mode = this->use_interrupt_ ? "interrupt" : "polling";
ESP_LOGCONFIG(TAG, " Mode: %s", mode);
if (this->use_interrupt_) {
const char *interrupt_type;
switch (this->interrupt_type_) {
case gpio::INTERRUPT_RISING_EDGE:
interrupt_type = "RISING_EDGE";
break;
case gpio::INTERRUPT_FALLING_EDGE:
interrupt_type = "FALLING_EDGE";
break;
case gpio::INTERRUPT_ANY_EDGE:
interrupt_type = "ANY_EDGE";
break;
default:
interrupt_type = "UNKNOWN";
break;
}
ESP_LOGCONFIG(TAG, " Interrupt Type: %s", interrupt_type);
}
} }
void GPIOBinarySensor::loop() { this->publish_state(this->pin_->digital_read()); } void GPIOBinarySensor::loop() {
if (this->use_interrupt_) {
if (this->store_.is_changed()) {
// Clear the flag immediately to minimize the window where we might miss changes
this->store_.clear_changed();
// Read the state and publish it
// Note: If the ISR fires between clear_changed() and get_state(), that's fine -
// we'll process the new change on the next loop iteration
bool state = this->store_.get_state();
this->publish_state(state);
} else {
// No changes, disable the loop until the next interrupt
this->disable_loop();
}
} else {
this->publish_state(this->pin_->digital_read());
}
}
float GPIOBinarySensor::get_setup_priority() const { return setup_priority::HARDWARE; } float GPIOBinarySensor::get_setup_priority() const { return setup_priority::HARDWARE; }

View File

@ -2,14 +2,51 @@
#include "esphome/core/component.h" #include "esphome/core/component.h"
#include "esphome/core/hal.h" #include "esphome/core/hal.h"
#include "esphome/core/helpers.h"
#include "esphome/components/binary_sensor/binary_sensor.h" #include "esphome/components/binary_sensor/binary_sensor.h"
namespace esphome { namespace esphome {
namespace gpio { namespace gpio {
// Store class for ISR data (no vtables, ISR-safe)
class GPIOBinarySensorStore {
public:
void setup(InternalGPIOPin *pin, gpio::InterruptType type, Component *component);
static void gpio_intr(GPIOBinarySensorStore *arg);
bool get_state() const {
// No lock needed: state_ is atomically updated by ISR
// Volatile ensures we read the latest value
return this->state_;
}
bool is_changed() const {
// Simple read of volatile bool - no clearing here
return this->changed_;
}
void clear_changed() {
// Separate method to clear the flag
this->changed_ = false;
}
protected:
ISRInternalGPIOPin isr_pin_;
volatile bool state_{false};
volatile bool last_state_{false};
volatile bool changed_{false};
Component *component_{nullptr}; // Pointer to the component for enable_loop_soon_any_context()
};
class GPIOBinarySensor : public binary_sensor::BinarySensor, public Component { class GPIOBinarySensor : public binary_sensor::BinarySensor, public Component {
public: public:
// No destructor needed: ESPHome components are created at boot and live forever.
// Interrupts are only detached on reboot when memory is cleared anyway.
void set_pin(GPIOPin *pin) { pin_ = pin; } void set_pin(GPIOPin *pin) { pin_ = pin; }
void set_use_interrupt(bool use_interrupt) { use_interrupt_ = use_interrupt; }
void set_interrupt_type(gpio::InterruptType type) { interrupt_type_ = type; }
// ========== INTERNAL METHODS ========== // ========== INTERNAL METHODS ==========
// (In most use cases you won't need these) // (In most use cases you won't need these)
/// Setup pin /// Setup pin
@ -22,6 +59,9 @@ class GPIOBinarySensor : public binary_sensor::BinarySensor, public Component {
protected: protected:
GPIOPin *pin_; GPIOPin *pin_;
bool use_interrupt_{true};
gpio::InterruptType interrupt_type_{gpio::INTERRUPT_ANY_EDGE};
GPIOBinarySensorStore store_;
}; };
} // namespace gpio } // namespace gpio

View File

@ -22,8 +22,6 @@ class GroveGasMultichannelV2Component : public PollingComponent, public i2c::I2C
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
protected: protected:
enum ErrorCode { enum ErrorCode {
UNKNOWN, UNKNOWN,

View File

@ -13,7 +13,6 @@ class HE60rCover : public cover::Cover, public Component, public uart::UARTDevic
void setup() override; void setup() override;
void loop() override; void loop() override;
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; };
void set_open_duration(uint32_t duration) { this->open_duration_ = duration; } void set_open_duration(uint32_t duration) { this->open_duration_ = duration; }
void set_close_duration(uint32_t duration) { this->close_duration_ = duration; } void set_close_duration(uint32_t duration) { this->close_duration_ = duration; }

View File

@ -18,7 +18,6 @@ class HONEYWELLABP2Sensor : public PollingComponent, public i2c::I2CDevice {
void set_temperature_sensor(sensor::Sensor *temperature_sensor) { this->temperature_sensor_ = temperature_sensor; }; void set_temperature_sensor(sensor::Sensor *temperature_sensor) { this->temperature_sensor_ = temperature_sensor; };
void loop() override; void loop() override;
void update() override; void update() override;
float get_setup_priority() const override { return setup_priority::DATA; };
void dump_config() override; void dump_config() override;
void read_sensor_data(); void read_sensor_data();

View File

@ -1,5 +1,8 @@
import logging
from esphome import pins from esphome import pins
import esphome.codegen as cg import esphome.codegen as cg
from esphome.components import esp32
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import ( from esphome.const import (
CONF_ADDRESS, CONF_ADDRESS,
@ -12,6 +15,8 @@ from esphome.const import (
CONF_SCL, CONF_SCL,
CONF_SDA, CONF_SDA,
CONF_TIMEOUT, CONF_TIMEOUT,
KEY_CORE,
KEY_FRAMEWORK_VERSION,
PLATFORM_ESP32, PLATFORM_ESP32,
PLATFORM_ESP8266, PLATFORM_ESP8266,
PLATFORM_RP2040, PLATFORM_RP2040,
@ -19,6 +24,7 @@ from esphome.const import (
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, coroutine_with_priority
import esphome.final_validate as fv import esphome.final_validate as fv
LOGGER = logging.getLogger(__name__)
CODEOWNERS = ["@esphome/core"] CODEOWNERS = ["@esphome/core"]
i2c_ns = cg.esphome_ns.namespace("i2c") i2c_ns = cg.esphome_ns.namespace("i2c")
I2CBus = i2c_ns.class_("I2CBus") I2CBus = i2c_ns.class_("I2CBus")
@ -41,6 +47,32 @@ def _bus_declare_type(value):
raise NotImplementedError raise NotImplementedError
def validate_config(config):
if (
config[CONF_SCAN]
and CORE.is_esp32
and CORE.using_esp_idf
and esp32.get_esp32_variant()
in [
esp32.const.VARIANT_ESP32C5,
esp32.const.VARIANT_ESP32C6,
esp32.const.VARIANT_ESP32P4,
]
):
version: cv.Version = CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION]
if version.major == 5 and (
(version.minor == 3 and version.patch <= 3)
or (version.minor == 4 and version.patch <= 1)
):
LOGGER.warning(
"There is a bug in esp-idf version %s that breaks I2C scan, I2C scan "
"has been disabled, see https://github.com/esphome/issues/issues/7128",
str(version),
)
config[CONF_SCAN] = False
return config
pin_with_input_and_output_support = pins.internal_gpio_pin_number( pin_with_input_and_output_support = pins.internal_gpio_pin_number(
{CONF_OUTPUT: True, CONF_INPUT: True} {CONF_OUTPUT: True, CONF_INPUT: True}
) )
@ -66,6 +98,7 @@ CONFIG_SCHEMA = cv.All(
} }
).extend(cv.COMPONENT_SCHEMA), ).extend(cv.COMPONENT_SCHEMA),
cv.only_on([PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_RP2040]), cv.only_on([PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_RP2040]),
validate_config,
) )

View File

@ -9,7 +9,6 @@ namespace i2c_device {
class I2CDeviceComponent : public Component, public i2c::I2CDevice { class I2CDeviceComponent : public Component, public i2c::I2CDevice {
public: public:
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
protected: protected:
}; };

View File

@ -16,8 +16,6 @@ class IAQCore : public PollingComponent, public i2c::I2CDevice {
void update() override; void update() override;
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
protected: protected:
sensor::Sensor *co2_{nullptr}; sensor::Sensor *co2_{nullptr};
sensor::Sensor *tvoc_{nullptr}; sensor::Sensor *tvoc_{nullptr};

View File

@ -13,8 +13,6 @@ class INA260Component : public PollingComponent, public i2c::I2CDevice {
void dump_config() override; void dump_config() override;
void update() override; void update() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void set_bus_voltage_sensor(sensor::Sensor *bus_voltage_sensor) { this->bus_voltage_sensor_ = bus_voltage_sensor; } void set_bus_voltage_sensor(sensor::Sensor *bus_voltage_sensor) { this->bus_voltage_sensor_ = bus_voltage_sensor; }
void set_current_sensor(sensor::Sensor *current_sensor) { this->current_sensor_ = current_sensor; } void set_current_sensor(sensor::Sensor *current_sensor) { this->current_sensor_ = current_sensor; }
void set_power_sensor(sensor::Sensor *power_sensor) { this->power_sensor_ = power_sensor; } void set_power_sensor(sensor::Sensor *power_sensor) { this->power_sensor_ = power_sensor; }

View File

@ -16,7 +16,6 @@ class InkbirdIbstH1Mini : public Component, public esp32_ble_tracker::ESPBTDevic
bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override; bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override;
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void set_temperature(sensor::Sensor *temperature) { temperature_ = temperature; } void set_temperature(sensor::Sensor *temperature) { temperature_ = temperature; }
void set_external_temperature(sensor::Sensor *external_temperature) { external_temperature_ = external_temperature; } void set_external_temperature(sensor::Sensor *external_temperature) { external_temperature_ = external_temperature; }
void set_humidity(sensor::Sensor *humidity) { humidity_ = humidity; } void set_humidity(sensor::Sensor *humidity) { humidity_ = humidity; }

View File

@ -27,7 +27,6 @@ class IntegrationSensor : public sensor::Sensor, public Component {
public: public:
void setup() override; void setup() override;
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void set_sensor(Sensor *sensor) { sensor_ = sensor; } void set_sensor(Sensor *sensor) { sensor_ = sensor; }
void set_time(IntegrationSensorTime time) { time_ = time; } void set_time(IntegrationSensorTime time) { time_ = time; }
void set_method(IntegrationMethod method) { method_ = method; } void set_method(IntegrationMethod method) { method_ = method; }

View File

@ -23,8 +23,6 @@ class IntervalTrigger : public Trigger<>, public PollingComponent {
void set_startup_delay(const uint32_t startup_delay) { this->startup_delay_ = startup_delay; } void set_startup_delay(const uint32_t startup_delay) { this->startup_delay_ = startup_delay; }
float get_setup_priority() const override { return setup_priority::DATA; }
protected: protected:
uint32_t startup_delay_{0}; uint32_t startup_delay_{0};
bool started_{false}; bool started_{false};

View File

@ -10,9 +10,11 @@ namespace libretiny {
static const char *const TAG = "lt.component"; static const char *const TAG = "lt.component";
void LTComponent::dump_config() { void LTComponent::dump_config() {
ESP_LOGCONFIG(TAG, "LibreTiny:"); ESP_LOGCONFIG(TAG,
ESP_LOGCONFIG(TAG, " Version: %s", LT_BANNER_STR + 10); "LibreTiny:\n"
ESP_LOGCONFIG(TAG, " Loglevel: %u", LT_LOGLEVEL); " Version: %s\n"
" Loglevel: %u",
LT_BANNER_STR + 10, LT_LOGLEVEL);
#ifdef USE_TEXT_SENSOR #ifdef USE_TEXT_SENSOR
if (this->version_ != nullptr) { if (this->version_ != nullptr) {

View File

@ -69,8 +69,8 @@ class ESPColorCorrection {
protected: protected:
uint8_t gamma_table_[256]; uint8_t gamma_table_[256];
uint8_t gamma_reverse_table_[256]; uint8_t gamma_reverse_table_[256];
Color max_brightness_;
uint8_t local_brightness_{255}; uint8_t local_brightness_{255};
Color max_brightness_;
}; };
} // namespace light } // namespace light

View File

@ -136,7 +136,7 @@ LightColorValues LightCall::validate_() {
// Color mode check // Color mode check
if (this->color_mode_.has_value() && !traits.supports_color_mode(this->color_mode_.value())) { if (this->color_mode_.has_value() && !traits.supports_color_mode(this->color_mode_.value())) {
ESP_LOGW(TAG, "'%s' - This light does not support color mode %s!", name, ESP_LOGW(TAG, "'%s' does not support color mode %s", name,
LOG_STR_ARG(color_mode_to_human(this->color_mode_.value()))); LOG_STR_ARG(color_mode_to_human(this->color_mode_.value())));
this->color_mode_.reset(); this->color_mode_.reset();
} }
@ -152,20 +152,20 @@ LightColorValues LightCall::validate_() {
// Brightness exists check // Brightness exists check
if (this->brightness_.has_value() && *this->brightness_ > 0.0f && !(color_mode & ColorCapability::BRIGHTNESS)) { if (this->brightness_.has_value() && *this->brightness_ > 0.0f && !(color_mode & ColorCapability::BRIGHTNESS)) {
ESP_LOGW(TAG, "'%s' - This light does not support setting brightness!", name); ESP_LOGW(TAG, "'%s': setting brightness not supported", name);
this->brightness_.reset(); this->brightness_.reset();
} }
// Transition length possible check // Transition length possible check
if (this->transition_length_.has_value() && *this->transition_length_ != 0 && if (this->transition_length_.has_value() && *this->transition_length_ != 0 &&
!(color_mode & ColorCapability::BRIGHTNESS)) { !(color_mode & ColorCapability::BRIGHTNESS)) {
ESP_LOGW(TAG, "'%s' - This light does not support transitions!", name); ESP_LOGW(TAG, "'%s': transitions not supported", name);
this->transition_length_.reset(); this->transition_length_.reset();
} }
// Color brightness exists check // Color brightness exists check
if (this->color_brightness_.has_value() && *this->color_brightness_ > 0.0f && !(color_mode & ColorCapability::RGB)) { if (this->color_brightness_.has_value() && *this->color_brightness_ > 0.0f && !(color_mode & ColorCapability::RGB)) {
ESP_LOGW(TAG, "'%s' - This color mode does not support setting RGB brightness!", name); ESP_LOGW(TAG, "'%s': color mode does not support setting RGB brightness", name);
this->color_brightness_.reset(); this->color_brightness_.reset();
} }
@ -173,7 +173,7 @@ LightColorValues LightCall::validate_() {
if ((this->red_.has_value() && *this->red_ > 0.0f) || (this->green_.has_value() && *this->green_ > 0.0f) || if ((this->red_.has_value() && *this->red_ > 0.0f) || (this->green_.has_value() && *this->green_ > 0.0f) ||
(this->blue_.has_value() && *this->blue_ > 0.0f)) { (this->blue_.has_value() && *this->blue_ > 0.0f)) {
if (!(color_mode & ColorCapability::RGB)) { if (!(color_mode & ColorCapability::RGB)) {
ESP_LOGW(TAG, "'%s' - This color mode does not support setting RGB color!", name); ESP_LOGW(TAG, "'%s': color mode does not support setting RGB color", name);
this->red_.reset(); this->red_.reset();
this->green_.reset(); this->green_.reset();
this->blue_.reset(); this->blue_.reset();
@ -183,14 +183,14 @@ LightColorValues LightCall::validate_() {
// White value exists check // White value exists check
if (this->white_.has_value() && *this->white_ > 0.0f && if (this->white_.has_value() && *this->white_ > 0.0f &&
!(color_mode & ColorCapability::WHITE || color_mode & ColorCapability::COLD_WARM_WHITE)) { !(color_mode & ColorCapability::WHITE || color_mode & ColorCapability::COLD_WARM_WHITE)) {
ESP_LOGW(TAG, "'%s' - This color mode does not support setting white value!", name); ESP_LOGW(TAG, "'%s': color mode does not support setting white value", name);
this->white_.reset(); this->white_.reset();
} }
// Color temperature exists check // Color temperature exists check
if (this->color_temperature_.has_value() && if (this->color_temperature_.has_value() &&
!(color_mode & ColorCapability::COLOR_TEMPERATURE || color_mode & ColorCapability::COLD_WARM_WHITE)) { !(color_mode & ColorCapability::COLOR_TEMPERATURE || color_mode & ColorCapability::COLD_WARM_WHITE)) {
ESP_LOGW(TAG, "'%s' - This color mode does not support setting color temperature!", name); ESP_LOGW(TAG, "'%s': color mode does not support setting color temperature", name);
this->color_temperature_.reset(); this->color_temperature_.reset();
} }
@ -198,7 +198,7 @@ LightColorValues LightCall::validate_() {
if ((this->cold_white_.has_value() && *this->cold_white_ > 0.0f) || if ((this->cold_white_.has_value() && *this->cold_white_ > 0.0f) ||
(this->warm_white_.has_value() && *this->warm_white_ > 0.0f)) { (this->warm_white_.has_value() && *this->warm_white_ > 0.0f)) {
if (!(color_mode & ColorCapability::COLD_WARM_WHITE)) { if (!(color_mode & ColorCapability::COLD_WARM_WHITE)) {
ESP_LOGW(TAG, "'%s' - This color mode does not support setting cold/warm white value!", name); ESP_LOGW(TAG, "'%s': color mode does not support setting cold/warm white value", name);
this->cold_white_.reset(); this->cold_white_.reset();
this->warm_white_.reset(); this->warm_white_.reset();
} }
@ -208,7 +208,7 @@ LightColorValues LightCall::validate_() {
if (name_##_.has_value()) { \ if (name_##_.has_value()) { \
auto val = *name_##_; \ auto val = *name_##_; \
if (val < (min) || val > (max)) { \ if (val < (min) || val > (max)) { \
ESP_LOGW(TAG, "'%s' - %s value %.2f is out of range [%.1f - %.1f]!", name, LOG_STR_LITERAL(upper_name), val, \ ESP_LOGW(TAG, "'%s': %s value %.2f is out of range [%.1f - %.1f]", name, LOG_STR_LITERAL(upper_name), val, \
(min), (max)); \ (min), (max)); \
name_##_ = clamp(val, (min), (max)); \ name_##_ = clamp(val, (min), (max)); \
} \ } \
@ -270,7 +270,7 @@ LightColorValues LightCall::validate_() {
// Flash length check // Flash length check
if (this->has_flash_() && *this->flash_length_ == 0) { if (this->has_flash_() && *this->flash_length_ == 0) {
ESP_LOGW(TAG, "'%s' - Flash length must be greater than zero!", name); ESP_LOGW(TAG, "'%s': flash length must be greater than zero", name);
this->flash_length_.reset(); this->flash_length_.reset();
} }
@ -284,18 +284,18 @@ LightColorValues LightCall::validate_() {
// validate effect index // validate effect index
if (this->has_effect_() && *this->effect_ > this->parent_->effects_.size()) { if (this->has_effect_() && *this->effect_ > this->parent_->effects_.size()) {
ESP_LOGW(TAG, "'%s' - Invalid effect index %" PRIu32 "!", name, *this->effect_); ESP_LOGW(TAG, "'%s': invalid effect index %" PRIu32, name, *this->effect_);
this->effect_.reset(); this->effect_.reset();
} }
if (this->has_effect_() && (this->has_transition_() || this->has_flash_())) { if (this->has_effect_() && (this->has_transition_() || this->has_flash_())) {
ESP_LOGW(TAG, "'%s' - Effect cannot be used together with transition/flash!", name); ESP_LOGW(TAG, "'%s': effect cannot be used with transition/flash", name);
this->transition_length_.reset(); this->transition_length_.reset();
this->flash_length_.reset(); this->flash_length_.reset();
} }
if (this->has_flash_() && this->has_transition_()) { if (this->has_flash_() && this->has_transition_()) {
ESP_LOGW(TAG, "'%s' - Flash cannot be used together with transition!", name); ESP_LOGW(TAG, "'%s': flash cannot be used with transition", name);
this->transition_length_.reset(); this->transition_length_.reset();
} }
@ -311,7 +311,7 @@ LightColorValues LightCall::validate_() {
} }
if (this->has_transition_() && !supports_transition) { if (this->has_transition_() && !supports_transition) {
ESP_LOGW(TAG, "'%s' - Light does not support transitions!", name); ESP_LOGW(TAG, "'%s': transitions not supported", name);
this->transition_length_.reset(); this->transition_length_.reset();
} }
@ -320,7 +320,7 @@ LightColorValues LightCall::validate_() {
// Reason: When user turns off the light in frontend, the effect should also stop // Reason: When user turns off the light in frontend, the effect should also stop
if (!this->has_flash_() && !this->state_.value_or(v.is_on())) { if (!this->has_flash_() && !this->state_.value_or(v.is_on())) {
if (this->has_effect_()) { if (this->has_effect_()) {
ESP_LOGW(TAG, "'%s' - Cannot start an effect when turning off!", name); ESP_LOGW(TAG, "'%s': cannot start effect when turning off", name);
this->effect_.reset(); this->effect_.reset();
} else if (this->parent_->active_effect_index_ != 0 && explicit_turn_off_request) { } else if (this->parent_->active_effect_index_ != 0 && explicit_turn_off_request) {
// Auto turn off effect // Auto turn off effect
@ -348,7 +348,7 @@ void LightCall::transform_parameters_() {
!(*this->color_mode_ & ColorCapability::WHITE) && // !(*this->color_mode_ & ColorCapability::WHITE) && //
!(*this->color_mode_ & ColorCapability::COLOR_TEMPERATURE) && // !(*this->color_mode_ & ColorCapability::COLOR_TEMPERATURE) && //
traits.get_min_mireds() > 0.0f && traits.get_max_mireds() > 0.0f) { traits.get_min_mireds() > 0.0f && traits.get_max_mireds() > 0.0f) {
ESP_LOGD(TAG, "'%s' - Setting cold/warm white channels using white/color temperature values.", ESP_LOGD(TAG, "'%s': setting cold/warm white channels using white/color temperature values",
this->parent_->get_name().c_str()); this->parent_->get_name().c_str());
if (this->color_temperature_.has_value()) { if (this->color_temperature_.has_value()) {
const float color_temp = clamp(*this->color_temperature_, traits.get_min_mireds(), traits.get_max_mireds()); const float color_temp = clamp(*this->color_temperature_, traits.get_min_mireds(), traits.get_max_mireds());
@ -388,8 +388,8 @@ ColorMode LightCall::compute_color_mode_() {
// Don't change if the current mode is suitable. // Don't change if the current mode is suitable.
if (suitable_modes.count(current_mode) > 0) { if (suitable_modes.count(current_mode) > 0) {
ESP_LOGI(TAG, "'%s' - Keeping current color mode %s for call without color mode.", ESP_LOGI(TAG, "'%s': color mode not specified; retaining %s", this->parent_->get_name().c_str(),
this->parent_->get_name().c_str(), LOG_STR_ARG(color_mode_to_human(current_mode))); LOG_STR_ARG(color_mode_to_human(current_mode)));
return current_mode; return current_mode;
} }
@ -398,7 +398,7 @@ ColorMode LightCall::compute_color_mode_() {
if (supported_modes.count(mode) == 0) if (supported_modes.count(mode) == 0)
continue; continue;
ESP_LOGI(TAG, "'%s' - Using color mode %s for call without color mode.", this->parent_->get_name().c_str(), ESP_LOGI(TAG, "'%s': color mode not specified; using %s", this->parent_->get_name().c_str(),
LOG_STR_ARG(color_mode_to_human(mode))); LOG_STR_ARG(color_mode_to_human(mode)));
return mode; return mode;
} }
@ -406,8 +406,8 @@ ColorMode LightCall::compute_color_mode_() {
// There's no supported mode for this call, so warn, use the current more or a mode at random and let validation strip // There's no supported mode for this call, so warn, use the current more or a mode at random and let validation strip
// out whatever we don't support. // out whatever we don't support.
auto color_mode = current_mode != ColorMode::UNKNOWN ? current_mode : *supported_modes.begin(); auto color_mode = current_mode != ColorMode::UNKNOWN ? current_mode : *supported_modes.begin();
ESP_LOGW(TAG, "'%s' - No color mode suitable for this call supported, defaulting to %s!", ESP_LOGW(TAG, "'%s': no suitable color mode supported; defaulting to %s", this->parent_->get_name().c_str(),
this->parent_->get_name().c_str(), LOG_STR_ARG(color_mode_to_human(color_mode))); LOG_STR_ARG(color_mode_to_human(color_mode)));
return color_mode; return color_mode;
} }
std::set<ColorMode> LightCall::get_suitable_color_modes_() { std::set<ColorMode> LightCall::get_suitable_color_modes_() {
@ -472,7 +472,7 @@ LightCall &LightCall::set_effect(const std::string &effect) {
} }
} }
if (!found) { if (!found) {
ESP_LOGW(TAG, "'%s' - No such effect '%s'", this->parent_->get_name().c_str(), effect.c_str()); ESP_LOGW(TAG, "'%s': no such effect '%s'", this->parent_->get_name().c_str(), effect.c_str());
} }
return *this; return *this;
} }

View File

@ -225,6 +225,11 @@ class LightState : public EntityBase, public Component {
/// Gamma correction factor for the light. /// Gamma correction factor for the light.
float gamma_correct_{}; float gamma_correct_{};
/// Whether the light value should be written in the next cycle.
bool next_write_{true};
// for effects, true if a transformer (transition) is active.
bool is_transformer_active_ = false;
/// Object used to store the persisted values of the light. /// Object used to store the persisted values of the light.
ESPPreferenceObject rtc_; ESPPreferenceObject rtc_;
@ -247,10 +252,6 @@ class LightState : public EntityBase, public Component {
/// Restore mode of the light. /// Restore mode of the light.
LightRestoreMode restore_mode_; LightRestoreMode restore_mode_;
/// Whether the light value should be written in the next cycle.
bool next_write_{true};
// for effects, true if a transformer (transition) is active.
bool is_transformer_active_ = false;
}; };
} // namespace light } // namespace light

View File

@ -44,7 +44,6 @@ enum LTR390RESOLUTION {
class LTR390Component : public PollingComponent, public i2c::I2CDevice { class LTR390Component : public PollingComponent, public i2c::I2CDevice {
public: public:
float get_setup_priority() const override { return setup_priority::DATA; }
void setup() override; void setup() override;
void dump_config() override; void dump_config() override;
void update() override; void update() override;

View File

@ -25,7 +25,6 @@ class LTRAlsPs501Component : public PollingComponent, public i2c::I2CDevice {
// //
// EspHome framework functions // EspHome framework functions
// //
float get_setup_priority() const override { return setup_priority::DATA; }
void setup() override; void setup() override;
void dump_config() override; void dump_config() override;
void update() override; void update() override;

View File

@ -25,7 +25,6 @@ class LTRAlsPsComponent : public PollingComponent, public i2c::I2CDevice {
// //
// EspHome framework functions // EspHome framework functions
// //
float get_setup_priority() const override { return setup_priority::DATA; }
void setup() override; void setup() override;
void dump_config() override; void dump_config() override;
void update() override; void update() override;

View File

@ -38,7 +38,6 @@ class MAX9611Component : public PollingComponent, public i2c::I2CDevice {
public: public:
void setup() override; void setup() override;
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void update() override; void update() override;
void set_voltage_sensor(sensor::Sensor *vs) { voltage_sensor_ = vs; } void set_voltage_sensor(sensor::Sensor *vs) { voltage_sensor_ = vs; }
void set_current_sensor(sensor::Sensor *cs) { current_sensor_ = cs; } void set_current_sensor(sensor::Sensor *cs) { current_sensor_ = cs; }

View File

@ -6,7 +6,11 @@ namespace mcp23xxx_base {
float MCP23XXXBase::get_setup_priority() const { return setup_priority::IO; } float MCP23XXXBase::get_setup_priority() const { return setup_priority::IO; }
void MCP23XXXGPIOPin::setup() { pin_mode(flags_); } void MCP23XXXGPIOPin::setup() {
pin_mode(flags_);
this->parent_->pin_interrupt_mode(this->pin_, this->interrupt_mode_);
}
void MCP23XXXGPIOPin::pin_mode(gpio::Flags flags) { this->parent_->pin_mode(this->pin_, flags); } void MCP23XXXGPIOPin::pin_mode(gpio::Flags flags) { this->parent_->pin_mode(this->pin_, flags); }
bool MCP23XXXGPIOPin::digital_read() { return this->parent_->digital_read(this->pin_) != this->inverted_; } bool MCP23XXXGPIOPin::digital_read() { return this->parent_->digital_read(this->pin_) != this->inverted_; }
void MCP23XXXGPIOPin::digital_write(bool value) { this->parent_->digital_write(this->pin_, value != this->inverted_); } void MCP23XXXGPIOPin::digital_write(bool value) { this->parent_->digital_write(this->pin_, value != this->inverted_); }

View File

@ -24,8 +24,6 @@ class MCP9600Component : public PollingComponent, public i2c::I2CDevice {
void dump_config() override; void dump_config() override;
void update() override; void update() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void set_hot_junction(sensor::Sensor *hot_junction) { this->hot_junction_sensor_ = hot_junction; } void set_hot_junction(sensor::Sensor *hot_junction) { this->hot_junction_sensor_ = hot_junction; }
void set_cold_junction(sensor::Sensor *cold_junction) { this->cold_junction_sensor_ = cold_junction; } void set_cold_junction(sensor::Sensor *cold_junction) { this->cold_junction_sensor_ = cold_junction; }
void set_thermocouple_type(MCP9600ThermocoupleType thermocouple_type) { void set_thermocouple_type(MCP9600ThermocoupleType thermocouple_type) {

View File

@ -34,7 +34,6 @@ class MopekaProCheck : public Component, public esp32_ble_tracker::ESPBTDeviceLi
bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override; bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override;
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void set_min_signal_quality(SensorReadQuality min) { this->min_signal_quality_ = min; }; void set_min_signal_quality(SensorReadQuality min) { this->min_signal_quality_ = min; };
void set_level(sensor::Sensor *level) { level_ = level; }; void set_level(sensor::Sensor *level) { level_ = level; };

View File

@ -48,7 +48,6 @@ class MopekaStdCheck : public Component, public esp32_ble_tracker::ESPBTDeviceLi
bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override; bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override;
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void set_level(sensor::Sensor *level) { this->level_ = level; }; void set_level(sensor::Sensor *level) { this->level_ = level; };
void set_temperature(sensor::Sensor *temperature) { this->temperature_ = temperature; }; void set_temperature(sensor::Sensor *temperature) { this->temperature_ = temperature; };

Some files were not shown because too many files have changed in this diff Show More