mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 15:12:06 +00:00 
			
		
		
		
	Merge branch 'dev' into update_libsodium
This commit is contained in:
		| @@ -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 | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
| @@ -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); | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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); | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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}; | ||||||
|   | |||||||
| @@ -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. | ||||||
|   | |||||||
| @@ -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); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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. | ||||||
|    * |    * | ||||||
|   | |||||||
| @@ -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; | ||||||
|   | |||||||
| @@ -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; } | ||||||
|   | |||||||
| @@ -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; } | ||||||
|   | |||||||
| @@ -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; } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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; } | ||||||
|   | |||||||
| @@ -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); | ||||||
|   | |||||||
| @@ -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,7 +136,9 @@ 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, []): | ||||||
|  |         cg.add_define("USE_API_YAML_SERVICES") | ||||||
|  |         for conf in actions: | ||||||
|             template_args = [] |             template_args = [] | ||||||
|             func_args = [] |             func_args = [] | ||||||
|             service_arg_names = [] |             service_arg_names = [] | ||||||
| @@ -152,6 +155,7 @@ async def to_code(config): | |||||||
|             await automation.build_automation(trigger, func_args, conf) |             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")], | ||||||
|   | |||||||
| @@ -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) { | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
| @@ -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) { | ||||||
|   | |||||||
| @@ -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 { | ||||||
|   | |||||||
| @@ -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); | ||||||
|   | |||||||
| @@ -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); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -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>(); | ||||||
|   | |||||||
| @@ -4,7 +4,13 @@ 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 | ||||||
|  |  | ||||||
|  | # Suppress protobuf version warnings | ||||||
|  | with warnings.catch_warnings(): | ||||||
|  |     warnings.filterwarnings( | ||||||
|  |         "ignore", category=UserWarning, message=".*Protobuf gencode version.*" | ||||||
|  |     ) | ||||||
|     from aioesphomeapi import APIClient, parse_log_message |     from aioesphomeapi import APIClient, parse_log_message | ||||||
|     from aioesphomeapi.log_runner import async_run |     from aioesphomeapi.log_runner import async_run | ||||||
|  |  | ||||||
| @@ -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, | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
| @@ -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; } | ||||||
|   | |||||||
| @@ -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) { | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
| @@ -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; } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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; } | ||||||
|   | |||||||
| @@ -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; } | ||||||
|   | |||||||
| @@ -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; } | ||||||
|   | |||||||
| @@ -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); } | ||||||
|   | |||||||
| @@ -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; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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); } | ||||||
|   | |||||||
| @@ -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; | ||||||
|   | |||||||
| @@ -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); } | ||||||
|   | |||||||
| @@ -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) { | ||||||
|   | |||||||
| @@ -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 }; | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
| @@ -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; | ||||||
|   | |||||||
| @@ -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: | ||||||
|   | |||||||
| @@ -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; } | ||||||
|   | |||||||
| @@ -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_; | ||||||
|   | |||||||
| @@ -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; | ||||||
|   | |||||||
| @@ -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; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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; | ||||||
|   | |||||||
| @@ -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; | ||||||
|   | |||||||
| @@ -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; | ||||||
|   | |||||||
| @@ -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_; | ||||||
|   | |||||||
| @@ -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; | ||||||
|   | |||||||
| @@ -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; | ||||||
|   | |||||||
| @@ -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_; | ||||||
|   | |||||||
| @@ -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: | ||||||
|   | |||||||
| @@ -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(); | ||||||
|   | |||||||
| @@ -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_(); | ||||||
|   | |||||||
| @@ -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; } | ||||||
|   | |||||||
| @@ -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; | ||||||
|   | |||||||
| @@ -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; | ||||||
|  |  | ||||||
|   //////////////////////// |   //////////////////////// | ||||||
|   | |||||||
| @@ -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; | ||||||
|  |  | ||||||
|   //////////////////////// |   //////////////////////// | ||||||
|   | |||||||
| @@ -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; | ||||||
|  |  | ||||||
|   //////////////////////// |   //////////////////////// | ||||||
|   | |||||||
| @@ -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) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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" | ||||||
|   | |||||||
| @@ -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_{}; | ||||||
|   | |||||||
| @@ -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); | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -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 |  | ||||||
| @@ -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 |  | ||||||
| @@ -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; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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); | ||||||
|   | |||||||
| @@ -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; | ||||||
|   | |||||||
| @@ -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_; } | ||||||
|   | |||||||
| @@ -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; } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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; } | ||||||
|   | |||||||
| @@ -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; } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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])) | ||||||
|   | |||||||
| @@ -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() { | ||||||
|  |   if (this->use_interrupt_ && !this->pin_->is_internal()) { | ||||||
|  |     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->pin_->setup(); | ||||||
|     this->publish_initial_state(this->pin_->digital_read()); |     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; } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
| @@ -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, | ||||||
|   | |||||||
| @@ -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; } | ||||||
|   | |||||||
| @@ -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(); | ||||||
|   | |||||||
| @@ -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, | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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: | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -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}; | ||||||
|   | |||||||
| @@ -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; } | ||||||
|   | |||||||
| @@ -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; } | ||||||
|   | |||||||
| @@ -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; } | ||||||
|   | |||||||
| @@ -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}; | ||||||
|   | |||||||
| @@ -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) { | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
| @@ -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; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
| @@ -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; | ||||||
|   | |||||||
| @@ -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; | ||||||
|   | |||||||
| @@ -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; | ||||||
|   | |||||||
| @@ -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; } | ||||||
|   | |||||||
| @@ -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_); } | ||||||
|   | |||||||
| @@ -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) { | ||||||
|   | |||||||
| @@ -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; }; | ||||||
|   | |||||||
| @@ -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
		Reference in New Issue
	
	Block a user