diff --git a/CODEOWNERS b/CODEOWNERS index 652f24dbe2..1d9b0efe91 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -125,6 +125,7 @@ esphome/components/dht/* @OttoWinter esphome/components/display_menu_base/* @numo68 esphome/components/dps310/* @kbx81 esphome/components/ds1307/* @badbadc0ffee +esphome/components/ds2484/* @mrk-its esphome/components/dsmr/* @glmnet @zuidwijk esphome/components/duty_time/* @dudanov esphome/components/ee895/* @Stock-M @@ -499,6 +500,7 @@ esphome/components/voice_assistant/* @jesserockz @kahrendt esphome/components/wake_on_lan/* @clydebarrow @willwill2will54 esphome/components/watchdog/* @oarcher esphome/components/waveshare_epaper/* @clydebarrow +esphome/components/web_server/ota/* @esphome/core esphome/components/web_server_base/* @OttoWinter esphome/components/web_server_idf/* @dentra esphome/components/weikai/* @DrCoolZic diff --git a/esphome/components/adc/adc_sensor.h b/esphome/components/adc/adc_sensor.h index 9ffb6cf856..28dfd2262c 100644 --- a/esphome/components/adc/adc_sensor.h +++ b/esphome/components/adc/adc_sensor.h @@ -15,8 +15,7 @@ namespace adc { #ifdef USE_ESP32 // clang-format off -#if (ESP_IDF_VERSION_MAJOR == 4 && ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 7)) || \ - (ESP_IDF_VERSION_MAJOR == 5 && \ +#if (ESP_IDF_VERSION_MAJOR == 5 && \ ((ESP_IDF_VERSION_MINOR == 0 && ESP_IDF_VERSION_PATCH >= 5) || \ (ESP_IDF_VERSION_MINOR == 1 && ESP_IDF_VERSION_PATCH >= 3) || \ (ESP_IDF_VERSION_MINOR >= 2)) \ @@ -100,11 +99,7 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage adc1_channel_t channel1_{ADC1_CHANNEL_MAX}; adc2_channel_t channel2_{ADC2_CHANNEL_MAX}; bool autorange_{false}; -#if ESP_IDF_VERSION_MAJOR >= 5 esp_adc_cal_characteristics_t cal_characteristics_[SOC_ADC_ATTEN_NUM] = {}; -#else - esp_adc_cal_characteristics_t cal_characteristics_[ADC_ATTEN_MAX] = {}; -#endif // ESP_IDF_VERSION_MAJOR #endif // USE_ESP32 }; diff --git a/esphome/components/api/__init__.py b/esphome/components/api/__init__.py index b02a875d72..2f1be28293 100644 --- a/esphome/components/api/__init__.py +++ b/esphome/components/api/__init__.py @@ -132,7 +132,9 @@ async def to_code(config): await cg.register_component(var, config) cg.add(var.set_port(config[CONF_PORT])) - cg.add(var.set_password(config[CONF_PASSWORD])) + if config[CONF_PASSWORD]: + cg.add_define("USE_API_PASSWORD") + cg.add(var.set_password(config[CONF_PASSWORD])) cg.add(var.set_reboot_timeout(config[CONF_REBOOT_TIMEOUT])) cg.add(var.set_batch_delay(config[CONF_BATCH_DELAY])) diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index 9bf1f2b0c6..bde29c6dc0 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -1508,7 +1508,10 @@ HelloResponse APIConnection::hello(const HelloRequest &msg) { return resp; } ConnectResponse APIConnection::connect(const ConnectRequest &msg) { - bool correct = this->parent_->check_password(msg.password); + bool correct = true; +#ifdef USE_API_PASSWORD + correct = this->parent_->check_password(msg.password); +#endif ConnectResponse resp; // bool invalid_password = 1; @@ -1529,7 +1532,11 @@ ConnectResponse APIConnection::connect(const ConnectRequest &msg) { } DeviceInfoResponse APIConnection::device_info(const DeviceInfoRequest &msg) { DeviceInfoResponse resp{}; +#ifdef USE_API_PASSWORD resp.uses_password = this->parent_->uses_password(); +#else + resp.uses_password = false; +#endif resp.name = App.get_name(); resp.friendly_name = App.get_friendly_name(); resp.suggested_area = App.get_area(); @@ -1692,7 +1699,9 @@ void APIConnection::DeferredBatch::add_item(EntityBase *entity, MessageCreator c // O(n) but optimized for RAM and not performance. for (auto &item : items) { if (item.entity == entity && item.message_type == message_type) { - // Update the existing item with the new creator + // Clean up old creator before replacing + item.creator.cleanup(message_type); + // Move assign the new creator item.creator = std::move(creator); return; } @@ -1735,11 +1744,11 @@ void APIConnection::process_batch_() { return; } - size_t num_items = this->deferred_batch_.items.size(); + size_t num_items = this->deferred_batch_.size(); // Fast path for single message - allocate exact size needed if (num_items == 1) { - const auto &item = this->deferred_batch_.items[0]; + const auto &item = this->deferred_batch_[0]; // Let the creator calculate size and encode if it fits uint16_t payload_size = @@ -1769,7 +1778,8 @@ void APIConnection::process_batch_() { // Pre-calculate exact buffer size needed based on message types uint32_t total_estimated_size = 0; - for (const auto &item : this->deferred_batch_.items) { + for (size_t i = 0; i < this->deferred_batch_.size(); i++) { + const auto &item = this->deferred_batch_[i]; total_estimated_size += get_estimated_message_size(item.message_type); } @@ -1790,7 +1800,8 @@ void APIConnection::process_batch_() { uint32_t current_offset = 0; // Process items and encode directly to buffer - for (const auto &item : this->deferred_batch_.items) { + for (size_t i = 0; i < this->deferred_batch_.size(); i++) { + const auto &item = this->deferred_batch_[i]; // Try to encode message // The creator will calculate overhead to determine if the message fits uint16_t payload_size = item.creator(item.entity, this, remaining_size, false, item.message_type); @@ -1845,17 +1856,15 @@ void APIConnection::process_batch_() { // 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]; + const auto &item = this->deferred_batch_[i]; this->log_batch_item_(item); } #endif // Handle remaining items more efficiently - if (items_processed < this->deferred_batch_.items.size()) { - // Remove processed items from the beginning - this->deferred_batch_.items.erase(this->deferred_batch_.items.begin(), - this->deferred_batch_.items.begin() + items_processed); - + if (items_processed < this->deferred_batch_.size()) { + // Remove processed items from the beginning with proper cleanup + this->deferred_batch_.remove_front(items_processed); // Reschedule for remaining items this->schedule_batch_(); } else { @@ -1866,23 +1875,16 @@ void APIConnection::process_batch_() { uint16_t APIConnection::MessageCreator::operator()(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, bool is_single, uint16_t message_type) const { - if (has_tagged_string_ptr_()) { - // Handle string-based messages - switch (message_type) { #ifdef USE_EVENT - case EventResponse::MESSAGE_TYPE: { - auto *e = static_cast(entity); - return APIConnection::try_send_event_response(e, *get_string_ptr_(), conn, remaining_size, is_single); - } -#endif - default: - // Should not happen, return 0 to indicate no message - return 0; - } - } else { - // Function pointer case - return data_.ptr(entity, conn, remaining_size, is_single); + // Special case: EventResponse uses string pointer + if (message_type == EventResponse::MESSAGE_TYPE) { + auto *e = static_cast(entity); + return APIConnection::try_send_event_response(e, *data_.string_ptr, conn, remaining_size, is_single); } +#endif + + // All other message types use function pointers + return data_.function_ptr(entity, conn, remaining_size, is_single); } uint16_t APIConnection::try_send_list_info_done(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, diff --git a/esphome/components/api/api_connection.h b/esphome/components/api/api_connection.h index 8f0671f390..08c88b172e 100644 --- a/esphome/components/api/api_connection.h +++ b/esphome/components/api/api_connection.h @@ -451,96 +451,53 @@ class APIConnection : public APIServerConnection { // Function pointer type for message encoding using MessageCreatorPtr = uint16_t (*)(EntityBase *, APIConnection *, uint32_t remaining_size, bool is_single); - // Optimized MessageCreator class using tagged pointer class MessageCreator { - // Ensure pointer alignment allows LSB tagging - static_assert(alignof(std::string *) > 1, "String pointer alignment must be > 1 for LSB tagging"); - public: // Constructor for function pointer - MessageCreator(MessageCreatorPtr ptr) { - // Function pointers are always aligned, so LSB is 0 - data_.ptr = ptr; - } + MessageCreator(MessageCreatorPtr ptr) { data_.function_ptr = ptr; } // Constructor for string state capture - explicit MessageCreator(const std::string &str_value) { - // Allocate string and tag the pointer - auto *str = new std::string(str_value); - // Set LSB to 1 to indicate string pointer - data_.tagged = reinterpret_cast(str) | 1; - } + explicit MessageCreator(const std::string &str_value) { data_.string_ptr = new std::string(str_value); } - // Destructor - ~MessageCreator() { - if (has_tagged_string_ptr_()) { - delete get_string_ptr_(); - } - } + // No destructor - cleanup must be called explicitly with message_type - // Copy constructor - MessageCreator(const MessageCreator &other) { - if (other.has_tagged_string_ptr_()) { - auto *str = new std::string(*other.get_string_ptr_()); - data_.tagged = reinterpret_cast(str) | 1; - } else { - data_ = other.data_; - } - } + // Delete copy operations - MessageCreator should only be moved + MessageCreator(const MessageCreator &other) = delete; + MessageCreator &operator=(const MessageCreator &other) = delete; // Move constructor - MessageCreator(MessageCreator &&other) noexcept : data_(other.data_) { other.data_.ptr = nullptr; } - - // Assignment operators (needed for batch deduplication) - MessageCreator &operator=(const MessageCreator &other) { - if (this != &other) { - // Clean up current string data if needed - if (has_tagged_string_ptr_()) { - delete get_string_ptr_(); - } - // Copy new data - if (other.has_tagged_string_ptr_()) { - auto *str = new std::string(*other.get_string_ptr_()); - data_.tagged = reinterpret_cast(str) | 1; - } else { - data_ = other.data_; - } - } - return *this; - } + MessageCreator(MessageCreator &&other) noexcept : data_(other.data_) { other.data_.function_ptr = nullptr; } + // Move assignment MessageCreator &operator=(MessageCreator &&other) noexcept { if (this != &other) { - // Clean up current string data if needed - if (has_tagged_string_ptr_()) { - delete get_string_ptr_(); - } - // Move data + // IMPORTANT: Caller must ensure cleanup() was called if this contains a string! + // In our usage, this happens in add_item() deduplication and vector::erase() data_ = other.data_; - // Reset other to safe state - other.data_.ptr = nullptr; + other.data_.function_ptr = nullptr; } return *this; } - // Call operator - now accepts message_type as parameter + // Call operator - uses message_type to determine union type uint16_t operator()(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, bool is_single, uint16_t message_type) const; - private: - // Check if this contains a string pointer - bool has_tagged_string_ptr_() const { return (data_.tagged & 1) != 0; } - - // Get the actual string pointer (clears the tag bit) - std::string *get_string_ptr_() const { - // NOLINTNEXTLINE(performance-no-int-to-ptr) - return reinterpret_cast(data_.tagged & ~uintptr_t(1)); + // Manual cleanup method - must be called before destruction for string types + void cleanup(uint16_t message_type) { +#ifdef USE_EVENT + if (message_type == EventResponse::MESSAGE_TYPE && data_.string_ptr != nullptr) { + delete data_.string_ptr; + data_.string_ptr = nullptr; + } +#endif } - union { - MessageCreatorPtr ptr; - uintptr_t tagged; - } data_; // 4 bytes on 32-bit + private: + union Data { + MessageCreatorPtr function_ptr; + std::string *string_ptr; + } data_; // 4 bytes on 32-bit, 8 bytes on 64-bit - same as before }; // Generic batching mechanism for both state updates and entity info @@ -558,20 +515,46 @@ class APIConnection : public APIServerConnection { std::vector items; uint32_t batch_start_time{0}; + private: + // Helper to cleanup items from the beginning + void cleanup_items_(size_t count) { + for (size_t i = 0; i < count; i++) { + items[i].creator.cleanup(items[i].message_type); + } + } + + public: DeferredBatch() { // Pre-allocate capacity for typical batch sizes to avoid reallocation items.reserve(8); } + ~DeferredBatch() { + // Ensure cleanup of any remaining items + clear(); + } + // Add item to the batch 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); + + // Clear all items with proper cleanup void clear() { + cleanup_items_(items.size()); items.clear(); batch_start_time = 0; } + + // Remove processed items from the front with proper cleanup + void remove_front(size_t count) { + cleanup_items_(count); + items.erase(items.begin(), items.begin() + count); + } + bool empty() const { return items.empty(); } + size_t size() const { return items.size(); } + const BatchItem &operator[](size_t index) const { return items[index]; } }; // DeferredBatch here (16 bytes, 4-byte aligned) diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index 9793565ee5..01140fbfc8 100644 --- a/esphome/components/api/api_pb2.cpp +++ b/esphome/components/api/api_pb2.cpp @@ -3,634 +3,11 @@ #include "api_pb2.h" #include "api_pb2_size.h" #include "esphome/core/log.h" - -#include +#include "esphome/core/helpers.h" namespace esphome { namespace api { -#ifdef HAS_PROTO_MESSAGE_DUMP -template<> const char *proto_enum_to_string(enums::EntityCategory value) { - switch (value) { - case enums::ENTITY_CATEGORY_NONE: - return "ENTITY_CATEGORY_NONE"; - case enums::ENTITY_CATEGORY_CONFIG: - return "ENTITY_CATEGORY_CONFIG"; - case enums::ENTITY_CATEGORY_DIAGNOSTIC: - return "ENTITY_CATEGORY_DIAGNOSTIC"; - default: - return "UNKNOWN"; - } -} -#endif -#ifdef HAS_PROTO_MESSAGE_DUMP -template<> const char *proto_enum_to_string(enums::LegacyCoverState value) { - switch (value) { - case enums::LEGACY_COVER_STATE_OPEN: - return "LEGACY_COVER_STATE_OPEN"; - case enums::LEGACY_COVER_STATE_CLOSED: - return "LEGACY_COVER_STATE_CLOSED"; - default: - return "UNKNOWN"; - } -} -#endif -#ifdef HAS_PROTO_MESSAGE_DUMP -template<> const char *proto_enum_to_string(enums::CoverOperation value) { - switch (value) { - case enums::COVER_OPERATION_IDLE: - return "COVER_OPERATION_IDLE"; - case enums::COVER_OPERATION_IS_OPENING: - return "COVER_OPERATION_IS_OPENING"; - case enums::COVER_OPERATION_IS_CLOSING: - return "COVER_OPERATION_IS_CLOSING"; - default: - return "UNKNOWN"; - } -} -#endif -#ifdef HAS_PROTO_MESSAGE_DUMP -template<> const char *proto_enum_to_string(enums::LegacyCoverCommand value) { - switch (value) { - case enums::LEGACY_COVER_COMMAND_OPEN: - return "LEGACY_COVER_COMMAND_OPEN"; - case enums::LEGACY_COVER_COMMAND_CLOSE: - return "LEGACY_COVER_COMMAND_CLOSE"; - case enums::LEGACY_COVER_COMMAND_STOP: - return "LEGACY_COVER_COMMAND_STOP"; - default: - return "UNKNOWN"; - } -} -#endif -#ifdef HAS_PROTO_MESSAGE_DUMP -template<> const char *proto_enum_to_string(enums::FanSpeed value) { - switch (value) { - case enums::FAN_SPEED_LOW: - return "FAN_SPEED_LOW"; - case enums::FAN_SPEED_MEDIUM: - return "FAN_SPEED_MEDIUM"; - case enums::FAN_SPEED_HIGH: - return "FAN_SPEED_HIGH"; - default: - return "UNKNOWN"; - } -} -#endif -#ifdef HAS_PROTO_MESSAGE_DUMP -template<> const char *proto_enum_to_string(enums::FanDirection value) { - switch (value) { - case enums::FAN_DIRECTION_FORWARD: - return "FAN_DIRECTION_FORWARD"; - case enums::FAN_DIRECTION_REVERSE: - return "FAN_DIRECTION_REVERSE"; - default: - return "UNKNOWN"; - } -} -#endif -#ifdef HAS_PROTO_MESSAGE_DUMP -template<> const char *proto_enum_to_string(enums::ColorMode value) { - switch (value) { - case enums::COLOR_MODE_UNKNOWN: - return "COLOR_MODE_UNKNOWN"; - case enums::COLOR_MODE_ON_OFF: - return "COLOR_MODE_ON_OFF"; - case enums::COLOR_MODE_LEGACY_BRIGHTNESS: - return "COLOR_MODE_LEGACY_BRIGHTNESS"; - case enums::COLOR_MODE_BRIGHTNESS: - return "COLOR_MODE_BRIGHTNESS"; - case enums::COLOR_MODE_WHITE: - return "COLOR_MODE_WHITE"; - case enums::COLOR_MODE_COLOR_TEMPERATURE: - return "COLOR_MODE_COLOR_TEMPERATURE"; - case enums::COLOR_MODE_COLD_WARM_WHITE: - return "COLOR_MODE_COLD_WARM_WHITE"; - case enums::COLOR_MODE_RGB: - return "COLOR_MODE_RGB"; - case enums::COLOR_MODE_RGB_WHITE: - return "COLOR_MODE_RGB_WHITE"; - case enums::COLOR_MODE_RGB_COLOR_TEMPERATURE: - return "COLOR_MODE_RGB_COLOR_TEMPERATURE"; - case enums::COLOR_MODE_RGB_COLD_WARM_WHITE: - return "COLOR_MODE_RGB_COLD_WARM_WHITE"; - default: - return "UNKNOWN"; - } -} -#endif -#ifdef HAS_PROTO_MESSAGE_DUMP -template<> const char *proto_enum_to_string(enums::SensorStateClass value) { - switch (value) { - case enums::STATE_CLASS_NONE: - return "STATE_CLASS_NONE"; - case enums::STATE_CLASS_MEASUREMENT: - return "STATE_CLASS_MEASUREMENT"; - case enums::STATE_CLASS_TOTAL_INCREASING: - return "STATE_CLASS_TOTAL_INCREASING"; - case enums::STATE_CLASS_TOTAL: - return "STATE_CLASS_TOTAL"; - default: - return "UNKNOWN"; - } -} -#endif -#ifdef HAS_PROTO_MESSAGE_DUMP -template<> const char *proto_enum_to_string(enums::SensorLastResetType value) { - switch (value) { - case enums::LAST_RESET_NONE: - return "LAST_RESET_NONE"; - case enums::LAST_RESET_NEVER: - return "LAST_RESET_NEVER"; - case enums::LAST_RESET_AUTO: - return "LAST_RESET_AUTO"; - default: - return "UNKNOWN"; - } -} -#endif -#ifdef HAS_PROTO_MESSAGE_DUMP -template<> const char *proto_enum_to_string(enums::LogLevel value) { - switch (value) { - case enums::LOG_LEVEL_NONE: - return "LOG_LEVEL_NONE"; - case enums::LOG_LEVEL_ERROR: - return "LOG_LEVEL_ERROR"; - case enums::LOG_LEVEL_WARN: - return "LOG_LEVEL_WARN"; - case enums::LOG_LEVEL_INFO: - return "LOG_LEVEL_INFO"; - case enums::LOG_LEVEL_CONFIG: - return "LOG_LEVEL_CONFIG"; - case enums::LOG_LEVEL_DEBUG: - return "LOG_LEVEL_DEBUG"; - case enums::LOG_LEVEL_VERBOSE: - return "LOG_LEVEL_VERBOSE"; - case enums::LOG_LEVEL_VERY_VERBOSE: - return "LOG_LEVEL_VERY_VERBOSE"; - default: - return "UNKNOWN"; - } -} -#endif -#ifdef HAS_PROTO_MESSAGE_DUMP -template<> const char *proto_enum_to_string(enums::ServiceArgType value) { - switch (value) { - case enums::SERVICE_ARG_TYPE_BOOL: - return "SERVICE_ARG_TYPE_BOOL"; - case enums::SERVICE_ARG_TYPE_INT: - return "SERVICE_ARG_TYPE_INT"; - case enums::SERVICE_ARG_TYPE_FLOAT: - return "SERVICE_ARG_TYPE_FLOAT"; - case enums::SERVICE_ARG_TYPE_STRING: - return "SERVICE_ARG_TYPE_STRING"; - case enums::SERVICE_ARG_TYPE_BOOL_ARRAY: - return "SERVICE_ARG_TYPE_BOOL_ARRAY"; - case enums::SERVICE_ARG_TYPE_INT_ARRAY: - return "SERVICE_ARG_TYPE_INT_ARRAY"; - case enums::SERVICE_ARG_TYPE_FLOAT_ARRAY: - return "SERVICE_ARG_TYPE_FLOAT_ARRAY"; - case enums::SERVICE_ARG_TYPE_STRING_ARRAY: - return "SERVICE_ARG_TYPE_STRING_ARRAY"; - default: - return "UNKNOWN"; - } -} -#endif -#ifdef HAS_PROTO_MESSAGE_DUMP -template<> const char *proto_enum_to_string(enums::ClimateMode value) { - switch (value) { - case enums::CLIMATE_MODE_OFF: - return "CLIMATE_MODE_OFF"; - case enums::CLIMATE_MODE_HEAT_COOL: - return "CLIMATE_MODE_HEAT_COOL"; - case enums::CLIMATE_MODE_COOL: - return "CLIMATE_MODE_COOL"; - case enums::CLIMATE_MODE_HEAT: - return "CLIMATE_MODE_HEAT"; - case enums::CLIMATE_MODE_FAN_ONLY: - return "CLIMATE_MODE_FAN_ONLY"; - case enums::CLIMATE_MODE_DRY: - return "CLIMATE_MODE_DRY"; - case enums::CLIMATE_MODE_AUTO: - return "CLIMATE_MODE_AUTO"; - default: - return "UNKNOWN"; - } -} -#endif -#ifdef HAS_PROTO_MESSAGE_DUMP -template<> const char *proto_enum_to_string(enums::ClimateFanMode value) { - switch (value) { - case enums::CLIMATE_FAN_ON: - return "CLIMATE_FAN_ON"; - case enums::CLIMATE_FAN_OFF: - return "CLIMATE_FAN_OFF"; - case enums::CLIMATE_FAN_AUTO: - return "CLIMATE_FAN_AUTO"; - case enums::CLIMATE_FAN_LOW: - return "CLIMATE_FAN_LOW"; - case enums::CLIMATE_FAN_MEDIUM: - return "CLIMATE_FAN_MEDIUM"; - case enums::CLIMATE_FAN_HIGH: - return "CLIMATE_FAN_HIGH"; - case enums::CLIMATE_FAN_MIDDLE: - return "CLIMATE_FAN_MIDDLE"; - case enums::CLIMATE_FAN_FOCUS: - return "CLIMATE_FAN_FOCUS"; - case enums::CLIMATE_FAN_DIFFUSE: - return "CLIMATE_FAN_DIFFUSE"; - case enums::CLIMATE_FAN_QUIET: - return "CLIMATE_FAN_QUIET"; - default: - return "UNKNOWN"; - } -} -#endif -#ifdef HAS_PROTO_MESSAGE_DUMP -template<> const char *proto_enum_to_string(enums::ClimateSwingMode value) { - switch (value) { - case enums::CLIMATE_SWING_OFF: - return "CLIMATE_SWING_OFF"; - case enums::CLIMATE_SWING_BOTH: - return "CLIMATE_SWING_BOTH"; - case enums::CLIMATE_SWING_VERTICAL: - return "CLIMATE_SWING_VERTICAL"; - case enums::CLIMATE_SWING_HORIZONTAL: - return "CLIMATE_SWING_HORIZONTAL"; - default: - return "UNKNOWN"; - } -} -#endif -#ifdef HAS_PROTO_MESSAGE_DUMP -template<> const char *proto_enum_to_string(enums::ClimateAction value) { - switch (value) { - case enums::CLIMATE_ACTION_OFF: - return "CLIMATE_ACTION_OFF"; - case enums::CLIMATE_ACTION_COOLING: - return "CLIMATE_ACTION_COOLING"; - case enums::CLIMATE_ACTION_HEATING: - return "CLIMATE_ACTION_HEATING"; - case enums::CLIMATE_ACTION_IDLE: - return "CLIMATE_ACTION_IDLE"; - case enums::CLIMATE_ACTION_DRYING: - return "CLIMATE_ACTION_DRYING"; - case enums::CLIMATE_ACTION_FAN: - return "CLIMATE_ACTION_FAN"; - default: - return "UNKNOWN"; - } -} -#endif -#ifdef HAS_PROTO_MESSAGE_DUMP -template<> const char *proto_enum_to_string(enums::ClimatePreset value) { - switch (value) { - case enums::CLIMATE_PRESET_NONE: - return "CLIMATE_PRESET_NONE"; - case enums::CLIMATE_PRESET_HOME: - return "CLIMATE_PRESET_HOME"; - case enums::CLIMATE_PRESET_AWAY: - return "CLIMATE_PRESET_AWAY"; - case enums::CLIMATE_PRESET_BOOST: - return "CLIMATE_PRESET_BOOST"; - case enums::CLIMATE_PRESET_COMFORT: - return "CLIMATE_PRESET_COMFORT"; - case enums::CLIMATE_PRESET_ECO: - return "CLIMATE_PRESET_ECO"; - case enums::CLIMATE_PRESET_SLEEP: - return "CLIMATE_PRESET_SLEEP"; - case enums::CLIMATE_PRESET_ACTIVITY: - return "CLIMATE_PRESET_ACTIVITY"; - default: - return "UNKNOWN"; - } -} -#endif -#ifdef HAS_PROTO_MESSAGE_DUMP -template<> const char *proto_enum_to_string(enums::NumberMode value) { - switch (value) { - case enums::NUMBER_MODE_AUTO: - return "NUMBER_MODE_AUTO"; - case enums::NUMBER_MODE_BOX: - return "NUMBER_MODE_BOX"; - case enums::NUMBER_MODE_SLIDER: - return "NUMBER_MODE_SLIDER"; - default: - return "UNKNOWN"; - } -} -#endif -#ifdef HAS_PROTO_MESSAGE_DUMP -template<> const char *proto_enum_to_string(enums::LockState value) { - switch (value) { - case enums::LOCK_STATE_NONE: - return "LOCK_STATE_NONE"; - case enums::LOCK_STATE_LOCKED: - return "LOCK_STATE_LOCKED"; - case enums::LOCK_STATE_UNLOCKED: - return "LOCK_STATE_UNLOCKED"; - case enums::LOCK_STATE_JAMMED: - return "LOCK_STATE_JAMMED"; - case enums::LOCK_STATE_LOCKING: - return "LOCK_STATE_LOCKING"; - case enums::LOCK_STATE_UNLOCKING: - return "LOCK_STATE_UNLOCKING"; - default: - return "UNKNOWN"; - } -} -#endif -#ifdef HAS_PROTO_MESSAGE_DUMP -template<> const char *proto_enum_to_string(enums::LockCommand value) { - switch (value) { - case enums::LOCK_UNLOCK: - return "LOCK_UNLOCK"; - case enums::LOCK_LOCK: - return "LOCK_LOCK"; - case enums::LOCK_OPEN: - return "LOCK_OPEN"; - default: - return "UNKNOWN"; - } -} -#endif -#ifdef HAS_PROTO_MESSAGE_DUMP -template<> const char *proto_enum_to_string(enums::MediaPlayerState value) { - switch (value) { - case enums::MEDIA_PLAYER_STATE_NONE: - return "MEDIA_PLAYER_STATE_NONE"; - case enums::MEDIA_PLAYER_STATE_IDLE: - return "MEDIA_PLAYER_STATE_IDLE"; - case enums::MEDIA_PLAYER_STATE_PLAYING: - return "MEDIA_PLAYER_STATE_PLAYING"; - case enums::MEDIA_PLAYER_STATE_PAUSED: - return "MEDIA_PLAYER_STATE_PAUSED"; - default: - return "UNKNOWN"; - } -} -#endif -#ifdef HAS_PROTO_MESSAGE_DUMP -template<> const char *proto_enum_to_string(enums::MediaPlayerCommand value) { - switch (value) { - case enums::MEDIA_PLAYER_COMMAND_PLAY: - return "MEDIA_PLAYER_COMMAND_PLAY"; - case enums::MEDIA_PLAYER_COMMAND_PAUSE: - return "MEDIA_PLAYER_COMMAND_PAUSE"; - case enums::MEDIA_PLAYER_COMMAND_STOP: - return "MEDIA_PLAYER_COMMAND_STOP"; - case enums::MEDIA_PLAYER_COMMAND_MUTE: - return "MEDIA_PLAYER_COMMAND_MUTE"; - case enums::MEDIA_PLAYER_COMMAND_UNMUTE: - return "MEDIA_PLAYER_COMMAND_UNMUTE"; - default: - return "UNKNOWN"; - } -} -#endif -#ifdef HAS_PROTO_MESSAGE_DUMP -template<> const char *proto_enum_to_string(enums::MediaPlayerFormatPurpose value) { - switch (value) { - case enums::MEDIA_PLAYER_FORMAT_PURPOSE_DEFAULT: - return "MEDIA_PLAYER_FORMAT_PURPOSE_DEFAULT"; - case enums::MEDIA_PLAYER_FORMAT_PURPOSE_ANNOUNCEMENT: - return "MEDIA_PLAYER_FORMAT_PURPOSE_ANNOUNCEMENT"; - default: - return "UNKNOWN"; - } -} -#endif -#ifdef HAS_PROTO_MESSAGE_DUMP -template<> -const char *proto_enum_to_string(enums::BluetoothDeviceRequestType value) { - switch (value) { - case enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT: - return "BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT"; - case enums::BLUETOOTH_DEVICE_REQUEST_TYPE_DISCONNECT: - return "BLUETOOTH_DEVICE_REQUEST_TYPE_DISCONNECT"; - case enums::BLUETOOTH_DEVICE_REQUEST_TYPE_PAIR: - return "BLUETOOTH_DEVICE_REQUEST_TYPE_PAIR"; - case enums::BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR: - return "BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR"; - case enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE: - return "BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE"; - case enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE: - return "BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE"; - case enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CLEAR_CACHE: - return "BLUETOOTH_DEVICE_REQUEST_TYPE_CLEAR_CACHE"; - default: - return "UNKNOWN"; - } -} -#endif -#ifdef HAS_PROTO_MESSAGE_DUMP -template<> const char *proto_enum_to_string(enums::BluetoothScannerState value) { - switch (value) { - case enums::BLUETOOTH_SCANNER_STATE_IDLE: - return "BLUETOOTH_SCANNER_STATE_IDLE"; - case enums::BLUETOOTH_SCANNER_STATE_STARTING: - return "BLUETOOTH_SCANNER_STATE_STARTING"; - case enums::BLUETOOTH_SCANNER_STATE_RUNNING: - return "BLUETOOTH_SCANNER_STATE_RUNNING"; - case enums::BLUETOOTH_SCANNER_STATE_FAILED: - return "BLUETOOTH_SCANNER_STATE_FAILED"; - case enums::BLUETOOTH_SCANNER_STATE_STOPPING: - return "BLUETOOTH_SCANNER_STATE_STOPPING"; - case enums::BLUETOOTH_SCANNER_STATE_STOPPED: - return "BLUETOOTH_SCANNER_STATE_STOPPED"; - default: - return "UNKNOWN"; - } -} -#endif -#ifdef HAS_PROTO_MESSAGE_DUMP -template<> const char *proto_enum_to_string(enums::BluetoothScannerMode value) { - switch (value) { - case enums::BLUETOOTH_SCANNER_MODE_PASSIVE: - return "BLUETOOTH_SCANNER_MODE_PASSIVE"; - case enums::BLUETOOTH_SCANNER_MODE_ACTIVE: - return "BLUETOOTH_SCANNER_MODE_ACTIVE"; - default: - return "UNKNOWN"; - } -} -#endif -#ifdef HAS_PROTO_MESSAGE_DUMP -template<> -const char *proto_enum_to_string(enums::VoiceAssistantSubscribeFlag value) { - switch (value) { - case enums::VOICE_ASSISTANT_SUBSCRIBE_NONE: - return "VOICE_ASSISTANT_SUBSCRIBE_NONE"; - case enums::VOICE_ASSISTANT_SUBSCRIBE_API_AUDIO: - return "VOICE_ASSISTANT_SUBSCRIBE_API_AUDIO"; - default: - return "UNKNOWN"; - } -} -#endif -#ifdef HAS_PROTO_MESSAGE_DUMP -template<> const char *proto_enum_to_string(enums::VoiceAssistantRequestFlag value) { - switch (value) { - case enums::VOICE_ASSISTANT_REQUEST_NONE: - return "VOICE_ASSISTANT_REQUEST_NONE"; - case enums::VOICE_ASSISTANT_REQUEST_USE_VAD: - return "VOICE_ASSISTANT_REQUEST_USE_VAD"; - case enums::VOICE_ASSISTANT_REQUEST_USE_WAKE_WORD: - return "VOICE_ASSISTANT_REQUEST_USE_WAKE_WORD"; - default: - return "UNKNOWN"; - } -} -#endif -#ifdef HAS_PROTO_MESSAGE_DUMP -template<> const char *proto_enum_to_string(enums::VoiceAssistantEvent value) { - switch (value) { - case enums::VOICE_ASSISTANT_ERROR: - return "VOICE_ASSISTANT_ERROR"; - case enums::VOICE_ASSISTANT_RUN_START: - return "VOICE_ASSISTANT_RUN_START"; - case enums::VOICE_ASSISTANT_RUN_END: - return "VOICE_ASSISTANT_RUN_END"; - case enums::VOICE_ASSISTANT_STT_START: - return "VOICE_ASSISTANT_STT_START"; - case enums::VOICE_ASSISTANT_STT_END: - return "VOICE_ASSISTANT_STT_END"; - case enums::VOICE_ASSISTANT_INTENT_START: - return "VOICE_ASSISTANT_INTENT_START"; - case enums::VOICE_ASSISTANT_INTENT_END: - return "VOICE_ASSISTANT_INTENT_END"; - case enums::VOICE_ASSISTANT_TTS_START: - return "VOICE_ASSISTANT_TTS_START"; - case enums::VOICE_ASSISTANT_TTS_END: - return "VOICE_ASSISTANT_TTS_END"; - case enums::VOICE_ASSISTANT_WAKE_WORD_START: - return "VOICE_ASSISTANT_WAKE_WORD_START"; - case enums::VOICE_ASSISTANT_WAKE_WORD_END: - return "VOICE_ASSISTANT_WAKE_WORD_END"; - case enums::VOICE_ASSISTANT_STT_VAD_START: - return "VOICE_ASSISTANT_STT_VAD_START"; - case enums::VOICE_ASSISTANT_STT_VAD_END: - return "VOICE_ASSISTANT_STT_VAD_END"; - case enums::VOICE_ASSISTANT_TTS_STREAM_START: - return "VOICE_ASSISTANT_TTS_STREAM_START"; - case enums::VOICE_ASSISTANT_TTS_STREAM_END: - return "VOICE_ASSISTANT_TTS_STREAM_END"; - case enums::VOICE_ASSISTANT_INTENT_PROGRESS: - return "VOICE_ASSISTANT_INTENT_PROGRESS"; - default: - return "UNKNOWN"; - } -} -#endif -#ifdef HAS_PROTO_MESSAGE_DUMP -template<> const char *proto_enum_to_string(enums::VoiceAssistantTimerEvent value) { - switch (value) { - case enums::VOICE_ASSISTANT_TIMER_STARTED: - return "VOICE_ASSISTANT_TIMER_STARTED"; - case enums::VOICE_ASSISTANT_TIMER_UPDATED: - return "VOICE_ASSISTANT_TIMER_UPDATED"; - case enums::VOICE_ASSISTANT_TIMER_CANCELLED: - return "VOICE_ASSISTANT_TIMER_CANCELLED"; - case enums::VOICE_ASSISTANT_TIMER_FINISHED: - return "VOICE_ASSISTANT_TIMER_FINISHED"; - default: - return "UNKNOWN"; - } -} -#endif -#ifdef HAS_PROTO_MESSAGE_DUMP -template<> const char *proto_enum_to_string(enums::AlarmControlPanelState value) { - switch (value) { - case enums::ALARM_STATE_DISARMED: - return "ALARM_STATE_DISARMED"; - case enums::ALARM_STATE_ARMED_HOME: - return "ALARM_STATE_ARMED_HOME"; - case enums::ALARM_STATE_ARMED_AWAY: - return "ALARM_STATE_ARMED_AWAY"; - case enums::ALARM_STATE_ARMED_NIGHT: - return "ALARM_STATE_ARMED_NIGHT"; - case enums::ALARM_STATE_ARMED_VACATION: - return "ALARM_STATE_ARMED_VACATION"; - case enums::ALARM_STATE_ARMED_CUSTOM_BYPASS: - return "ALARM_STATE_ARMED_CUSTOM_BYPASS"; - case enums::ALARM_STATE_PENDING: - return "ALARM_STATE_PENDING"; - case enums::ALARM_STATE_ARMING: - return "ALARM_STATE_ARMING"; - case enums::ALARM_STATE_DISARMING: - return "ALARM_STATE_DISARMING"; - case enums::ALARM_STATE_TRIGGERED: - return "ALARM_STATE_TRIGGERED"; - default: - return "UNKNOWN"; - } -} -#endif -#ifdef HAS_PROTO_MESSAGE_DUMP -template<> -const char *proto_enum_to_string(enums::AlarmControlPanelStateCommand value) { - switch (value) { - case enums::ALARM_CONTROL_PANEL_DISARM: - return "ALARM_CONTROL_PANEL_DISARM"; - case enums::ALARM_CONTROL_PANEL_ARM_AWAY: - return "ALARM_CONTROL_PANEL_ARM_AWAY"; - case enums::ALARM_CONTROL_PANEL_ARM_HOME: - return "ALARM_CONTROL_PANEL_ARM_HOME"; - case enums::ALARM_CONTROL_PANEL_ARM_NIGHT: - return "ALARM_CONTROL_PANEL_ARM_NIGHT"; - case enums::ALARM_CONTROL_PANEL_ARM_VACATION: - return "ALARM_CONTROL_PANEL_ARM_VACATION"; - case enums::ALARM_CONTROL_PANEL_ARM_CUSTOM_BYPASS: - return "ALARM_CONTROL_PANEL_ARM_CUSTOM_BYPASS"; - case enums::ALARM_CONTROL_PANEL_TRIGGER: - return "ALARM_CONTROL_PANEL_TRIGGER"; - default: - return "UNKNOWN"; - } -} -#endif -#ifdef HAS_PROTO_MESSAGE_DUMP -template<> const char *proto_enum_to_string(enums::TextMode value) { - switch (value) { - case enums::TEXT_MODE_TEXT: - return "TEXT_MODE_TEXT"; - case enums::TEXT_MODE_PASSWORD: - return "TEXT_MODE_PASSWORD"; - default: - return "UNKNOWN"; - } -} -#endif -#ifdef HAS_PROTO_MESSAGE_DUMP -template<> const char *proto_enum_to_string(enums::ValveOperation value) { - switch (value) { - case enums::VALVE_OPERATION_IDLE: - return "VALVE_OPERATION_IDLE"; - case enums::VALVE_OPERATION_IS_OPENING: - return "VALVE_OPERATION_IS_OPENING"; - case enums::VALVE_OPERATION_IS_CLOSING: - return "VALVE_OPERATION_IS_CLOSING"; - default: - return "UNKNOWN"; - } -} -#endif -#ifdef HAS_PROTO_MESSAGE_DUMP -template<> const char *proto_enum_to_string(enums::UpdateCommand value) { - switch (value) { - case enums::UPDATE_COMMAND_NONE: - return "UPDATE_COMMAND_NONE"; - case enums::UPDATE_COMMAND_UPDATE: - return "UPDATE_COMMAND_UPDATE"; - case enums::UPDATE_COMMAND_CHECK: - return "UPDATE_COMMAND_CHECK"; - default: - return "UNKNOWN"; - } -} -#endif - bool HelloRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 2: { @@ -665,26 +42,6 @@ void HelloRequest::calculate_size(uint32_t &total_size) const { ProtoSize::add_uint32_field(total_size, 1, this->api_version_major, false); ProtoSize::add_uint32_field(total_size, 1, this->api_version_minor, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void HelloRequest::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("HelloRequest {\n"); - out.append(" client_info: "); - out.append("'").append(this->client_info).append("'"); - out.append("\n"); - - out.append(" api_version_major: "); - sprintf(buffer, "%" PRIu32, this->api_version_major); - out.append(buffer); - out.append("\n"); - - out.append(" api_version_minor: "); - sprintf(buffer, "%" PRIu32, this->api_version_minor); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif bool HelloResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: { @@ -725,30 +82,6 @@ void HelloResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_string_field(total_size, 1, this->server_info, false); ProtoSize::add_string_field(total_size, 1, this->name, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void HelloResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("HelloResponse {\n"); - out.append(" api_version_major: "); - sprintf(buffer, "%" PRIu32, this->api_version_major); - out.append(buffer); - out.append("\n"); - - out.append(" api_version_minor: "); - sprintf(buffer, "%" PRIu32, this->api_version_minor); - out.append(buffer); - out.append("\n"); - - out.append(" server_info: "); - out.append("'").append(this->server_info).append("'"); - out.append("\n"); - - out.append(" name: "); - out.append("'").append(this->name).append("'"); - out.append("\n"); - out.append("}"); -} -#endif bool ConnectRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) { switch (field_id) { case 1: { @@ -763,16 +96,6 @@ void ConnectRequest::encode(ProtoWriteBuffer buffer) const { buffer.encode_strin void ConnectRequest::calculate_size(uint32_t &total_size) const { ProtoSize::add_string_field(total_size, 1, this->password, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void ConnectRequest::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("ConnectRequest {\n"); - out.append(" password: "); - out.append("'").append(this->password).append("'"); - out.append("\n"); - out.append("}"); -} -#endif bool ConnectResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: { @@ -787,31 +110,6 @@ void ConnectResponse::encode(ProtoWriteBuffer buffer) const { buffer.encode_bool void ConnectResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_bool_field(total_size, 1, this->invalid_password, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void ConnectResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("ConnectResponse {\n"); - out.append(" invalid_password: "); - out.append(YESNO(this->invalid_password)); - out.append("\n"); - out.append("}"); -} -#endif -#ifdef HAS_PROTO_MESSAGE_DUMP -void DisconnectRequest::dump_to(std::string &out) const { out.append("DisconnectRequest {}"); } -#endif -#ifdef HAS_PROTO_MESSAGE_DUMP -void DisconnectResponse::dump_to(std::string &out) const { out.append("DisconnectResponse {}"); } -#endif -#ifdef HAS_PROTO_MESSAGE_DUMP -void PingRequest::dump_to(std::string &out) const { out.append("PingRequest {}"); } -#endif -#ifdef HAS_PROTO_MESSAGE_DUMP -void PingResponse::dump_to(std::string &out) const { out.append("PingResponse {}"); } -#endif -#ifdef HAS_PROTO_MESSAGE_DUMP -void DeviceInfoRequest::dump_to(std::string &out) const { out.append("DeviceInfoRequest {}"); } -#endif bool AreaInfo::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: { @@ -840,21 +138,6 @@ void AreaInfo::calculate_size(uint32_t &total_size) const { ProtoSize::add_uint32_field(total_size, 1, this->area_id, false); ProtoSize::add_string_field(total_size, 1, this->name, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void AreaInfo::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("AreaInfo {\n"); - out.append(" area_id: "); - sprintf(buffer, "%" PRIu32, this->area_id); - out.append(buffer); - out.append("\n"); - - out.append(" name: "); - out.append("'").append(this->name).append("'"); - out.append("\n"); - out.append("}"); -} -#endif bool DeviceInfo::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: { @@ -889,26 +172,6 @@ void DeviceInfo::calculate_size(uint32_t &total_size) const { ProtoSize::add_string_field(total_size, 1, this->name, false); ProtoSize::add_uint32_field(total_size, 1, this->area_id, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void DeviceInfo::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("DeviceInfo {\n"); - out.append(" device_id: "); - sprintf(buffer, "%" PRIu32, this->device_id); - out.append(buffer); - out.append("\n"); - - out.append(" name: "); - out.append("'").append(this->name).append("'"); - out.append("\n"); - - out.append(" area_id: "); - sprintf(buffer, "%" PRIu32, this->area_id); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif bool DeviceInfoResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: { @@ -1061,118 +324,7 @@ void DeviceInfoResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_repeated_message(total_size, 2, this->areas); ProtoSize::add_message_object(total_size, 2, this->area, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void DeviceInfoResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("DeviceInfoResponse {\n"); - out.append(" uses_password: "); - out.append(YESNO(this->uses_password)); - out.append("\n"); - - out.append(" name: "); - out.append("'").append(this->name).append("'"); - out.append("\n"); - - out.append(" mac_address: "); - out.append("'").append(this->mac_address).append("'"); - out.append("\n"); - - out.append(" esphome_version: "); - out.append("'").append(this->esphome_version).append("'"); - out.append("\n"); - - out.append(" compilation_time: "); - out.append("'").append(this->compilation_time).append("'"); - out.append("\n"); - - out.append(" model: "); - out.append("'").append(this->model).append("'"); - out.append("\n"); - - out.append(" has_deep_sleep: "); - out.append(YESNO(this->has_deep_sleep)); - out.append("\n"); - - out.append(" project_name: "); - out.append("'").append(this->project_name).append("'"); - out.append("\n"); - - out.append(" project_version: "); - out.append("'").append(this->project_version).append("'"); - out.append("\n"); - - out.append(" webserver_port: "); - sprintf(buffer, "%" PRIu32, this->webserver_port); - out.append(buffer); - out.append("\n"); - - out.append(" legacy_bluetooth_proxy_version: "); - sprintf(buffer, "%" PRIu32, this->legacy_bluetooth_proxy_version); - out.append(buffer); - out.append("\n"); - - out.append(" bluetooth_proxy_feature_flags: "); - sprintf(buffer, "%" PRIu32, this->bluetooth_proxy_feature_flags); - out.append(buffer); - out.append("\n"); - - out.append(" manufacturer: "); - out.append("'").append(this->manufacturer).append("'"); - out.append("\n"); - - out.append(" friendly_name: "); - out.append("'").append(this->friendly_name).append("'"); - out.append("\n"); - - out.append(" legacy_voice_assistant_version: "); - sprintf(buffer, "%" PRIu32, this->legacy_voice_assistant_version); - out.append(buffer); - out.append("\n"); - - out.append(" voice_assistant_feature_flags: "); - sprintf(buffer, "%" PRIu32, this->voice_assistant_feature_flags); - out.append(buffer); - out.append("\n"); - - out.append(" suggested_area: "); - out.append("'").append(this->suggested_area).append("'"); - out.append("\n"); - - out.append(" bluetooth_mac_address: "); - out.append("'").append(this->bluetooth_mac_address).append("'"); - out.append("\n"); - - out.append(" api_encryption_supported: "); - out.append(YESNO(this->api_encryption_supported)); - out.append("\n"); - - for (const auto &it : this->devices) { - out.append(" devices: "); - it.dump_to(out); - out.append("\n"); - } - - for (const auto &it : this->areas) { - out.append(" areas: "); - it.dump_to(out); - out.append("\n"); - } - - out.append(" area: "); - this->area.dump_to(out); - out.append("\n"); - out.append("}"); -} -#endif -#ifdef HAS_PROTO_MESSAGE_DUMP -void ListEntitiesRequest::dump_to(std::string &out) const { out.append("ListEntitiesRequest {}"); } -#endif -#ifdef HAS_PROTO_MESSAGE_DUMP -void ListEntitiesDoneResponse::dump_to(std::string &out) const { out.append("ListEntitiesDoneResponse {}"); } -#endif -#ifdef HAS_PROTO_MESSAGE_DUMP -void SubscribeStatesRequest::dump_to(std::string &out) const { out.append("SubscribeStatesRequest {}"); } -#endif +#ifdef USE_BINARY_SENSOR bool ListEntitiesBinarySensorResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 6: { @@ -1255,54 +407,6 @@ void ListEntitiesBinarySensorResponse::calculate_size(uint32_t &total_size) cons ProtoSize::add_enum_field(total_size, 1, static_cast(this->entity_category), false); ProtoSize::add_uint32_field(total_size, 1, this->device_id, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void ListEntitiesBinarySensorResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("ListEntitiesBinarySensorResponse {\n"); - out.append(" object_id: "); - out.append("'").append(this->object_id).append("'"); - out.append("\n"); - - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" name: "); - out.append("'").append(this->name).append("'"); - out.append("\n"); - - out.append(" unique_id: "); - out.append("'").append(this->unique_id).append("'"); - out.append("\n"); - - out.append(" device_class: "); - out.append("'").append(this->device_class).append("'"); - out.append("\n"); - - out.append(" is_status_binary_sensor: "); - out.append(YESNO(this->is_status_binary_sensor)); - out.append("\n"); - - out.append(" disabled_by_default: "); - out.append(YESNO(this->disabled_by_default)); - out.append("\n"); - - out.append(" icon: "); - out.append("'").append(this->icon).append("'"); - out.append("\n"); - - out.append(" entity_category: "); - out.append(proto_enum_to_string(this->entity_category)); - out.append("\n"); - - out.append(" device_id: "); - sprintf(buffer, "%" PRIu32, this->device_id); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif bool BinarySensorStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 2: { @@ -1337,25 +441,8 @@ void BinarySensorStateResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_bool_field(total_size, 1, this->state, false); ProtoSize::add_bool_field(total_size, 1, this->missing_state, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void BinarySensorStateResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("BinarySensorStateResponse {\n"); - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" state: "); - out.append(YESNO(this->state)); - out.append("\n"); - - out.append(" missing_state: "); - out.append(YESNO(this->missing_state)); - out.append("\n"); - out.append("}"); -} #endif +#ifdef USE_COVER bool ListEntitiesCoverResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 5: { @@ -1456,66 +543,6 @@ void ListEntitiesCoverResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_bool_field(total_size, 1, this->supports_stop, false); ProtoSize::add_uint32_field(total_size, 1, this->device_id, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void ListEntitiesCoverResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("ListEntitiesCoverResponse {\n"); - out.append(" object_id: "); - out.append("'").append(this->object_id).append("'"); - out.append("\n"); - - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" name: "); - out.append("'").append(this->name).append("'"); - out.append("\n"); - - out.append(" unique_id: "); - out.append("'").append(this->unique_id).append("'"); - out.append("\n"); - - out.append(" assumed_state: "); - out.append(YESNO(this->assumed_state)); - out.append("\n"); - - out.append(" supports_position: "); - out.append(YESNO(this->supports_position)); - out.append("\n"); - - out.append(" supports_tilt: "); - out.append(YESNO(this->supports_tilt)); - out.append("\n"); - - out.append(" device_class: "); - out.append("'").append(this->device_class).append("'"); - out.append("\n"); - - out.append(" disabled_by_default: "); - out.append(YESNO(this->disabled_by_default)); - out.append("\n"); - - out.append(" icon: "); - out.append("'").append(this->icon).append("'"); - out.append("\n"); - - out.append(" entity_category: "); - out.append(proto_enum_to_string(this->entity_category)); - out.append("\n"); - - out.append(" supports_stop: "); - out.append(YESNO(this->supports_stop)); - out.append("\n"); - - out.append(" device_id: "); - sprintf(buffer, "%" PRIu32, this->device_id); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif bool CoverStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 2: { @@ -1562,35 +589,6 @@ void CoverStateResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_fixed_field<4>(total_size, 1, this->tilt != 0.0f, false); ProtoSize::add_enum_field(total_size, 1, static_cast(this->current_operation), false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void CoverStateResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("CoverStateResponse {\n"); - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" legacy_state: "); - out.append(proto_enum_to_string(this->legacy_state)); - out.append("\n"); - - out.append(" position: "); - sprintf(buffer, "%g", this->position); - out.append(buffer); - out.append("\n"); - - out.append(" tilt: "); - sprintf(buffer, "%g", this->tilt); - out.append(buffer); - out.append("\n"); - - out.append(" current_operation: "); - out.append(proto_enum_to_string(this->current_operation)); - out.append("\n"); - out.append("}"); -} -#endif bool CoverCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 2: { @@ -1655,47 +653,8 @@ void CoverCommandRequest::calculate_size(uint32_t &total_size) const { ProtoSize::add_fixed_field<4>(total_size, 1, this->tilt != 0.0f, false); ProtoSize::add_bool_field(total_size, 1, this->stop, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void CoverCommandRequest::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("CoverCommandRequest {\n"); - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" has_legacy_command: "); - out.append(YESNO(this->has_legacy_command)); - out.append("\n"); - - out.append(" legacy_command: "); - out.append(proto_enum_to_string(this->legacy_command)); - out.append("\n"); - - out.append(" has_position: "); - out.append(YESNO(this->has_position)); - out.append("\n"); - - out.append(" position: "); - sprintf(buffer, "%g", this->position); - out.append(buffer); - out.append("\n"); - - out.append(" has_tilt: "); - out.append(YESNO(this->has_tilt)); - out.append("\n"); - - out.append(" tilt: "); - sprintf(buffer, "%g", this->tilt); - out.append(buffer); - out.append("\n"); - - out.append(" stop: "); - out.append(YESNO(this->stop)); - out.append("\n"); - out.append("}"); -} #endif +#ifdef USE_FAN bool ListEntitiesFanResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 5: { @@ -1802,69 +761,6 @@ void ListEntitiesFanResponse::calculate_size(uint32_t &total_size) const { } ProtoSize::add_uint32_field(total_size, 1, this->device_id, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void ListEntitiesFanResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("ListEntitiesFanResponse {\n"); - out.append(" object_id: "); - out.append("'").append(this->object_id).append("'"); - out.append("\n"); - - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" name: "); - out.append("'").append(this->name).append("'"); - out.append("\n"); - - out.append(" unique_id: "); - out.append("'").append(this->unique_id).append("'"); - out.append("\n"); - - out.append(" supports_oscillation: "); - out.append(YESNO(this->supports_oscillation)); - out.append("\n"); - - out.append(" supports_speed: "); - out.append(YESNO(this->supports_speed)); - out.append("\n"); - - out.append(" supports_direction: "); - out.append(YESNO(this->supports_direction)); - out.append("\n"); - - out.append(" supported_speed_count: "); - sprintf(buffer, "%" PRId32, this->supported_speed_count); - out.append(buffer); - out.append("\n"); - - out.append(" disabled_by_default: "); - out.append(YESNO(this->disabled_by_default)); - out.append("\n"); - - out.append(" icon: "); - out.append("'").append(this->icon).append("'"); - out.append("\n"); - - out.append(" entity_category: "); - out.append(proto_enum_to_string(this->entity_category)); - out.append("\n"); - - for (const auto &it : this->supported_preset_modes) { - out.append(" supported_preset_modes: "); - out.append("'").append(it).append("'"); - out.append("\n"); - } - - out.append(" device_id: "); - sprintf(buffer, "%" PRIu32, this->device_id); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif bool FanStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 2: { @@ -1929,42 +825,6 @@ void FanStateResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_int32_field(total_size, 1, this->speed_level, false); ProtoSize::add_string_field(total_size, 1, this->preset_mode, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void FanStateResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("FanStateResponse {\n"); - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" state: "); - out.append(YESNO(this->state)); - out.append("\n"); - - out.append(" oscillating: "); - out.append(YESNO(this->oscillating)); - out.append("\n"); - - out.append(" speed: "); - out.append(proto_enum_to_string(this->speed)); - out.append("\n"); - - out.append(" direction: "); - out.append(proto_enum_to_string(this->direction)); - out.append("\n"); - - out.append(" speed_level: "); - sprintf(buffer, "%" PRId32, this->speed_level); - out.append(buffer); - out.append("\n"); - - out.append(" preset_mode: "); - out.append("'").append(this->preset_mode).append("'"); - out.append("\n"); - out.append("}"); -} -#endif bool FanCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 2: { @@ -2065,66 +925,8 @@ void FanCommandRequest::calculate_size(uint32_t &total_size) const { ProtoSize::add_bool_field(total_size, 1, this->has_preset_mode, false); ProtoSize::add_string_field(total_size, 1, this->preset_mode, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void FanCommandRequest::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("FanCommandRequest {\n"); - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" has_state: "); - out.append(YESNO(this->has_state)); - out.append("\n"); - - out.append(" state: "); - out.append(YESNO(this->state)); - out.append("\n"); - - out.append(" has_speed: "); - out.append(YESNO(this->has_speed)); - out.append("\n"); - - out.append(" speed: "); - out.append(proto_enum_to_string(this->speed)); - out.append("\n"); - - out.append(" has_oscillating: "); - out.append(YESNO(this->has_oscillating)); - out.append("\n"); - - out.append(" oscillating: "); - out.append(YESNO(this->oscillating)); - out.append("\n"); - - out.append(" has_direction: "); - out.append(YESNO(this->has_direction)); - out.append("\n"); - - out.append(" direction: "); - out.append(proto_enum_to_string(this->direction)); - out.append("\n"); - - out.append(" has_speed_level: "); - out.append(YESNO(this->has_speed_level)); - out.append("\n"); - - out.append(" speed_level: "); - sprintf(buffer, "%" PRId32, this->speed_level); - out.append(buffer); - out.append("\n"); - - out.append(" has_preset_mode: "); - out.append(YESNO(this->has_preset_mode)); - out.append("\n"); - - out.append(" preset_mode: "); - out.append("'").append(this->preset_mode).append("'"); - out.append("\n"); - out.append("}"); -} #endif +#ifdef USE_LIGHT bool ListEntitiesLightResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 12: { @@ -2255,84 +1057,6 @@ void ListEntitiesLightResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_enum_field(total_size, 1, static_cast(this->entity_category), false); ProtoSize::add_uint32_field(total_size, 2, this->device_id, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void ListEntitiesLightResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("ListEntitiesLightResponse {\n"); - out.append(" object_id: "); - out.append("'").append(this->object_id).append("'"); - out.append("\n"); - - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" name: "); - out.append("'").append(this->name).append("'"); - out.append("\n"); - - out.append(" unique_id: "); - out.append("'").append(this->unique_id).append("'"); - out.append("\n"); - - for (const auto &it : this->supported_color_modes) { - out.append(" supported_color_modes: "); - out.append(proto_enum_to_string(it)); - out.append("\n"); - } - - out.append(" legacy_supports_brightness: "); - out.append(YESNO(this->legacy_supports_brightness)); - out.append("\n"); - - out.append(" legacy_supports_rgb: "); - out.append(YESNO(this->legacy_supports_rgb)); - out.append("\n"); - - out.append(" legacy_supports_white_value: "); - out.append(YESNO(this->legacy_supports_white_value)); - out.append("\n"); - - out.append(" legacy_supports_color_temperature: "); - out.append(YESNO(this->legacy_supports_color_temperature)); - out.append("\n"); - - out.append(" min_mireds: "); - sprintf(buffer, "%g", this->min_mireds); - out.append(buffer); - out.append("\n"); - - out.append(" max_mireds: "); - sprintf(buffer, "%g", this->max_mireds); - out.append(buffer); - out.append("\n"); - - for (const auto &it : this->effects) { - out.append(" effects: "); - out.append("'").append(it).append("'"); - out.append("\n"); - } - - out.append(" disabled_by_default: "); - out.append(YESNO(this->disabled_by_default)); - out.append("\n"); - - out.append(" icon: "); - out.append("'").append(this->icon).append("'"); - out.append("\n"); - - out.append(" entity_category: "); - out.append(proto_enum_to_string(this->entity_category)); - out.append("\n"); - - out.append(" device_id: "); - sprintf(buffer, "%" PRIu32, this->device_id); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif bool LightStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 2: { @@ -2433,74 +1157,6 @@ void LightStateResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_fixed_field<4>(total_size, 1, this->warm_white != 0.0f, false); ProtoSize::add_string_field(total_size, 1, this->effect, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void LightStateResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("LightStateResponse {\n"); - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" state: "); - out.append(YESNO(this->state)); - out.append("\n"); - - out.append(" brightness: "); - sprintf(buffer, "%g", this->brightness); - out.append(buffer); - out.append("\n"); - - out.append(" color_mode: "); - out.append(proto_enum_to_string(this->color_mode)); - out.append("\n"); - - out.append(" color_brightness: "); - sprintf(buffer, "%g", this->color_brightness); - out.append(buffer); - out.append("\n"); - - out.append(" red: "); - sprintf(buffer, "%g", this->red); - out.append(buffer); - out.append("\n"); - - out.append(" green: "); - sprintf(buffer, "%g", this->green); - out.append(buffer); - out.append("\n"); - - out.append(" blue: "); - sprintf(buffer, "%g", this->blue); - out.append(buffer); - out.append("\n"); - - out.append(" white: "); - sprintf(buffer, "%g", this->white); - out.append(buffer); - out.append("\n"); - - out.append(" color_temperature: "); - sprintf(buffer, "%g", this->color_temperature); - out.append(buffer); - out.append("\n"); - - out.append(" cold_white: "); - sprintf(buffer, "%g", this->cold_white); - out.append(buffer); - out.append("\n"); - - out.append(" warm_white: "); - sprintf(buffer, "%g", this->warm_white); - out.append(buffer); - out.append("\n"); - - out.append(" effect: "); - out.append("'").append(this->effect).append("'"); - out.append("\n"); - out.append("}"); -} -#endif bool LightCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 2: { @@ -2685,132 +1341,8 @@ void LightCommandRequest::calculate_size(uint32_t &total_size) const { ProtoSize::add_bool_field(total_size, 2, this->has_effect, false); ProtoSize::add_string_field(total_size, 2, this->effect, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void LightCommandRequest::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("LightCommandRequest {\n"); - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" has_state: "); - out.append(YESNO(this->has_state)); - out.append("\n"); - - out.append(" state: "); - out.append(YESNO(this->state)); - out.append("\n"); - - out.append(" has_brightness: "); - out.append(YESNO(this->has_brightness)); - out.append("\n"); - - out.append(" brightness: "); - sprintf(buffer, "%g", this->brightness); - out.append(buffer); - out.append("\n"); - - out.append(" has_color_mode: "); - out.append(YESNO(this->has_color_mode)); - out.append("\n"); - - out.append(" color_mode: "); - out.append(proto_enum_to_string(this->color_mode)); - out.append("\n"); - - out.append(" has_color_brightness: "); - out.append(YESNO(this->has_color_brightness)); - out.append("\n"); - - out.append(" color_brightness: "); - sprintf(buffer, "%g", this->color_brightness); - out.append(buffer); - out.append("\n"); - - out.append(" has_rgb: "); - out.append(YESNO(this->has_rgb)); - out.append("\n"); - - out.append(" red: "); - sprintf(buffer, "%g", this->red); - out.append(buffer); - out.append("\n"); - - out.append(" green: "); - sprintf(buffer, "%g", this->green); - out.append(buffer); - out.append("\n"); - - out.append(" blue: "); - sprintf(buffer, "%g", this->blue); - out.append(buffer); - out.append("\n"); - - out.append(" has_white: "); - out.append(YESNO(this->has_white)); - out.append("\n"); - - out.append(" white: "); - sprintf(buffer, "%g", this->white); - out.append(buffer); - out.append("\n"); - - out.append(" has_color_temperature: "); - out.append(YESNO(this->has_color_temperature)); - out.append("\n"); - - out.append(" color_temperature: "); - sprintf(buffer, "%g", this->color_temperature); - out.append(buffer); - out.append("\n"); - - out.append(" has_cold_white: "); - out.append(YESNO(this->has_cold_white)); - out.append("\n"); - - out.append(" cold_white: "); - sprintf(buffer, "%g", this->cold_white); - out.append(buffer); - out.append("\n"); - - out.append(" has_warm_white: "); - out.append(YESNO(this->has_warm_white)); - out.append("\n"); - - out.append(" warm_white: "); - sprintf(buffer, "%g", this->warm_white); - out.append(buffer); - out.append("\n"); - - out.append(" has_transition_length: "); - out.append(YESNO(this->has_transition_length)); - out.append("\n"); - - out.append(" transition_length: "); - sprintf(buffer, "%" PRIu32, this->transition_length); - out.append(buffer); - out.append("\n"); - - out.append(" has_flash_length: "); - out.append(YESNO(this->has_flash_length)); - out.append("\n"); - - out.append(" flash_length: "); - sprintf(buffer, "%" PRIu32, this->flash_length); - out.append(buffer); - out.append("\n"); - - out.append(" has_effect: "); - out.append(YESNO(this->has_effect)); - out.append("\n"); - - out.append(" effect: "); - out.append("'").append(this->effect).append("'"); - out.append("\n"); - out.append("}"); -} #endif +#ifdef USE_SENSOR bool ListEntitiesSensorResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 7: { @@ -2917,71 +1449,6 @@ void ListEntitiesSensorResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_enum_field(total_size, 1, static_cast(this->entity_category), false); ProtoSize::add_uint32_field(total_size, 1, this->device_id, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void ListEntitiesSensorResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("ListEntitiesSensorResponse {\n"); - out.append(" object_id: "); - out.append("'").append(this->object_id).append("'"); - out.append("\n"); - - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" name: "); - out.append("'").append(this->name).append("'"); - out.append("\n"); - - out.append(" unique_id: "); - out.append("'").append(this->unique_id).append("'"); - out.append("\n"); - - out.append(" icon: "); - out.append("'").append(this->icon).append("'"); - out.append("\n"); - - out.append(" unit_of_measurement: "); - out.append("'").append(this->unit_of_measurement).append("'"); - out.append("\n"); - - out.append(" accuracy_decimals: "); - sprintf(buffer, "%" PRId32, this->accuracy_decimals); - out.append(buffer); - out.append("\n"); - - out.append(" force_update: "); - out.append(YESNO(this->force_update)); - out.append("\n"); - - out.append(" device_class: "); - out.append("'").append(this->device_class).append("'"); - out.append("\n"); - - out.append(" state_class: "); - out.append(proto_enum_to_string(this->state_class)); - out.append("\n"); - - out.append(" legacy_last_reset_type: "); - out.append(proto_enum_to_string(this->legacy_last_reset_type)); - out.append("\n"); - - out.append(" disabled_by_default: "); - out.append(YESNO(this->disabled_by_default)); - out.append("\n"); - - out.append(" entity_category: "); - out.append(proto_enum_to_string(this->entity_category)); - out.append("\n"); - - out.append(" device_id: "); - sprintf(buffer, "%" PRIu32, this->device_id); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif bool SensorStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 3: { @@ -3016,26 +1483,8 @@ void SensorStateResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_fixed_field<4>(total_size, 1, this->state != 0.0f, false); ProtoSize::add_bool_field(total_size, 1, this->missing_state, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void SensorStateResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("SensorStateResponse {\n"); - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" state: "); - sprintf(buffer, "%g", this->state); - out.append(buffer); - out.append("\n"); - - out.append(" missing_state: "); - out.append(YESNO(this->missing_state)); - out.append("\n"); - out.append("}"); -} #endif +#ifdef USE_SWITCH bool ListEntitiesSwitchResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 6: { @@ -3118,54 +1567,6 @@ void ListEntitiesSwitchResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_string_field(total_size, 1, this->device_class, false); ProtoSize::add_uint32_field(total_size, 1, this->device_id, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void ListEntitiesSwitchResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("ListEntitiesSwitchResponse {\n"); - out.append(" object_id: "); - out.append("'").append(this->object_id).append("'"); - out.append("\n"); - - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" name: "); - out.append("'").append(this->name).append("'"); - out.append("\n"); - - out.append(" unique_id: "); - out.append("'").append(this->unique_id).append("'"); - out.append("\n"); - - out.append(" icon: "); - out.append("'").append(this->icon).append("'"); - out.append("\n"); - - out.append(" assumed_state: "); - out.append(YESNO(this->assumed_state)); - out.append("\n"); - - out.append(" disabled_by_default: "); - out.append(YESNO(this->disabled_by_default)); - out.append("\n"); - - out.append(" entity_category: "); - out.append(proto_enum_to_string(this->entity_category)); - out.append("\n"); - - out.append(" device_class: "); - out.append("'").append(this->device_class).append("'"); - out.append("\n"); - - out.append(" device_id: "); - sprintf(buffer, "%" PRIu32, this->device_id); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif bool SwitchStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 2: { @@ -3194,21 +1595,6 @@ void SwitchStateResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_fixed_field<4>(total_size, 1, this->key != 0, false); ProtoSize::add_bool_field(total_size, 1, this->state, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void SwitchStateResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("SwitchStateResponse {\n"); - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" state: "); - out.append(YESNO(this->state)); - out.append("\n"); - out.append("}"); -} -#endif bool SwitchCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 2: { @@ -3237,21 +1623,8 @@ void SwitchCommandRequest::calculate_size(uint32_t &total_size) const { ProtoSize::add_fixed_field<4>(total_size, 1, this->key != 0, false); ProtoSize::add_bool_field(total_size, 1, this->state, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void SwitchCommandRequest::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("SwitchCommandRequest {\n"); - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" state: "); - out.append(YESNO(this->state)); - out.append("\n"); - out.append("}"); -} #endif +#ifdef USE_TEXT_SENSOR bool ListEntitiesTextSensorResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 6: { @@ -3328,50 +1701,6 @@ void ListEntitiesTextSensorResponse::calculate_size(uint32_t &total_size) const ProtoSize::add_string_field(total_size, 1, this->device_class, false); ProtoSize::add_uint32_field(total_size, 1, this->device_id, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void ListEntitiesTextSensorResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("ListEntitiesTextSensorResponse {\n"); - out.append(" object_id: "); - out.append("'").append(this->object_id).append("'"); - out.append("\n"); - - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" name: "); - out.append("'").append(this->name).append("'"); - out.append("\n"); - - out.append(" unique_id: "); - out.append("'").append(this->unique_id).append("'"); - out.append("\n"); - - out.append(" icon: "); - out.append("'").append(this->icon).append("'"); - out.append("\n"); - - out.append(" disabled_by_default: "); - out.append(YESNO(this->disabled_by_default)); - out.append("\n"); - - out.append(" entity_category: "); - out.append(proto_enum_to_string(this->entity_category)); - out.append("\n"); - - out.append(" device_class: "); - out.append("'").append(this->device_class).append("'"); - out.append("\n"); - - out.append(" device_id: "); - sprintf(buffer, "%" PRIu32, this->device_id); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif bool TextSensorStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 3: { @@ -3412,24 +1741,6 @@ void TextSensorStateResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_string_field(total_size, 1, this->state, false); ProtoSize::add_bool_field(total_size, 1, this->missing_state, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void TextSensorStateResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("TextSensorStateResponse {\n"); - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" state: "); - out.append("'").append(this->state).append("'"); - out.append("\n"); - - out.append(" missing_state: "); - out.append(YESNO(this->missing_state)); - out.append("\n"); - out.append("}"); -} #endif bool SubscribeLogsRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -3453,20 +1764,6 @@ void SubscribeLogsRequest::calculate_size(uint32_t &total_size) const { ProtoSize::add_enum_field(total_size, 1, static_cast(this->level), false); ProtoSize::add_bool_field(total_size, 1, this->dump_config, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void SubscribeLogsRequest::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("SubscribeLogsRequest {\n"); - out.append(" level: "); - out.append(proto_enum_to_string(this->level)); - out.append("\n"); - - out.append(" dump_config: "); - out.append(YESNO(this->dump_config)); - out.append("\n"); - out.append("}"); -} -#endif bool SubscribeLogsResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: { @@ -3493,7 +1790,7 @@ bool SubscribeLogsResponse::decode_length(uint32_t field_id, ProtoLengthDelimite } void SubscribeLogsResponse::encode(ProtoWriteBuffer buffer) const { buffer.encode_enum(1, this->level); - buffer.encode_string(3, this->message); + buffer.encode_bytes(3, reinterpret_cast(this->message.data()), this->message.size()); buffer.encode_bool(4, this->send_failed); } void SubscribeLogsResponse::calculate_size(uint32_t &total_size) const { @@ -3501,24 +1798,7 @@ void SubscribeLogsResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_string_field(total_size, 1, this->message, false); ProtoSize::add_bool_field(total_size, 1, this->send_failed, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void SubscribeLogsResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("SubscribeLogsResponse {\n"); - out.append(" level: "); - out.append(proto_enum_to_string(this->level)); - out.append("\n"); - - out.append(" message: "); - out.append("'").append(this->message).append("'"); - out.append("\n"); - - out.append(" send_failed: "); - out.append(YESNO(this->send_failed)); - out.append("\n"); - out.append("}"); -} -#endif +#ifdef USE_API_NOISE bool NoiseEncryptionSetKeyRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) { switch (field_id) { case 1: { @@ -3529,20 +1809,12 @@ bool NoiseEncryptionSetKeyRequest::decode_length(uint32_t field_id, ProtoLengthD return false; } } -void NoiseEncryptionSetKeyRequest::encode(ProtoWriteBuffer buffer) const { buffer.encode_string(1, this->key); } +void NoiseEncryptionSetKeyRequest::encode(ProtoWriteBuffer buffer) const { + buffer.encode_bytes(1, reinterpret_cast(this->key.data()), this->key.size()); +} void NoiseEncryptionSetKeyRequest::calculate_size(uint32_t &total_size) const { ProtoSize::add_string_field(total_size, 1, this->key, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void NoiseEncryptionSetKeyRequest::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("NoiseEncryptionSetKeyRequest {\n"); - out.append(" key: "); - out.append("'").append(this->key).append("'"); - out.append("\n"); - out.append("}"); -} -#endif bool NoiseEncryptionSetKeyResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: { @@ -3557,20 +1829,6 @@ void NoiseEncryptionSetKeyResponse::encode(ProtoWriteBuffer buffer) const { buff void NoiseEncryptionSetKeyResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_bool_field(total_size, 1, this->success, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void NoiseEncryptionSetKeyResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("NoiseEncryptionSetKeyResponse {\n"); - out.append(" success: "); - out.append(YESNO(this->success)); - out.append("\n"); - out.append("}"); -} -#endif -#ifdef HAS_PROTO_MESSAGE_DUMP -void SubscribeHomeassistantServicesRequest::dump_to(std::string &out) const { - out.append("SubscribeHomeassistantServicesRequest {}"); -} #endif bool HomeassistantServiceMap::decode_length(uint32_t field_id, ProtoLengthDelimited value) { switch (field_id) { @@ -3594,20 +1852,6 @@ void HomeassistantServiceMap::calculate_size(uint32_t &total_size) const { ProtoSize::add_string_field(total_size, 1, this->key, false); ProtoSize::add_string_field(total_size, 1, this->value, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void HomeassistantServiceMap::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("HomeassistantServiceMap {\n"); - out.append(" key: "); - out.append("'").append(this->key).append("'"); - out.append("\n"); - - out.append(" value: "); - out.append("'").append(this->value).append("'"); - out.append("\n"); - out.append("}"); -} -#endif bool HomeassistantServiceResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 5: { @@ -3660,43 +1904,6 @@ void HomeassistantServiceResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_repeated_message(total_size, 1, this->variables); ProtoSize::add_bool_field(total_size, 1, this->is_event, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void HomeassistantServiceResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("HomeassistantServiceResponse {\n"); - out.append(" service: "); - out.append("'").append(this->service).append("'"); - out.append("\n"); - - for (const auto &it : this->data) { - out.append(" data: "); - it.dump_to(out); - out.append("\n"); - } - - for (const auto &it : this->data_template) { - out.append(" data_template: "); - it.dump_to(out); - out.append("\n"); - } - - for (const auto &it : this->variables) { - out.append(" variables: "); - it.dump_to(out); - out.append("\n"); - } - - out.append(" is_event: "); - out.append(YESNO(this->is_event)); - out.append("\n"); - out.append("}"); -} -#endif -#ifdef HAS_PROTO_MESSAGE_DUMP -void SubscribeHomeAssistantStatesRequest::dump_to(std::string &out) const { - out.append("SubscribeHomeAssistantStatesRequest {}"); -} -#endif bool SubscribeHomeAssistantStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 3: { @@ -3731,24 +1938,6 @@ void SubscribeHomeAssistantStateResponse::calculate_size(uint32_t &total_size) c ProtoSize::add_string_field(total_size, 1, this->attribute, false); ProtoSize::add_bool_field(total_size, 1, this->once, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void SubscribeHomeAssistantStateResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("SubscribeHomeAssistantStateResponse {\n"); - out.append(" entity_id: "); - out.append("'").append(this->entity_id).append("'"); - out.append("\n"); - - out.append(" attribute: "); - out.append("'").append(this->attribute).append("'"); - out.append("\n"); - - out.append(" once: "); - out.append(YESNO(this->once)); - out.append("\n"); - out.append("}"); -} -#endif bool HomeAssistantStateResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) { switch (field_id) { case 1: { @@ -3777,27 +1966,6 @@ void HomeAssistantStateResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_string_field(total_size, 1, this->state, false); ProtoSize::add_string_field(total_size, 1, this->attribute, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void HomeAssistantStateResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("HomeAssistantStateResponse {\n"); - out.append(" entity_id: "); - out.append("'").append(this->entity_id).append("'"); - out.append("\n"); - - out.append(" state: "); - out.append("'").append(this->state).append("'"); - out.append("\n"); - - out.append(" attribute: "); - out.append("'").append(this->attribute).append("'"); - out.append("\n"); - out.append("}"); -} -#endif -#ifdef HAS_PROTO_MESSAGE_DUMP -void GetTimeRequest::dump_to(std::string &out) const { out.append("GetTimeRequest {}"); } -#endif bool GetTimeResponse::decode_32bit(uint32_t field_id, Proto32Bit value) { switch (field_id) { case 1: { @@ -3812,17 +1980,6 @@ void GetTimeResponse::encode(ProtoWriteBuffer buffer) const { buffer.encode_fixe void GetTimeResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_fixed_field<4>(total_size, 1, this->epoch_seconds != 0, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void GetTimeResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("GetTimeResponse {\n"); - out.append(" epoch_seconds: "); - sprintf(buffer, "%" PRIu32, this->epoch_seconds); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif bool ListEntitiesServicesArgument::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 2: { @@ -3851,20 +2008,6 @@ void ListEntitiesServicesArgument::calculate_size(uint32_t &total_size) const { ProtoSize::add_string_field(total_size, 1, this->name, false); ProtoSize::add_enum_field(total_size, 1, static_cast(this->type), false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void ListEntitiesServicesArgument::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("ListEntitiesServicesArgument {\n"); - out.append(" name: "); - out.append("'").append(this->name).append("'"); - out.append("\n"); - - out.append(" type: "); - out.append(proto_enum_to_string(this->type)); - out.append("\n"); - out.append("}"); -} -#endif bool ListEntitiesServicesResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) { switch (field_id) { case 1: { @@ -3901,27 +2044,6 @@ void ListEntitiesServicesResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_fixed_field<4>(total_size, 1, this->key != 0, false); ProtoSize::add_repeated_message(total_size, 1, this->args); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void ListEntitiesServicesResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("ListEntitiesServicesResponse {\n"); - out.append(" name: "); - out.append("'").append(this->name).append("'"); - out.append("\n"); - - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - for (const auto &it : this->args) { - out.append(" args: "); - it.dump_to(out); - out.append("\n"); - } - out.append("}"); -} -#endif bool ExecuteServiceArgument::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: { @@ -4022,61 +2144,6 @@ void ExecuteServiceArgument::calculate_size(uint32_t &total_size) const { } } } -#ifdef HAS_PROTO_MESSAGE_DUMP -void ExecuteServiceArgument::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("ExecuteServiceArgument {\n"); - out.append(" bool_: "); - out.append(YESNO(this->bool_)); - out.append("\n"); - - out.append(" legacy_int: "); - sprintf(buffer, "%" PRId32, this->legacy_int); - out.append(buffer); - out.append("\n"); - - out.append(" float_: "); - sprintf(buffer, "%g", this->float_); - out.append(buffer); - out.append("\n"); - - out.append(" string_: "); - out.append("'").append(this->string_).append("'"); - out.append("\n"); - - out.append(" int_: "); - sprintf(buffer, "%" PRId32, this->int_); - out.append(buffer); - out.append("\n"); - - for (const auto it : this->bool_array) { - out.append(" bool_array: "); - out.append(YESNO(it)); - out.append("\n"); - } - - for (const auto &it : this->int_array) { - out.append(" int_array: "); - sprintf(buffer, "%" PRId32, it); - out.append(buffer); - out.append("\n"); - } - - for (const auto &it : this->float_array) { - out.append(" float_array: "); - sprintf(buffer, "%g", it); - out.append(buffer); - out.append("\n"); - } - - for (const auto &it : this->string_array) { - out.append(" string_array: "); - out.append("'").append(it).append("'"); - out.append("\n"); - } - out.append("}"); -} -#endif bool ExecuteServiceRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) { switch (field_id) { case 2: { @@ -4107,23 +2174,7 @@ void ExecuteServiceRequest::calculate_size(uint32_t &total_size) const { ProtoSize::add_fixed_field<4>(total_size, 1, this->key != 0, false); ProtoSize::add_repeated_message(total_size, 1, this->args); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void ExecuteServiceRequest::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("ExecuteServiceRequest {\n"); - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - for (const auto &it : this->args) { - out.append(" args: "); - it.dump_to(out); - out.append("\n"); - } - out.append("}"); -} -#endif +#ifdef USE_ESP32_CAMERA bool ListEntitiesCameraResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 5: { @@ -4194,46 +2245,6 @@ void ListEntitiesCameraResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_enum_field(total_size, 1, static_cast(this->entity_category), false); ProtoSize::add_uint32_field(total_size, 1, this->device_id, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void ListEntitiesCameraResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("ListEntitiesCameraResponse {\n"); - out.append(" object_id: "); - out.append("'").append(this->object_id).append("'"); - out.append("\n"); - - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" name: "); - out.append("'").append(this->name).append("'"); - out.append("\n"); - - out.append(" unique_id: "); - out.append("'").append(this->unique_id).append("'"); - out.append("\n"); - - out.append(" disabled_by_default: "); - out.append(YESNO(this->disabled_by_default)); - out.append("\n"); - - out.append(" icon: "); - out.append("'").append(this->icon).append("'"); - out.append("\n"); - - out.append(" entity_category: "); - out.append(proto_enum_to_string(this->entity_category)); - out.append("\n"); - - out.append(" device_id: "); - sprintf(buffer, "%" PRIu32, this->device_id); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif bool CameraImageResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 3: { @@ -4266,7 +2277,7 @@ bool CameraImageResponse::decode_32bit(uint32_t field_id, Proto32Bit value) { } void CameraImageResponse::encode(ProtoWriteBuffer buffer) const { buffer.encode_fixed32(1, this->key); - buffer.encode_string(2, this->data); + buffer.encode_bytes(2, reinterpret_cast(this->data.data()), this->data.size()); buffer.encode_bool(3, this->done); } void CameraImageResponse::calculate_size(uint32_t &total_size) const { @@ -4274,25 +2285,6 @@ void CameraImageResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_string_field(total_size, 1, this->data, false); ProtoSize::add_bool_field(total_size, 1, this->done, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void CameraImageResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("CameraImageResponse {\n"); - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" data: "); - out.append("'").append(this->data).append("'"); - out.append("\n"); - - out.append(" done: "); - out.append(YESNO(this->done)); - out.append("\n"); - out.append("}"); -} -#endif bool CameraImageRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: { @@ -4315,20 +2307,8 @@ void CameraImageRequest::calculate_size(uint32_t &total_size) const { ProtoSize::add_bool_field(total_size, 1, this->single, false); ProtoSize::add_bool_field(total_size, 1, this->stream, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void CameraImageRequest::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("CameraImageRequest {\n"); - out.append(" single: "); - out.append(YESNO(this->single)); - out.append("\n"); - - out.append(" stream: "); - out.append(YESNO(this->stream)); - out.append("\n"); - out.append("}"); -} #endif +#ifdef USE_CLIMATE bool ListEntitiesClimateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 5: { @@ -4543,136 +2523,6 @@ void ListEntitiesClimateResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_fixed_field<4>(total_size, 2, this->visual_max_humidity != 0.0f, false); ProtoSize::add_uint32_field(total_size, 2, this->device_id, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void ListEntitiesClimateResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("ListEntitiesClimateResponse {\n"); - out.append(" object_id: "); - out.append("'").append(this->object_id).append("'"); - out.append("\n"); - - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" name: "); - out.append("'").append(this->name).append("'"); - out.append("\n"); - - out.append(" unique_id: "); - out.append("'").append(this->unique_id).append("'"); - out.append("\n"); - - out.append(" supports_current_temperature: "); - out.append(YESNO(this->supports_current_temperature)); - out.append("\n"); - - out.append(" supports_two_point_target_temperature: "); - out.append(YESNO(this->supports_two_point_target_temperature)); - out.append("\n"); - - for (const auto &it : this->supported_modes) { - out.append(" supported_modes: "); - out.append(proto_enum_to_string(it)); - out.append("\n"); - } - - out.append(" visual_min_temperature: "); - sprintf(buffer, "%g", this->visual_min_temperature); - out.append(buffer); - out.append("\n"); - - out.append(" visual_max_temperature: "); - sprintf(buffer, "%g", this->visual_max_temperature); - out.append(buffer); - out.append("\n"); - - out.append(" visual_target_temperature_step: "); - sprintf(buffer, "%g", this->visual_target_temperature_step); - out.append(buffer); - out.append("\n"); - - out.append(" legacy_supports_away: "); - out.append(YESNO(this->legacy_supports_away)); - out.append("\n"); - - out.append(" supports_action: "); - out.append(YESNO(this->supports_action)); - out.append("\n"); - - for (const auto &it : this->supported_fan_modes) { - out.append(" supported_fan_modes: "); - out.append(proto_enum_to_string(it)); - out.append("\n"); - } - - for (const auto &it : this->supported_swing_modes) { - out.append(" supported_swing_modes: "); - out.append(proto_enum_to_string(it)); - out.append("\n"); - } - - for (const auto &it : this->supported_custom_fan_modes) { - out.append(" supported_custom_fan_modes: "); - out.append("'").append(it).append("'"); - out.append("\n"); - } - - for (const auto &it : this->supported_presets) { - out.append(" supported_presets: "); - out.append(proto_enum_to_string(it)); - out.append("\n"); - } - - for (const auto &it : this->supported_custom_presets) { - out.append(" supported_custom_presets: "); - out.append("'").append(it).append("'"); - out.append("\n"); - } - - out.append(" disabled_by_default: "); - out.append(YESNO(this->disabled_by_default)); - out.append("\n"); - - out.append(" icon: "); - out.append("'").append(this->icon).append("'"); - out.append("\n"); - - out.append(" entity_category: "); - out.append(proto_enum_to_string(this->entity_category)); - out.append("\n"); - - out.append(" visual_current_temperature_step: "); - sprintf(buffer, "%g", this->visual_current_temperature_step); - out.append(buffer); - out.append("\n"); - - out.append(" supports_current_humidity: "); - out.append(YESNO(this->supports_current_humidity)); - out.append("\n"); - - out.append(" supports_target_humidity: "); - out.append(YESNO(this->supports_target_humidity)); - out.append("\n"); - - out.append(" visual_min_humidity: "); - sprintf(buffer, "%g", this->visual_min_humidity); - out.append(buffer); - out.append("\n"); - - out.append(" visual_max_humidity: "); - sprintf(buffer, "%g", this->visual_max_humidity); - out.append(buffer); - out.append("\n"); - - out.append(" device_id: "); - sprintf(buffer, "%" PRIu32, this->device_id); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif bool ClimateStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 2: { @@ -4785,79 +2635,6 @@ void ClimateStateResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_fixed_field<4>(total_size, 1, this->current_humidity != 0.0f, false); ProtoSize::add_fixed_field<4>(total_size, 1, this->target_humidity != 0.0f, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void ClimateStateResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("ClimateStateResponse {\n"); - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" mode: "); - out.append(proto_enum_to_string(this->mode)); - out.append("\n"); - - out.append(" current_temperature: "); - sprintf(buffer, "%g", this->current_temperature); - out.append(buffer); - out.append("\n"); - - out.append(" target_temperature: "); - sprintf(buffer, "%g", this->target_temperature); - out.append(buffer); - out.append("\n"); - - out.append(" target_temperature_low: "); - sprintf(buffer, "%g", this->target_temperature_low); - out.append(buffer); - out.append("\n"); - - out.append(" target_temperature_high: "); - sprintf(buffer, "%g", this->target_temperature_high); - out.append(buffer); - out.append("\n"); - - out.append(" unused_legacy_away: "); - out.append(YESNO(this->unused_legacy_away)); - out.append("\n"); - - out.append(" action: "); - out.append(proto_enum_to_string(this->action)); - out.append("\n"); - - out.append(" fan_mode: "); - out.append(proto_enum_to_string(this->fan_mode)); - out.append("\n"); - - out.append(" swing_mode: "); - out.append(proto_enum_to_string(this->swing_mode)); - out.append("\n"); - - out.append(" custom_fan_mode: "); - out.append("'").append(this->custom_fan_mode).append("'"); - out.append("\n"); - - out.append(" preset: "); - out.append(proto_enum_to_string(this->preset)); - out.append("\n"); - - out.append(" custom_preset: "); - out.append("'").append(this->custom_preset).append("'"); - out.append("\n"); - - out.append(" current_humidity: "); - sprintf(buffer, "%g", this->current_humidity); - out.append(buffer); - out.append("\n"); - - out.append(" target_humidity: "); - sprintf(buffer, "%g", this->target_humidity); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif bool ClimateCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 2: { @@ -5018,109 +2795,8 @@ void ClimateCommandRequest::calculate_size(uint32_t &total_size) const { ProtoSize::add_bool_field(total_size, 2, this->has_target_humidity, false); ProtoSize::add_fixed_field<4>(total_size, 2, this->target_humidity != 0.0f, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void ClimateCommandRequest::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("ClimateCommandRequest {\n"); - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" has_mode: "); - out.append(YESNO(this->has_mode)); - out.append("\n"); - - out.append(" mode: "); - out.append(proto_enum_to_string(this->mode)); - out.append("\n"); - - out.append(" has_target_temperature: "); - out.append(YESNO(this->has_target_temperature)); - out.append("\n"); - - out.append(" target_temperature: "); - sprintf(buffer, "%g", this->target_temperature); - out.append(buffer); - out.append("\n"); - - out.append(" has_target_temperature_low: "); - out.append(YESNO(this->has_target_temperature_low)); - out.append("\n"); - - out.append(" target_temperature_low: "); - sprintf(buffer, "%g", this->target_temperature_low); - out.append(buffer); - out.append("\n"); - - out.append(" has_target_temperature_high: "); - out.append(YESNO(this->has_target_temperature_high)); - out.append("\n"); - - out.append(" target_temperature_high: "); - sprintf(buffer, "%g", this->target_temperature_high); - out.append(buffer); - out.append("\n"); - - out.append(" unused_has_legacy_away: "); - out.append(YESNO(this->unused_has_legacy_away)); - out.append("\n"); - - out.append(" unused_legacy_away: "); - out.append(YESNO(this->unused_legacy_away)); - out.append("\n"); - - out.append(" has_fan_mode: "); - out.append(YESNO(this->has_fan_mode)); - out.append("\n"); - - out.append(" fan_mode: "); - out.append(proto_enum_to_string(this->fan_mode)); - out.append("\n"); - - out.append(" has_swing_mode: "); - out.append(YESNO(this->has_swing_mode)); - out.append("\n"); - - out.append(" swing_mode: "); - out.append(proto_enum_to_string(this->swing_mode)); - out.append("\n"); - - out.append(" has_custom_fan_mode: "); - out.append(YESNO(this->has_custom_fan_mode)); - out.append("\n"); - - out.append(" custom_fan_mode: "); - out.append("'").append(this->custom_fan_mode).append("'"); - out.append("\n"); - - out.append(" has_preset: "); - out.append(YESNO(this->has_preset)); - out.append("\n"); - - out.append(" preset: "); - out.append(proto_enum_to_string(this->preset)); - out.append("\n"); - - out.append(" has_custom_preset: "); - out.append(YESNO(this->has_custom_preset)); - out.append("\n"); - - out.append(" custom_preset: "); - out.append("'").append(this->custom_preset).append("'"); - out.append("\n"); - - out.append(" has_target_humidity: "); - out.append(YESNO(this->has_target_humidity)); - out.append("\n"); - - out.append(" target_humidity: "); - sprintf(buffer, "%g", this->target_humidity); - out.append(buffer); - out.append("\n"); - out.append("}"); -} #endif +#ifdef USE_NUMBER bool ListEntitiesNumberResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 9: { @@ -5227,73 +2903,6 @@ void ListEntitiesNumberResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_string_field(total_size, 1, this->device_class, false); ProtoSize::add_uint32_field(total_size, 1, this->device_id, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void ListEntitiesNumberResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("ListEntitiesNumberResponse {\n"); - out.append(" object_id: "); - out.append("'").append(this->object_id).append("'"); - out.append("\n"); - - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" name: "); - out.append("'").append(this->name).append("'"); - out.append("\n"); - - out.append(" unique_id: "); - out.append("'").append(this->unique_id).append("'"); - out.append("\n"); - - out.append(" icon: "); - out.append("'").append(this->icon).append("'"); - out.append("\n"); - - out.append(" min_value: "); - sprintf(buffer, "%g", this->min_value); - out.append(buffer); - out.append("\n"); - - out.append(" max_value: "); - sprintf(buffer, "%g", this->max_value); - out.append(buffer); - out.append("\n"); - - out.append(" step: "); - sprintf(buffer, "%g", this->step); - out.append(buffer); - out.append("\n"); - - out.append(" disabled_by_default: "); - out.append(YESNO(this->disabled_by_default)); - out.append("\n"); - - out.append(" entity_category: "); - out.append(proto_enum_to_string(this->entity_category)); - out.append("\n"); - - out.append(" unit_of_measurement: "); - out.append("'").append(this->unit_of_measurement).append("'"); - out.append("\n"); - - out.append(" mode: "); - out.append(proto_enum_to_string(this->mode)); - out.append("\n"); - - out.append(" device_class: "); - out.append("'").append(this->device_class).append("'"); - out.append("\n"); - - out.append(" device_id: "); - sprintf(buffer, "%" PRIu32, this->device_id); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif bool NumberStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 3: { @@ -5328,26 +2937,6 @@ void NumberStateResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_fixed_field<4>(total_size, 1, this->state != 0.0f, false); ProtoSize::add_bool_field(total_size, 1, this->missing_state, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void NumberStateResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("NumberStateResponse {\n"); - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" state: "); - sprintf(buffer, "%g", this->state); - out.append(buffer); - out.append("\n"); - - out.append(" missing_state: "); - out.append(YESNO(this->missing_state)); - out.append("\n"); - out.append("}"); -} -#endif bool NumberCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) { switch (field_id) { case 1: { @@ -5370,22 +2959,8 @@ void NumberCommandRequest::calculate_size(uint32_t &total_size) const { ProtoSize::add_fixed_field<4>(total_size, 1, this->key != 0, false); ProtoSize::add_fixed_field<4>(total_size, 1, this->state != 0.0f, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void NumberCommandRequest::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("NumberCommandRequest {\n"); - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" state: "); - sprintf(buffer, "%g", this->state); - out.append(buffer); - out.append("\n"); - out.append("}"); -} #endif +#ifdef USE_SELECT bool ListEntitiesSelectResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 7: { @@ -5468,52 +3043,6 @@ void ListEntitiesSelectResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_enum_field(total_size, 1, static_cast(this->entity_category), false); ProtoSize::add_uint32_field(total_size, 1, this->device_id, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void ListEntitiesSelectResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("ListEntitiesSelectResponse {\n"); - out.append(" object_id: "); - out.append("'").append(this->object_id).append("'"); - out.append("\n"); - - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" name: "); - out.append("'").append(this->name).append("'"); - out.append("\n"); - - out.append(" unique_id: "); - out.append("'").append(this->unique_id).append("'"); - out.append("\n"); - - out.append(" icon: "); - out.append("'").append(this->icon).append("'"); - out.append("\n"); - - for (const auto &it : this->options) { - out.append(" options: "); - out.append("'").append(it).append("'"); - out.append("\n"); - } - - out.append(" disabled_by_default: "); - out.append(YESNO(this->disabled_by_default)); - out.append("\n"); - - out.append(" entity_category: "); - out.append(proto_enum_to_string(this->entity_category)); - out.append("\n"); - - out.append(" device_id: "); - sprintf(buffer, "%" PRIu32, this->device_id); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif bool SelectStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 3: { @@ -5554,25 +3083,6 @@ void SelectStateResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_string_field(total_size, 1, this->state, false); ProtoSize::add_bool_field(total_size, 1, this->missing_state, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void SelectStateResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("SelectStateResponse {\n"); - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" state: "); - out.append("'").append(this->state).append("'"); - out.append("\n"); - - out.append(" missing_state: "); - out.append(YESNO(this->missing_state)); - out.append("\n"); - out.append("}"); -} -#endif bool SelectCommandRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) { switch (field_id) { case 2: { @@ -5601,21 +3111,8 @@ void SelectCommandRequest::calculate_size(uint32_t &total_size) const { ProtoSize::add_fixed_field<4>(total_size, 1, this->key != 0, false); ProtoSize::add_string_field(total_size, 1, this->state, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void SelectCommandRequest::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("SelectCommandRequest {\n"); - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" state: "); - out.append("'").append(this->state).append("'"); - out.append("\n"); - out.append("}"); -} #endif +#ifdef USE_SIREN bool ListEntitiesSirenResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 6: { @@ -5710,60 +3207,6 @@ void ListEntitiesSirenResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_enum_field(total_size, 1, static_cast(this->entity_category), false); ProtoSize::add_uint32_field(total_size, 1, this->device_id, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void ListEntitiesSirenResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("ListEntitiesSirenResponse {\n"); - out.append(" object_id: "); - out.append("'").append(this->object_id).append("'"); - out.append("\n"); - - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" name: "); - out.append("'").append(this->name).append("'"); - out.append("\n"); - - out.append(" unique_id: "); - out.append("'").append(this->unique_id).append("'"); - out.append("\n"); - - out.append(" icon: "); - out.append("'").append(this->icon).append("'"); - out.append("\n"); - - out.append(" disabled_by_default: "); - out.append(YESNO(this->disabled_by_default)); - out.append("\n"); - - for (const auto &it : this->tones) { - out.append(" tones: "); - out.append("'").append(it).append("'"); - out.append("\n"); - } - - out.append(" supports_duration: "); - out.append(YESNO(this->supports_duration)); - out.append("\n"); - - out.append(" supports_volume: "); - out.append(YESNO(this->supports_volume)); - out.append("\n"); - - out.append(" entity_category: "); - out.append(proto_enum_to_string(this->entity_category)); - out.append("\n"); - - out.append(" device_id: "); - sprintf(buffer, "%" PRIu32, this->device_id); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif bool SirenStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 2: { @@ -5792,21 +3235,6 @@ void SirenStateResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_fixed_field<4>(total_size, 1, this->key != 0, false); ProtoSize::add_bool_field(total_size, 1, this->state, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void SirenStateResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("SirenStateResponse {\n"); - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" state: "); - out.append(YESNO(this->state)); - out.append("\n"); - out.append("}"); -} -#endif bool SirenCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 2: { @@ -5883,51 +3311,8 @@ void SirenCommandRequest::calculate_size(uint32_t &total_size) const { ProtoSize::add_bool_field(total_size, 1, this->has_volume, false); ProtoSize::add_fixed_field<4>(total_size, 1, this->volume != 0.0f, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void SirenCommandRequest::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("SirenCommandRequest {\n"); - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" has_state: "); - out.append(YESNO(this->has_state)); - out.append("\n"); - - out.append(" state: "); - out.append(YESNO(this->state)); - out.append("\n"); - - out.append(" has_tone: "); - out.append(YESNO(this->has_tone)); - out.append("\n"); - - out.append(" tone: "); - out.append("'").append(this->tone).append("'"); - out.append("\n"); - - out.append(" has_duration: "); - out.append(YESNO(this->has_duration)); - out.append("\n"); - - out.append(" duration: "); - sprintf(buffer, "%" PRIu32, this->duration); - out.append(buffer); - out.append("\n"); - - out.append(" has_volume: "); - out.append(YESNO(this->has_volume)); - out.append("\n"); - - out.append(" volume: "); - sprintf(buffer, "%g", this->volume); - out.append(buffer); - out.append("\n"); - out.append("}"); -} #endif +#ifdef USE_LOCK bool ListEntitiesLockResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 6: { @@ -6022,62 +3407,6 @@ void ListEntitiesLockResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_string_field(total_size, 1, this->code_format, false); ProtoSize::add_uint32_field(total_size, 1, this->device_id, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void ListEntitiesLockResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("ListEntitiesLockResponse {\n"); - out.append(" object_id: "); - out.append("'").append(this->object_id).append("'"); - out.append("\n"); - - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" name: "); - out.append("'").append(this->name).append("'"); - out.append("\n"); - - out.append(" unique_id: "); - out.append("'").append(this->unique_id).append("'"); - out.append("\n"); - - out.append(" icon: "); - out.append("'").append(this->icon).append("'"); - out.append("\n"); - - out.append(" disabled_by_default: "); - out.append(YESNO(this->disabled_by_default)); - out.append("\n"); - - out.append(" entity_category: "); - out.append(proto_enum_to_string(this->entity_category)); - out.append("\n"); - - out.append(" assumed_state: "); - out.append(YESNO(this->assumed_state)); - out.append("\n"); - - out.append(" supports_open: "); - out.append(YESNO(this->supports_open)); - out.append("\n"); - - out.append(" requires_code: "); - out.append(YESNO(this->requires_code)); - out.append("\n"); - - out.append(" code_format: "); - out.append("'").append(this->code_format).append("'"); - out.append("\n"); - - out.append(" device_id: "); - sprintf(buffer, "%" PRIu32, this->device_id); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif bool LockStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 2: { @@ -6106,21 +3435,6 @@ void LockStateResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_fixed_field<4>(total_size, 1, this->key != 0, false); ProtoSize::add_enum_field(total_size, 1, static_cast(this->state), false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void LockStateResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("LockStateResponse {\n"); - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" state: "); - out.append(proto_enum_to_string(this->state)); - out.append("\n"); - out.append("}"); -} -#endif bool LockCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 2: { @@ -6167,29 +3481,8 @@ void LockCommandRequest::calculate_size(uint32_t &total_size) const { ProtoSize::add_bool_field(total_size, 1, this->has_code, false); ProtoSize::add_string_field(total_size, 1, this->code, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void LockCommandRequest::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("LockCommandRequest {\n"); - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" command: "); - out.append(proto_enum_to_string(this->command)); - out.append("\n"); - - out.append(" has_code: "); - out.append(YESNO(this->has_code)); - out.append("\n"); - - out.append(" code: "); - out.append("'").append(this->code).append("'"); - out.append("\n"); - out.append("}"); -} #endif +#ifdef USE_BUTTON bool ListEntitiesButtonResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 6: { @@ -6266,50 +3559,6 @@ void ListEntitiesButtonResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_string_field(total_size, 1, this->device_class, false); ProtoSize::add_uint32_field(total_size, 1, this->device_id, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void ListEntitiesButtonResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("ListEntitiesButtonResponse {\n"); - out.append(" object_id: "); - out.append("'").append(this->object_id).append("'"); - out.append("\n"); - - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" name: "); - out.append("'").append(this->name).append("'"); - out.append("\n"); - - out.append(" unique_id: "); - out.append("'").append(this->unique_id).append("'"); - out.append("\n"); - - out.append(" icon: "); - out.append("'").append(this->icon).append("'"); - out.append("\n"); - - out.append(" disabled_by_default: "); - out.append(YESNO(this->disabled_by_default)); - out.append("\n"); - - out.append(" entity_category: "); - out.append(proto_enum_to_string(this->entity_category)); - out.append("\n"); - - out.append(" device_class: "); - out.append("'").append(this->device_class).append("'"); - out.append("\n"); - - out.append(" device_id: "); - sprintf(buffer, "%" PRIu32, this->device_id); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif bool ButtonCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) { switch (field_id) { case 1: { @@ -6324,17 +3573,8 @@ void ButtonCommandRequest::encode(ProtoWriteBuffer buffer) const { buffer.encode void ButtonCommandRequest::calculate_size(uint32_t &total_size) const { ProtoSize::add_fixed_field<4>(total_size, 1, this->key != 0, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void ButtonCommandRequest::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("ButtonCommandRequest {\n"); - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - out.append("}"); -} #endif +#ifdef USE_MEDIA_PLAYER bool MediaPlayerSupportedFormat::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 2: { @@ -6381,35 +3621,6 @@ void MediaPlayerSupportedFormat::calculate_size(uint32_t &total_size) const { ProtoSize::add_enum_field(total_size, 1, static_cast(this->purpose), false); ProtoSize::add_uint32_field(total_size, 1, this->sample_bytes, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void MediaPlayerSupportedFormat::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("MediaPlayerSupportedFormat {\n"); - out.append(" format: "); - out.append("'").append(this->format).append("'"); - out.append("\n"); - - out.append(" sample_rate: "); - sprintf(buffer, "%" PRIu32, this->sample_rate); - out.append(buffer); - out.append("\n"); - - out.append(" num_channels: "); - sprintf(buffer, "%" PRIu32, this->num_channels); - out.append(buffer); - out.append("\n"); - - out.append(" purpose: "); - out.append(proto_enum_to_string(this->purpose)); - out.append("\n"); - - out.append(" sample_bytes: "); - sprintf(buffer, "%" PRIu32, this->sample_bytes); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif bool ListEntitiesMediaPlayerResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 6: { @@ -6494,56 +3705,6 @@ void ListEntitiesMediaPlayerResponse::calculate_size(uint32_t &total_size) const ProtoSize::add_repeated_message(total_size, 1, this->supported_formats); ProtoSize::add_uint32_field(total_size, 1, this->device_id, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void ListEntitiesMediaPlayerResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("ListEntitiesMediaPlayerResponse {\n"); - out.append(" object_id: "); - out.append("'").append(this->object_id).append("'"); - out.append("\n"); - - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" name: "); - out.append("'").append(this->name).append("'"); - out.append("\n"); - - out.append(" unique_id: "); - out.append("'").append(this->unique_id).append("'"); - out.append("\n"); - - out.append(" icon: "); - out.append("'").append(this->icon).append("'"); - out.append("\n"); - - out.append(" disabled_by_default: "); - out.append(YESNO(this->disabled_by_default)); - out.append("\n"); - - out.append(" entity_category: "); - out.append(proto_enum_to_string(this->entity_category)); - out.append("\n"); - - out.append(" supports_pause: "); - out.append(YESNO(this->supports_pause)); - out.append("\n"); - - for (const auto &it : this->supported_formats) { - out.append(" supported_formats: "); - it.dump_to(out); - out.append("\n"); - } - - out.append(" device_id: "); - sprintf(buffer, "%" PRIu32, this->device_id); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif bool MediaPlayerStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 2: { @@ -6584,30 +3745,6 @@ void MediaPlayerStateResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_fixed_field<4>(total_size, 1, this->volume != 0.0f, false); ProtoSize::add_bool_field(total_size, 1, this->muted, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void MediaPlayerStateResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("MediaPlayerStateResponse {\n"); - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" state: "); - out.append(proto_enum_to_string(this->state)); - out.append("\n"); - - out.append(" volume: "); - sprintf(buffer, "%g", this->volume); - out.append(buffer); - out.append("\n"); - - out.append(" muted: "); - out.append(YESNO(this->muted)); - out.append("\n"); - out.append("}"); -} -#endif bool MediaPlayerCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 2: { @@ -6684,50 +3821,8 @@ void MediaPlayerCommandRequest::calculate_size(uint32_t &total_size) const { ProtoSize::add_bool_field(total_size, 1, this->has_announcement, false); ProtoSize::add_bool_field(total_size, 1, this->announcement, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void MediaPlayerCommandRequest::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("MediaPlayerCommandRequest {\n"); - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" has_command: "); - out.append(YESNO(this->has_command)); - out.append("\n"); - - out.append(" command: "); - out.append(proto_enum_to_string(this->command)); - out.append("\n"); - - out.append(" has_volume: "); - out.append(YESNO(this->has_volume)); - out.append("\n"); - - out.append(" volume: "); - sprintf(buffer, "%g", this->volume); - out.append(buffer); - out.append("\n"); - - out.append(" has_media_url: "); - out.append(YESNO(this->has_media_url)); - out.append("\n"); - - out.append(" media_url: "); - out.append("'").append(this->media_url).append("'"); - out.append("\n"); - - out.append(" has_announcement: "); - out.append(YESNO(this->has_announcement)); - out.append("\n"); - - out.append(" announcement: "); - out.append(YESNO(this->announcement)); - out.append("\n"); - out.append("}"); -} #endif +#ifdef USE_BLUETOOTH_PROXY bool SubscribeBluetoothLEAdvertisementsRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: { @@ -6744,17 +3839,6 @@ void SubscribeBluetoothLEAdvertisementsRequest::encode(ProtoWriteBuffer buffer) void SubscribeBluetoothLEAdvertisementsRequest::calculate_size(uint32_t &total_size) const { ProtoSize::add_uint32_field(total_size, 1, this->flags, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void SubscribeBluetoothLEAdvertisementsRequest::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("SubscribeBluetoothLEAdvertisementsRequest {\n"); - out.append(" flags: "); - sprintf(buffer, "%" PRIu32, this->flags); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif bool BluetoothServiceData::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 2: { @@ -6784,7 +3868,7 @@ void BluetoothServiceData::encode(ProtoWriteBuffer buffer) const { for (auto &it : this->legacy_data) { buffer.encode_uint32(2, it, true); } - buffer.encode_string(3, this->data); + buffer.encode_bytes(3, reinterpret_cast(this->data.data()), this->data.size()); } void BluetoothServiceData::calculate_size(uint32_t &total_size) const { ProtoSize::add_string_field(total_size, 1, this->uuid, false); @@ -6795,27 +3879,6 @@ void BluetoothServiceData::calculate_size(uint32_t &total_size) const { } ProtoSize::add_string_field(total_size, 1, this->data, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void BluetoothServiceData::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("BluetoothServiceData {\n"); - out.append(" uuid: "); - out.append("'").append(this->uuid).append("'"); - out.append("\n"); - - for (const auto &it : this->legacy_data) { - out.append(" legacy_data: "); - sprintf(buffer, "%" PRIu32, it); - out.append(buffer); - out.append("\n"); - } - - out.append(" data: "); - out.append("'").append(this->data).append("'"); - out.append("\n"); - out.append("}"); -} -#endif bool BluetoothLEAdvertisementResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: { @@ -6858,7 +3921,7 @@ bool BluetoothLEAdvertisementResponse::decode_length(uint32_t field_id, ProtoLen } void BluetoothLEAdvertisementResponse::encode(ProtoWriteBuffer buffer) const { buffer.encode_uint64(1, this->address); - buffer.encode_string(2, this->name); + buffer.encode_bytes(2, reinterpret_cast(this->name.data()), this->name.size()); buffer.encode_sint32(3, this->rssi); for (auto &it : this->service_uuids) { buffer.encode_string(4, it, true); @@ -6884,49 +3947,6 @@ void BluetoothLEAdvertisementResponse::calculate_size(uint32_t &total_size) cons ProtoSize::add_repeated_message(total_size, 1, this->manufacturer_data); ProtoSize::add_uint32_field(total_size, 1, this->address_type, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void BluetoothLEAdvertisementResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("BluetoothLEAdvertisementResponse {\n"); - out.append(" address: "); - sprintf(buffer, "%llu", this->address); - out.append(buffer); - out.append("\n"); - - out.append(" name: "); - out.append("'").append(this->name).append("'"); - out.append("\n"); - - out.append(" rssi: "); - sprintf(buffer, "%" PRId32, this->rssi); - out.append(buffer); - out.append("\n"); - - for (const auto &it : this->service_uuids) { - out.append(" service_uuids: "); - out.append("'").append(it).append("'"); - out.append("\n"); - } - - for (const auto &it : this->service_data) { - out.append(" service_data: "); - it.dump_to(out); - out.append("\n"); - } - - for (const auto &it : this->manufacturer_data) { - out.append(" manufacturer_data: "); - it.dump_to(out); - out.append("\n"); - } - - out.append(" address_type: "); - sprintf(buffer, "%" PRIu32, this->address_type); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif bool BluetoothLERawAdvertisement::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: { @@ -6959,7 +3979,7 @@ void BluetoothLERawAdvertisement::encode(ProtoWriteBuffer buffer) const { buffer.encode_uint64(1, this->address); buffer.encode_sint32(2, this->rssi); buffer.encode_uint32(3, this->address_type); - buffer.encode_string(4, this->data); + buffer.encode_bytes(4, reinterpret_cast(this->data.data()), this->data.size()); } void BluetoothLERawAdvertisement::calculate_size(uint32_t &total_size) const { ProtoSize::add_uint64_field(total_size, 1, this->address, false); @@ -6967,31 +3987,6 @@ void BluetoothLERawAdvertisement::calculate_size(uint32_t &total_size) const { ProtoSize::add_uint32_field(total_size, 1, this->address_type, false); ProtoSize::add_string_field(total_size, 1, this->data, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void BluetoothLERawAdvertisement::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("BluetoothLERawAdvertisement {\n"); - out.append(" address: "); - sprintf(buffer, "%llu", this->address); - out.append(buffer); - out.append("\n"); - - out.append(" rssi: "); - sprintf(buffer, "%" PRId32, this->rssi); - out.append(buffer); - out.append("\n"); - - out.append(" address_type: "); - sprintf(buffer, "%" PRIu32, this->address_type); - out.append(buffer); - out.append("\n"); - - out.append(" data: "); - out.append("'").append(this->data).append("'"); - out.append("\n"); - out.append("}"); -} -#endif bool BluetoothLERawAdvertisementsResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) { switch (field_id) { case 1: { @@ -7010,18 +4005,6 @@ void BluetoothLERawAdvertisementsResponse::encode(ProtoWriteBuffer buffer) const void BluetoothLERawAdvertisementsResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_repeated_message(total_size, 1, this->advertisements); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void BluetoothLERawAdvertisementsResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("BluetoothLERawAdvertisementsResponse {\n"); - for (const auto &it : this->advertisements) { - out.append(" advertisements: "); - it.dump_to(out); - out.append("\n"); - } - out.append("}"); -} -#endif bool BluetoothDeviceRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: { @@ -7056,30 +4039,6 @@ void BluetoothDeviceRequest::calculate_size(uint32_t &total_size) const { ProtoSize::add_bool_field(total_size, 1, this->has_address_type, false); ProtoSize::add_uint32_field(total_size, 1, this->address_type, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void BluetoothDeviceRequest::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("BluetoothDeviceRequest {\n"); - out.append(" address: "); - sprintf(buffer, "%llu", this->address); - out.append(buffer); - out.append("\n"); - - out.append(" request_type: "); - out.append(proto_enum_to_string(this->request_type)); - out.append("\n"); - - out.append(" has_address_type: "); - out.append(YESNO(this->has_address_type)); - out.append("\n"); - - out.append(" address_type: "); - sprintf(buffer, "%" PRIu32, this->address_type); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif bool BluetoothDeviceConnectionResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: { @@ -7114,31 +4073,6 @@ void BluetoothDeviceConnectionResponse::calculate_size(uint32_t &total_size) con ProtoSize::add_uint32_field(total_size, 1, this->mtu, false); ProtoSize::add_int32_field(total_size, 1, this->error, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void BluetoothDeviceConnectionResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("BluetoothDeviceConnectionResponse {\n"); - out.append(" address: "); - sprintf(buffer, "%llu", this->address); - out.append(buffer); - out.append("\n"); - - out.append(" connected: "); - out.append(YESNO(this->connected)); - out.append("\n"); - - out.append(" mtu: "); - sprintf(buffer, "%" PRIu32, this->mtu); - out.append(buffer); - out.append("\n"); - - out.append(" error: "); - sprintf(buffer, "%" PRId32, this->error); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif bool BluetoothGATTGetServicesRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: { @@ -7153,17 +4087,6 @@ void BluetoothGATTGetServicesRequest::encode(ProtoWriteBuffer buffer) const { bu void BluetoothGATTGetServicesRequest::calculate_size(uint32_t &total_size) const { ProtoSize::add_uint64_field(total_size, 1, this->address, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void BluetoothGATTGetServicesRequest::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("BluetoothGATTGetServicesRequest {\n"); - out.append(" address: "); - sprintf(buffer, "%llu", this->address); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif bool BluetoothGATTDescriptor::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: { @@ -7192,24 +4115,6 @@ void BluetoothGATTDescriptor::calculate_size(uint32_t &total_size) const { } ProtoSize::add_uint32_field(total_size, 1, this->handle, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void BluetoothGATTDescriptor::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("BluetoothGATTDescriptor {\n"); - for (const auto &it : this->uuid) { - out.append(" uuid: "); - sprintf(buffer, "%llu", it); - out.append(buffer); - out.append("\n"); - } - - out.append(" handle: "); - sprintf(buffer, "%" PRIu32, this->handle); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif bool BluetoothGATTCharacteristic::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: { @@ -7258,35 +4163,6 @@ void BluetoothGATTCharacteristic::calculate_size(uint32_t &total_size) const { ProtoSize::add_uint32_field(total_size, 1, this->properties, false); ProtoSize::add_repeated_message(total_size, 1, this->descriptors); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void BluetoothGATTCharacteristic::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("BluetoothGATTCharacteristic {\n"); - for (const auto &it : this->uuid) { - out.append(" uuid: "); - sprintf(buffer, "%llu", it); - out.append(buffer); - out.append("\n"); - } - - out.append(" handle: "); - sprintf(buffer, "%" PRIu32, this->handle); - out.append(buffer); - out.append("\n"); - - out.append(" properties: "); - sprintf(buffer, "%" PRIu32, this->properties); - out.append(buffer); - out.append("\n"); - - for (const auto &it : this->descriptors) { - out.append(" descriptors: "); - it.dump_to(out); - out.append("\n"); - } - out.append("}"); -} -#endif bool BluetoothGATTService::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: { @@ -7329,30 +4205,6 @@ void BluetoothGATTService::calculate_size(uint32_t &total_size) const { ProtoSize::add_uint32_field(total_size, 1, this->handle, false); ProtoSize::add_repeated_message(total_size, 1, this->characteristics); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void BluetoothGATTService::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("BluetoothGATTService {\n"); - for (const auto &it : this->uuid) { - out.append(" uuid: "); - sprintf(buffer, "%llu", it); - out.append(buffer); - out.append("\n"); - } - - out.append(" handle: "); - sprintf(buffer, "%" PRIu32, this->handle); - out.append(buffer); - out.append("\n"); - - for (const auto &it : this->characteristics) { - out.append(" characteristics: "); - it.dump_to(out); - out.append("\n"); - } - out.append("}"); -} -#endif bool BluetoothGATTGetServicesResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: { @@ -7383,23 +4235,6 @@ void BluetoothGATTGetServicesResponse::calculate_size(uint32_t &total_size) cons ProtoSize::add_uint64_field(total_size, 1, this->address, false); ProtoSize::add_repeated_message(total_size, 1, this->services); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void BluetoothGATTGetServicesResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("BluetoothGATTGetServicesResponse {\n"); - out.append(" address: "); - sprintf(buffer, "%llu", this->address); - out.append(buffer); - out.append("\n"); - - for (const auto &it : this->services) { - out.append(" services: "); - it.dump_to(out); - out.append("\n"); - } - out.append("}"); -} -#endif bool BluetoothGATTGetServicesDoneResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: { @@ -7416,17 +4251,6 @@ void BluetoothGATTGetServicesDoneResponse::encode(ProtoWriteBuffer buffer) const void BluetoothGATTGetServicesDoneResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_uint64_field(total_size, 1, this->address, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void BluetoothGATTGetServicesDoneResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("BluetoothGATTGetServicesDoneResponse {\n"); - out.append(" address: "); - sprintf(buffer, "%llu", this->address); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif bool BluetoothGATTReadRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: { @@ -7449,22 +4273,6 @@ void BluetoothGATTReadRequest::calculate_size(uint32_t &total_size) const { ProtoSize::add_uint64_field(total_size, 1, this->address, false); ProtoSize::add_uint32_field(total_size, 1, this->handle, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void BluetoothGATTReadRequest::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("BluetoothGATTReadRequest {\n"); - out.append(" address: "); - sprintf(buffer, "%llu", this->address); - out.append(buffer); - out.append("\n"); - - out.append(" handle: "); - sprintf(buffer, "%" PRIu32, this->handle); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif bool BluetoothGATTReadResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: { @@ -7492,33 +4300,13 @@ bool BluetoothGATTReadResponse::decode_length(uint32_t field_id, ProtoLengthDeli void BluetoothGATTReadResponse::encode(ProtoWriteBuffer buffer) const { buffer.encode_uint64(1, this->address); buffer.encode_uint32(2, this->handle); - buffer.encode_string(3, this->data); + buffer.encode_bytes(3, reinterpret_cast(this->data.data()), this->data.size()); } void BluetoothGATTReadResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_uint64_field(total_size, 1, this->address, false); ProtoSize::add_uint32_field(total_size, 1, this->handle, false); ProtoSize::add_string_field(total_size, 1, this->data, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void BluetoothGATTReadResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("BluetoothGATTReadResponse {\n"); - out.append(" address: "); - sprintf(buffer, "%llu", this->address); - out.append(buffer); - out.append("\n"); - - out.append(" handle: "); - sprintf(buffer, "%" PRIu32, this->handle); - out.append(buffer); - out.append("\n"); - - out.append(" data: "); - out.append("'").append(this->data).append("'"); - out.append("\n"); - out.append("}"); -} -#endif bool BluetoothGATTWriteRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: { @@ -7551,7 +4339,7 @@ void BluetoothGATTWriteRequest::encode(ProtoWriteBuffer buffer) const { buffer.encode_uint64(1, this->address); buffer.encode_uint32(2, this->handle); buffer.encode_bool(3, this->response); - buffer.encode_string(4, this->data); + buffer.encode_bytes(4, reinterpret_cast(this->data.data()), this->data.size()); } void BluetoothGATTWriteRequest::calculate_size(uint32_t &total_size) const { ProtoSize::add_uint64_field(total_size, 1, this->address, false); @@ -7559,30 +4347,6 @@ void BluetoothGATTWriteRequest::calculate_size(uint32_t &total_size) const { ProtoSize::add_bool_field(total_size, 1, this->response, false); ProtoSize::add_string_field(total_size, 1, this->data, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void BluetoothGATTWriteRequest::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("BluetoothGATTWriteRequest {\n"); - out.append(" address: "); - sprintf(buffer, "%llu", this->address); - out.append(buffer); - out.append("\n"); - - out.append(" handle: "); - sprintf(buffer, "%" PRIu32, this->handle); - out.append(buffer); - out.append("\n"); - - out.append(" response: "); - out.append(YESNO(this->response)); - out.append("\n"); - - out.append(" data: "); - out.append("'").append(this->data).append("'"); - out.append("\n"); - out.append("}"); -} -#endif bool BluetoothGATTReadDescriptorRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: { @@ -7605,22 +4369,6 @@ void BluetoothGATTReadDescriptorRequest::calculate_size(uint32_t &total_size) co ProtoSize::add_uint64_field(total_size, 1, this->address, false); ProtoSize::add_uint32_field(total_size, 1, this->handle, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void BluetoothGATTReadDescriptorRequest::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("BluetoothGATTReadDescriptorRequest {\n"); - out.append(" address: "); - sprintf(buffer, "%llu", this->address); - out.append(buffer); - out.append("\n"); - - out.append(" handle: "); - sprintf(buffer, "%" PRIu32, this->handle); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif bool BluetoothGATTWriteDescriptorRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: { @@ -7648,33 +4396,13 @@ bool BluetoothGATTWriteDescriptorRequest::decode_length(uint32_t field_id, Proto void BluetoothGATTWriteDescriptorRequest::encode(ProtoWriteBuffer buffer) const { buffer.encode_uint64(1, this->address); buffer.encode_uint32(2, this->handle); - buffer.encode_string(3, this->data); + buffer.encode_bytes(3, reinterpret_cast(this->data.data()), this->data.size()); } void BluetoothGATTWriteDescriptorRequest::calculate_size(uint32_t &total_size) const { ProtoSize::add_uint64_field(total_size, 1, this->address, false); ProtoSize::add_uint32_field(total_size, 1, this->handle, false); ProtoSize::add_string_field(total_size, 1, this->data, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void BluetoothGATTWriteDescriptorRequest::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("BluetoothGATTWriteDescriptorRequest {\n"); - out.append(" address: "); - sprintf(buffer, "%llu", this->address); - out.append(buffer); - out.append("\n"); - - out.append(" handle: "); - sprintf(buffer, "%" PRIu32, this->handle); - out.append(buffer); - out.append("\n"); - - out.append(" data: "); - out.append("'").append(this->data).append("'"); - out.append("\n"); - out.append("}"); -} -#endif bool BluetoothGATTNotifyRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: { @@ -7703,26 +4431,6 @@ void BluetoothGATTNotifyRequest::calculate_size(uint32_t &total_size) const { ProtoSize::add_uint32_field(total_size, 1, this->handle, false); ProtoSize::add_bool_field(total_size, 1, this->enable, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void BluetoothGATTNotifyRequest::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("BluetoothGATTNotifyRequest {\n"); - out.append(" address: "); - sprintf(buffer, "%llu", this->address); - out.append(buffer); - out.append("\n"); - - out.append(" handle: "); - sprintf(buffer, "%" PRIu32, this->handle); - out.append(buffer); - out.append("\n"); - - out.append(" enable: "); - out.append(YESNO(this->enable)); - out.append("\n"); - out.append("}"); -} -#endif bool BluetoothGATTNotifyDataResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: { @@ -7750,38 +4458,13 @@ bool BluetoothGATTNotifyDataResponse::decode_length(uint32_t field_id, ProtoLeng void BluetoothGATTNotifyDataResponse::encode(ProtoWriteBuffer buffer) const { buffer.encode_uint64(1, this->address); buffer.encode_uint32(2, this->handle); - buffer.encode_string(3, this->data); + buffer.encode_bytes(3, reinterpret_cast(this->data.data()), this->data.size()); } void BluetoothGATTNotifyDataResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_uint64_field(total_size, 1, this->address, false); ProtoSize::add_uint32_field(total_size, 1, this->handle, false); ProtoSize::add_string_field(total_size, 1, this->data, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void BluetoothGATTNotifyDataResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("BluetoothGATTNotifyDataResponse {\n"); - out.append(" address: "); - sprintf(buffer, "%llu", this->address); - out.append(buffer); - out.append("\n"); - - out.append(" handle: "); - sprintf(buffer, "%" PRIu32, this->handle); - out.append(buffer); - out.append("\n"); - - out.append(" data: "); - out.append("'").append(this->data).append("'"); - out.append("\n"); - out.append("}"); -} -#endif -#ifdef HAS_PROTO_MESSAGE_DUMP -void SubscribeBluetoothConnectionsFreeRequest::dump_to(std::string &out) const { - out.append("SubscribeBluetoothConnectionsFreeRequest {}"); -} -#endif bool BluetoothConnectionsFreeResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: { @@ -7816,29 +4499,6 @@ void BluetoothConnectionsFreeResponse::calculate_size(uint32_t &total_size) cons } } } -#ifdef HAS_PROTO_MESSAGE_DUMP -void BluetoothConnectionsFreeResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("BluetoothConnectionsFreeResponse {\n"); - out.append(" free: "); - sprintf(buffer, "%" PRIu32, this->free); - out.append(buffer); - out.append("\n"); - - out.append(" limit: "); - sprintf(buffer, "%" PRIu32, this->limit); - out.append(buffer); - out.append("\n"); - - for (const auto &it : this->allocated) { - out.append(" allocated: "); - sprintf(buffer, "%llu", it); - out.append(buffer); - out.append("\n"); - } - out.append("}"); -} -#endif bool BluetoothGATTErrorResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: { @@ -7867,27 +4527,6 @@ void BluetoothGATTErrorResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_uint32_field(total_size, 1, this->handle, false); ProtoSize::add_int32_field(total_size, 1, this->error, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void BluetoothGATTErrorResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("BluetoothGATTErrorResponse {\n"); - out.append(" address: "); - sprintf(buffer, "%llu", this->address); - out.append(buffer); - out.append("\n"); - - out.append(" handle: "); - sprintf(buffer, "%" PRIu32, this->handle); - out.append(buffer); - out.append("\n"); - - out.append(" error: "); - sprintf(buffer, "%" PRId32, this->error); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif bool BluetoothGATTWriteResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: { @@ -7910,22 +4549,6 @@ void BluetoothGATTWriteResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_uint64_field(total_size, 1, this->address, false); ProtoSize::add_uint32_field(total_size, 1, this->handle, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void BluetoothGATTWriteResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("BluetoothGATTWriteResponse {\n"); - out.append(" address: "); - sprintf(buffer, "%llu", this->address); - out.append(buffer); - out.append("\n"); - - out.append(" handle: "); - sprintf(buffer, "%" PRIu32, this->handle); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif bool BluetoothGATTNotifyResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: { @@ -7948,22 +4571,6 @@ void BluetoothGATTNotifyResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_uint64_field(total_size, 1, this->address, false); ProtoSize::add_uint32_field(total_size, 1, this->handle, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void BluetoothGATTNotifyResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("BluetoothGATTNotifyResponse {\n"); - out.append(" address: "); - sprintf(buffer, "%llu", this->address); - out.append(buffer); - out.append("\n"); - - out.append(" handle: "); - sprintf(buffer, "%" PRIu32, this->handle); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif bool BluetoothDevicePairingResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: { @@ -7992,26 +4599,6 @@ void BluetoothDevicePairingResponse::calculate_size(uint32_t &total_size) const ProtoSize::add_bool_field(total_size, 1, this->paired, false); ProtoSize::add_int32_field(total_size, 1, this->error, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void BluetoothDevicePairingResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("BluetoothDevicePairingResponse {\n"); - out.append(" address: "); - sprintf(buffer, "%llu", this->address); - out.append(buffer); - out.append("\n"); - - out.append(" paired: "); - out.append(YESNO(this->paired)); - out.append("\n"); - - out.append(" error: "); - sprintf(buffer, "%" PRId32, this->error); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif bool BluetoothDeviceUnpairingResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: { @@ -8040,31 +4627,6 @@ void BluetoothDeviceUnpairingResponse::calculate_size(uint32_t &total_size) cons ProtoSize::add_bool_field(total_size, 1, this->success, false); ProtoSize::add_int32_field(total_size, 1, this->error, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void BluetoothDeviceUnpairingResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("BluetoothDeviceUnpairingResponse {\n"); - out.append(" address: "); - sprintf(buffer, "%llu", this->address); - out.append(buffer); - out.append("\n"); - - out.append(" success: "); - out.append(YESNO(this->success)); - out.append("\n"); - - out.append(" error: "); - sprintf(buffer, "%" PRId32, this->error); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif -#ifdef HAS_PROTO_MESSAGE_DUMP -void UnsubscribeBluetoothLEAdvertisementsRequest::dump_to(std::string &out) const { - out.append("UnsubscribeBluetoothLEAdvertisementsRequest {}"); -} -#endif bool BluetoothDeviceClearCacheResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: { @@ -8093,26 +4655,6 @@ void BluetoothDeviceClearCacheResponse::calculate_size(uint32_t &total_size) con ProtoSize::add_bool_field(total_size, 1, this->success, false); ProtoSize::add_int32_field(total_size, 1, this->error, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void BluetoothDeviceClearCacheResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("BluetoothDeviceClearCacheResponse {\n"); - out.append(" address: "); - sprintf(buffer, "%llu", this->address); - out.append(buffer); - out.append("\n"); - - out.append(" success: "); - out.append(YESNO(this->success)); - out.append("\n"); - - out.append(" error: "); - sprintf(buffer, "%" PRId32, this->error); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif bool BluetoothScannerStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: { @@ -8135,20 +4677,6 @@ void BluetoothScannerStateResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_enum_field(total_size, 1, static_cast(this->state), false); ProtoSize::add_enum_field(total_size, 1, static_cast(this->mode), false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void BluetoothScannerStateResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("BluetoothScannerStateResponse {\n"); - out.append(" state: "); - out.append(proto_enum_to_string(this->state)); - out.append("\n"); - - out.append(" mode: "); - out.append(proto_enum_to_string(this->mode)); - out.append("\n"); - out.append("}"); -} -#endif bool BluetoothScannerSetModeRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: { @@ -8165,16 +4693,8 @@ void BluetoothScannerSetModeRequest::encode(ProtoWriteBuffer buffer) const { void BluetoothScannerSetModeRequest::calculate_size(uint32_t &total_size) const { ProtoSize::add_enum_field(total_size, 1, static_cast(this->mode), false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void BluetoothScannerSetModeRequest::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("BluetoothScannerSetModeRequest {\n"); - out.append(" mode: "); - out.append(proto_enum_to_string(this->mode)); - out.append("\n"); - out.append("}"); -} #endif +#ifdef USE_VOICE_ASSISTANT bool SubscribeVoiceAssistantRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: { @@ -8197,21 +4717,6 @@ void SubscribeVoiceAssistantRequest::calculate_size(uint32_t &total_size) const ProtoSize::add_bool_field(total_size, 1, this->subscribe, false); ProtoSize::add_uint32_field(total_size, 1, this->flags, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void SubscribeVoiceAssistantRequest::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("SubscribeVoiceAssistantRequest {\n"); - out.append(" subscribe: "); - out.append(YESNO(this->subscribe)); - out.append("\n"); - - out.append(" flags: "); - sprintf(buffer, "%" PRIu32, this->flags); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif bool VoiceAssistantAudioSettings::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: { @@ -8246,27 +4751,6 @@ void VoiceAssistantAudioSettings::calculate_size(uint32_t &total_size) const { ProtoSize::add_uint32_field(total_size, 1, this->auto_gain, false); ProtoSize::add_fixed_field<4>(total_size, 1, this->volume_multiplier != 0.0f, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void VoiceAssistantAudioSettings::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("VoiceAssistantAudioSettings {\n"); - out.append(" noise_suppression_level: "); - sprintf(buffer, "%" PRIu32, this->noise_suppression_level); - out.append(buffer); - out.append("\n"); - - out.append(" auto_gain: "); - sprintf(buffer, "%" PRIu32, this->auto_gain); - out.append(buffer); - out.append("\n"); - - out.append(" volume_multiplier: "); - sprintf(buffer, "%g", this->volume_multiplier); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif bool VoiceAssistantRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: { @@ -8313,33 +4797,6 @@ void VoiceAssistantRequest::calculate_size(uint32_t &total_size) const { ProtoSize::add_message_object(total_size, 1, this->audio_settings, false); ProtoSize::add_string_field(total_size, 1, this->wake_word_phrase, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void VoiceAssistantRequest::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("VoiceAssistantRequest {\n"); - out.append(" start: "); - out.append(YESNO(this->start)); - out.append("\n"); - - out.append(" conversation_id: "); - out.append("'").append(this->conversation_id).append("'"); - out.append("\n"); - - out.append(" flags: "); - sprintf(buffer, "%" PRIu32, this->flags); - out.append(buffer); - out.append("\n"); - - out.append(" audio_settings: "); - this->audio_settings.dump_to(out); - out.append("\n"); - - out.append(" wake_word_phrase: "); - out.append("'").append(this->wake_word_phrase).append("'"); - out.append("\n"); - out.append("}"); -} -#endif bool VoiceAssistantResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: { @@ -8362,21 +4819,6 @@ void VoiceAssistantResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_uint32_field(total_size, 1, this->port, false); ProtoSize::add_bool_field(total_size, 1, this->error, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void VoiceAssistantResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("VoiceAssistantResponse {\n"); - out.append(" port: "); - sprintf(buffer, "%" PRIu32, this->port); - out.append(buffer); - out.append("\n"); - - out.append(" error: "); - out.append(YESNO(this->error)); - out.append("\n"); - out.append("}"); -} -#endif bool VoiceAssistantEventData::decode_length(uint32_t field_id, ProtoLengthDelimited value) { switch (field_id) { case 1: { @@ -8399,20 +4841,6 @@ void VoiceAssistantEventData::calculate_size(uint32_t &total_size) const { ProtoSize::add_string_field(total_size, 1, this->name, false); ProtoSize::add_string_field(total_size, 1, this->value, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void VoiceAssistantEventData::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("VoiceAssistantEventData {\n"); - out.append(" name: "); - out.append("'").append(this->name).append("'"); - out.append("\n"); - - out.append(" value: "); - out.append("'").append(this->value).append("'"); - out.append("\n"); - out.append("}"); -} -#endif bool VoiceAssistantEventResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: { @@ -8443,22 +4871,6 @@ void VoiceAssistantEventResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_enum_field(total_size, 1, static_cast(this->event_type), false); ProtoSize::add_repeated_message(total_size, 1, this->data); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void VoiceAssistantEventResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("VoiceAssistantEventResponse {\n"); - out.append(" event_type: "); - out.append(proto_enum_to_string(this->event_type)); - out.append("\n"); - - for (const auto &it : this->data) { - out.append(" data: "); - it.dump_to(out); - out.append("\n"); - } - out.append("}"); -} -#endif bool VoiceAssistantAudio::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 2: { @@ -8480,27 +4892,13 @@ bool VoiceAssistantAudio::decode_length(uint32_t field_id, ProtoLengthDelimited } } void VoiceAssistantAudio::encode(ProtoWriteBuffer buffer) const { - buffer.encode_string(1, this->data); + buffer.encode_bytes(1, reinterpret_cast(this->data.data()), this->data.size()); buffer.encode_bool(2, this->end); } void VoiceAssistantAudio::calculate_size(uint32_t &total_size) const { ProtoSize::add_string_field(total_size, 1, this->data, false); ProtoSize::add_bool_field(total_size, 1, this->end, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void VoiceAssistantAudio::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("VoiceAssistantAudio {\n"); - out.append(" data: "); - out.append("'").append(this->data).append("'"); - out.append("\n"); - - out.append(" end: "); - out.append(YESNO(this->end)); - out.append("\n"); - out.append("}"); -} -#endif bool VoiceAssistantTimerEventResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: { @@ -8553,38 +4951,6 @@ void VoiceAssistantTimerEventResponse::calculate_size(uint32_t &total_size) cons ProtoSize::add_uint32_field(total_size, 1, this->seconds_left, false); ProtoSize::add_bool_field(total_size, 1, this->is_active, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void VoiceAssistantTimerEventResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("VoiceAssistantTimerEventResponse {\n"); - out.append(" event_type: "); - out.append(proto_enum_to_string(this->event_type)); - out.append("\n"); - - out.append(" timer_id: "); - out.append("'").append(this->timer_id).append("'"); - out.append("\n"); - - out.append(" name: "); - out.append("'").append(this->name).append("'"); - out.append("\n"); - - out.append(" total_seconds: "); - sprintf(buffer, "%" PRIu32, this->total_seconds); - out.append(buffer); - out.append("\n"); - - out.append(" seconds_left: "); - sprintf(buffer, "%" PRIu32, this->seconds_left); - out.append(buffer); - out.append("\n"); - - out.append(" is_active: "); - out.append(YESNO(this->is_active)); - out.append("\n"); - out.append("}"); -} -#endif bool VoiceAssistantAnnounceRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 4: { @@ -8625,28 +4991,6 @@ void VoiceAssistantAnnounceRequest::calculate_size(uint32_t &total_size) const { ProtoSize::add_string_field(total_size, 1, this->preannounce_media_id, false); ProtoSize::add_bool_field(total_size, 1, this->start_conversation, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void VoiceAssistantAnnounceRequest::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("VoiceAssistantAnnounceRequest {\n"); - out.append(" media_id: "); - out.append("'").append(this->media_id).append("'"); - out.append("\n"); - - out.append(" text: "); - out.append("'").append(this->text).append("'"); - out.append("\n"); - - out.append(" preannounce_media_id: "); - out.append("'").append(this->preannounce_media_id).append("'"); - out.append("\n"); - - out.append(" start_conversation: "); - out.append(YESNO(this->start_conversation)); - out.append("\n"); - out.append("}"); -} -#endif bool VoiceAssistantAnnounceFinished::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: { @@ -8661,16 +5005,6 @@ void VoiceAssistantAnnounceFinished::encode(ProtoWriteBuffer buffer) const { buf void VoiceAssistantAnnounceFinished::calculate_size(uint32_t &total_size) const { ProtoSize::add_bool_field(total_size, 1, this->success, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void VoiceAssistantAnnounceFinished::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("VoiceAssistantAnnounceFinished {\n"); - out.append(" success: "); - out.append(YESNO(this->success)); - out.append("\n"); - out.append("}"); -} -#endif bool VoiceAssistantWakeWord::decode_length(uint32_t field_id, ProtoLengthDelimited value) { switch (field_id) { case 1: { @@ -8705,31 +5039,6 @@ void VoiceAssistantWakeWord::calculate_size(uint32_t &total_size) const { } } } -#ifdef HAS_PROTO_MESSAGE_DUMP -void VoiceAssistantWakeWord::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("VoiceAssistantWakeWord {\n"); - out.append(" id: "); - out.append("'").append(this->id).append("'"); - out.append("\n"); - - out.append(" wake_word: "); - out.append("'").append(this->wake_word).append("'"); - out.append("\n"); - - for (const auto &it : this->trained_languages) { - out.append(" trained_languages: "); - out.append("'").append(it).append("'"); - out.append("\n"); - } - out.append("}"); -} -#endif -#ifdef HAS_PROTO_MESSAGE_DUMP -void VoiceAssistantConfigurationRequest::dump_to(std::string &out) const { - out.append("VoiceAssistantConfigurationRequest {}"); -} -#endif bool VoiceAssistantConfigurationResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 3: { @@ -8772,29 +5081,6 @@ void VoiceAssistantConfigurationResponse::calculate_size(uint32_t &total_size) c } ProtoSize::add_uint32_field(total_size, 1, this->max_active_wake_words, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void VoiceAssistantConfigurationResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("VoiceAssistantConfigurationResponse {\n"); - for (const auto &it : this->available_wake_words) { - out.append(" available_wake_words: "); - it.dump_to(out); - out.append("\n"); - } - - for (const auto &it : this->active_wake_words) { - out.append(" active_wake_words: "); - out.append("'").append(it).append("'"); - out.append("\n"); - } - - out.append(" max_active_wake_words: "); - sprintf(buffer, "%" PRIu32, this->max_active_wake_words); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif bool VoiceAssistantSetConfiguration::decode_length(uint32_t field_id, ProtoLengthDelimited value) { switch (field_id) { case 1: { @@ -8817,18 +5103,8 @@ void VoiceAssistantSetConfiguration::calculate_size(uint32_t &total_size) const } } } -#ifdef HAS_PROTO_MESSAGE_DUMP -void VoiceAssistantSetConfiguration::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("VoiceAssistantSetConfiguration {\n"); - for (const auto &it : this->active_wake_words) { - out.append(" active_wake_words: "); - out.append("'").append(it).append("'"); - out.append("\n"); - } - out.append("}"); -} #endif +#ifdef USE_ALARM_CONTROL_PANEL bool ListEntitiesAlarmControlPanelResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 6: { @@ -8917,59 +5193,6 @@ void ListEntitiesAlarmControlPanelResponse::calculate_size(uint32_t &total_size) ProtoSize::add_bool_field(total_size, 1, this->requires_code_to_arm, false); ProtoSize::add_uint32_field(total_size, 1, this->device_id, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void ListEntitiesAlarmControlPanelResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("ListEntitiesAlarmControlPanelResponse {\n"); - out.append(" object_id: "); - out.append("'").append(this->object_id).append("'"); - out.append("\n"); - - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" name: "); - out.append("'").append(this->name).append("'"); - out.append("\n"); - - out.append(" unique_id: "); - out.append("'").append(this->unique_id).append("'"); - out.append("\n"); - - out.append(" icon: "); - out.append("'").append(this->icon).append("'"); - out.append("\n"); - - out.append(" disabled_by_default: "); - out.append(YESNO(this->disabled_by_default)); - out.append("\n"); - - out.append(" entity_category: "); - out.append(proto_enum_to_string(this->entity_category)); - out.append("\n"); - - out.append(" supported_features: "); - sprintf(buffer, "%" PRIu32, this->supported_features); - out.append(buffer); - out.append("\n"); - - out.append(" requires_code: "); - out.append(YESNO(this->requires_code)); - out.append("\n"); - - out.append(" requires_code_to_arm: "); - out.append(YESNO(this->requires_code_to_arm)); - out.append("\n"); - - out.append(" device_id: "); - sprintf(buffer, "%" PRIu32, this->device_id); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif bool AlarmControlPanelStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 2: { @@ -8998,21 +5221,6 @@ void AlarmControlPanelStateResponse::calculate_size(uint32_t &total_size) const ProtoSize::add_fixed_field<4>(total_size, 1, this->key != 0, false); ProtoSize::add_enum_field(total_size, 1, static_cast(this->state), false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void AlarmControlPanelStateResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("AlarmControlPanelStateResponse {\n"); - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" state: "); - out.append(proto_enum_to_string(this->state)); - out.append("\n"); - out.append("}"); -} -#endif bool AlarmControlPanelCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 2: { @@ -9053,25 +5261,8 @@ void AlarmControlPanelCommandRequest::calculate_size(uint32_t &total_size) const ProtoSize::add_enum_field(total_size, 1, static_cast(this->command), false); ProtoSize::add_string_field(total_size, 1, this->code, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void AlarmControlPanelCommandRequest::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("AlarmControlPanelCommandRequest {\n"); - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" command: "); - out.append(proto_enum_to_string(this->command)); - out.append("\n"); - - out.append(" code: "); - out.append("'").append(this->code).append("'"); - out.append("\n"); - out.append("}"); -} #endif +#ifdef USE_TEXT bool ListEntitiesTextResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 6: { @@ -9166,64 +5357,6 @@ void ListEntitiesTextResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_enum_field(total_size, 1, static_cast(this->mode), false); ProtoSize::add_uint32_field(total_size, 1, this->device_id, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void ListEntitiesTextResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("ListEntitiesTextResponse {\n"); - out.append(" object_id: "); - out.append("'").append(this->object_id).append("'"); - out.append("\n"); - - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" name: "); - out.append("'").append(this->name).append("'"); - out.append("\n"); - - out.append(" unique_id: "); - out.append("'").append(this->unique_id).append("'"); - out.append("\n"); - - out.append(" icon: "); - out.append("'").append(this->icon).append("'"); - out.append("\n"); - - out.append(" disabled_by_default: "); - out.append(YESNO(this->disabled_by_default)); - out.append("\n"); - - out.append(" entity_category: "); - out.append(proto_enum_to_string(this->entity_category)); - out.append("\n"); - - out.append(" min_length: "); - sprintf(buffer, "%" PRIu32, this->min_length); - out.append(buffer); - out.append("\n"); - - out.append(" max_length: "); - sprintf(buffer, "%" PRIu32, this->max_length); - out.append(buffer); - out.append("\n"); - - out.append(" pattern: "); - out.append("'").append(this->pattern).append("'"); - out.append("\n"); - - out.append(" mode: "); - out.append(proto_enum_to_string(this->mode)); - out.append("\n"); - - out.append(" device_id: "); - sprintf(buffer, "%" PRIu32, this->device_id); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif bool TextStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 3: { @@ -9264,25 +5397,6 @@ void TextStateResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_string_field(total_size, 1, this->state, false); ProtoSize::add_bool_field(total_size, 1, this->missing_state, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void TextStateResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("TextStateResponse {\n"); - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" state: "); - out.append("'").append(this->state).append("'"); - out.append("\n"); - - out.append(" missing_state: "); - out.append(YESNO(this->missing_state)); - out.append("\n"); - out.append("}"); -} -#endif bool TextCommandRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) { switch (field_id) { case 2: { @@ -9311,21 +5425,8 @@ void TextCommandRequest::calculate_size(uint32_t &total_size) const { ProtoSize::add_fixed_field<4>(total_size, 1, this->key != 0, false); ProtoSize::add_string_field(total_size, 1, this->state, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void TextCommandRequest::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("TextCommandRequest {\n"); - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" state: "); - out.append("'").append(this->state).append("'"); - out.append("\n"); - out.append("}"); -} #endif +#ifdef USE_DATETIME_DATE bool ListEntitiesDateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 6: { @@ -9396,46 +5497,6 @@ void ListEntitiesDateResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_enum_field(total_size, 1, static_cast(this->entity_category), false); ProtoSize::add_uint32_field(total_size, 1, this->device_id, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void ListEntitiesDateResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("ListEntitiesDateResponse {\n"); - out.append(" object_id: "); - out.append("'").append(this->object_id).append("'"); - out.append("\n"); - - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" name: "); - out.append("'").append(this->name).append("'"); - out.append("\n"); - - out.append(" unique_id: "); - out.append("'").append(this->unique_id).append("'"); - out.append("\n"); - - out.append(" icon: "); - out.append("'").append(this->icon).append("'"); - out.append("\n"); - - out.append(" disabled_by_default: "); - out.append(YESNO(this->disabled_by_default)); - out.append("\n"); - - out.append(" entity_category: "); - out.append(proto_enum_to_string(this->entity_category)); - out.append("\n"); - - out.append(" device_id: "); - sprintf(buffer, "%" PRIu32, this->device_id); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif bool DateStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 2: { @@ -9482,36 +5543,6 @@ void DateStateResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_uint32_field(total_size, 1, this->month, false); ProtoSize::add_uint32_field(total_size, 1, this->day, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void DateStateResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("DateStateResponse {\n"); - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" missing_state: "); - out.append(YESNO(this->missing_state)); - out.append("\n"); - - out.append(" year: "); - sprintf(buffer, "%" PRIu32, this->year); - out.append(buffer); - out.append("\n"); - - out.append(" month: "); - sprintf(buffer, "%" PRIu32, this->month); - out.append(buffer); - out.append("\n"); - - out.append(" day: "); - sprintf(buffer, "%" PRIu32, this->day); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif bool DateCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 2: { @@ -9552,32 +5583,8 @@ void DateCommandRequest::calculate_size(uint32_t &total_size) const { ProtoSize::add_uint32_field(total_size, 1, this->month, false); ProtoSize::add_uint32_field(total_size, 1, this->day, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void DateCommandRequest::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("DateCommandRequest {\n"); - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" year: "); - sprintf(buffer, "%" PRIu32, this->year); - out.append(buffer); - out.append("\n"); - - out.append(" month: "); - sprintf(buffer, "%" PRIu32, this->month); - out.append(buffer); - out.append("\n"); - - out.append(" day: "); - sprintf(buffer, "%" PRIu32, this->day); - out.append(buffer); - out.append("\n"); - out.append("}"); -} #endif +#ifdef USE_DATETIME_TIME bool ListEntitiesTimeResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 6: { @@ -9648,46 +5655,6 @@ void ListEntitiesTimeResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_enum_field(total_size, 1, static_cast(this->entity_category), false); ProtoSize::add_uint32_field(total_size, 1, this->device_id, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void ListEntitiesTimeResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("ListEntitiesTimeResponse {\n"); - out.append(" object_id: "); - out.append("'").append(this->object_id).append("'"); - out.append("\n"); - - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" name: "); - out.append("'").append(this->name).append("'"); - out.append("\n"); - - out.append(" unique_id: "); - out.append("'").append(this->unique_id).append("'"); - out.append("\n"); - - out.append(" icon: "); - out.append("'").append(this->icon).append("'"); - out.append("\n"); - - out.append(" disabled_by_default: "); - out.append(YESNO(this->disabled_by_default)); - out.append("\n"); - - out.append(" entity_category: "); - out.append(proto_enum_to_string(this->entity_category)); - out.append("\n"); - - out.append(" device_id: "); - sprintf(buffer, "%" PRIu32, this->device_id); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif bool TimeStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 2: { @@ -9734,36 +5701,6 @@ void TimeStateResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_uint32_field(total_size, 1, this->minute, false); ProtoSize::add_uint32_field(total_size, 1, this->second, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void TimeStateResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("TimeStateResponse {\n"); - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" missing_state: "); - out.append(YESNO(this->missing_state)); - out.append("\n"); - - out.append(" hour: "); - sprintf(buffer, "%" PRIu32, this->hour); - out.append(buffer); - out.append("\n"); - - out.append(" minute: "); - sprintf(buffer, "%" PRIu32, this->minute); - out.append(buffer); - out.append("\n"); - - out.append(" second: "); - sprintf(buffer, "%" PRIu32, this->second); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif bool TimeCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 2: { @@ -9804,32 +5741,8 @@ void TimeCommandRequest::calculate_size(uint32_t &total_size) const { ProtoSize::add_uint32_field(total_size, 1, this->minute, false); ProtoSize::add_uint32_field(total_size, 1, this->second, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void TimeCommandRequest::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("TimeCommandRequest {\n"); - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" hour: "); - sprintf(buffer, "%" PRIu32, this->hour); - out.append(buffer); - out.append("\n"); - - out.append(" minute: "); - sprintf(buffer, "%" PRIu32, this->minute); - out.append(buffer); - out.append("\n"); - - out.append(" second: "); - sprintf(buffer, "%" PRIu32, this->second); - out.append(buffer); - out.append("\n"); - out.append("}"); -} #endif +#ifdef USE_EVENT bool ListEntitiesEventResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 6: { @@ -9918,56 +5831,6 @@ void ListEntitiesEventResponse::calculate_size(uint32_t &total_size) const { } ProtoSize::add_uint32_field(total_size, 1, this->device_id, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void ListEntitiesEventResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("ListEntitiesEventResponse {\n"); - out.append(" object_id: "); - out.append("'").append(this->object_id).append("'"); - out.append("\n"); - - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" name: "); - out.append("'").append(this->name).append("'"); - out.append("\n"); - - out.append(" unique_id: "); - out.append("'").append(this->unique_id).append("'"); - out.append("\n"); - - out.append(" icon: "); - out.append("'").append(this->icon).append("'"); - out.append("\n"); - - out.append(" disabled_by_default: "); - out.append(YESNO(this->disabled_by_default)); - out.append("\n"); - - out.append(" entity_category: "); - out.append(proto_enum_to_string(this->entity_category)); - out.append("\n"); - - out.append(" device_class: "); - out.append("'").append(this->device_class).append("'"); - out.append("\n"); - - for (const auto &it : this->event_types) { - out.append(" event_types: "); - out.append("'").append(it).append("'"); - out.append("\n"); - } - - out.append(" device_id: "); - sprintf(buffer, "%" PRIu32, this->device_id); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif bool EventResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) { switch (field_id) { case 2: { @@ -9996,21 +5859,8 @@ void EventResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_fixed_field<4>(total_size, 1, this->key != 0, false); ProtoSize::add_string_field(total_size, 1, this->event_type, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void EventResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("EventResponse {\n"); - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" event_type: "); - out.append("'").append(this->event_type).append("'"); - out.append("\n"); - out.append("}"); -} #endif +#ifdef USE_VALVE bool ListEntitiesValveResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 6: { @@ -10105,62 +5955,6 @@ void ListEntitiesValveResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_bool_field(total_size, 1, this->supports_stop, false); ProtoSize::add_uint32_field(total_size, 1, this->device_id, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void ListEntitiesValveResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("ListEntitiesValveResponse {\n"); - out.append(" object_id: "); - out.append("'").append(this->object_id).append("'"); - out.append("\n"); - - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" name: "); - out.append("'").append(this->name).append("'"); - out.append("\n"); - - out.append(" unique_id: "); - out.append("'").append(this->unique_id).append("'"); - out.append("\n"); - - out.append(" icon: "); - out.append("'").append(this->icon).append("'"); - out.append("\n"); - - out.append(" disabled_by_default: "); - out.append(YESNO(this->disabled_by_default)); - out.append("\n"); - - out.append(" entity_category: "); - out.append(proto_enum_to_string(this->entity_category)); - out.append("\n"); - - out.append(" device_class: "); - out.append("'").append(this->device_class).append("'"); - out.append("\n"); - - out.append(" assumed_state: "); - out.append(YESNO(this->assumed_state)); - out.append("\n"); - - out.append(" supports_position: "); - out.append(YESNO(this->supports_position)); - out.append("\n"); - - out.append(" supports_stop: "); - out.append(YESNO(this->supports_stop)); - out.append("\n"); - - out.append(" device_id: "); - sprintf(buffer, "%" PRIu32, this->device_id); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif bool ValveStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 3: { @@ -10195,26 +5989,6 @@ void ValveStateResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_fixed_field<4>(total_size, 1, this->position != 0.0f, false); ProtoSize::add_enum_field(total_size, 1, static_cast(this->current_operation), false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void ValveStateResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("ValveStateResponse {\n"); - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" position: "); - sprintf(buffer, "%g", this->position); - out.append(buffer); - out.append("\n"); - - out.append(" current_operation: "); - out.append(proto_enum_to_string(this->current_operation)); - out.append("\n"); - out.append("}"); -} -#endif bool ValveCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 2: { @@ -10255,30 +6029,8 @@ void ValveCommandRequest::calculate_size(uint32_t &total_size) const { ProtoSize::add_fixed_field<4>(total_size, 1, this->position != 0.0f, false); ProtoSize::add_bool_field(total_size, 1, this->stop, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void ValveCommandRequest::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("ValveCommandRequest {\n"); - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" has_position: "); - out.append(YESNO(this->has_position)); - out.append("\n"); - - out.append(" position: "); - sprintf(buffer, "%g", this->position); - out.append(buffer); - out.append("\n"); - - out.append(" stop: "); - out.append(YESNO(this->stop)); - out.append("\n"); - out.append("}"); -} #endif +#ifdef USE_DATETIME_DATETIME bool ListEntitiesDateTimeResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 6: { @@ -10349,46 +6101,6 @@ void ListEntitiesDateTimeResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_enum_field(total_size, 1, static_cast(this->entity_category), false); ProtoSize::add_uint32_field(total_size, 1, this->device_id, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void ListEntitiesDateTimeResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("ListEntitiesDateTimeResponse {\n"); - out.append(" object_id: "); - out.append("'").append(this->object_id).append("'"); - out.append("\n"); - - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" name: "); - out.append("'").append(this->name).append("'"); - out.append("\n"); - - out.append(" unique_id: "); - out.append("'").append(this->unique_id).append("'"); - out.append("\n"); - - out.append(" icon: "); - out.append("'").append(this->icon).append("'"); - out.append("\n"); - - out.append(" disabled_by_default: "); - out.append(YESNO(this->disabled_by_default)); - out.append("\n"); - - out.append(" entity_category: "); - out.append(proto_enum_to_string(this->entity_category)); - out.append("\n"); - - out.append(" device_id: "); - sprintf(buffer, "%" PRIu32, this->device_id); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif bool DateTimeStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 2: { @@ -10423,26 +6135,6 @@ void DateTimeStateResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_bool_field(total_size, 1, this->missing_state, false); ProtoSize::add_fixed_field<4>(total_size, 1, this->epoch_seconds != 0, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void DateTimeStateResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("DateTimeStateResponse {\n"); - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" missing_state: "); - out.append(YESNO(this->missing_state)); - out.append("\n"); - - out.append(" epoch_seconds: "); - sprintf(buffer, "%" PRIu32, this->epoch_seconds); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif bool DateTimeCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) { switch (field_id) { case 1: { @@ -10465,22 +6157,8 @@ void DateTimeCommandRequest::calculate_size(uint32_t &total_size) const { ProtoSize::add_fixed_field<4>(total_size, 1, this->key != 0, false); ProtoSize::add_fixed_field<4>(total_size, 1, this->epoch_seconds != 0, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void DateTimeCommandRequest::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("DateTimeCommandRequest {\n"); - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" epoch_seconds: "); - sprintf(buffer, "%" PRIu32, this->epoch_seconds); - out.append(buffer); - out.append("\n"); - out.append("}"); -} #endif +#ifdef USE_UPDATE bool ListEntitiesUpdateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 6: { @@ -10557,50 +6235,6 @@ void ListEntitiesUpdateResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_string_field(total_size, 1, this->device_class, false); ProtoSize::add_uint32_field(total_size, 1, this->device_id, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void ListEntitiesUpdateResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("ListEntitiesUpdateResponse {\n"); - out.append(" object_id: "); - out.append("'").append(this->object_id).append("'"); - out.append("\n"); - - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" name: "); - out.append("'").append(this->name).append("'"); - out.append("\n"); - - out.append(" unique_id: "); - out.append("'").append(this->unique_id).append("'"); - out.append("\n"); - - out.append(" icon: "); - out.append("'").append(this->icon).append("'"); - out.append("\n"); - - out.append(" disabled_by_default: "); - out.append(YESNO(this->disabled_by_default)); - out.append("\n"); - - out.append(" entity_category: "); - out.append(proto_enum_to_string(this->entity_category)); - out.append("\n"); - - out.append(" device_class: "); - out.append("'").append(this->device_class).append("'"); - out.append("\n"); - - out.append(" device_id: "); - sprintf(buffer, "%" PRIu32, this->device_id); - out.append(buffer); - out.append("\n"); - out.append("}"); -} -#endif bool UpdateStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 2: { @@ -10683,54 +6317,6 @@ void UpdateStateResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_string_field(total_size, 1, this->release_summary, false); ProtoSize::add_string_field(total_size, 1, this->release_url, false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void UpdateStateResponse::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("UpdateStateResponse {\n"); - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" missing_state: "); - out.append(YESNO(this->missing_state)); - out.append("\n"); - - out.append(" in_progress: "); - out.append(YESNO(this->in_progress)); - out.append("\n"); - - out.append(" has_progress: "); - out.append(YESNO(this->has_progress)); - out.append("\n"); - - out.append(" progress: "); - sprintf(buffer, "%g", this->progress); - out.append(buffer); - out.append("\n"); - - out.append(" current_version: "); - out.append("'").append(this->current_version).append("'"); - out.append("\n"); - - out.append(" latest_version: "); - out.append("'").append(this->latest_version).append("'"); - out.append("\n"); - - out.append(" title: "); - out.append("'").append(this->title).append("'"); - out.append("\n"); - - out.append(" release_summary: "); - out.append("'").append(this->release_summary).append("'"); - out.append("\n"); - - out.append(" release_url: "); - out.append("'").append(this->release_url).append("'"); - out.append("\n"); - out.append("}"); -} -#endif bool UpdateCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 2: { @@ -10759,20 +6345,6 @@ void UpdateCommandRequest::calculate_size(uint32_t &total_size) const { ProtoSize::add_fixed_field<4>(total_size, 1, this->key != 0, false); ProtoSize::add_enum_field(total_size, 1, static_cast(this->command), false); } -#ifdef HAS_PROTO_MESSAGE_DUMP -void UpdateCommandRequest::dump_to(std::string &out) const { - __attribute__((unused)) char buffer[64]; - out.append("UpdateCommandRequest {\n"); - out.append(" key: "); - sprintf(buffer, "%" PRIu32, this->key); - out.append(buffer); - out.append("\n"); - - out.append(" command: "); - out.append(proto_enum_to_string(this->command)); - out.append("\n"); - out.append("}"); -} #endif } // namespace api diff --git a/esphome/components/api/api_pb2.h b/esphome/components/api/api_pb2.h index 2f0444c2cd..24b0e891c9 100644 --- a/esphome/components/api/api_pb2.h +++ b/esphome/components/api/api_pb2.h @@ -2,6 +2,8 @@ // See script/api_protobuf/api_protobuf.py #pragma once +#include "esphome/core/defines.h" + #include "proto.h" #include "api_pb2_size.h" @@ -15,6 +17,7 @@ enum EntityCategory : uint32_t { ENTITY_CATEGORY_CONFIG = 1, ENTITY_CATEGORY_DIAGNOSTIC = 2, }; +#ifdef USE_COVER enum LegacyCoverState : uint32_t { LEGACY_COVER_STATE_OPEN = 0, LEGACY_COVER_STATE_CLOSED = 1, @@ -29,6 +32,8 @@ enum LegacyCoverCommand : uint32_t { LEGACY_COVER_COMMAND_CLOSE = 1, LEGACY_COVER_COMMAND_STOP = 2, }; +#endif +#ifdef USE_FAN enum FanSpeed : uint32_t { FAN_SPEED_LOW = 0, FAN_SPEED_MEDIUM = 1, @@ -38,6 +43,8 @@ enum FanDirection : uint32_t { FAN_DIRECTION_FORWARD = 0, FAN_DIRECTION_REVERSE = 1, }; +#endif +#ifdef USE_LIGHT enum ColorMode : uint32_t { COLOR_MODE_UNKNOWN = 0, COLOR_MODE_ON_OFF = 1, @@ -51,6 +58,8 @@ enum ColorMode : uint32_t { COLOR_MODE_RGB_COLOR_TEMPERATURE = 47, COLOR_MODE_RGB_COLD_WARM_WHITE = 51, }; +#endif +#ifdef USE_SENSOR enum SensorStateClass : uint32_t { STATE_CLASS_NONE = 0, STATE_CLASS_MEASUREMENT = 1, @@ -62,6 +71,7 @@ enum SensorLastResetType : uint32_t { LAST_RESET_NEVER = 1, LAST_RESET_AUTO = 2, }; +#endif enum LogLevel : uint32_t { LOG_LEVEL_NONE = 0, LOG_LEVEL_ERROR = 1, @@ -82,6 +92,7 @@ enum ServiceArgType : uint32_t { SERVICE_ARG_TYPE_FLOAT_ARRAY = 6, SERVICE_ARG_TYPE_STRING_ARRAY = 7, }; +#ifdef USE_CLIMATE enum ClimateMode : uint32_t { CLIMATE_MODE_OFF = 0, CLIMATE_MODE_HEAT_COOL = 1, @@ -127,11 +138,15 @@ enum ClimatePreset : uint32_t { CLIMATE_PRESET_SLEEP = 6, CLIMATE_PRESET_ACTIVITY = 7, }; +#endif +#ifdef USE_NUMBER enum NumberMode : uint32_t { NUMBER_MODE_AUTO = 0, NUMBER_MODE_BOX = 1, NUMBER_MODE_SLIDER = 2, }; +#endif +#ifdef USE_LOCK enum LockState : uint32_t { LOCK_STATE_NONE = 0, LOCK_STATE_LOCKED = 1, @@ -145,6 +160,8 @@ enum LockCommand : uint32_t { LOCK_LOCK = 1, LOCK_OPEN = 2, }; +#endif +#ifdef USE_MEDIA_PLAYER enum MediaPlayerState : uint32_t { MEDIA_PLAYER_STATE_NONE = 0, MEDIA_PLAYER_STATE_IDLE = 1, @@ -162,6 +179,8 @@ enum MediaPlayerFormatPurpose : uint32_t { MEDIA_PLAYER_FORMAT_PURPOSE_DEFAULT = 0, MEDIA_PLAYER_FORMAT_PURPOSE_ANNOUNCEMENT = 1, }; +#endif +#ifdef USE_BLUETOOTH_PROXY enum BluetoothDeviceRequestType : uint32_t { BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT = 0, BLUETOOTH_DEVICE_REQUEST_TYPE_DISCONNECT = 1, @@ -183,6 +202,7 @@ enum BluetoothScannerMode : uint32_t { BLUETOOTH_SCANNER_MODE_PASSIVE = 0, BLUETOOTH_SCANNER_MODE_ACTIVE = 1, }; +#endif enum VoiceAssistantSubscribeFlag : uint32_t { VOICE_ASSISTANT_SUBSCRIBE_NONE = 0, VOICE_ASSISTANT_SUBSCRIBE_API_AUDIO = 1, @@ -192,6 +212,7 @@ enum VoiceAssistantRequestFlag : uint32_t { VOICE_ASSISTANT_REQUEST_USE_VAD = 1, VOICE_ASSISTANT_REQUEST_USE_WAKE_WORD = 2, }; +#ifdef USE_VOICE_ASSISTANT enum VoiceAssistantEvent : uint32_t { VOICE_ASSISTANT_ERROR = 0, VOICE_ASSISTANT_RUN_START = 1, @@ -216,6 +237,8 @@ enum VoiceAssistantTimerEvent : uint32_t { VOICE_ASSISTANT_TIMER_CANCELLED = 2, VOICE_ASSISTANT_TIMER_FINISHED = 3, }; +#endif +#ifdef USE_ALARM_CONTROL_PANEL enum AlarmControlPanelState : uint32_t { ALARM_STATE_DISARMED = 0, ALARM_STATE_ARMED_HOME = 1, @@ -237,20 +260,27 @@ enum AlarmControlPanelStateCommand : uint32_t { ALARM_CONTROL_PANEL_ARM_CUSTOM_BYPASS = 5, ALARM_CONTROL_PANEL_TRIGGER = 6, }; +#endif +#ifdef USE_TEXT enum TextMode : uint32_t { TEXT_MODE_TEXT = 0, TEXT_MODE_PASSWORD = 1, }; +#endif +#ifdef USE_VALVE enum ValveOperation : uint32_t { VALVE_OPERATION_IDLE = 0, VALVE_OPERATION_IS_OPENING = 1, VALVE_OPERATION_IS_CLOSING = 2, }; +#endif +#ifdef USE_UPDATE enum UpdateCommand : uint32_t { UPDATE_COMMAND_NONE = 0, UPDATE_COMMAND_UPDATE = 1, UPDATE_COMMAND_CHECK = 2, }; +#endif } // namespace enums @@ -523,6 +553,7 @@ class SubscribeStatesRequest : public ProtoMessage { protected: }; +#ifdef USE_BINARY_SENSOR class ListEntitiesBinarySensorResponse : public InfoResponseProtoMessage { public: static constexpr uint16_t MESSAGE_TYPE = 12; @@ -562,6 +593,8 @@ class BinarySensorStateResponse : public StateResponseProtoMessage { bool decode_32bit(uint32_t field_id, Proto32Bit value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override; }; +#endif +#ifdef USE_COVER class ListEntitiesCoverResponse : public InfoResponseProtoMessage { public: static constexpr uint16_t MESSAGE_TYPE = 13; @@ -631,6 +664,8 @@ class CoverCommandRequest : public ProtoMessage { bool decode_32bit(uint32_t field_id, Proto32Bit value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override; }; +#endif +#ifdef USE_FAN class ListEntitiesFanResponse : public InfoResponseProtoMessage { public: static constexpr uint16_t MESSAGE_TYPE = 14; @@ -709,6 +744,8 @@ class FanCommandRequest : public ProtoMessage { bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override; }; +#endif +#ifdef USE_LIGHT class ListEntitiesLightResponse : public InfoResponseProtoMessage { public: static constexpr uint16_t MESSAGE_TYPE = 15; @@ -810,6 +847,8 @@ class LightCommandRequest : public ProtoMessage { bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override; }; +#endif +#ifdef USE_SENSOR class ListEntitiesSensorResponse : public InfoResponseProtoMessage { public: static constexpr uint16_t MESSAGE_TYPE = 16; @@ -853,6 +892,8 @@ class SensorStateResponse : public StateResponseProtoMessage { bool decode_32bit(uint32_t field_id, Proto32Bit value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override; }; +#endif +#ifdef USE_SWITCH class ListEntitiesSwitchResponse : public InfoResponseProtoMessage { public: static constexpr uint16_t MESSAGE_TYPE = 17; @@ -910,6 +951,8 @@ class SwitchCommandRequest : public ProtoMessage { bool decode_32bit(uint32_t field_id, Proto32Bit value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override; }; +#endif +#ifdef USE_TEXT_SENSOR class ListEntitiesTextSensorResponse : public InfoResponseProtoMessage { public: static constexpr uint16_t MESSAGE_TYPE = 18; @@ -949,6 +992,7 @@ class TextSensorStateResponse : public StateResponseProtoMessage { bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override; }; +#endif class SubscribeLogsRequest : public ProtoMessage { public: static constexpr uint16_t MESSAGE_TYPE = 28; @@ -987,6 +1031,7 @@ class SubscribeLogsResponse : public ProtoMessage { bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override; }; +#ifdef USE_API_NOISE class NoiseEncryptionSetKeyRequest : public ProtoMessage { public: static constexpr uint16_t MESSAGE_TYPE = 124; @@ -1021,6 +1066,7 @@ class NoiseEncryptionSetKeyResponse : public ProtoMessage { protected: bool decode_varint(uint32_t field_id, ProtoVarInt value) override; }; +#endif class SubscribeHomeassistantServicesRequest : public ProtoMessage { public: static constexpr uint16_t MESSAGE_TYPE = 34; @@ -1226,6 +1272,7 @@ class ExecuteServiceRequest : public ProtoMessage { bool decode_32bit(uint32_t field_id, Proto32Bit value) override; bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; }; +#ifdef USE_ESP32_CAMERA class ListEntitiesCameraResponse : public InfoResponseProtoMessage { public: static constexpr uint16_t MESSAGE_TYPE = 43; @@ -1283,6 +1330,8 @@ class CameraImageRequest : public ProtoMessage { protected: bool decode_varint(uint32_t field_id, ProtoVarInt value) override; }; +#endif +#ifdef USE_CLIMATE class ListEntitiesClimateResponse : public InfoResponseProtoMessage { public: static constexpr uint16_t MESSAGE_TYPE = 46; @@ -1392,6 +1441,8 @@ class ClimateCommandRequest : public ProtoMessage { bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override; }; +#endif +#ifdef USE_NUMBER class ListEntitiesNumberResponse : public InfoResponseProtoMessage { public: static constexpr uint16_t MESSAGE_TYPE = 49; @@ -1453,6 +1504,8 @@ class NumberCommandRequest : public ProtoMessage { protected: bool decode_32bit(uint32_t field_id, Proto32Bit value) override; }; +#endif +#ifdef USE_SELECT class ListEntitiesSelectResponse : public InfoResponseProtoMessage { public: static constexpr uint16_t MESSAGE_TYPE = 52; @@ -1511,6 +1564,8 @@ class SelectCommandRequest : public ProtoMessage { bool decode_32bit(uint32_t field_id, Proto32Bit value) override; bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; }; +#endif +#ifdef USE_SIREN class ListEntitiesSirenResponse : public InfoResponseProtoMessage { public: static constexpr uint16_t MESSAGE_TYPE = 55; @@ -1577,6 +1632,8 @@ class SirenCommandRequest : public ProtoMessage { bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override; }; +#endif +#ifdef USE_LOCK class ListEntitiesLockResponse : public InfoResponseProtoMessage { public: static constexpr uint16_t MESSAGE_TYPE = 58; @@ -1639,6 +1696,8 @@ class LockCommandRequest : public ProtoMessage { bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override; }; +#endif +#ifdef USE_BUTTON class ListEntitiesButtonResponse : public InfoResponseProtoMessage { public: static constexpr uint16_t MESSAGE_TYPE = 61; @@ -1675,6 +1734,8 @@ class ButtonCommandRequest : public ProtoMessage { protected: bool decode_32bit(uint32_t field_id, Proto32Bit value) override; }; +#endif +#ifdef USE_MEDIA_PLAYER class MediaPlayerSupportedFormat : public ProtoMessage { public: std::string format{}; @@ -1759,6 +1820,8 @@ class MediaPlayerCommandRequest : public ProtoMessage { bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override; }; +#endif +#ifdef USE_BLUETOOTH_PROXY class SubscribeBluetoothLEAdvertisementsRequest : public ProtoMessage { public: static constexpr uint16_t MESSAGE_TYPE = 66; @@ -2313,6 +2376,8 @@ class BluetoothScannerSetModeRequest : public ProtoMessage { protected: bool decode_varint(uint32_t field_id, ProtoVarInt value) override; }; +#endif +#ifdef USE_VOICE_ASSISTANT class SubscribeVoiceAssistantRequest : public ProtoMessage { public: static constexpr uint16_t MESSAGE_TYPE = 89; @@ -2562,6 +2627,8 @@ class VoiceAssistantSetConfiguration : public ProtoMessage { protected: bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; }; +#endif +#ifdef USE_ALARM_CONTROL_PANEL class ListEntitiesAlarmControlPanelResponse : public InfoResponseProtoMessage { public: static constexpr uint16_t MESSAGE_TYPE = 94; @@ -2622,6 +2689,8 @@ class AlarmControlPanelCommandRequest : public ProtoMessage { bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override; }; +#endif +#ifdef USE_TEXT class ListEntitiesTextResponse : public InfoResponseProtoMessage { public: static constexpr uint16_t MESSAGE_TYPE = 97; @@ -2683,6 +2752,8 @@ class TextCommandRequest : public ProtoMessage { bool decode_32bit(uint32_t field_id, Proto32Bit value) override; bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; }; +#endif +#ifdef USE_DATETIME_DATE class ListEntitiesDateResponse : public InfoResponseProtoMessage { public: static constexpr uint16_t MESSAGE_TYPE = 100; @@ -2743,6 +2814,8 @@ class DateCommandRequest : public ProtoMessage { bool decode_32bit(uint32_t field_id, Proto32Bit value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override; }; +#endif +#ifdef USE_DATETIME_TIME class ListEntitiesTimeResponse : public InfoResponseProtoMessage { public: static constexpr uint16_t MESSAGE_TYPE = 103; @@ -2803,6 +2876,8 @@ class TimeCommandRequest : public ProtoMessage { bool decode_32bit(uint32_t field_id, Proto32Bit value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override; }; +#endif +#ifdef USE_EVENT class ListEntitiesEventResponse : public InfoResponseProtoMessage { public: static constexpr uint16_t MESSAGE_TYPE = 107; @@ -2841,6 +2916,8 @@ class EventResponse : public StateResponseProtoMessage { bool decode_32bit(uint32_t field_id, Proto32Bit value) override; bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; }; +#endif +#ifdef USE_VALVE class ListEntitiesValveResponse : public InfoResponseProtoMessage { public: static constexpr uint16_t MESSAGE_TYPE = 109; @@ -2903,6 +2980,8 @@ class ValveCommandRequest : public ProtoMessage { bool decode_32bit(uint32_t field_id, Proto32Bit value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override; }; +#endif +#ifdef USE_DATETIME_DATETIME class ListEntitiesDateTimeResponse : public InfoResponseProtoMessage { public: static constexpr uint16_t MESSAGE_TYPE = 112; @@ -2958,6 +3037,8 @@ class DateTimeCommandRequest : public ProtoMessage { protected: bool decode_32bit(uint32_t field_id, Proto32Bit value) override; }; +#endif +#ifdef USE_UPDATE class ListEntitiesUpdateResponse : public InfoResponseProtoMessage { public: static constexpr uint16_t MESSAGE_TYPE = 116; @@ -3023,6 +3104,7 @@ class UpdateCommandRequest : public ProtoMessage { bool decode_32bit(uint32_t field_id, Proto32Bit value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override; }; +#endif } // namespace api } // namespace esphome diff --git a/esphome/components/api/api_pb2_dump.cpp b/esphome/components/api/api_pb2_dump.cpp new file mode 100644 index 0000000000..6658fd754b --- /dev/null +++ b/esphome/components/api/api_pb2_dump.cpp @@ -0,0 +1,4228 @@ +// This file was automatically generated with a tool. +// See script/api_protobuf/api_protobuf.py +#include "api_pb2.h" +#include "esphome/core/helpers.h" + +#include + +#ifdef HAS_PROTO_MESSAGE_DUMP + +namespace esphome { +namespace api { + +template<> const char *proto_enum_to_string(enums::EntityCategory value) { + switch (value) { + case enums::ENTITY_CATEGORY_NONE: + return "ENTITY_CATEGORY_NONE"; + case enums::ENTITY_CATEGORY_CONFIG: + return "ENTITY_CATEGORY_CONFIG"; + case enums::ENTITY_CATEGORY_DIAGNOSTIC: + return "ENTITY_CATEGORY_DIAGNOSTIC"; + default: + return "UNKNOWN"; + } +} +#ifdef USE_COVER +template<> const char *proto_enum_to_string(enums::LegacyCoverState value) { + switch (value) { + case enums::LEGACY_COVER_STATE_OPEN: + return "LEGACY_COVER_STATE_OPEN"; + case enums::LEGACY_COVER_STATE_CLOSED: + return "LEGACY_COVER_STATE_CLOSED"; + default: + return "UNKNOWN"; + } +} +template<> const char *proto_enum_to_string(enums::CoverOperation value) { + switch (value) { + case enums::COVER_OPERATION_IDLE: + return "COVER_OPERATION_IDLE"; + case enums::COVER_OPERATION_IS_OPENING: + return "COVER_OPERATION_IS_OPENING"; + case enums::COVER_OPERATION_IS_CLOSING: + return "COVER_OPERATION_IS_CLOSING"; + default: + return "UNKNOWN"; + } +} +template<> const char *proto_enum_to_string(enums::LegacyCoverCommand value) { + switch (value) { + case enums::LEGACY_COVER_COMMAND_OPEN: + return "LEGACY_COVER_COMMAND_OPEN"; + case enums::LEGACY_COVER_COMMAND_CLOSE: + return "LEGACY_COVER_COMMAND_CLOSE"; + case enums::LEGACY_COVER_COMMAND_STOP: + return "LEGACY_COVER_COMMAND_STOP"; + default: + return "UNKNOWN"; + } +} +#endif +#ifdef USE_FAN +template<> const char *proto_enum_to_string(enums::FanSpeed value) { + switch (value) { + case enums::FAN_SPEED_LOW: + return "FAN_SPEED_LOW"; + case enums::FAN_SPEED_MEDIUM: + return "FAN_SPEED_MEDIUM"; + case enums::FAN_SPEED_HIGH: + return "FAN_SPEED_HIGH"; + default: + return "UNKNOWN"; + } +} +template<> const char *proto_enum_to_string(enums::FanDirection value) { + switch (value) { + case enums::FAN_DIRECTION_FORWARD: + return "FAN_DIRECTION_FORWARD"; + case enums::FAN_DIRECTION_REVERSE: + return "FAN_DIRECTION_REVERSE"; + default: + return "UNKNOWN"; + } +} +#endif +#ifdef USE_LIGHT +template<> const char *proto_enum_to_string(enums::ColorMode value) { + switch (value) { + case enums::COLOR_MODE_UNKNOWN: + return "COLOR_MODE_UNKNOWN"; + case enums::COLOR_MODE_ON_OFF: + return "COLOR_MODE_ON_OFF"; + case enums::COLOR_MODE_LEGACY_BRIGHTNESS: + return "COLOR_MODE_LEGACY_BRIGHTNESS"; + case enums::COLOR_MODE_BRIGHTNESS: + return "COLOR_MODE_BRIGHTNESS"; + case enums::COLOR_MODE_WHITE: + return "COLOR_MODE_WHITE"; + case enums::COLOR_MODE_COLOR_TEMPERATURE: + return "COLOR_MODE_COLOR_TEMPERATURE"; + case enums::COLOR_MODE_COLD_WARM_WHITE: + return "COLOR_MODE_COLD_WARM_WHITE"; + case enums::COLOR_MODE_RGB: + return "COLOR_MODE_RGB"; + case enums::COLOR_MODE_RGB_WHITE: + return "COLOR_MODE_RGB_WHITE"; + case enums::COLOR_MODE_RGB_COLOR_TEMPERATURE: + return "COLOR_MODE_RGB_COLOR_TEMPERATURE"; + case enums::COLOR_MODE_RGB_COLD_WARM_WHITE: + return "COLOR_MODE_RGB_COLD_WARM_WHITE"; + default: + return "UNKNOWN"; + } +} +#endif +#ifdef USE_SENSOR +template<> const char *proto_enum_to_string(enums::SensorStateClass value) { + switch (value) { + case enums::STATE_CLASS_NONE: + return "STATE_CLASS_NONE"; + case enums::STATE_CLASS_MEASUREMENT: + return "STATE_CLASS_MEASUREMENT"; + case enums::STATE_CLASS_TOTAL_INCREASING: + return "STATE_CLASS_TOTAL_INCREASING"; + case enums::STATE_CLASS_TOTAL: + return "STATE_CLASS_TOTAL"; + default: + return "UNKNOWN"; + } +} +template<> const char *proto_enum_to_string(enums::SensorLastResetType value) { + switch (value) { + case enums::LAST_RESET_NONE: + return "LAST_RESET_NONE"; + case enums::LAST_RESET_NEVER: + return "LAST_RESET_NEVER"; + case enums::LAST_RESET_AUTO: + return "LAST_RESET_AUTO"; + default: + return "UNKNOWN"; + } +} +#endif +template<> const char *proto_enum_to_string(enums::LogLevel value) { + switch (value) { + case enums::LOG_LEVEL_NONE: + return "LOG_LEVEL_NONE"; + case enums::LOG_LEVEL_ERROR: + return "LOG_LEVEL_ERROR"; + case enums::LOG_LEVEL_WARN: + return "LOG_LEVEL_WARN"; + case enums::LOG_LEVEL_INFO: + return "LOG_LEVEL_INFO"; + case enums::LOG_LEVEL_CONFIG: + return "LOG_LEVEL_CONFIG"; + case enums::LOG_LEVEL_DEBUG: + return "LOG_LEVEL_DEBUG"; + case enums::LOG_LEVEL_VERBOSE: + return "LOG_LEVEL_VERBOSE"; + case enums::LOG_LEVEL_VERY_VERBOSE: + return "LOG_LEVEL_VERY_VERBOSE"; + default: + return "UNKNOWN"; + } +} +template<> const char *proto_enum_to_string(enums::ServiceArgType value) { + switch (value) { + case enums::SERVICE_ARG_TYPE_BOOL: + return "SERVICE_ARG_TYPE_BOOL"; + case enums::SERVICE_ARG_TYPE_INT: + return "SERVICE_ARG_TYPE_INT"; + case enums::SERVICE_ARG_TYPE_FLOAT: + return "SERVICE_ARG_TYPE_FLOAT"; + case enums::SERVICE_ARG_TYPE_STRING: + return "SERVICE_ARG_TYPE_STRING"; + case enums::SERVICE_ARG_TYPE_BOOL_ARRAY: + return "SERVICE_ARG_TYPE_BOOL_ARRAY"; + case enums::SERVICE_ARG_TYPE_INT_ARRAY: + return "SERVICE_ARG_TYPE_INT_ARRAY"; + case enums::SERVICE_ARG_TYPE_FLOAT_ARRAY: + return "SERVICE_ARG_TYPE_FLOAT_ARRAY"; + case enums::SERVICE_ARG_TYPE_STRING_ARRAY: + return "SERVICE_ARG_TYPE_STRING_ARRAY"; + default: + return "UNKNOWN"; + } +} +#ifdef USE_CLIMATE +template<> const char *proto_enum_to_string(enums::ClimateMode value) { + switch (value) { + case enums::CLIMATE_MODE_OFF: + return "CLIMATE_MODE_OFF"; + case enums::CLIMATE_MODE_HEAT_COOL: + return "CLIMATE_MODE_HEAT_COOL"; + case enums::CLIMATE_MODE_COOL: + return "CLIMATE_MODE_COOL"; + case enums::CLIMATE_MODE_HEAT: + return "CLIMATE_MODE_HEAT"; + case enums::CLIMATE_MODE_FAN_ONLY: + return "CLIMATE_MODE_FAN_ONLY"; + case enums::CLIMATE_MODE_DRY: + return "CLIMATE_MODE_DRY"; + case enums::CLIMATE_MODE_AUTO: + return "CLIMATE_MODE_AUTO"; + default: + return "UNKNOWN"; + } +} +template<> const char *proto_enum_to_string(enums::ClimateFanMode value) { + switch (value) { + case enums::CLIMATE_FAN_ON: + return "CLIMATE_FAN_ON"; + case enums::CLIMATE_FAN_OFF: + return "CLIMATE_FAN_OFF"; + case enums::CLIMATE_FAN_AUTO: + return "CLIMATE_FAN_AUTO"; + case enums::CLIMATE_FAN_LOW: + return "CLIMATE_FAN_LOW"; + case enums::CLIMATE_FAN_MEDIUM: + return "CLIMATE_FAN_MEDIUM"; + case enums::CLIMATE_FAN_HIGH: + return "CLIMATE_FAN_HIGH"; + case enums::CLIMATE_FAN_MIDDLE: + return "CLIMATE_FAN_MIDDLE"; + case enums::CLIMATE_FAN_FOCUS: + return "CLIMATE_FAN_FOCUS"; + case enums::CLIMATE_FAN_DIFFUSE: + return "CLIMATE_FAN_DIFFUSE"; + case enums::CLIMATE_FAN_QUIET: + return "CLIMATE_FAN_QUIET"; + default: + return "UNKNOWN"; + } +} +template<> const char *proto_enum_to_string(enums::ClimateSwingMode value) { + switch (value) { + case enums::CLIMATE_SWING_OFF: + return "CLIMATE_SWING_OFF"; + case enums::CLIMATE_SWING_BOTH: + return "CLIMATE_SWING_BOTH"; + case enums::CLIMATE_SWING_VERTICAL: + return "CLIMATE_SWING_VERTICAL"; + case enums::CLIMATE_SWING_HORIZONTAL: + return "CLIMATE_SWING_HORIZONTAL"; + default: + return "UNKNOWN"; + } +} +template<> const char *proto_enum_to_string(enums::ClimateAction value) { + switch (value) { + case enums::CLIMATE_ACTION_OFF: + return "CLIMATE_ACTION_OFF"; + case enums::CLIMATE_ACTION_COOLING: + return "CLIMATE_ACTION_COOLING"; + case enums::CLIMATE_ACTION_HEATING: + return "CLIMATE_ACTION_HEATING"; + case enums::CLIMATE_ACTION_IDLE: + return "CLIMATE_ACTION_IDLE"; + case enums::CLIMATE_ACTION_DRYING: + return "CLIMATE_ACTION_DRYING"; + case enums::CLIMATE_ACTION_FAN: + return "CLIMATE_ACTION_FAN"; + default: + return "UNKNOWN"; + } +} +template<> const char *proto_enum_to_string(enums::ClimatePreset value) { + switch (value) { + case enums::CLIMATE_PRESET_NONE: + return "CLIMATE_PRESET_NONE"; + case enums::CLIMATE_PRESET_HOME: + return "CLIMATE_PRESET_HOME"; + case enums::CLIMATE_PRESET_AWAY: + return "CLIMATE_PRESET_AWAY"; + case enums::CLIMATE_PRESET_BOOST: + return "CLIMATE_PRESET_BOOST"; + case enums::CLIMATE_PRESET_COMFORT: + return "CLIMATE_PRESET_COMFORT"; + case enums::CLIMATE_PRESET_ECO: + return "CLIMATE_PRESET_ECO"; + case enums::CLIMATE_PRESET_SLEEP: + return "CLIMATE_PRESET_SLEEP"; + case enums::CLIMATE_PRESET_ACTIVITY: + return "CLIMATE_PRESET_ACTIVITY"; + default: + return "UNKNOWN"; + } +} +#endif +#ifdef USE_NUMBER +template<> const char *proto_enum_to_string(enums::NumberMode value) { + switch (value) { + case enums::NUMBER_MODE_AUTO: + return "NUMBER_MODE_AUTO"; + case enums::NUMBER_MODE_BOX: + return "NUMBER_MODE_BOX"; + case enums::NUMBER_MODE_SLIDER: + return "NUMBER_MODE_SLIDER"; + default: + return "UNKNOWN"; + } +} +#endif +#ifdef USE_LOCK +template<> const char *proto_enum_to_string(enums::LockState value) { + switch (value) { + case enums::LOCK_STATE_NONE: + return "LOCK_STATE_NONE"; + case enums::LOCK_STATE_LOCKED: + return "LOCK_STATE_LOCKED"; + case enums::LOCK_STATE_UNLOCKED: + return "LOCK_STATE_UNLOCKED"; + case enums::LOCK_STATE_JAMMED: + return "LOCK_STATE_JAMMED"; + case enums::LOCK_STATE_LOCKING: + return "LOCK_STATE_LOCKING"; + case enums::LOCK_STATE_UNLOCKING: + return "LOCK_STATE_UNLOCKING"; + default: + return "UNKNOWN"; + } +} +template<> const char *proto_enum_to_string(enums::LockCommand value) { + switch (value) { + case enums::LOCK_UNLOCK: + return "LOCK_UNLOCK"; + case enums::LOCK_LOCK: + return "LOCK_LOCK"; + case enums::LOCK_OPEN: + return "LOCK_OPEN"; + default: + return "UNKNOWN"; + } +} +#endif +#ifdef USE_MEDIA_PLAYER +template<> const char *proto_enum_to_string(enums::MediaPlayerState value) { + switch (value) { + case enums::MEDIA_PLAYER_STATE_NONE: + return "MEDIA_PLAYER_STATE_NONE"; + case enums::MEDIA_PLAYER_STATE_IDLE: + return "MEDIA_PLAYER_STATE_IDLE"; + case enums::MEDIA_PLAYER_STATE_PLAYING: + return "MEDIA_PLAYER_STATE_PLAYING"; + case enums::MEDIA_PLAYER_STATE_PAUSED: + return "MEDIA_PLAYER_STATE_PAUSED"; + default: + return "UNKNOWN"; + } +} +template<> const char *proto_enum_to_string(enums::MediaPlayerCommand value) { + switch (value) { + case enums::MEDIA_PLAYER_COMMAND_PLAY: + return "MEDIA_PLAYER_COMMAND_PLAY"; + case enums::MEDIA_PLAYER_COMMAND_PAUSE: + return "MEDIA_PLAYER_COMMAND_PAUSE"; + case enums::MEDIA_PLAYER_COMMAND_STOP: + return "MEDIA_PLAYER_COMMAND_STOP"; + case enums::MEDIA_PLAYER_COMMAND_MUTE: + return "MEDIA_PLAYER_COMMAND_MUTE"; + case enums::MEDIA_PLAYER_COMMAND_UNMUTE: + return "MEDIA_PLAYER_COMMAND_UNMUTE"; + default: + return "UNKNOWN"; + } +} +template<> const char *proto_enum_to_string(enums::MediaPlayerFormatPurpose value) { + switch (value) { + case enums::MEDIA_PLAYER_FORMAT_PURPOSE_DEFAULT: + return "MEDIA_PLAYER_FORMAT_PURPOSE_DEFAULT"; + case enums::MEDIA_PLAYER_FORMAT_PURPOSE_ANNOUNCEMENT: + return "MEDIA_PLAYER_FORMAT_PURPOSE_ANNOUNCEMENT"; + default: + return "UNKNOWN"; + } +} +#endif +#ifdef USE_BLUETOOTH_PROXY +template<> +const char *proto_enum_to_string(enums::BluetoothDeviceRequestType value) { + switch (value) { + case enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT: + return "BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT"; + case enums::BLUETOOTH_DEVICE_REQUEST_TYPE_DISCONNECT: + return "BLUETOOTH_DEVICE_REQUEST_TYPE_DISCONNECT"; + case enums::BLUETOOTH_DEVICE_REQUEST_TYPE_PAIR: + return "BLUETOOTH_DEVICE_REQUEST_TYPE_PAIR"; + case enums::BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR: + return "BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR"; + case enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE: + return "BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE"; + case enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE: + return "BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE"; + case enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CLEAR_CACHE: + return "BLUETOOTH_DEVICE_REQUEST_TYPE_CLEAR_CACHE"; + default: + return "UNKNOWN"; + } +} +template<> const char *proto_enum_to_string(enums::BluetoothScannerState value) { + switch (value) { + case enums::BLUETOOTH_SCANNER_STATE_IDLE: + return "BLUETOOTH_SCANNER_STATE_IDLE"; + case enums::BLUETOOTH_SCANNER_STATE_STARTING: + return "BLUETOOTH_SCANNER_STATE_STARTING"; + case enums::BLUETOOTH_SCANNER_STATE_RUNNING: + return "BLUETOOTH_SCANNER_STATE_RUNNING"; + case enums::BLUETOOTH_SCANNER_STATE_FAILED: + return "BLUETOOTH_SCANNER_STATE_FAILED"; + case enums::BLUETOOTH_SCANNER_STATE_STOPPING: + return "BLUETOOTH_SCANNER_STATE_STOPPING"; + case enums::BLUETOOTH_SCANNER_STATE_STOPPED: + return "BLUETOOTH_SCANNER_STATE_STOPPED"; + default: + return "UNKNOWN"; + } +} +template<> const char *proto_enum_to_string(enums::BluetoothScannerMode value) { + switch (value) { + case enums::BLUETOOTH_SCANNER_MODE_PASSIVE: + return "BLUETOOTH_SCANNER_MODE_PASSIVE"; + case enums::BLUETOOTH_SCANNER_MODE_ACTIVE: + return "BLUETOOTH_SCANNER_MODE_ACTIVE"; + default: + return "UNKNOWN"; + } +} +#endif +template<> +const char *proto_enum_to_string(enums::VoiceAssistantSubscribeFlag value) { + switch (value) { + case enums::VOICE_ASSISTANT_SUBSCRIBE_NONE: + return "VOICE_ASSISTANT_SUBSCRIBE_NONE"; + case enums::VOICE_ASSISTANT_SUBSCRIBE_API_AUDIO: + return "VOICE_ASSISTANT_SUBSCRIBE_API_AUDIO"; + default: + return "UNKNOWN"; + } +} +template<> const char *proto_enum_to_string(enums::VoiceAssistantRequestFlag value) { + switch (value) { + case enums::VOICE_ASSISTANT_REQUEST_NONE: + return "VOICE_ASSISTANT_REQUEST_NONE"; + case enums::VOICE_ASSISTANT_REQUEST_USE_VAD: + return "VOICE_ASSISTANT_REQUEST_USE_VAD"; + case enums::VOICE_ASSISTANT_REQUEST_USE_WAKE_WORD: + return "VOICE_ASSISTANT_REQUEST_USE_WAKE_WORD"; + default: + return "UNKNOWN"; + } +} +#ifdef USE_VOICE_ASSISTANT +template<> const char *proto_enum_to_string(enums::VoiceAssistantEvent value) { + switch (value) { + case enums::VOICE_ASSISTANT_ERROR: + return "VOICE_ASSISTANT_ERROR"; + case enums::VOICE_ASSISTANT_RUN_START: + return "VOICE_ASSISTANT_RUN_START"; + case enums::VOICE_ASSISTANT_RUN_END: + return "VOICE_ASSISTANT_RUN_END"; + case enums::VOICE_ASSISTANT_STT_START: + return "VOICE_ASSISTANT_STT_START"; + case enums::VOICE_ASSISTANT_STT_END: + return "VOICE_ASSISTANT_STT_END"; + case enums::VOICE_ASSISTANT_INTENT_START: + return "VOICE_ASSISTANT_INTENT_START"; + case enums::VOICE_ASSISTANT_INTENT_END: + return "VOICE_ASSISTANT_INTENT_END"; + case enums::VOICE_ASSISTANT_TTS_START: + return "VOICE_ASSISTANT_TTS_START"; + case enums::VOICE_ASSISTANT_TTS_END: + return "VOICE_ASSISTANT_TTS_END"; + case enums::VOICE_ASSISTANT_WAKE_WORD_START: + return "VOICE_ASSISTANT_WAKE_WORD_START"; + case enums::VOICE_ASSISTANT_WAKE_WORD_END: + return "VOICE_ASSISTANT_WAKE_WORD_END"; + case enums::VOICE_ASSISTANT_STT_VAD_START: + return "VOICE_ASSISTANT_STT_VAD_START"; + case enums::VOICE_ASSISTANT_STT_VAD_END: + return "VOICE_ASSISTANT_STT_VAD_END"; + case enums::VOICE_ASSISTANT_TTS_STREAM_START: + return "VOICE_ASSISTANT_TTS_STREAM_START"; + case enums::VOICE_ASSISTANT_TTS_STREAM_END: + return "VOICE_ASSISTANT_TTS_STREAM_END"; + case enums::VOICE_ASSISTANT_INTENT_PROGRESS: + return "VOICE_ASSISTANT_INTENT_PROGRESS"; + default: + return "UNKNOWN"; + } +} +template<> const char *proto_enum_to_string(enums::VoiceAssistantTimerEvent value) { + switch (value) { + case enums::VOICE_ASSISTANT_TIMER_STARTED: + return "VOICE_ASSISTANT_TIMER_STARTED"; + case enums::VOICE_ASSISTANT_TIMER_UPDATED: + return "VOICE_ASSISTANT_TIMER_UPDATED"; + case enums::VOICE_ASSISTANT_TIMER_CANCELLED: + return "VOICE_ASSISTANT_TIMER_CANCELLED"; + case enums::VOICE_ASSISTANT_TIMER_FINISHED: + return "VOICE_ASSISTANT_TIMER_FINISHED"; + default: + return "UNKNOWN"; + } +} +#endif +#ifdef USE_ALARM_CONTROL_PANEL +template<> const char *proto_enum_to_string(enums::AlarmControlPanelState value) { + switch (value) { + case enums::ALARM_STATE_DISARMED: + return "ALARM_STATE_DISARMED"; + case enums::ALARM_STATE_ARMED_HOME: + return "ALARM_STATE_ARMED_HOME"; + case enums::ALARM_STATE_ARMED_AWAY: + return "ALARM_STATE_ARMED_AWAY"; + case enums::ALARM_STATE_ARMED_NIGHT: + return "ALARM_STATE_ARMED_NIGHT"; + case enums::ALARM_STATE_ARMED_VACATION: + return "ALARM_STATE_ARMED_VACATION"; + case enums::ALARM_STATE_ARMED_CUSTOM_BYPASS: + return "ALARM_STATE_ARMED_CUSTOM_BYPASS"; + case enums::ALARM_STATE_PENDING: + return "ALARM_STATE_PENDING"; + case enums::ALARM_STATE_ARMING: + return "ALARM_STATE_ARMING"; + case enums::ALARM_STATE_DISARMING: + return "ALARM_STATE_DISARMING"; + case enums::ALARM_STATE_TRIGGERED: + return "ALARM_STATE_TRIGGERED"; + default: + return "UNKNOWN"; + } +} +template<> +const char *proto_enum_to_string(enums::AlarmControlPanelStateCommand value) { + switch (value) { + case enums::ALARM_CONTROL_PANEL_DISARM: + return "ALARM_CONTROL_PANEL_DISARM"; + case enums::ALARM_CONTROL_PANEL_ARM_AWAY: + return "ALARM_CONTROL_PANEL_ARM_AWAY"; + case enums::ALARM_CONTROL_PANEL_ARM_HOME: + return "ALARM_CONTROL_PANEL_ARM_HOME"; + case enums::ALARM_CONTROL_PANEL_ARM_NIGHT: + return "ALARM_CONTROL_PANEL_ARM_NIGHT"; + case enums::ALARM_CONTROL_PANEL_ARM_VACATION: + return "ALARM_CONTROL_PANEL_ARM_VACATION"; + case enums::ALARM_CONTROL_PANEL_ARM_CUSTOM_BYPASS: + return "ALARM_CONTROL_PANEL_ARM_CUSTOM_BYPASS"; + case enums::ALARM_CONTROL_PANEL_TRIGGER: + return "ALARM_CONTROL_PANEL_TRIGGER"; + default: + return "UNKNOWN"; + } +} +#endif +#ifdef USE_TEXT +template<> const char *proto_enum_to_string(enums::TextMode value) { + switch (value) { + case enums::TEXT_MODE_TEXT: + return "TEXT_MODE_TEXT"; + case enums::TEXT_MODE_PASSWORD: + return "TEXT_MODE_PASSWORD"; + default: + return "UNKNOWN"; + } +} +#endif +#ifdef USE_VALVE +template<> const char *proto_enum_to_string(enums::ValveOperation value) { + switch (value) { + case enums::VALVE_OPERATION_IDLE: + return "VALVE_OPERATION_IDLE"; + case enums::VALVE_OPERATION_IS_OPENING: + return "VALVE_OPERATION_IS_OPENING"; + case enums::VALVE_OPERATION_IS_CLOSING: + return "VALVE_OPERATION_IS_CLOSING"; + default: + return "UNKNOWN"; + } +} +#endif +#ifdef USE_UPDATE +template<> const char *proto_enum_to_string(enums::UpdateCommand value) { + switch (value) { + case enums::UPDATE_COMMAND_NONE: + return "UPDATE_COMMAND_NONE"; + case enums::UPDATE_COMMAND_UPDATE: + return "UPDATE_COMMAND_UPDATE"; + case enums::UPDATE_COMMAND_CHECK: + return "UPDATE_COMMAND_CHECK"; + default: + return "UNKNOWN"; + } +} +#endif + +void HelloRequest::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("HelloRequest {\n"); + out.append(" client_info: "); + out.append("'").append(this->client_info).append("'"); + out.append("\n"); + + out.append(" api_version_major: "); + sprintf(buffer, "%" PRIu32, this->api_version_major); + out.append(buffer); + out.append("\n"); + + out.append(" api_version_minor: "); + sprintf(buffer, "%" PRIu32, this->api_version_minor); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void HelloResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("HelloResponse {\n"); + out.append(" api_version_major: "); + sprintf(buffer, "%" PRIu32, this->api_version_major); + out.append(buffer); + out.append("\n"); + + out.append(" api_version_minor: "); + sprintf(buffer, "%" PRIu32, this->api_version_minor); + out.append(buffer); + out.append("\n"); + + out.append(" server_info: "); + out.append("'").append(this->server_info).append("'"); + out.append("\n"); + + out.append(" name: "); + out.append("'").append(this->name).append("'"); + out.append("\n"); + out.append("}"); +} +void ConnectRequest::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("ConnectRequest {\n"); + out.append(" password: "); + out.append("'").append(this->password).append("'"); + out.append("\n"); + out.append("}"); +} +void ConnectResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("ConnectResponse {\n"); + out.append(" invalid_password: "); + out.append(YESNO(this->invalid_password)); + out.append("\n"); + out.append("}"); +} +void DisconnectRequest::dump_to(std::string &out) const { out.append("DisconnectRequest {}"); } +void DisconnectResponse::dump_to(std::string &out) const { out.append("DisconnectResponse {}"); } +void PingRequest::dump_to(std::string &out) const { out.append("PingRequest {}"); } +void PingResponse::dump_to(std::string &out) const { out.append("PingResponse {}"); } +void DeviceInfoRequest::dump_to(std::string &out) const { out.append("DeviceInfoRequest {}"); } +void AreaInfo::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("AreaInfo {\n"); + out.append(" area_id: "); + sprintf(buffer, "%" PRIu32, this->area_id); + out.append(buffer); + out.append("\n"); + + out.append(" name: "); + out.append("'").append(this->name).append("'"); + out.append("\n"); + out.append("}"); +} +void DeviceInfo::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("DeviceInfo {\n"); + out.append(" device_id: "); + sprintf(buffer, "%" PRIu32, this->device_id); + out.append(buffer); + out.append("\n"); + + out.append(" name: "); + out.append("'").append(this->name).append("'"); + out.append("\n"); + + out.append(" area_id: "); + sprintf(buffer, "%" PRIu32, this->area_id); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void DeviceInfoResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("DeviceInfoResponse {\n"); + out.append(" uses_password: "); + out.append(YESNO(this->uses_password)); + out.append("\n"); + + out.append(" name: "); + out.append("'").append(this->name).append("'"); + out.append("\n"); + + out.append(" mac_address: "); + out.append("'").append(this->mac_address).append("'"); + out.append("\n"); + + out.append(" esphome_version: "); + out.append("'").append(this->esphome_version).append("'"); + out.append("\n"); + + out.append(" compilation_time: "); + out.append("'").append(this->compilation_time).append("'"); + out.append("\n"); + + out.append(" model: "); + out.append("'").append(this->model).append("'"); + out.append("\n"); + + out.append(" has_deep_sleep: "); + out.append(YESNO(this->has_deep_sleep)); + out.append("\n"); + + out.append(" project_name: "); + out.append("'").append(this->project_name).append("'"); + out.append("\n"); + + out.append(" project_version: "); + out.append("'").append(this->project_version).append("'"); + out.append("\n"); + + out.append(" webserver_port: "); + sprintf(buffer, "%" PRIu32, this->webserver_port); + out.append(buffer); + out.append("\n"); + + out.append(" legacy_bluetooth_proxy_version: "); + sprintf(buffer, "%" PRIu32, this->legacy_bluetooth_proxy_version); + out.append(buffer); + out.append("\n"); + + out.append(" bluetooth_proxy_feature_flags: "); + sprintf(buffer, "%" PRIu32, this->bluetooth_proxy_feature_flags); + out.append(buffer); + out.append("\n"); + + out.append(" manufacturer: "); + out.append("'").append(this->manufacturer).append("'"); + out.append("\n"); + + out.append(" friendly_name: "); + out.append("'").append(this->friendly_name).append("'"); + out.append("\n"); + + out.append(" legacy_voice_assistant_version: "); + sprintf(buffer, "%" PRIu32, this->legacy_voice_assistant_version); + out.append(buffer); + out.append("\n"); + + out.append(" voice_assistant_feature_flags: "); + sprintf(buffer, "%" PRIu32, this->voice_assistant_feature_flags); + out.append(buffer); + out.append("\n"); + + out.append(" suggested_area: "); + out.append("'").append(this->suggested_area).append("'"); + out.append("\n"); + + out.append(" bluetooth_mac_address: "); + out.append("'").append(this->bluetooth_mac_address).append("'"); + out.append("\n"); + + out.append(" api_encryption_supported: "); + out.append(YESNO(this->api_encryption_supported)); + out.append("\n"); + + for (const auto &it : this->devices) { + out.append(" devices: "); + it.dump_to(out); + out.append("\n"); + } + + for (const auto &it : this->areas) { + out.append(" areas: "); + it.dump_to(out); + out.append("\n"); + } + + out.append(" area: "); + this->area.dump_to(out); + out.append("\n"); + out.append("}"); +} +void ListEntitiesRequest::dump_to(std::string &out) const { out.append("ListEntitiesRequest {}"); } +void ListEntitiesDoneResponse::dump_to(std::string &out) const { out.append("ListEntitiesDoneResponse {}"); } +void SubscribeStatesRequest::dump_to(std::string &out) const { out.append("SubscribeStatesRequest {}"); } +#ifdef USE_BINARY_SENSOR +void ListEntitiesBinarySensorResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("ListEntitiesBinarySensorResponse {\n"); + out.append(" object_id: "); + out.append("'").append(this->object_id).append("'"); + out.append("\n"); + + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" name: "); + out.append("'").append(this->name).append("'"); + out.append("\n"); + + out.append(" unique_id: "); + out.append("'").append(this->unique_id).append("'"); + out.append("\n"); + + out.append(" device_class: "); + out.append("'").append(this->device_class).append("'"); + out.append("\n"); + + out.append(" is_status_binary_sensor: "); + out.append(YESNO(this->is_status_binary_sensor)); + out.append("\n"); + + out.append(" disabled_by_default: "); + out.append(YESNO(this->disabled_by_default)); + out.append("\n"); + + out.append(" icon: "); + out.append("'").append(this->icon).append("'"); + out.append("\n"); + + out.append(" entity_category: "); + out.append(proto_enum_to_string(this->entity_category)); + out.append("\n"); + + out.append(" device_id: "); + sprintf(buffer, "%" PRIu32, this->device_id); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void BinarySensorStateResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("BinarySensorStateResponse {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" state: "); + out.append(YESNO(this->state)); + out.append("\n"); + + out.append(" missing_state: "); + out.append(YESNO(this->missing_state)); + out.append("\n"); + out.append("}"); +} +#endif +#ifdef USE_COVER +void ListEntitiesCoverResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("ListEntitiesCoverResponse {\n"); + out.append(" object_id: "); + out.append("'").append(this->object_id).append("'"); + out.append("\n"); + + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" name: "); + out.append("'").append(this->name).append("'"); + out.append("\n"); + + out.append(" unique_id: "); + out.append("'").append(this->unique_id).append("'"); + out.append("\n"); + + out.append(" assumed_state: "); + out.append(YESNO(this->assumed_state)); + out.append("\n"); + + out.append(" supports_position: "); + out.append(YESNO(this->supports_position)); + out.append("\n"); + + out.append(" supports_tilt: "); + out.append(YESNO(this->supports_tilt)); + out.append("\n"); + + out.append(" device_class: "); + out.append("'").append(this->device_class).append("'"); + out.append("\n"); + + out.append(" disabled_by_default: "); + out.append(YESNO(this->disabled_by_default)); + out.append("\n"); + + out.append(" icon: "); + out.append("'").append(this->icon).append("'"); + out.append("\n"); + + out.append(" entity_category: "); + out.append(proto_enum_to_string(this->entity_category)); + out.append("\n"); + + out.append(" supports_stop: "); + out.append(YESNO(this->supports_stop)); + out.append("\n"); + + out.append(" device_id: "); + sprintf(buffer, "%" PRIu32, this->device_id); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void CoverStateResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("CoverStateResponse {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" legacy_state: "); + out.append(proto_enum_to_string(this->legacy_state)); + out.append("\n"); + + out.append(" position: "); + sprintf(buffer, "%g", this->position); + out.append(buffer); + out.append("\n"); + + out.append(" tilt: "); + sprintf(buffer, "%g", this->tilt); + out.append(buffer); + out.append("\n"); + + out.append(" current_operation: "); + out.append(proto_enum_to_string(this->current_operation)); + out.append("\n"); + out.append("}"); +} +void CoverCommandRequest::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("CoverCommandRequest {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" has_legacy_command: "); + out.append(YESNO(this->has_legacy_command)); + out.append("\n"); + + out.append(" legacy_command: "); + out.append(proto_enum_to_string(this->legacy_command)); + out.append("\n"); + + out.append(" has_position: "); + out.append(YESNO(this->has_position)); + out.append("\n"); + + out.append(" position: "); + sprintf(buffer, "%g", this->position); + out.append(buffer); + out.append("\n"); + + out.append(" has_tilt: "); + out.append(YESNO(this->has_tilt)); + out.append("\n"); + + out.append(" tilt: "); + sprintf(buffer, "%g", this->tilt); + out.append(buffer); + out.append("\n"); + + out.append(" stop: "); + out.append(YESNO(this->stop)); + out.append("\n"); + out.append("}"); +} +#endif +#ifdef USE_FAN +void ListEntitiesFanResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("ListEntitiesFanResponse {\n"); + out.append(" object_id: "); + out.append("'").append(this->object_id).append("'"); + out.append("\n"); + + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" name: "); + out.append("'").append(this->name).append("'"); + out.append("\n"); + + out.append(" unique_id: "); + out.append("'").append(this->unique_id).append("'"); + out.append("\n"); + + out.append(" supports_oscillation: "); + out.append(YESNO(this->supports_oscillation)); + out.append("\n"); + + out.append(" supports_speed: "); + out.append(YESNO(this->supports_speed)); + out.append("\n"); + + out.append(" supports_direction: "); + out.append(YESNO(this->supports_direction)); + out.append("\n"); + + out.append(" supported_speed_count: "); + sprintf(buffer, "%" PRId32, this->supported_speed_count); + out.append(buffer); + out.append("\n"); + + out.append(" disabled_by_default: "); + out.append(YESNO(this->disabled_by_default)); + out.append("\n"); + + out.append(" icon: "); + out.append("'").append(this->icon).append("'"); + out.append("\n"); + + out.append(" entity_category: "); + out.append(proto_enum_to_string(this->entity_category)); + out.append("\n"); + + for (const auto &it : this->supported_preset_modes) { + out.append(" supported_preset_modes: "); + out.append("'").append(it).append("'"); + out.append("\n"); + } + + out.append(" device_id: "); + sprintf(buffer, "%" PRIu32, this->device_id); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void FanStateResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("FanStateResponse {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" state: "); + out.append(YESNO(this->state)); + out.append("\n"); + + out.append(" oscillating: "); + out.append(YESNO(this->oscillating)); + out.append("\n"); + + out.append(" speed: "); + out.append(proto_enum_to_string(this->speed)); + out.append("\n"); + + out.append(" direction: "); + out.append(proto_enum_to_string(this->direction)); + out.append("\n"); + + out.append(" speed_level: "); + sprintf(buffer, "%" PRId32, this->speed_level); + out.append(buffer); + out.append("\n"); + + out.append(" preset_mode: "); + out.append("'").append(this->preset_mode).append("'"); + out.append("\n"); + out.append("}"); +} +void FanCommandRequest::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("FanCommandRequest {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" has_state: "); + out.append(YESNO(this->has_state)); + out.append("\n"); + + out.append(" state: "); + out.append(YESNO(this->state)); + out.append("\n"); + + out.append(" has_speed: "); + out.append(YESNO(this->has_speed)); + out.append("\n"); + + out.append(" speed: "); + out.append(proto_enum_to_string(this->speed)); + out.append("\n"); + + out.append(" has_oscillating: "); + out.append(YESNO(this->has_oscillating)); + out.append("\n"); + + out.append(" oscillating: "); + out.append(YESNO(this->oscillating)); + out.append("\n"); + + out.append(" has_direction: "); + out.append(YESNO(this->has_direction)); + out.append("\n"); + + out.append(" direction: "); + out.append(proto_enum_to_string(this->direction)); + out.append("\n"); + + out.append(" has_speed_level: "); + out.append(YESNO(this->has_speed_level)); + out.append("\n"); + + out.append(" speed_level: "); + sprintf(buffer, "%" PRId32, this->speed_level); + out.append(buffer); + out.append("\n"); + + out.append(" has_preset_mode: "); + out.append(YESNO(this->has_preset_mode)); + out.append("\n"); + + out.append(" preset_mode: "); + out.append("'").append(this->preset_mode).append("'"); + out.append("\n"); + out.append("}"); +} +#endif +#ifdef USE_LIGHT +void ListEntitiesLightResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("ListEntitiesLightResponse {\n"); + out.append(" object_id: "); + out.append("'").append(this->object_id).append("'"); + out.append("\n"); + + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" name: "); + out.append("'").append(this->name).append("'"); + out.append("\n"); + + out.append(" unique_id: "); + out.append("'").append(this->unique_id).append("'"); + out.append("\n"); + + for (const auto &it : this->supported_color_modes) { + out.append(" supported_color_modes: "); + out.append(proto_enum_to_string(it)); + out.append("\n"); + } + + out.append(" legacy_supports_brightness: "); + out.append(YESNO(this->legacy_supports_brightness)); + out.append("\n"); + + out.append(" legacy_supports_rgb: "); + out.append(YESNO(this->legacy_supports_rgb)); + out.append("\n"); + + out.append(" legacy_supports_white_value: "); + out.append(YESNO(this->legacy_supports_white_value)); + out.append("\n"); + + out.append(" legacy_supports_color_temperature: "); + out.append(YESNO(this->legacy_supports_color_temperature)); + out.append("\n"); + + out.append(" min_mireds: "); + sprintf(buffer, "%g", this->min_mireds); + out.append(buffer); + out.append("\n"); + + out.append(" max_mireds: "); + sprintf(buffer, "%g", this->max_mireds); + out.append(buffer); + out.append("\n"); + + for (const auto &it : this->effects) { + out.append(" effects: "); + out.append("'").append(it).append("'"); + out.append("\n"); + } + + out.append(" disabled_by_default: "); + out.append(YESNO(this->disabled_by_default)); + out.append("\n"); + + out.append(" icon: "); + out.append("'").append(this->icon).append("'"); + out.append("\n"); + + out.append(" entity_category: "); + out.append(proto_enum_to_string(this->entity_category)); + out.append("\n"); + + out.append(" device_id: "); + sprintf(buffer, "%" PRIu32, this->device_id); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void LightStateResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("LightStateResponse {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" state: "); + out.append(YESNO(this->state)); + out.append("\n"); + + out.append(" brightness: "); + sprintf(buffer, "%g", this->brightness); + out.append(buffer); + out.append("\n"); + + out.append(" color_mode: "); + out.append(proto_enum_to_string(this->color_mode)); + out.append("\n"); + + out.append(" color_brightness: "); + sprintf(buffer, "%g", this->color_brightness); + out.append(buffer); + out.append("\n"); + + out.append(" red: "); + sprintf(buffer, "%g", this->red); + out.append(buffer); + out.append("\n"); + + out.append(" green: "); + sprintf(buffer, "%g", this->green); + out.append(buffer); + out.append("\n"); + + out.append(" blue: "); + sprintf(buffer, "%g", this->blue); + out.append(buffer); + out.append("\n"); + + out.append(" white: "); + sprintf(buffer, "%g", this->white); + out.append(buffer); + out.append("\n"); + + out.append(" color_temperature: "); + sprintf(buffer, "%g", this->color_temperature); + out.append(buffer); + out.append("\n"); + + out.append(" cold_white: "); + sprintf(buffer, "%g", this->cold_white); + out.append(buffer); + out.append("\n"); + + out.append(" warm_white: "); + sprintf(buffer, "%g", this->warm_white); + out.append(buffer); + out.append("\n"); + + out.append(" effect: "); + out.append("'").append(this->effect).append("'"); + out.append("\n"); + out.append("}"); +} +void LightCommandRequest::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("LightCommandRequest {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" has_state: "); + out.append(YESNO(this->has_state)); + out.append("\n"); + + out.append(" state: "); + out.append(YESNO(this->state)); + out.append("\n"); + + out.append(" has_brightness: "); + out.append(YESNO(this->has_brightness)); + out.append("\n"); + + out.append(" brightness: "); + sprintf(buffer, "%g", this->brightness); + out.append(buffer); + out.append("\n"); + + out.append(" has_color_mode: "); + out.append(YESNO(this->has_color_mode)); + out.append("\n"); + + out.append(" color_mode: "); + out.append(proto_enum_to_string(this->color_mode)); + out.append("\n"); + + out.append(" has_color_brightness: "); + out.append(YESNO(this->has_color_brightness)); + out.append("\n"); + + out.append(" color_brightness: "); + sprintf(buffer, "%g", this->color_brightness); + out.append(buffer); + out.append("\n"); + + out.append(" has_rgb: "); + out.append(YESNO(this->has_rgb)); + out.append("\n"); + + out.append(" red: "); + sprintf(buffer, "%g", this->red); + out.append(buffer); + out.append("\n"); + + out.append(" green: "); + sprintf(buffer, "%g", this->green); + out.append(buffer); + out.append("\n"); + + out.append(" blue: "); + sprintf(buffer, "%g", this->blue); + out.append(buffer); + out.append("\n"); + + out.append(" has_white: "); + out.append(YESNO(this->has_white)); + out.append("\n"); + + out.append(" white: "); + sprintf(buffer, "%g", this->white); + out.append(buffer); + out.append("\n"); + + out.append(" has_color_temperature: "); + out.append(YESNO(this->has_color_temperature)); + out.append("\n"); + + out.append(" color_temperature: "); + sprintf(buffer, "%g", this->color_temperature); + out.append(buffer); + out.append("\n"); + + out.append(" has_cold_white: "); + out.append(YESNO(this->has_cold_white)); + out.append("\n"); + + out.append(" cold_white: "); + sprintf(buffer, "%g", this->cold_white); + out.append(buffer); + out.append("\n"); + + out.append(" has_warm_white: "); + out.append(YESNO(this->has_warm_white)); + out.append("\n"); + + out.append(" warm_white: "); + sprintf(buffer, "%g", this->warm_white); + out.append(buffer); + out.append("\n"); + + out.append(" has_transition_length: "); + out.append(YESNO(this->has_transition_length)); + out.append("\n"); + + out.append(" transition_length: "); + sprintf(buffer, "%" PRIu32, this->transition_length); + out.append(buffer); + out.append("\n"); + + out.append(" has_flash_length: "); + out.append(YESNO(this->has_flash_length)); + out.append("\n"); + + out.append(" flash_length: "); + sprintf(buffer, "%" PRIu32, this->flash_length); + out.append(buffer); + out.append("\n"); + + out.append(" has_effect: "); + out.append(YESNO(this->has_effect)); + out.append("\n"); + + out.append(" effect: "); + out.append("'").append(this->effect).append("'"); + out.append("\n"); + out.append("}"); +} +#endif +#ifdef USE_SENSOR +void ListEntitiesSensorResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("ListEntitiesSensorResponse {\n"); + out.append(" object_id: "); + out.append("'").append(this->object_id).append("'"); + out.append("\n"); + + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" name: "); + out.append("'").append(this->name).append("'"); + out.append("\n"); + + out.append(" unique_id: "); + out.append("'").append(this->unique_id).append("'"); + out.append("\n"); + + out.append(" icon: "); + out.append("'").append(this->icon).append("'"); + out.append("\n"); + + out.append(" unit_of_measurement: "); + out.append("'").append(this->unit_of_measurement).append("'"); + out.append("\n"); + + out.append(" accuracy_decimals: "); + sprintf(buffer, "%" PRId32, this->accuracy_decimals); + out.append(buffer); + out.append("\n"); + + out.append(" force_update: "); + out.append(YESNO(this->force_update)); + out.append("\n"); + + out.append(" device_class: "); + out.append("'").append(this->device_class).append("'"); + out.append("\n"); + + out.append(" state_class: "); + out.append(proto_enum_to_string(this->state_class)); + out.append("\n"); + + out.append(" legacy_last_reset_type: "); + out.append(proto_enum_to_string(this->legacy_last_reset_type)); + out.append("\n"); + + out.append(" disabled_by_default: "); + out.append(YESNO(this->disabled_by_default)); + out.append("\n"); + + out.append(" entity_category: "); + out.append(proto_enum_to_string(this->entity_category)); + out.append("\n"); + + out.append(" device_id: "); + sprintf(buffer, "%" PRIu32, this->device_id); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void SensorStateResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("SensorStateResponse {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" state: "); + sprintf(buffer, "%g", this->state); + out.append(buffer); + out.append("\n"); + + out.append(" missing_state: "); + out.append(YESNO(this->missing_state)); + out.append("\n"); + out.append("}"); +} +#endif +#ifdef USE_SWITCH +void ListEntitiesSwitchResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("ListEntitiesSwitchResponse {\n"); + out.append(" object_id: "); + out.append("'").append(this->object_id).append("'"); + out.append("\n"); + + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" name: "); + out.append("'").append(this->name).append("'"); + out.append("\n"); + + out.append(" unique_id: "); + out.append("'").append(this->unique_id).append("'"); + out.append("\n"); + + out.append(" icon: "); + out.append("'").append(this->icon).append("'"); + out.append("\n"); + + out.append(" assumed_state: "); + out.append(YESNO(this->assumed_state)); + out.append("\n"); + + out.append(" disabled_by_default: "); + out.append(YESNO(this->disabled_by_default)); + out.append("\n"); + + out.append(" entity_category: "); + out.append(proto_enum_to_string(this->entity_category)); + out.append("\n"); + + out.append(" device_class: "); + out.append("'").append(this->device_class).append("'"); + out.append("\n"); + + out.append(" device_id: "); + sprintf(buffer, "%" PRIu32, this->device_id); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void SwitchStateResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("SwitchStateResponse {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" state: "); + out.append(YESNO(this->state)); + out.append("\n"); + out.append("}"); +} +void SwitchCommandRequest::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("SwitchCommandRequest {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" state: "); + out.append(YESNO(this->state)); + out.append("\n"); + out.append("}"); +} +#endif +#ifdef USE_TEXT_SENSOR +void ListEntitiesTextSensorResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("ListEntitiesTextSensorResponse {\n"); + out.append(" object_id: "); + out.append("'").append(this->object_id).append("'"); + out.append("\n"); + + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" name: "); + out.append("'").append(this->name).append("'"); + out.append("\n"); + + out.append(" unique_id: "); + out.append("'").append(this->unique_id).append("'"); + out.append("\n"); + + out.append(" icon: "); + out.append("'").append(this->icon).append("'"); + out.append("\n"); + + out.append(" disabled_by_default: "); + out.append(YESNO(this->disabled_by_default)); + out.append("\n"); + + out.append(" entity_category: "); + out.append(proto_enum_to_string(this->entity_category)); + out.append("\n"); + + out.append(" device_class: "); + out.append("'").append(this->device_class).append("'"); + out.append("\n"); + + out.append(" device_id: "); + sprintf(buffer, "%" PRIu32, this->device_id); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void TextSensorStateResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("TextSensorStateResponse {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" state: "); + out.append("'").append(this->state).append("'"); + out.append("\n"); + + out.append(" missing_state: "); + out.append(YESNO(this->missing_state)); + out.append("\n"); + out.append("}"); +} +#endif +void SubscribeLogsRequest::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("SubscribeLogsRequest {\n"); + out.append(" level: "); + out.append(proto_enum_to_string(this->level)); + out.append("\n"); + + out.append(" dump_config: "); + out.append(YESNO(this->dump_config)); + out.append("\n"); + out.append("}"); +} +void SubscribeLogsResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("SubscribeLogsResponse {\n"); + out.append(" level: "); + out.append(proto_enum_to_string(this->level)); + out.append("\n"); + + out.append(" message: "); + out.append(format_hex_pretty(this->message)); + out.append("\n"); + + out.append(" send_failed: "); + out.append(YESNO(this->send_failed)); + out.append("\n"); + out.append("}"); +} +#ifdef USE_API_NOISE +void NoiseEncryptionSetKeyRequest::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("NoiseEncryptionSetKeyRequest {\n"); + out.append(" key: "); + out.append(format_hex_pretty(this->key)); + out.append("\n"); + out.append("}"); +} +void NoiseEncryptionSetKeyResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("NoiseEncryptionSetKeyResponse {\n"); + out.append(" success: "); + out.append(YESNO(this->success)); + out.append("\n"); + out.append("}"); +} +#endif +void SubscribeHomeassistantServicesRequest::dump_to(std::string &out) const { + out.append("SubscribeHomeassistantServicesRequest {}"); +} +void HomeassistantServiceMap::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("HomeassistantServiceMap {\n"); + out.append(" key: "); + out.append("'").append(this->key).append("'"); + out.append("\n"); + + out.append(" value: "); + out.append("'").append(this->value).append("'"); + out.append("\n"); + out.append("}"); +} +void HomeassistantServiceResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("HomeassistantServiceResponse {\n"); + out.append(" service: "); + out.append("'").append(this->service).append("'"); + out.append("\n"); + + for (const auto &it : this->data) { + out.append(" data: "); + it.dump_to(out); + out.append("\n"); + } + + for (const auto &it : this->data_template) { + out.append(" data_template: "); + it.dump_to(out); + out.append("\n"); + } + + for (const auto &it : this->variables) { + out.append(" variables: "); + it.dump_to(out); + out.append("\n"); + } + + out.append(" is_event: "); + out.append(YESNO(this->is_event)); + out.append("\n"); + out.append("}"); +} +void SubscribeHomeAssistantStatesRequest::dump_to(std::string &out) const { + out.append("SubscribeHomeAssistantStatesRequest {}"); +} +void SubscribeHomeAssistantStateResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("SubscribeHomeAssistantStateResponse {\n"); + out.append(" entity_id: "); + out.append("'").append(this->entity_id).append("'"); + out.append("\n"); + + out.append(" attribute: "); + out.append("'").append(this->attribute).append("'"); + out.append("\n"); + + out.append(" once: "); + out.append(YESNO(this->once)); + out.append("\n"); + out.append("}"); +} +void HomeAssistantStateResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("HomeAssistantStateResponse {\n"); + out.append(" entity_id: "); + out.append("'").append(this->entity_id).append("'"); + out.append("\n"); + + out.append(" state: "); + out.append("'").append(this->state).append("'"); + out.append("\n"); + + out.append(" attribute: "); + out.append("'").append(this->attribute).append("'"); + out.append("\n"); + out.append("}"); +} +void GetTimeRequest::dump_to(std::string &out) const { out.append("GetTimeRequest {}"); } +void GetTimeResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("GetTimeResponse {\n"); + out.append(" epoch_seconds: "); + sprintf(buffer, "%" PRIu32, this->epoch_seconds); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void ListEntitiesServicesArgument::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("ListEntitiesServicesArgument {\n"); + out.append(" name: "); + out.append("'").append(this->name).append("'"); + out.append("\n"); + + out.append(" type: "); + out.append(proto_enum_to_string(this->type)); + out.append("\n"); + out.append("}"); +} +void ListEntitiesServicesResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("ListEntitiesServicesResponse {\n"); + out.append(" name: "); + out.append("'").append(this->name).append("'"); + out.append("\n"); + + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + for (const auto &it : this->args) { + out.append(" args: "); + it.dump_to(out); + out.append("\n"); + } + out.append("}"); +} +void ExecuteServiceArgument::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("ExecuteServiceArgument {\n"); + out.append(" bool_: "); + out.append(YESNO(this->bool_)); + out.append("\n"); + + out.append(" legacy_int: "); + sprintf(buffer, "%" PRId32, this->legacy_int); + out.append(buffer); + out.append("\n"); + + out.append(" float_: "); + sprintf(buffer, "%g", this->float_); + out.append(buffer); + out.append("\n"); + + out.append(" string_: "); + out.append("'").append(this->string_).append("'"); + out.append("\n"); + + out.append(" int_: "); + sprintf(buffer, "%" PRId32, this->int_); + out.append(buffer); + out.append("\n"); + + for (const auto it : this->bool_array) { + out.append(" bool_array: "); + out.append(YESNO(it)); + out.append("\n"); + } + + for (const auto &it : this->int_array) { + out.append(" int_array: "); + sprintf(buffer, "%" PRId32, it); + out.append(buffer); + out.append("\n"); + } + + for (const auto &it : this->float_array) { + out.append(" float_array: "); + sprintf(buffer, "%g", it); + out.append(buffer); + out.append("\n"); + } + + for (const auto &it : this->string_array) { + out.append(" string_array: "); + out.append("'").append(it).append("'"); + out.append("\n"); + } + out.append("}"); +} +void ExecuteServiceRequest::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("ExecuteServiceRequest {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + for (const auto &it : this->args) { + out.append(" args: "); + it.dump_to(out); + out.append("\n"); + } + out.append("}"); +} +#ifdef USE_ESP32_CAMERA +void ListEntitiesCameraResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("ListEntitiesCameraResponse {\n"); + out.append(" object_id: "); + out.append("'").append(this->object_id).append("'"); + out.append("\n"); + + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" name: "); + out.append("'").append(this->name).append("'"); + out.append("\n"); + + out.append(" unique_id: "); + out.append("'").append(this->unique_id).append("'"); + out.append("\n"); + + out.append(" disabled_by_default: "); + out.append(YESNO(this->disabled_by_default)); + out.append("\n"); + + out.append(" icon: "); + out.append("'").append(this->icon).append("'"); + out.append("\n"); + + out.append(" entity_category: "); + out.append(proto_enum_to_string(this->entity_category)); + out.append("\n"); + + out.append(" device_id: "); + sprintf(buffer, "%" PRIu32, this->device_id); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void CameraImageResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("CameraImageResponse {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" data: "); + out.append(format_hex_pretty(this->data)); + out.append("\n"); + + out.append(" done: "); + out.append(YESNO(this->done)); + out.append("\n"); + out.append("}"); +} +void CameraImageRequest::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("CameraImageRequest {\n"); + out.append(" single: "); + out.append(YESNO(this->single)); + out.append("\n"); + + out.append(" stream: "); + out.append(YESNO(this->stream)); + out.append("\n"); + out.append("}"); +} +#endif +#ifdef USE_CLIMATE +void ListEntitiesClimateResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("ListEntitiesClimateResponse {\n"); + out.append(" object_id: "); + out.append("'").append(this->object_id).append("'"); + out.append("\n"); + + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" name: "); + out.append("'").append(this->name).append("'"); + out.append("\n"); + + out.append(" unique_id: "); + out.append("'").append(this->unique_id).append("'"); + out.append("\n"); + + out.append(" supports_current_temperature: "); + out.append(YESNO(this->supports_current_temperature)); + out.append("\n"); + + out.append(" supports_two_point_target_temperature: "); + out.append(YESNO(this->supports_two_point_target_temperature)); + out.append("\n"); + + for (const auto &it : this->supported_modes) { + out.append(" supported_modes: "); + out.append(proto_enum_to_string(it)); + out.append("\n"); + } + + out.append(" visual_min_temperature: "); + sprintf(buffer, "%g", this->visual_min_temperature); + out.append(buffer); + out.append("\n"); + + out.append(" visual_max_temperature: "); + sprintf(buffer, "%g", this->visual_max_temperature); + out.append(buffer); + out.append("\n"); + + out.append(" visual_target_temperature_step: "); + sprintf(buffer, "%g", this->visual_target_temperature_step); + out.append(buffer); + out.append("\n"); + + out.append(" legacy_supports_away: "); + out.append(YESNO(this->legacy_supports_away)); + out.append("\n"); + + out.append(" supports_action: "); + out.append(YESNO(this->supports_action)); + out.append("\n"); + + for (const auto &it : this->supported_fan_modes) { + out.append(" supported_fan_modes: "); + out.append(proto_enum_to_string(it)); + out.append("\n"); + } + + for (const auto &it : this->supported_swing_modes) { + out.append(" supported_swing_modes: "); + out.append(proto_enum_to_string(it)); + out.append("\n"); + } + + for (const auto &it : this->supported_custom_fan_modes) { + out.append(" supported_custom_fan_modes: "); + out.append("'").append(it).append("'"); + out.append("\n"); + } + + for (const auto &it : this->supported_presets) { + out.append(" supported_presets: "); + out.append(proto_enum_to_string(it)); + out.append("\n"); + } + + for (const auto &it : this->supported_custom_presets) { + out.append(" supported_custom_presets: "); + out.append("'").append(it).append("'"); + out.append("\n"); + } + + out.append(" disabled_by_default: "); + out.append(YESNO(this->disabled_by_default)); + out.append("\n"); + + out.append(" icon: "); + out.append("'").append(this->icon).append("'"); + out.append("\n"); + + out.append(" entity_category: "); + out.append(proto_enum_to_string(this->entity_category)); + out.append("\n"); + + out.append(" visual_current_temperature_step: "); + sprintf(buffer, "%g", this->visual_current_temperature_step); + out.append(buffer); + out.append("\n"); + + out.append(" supports_current_humidity: "); + out.append(YESNO(this->supports_current_humidity)); + out.append("\n"); + + out.append(" supports_target_humidity: "); + out.append(YESNO(this->supports_target_humidity)); + out.append("\n"); + + out.append(" visual_min_humidity: "); + sprintf(buffer, "%g", this->visual_min_humidity); + out.append(buffer); + out.append("\n"); + + out.append(" visual_max_humidity: "); + sprintf(buffer, "%g", this->visual_max_humidity); + out.append(buffer); + out.append("\n"); + + out.append(" device_id: "); + sprintf(buffer, "%" PRIu32, this->device_id); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void ClimateStateResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("ClimateStateResponse {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" mode: "); + out.append(proto_enum_to_string(this->mode)); + out.append("\n"); + + out.append(" current_temperature: "); + sprintf(buffer, "%g", this->current_temperature); + out.append(buffer); + out.append("\n"); + + out.append(" target_temperature: "); + sprintf(buffer, "%g", this->target_temperature); + out.append(buffer); + out.append("\n"); + + out.append(" target_temperature_low: "); + sprintf(buffer, "%g", this->target_temperature_low); + out.append(buffer); + out.append("\n"); + + out.append(" target_temperature_high: "); + sprintf(buffer, "%g", this->target_temperature_high); + out.append(buffer); + out.append("\n"); + + out.append(" unused_legacy_away: "); + out.append(YESNO(this->unused_legacy_away)); + out.append("\n"); + + out.append(" action: "); + out.append(proto_enum_to_string(this->action)); + out.append("\n"); + + out.append(" fan_mode: "); + out.append(proto_enum_to_string(this->fan_mode)); + out.append("\n"); + + out.append(" swing_mode: "); + out.append(proto_enum_to_string(this->swing_mode)); + out.append("\n"); + + out.append(" custom_fan_mode: "); + out.append("'").append(this->custom_fan_mode).append("'"); + out.append("\n"); + + out.append(" preset: "); + out.append(proto_enum_to_string(this->preset)); + out.append("\n"); + + out.append(" custom_preset: "); + out.append("'").append(this->custom_preset).append("'"); + out.append("\n"); + + out.append(" current_humidity: "); + sprintf(buffer, "%g", this->current_humidity); + out.append(buffer); + out.append("\n"); + + out.append(" target_humidity: "); + sprintf(buffer, "%g", this->target_humidity); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void ClimateCommandRequest::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("ClimateCommandRequest {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" has_mode: "); + out.append(YESNO(this->has_mode)); + out.append("\n"); + + out.append(" mode: "); + out.append(proto_enum_to_string(this->mode)); + out.append("\n"); + + out.append(" has_target_temperature: "); + out.append(YESNO(this->has_target_temperature)); + out.append("\n"); + + out.append(" target_temperature: "); + sprintf(buffer, "%g", this->target_temperature); + out.append(buffer); + out.append("\n"); + + out.append(" has_target_temperature_low: "); + out.append(YESNO(this->has_target_temperature_low)); + out.append("\n"); + + out.append(" target_temperature_low: "); + sprintf(buffer, "%g", this->target_temperature_low); + out.append(buffer); + out.append("\n"); + + out.append(" has_target_temperature_high: "); + out.append(YESNO(this->has_target_temperature_high)); + out.append("\n"); + + out.append(" target_temperature_high: "); + sprintf(buffer, "%g", this->target_temperature_high); + out.append(buffer); + out.append("\n"); + + out.append(" unused_has_legacy_away: "); + out.append(YESNO(this->unused_has_legacy_away)); + out.append("\n"); + + out.append(" unused_legacy_away: "); + out.append(YESNO(this->unused_legacy_away)); + out.append("\n"); + + out.append(" has_fan_mode: "); + out.append(YESNO(this->has_fan_mode)); + out.append("\n"); + + out.append(" fan_mode: "); + out.append(proto_enum_to_string(this->fan_mode)); + out.append("\n"); + + out.append(" has_swing_mode: "); + out.append(YESNO(this->has_swing_mode)); + out.append("\n"); + + out.append(" swing_mode: "); + out.append(proto_enum_to_string(this->swing_mode)); + out.append("\n"); + + out.append(" has_custom_fan_mode: "); + out.append(YESNO(this->has_custom_fan_mode)); + out.append("\n"); + + out.append(" custom_fan_mode: "); + out.append("'").append(this->custom_fan_mode).append("'"); + out.append("\n"); + + out.append(" has_preset: "); + out.append(YESNO(this->has_preset)); + out.append("\n"); + + out.append(" preset: "); + out.append(proto_enum_to_string(this->preset)); + out.append("\n"); + + out.append(" has_custom_preset: "); + out.append(YESNO(this->has_custom_preset)); + out.append("\n"); + + out.append(" custom_preset: "); + out.append("'").append(this->custom_preset).append("'"); + out.append("\n"); + + out.append(" has_target_humidity: "); + out.append(YESNO(this->has_target_humidity)); + out.append("\n"); + + out.append(" target_humidity: "); + sprintf(buffer, "%g", this->target_humidity); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +#endif +#ifdef USE_NUMBER +void ListEntitiesNumberResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("ListEntitiesNumberResponse {\n"); + out.append(" object_id: "); + out.append("'").append(this->object_id).append("'"); + out.append("\n"); + + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" name: "); + out.append("'").append(this->name).append("'"); + out.append("\n"); + + out.append(" unique_id: "); + out.append("'").append(this->unique_id).append("'"); + out.append("\n"); + + out.append(" icon: "); + out.append("'").append(this->icon).append("'"); + out.append("\n"); + + out.append(" min_value: "); + sprintf(buffer, "%g", this->min_value); + out.append(buffer); + out.append("\n"); + + out.append(" max_value: "); + sprintf(buffer, "%g", this->max_value); + out.append(buffer); + out.append("\n"); + + out.append(" step: "); + sprintf(buffer, "%g", this->step); + out.append(buffer); + out.append("\n"); + + out.append(" disabled_by_default: "); + out.append(YESNO(this->disabled_by_default)); + out.append("\n"); + + out.append(" entity_category: "); + out.append(proto_enum_to_string(this->entity_category)); + out.append("\n"); + + out.append(" unit_of_measurement: "); + out.append("'").append(this->unit_of_measurement).append("'"); + out.append("\n"); + + out.append(" mode: "); + out.append(proto_enum_to_string(this->mode)); + out.append("\n"); + + out.append(" device_class: "); + out.append("'").append(this->device_class).append("'"); + out.append("\n"); + + out.append(" device_id: "); + sprintf(buffer, "%" PRIu32, this->device_id); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void NumberStateResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("NumberStateResponse {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" state: "); + sprintf(buffer, "%g", this->state); + out.append(buffer); + out.append("\n"); + + out.append(" missing_state: "); + out.append(YESNO(this->missing_state)); + out.append("\n"); + out.append("}"); +} +void NumberCommandRequest::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("NumberCommandRequest {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" state: "); + sprintf(buffer, "%g", this->state); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +#endif +#ifdef USE_SELECT +void ListEntitiesSelectResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("ListEntitiesSelectResponse {\n"); + out.append(" object_id: "); + out.append("'").append(this->object_id).append("'"); + out.append("\n"); + + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" name: "); + out.append("'").append(this->name).append("'"); + out.append("\n"); + + out.append(" unique_id: "); + out.append("'").append(this->unique_id).append("'"); + out.append("\n"); + + out.append(" icon: "); + out.append("'").append(this->icon).append("'"); + out.append("\n"); + + for (const auto &it : this->options) { + out.append(" options: "); + out.append("'").append(it).append("'"); + out.append("\n"); + } + + out.append(" disabled_by_default: "); + out.append(YESNO(this->disabled_by_default)); + out.append("\n"); + + out.append(" entity_category: "); + out.append(proto_enum_to_string(this->entity_category)); + out.append("\n"); + + out.append(" device_id: "); + sprintf(buffer, "%" PRIu32, this->device_id); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void SelectStateResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("SelectStateResponse {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" state: "); + out.append("'").append(this->state).append("'"); + out.append("\n"); + + out.append(" missing_state: "); + out.append(YESNO(this->missing_state)); + out.append("\n"); + out.append("}"); +} +void SelectCommandRequest::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("SelectCommandRequest {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" state: "); + out.append("'").append(this->state).append("'"); + out.append("\n"); + out.append("}"); +} +#endif +#ifdef USE_SIREN +void ListEntitiesSirenResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("ListEntitiesSirenResponse {\n"); + out.append(" object_id: "); + out.append("'").append(this->object_id).append("'"); + out.append("\n"); + + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" name: "); + out.append("'").append(this->name).append("'"); + out.append("\n"); + + out.append(" unique_id: "); + out.append("'").append(this->unique_id).append("'"); + out.append("\n"); + + out.append(" icon: "); + out.append("'").append(this->icon).append("'"); + out.append("\n"); + + out.append(" disabled_by_default: "); + out.append(YESNO(this->disabled_by_default)); + out.append("\n"); + + for (const auto &it : this->tones) { + out.append(" tones: "); + out.append("'").append(it).append("'"); + out.append("\n"); + } + + out.append(" supports_duration: "); + out.append(YESNO(this->supports_duration)); + out.append("\n"); + + out.append(" supports_volume: "); + out.append(YESNO(this->supports_volume)); + out.append("\n"); + + out.append(" entity_category: "); + out.append(proto_enum_to_string(this->entity_category)); + out.append("\n"); + + out.append(" device_id: "); + sprintf(buffer, "%" PRIu32, this->device_id); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void SirenStateResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("SirenStateResponse {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" state: "); + out.append(YESNO(this->state)); + out.append("\n"); + out.append("}"); +} +void SirenCommandRequest::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("SirenCommandRequest {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" has_state: "); + out.append(YESNO(this->has_state)); + out.append("\n"); + + out.append(" state: "); + out.append(YESNO(this->state)); + out.append("\n"); + + out.append(" has_tone: "); + out.append(YESNO(this->has_tone)); + out.append("\n"); + + out.append(" tone: "); + out.append("'").append(this->tone).append("'"); + out.append("\n"); + + out.append(" has_duration: "); + out.append(YESNO(this->has_duration)); + out.append("\n"); + + out.append(" duration: "); + sprintf(buffer, "%" PRIu32, this->duration); + out.append(buffer); + out.append("\n"); + + out.append(" has_volume: "); + out.append(YESNO(this->has_volume)); + out.append("\n"); + + out.append(" volume: "); + sprintf(buffer, "%g", this->volume); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +#endif +#ifdef USE_LOCK +void ListEntitiesLockResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("ListEntitiesLockResponse {\n"); + out.append(" object_id: "); + out.append("'").append(this->object_id).append("'"); + out.append("\n"); + + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" name: "); + out.append("'").append(this->name).append("'"); + out.append("\n"); + + out.append(" unique_id: "); + out.append("'").append(this->unique_id).append("'"); + out.append("\n"); + + out.append(" icon: "); + out.append("'").append(this->icon).append("'"); + out.append("\n"); + + out.append(" disabled_by_default: "); + out.append(YESNO(this->disabled_by_default)); + out.append("\n"); + + out.append(" entity_category: "); + out.append(proto_enum_to_string(this->entity_category)); + out.append("\n"); + + out.append(" assumed_state: "); + out.append(YESNO(this->assumed_state)); + out.append("\n"); + + out.append(" supports_open: "); + out.append(YESNO(this->supports_open)); + out.append("\n"); + + out.append(" requires_code: "); + out.append(YESNO(this->requires_code)); + out.append("\n"); + + out.append(" code_format: "); + out.append("'").append(this->code_format).append("'"); + out.append("\n"); + + out.append(" device_id: "); + sprintf(buffer, "%" PRIu32, this->device_id); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void LockStateResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("LockStateResponse {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" state: "); + out.append(proto_enum_to_string(this->state)); + out.append("\n"); + out.append("}"); +} +void LockCommandRequest::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("LockCommandRequest {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" command: "); + out.append(proto_enum_to_string(this->command)); + out.append("\n"); + + out.append(" has_code: "); + out.append(YESNO(this->has_code)); + out.append("\n"); + + out.append(" code: "); + out.append("'").append(this->code).append("'"); + out.append("\n"); + out.append("}"); +} +#endif +#ifdef USE_BUTTON +void ListEntitiesButtonResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("ListEntitiesButtonResponse {\n"); + out.append(" object_id: "); + out.append("'").append(this->object_id).append("'"); + out.append("\n"); + + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" name: "); + out.append("'").append(this->name).append("'"); + out.append("\n"); + + out.append(" unique_id: "); + out.append("'").append(this->unique_id).append("'"); + out.append("\n"); + + out.append(" icon: "); + out.append("'").append(this->icon).append("'"); + out.append("\n"); + + out.append(" disabled_by_default: "); + out.append(YESNO(this->disabled_by_default)); + out.append("\n"); + + out.append(" entity_category: "); + out.append(proto_enum_to_string(this->entity_category)); + out.append("\n"); + + out.append(" device_class: "); + out.append("'").append(this->device_class).append("'"); + out.append("\n"); + + out.append(" device_id: "); + sprintf(buffer, "%" PRIu32, this->device_id); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void ButtonCommandRequest::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("ButtonCommandRequest {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +#endif +#ifdef USE_MEDIA_PLAYER +void MediaPlayerSupportedFormat::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("MediaPlayerSupportedFormat {\n"); + out.append(" format: "); + out.append("'").append(this->format).append("'"); + out.append("\n"); + + out.append(" sample_rate: "); + sprintf(buffer, "%" PRIu32, this->sample_rate); + out.append(buffer); + out.append("\n"); + + out.append(" num_channels: "); + sprintf(buffer, "%" PRIu32, this->num_channels); + out.append(buffer); + out.append("\n"); + + out.append(" purpose: "); + out.append(proto_enum_to_string(this->purpose)); + out.append("\n"); + + out.append(" sample_bytes: "); + sprintf(buffer, "%" PRIu32, this->sample_bytes); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void ListEntitiesMediaPlayerResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("ListEntitiesMediaPlayerResponse {\n"); + out.append(" object_id: "); + out.append("'").append(this->object_id).append("'"); + out.append("\n"); + + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" name: "); + out.append("'").append(this->name).append("'"); + out.append("\n"); + + out.append(" unique_id: "); + out.append("'").append(this->unique_id).append("'"); + out.append("\n"); + + out.append(" icon: "); + out.append("'").append(this->icon).append("'"); + out.append("\n"); + + out.append(" disabled_by_default: "); + out.append(YESNO(this->disabled_by_default)); + out.append("\n"); + + out.append(" entity_category: "); + out.append(proto_enum_to_string(this->entity_category)); + out.append("\n"); + + out.append(" supports_pause: "); + out.append(YESNO(this->supports_pause)); + out.append("\n"); + + for (const auto &it : this->supported_formats) { + out.append(" supported_formats: "); + it.dump_to(out); + out.append("\n"); + } + + out.append(" device_id: "); + sprintf(buffer, "%" PRIu32, this->device_id); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void MediaPlayerStateResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("MediaPlayerStateResponse {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" state: "); + out.append(proto_enum_to_string(this->state)); + out.append("\n"); + + out.append(" volume: "); + sprintf(buffer, "%g", this->volume); + out.append(buffer); + out.append("\n"); + + out.append(" muted: "); + out.append(YESNO(this->muted)); + out.append("\n"); + out.append("}"); +} +void MediaPlayerCommandRequest::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("MediaPlayerCommandRequest {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" has_command: "); + out.append(YESNO(this->has_command)); + out.append("\n"); + + out.append(" command: "); + out.append(proto_enum_to_string(this->command)); + out.append("\n"); + + out.append(" has_volume: "); + out.append(YESNO(this->has_volume)); + out.append("\n"); + + out.append(" volume: "); + sprintf(buffer, "%g", this->volume); + out.append(buffer); + out.append("\n"); + + out.append(" has_media_url: "); + out.append(YESNO(this->has_media_url)); + out.append("\n"); + + out.append(" media_url: "); + out.append("'").append(this->media_url).append("'"); + out.append("\n"); + + out.append(" has_announcement: "); + out.append(YESNO(this->has_announcement)); + out.append("\n"); + + out.append(" announcement: "); + out.append(YESNO(this->announcement)); + out.append("\n"); + out.append("}"); +} +#endif +#ifdef USE_BLUETOOTH_PROXY +void SubscribeBluetoothLEAdvertisementsRequest::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("SubscribeBluetoothLEAdvertisementsRequest {\n"); + out.append(" flags: "); + sprintf(buffer, "%" PRIu32, this->flags); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void BluetoothServiceData::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("BluetoothServiceData {\n"); + out.append(" uuid: "); + out.append("'").append(this->uuid).append("'"); + out.append("\n"); + + for (const auto &it : this->legacy_data) { + out.append(" legacy_data: "); + sprintf(buffer, "%" PRIu32, it); + out.append(buffer); + out.append("\n"); + } + + out.append(" data: "); + out.append(format_hex_pretty(this->data)); + out.append("\n"); + out.append("}"); +} +void BluetoothLEAdvertisementResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("BluetoothLEAdvertisementResponse {\n"); + out.append(" address: "); + sprintf(buffer, "%llu", this->address); + out.append(buffer); + out.append("\n"); + + out.append(" name: "); + out.append(format_hex_pretty(this->name)); + out.append("\n"); + + out.append(" rssi: "); + sprintf(buffer, "%" PRId32, this->rssi); + out.append(buffer); + out.append("\n"); + + for (const auto &it : this->service_uuids) { + out.append(" service_uuids: "); + out.append("'").append(it).append("'"); + out.append("\n"); + } + + for (const auto &it : this->service_data) { + out.append(" service_data: "); + it.dump_to(out); + out.append("\n"); + } + + for (const auto &it : this->manufacturer_data) { + out.append(" manufacturer_data: "); + it.dump_to(out); + out.append("\n"); + } + + out.append(" address_type: "); + sprintf(buffer, "%" PRIu32, this->address_type); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void BluetoothLERawAdvertisement::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("BluetoothLERawAdvertisement {\n"); + out.append(" address: "); + sprintf(buffer, "%llu", this->address); + out.append(buffer); + out.append("\n"); + + out.append(" rssi: "); + sprintf(buffer, "%" PRId32, this->rssi); + out.append(buffer); + out.append("\n"); + + out.append(" address_type: "); + sprintf(buffer, "%" PRIu32, this->address_type); + out.append(buffer); + out.append("\n"); + + out.append(" data: "); + out.append(format_hex_pretty(this->data)); + out.append("\n"); + out.append("}"); +} +void BluetoothLERawAdvertisementsResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("BluetoothLERawAdvertisementsResponse {\n"); + for (const auto &it : this->advertisements) { + out.append(" advertisements: "); + it.dump_to(out); + out.append("\n"); + } + out.append("}"); +} +void BluetoothDeviceRequest::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("BluetoothDeviceRequest {\n"); + out.append(" address: "); + sprintf(buffer, "%llu", this->address); + out.append(buffer); + out.append("\n"); + + out.append(" request_type: "); + out.append(proto_enum_to_string(this->request_type)); + out.append("\n"); + + out.append(" has_address_type: "); + out.append(YESNO(this->has_address_type)); + out.append("\n"); + + out.append(" address_type: "); + sprintf(buffer, "%" PRIu32, this->address_type); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void BluetoothDeviceConnectionResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("BluetoothDeviceConnectionResponse {\n"); + out.append(" address: "); + sprintf(buffer, "%llu", this->address); + out.append(buffer); + out.append("\n"); + + out.append(" connected: "); + out.append(YESNO(this->connected)); + out.append("\n"); + + out.append(" mtu: "); + sprintf(buffer, "%" PRIu32, this->mtu); + out.append(buffer); + out.append("\n"); + + out.append(" error: "); + sprintf(buffer, "%" PRId32, this->error); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void BluetoothGATTGetServicesRequest::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("BluetoothGATTGetServicesRequest {\n"); + out.append(" address: "); + sprintf(buffer, "%llu", this->address); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void BluetoothGATTDescriptor::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("BluetoothGATTDescriptor {\n"); + for (const auto &it : this->uuid) { + out.append(" uuid: "); + sprintf(buffer, "%llu", it); + out.append(buffer); + out.append("\n"); + } + + out.append(" handle: "); + sprintf(buffer, "%" PRIu32, this->handle); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void BluetoothGATTCharacteristic::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("BluetoothGATTCharacteristic {\n"); + for (const auto &it : this->uuid) { + out.append(" uuid: "); + sprintf(buffer, "%llu", it); + out.append(buffer); + out.append("\n"); + } + + out.append(" handle: "); + sprintf(buffer, "%" PRIu32, this->handle); + out.append(buffer); + out.append("\n"); + + out.append(" properties: "); + sprintf(buffer, "%" PRIu32, this->properties); + out.append(buffer); + out.append("\n"); + + for (const auto &it : this->descriptors) { + out.append(" descriptors: "); + it.dump_to(out); + out.append("\n"); + } + out.append("}"); +} +void BluetoothGATTService::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("BluetoothGATTService {\n"); + for (const auto &it : this->uuid) { + out.append(" uuid: "); + sprintf(buffer, "%llu", it); + out.append(buffer); + out.append("\n"); + } + + out.append(" handle: "); + sprintf(buffer, "%" PRIu32, this->handle); + out.append(buffer); + out.append("\n"); + + for (const auto &it : this->characteristics) { + out.append(" characteristics: "); + it.dump_to(out); + out.append("\n"); + } + out.append("}"); +} +void BluetoothGATTGetServicesResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("BluetoothGATTGetServicesResponse {\n"); + out.append(" address: "); + sprintf(buffer, "%llu", this->address); + out.append(buffer); + out.append("\n"); + + for (const auto &it : this->services) { + out.append(" services: "); + it.dump_to(out); + out.append("\n"); + } + out.append("}"); +} +void BluetoothGATTGetServicesDoneResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("BluetoothGATTGetServicesDoneResponse {\n"); + out.append(" address: "); + sprintf(buffer, "%llu", this->address); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void BluetoothGATTReadRequest::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("BluetoothGATTReadRequest {\n"); + out.append(" address: "); + sprintf(buffer, "%llu", this->address); + out.append(buffer); + out.append("\n"); + + out.append(" handle: "); + sprintf(buffer, "%" PRIu32, this->handle); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void BluetoothGATTReadResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("BluetoothGATTReadResponse {\n"); + out.append(" address: "); + sprintf(buffer, "%llu", this->address); + out.append(buffer); + out.append("\n"); + + out.append(" handle: "); + sprintf(buffer, "%" PRIu32, this->handle); + out.append(buffer); + out.append("\n"); + + out.append(" data: "); + out.append(format_hex_pretty(this->data)); + out.append("\n"); + out.append("}"); +} +void BluetoothGATTWriteRequest::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("BluetoothGATTWriteRequest {\n"); + out.append(" address: "); + sprintf(buffer, "%llu", this->address); + out.append(buffer); + out.append("\n"); + + out.append(" handle: "); + sprintf(buffer, "%" PRIu32, this->handle); + out.append(buffer); + out.append("\n"); + + out.append(" response: "); + out.append(YESNO(this->response)); + out.append("\n"); + + out.append(" data: "); + out.append(format_hex_pretty(this->data)); + out.append("\n"); + out.append("}"); +} +void BluetoothGATTReadDescriptorRequest::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("BluetoothGATTReadDescriptorRequest {\n"); + out.append(" address: "); + sprintf(buffer, "%llu", this->address); + out.append(buffer); + out.append("\n"); + + out.append(" handle: "); + sprintf(buffer, "%" PRIu32, this->handle); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void BluetoothGATTWriteDescriptorRequest::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("BluetoothGATTWriteDescriptorRequest {\n"); + out.append(" address: "); + sprintf(buffer, "%llu", this->address); + out.append(buffer); + out.append("\n"); + + out.append(" handle: "); + sprintf(buffer, "%" PRIu32, this->handle); + out.append(buffer); + out.append("\n"); + + out.append(" data: "); + out.append(format_hex_pretty(this->data)); + out.append("\n"); + out.append("}"); +} +void BluetoothGATTNotifyRequest::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("BluetoothGATTNotifyRequest {\n"); + out.append(" address: "); + sprintf(buffer, "%llu", this->address); + out.append(buffer); + out.append("\n"); + + out.append(" handle: "); + sprintf(buffer, "%" PRIu32, this->handle); + out.append(buffer); + out.append("\n"); + + out.append(" enable: "); + out.append(YESNO(this->enable)); + out.append("\n"); + out.append("}"); +} +void BluetoothGATTNotifyDataResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("BluetoothGATTNotifyDataResponse {\n"); + out.append(" address: "); + sprintf(buffer, "%llu", this->address); + out.append(buffer); + out.append("\n"); + + out.append(" handle: "); + sprintf(buffer, "%" PRIu32, this->handle); + out.append(buffer); + out.append("\n"); + + out.append(" data: "); + out.append(format_hex_pretty(this->data)); + out.append("\n"); + out.append("}"); +} +void SubscribeBluetoothConnectionsFreeRequest::dump_to(std::string &out) const { + out.append("SubscribeBluetoothConnectionsFreeRequest {}"); +} +void BluetoothConnectionsFreeResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("BluetoothConnectionsFreeResponse {\n"); + out.append(" free: "); + sprintf(buffer, "%" PRIu32, this->free); + out.append(buffer); + out.append("\n"); + + out.append(" limit: "); + sprintf(buffer, "%" PRIu32, this->limit); + out.append(buffer); + out.append("\n"); + + for (const auto &it : this->allocated) { + out.append(" allocated: "); + sprintf(buffer, "%llu", it); + out.append(buffer); + out.append("\n"); + } + out.append("}"); +} +void BluetoothGATTErrorResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("BluetoothGATTErrorResponse {\n"); + out.append(" address: "); + sprintf(buffer, "%llu", this->address); + out.append(buffer); + out.append("\n"); + + out.append(" handle: "); + sprintf(buffer, "%" PRIu32, this->handle); + out.append(buffer); + out.append("\n"); + + out.append(" error: "); + sprintf(buffer, "%" PRId32, this->error); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void BluetoothGATTWriteResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("BluetoothGATTWriteResponse {\n"); + out.append(" address: "); + sprintf(buffer, "%llu", this->address); + out.append(buffer); + out.append("\n"); + + out.append(" handle: "); + sprintf(buffer, "%" PRIu32, this->handle); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void BluetoothGATTNotifyResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("BluetoothGATTNotifyResponse {\n"); + out.append(" address: "); + sprintf(buffer, "%llu", this->address); + out.append(buffer); + out.append("\n"); + + out.append(" handle: "); + sprintf(buffer, "%" PRIu32, this->handle); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void BluetoothDevicePairingResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("BluetoothDevicePairingResponse {\n"); + out.append(" address: "); + sprintf(buffer, "%llu", this->address); + out.append(buffer); + out.append("\n"); + + out.append(" paired: "); + out.append(YESNO(this->paired)); + out.append("\n"); + + out.append(" error: "); + sprintf(buffer, "%" PRId32, this->error); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void BluetoothDeviceUnpairingResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("BluetoothDeviceUnpairingResponse {\n"); + out.append(" address: "); + sprintf(buffer, "%llu", this->address); + out.append(buffer); + out.append("\n"); + + out.append(" success: "); + out.append(YESNO(this->success)); + out.append("\n"); + + out.append(" error: "); + sprintf(buffer, "%" PRId32, this->error); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void UnsubscribeBluetoothLEAdvertisementsRequest::dump_to(std::string &out) const { + out.append("UnsubscribeBluetoothLEAdvertisementsRequest {}"); +} +void BluetoothDeviceClearCacheResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("BluetoothDeviceClearCacheResponse {\n"); + out.append(" address: "); + sprintf(buffer, "%llu", this->address); + out.append(buffer); + out.append("\n"); + + out.append(" success: "); + out.append(YESNO(this->success)); + out.append("\n"); + + out.append(" error: "); + sprintf(buffer, "%" PRId32, this->error); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void BluetoothScannerStateResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("BluetoothScannerStateResponse {\n"); + out.append(" state: "); + out.append(proto_enum_to_string(this->state)); + out.append("\n"); + + out.append(" mode: "); + out.append(proto_enum_to_string(this->mode)); + out.append("\n"); + out.append("}"); +} +void BluetoothScannerSetModeRequest::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("BluetoothScannerSetModeRequest {\n"); + out.append(" mode: "); + out.append(proto_enum_to_string(this->mode)); + out.append("\n"); + out.append("}"); +} +#endif +#ifdef USE_VOICE_ASSISTANT +void SubscribeVoiceAssistantRequest::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("SubscribeVoiceAssistantRequest {\n"); + out.append(" subscribe: "); + out.append(YESNO(this->subscribe)); + out.append("\n"); + + out.append(" flags: "); + sprintf(buffer, "%" PRIu32, this->flags); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void VoiceAssistantAudioSettings::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("VoiceAssistantAudioSettings {\n"); + out.append(" noise_suppression_level: "); + sprintf(buffer, "%" PRIu32, this->noise_suppression_level); + out.append(buffer); + out.append("\n"); + + out.append(" auto_gain: "); + sprintf(buffer, "%" PRIu32, this->auto_gain); + out.append(buffer); + out.append("\n"); + + out.append(" volume_multiplier: "); + sprintf(buffer, "%g", this->volume_multiplier); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void VoiceAssistantRequest::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("VoiceAssistantRequest {\n"); + out.append(" start: "); + out.append(YESNO(this->start)); + out.append("\n"); + + out.append(" conversation_id: "); + out.append("'").append(this->conversation_id).append("'"); + out.append("\n"); + + out.append(" flags: "); + sprintf(buffer, "%" PRIu32, this->flags); + out.append(buffer); + out.append("\n"); + + out.append(" audio_settings: "); + this->audio_settings.dump_to(out); + out.append("\n"); + + out.append(" wake_word_phrase: "); + out.append("'").append(this->wake_word_phrase).append("'"); + out.append("\n"); + out.append("}"); +} +void VoiceAssistantResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("VoiceAssistantResponse {\n"); + out.append(" port: "); + sprintf(buffer, "%" PRIu32, this->port); + out.append(buffer); + out.append("\n"); + + out.append(" error: "); + out.append(YESNO(this->error)); + out.append("\n"); + out.append("}"); +} +void VoiceAssistantEventData::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("VoiceAssistantEventData {\n"); + out.append(" name: "); + out.append("'").append(this->name).append("'"); + out.append("\n"); + + out.append(" value: "); + out.append("'").append(this->value).append("'"); + out.append("\n"); + out.append("}"); +} +void VoiceAssistantEventResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("VoiceAssistantEventResponse {\n"); + out.append(" event_type: "); + out.append(proto_enum_to_string(this->event_type)); + out.append("\n"); + + for (const auto &it : this->data) { + out.append(" data: "); + it.dump_to(out); + out.append("\n"); + } + out.append("}"); +} +void VoiceAssistantAudio::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("VoiceAssistantAudio {\n"); + out.append(" data: "); + out.append(format_hex_pretty(this->data)); + out.append("\n"); + + out.append(" end: "); + out.append(YESNO(this->end)); + out.append("\n"); + out.append("}"); +} +void VoiceAssistantTimerEventResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("VoiceAssistantTimerEventResponse {\n"); + out.append(" event_type: "); + out.append(proto_enum_to_string(this->event_type)); + out.append("\n"); + + out.append(" timer_id: "); + out.append("'").append(this->timer_id).append("'"); + out.append("\n"); + + out.append(" name: "); + out.append("'").append(this->name).append("'"); + out.append("\n"); + + out.append(" total_seconds: "); + sprintf(buffer, "%" PRIu32, this->total_seconds); + out.append(buffer); + out.append("\n"); + + out.append(" seconds_left: "); + sprintf(buffer, "%" PRIu32, this->seconds_left); + out.append(buffer); + out.append("\n"); + + out.append(" is_active: "); + out.append(YESNO(this->is_active)); + out.append("\n"); + out.append("}"); +} +void VoiceAssistantAnnounceRequest::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("VoiceAssistantAnnounceRequest {\n"); + out.append(" media_id: "); + out.append("'").append(this->media_id).append("'"); + out.append("\n"); + + out.append(" text: "); + out.append("'").append(this->text).append("'"); + out.append("\n"); + + out.append(" preannounce_media_id: "); + out.append("'").append(this->preannounce_media_id).append("'"); + out.append("\n"); + + out.append(" start_conversation: "); + out.append(YESNO(this->start_conversation)); + out.append("\n"); + out.append("}"); +} +void VoiceAssistantAnnounceFinished::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("VoiceAssistantAnnounceFinished {\n"); + out.append(" success: "); + out.append(YESNO(this->success)); + out.append("\n"); + out.append("}"); +} +void VoiceAssistantWakeWord::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("VoiceAssistantWakeWord {\n"); + out.append(" id: "); + out.append("'").append(this->id).append("'"); + out.append("\n"); + + out.append(" wake_word: "); + out.append("'").append(this->wake_word).append("'"); + out.append("\n"); + + for (const auto &it : this->trained_languages) { + out.append(" trained_languages: "); + out.append("'").append(it).append("'"); + out.append("\n"); + } + out.append("}"); +} +void VoiceAssistantConfigurationRequest::dump_to(std::string &out) const { + out.append("VoiceAssistantConfigurationRequest {}"); +} +void VoiceAssistantConfigurationResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("VoiceAssistantConfigurationResponse {\n"); + for (const auto &it : this->available_wake_words) { + out.append(" available_wake_words: "); + it.dump_to(out); + out.append("\n"); + } + + for (const auto &it : this->active_wake_words) { + out.append(" active_wake_words: "); + out.append("'").append(it).append("'"); + out.append("\n"); + } + + out.append(" max_active_wake_words: "); + sprintf(buffer, "%" PRIu32, this->max_active_wake_words); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void VoiceAssistantSetConfiguration::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("VoiceAssistantSetConfiguration {\n"); + for (const auto &it : this->active_wake_words) { + out.append(" active_wake_words: "); + out.append("'").append(it).append("'"); + out.append("\n"); + } + out.append("}"); +} +#endif +#ifdef USE_ALARM_CONTROL_PANEL +void ListEntitiesAlarmControlPanelResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("ListEntitiesAlarmControlPanelResponse {\n"); + out.append(" object_id: "); + out.append("'").append(this->object_id).append("'"); + out.append("\n"); + + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" name: "); + out.append("'").append(this->name).append("'"); + out.append("\n"); + + out.append(" unique_id: "); + out.append("'").append(this->unique_id).append("'"); + out.append("\n"); + + out.append(" icon: "); + out.append("'").append(this->icon).append("'"); + out.append("\n"); + + out.append(" disabled_by_default: "); + out.append(YESNO(this->disabled_by_default)); + out.append("\n"); + + out.append(" entity_category: "); + out.append(proto_enum_to_string(this->entity_category)); + out.append("\n"); + + out.append(" supported_features: "); + sprintf(buffer, "%" PRIu32, this->supported_features); + out.append(buffer); + out.append("\n"); + + out.append(" requires_code: "); + out.append(YESNO(this->requires_code)); + out.append("\n"); + + out.append(" requires_code_to_arm: "); + out.append(YESNO(this->requires_code_to_arm)); + out.append("\n"); + + out.append(" device_id: "); + sprintf(buffer, "%" PRIu32, this->device_id); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void AlarmControlPanelStateResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("AlarmControlPanelStateResponse {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" state: "); + out.append(proto_enum_to_string(this->state)); + out.append("\n"); + out.append("}"); +} +void AlarmControlPanelCommandRequest::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("AlarmControlPanelCommandRequest {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" command: "); + out.append(proto_enum_to_string(this->command)); + out.append("\n"); + + out.append(" code: "); + out.append("'").append(this->code).append("'"); + out.append("\n"); + out.append("}"); +} +#endif +#ifdef USE_TEXT +void ListEntitiesTextResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("ListEntitiesTextResponse {\n"); + out.append(" object_id: "); + out.append("'").append(this->object_id).append("'"); + out.append("\n"); + + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" name: "); + out.append("'").append(this->name).append("'"); + out.append("\n"); + + out.append(" unique_id: "); + out.append("'").append(this->unique_id).append("'"); + out.append("\n"); + + out.append(" icon: "); + out.append("'").append(this->icon).append("'"); + out.append("\n"); + + out.append(" disabled_by_default: "); + out.append(YESNO(this->disabled_by_default)); + out.append("\n"); + + out.append(" entity_category: "); + out.append(proto_enum_to_string(this->entity_category)); + out.append("\n"); + + out.append(" min_length: "); + sprintf(buffer, "%" PRIu32, this->min_length); + out.append(buffer); + out.append("\n"); + + out.append(" max_length: "); + sprintf(buffer, "%" PRIu32, this->max_length); + out.append(buffer); + out.append("\n"); + + out.append(" pattern: "); + out.append("'").append(this->pattern).append("'"); + out.append("\n"); + + out.append(" mode: "); + out.append(proto_enum_to_string(this->mode)); + out.append("\n"); + + out.append(" device_id: "); + sprintf(buffer, "%" PRIu32, this->device_id); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void TextStateResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("TextStateResponse {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" state: "); + out.append("'").append(this->state).append("'"); + out.append("\n"); + + out.append(" missing_state: "); + out.append(YESNO(this->missing_state)); + out.append("\n"); + out.append("}"); +} +void TextCommandRequest::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("TextCommandRequest {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" state: "); + out.append("'").append(this->state).append("'"); + out.append("\n"); + out.append("}"); +} +#endif +#ifdef USE_DATETIME_DATE +void ListEntitiesDateResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("ListEntitiesDateResponse {\n"); + out.append(" object_id: "); + out.append("'").append(this->object_id).append("'"); + out.append("\n"); + + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" name: "); + out.append("'").append(this->name).append("'"); + out.append("\n"); + + out.append(" unique_id: "); + out.append("'").append(this->unique_id).append("'"); + out.append("\n"); + + out.append(" icon: "); + out.append("'").append(this->icon).append("'"); + out.append("\n"); + + out.append(" disabled_by_default: "); + out.append(YESNO(this->disabled_by_default)); + out.append("\n"); + + out.append(" entity_category: "); + out.append(proto_enum_to_string(this->entity_category)); + out.append("\n"); + + out.append(" device_id: "); + sprintf(buffer, "%" PRIu32, this->device_id); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void DateStateResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("DateStateResponse {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" missing_state: "); + out.append(YESNO(this->missing_state)); + out.append("\n"); + + out.append(" year: "); + sprintf(buffer, "%" PRIu32, this->year); + out.append(buffer); + out.append("\n"); + + out.append(" month: "); + sprintf(buffer, "%" PRIu32, this->month); + out.append(buffer); + out.append("\n"); + + out.append(" day: "); + sprintf(buffer, "%" PRIu32, this->day); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void DateCommandRequest::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("DateCommandRequest {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" year: "); + sprintf(buffer, "%" PRIu32, this->year); + out.append(buffer); + out.append("\n"); + + out.append(" month: "); + sprintf(buffer, "%" PRIu32, this->month); + out.append(buffer); + out.append("\n"); + + out.append(" day: "); + sprintf(buffer, "%" PRIu32, this->day); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +#endif +#ifdef USE_DATETIME_TIME +void ListEntitiesTimeResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("ListEntitiesTimeResponse {\n"); + out.append(" object_id: "); + out.append("'").append(this->object_id).append("'"); + out.append("\n"); + + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" name: "); + out.append("'").append(this->name).append("'"); + out.append("\n"); + + out.append(" unique_id: "); + out.append("'").append(this->unique_id).append("'"); + out.append("\n"); + + out.append(" icon: "); + out.append("'").append(this->icon).append("'"); + out.append("\n"); + + out.append(" disabled_by_default: "); + out.append(YESNO(this->disabled_by_default)); + out.append("\n"); + + out.append(" entity_category: "); + out.append(proto_enum_to_string(this->entity_category)); + out.append("\n"); + + out.append(" device_id: "); + sprintf(buffer, "%" PRIu32, this->device_id); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void TimeStateResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("TimeStateResponse {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" missing_state: "); + out.append(YESNO(this->missing_state)); + out.append("\n"); + + out.append(" hour: "); + sprintf(buffer, "%" PRIu32, this->hour); + out.append(buffer); + out.append("\n"); + + out.append(" minute: "); + sprintf(buffer, "%" PRIu32, this->minute); + out.append(buffer); + out.append("\n"); + + out.append(" second: "); + sprintf(buffer, "%" PRIu32, this->second); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void TimeCommandRequest::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("TimeCommandRequest {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" hour: "); + sprintf(buffer, "%" PRIu32, this->hour); + out.append(buffer); + out.append("\n"); + + out.append(" minute: "); + sprintf(buffer, "%" PRIu32, this->minute); + out.append(buffer); + out.append("\n"); + + out.append(" second: "); + sprintf(buffer, "%" PRIu32, this->second); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +#endif +#ifdef USE_EVENT +void ListEntitiesEventResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("ListEntitiesEventResponse {\n"); + out.append(" object_id: "); + out.append("'").append(this->object_id).append("'"); + out.append("\n"); + + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" name: "); + out.append("'").append(this->name).append("'"); + out.append("\n"); + + out.append(" unique_id: "); + out.append("'").append(this->unique_id).append("'"); + out.append("\n"); + + out.append(" icon: "); + out.append("'").append(this->icon).append("'"); + out.append("\n"); + + out.append(" disabled_by_default: "); + out.append(YESNO(this->disabled_by_default)); + out.append("\n"); + + out.append(" entity_category: "); + out.append(proto_enum_to_string(this->entity_category)); + out.append("\n"); + + out.append(" device_class: "); + out.append("'").append(this->device_class).append("'"); + out.append("\n"); + + for (const auto &it : this->event_types) { + out.append(" event_types: "); + out.append("'").append(it).append("'"); + out.append("\n"); + } + + out.append(" device_id: "); + sprintf(buffer, "%" PRIu32, this->device_id); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void EventResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("EventResponse {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" event_type: "); + out.append("'").append(this->event_type).append("'"); + out.append("\n"); + out.append("}"); +} +#endif +#ifdef USE_VALVE +void ListEntitiesValveResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("ListEntitiesValveResponse {\n"); + out.append(" object_id: "); + out.append("'").append(this->object_id).append("'"); + out.append("\n"); + + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" name: "); + out.append("'").append(this->name).append("'"); + out.append("\n"); + + out.append(" unique_id: "); + out.append("'").append(this->unique_id).append("'"); + out.append("\n"); + + out.append(" icon: "); + out.append("'").append(this->icon).append("'"); + out.append("\n"); + + out.append(" disabled_by_default: "); + out.append(YESNO(this->disabled_by_default)); + out.append("\n"); + + out.append(" entity_category: "); + out.append(proto_enum_to_string(this->entity_category)); + out.append("\n"); + + out.append(" device_class: "); + out.append("'").append(this->device_class).append("'"); + out.append("\n"); + + out.append(" assumed_state: "); + out.append(YESNO(this->assumed_state)); + out.append("\n"); + + out.append(" supports_position: "); + out.append(YESNO(this->supports_position)); + out.append("\n"); + + out.append(" supports_stop: "); + out.append(YESNO(this->supports_stop)); + out.append("\n"); + + out.append(" device_id: "); + sprintf(buffer, "%" PRIu32, this->device_id); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void ValveStateResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("ValveStateResponse {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" position: "); + sprintf(buffer, "%g", this->position); + out.append(buffer); + out.append("\n"); + + out.append(" current_operation: "); + out.append(proto_enum_to_string(this->current_operation)); + out.append("\n"); + out.append("}"); +} +void ValveCommandRequest::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("ValveCommandRequest {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" has_position: "); + out.append(YESNO(this->has_position)); + out.append("\n"); + + out.append(" position: "); + sprintf(buffer, "%g", this->position); + out.append(buffer); + out.append("\n"); + + out.append(" stop: "); + out.append(YESNO(this->stop)); + out.append("\n"); + out.append("}"); +} +#endif +#ifdef USE_DATETIME_DATETIME +void ListEntitiesDateTimeResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("ListEntitiesDateTimeResponse {\n"); + out.append(" object_id: "); + out.append("'").append(this->object_id).append("'"); + out.append("\n"); + + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" name: "); + out.append("'").append(this->name).append("'"); + out.append("\n"); + + out.append(" unique_id: "); + out.append("'").append(this->unique_id).append("'"); + out.append("\n"); + + out.append(" icon: "); + out.append("'").append(this->icon).append("'"); + out.append("\n"); + + out.append(" disabled_by_default: "); + out.append(YESNO(this->disabled_by_default)); + out.append("\n"); + + out.append(" entity_category: "); + out.append(proto_enum_to_string(this->entity_category)); + out.append("\n"); + + out.append(" device_id: "); + sprintf(buffer, "%" PRIu32, this->device_id); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void DateTimeStateResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("DateTimeStateResponse {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" missing_state: "); + out.append(YESNO(this->missing_state)); + out.append("\n"); + + out.append(" epoch_seconds: "); + sprintf(buffer, "%" PRIu32, this->epoch_seconds); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void DateTimeCommandRequest::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("DateTimeCommandRequest {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" epoch_seconds: "); + sprintf(buffer, "%" PRIu32, this->epoch_seconds); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +#endif +#ifdef USE_UPDATE +void ListEntitiesUpdateResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("ListEntitiesUpdateResponse {\n"); + out.append(" object_id: "); + out.append("'").append(this->object_id).append("'"); + out.append("\n"); + + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" name: "); + out.append("'").append(this->name).append("'"); + out.append("\n"); + + out.append(" unique_id: "); + out.append("'").append(this->unique_id).append("'"); + out.append("\n"); + + out.append(" icon: "); + out.append("'").append(this->icon).append("'"); + out.append("\n"); + + out.append(" disabled_by_default: "); + out.append(YESNO(this->disabled_by_default)); + out.append("\n"); + + out.append(" entity_category: "); + out.append(proto_enum_to_string(this->entity_category)); + out.append("\n"); + + out.append(" device_class: "); + out.append("'").append(this->device_class).append("'"); + out.append("\n"); + + out.append(" device_id: "); + sprintf(buffer, "%" PRIu32, this->device_id); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +void UpdateStateResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("UpdateStateResponse {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" missing_state: "); + out.append(YESNO(this->missing_state)); + out.append("\n"); + + out.append(" in_progress: "); + out.append(YESNO(this->in_progress)); + out.append("\n"); + + out.append(" has_progress: "); + out.append(YESNO(this->has_progress)); + out.append("\n"); + + out.append(" progress: "); + sprintf(buffer, "%g", this->progress); + out.append(buffer); + out.append("\n"); + + out.append(" current_version: "); + out.append("'").append(this->current_version).append("'"); + out.append("\n"); + + out.append(" latest_version: "); + out.append("'").append(this->latest_version).append("'"); + out.append("\n"); + + out.append(" title: "); + out.append("'").append(this->title).append("'"); + out.append("\n"); + + out.append(" release_summary: "); + out.append("'").append(this->release_summary).append("'"); + out.append("\n"); + + out.append(" release_url: "); + out.append("'").append(this->release_url).append("'"); + out.append("\n"); + out.append("}"); +} +void UpdateCommandRequest::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("UpdateCommandRequest {\n"); + out.append(" key: "); + sprintf(buffer, "%" PRIu32, this->key); + out.append(buffer); + out.append("\n"); + + out.append(" command: "); + out.append(proto_enum_to_string(this->command)); + out.append("\n"); + out.append("}"); +} +#endif + +} // namespace api +} // namespace esphome + +#endif // HAS_PROTO_MESSAGE_DUMP diff --git a/esphome/components/api/api_pb2_service.h b/esphome/components/api/api_pb2_service.h index c46cf2de59..458f8ec81b 100644 --- a/esphome/components/api/api_pb2_service.h +++ b/esphome/components/api/api_pb2_service.h @@ -2,9 +2,10 @@ // See script/api_protobuf/api_protobuf.py #pragma once -#include "api_pb2.h" #include "esphome/core/defines.h" +#include "api_pb2.h" + namespace esphome { namespace api { diff --git a/esphome/components/api/api_server.cpp b/esphome/components/api/api_server.cpp index 49a25c94af..6d8546e805 100644 --- a/esphome/components/api/api_server.cpp +++ b/esphome/components/api/api_server.cpp @@ -217,6 +217,7 @@ void APIServer::dump_config() { #endif } +#ifdef USE_API_PASSWORD bool APIServer::uses_password() const { return !this->password_.empty(); } bool APIServer::check_password(const std::string &password) const { @@ -247,6 +248,7 @@ bool APIServer::check_password(const std::string &password) const { return result == 0; } +#endif void APIServer::handle_disconnect(APIConnection *conn) {} @@ -430,7 +432,9 @@ float APIServer::get_setup_priority() const { return setup_priority::AFTER_WIFI; void APIServer::set_port(uint16_t port) { this->port_ = port; } +#ifdef USE_API_PASSWORD void APIServer::set_password(const std::string &password) { this->password_ = password; } +#endif void APIServer::set_batch_delay(uint16_t batch_delay) { this->batch_delay_ = batch_delay; } diff --git a/esphome/components/api/api_server.h b/esphome/components/api/api_server.h index 5a9b0677bc..9dc2b4b7d6 100644 --- a/esphome/components/api/api_server.h +++ b/esphome/components/api/api_server.h @@ -35,10 +35,12 @@ class APIServer : public Component, public Controller { void dump_config() override; void on_shutdown() override; bool teardown() override; +#ifdef USE_API_PASSWORD bool check_password(const std::string &password) const; bool uses_password() const; - void set_port(uint16_t port); void set_password(const std::string &password); +#endif + void set_port(uint16_t port); void set_reboot_timeout(uint32_t reboot_timeout); void set_batch_delay(uint16_t batch_delay); uint16_t get_batch_delay() const { return batch_delay_; } @@ -179,7 +181,9 @@ class APIServer : public Component, public Controller { // Vectors and strings (12 bytes each on 32-bit) std::vector> clients_; +#ifdef USE_API_PASSWORD std::string password_; +#endif std::vector shared_write_buffer_; // Shared proto write buffer for all connections std::vector state_subs_; #ifdef USE_API_YAML_SERVICES diff --git a/esphome/components/captive_portal/__init__.py b/esphome/components/captive_portal/__init__.py index cba3b4921a..7e8afd8fab 100644 --- a/esphome/components/captive_portal/__init__.py +++ b/esphome/components/captive_portal/__init__.py @@ -12,7 +12,7 @@ from esphome.const import ( ) from esphome.core import CORE, coroutine_with_priority -AUTO_LOAD = ["web_server_base"] +AUTO_LOAD = ["web_server_base", "ota.web_server"] DEPENDENCIES = ["wifi"] CODEOWNERS = ["@OttoWinter"] diff --git a/esphome/components/captive_portal/captive_portal.cpp b/esphome/components/captive_portal/captive_portal.cpp index 51e5cfc8ff..25179fdacc 100644 --- a/esphome/components/captive_portal/captive_portal.cpp +++ b/esphome/components/captive_portal/captive_portal.cpp @@ -47,7 +47,6 @@ void CaptivePortal::start() { this->base_->init(); if (!this->initialized_) { this->base_->add_handler(this); - this->base_->add_ota_handler(); } #ifdef USE_ARDUINO diff --git a/esphome/components/ds2484/__init__.py b/esphome/components/ds2484/__init__.py new file mode 100644 index 0000000000..3d9f24ff19 --- /dev/null +++ b/esphome/components/ds2484/__init__.py @@ -0,0 +1 @@ +CODEOWNERS = ["@mrk-its"] diff --git a/esphome/components/ds2484/ds2484.cpp b/esphome/components/ds2484/ds2484.cpp new file mode 100644 index 0000000000..c3df9786b6 --- /dev/null +++ b/esphome/components/ds2484/ds2484.cpp @@ -0,0 +1,209 @@ +#include "ds2484.h" + +namespace esphome { +namespace ds2484 { +static const char *const TAG = "ds2484.onewire"; + +void DS2484OneWireBus::setup() { + ESP_LOGCONFIG(TAG, "Running setup"); + this->reset_device(); + this->search(); +} + +void DS2484OneWireBus::dump_config() { + ESP_LOGCONFIG(TAG, "1-wire bus:"); + this->dump_devices_(TAG); +} + +bool DS2484OneWireBus::read_status_(uint8_t *status) { + for (uint8_t retry_nr = 0; retry_nr < 10; retry_nr++) { + if (this->read(status, 1) != i2c::ERROR_OK) { + ESP_LOGE(TAG, "read status error"); + return false; + } + ESP_LOGVV(TAG, "status: %02x", *status); + if (!(*status & 1)) { + return true; + } + } + ESP_LOGE(TAG, "read status error: too many retries"); + return false; +} + +bool DS2484OneWireBus::wait_for_completion_() { + uint8_t status; + return this->read_status_(&status); +} + +bool DS2484OneWireBus::reset_device() { + ESP_LOGVV(TAG, "reset_device"); + uint8_t device_reset_cmd = 0xf0; + uint8_t response; + if (this->write(&device_reset_cmd, 1) != i2c::ERROR_OK) { + return false; + } + if (!this->wait_for_completion_()) { + ESP_LOGE(TAG, "reset_device: can't complete"); + return false; + } + uint8_t config = (this->active_pullup_ ? 1 : 0) | (this->strong_pullup_ ? 4 : 0); + uint8_t write_config[2] = {0xd2, (uint8_t) (config | (~config << 4))}; + if (this->write(write_config, 2) != i2c::ERROR_OK) { + ESP_LOGE(TAG, "reset_device: can't write config"); + return false; + } + if (this->read(&response, 1) != i2c::ERROR_OK) { + ESP_LOGE(TAG, "can't read read8 response"); + return false; + } + if (response != (write_config[1] & 0xf)) { + ESP_LOGE(TAG, "configuration didn't update"); + return false; + } + return true; +}; + +int DS2484OneWireBus::reset_int() { + ESP_LOGVV(TAG, "reset"); + uint8_t reset_cmd = 0xb4; + if (this->write(&reset_cmd, 1) != i2c::ERROR_OK) { + return -1; + } + return this->wait_for_completion_() ? 1 : 0; +}; + +void DS2484OneWireBus::write8_(uint8_t value) { + uint8_t buffer[2] = {0xa5, value}; + this->write(buffer, 2); + this->wait_for_completion_(); +}; + +void DS2484OneWireBus::write8(uint8_t value) { + ESP_LOGVV(TAG, "write8: %02x", value); + this->write8_(value); +}; + +void DS2484OneWireBus::write64(uint64_t value) { + ESP_LOGVV(TAG, "write64: %llx", value); + for (uint8_t i = 0; i < 8; i++) { + this->write8_((value >> (i * 8)) & 0xff); + } +} + +uint8_t DS2484OneWireBus::read8() { + uint8_t read8_cmd = 0x96; + uint8_t set_read_reg_cmd[2] = {0xe1, 0xe1}; + uint8_t response = 0; + if (this->write(&read8_cmd, 1) != i2c::ERROR_OK) { + ESP_LOGE(TAG, "can't write read8 cmd"); + return 0; + } + this->wait_for_completion_(); + if (this->write(set_read_reg_cmd, 2) != i2c::ERROR_OK) { + ESP_LOGE(TAG, "can't set read data reg"); + return 0; + } + if (this->read(&response, 1) != i2c::ERROR_OK) { + ESP_LOGE(TAG, "can't read read8 response"); + return 0; + } + return response; +} + +uint64_t DS2484OneWireBus::read64() { + uint8_t response = 0; + for (uint8_t i = 0; i < 8; i++) { + response |= (this->read8() << (i * 8)); + } + return response; +} + +void DS2484OneWireBus::reset_search() { + this->last_discrepancy_ = 0; + this->last_device_flag_ = false; + this->address_ = 0; +} + +bool DS2484OneWireBus::one_wire_triple_(bool *branch, bool *id_bit, bool *cmp_id_bit) { + uint8_t buffer[2] = {(uint8_t) 0x78, (uint8_t) (*branch ? 0x80u : 0)}; + uint8_t status; + if (!this->read_status_(&status)) { + ESP_LOGE(TAG, "one_wire_triple start: read status error"); + return false; + } + if (this->write(buffer, 2) != i2c::ERROR_OK) { + ESP_LOGV(TAG, "one_wire_triple: can't write cmd"); + return false; + } + if (!this->read_status_(&status)) { + ESP_LOGE(TAG, "one_wire_triple: read status error"); + return false; + } + *id_bit = bool(status & 0x20); + *cmp_id_bit = bool(status & 0x40); + *branch = bool(status & 0x80); + return true; +} + +uint64_t IRAM_ATTR DS2484OneWireBus::search_int() { + ESP_LOGVV(TAG, "search_int"); + if (this->last_device_flag_) { + ESP_LOGVV(TAG, "last device flag set, quitting"); + return 0u; + } + + uint8_t last_zero = 0; + uint64_t bit_mask = 1; + uint64_t address = this->address_; + + // Initiate search + for (uint8_t bit_number = 1; bit_number <= 64; bit_number++, bit_mask <<= 1) { + bool branch; + + // compute branch value for the case when there is a discrepancy + // (there are devices with both 0s and 1s at this bit) + if (bit_number < this->last_discrepancy_) { + branch = (address & bit_mask) > 0; + } else { + branch = bit_number == this->last_discrepancy_; + } + + bool id_bit, cmp_id_bit; + bool branch_before = branch; + if (!this->one_wire_triple_(&branch, &id_bit, &cmp_id_bit)) { + ESP_LOGW(TAG, "one wire triple error, quitting"); + return 0; + } + + if (id_bit && cmp_id_bit) { + ESP_LOGW(TAG, "no devices on the bus, quitting"); + // No devices participating in search + return 0; + } + + if (!id_bit && !cmp_id_bit && !branch) { + last_zero = bit_number; + } + + ESP_LOGVV(TAG, "%d %d branch: %d %d", id_bit, cmp_id_bit, branch_before, branch); + + if (branch) { + address |= bit_mask; + } else { + address &= ~bit_mask; + } + } + ESP_LOGVV(TAG, "last_discepancy: %d", last_zero); + ESP_LOGVV(TAG, "address: %llx", address); + this->last_discrepancy_ = last_zero; + if (this->last_discrepancy_ == 0) { + // we're at root and have no choices left, so this was the last one. + this->last_device_flag_ = true; + } + + this->address_ = address; + return address; +} + +} // namespace ds2484 +} // namespace esphome diff --git a/esphome/components/ds2484/ds2484.h b/esphome/components/ds2484/ds2484.h new file mode 100644 index 0000000000..223227c0a2 --- /dev/null +++ b/esphome/components/ds2484/ds2484.h @@ -0,0 +1,43 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/core/hal.h" +#include "esphome/core/preferences.h" +#include "esphome/components/i2c/i2c.h" +#include "esphome/components/one_wire/one_wire.h" + +namespace esphome { +namespace ds2484 { + +class DS2484OneWireBus : public one_wire::OneWireBus, public i2c::I2CDevice, public Component { + public: + void setup() override; + void dump_config() override; + float get_setup_priority() const override { return setup_priority::BUS - 1.0; } + + bool reset_device(); + int reset_int() override; + void write8(uint8_t) override; + void write64(uint64_t) override; + uint8_t read8() override; + uint64_t read64() override; + + void set_active_pullup(bool value) { this->active_pullup_ = value; } + void set_strong_pullup(bool value) { this->strong_pullup_ = value; } + + protected: + void reset_search() override; + uint64_t search_int() override; + bool read_status_(uint8_t *); + bool wait_for_completion_(); + void write8_(uint8_t); + bool one_wire_triple_(bool *branch, bool *id_bit, bool *cmp_id_bit); + + uint64_t address_; + uint8_t last_discrepancy_{0}; + bool last_device_flag_{false}; + bool active_pullup_{false}; + bool strong_pullup_{false}; +}; +} // namespace ds2484 +} // namespace esphome diff --git a/esphome/components/ds2484/one_wire.py b/esphome/components/ds2484/one_wire.py new file mode 100644 index 0000000000..384b2d01e6 --- /dev/null +++ b/esphome/components/ds2484/one_wire.py @@ -0,0 +1,37 @@ +import esphome.codegen as cg +from esphome.components import i2c +from esphome.components.one_wire import OneWireBus +import esphome.config_validation as cv +from esphome.const import CONF_ID + +ds2484_ns = cg.esphome_ns.namespace("ds2484") + +CONF_ACTIVE_PULLUP = "active_pullup" +CONF_STRONG_PULLUP = "strong_pullup" + +CODEOWNERS = ["@mrk-its"] +DEPENDENCIES = ["i2c"] + +DS2484OneWireBus = ds2484_ns.class_( + "DS2484OneWireBus", OneWireBus, i2c.I2CDevice, cg.Component +) + +CONFIG_SCHEMA = ( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(DS2484OneWireBus), + cv.Optional(CONF_ACTIVE_PULLUP, default=False): cv.boolean, + cv.Optional(CONF_STRONG_PULLUP, default=False): cv.boolean, + } + ) + .extend(cv.COMPONENT_SCHEMA) + .extend(i2c.i2c_device_schema(0x18)) +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await i2c.register_i2c_device(var, config) + await cg.register_component(var, config) + cg.add(var.set_active_pullup(config[CONF_ACTIVE_PULLUP])) + cg.add(var.set_strong_pullup(config[CONF_STRONG_PULLUP])) diff --git a/esphome/components/esp32/__init__.py b/esphome/components/esp32/__init__.py index 32323b7504..b4c7a4e05b 100644 --- a/esphome/components/esp32/__init__.py +++ b/esphome/components/esp32/__init__.py @@ -411,8 +411,8 @@ def _esp_idf_check_versions(value): version = cv.Version.parse(cv.version_number(value[CONF_VERSION])) source = value.get(CONF_SOURCE, None) - if version < cv.Version(4, 0, 0): - raise cv.Invalid("Only ESP-IDF 4.0+ is supported.") + if version < cv.Version(5, 0, 0): + raise cv.Invalid("Only ESP-IDF 5.0+ is supported.") # flag this for later *before* we set value[CONF_PLATFORM_VERSION] below has_platform_ver = CONF_PLATFORM_VERSION in value @@ -422,20 +422,15 @@ def _esp_idf_check_versions(value): ) if ( - (is_platformio := _platform_is_platformio(value[CONF_PLATFORM_VERSION])) - and version.major >= 5 - and version not in SUPPORTED_PLATFORMIO_ESP_IDF_5X - ): + is_platformio := _platform_is_platformio(value[CONF_PLATFORM_VERSION]) + ) and version not in SUPPORTED_PLATFORMIO_ESP_IDF_5X: raise cv.Invalid( f"ESP-IDF {str(version)} not supported by platformio/espressif32" ) if ( - version.major < 5 - or ( - version in SUPPORTED_PLATFORMIO_ESP_IDF_5X - and version not in SUPPORTED_PIOARDUINO_ESP_IDF_5X - ) + version in SUPPORTED_PLATFORMIO_ESP_IDF_5X + and version not in SUPPORTED_PIOARDUINO_ESP_IDF_5X ) and not has_platform_ver: raise cv.Invalid( f"ESP-IDF {value[CONF_VERSION]} may be supported by platformio/espressif32; please specify '{CONF_PLATFORM_VERSION}'" @@ -801,14 +796,9 @@ async def to_code(config): if advanced.get(CONF_IGNORE_EFUSE_MAC_CRC): add_idf_sdkconfig_option("CONFIG_ESP_MAC_IGNORE_MAC_CRC_ERROR", True) - if (framework_ver.major, framework_ver.minor) >= (4, 4): - add_idf_sdkconfig_option( - "CONFIG_ESP_PHY_CALIBRATION_AND_DATA_STORAGE", False - ) - else: - add_idf_sdkconfig_option( - "CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE", False - ) + add_idf_sdkconfig_option( + "CONFIG_ESP_PHY_CALIBRATION_AND_DATA_STORAGE", False + ) if advanced.get(CONF_ENABLE_IDF_EXPERIMENTAL_FEATURES): _LOGGER.warning( "Using experimental features in ESP-IDF may result in unexpected failures." diff --git a/esphome/components/esp32/core.cpp b/esphome/components/esp32/core.cpp index 562bcba3c2..f3bdfea2a0 100644 --- a/esphome/components/esp32/core.cpp +++ b/esphome/components/esp32/core.cpp @@ -56,11 +56,7 @@ void arch_init() { void IRAM_ATTR HOT arch_feed_wdt() { esp_task_wdt_reset(); } uint8_t progmem_read_byte(const uint8_t *addr) { return *addr; } -#if ESP_IDF_VERSION_MAJOR >= 5 uint32_t arch_get_cpu_cycle_count() { return esp_cpu_get_cycle_count(); } -#else -uint32_t arch_get_cpu_cycle_count() { return cpu_hal_get_cycle_count(); } -#endif uint32_t arch_get_cpu_freq_hz() { uint32_t freq = 0; #ifdef USE_ESP_IDF diff --git a/esphome/components/esp32_ble_tracker/__init__.py b/esphome/components/esp32_ble_tracker/__init__.py index 2242d709a4..547cf84ed1 100644 --- a/esphome/components/esp32_ble_tracker/__init__.py +++ b/esphome/components/esp32_ble_tracker/__init__.py @@ -29,8 +29,6 @@ from esphome.const import ( CONF_ON_BLE_SERVICE_DATA_ADVERTISE, CONF_SERVICE_UUID, CONF_TRIGGER_ID, - KEY_CORE, - KEY_FRAMEWORK_VERSION, ) from esphome.core import CORE @@ -323,10 +321,7 @@ async def to_code(config): # https://github.com/espressif/esp-idf/issues/2503 # Match arduino CONFIG_BTU_TASK_STACK_SIZE # https://github.com/espressif/arduino-esp32/blob/fd72cf46ad6fc1a6de99c1d83ba8eba17d80a4ee/tools/sdk/esp32/sdkconfig#L1866 - if CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION] >= cv.Version(4, 4, 6): - add_idf_sdkconfig_option("CONFIG_BT_BTU_TASK_STACK_SIZE", 8192) - else: - add_idf_sdkconfig_option("CONFIG_BTU_TASK_STACK_SIZE", 8192) + add_idf_sdkconfig_option("CONFIG_BT_BTU_TASK_STACK_SIZE", 8192) add_idf_sdkconfig_option("CONFIG_BT_ACL_CONNECTIONS", 9) add_idf_sdkconfig_option( "CONFIG_BTDM_CTRL_BLE_MAX_CONN", config[CONF_MAX_CONNECTIONS] @@ -335,8 +330,7 @@ async def to_code(config): # max notifications in 5.x, setting CONFIG_BT_ACL_CONNECTIONS # is enough in 4.x # https://github.com/esphome/issues/issues/6808 - if CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION] >= cv.Version(5, 0, 0): - add_idf_sdkconfig_option("CONFIG_BT_GATTC_NOTIF_REG_MAX", 9) + add_idf_sdkconfig_option("CONFIG_BT_GATTC_NOTIF_REG_MAX", 9) cg.add_define("USE_OTA_STATE_CALLBACK") # To be notified when an OTA update starts cg.add_define("USE_ESP32_BLE_CLIENT") diff --git a/esphome/components/esp32_rmt_led_strip/led_strip.cpp b/esphome/components/esp32_rmt_led_strip/led_strip.cpp index dfdf50aa66..389c32882b 100644 --- a/esphome/components/esp32_rmt_led_strip/led_strip.cpp +++ b/esphome/components/esp32_rmt_led_strip/led_strip.cpp @@ -21,6 +21,43 @@ static const uint32_t RMT_CLK_FREQ = 80000000; static const uint8_t RMT_CLK_DIV = 2; #endif +static const size_t RMT_SYMBOLS_PER_BYTE = 8; + +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0) +static size_t IRAM_ATTR HOT encoder_callback(const void *data, size_t size, size_t symbols_written, size_t symbols_free, + rmt_symbol_word_t *symbols, bool *done, void *arg) { + auto *params = static_cast(arg); + const auto *bytes = static_cast(data); + size_t index = symbols_written / RMT_SYMBOLS_PER_BYTE; + + // convert byte to symbols + if (index < size) { + if (symbols_free < RMT_SYMBOLS_PER_BYTE) { + return 0; + } + for (int32_t i = 0; i < RMT_SYMBOLS_PER_BYTE; i++) { + if (bytes[index] & (1 << (7 - i))) { + symbols[i] = params->bit1; + } else { + symbols[i] = params->bit0; + } + } + if ((index + 1) >= size && params->reset.duration0 == 0 && params->reset.duration1 == 0) { + *done = true; + } + return RMT_SYMBOLS_PER_BYTE; + } + + // send reset + if (symbols_free < 1) { + return 0; + } + symbols[0] = params->reset; + *done = true; + return 1; +} +#endif + void ESP32RMTLEDStripLightOutput::setup() { ESP_LOGCONFIG(TAG, "Running setup"); @@ -42,10 +79,15 @@ void ESP32RMTLEDStripLightOutput::setup() { return; } +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0) + // copy of the led buffer + this->rmt_buf_ = allocator.allocate(buffer_size); +#else RAMAllocator rmt_allocator(this->use_psram_ ? 0 : RAMAllocator::ALLOC_INTERNAL); // 8 bits per byte, 1 rmt_symbol_word_t per bit + 1 rmt_symbol_word_t for reset this->rmt_buf_ = rmt_allocator.allocate(buffer_size * 8 + 1); +#endif rmt_tx_channel_config_t channel; memset(&channel, 0, sizeof(channel)); @@ -65,6 +107,18 @@ void ESP32RMTLEDStripLightOutput::setup() { return; } +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0) + rmt_simple_encoder_config_t encoder; + memset(&encoder, 0, sizeof(encoder)); + encoder.callback = encoder_callback; + encoder.arg = &this->params_; + encoder.min_chunk_size = 8; + if (rmt_new_simple_encoder(&encoder, &this->encoder_) != ESP_OK) { + ESP_LOGE(TAG, "Encoder creation failed"); + this->mark_failed(); + return; + } +#else rmt_copy_encoder_config_t encoder; memset(&encoder, 0, sizeof(encoder)); if (rmt_new_copy_encoder(&encoder, &this->encoder_) != ESP_OK) { @@ -72,6 +126,7 @@ void ESP32RMTLEDStripLightOutput::setup() { this->mark_failed(); return; } +#endif if (rmt_enable(this->channel_) != ESP_OK) { ESP_LOGE(TAG, "Enabling channel failed"); @@ -85,20 +140,20 @@ void ESP32RMTLEDStripLightOutput::set_led_params(uint32_t bit0_high, uint32_t bi float ratio = (float) RMT_CLK_FREQ / RMT_CLK_DIV / 1e09f; // 0-bit - this->bit0_.duration0 = (uint32_t) (ratio * bit0_high); - this->bit0_.level0 = 1; - this->bit0_.duration1 = (uint32_t) (ratio * bit0_low); - this->bit0_.level1 = 0; + this->params_.bit0.duration0 = (uint32_t) (ratio * bit0_high); + this->params_.bit0.level0 = 1; + this->params_.bit0.duration1 = (uint32_t) (ratio * bit0_low); + this->params_.bit0.level1 = 0; // 1-bit - this->bit1_.duration0 = (uint32_t) (ratio * bit1_high); - this->bit1_.level0 = 1; - this->bit1_.duration1 = (uint32_t) (ratio * bit1_low); - this->bit1_.level1 = 0; + this->params_.bit1.duration0 = (uint32_t) (ratio * bit1_high); + this->params_.bit1.level0 = 1; + this->params_.bit1.duration1 = (uint32_t) (ratio * bit1_low); + this->params_.bit1.level1 = 0; // reset - this->reset_.duration0 = (uint32_t) (ratio * reset_time_high); - this->reset_.level0 = 1; - this->reset_.duration1 = (uint32_t) (ratio * reset_time_low); - this->reset_.level1 = 0; + this->params_.reset.duration0 = (uint32_t) (ratio * reset_time_high); + this->params_.reset.level0 = 1; + this->params_.reset.duration1 = (uint32_t) (ratio * reset_time_low); + this->params_.reset.level1 = 0; } void ESP32RMTLEDStripLightOutput::write_state(light::LightState *state) { @@ -122,6 +177,9 @@ void ESP32RMTLEDStripLightOutput::write_state(light::LightState *state) { } delayMicroseconds(50); +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0) + memcpy(this->rmt_buf_, this->buf_, this->get_buffer_size_()); +#else size_t buffer_size = this->get_buffer_size_(); size_t size = 0; @@ -131,7 +189,7 @@ void ESP32RMTLEDStripLightOutput::write_state(light::LightState *state) { while (size < buffer_size) { uint8_t b = *psrc; for (int i = 0; i < 8; i++) { - pdest->val = b & (1 << (7 - i)) ? this->bit1_.val : this->bit0_.val; + pdest->val = b & (1 << (7 - i)) ? this->params_.bit1.val : this->params_.bit0.val; pdest++; len++; } @@ -139,17 +197,20 @@ void ESP32RMTLEDStripLightOutput::write_state(light::LightState *state) { psrc++; } - if (this->reset_.duration0 > 0 || this->reset_.duration1 > 0) { - pdest->val = this->reset_.val; + if (this->params_.reset.duration0 > 0 || this->params_.reset.duration1 > 0) { + pdest->val = this->params_.reset.val; pdest++; len++; } +#endif rmt_transmit_config_t config; memset(&config, 0, sizeof(config)); - config.loop_count = 0; - config.flags.eot_level = 0; +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0) + error = rmt_transmit(this->channel_, this->encoder_, this->rmt_buf_, this->get_buffer_size_(), &config); +#else error = rmt_transmit(this->channel_, this->encoder_, this->rmt_buf_, len * sizeof(rmt_symbol_word_t), &config); +#endif if (error != ESP_OK) { ESP_LOGE(TAG, "RMT TX error"); this->status_set_warning(); diff --git a/esphome/components/esp32_rmt_led_strip/led_strip.h b/esphome/components/esp32_rmt_led_strip/led_strip.h index c6a2b4bc9f..72ce659b4f 100644 --- a/esphome/components/esp32_rmt_led_strip/led_strip.h +++ b/esphome/components/esp32_rmt_led_strip/led_strip.h @@ -25,6 +25,12 @@ enum RGBOrder : uint8_t { ORDER_BRG, }; +struct LedParams { + rmt_symbol_word_t bit0; + rmt_symbol_word_t bit1; + rmt_symbol_word_t reset; +}; + class ESP32RMTLEDStripLightOutput : public light::AddressableLight { public: void setup() override; @@ -72,12 +78,15 @@ class ESP32RMTLEDStripLightOutput : public light::AddressableLight { uint8_t *buf_{nullptr}; uint8_t *effect_data_{nullptr}; + LedParams params_; rmt_channel_handle_t channel_{nullptr}; rmt_encoder_handle_t encoder_{nullptr}; +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0) + uint8_t *rmt_buf_{nullptr}; +#else rmt_symbol_word_t *rmt_buf_{nullptr}; - rmt_symbol_word_t bit0_, bit1_, reset_; +#endif uint32_t rmt_symbols_{48}; - uint8_t pin_; uint16_t num_leds_; bool is_rgbw_{false}; diff --git a/esphome/components/esp32_touch/esp32_touch.cpp b/esphome/components/esp32_touch/esp32_touch.cpp deleted file mode 100644 index 366aa10697..0000000000 --- a/esphome/components/esp32_touch/esp32_touch.cpp +++ /dev/null @@ -1,355 +0,0 @@ -#ifdef USE_ESP32 - -#include "esp32_touch.h" -#include "esphome/core/application.h" -#include "esphome/core/log.h" -#include "esphome/core/hal.h" - -#include - -namespace esphome { -namespace esp32_touch { - -static const char *const TAG = "esp32_touch"; - -void ESP32TouchComponent::setup() { - ESP_LOGCONFIG(TAG, "Running setup"); - touch_pad_init(); -// set up and enable/start filtering based on ESP32 variant -#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) - if (this->filter_configured_()) { - touch_filter_config_t filter_info = { - .mode = this->filter_mode_, - .debounce_cnt = this->debounce_count_, - .noise_thr = this->noise_threshold_, - .jitter_step = this->jitter_step_, - .smh_lvl = this->smooth_level_, - }; - touch_pad_filter_set_config(&filter_info); - touch_pad_filter_enable(); - } - - if (this->denoise_configured_()) { - touch_pad_denoise_t denoise = { - .grade = this->grade_, - .cap_level = this->cap_level_, - }; - touch_pad_denoise_set_config(&denoise); - touch_pad_denoise_enable(); - } - - if (this->waterproof_configured_()) { - touch_pad_waterproof_t waterproof = { - .guard_ring_pad = this->waterproof_guard_ring_pad_, - .shield_driver = this->waterproof_shield_driver_, - }; - touch_pad_waterproof_set_config(&waterproof); - touch_pad_waterproof_enable(); - } -#else - if (this->iir_filter_enabled_()) { - touch_pad_filter_start(this->iir_filter_); - } -#endif - -#if ESP_IDF_VERSION_MAJOR >= 5 && defined(USE_ESP32_VARIANT_ESP32) - touch_pad_set_measurement_clock_cycles(this->meas_cycle_); - touch_pad_set_measurement_interval(this->sleep_cycle_); -#else - touch_pad_set_meas_time(this->sleep_cycle_, this->meas_cycle_); -#endif - touch_pad_set_voltage(this->high_voltage_reference_, this->low_voltage_reference_, this->voltage_attenuation_); - - for (auto *child : this->children_) { -#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) - touch_pad_config(child->get_touch_pad()); -#else - // Disable interrupt threshold - touch_pad_config(child->get_touch_pad(), 0); -#endif - } -#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) - touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER); - touch_pad_fsm_start(); -#endif -} - -void ESP32TouchComponent::dump_config() { - ESP_LOGCONFIG(TAG, - "Config for ESP32 Touch Hub:\n" - " Meas cycle: %.2fms\n" - " Sleep cycle: %.2fms", - this->meas_cycle_ / (8000000.0f / 1000.0f), this->sleep_cycle_ / (150000.0f / 1000.0f)); - - const char *lv_s; - switch (this->low_voltage_reference_) { - case TOUCH_LVOLT_0V5: - lv_s = "0.5V"; - break; - case TOUCH_LVOLT_0V6: - lv_s = "0.6V"; - break; - case TOUCH_LVOLT_0V7: - lv_s = "0.7V"; - break; - case TOUCH_LVOLT_0V8: - lv_s = "0.8V"; - break; - default: - lv_s = "UNKNOWN"; - break; - } - ESP_LOGCONFIG(TAG, " Low Voltage Reference: %s", lv_s); - - const char *hv_s; - switch (this->high_voltage_reference_) { - case TOUCH_HVOLT_2V4: - hv_s = "2.4V"; - break; - case TOUCH_HVOLT_2V5: - hv_s = "2.5V"; - break; - case TOUCH_HVOLT_2V6: - hv_s = "2.6V"; - break; - case TOUCH_HVOLT_2V7: - hv_s = "2.7V"; - break; - default: - hv_s = "UNKNOWN"; - break; - } - ESP_LOGCONFIG(TAG, " High Voltage Reference: %s", hv_s); - - const char *atten_s; - switch (this->voltage_attenuation_) { - case TOUCH_HVOLT_ATTEN_1V5: - atten_s = "1.5V"; - break; - case TOUCH_HVOLT_ATTEN_1V: - atten_s = "1V"; - break; - case TOUCH_HVOLT_ATTEN_0V5: - atten_s = "0.5V"; - break; - case TOUCH_HVOLT_ATTEN_0V: - atten_s = "0V"; - break; - default: - atten_s = "UNKNOWN"; - break; - } - ESP_LOGCONFIG(TAG, " Voltage Attenuation: %s", atten_s); - -#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) - if (this->filter_configured_()) { - const char *filter_mode_s; - switch (this->filter_mode_) { - case TOUCH_PAD_FILTER_IIR_4: - filter_mode_s = "IIR_4"; - break; - case TOUCH_PAD_FILTER_IIR_8: - filter_mode_s = "IIR_8"; - break; - case TOUCH_PAD_FILTER_IIR_16: - filter_mode_s = "IIR_16"; - break; - case TOUCH_PAD_FILTER_IIR_32: - filter_mode_s = "IIR_32"; - break; - case TOUCH_PAD_FILTER_IIR_64: - filter_mode_s = "IIR_64"; - break; - case TOUCH_PAD_FILTER_IIR_128: - filter_mode_s = "IIR_128"; - break; - case TOUCH_PAD_FILTER_IIR_256: - filter_mode_s = "IIR_256"; - break; - case TOUCH_PAD_FILTER_JITTER: - filter_mode_s = "JITTER"; - break; - default: - filter_mode_s = "UNKNOWN"; - break; - } - ESP_LOGCONFIG(TAG, - " Filter mode: %s\n" - " Debounce count: %" PRIu32 "\n" - " Noise threshold coefficient: %" PRIu32 "\n" - " Jitter filter step size: %" PRIu32, - filter_mode_s, this->debounce_count_, this->noise_threshold_, this->jitter_step_); - const char *smooth_level_s; - switch (this->smooth_level_) { - case TOUCH_PAD_SMOOTH_OFF: - smooth_level_s = "OFF"; - break; - case TOUCH_PAD_SMOOTH_IIR_2: - smooth_level_s = "IIR_2"; - break; - case TOUCH_PAD_SMOOTH_IIR_4: - smooth_level_s = "IIR_4"; - break; - case TOUCH_PAD_SMOOTH_IIR_8: - smooth_level_s = "IIR_8"; - break; - default: - smooth_level_s = "UNKNOWN"; - break; - } - ESP_LOGCONFIG(TAG, " Smooth level: %s", smooth_level_s); - } - - if (this->denoise_configured_()) { - const char *grade_s; - switch (this->grade_) { - case TOUCH_PAD_DENOISE_BIT12: - grade_s = "BIT12"; - break; - case TOUCH_PAD_DENOISE_BIT10: - grade_s = "BIT10"; - break; - case TOUCH_PAD_DENOISE_BIT8: - grade_s = "BIT8"; - break; - case TOUCH_PAD_DENOISE_BIT4: - grade_s = "BIT4"; - break; - default: - grade_s = "UNKNOWN"; - break; - } - ESP_LOGCONFIG(TAG, " Denoise grade: %s", grade_s); - - const char *cap_level_s; - switch (this->cap_level_) { - case TOUCH_PAD_DENOISE_CAP_L0: - cap_level_s = "L0"; - break; - case TOUCH_PAD_DENOISE_CAP_L1: - cap_level_s = "L1"; - break; - case TOUCH_PAD_DENOISE_CAP_L2: - cap_level_s = "L2"; - break; - case TOUCH_PAD_DENOISE_CAP_L3: - cap_level_s = "L3"; - break; - case TOUCH_PAD_DENOISE_CAP_L4: - cap_level_s = "L4"; - break; - case TOUCH_PAD_DENOISE_CAP_L5: - cap_level_s = "L5"; - break; - case TOUCH_PAD_DENOISE_CAP_L6: - cap_level_s = "L6"; - break; - case TOUCH_PAD_DENOISE_CAP_L7: - cap_level_s = "L7"; - break; - default: - cap_level_s = "UNKNOWN"; - break; - } - ESP_LOGCONFIG(TAG, " Denoise capacitance level: %s", cap_level_s); - } -#else - if (this->iir_filter_enabled_()) { - ESP_LOGCONFIG(TAG, " IIR Filter: %" PRIu32 "ms", this->iir_filter_); - } else { - ESP_LOGCONFIG(TAG, " IIR Filter DISABLED"); - } -#endif - - if (this->setup_mode_) { - ESP_LOGCONFIG(TAG, " Setup Mode ENABLED"); - } - - for (auto *child : this->children_) { - LOG_BINARY_SENSOR(" ", "Touch Pad", child); - ESP_LOGCONFIG(TAG, " Pad: T%" PRIu32, (uint32_t) child->get_touch_pad()); - ESP_LOGCONFIG(TAG, " Threshold: %" PRIu32, child->get_threshold()); - } -} - -uint32_t ESP32TouchComponent::component_touch_pad_read(touch_pad_t tp) { -#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) - uint32_t value = 0; - if (this->filter_configured_()) { - touch_pad_filter_read_smooth(tp, &value); - } else { - touch_pad_read_raw_data(tp, &value); - } -#else - uint16_t value = 0; - if (this->iir_filter_enabled_()) { - touch_pad_read_filtered(tp, &value); - } else { - touch_pad_read(tp, &value); - } -#endif - return value; -} - -void ESP32TouchComponent::loop() { - const uint32_t now = App.get_loop_component_start_time(); - bool should_print = this->setup_mode_ && now - this->setup_mode_last_log_print_ > 250; - for (auto *child : this->children_) { - child->value_ = this->component_touch_pad_read(child->get_touch_pad()); -#if !(defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)) - child->publish_state(child->value_ < child->get_threshold()); -#else - child->publish_state(child->value_ > child->get_threshold()); -#endif - - if (should_print) { - ESP_LOGD(TAG, "Touch Pad '%s' (T%" PRIu32 "): %" PRIu32, child->get_name().c_str(), - (uint32_t) child->get_touch_pad(), child->value_); - } - - App.feed_wdt(); - } - - if (should_print) { - // Avoid spamming logs - this->setup_mode_last_log_print_ = now; - } -} - -void ESP32TouchComponent::on_shutdown() { - bool is_wakeup_source = false; - -#if !(defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)) - if (this->iir_filter_enabled_()) { - touch_pad_filter_stop(); - touch_pad_filter_delete(); - } -#endif - - for (auto *child : this->children_) { - if (child->get_wakeup_threshold() != 0) { - if (!is_wakeup_source) { - is_wakeup_source = true; - // Touch sensor FSM mode must be 'TOUCH_FSM_MODE_TIMER' to use it to wake-up. - touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER); - } - -#if !(defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)) - // No filter available when using as wake-up source. - touch_pad_config(child->get_touch_pad(), child->get_wakeup_threshold()); -#endif - } - } - - if (!is_wakeup_source) { - touch_pad_deinit(); - } -} - -ESP32TouchBinarySensor::ESP32TouchBinarySensor(touch_pad_t touch_pad, uint32_t threshold, uint32_t wakeup_threshold) - : touch_pad_(touch_pad), threshold_(threshold), wakeup_threshold_(wakeup_threshold) {} - -} // namespace esp32_touch -} // namespace esphome - -#endif diff --git a/esphome/components/esp32_touch/esp32_touch.h b/esphome/components/esp32_touch/esp32_touch.h index 3fce8a7e18..5a91b1c750 100644 --- a/esphome/components/esp32_touch/esp32_touch.h +++ b/esphome/components/esp32_touch/esp32_touch.h @@ -9,10 +9,26 @@ #include #include +#include +#include namespace esphome { namespace esp32_touch { +// IMPORTANT: Touch detection logic differs between ESP32 variants: +// - ESP32 v1 (original): Touch detected when value < threshold (capacitance increase causes value decrease) +// - ESP32-S2/S3 v2: Touch detected when value > threshold (capacitance increase causes value increase) +// This inversion is due to different hardware implementations between chip generations. +// +// INTERRUPT BEHAVIOR: +// - ESP32 v1: Interrupts fire when ANY pad is touched and continue while touched. +// Releases are detected by timeout since hardware doesn't generate release interrupts. +// - ESP32-S2/S3 v2: Hardware supports both touch and release interrupts, but release +// interrupts are unreliable and sometimes don't fire. We now only use touch interrupts +// and detect releases via timeout, similar to v1. + +static const uint32_t SETUP_MODE_LOG_INTERVAL_MS = 250; + class ESP32TouchBinarySensor; class ESP32TouchComponent : public Component { @@ -31,6 +47,14 @@ class ESP32TouchComponent : public Component { void set_voltage_attenuation(touch_volt_atten_t voltage_attenuation) { this->voltage_attenuation_ = voltage_attenuation; } + + void setup() override; + void dump_config() override; + void loop() override; + float get_setup_priority() const override { return setup_priority::DATA; } + + void on_shutdown() override; + #if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) void set_filter_mode(touch_filter_mode_t filter_mode) { this->filter_mode_ = filter_mode; } void set_debounce_count(uint32_t debounce_count) { this->debounce_count_ = debounce_count; } @@ -47,16 +71,90 @@ class ESP32TouchComponent : public Component { void set_iir_filter(uint32_t iir_filter) { this->iir_filter_ = iir_filter; } #endif - uint32_t component_touch_pad_read(touch_pad_t tp); + protected: + // Common helper methods + void dump_config_base_(); + void dump_config_sensors_(); + bool create_touch_queue_(); + void cleanup_touch_queue_(); + void configure_wakeup_pads_(); - void setup() override; - void dump_config() override; - void loop() override; + // Helper methods for loop() logic + void process_setup_mode_logging_(uint32_t now); + bool should_check_for_releases_(uint32_t now); + void publish_initial_state_if_needed_(ESP32TouchBinarySensor *child, uint32_t now); + void check_and_disable_loop_if_all_released_(size_t pads_off); + void calculate_release_timeout_(); - void on_shutdown() override; + // Common members + std::vector children_; + bool setup_mode_{false}; + uint32_t setup_mode_last_log_print_{0}; + uint32_t last_release_check_{0}; + uint32_t release_timeout_ms_{1500}; + uint32_t release_check_interval_ms_{50}; + + // Common configuration parameters + uint16_t sleep_cycle_{4095}; + uint16_t meas_cycle_{65535}; + touch_low_volt_t low_voltage_reference_{TOUCH_LVOLT_0V5}; + touch_high_volt_t high_voltage_reference_{TOUCH_HVOLT_2V7}; + touch_volt_atten_t voltage_attenuation_{TOUCH_HVOLT_ATTEN_0V}; + + // Common constants + static constexpr uint32_t MINIMUM_RELEASE_TIME_MS = 100; + + // ==================== PLATFORM SPECIFIC ==================== + +#ifdef USE_ESP32_VARIANT_ESP32 + // ESP32 v1 specific + + static void touch_isr_handler(void *arg); + QueueHandle_t touch_queue_{nullptr}; + + private: + // Touch event structure for ESP32 v1 + // Contains touch pad info, value, and touch state for queue communication + struct TouchPadEventV1 { + touch_pad_t pad; + uint32_t value; + bool is_touched; + }; protected: -#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) + uint32_t iir_filter_{0}; + + bool iir_filter_enabled_() const { return this->iir_filter_ > 0; } + +#elif defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) + // ESP32-S2/S3 v2 specific + static void touch_isr_handler(void *arg); + QueueHandle_t touch_queue_{nullptr}; + + private: + // Touch event structure for ESP32 v2 (S2/S3) + // Contains touch pad and interrupt mask for queue communication + struct TouchPadEventV2 { + touch_pad_t pad; + uint32_t intr_mask; + }; + + protected: + // Filter configuration + touch_filter_mode_t filter_mode_{TOUCH_PAD_FILTER_MAX}; + uint32_t debounce_count_{0}; + uint32_t noise_threshold_{0}; + uint32_t jitter_step_{0}; + touch_smooth_mode_t smooth_level_{TOUCH_PAD_SMOOTH_MAX}; + + // Denoise configuration + touch_pad_denoise_grade_t grade_{TOUCH_PAD_DENOISE_MAX}; + touch_pad_denoise_cap_t cap_level_{TOUCH_PAD_DENOISE_CAP_MAX}; + + // Waterproof configuration + touch_pad_t waterproof_guard_ring_pad_{TOUCH_PAD_MAX}; + touch_pad_shield_driver_t waterproof_shield_driver_{TOUCH_PAD_SHIELD_DRV_MAX}; + bool filter_configured_() const { return (this->filter_mode_ != TOUCH_PAD_FILTER_MAX) && (this->smooth_level_ != TOUCH_PAD_SMOOTH_MAX); } @@ -67,43 +165,78 @@ class ESP32TouchComponent : public Component { return (this->waterproof_guard_ring_pad_ != TOUCH_PAD_MAX) && (this->waterproof_shield_driver_ != TOUCH_PAD_SHIELD_DRV_MAX); } -#else - bool iir_filter_enabled_() const { return this->iir_filter_ > 0; } + + // Helper method to read touch values - non-blocking operation + // Returns the current touch pad value using either filtered or raw reading + // based on the filter configuration + uint32_t read_touch_value(touch_pad_t pad) const; + + // Helper to update touch state with a known state + void update_touch_state_(ESP32TouchBinarySensor *child, bool is_touched); + + // Helper to read touch value and update state for a given child + bool check_and_update_touch_state_(ESP32TouchBinarySensor *child); #endif - std::vector children_; - bool setup_mode_{false}; - uint32_t setup_mode_last_log_print_{0}; - // common parameters - uint16_t sleep_cycle_{4095}; - uint16_t meas_cycle_{65535}; - touch_low_volt_t low_voltage_reference_{TOUCH_LVOLT_0V5}; - touch_high_volt_t high_voltage_reference_{TOUCH_HVOLT_2V7}; - touch_volt_atten_t voltage_attenuation_{TOUCH_HVOLT_ATTEN_0V}; -#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) - touch_filter_mode_t filter_mode_{TOUCH_PAD_FILTER_MAX}; - uint32_t debounce_count_{0}; - uint32_t noise_threshold_{0}; - uint32_t jitter_step_{0}; - touch_smooth_mode_t smooth_level_{TOUCH_PAD_SMOOTH_MAX}; - touch_pad_denoise_grade_t grade_{TOUCH_PAD_DENOISE_MAX}; - touch_pad_denoise_cap_t cap_level_{TOUCH_PAD_DENOISE_CAP_MAX}; - touch_pad_t waterproof_guard_ring_pad_{TOUCH_PAD_MAX}; - touch_pad_shield_driver_t waterproof_shield_driver_{TOUCH_PAD_SHIELD_DRV_MAX}; -#else - uint32_t iir_filter_{0}; -#endif + // Helper functions for dump_config - common to both implementations + static const char *get_low_voltage_reference_str(touch_low_volt_t ref) { + switch (ref) { + case TOUCH_LVOLT_0V5: + return "0.5V"; + case TOUCH_LVOLT_0V6: + return "0.6V"; + case TOUCH_LVOLT_0V7: + return "0.7V"; + case TOUCH_LVOLT_0V8: + return "0.8V"; + default: + return "UNKNOWN"; + } + } + + static const char *get_high_voltage_reference_str(touch_high_volt_t ref) { + switch (ref) { + case TOUCH_HVOLT_2V4: + return "2.4V"; + case TOUCH_HVOLT_2V5: + return "2.5V"; + case TOUCH_HVOLT_2V6: + return "2.6V"; + case TOUCH_HVOLT_2V7: + return "2.7V"; + default: + return "UNKNOWN"; + } + } + + static const char *get_voltage_attenuation_str(touch_volt_atten_t atten) { + switch (atten) { + case TOUCH_HVOLT_ATTEN_1V5: + return "1.5V"; + case TOUCH_HVOLT_ATTEN_1V: + return "1V"; + case TOUCH_HVOLT_ATTEN_0V5: + return "0.5V"; + case TOUCH_HVOLT_ATTEN_0V: + return "0V"; + default: + return "UNKNOWN"; + } + } }; /// Simple helper class to expose a touch pad value as a binary sensor. class ESP32TouchBinarySensor : public binary_sensor::BinarySensor { public: - ESP32TouchBinarySensor(touch_pad_t touch_pad, uint32_t threshold, uint32_t wakeup_threshold); + ESP32TouchBinarySensor(touch_pad_t touch_pad, uint32_t threshold, uint32_t wakeup_threshold) + : touch_pad_(touch_pad), threshold_(threshold), wakeup_threshold_(wakeup_threshold) {} touch_pad_t get_touch_pad() const { return this->touch_pad_; } uint32_t get_threshold() const { return this->threshold_; } void set_threshold(uint32_t threshold) { this->threshold_ = threshold; } +#ifdef USE_ESP32_VARIANT_ESP32 uint32_t get_value() const { return this->value_; } +#endif uint32_t get_wakeup_threshold() const { return this->wakeup_threshold_; } protected: @@ -111,8 +244,22 @@ class ESP32TouchBinarySensor : public binary_sensor::BinarySensor { touch_pad_t touch_pad_{TOUCH_PAD_MAX}; uint32_t threshold_{0}; + uint32_t benchmark_{}; +#ifdef USE_ESP32_VARIANT_ESP32 uint32_t value_{0}; +#endif + bool last_state_{false}; const uint32_t wakeup_threshold_{0}; + + // Track last touch time for timeout-based release detection + // Design note: last_touch_time_ does not require synchronization primitives because: + // 1. ESP32 guarantees atomic 32-bit aligned reads/writes + // 2. ISR only writes timestamps, main loop only reads + // 3. Timing tolerance allows for occasional stale reads (50ms check interval) + // 4. Queue operations provide implicit memory barriers + // Using atomic/critical sections would add overhead without meaningful benefit + uint32_t last_touch_time_{}; + bool initial_state_published_{}; }; } // namespace esp32_touch diff --git a/esphome/components/esp32_touch/esp32_touch_common.cpp b/esphome/components/esp32_touch/esp32_touch_common.cpp new file mode 100644 index 0000000000..2d93de077e --- /dev/null +++ b/esphome/components/esp32_touch/esp32_touch_common.cpp @@ -0,0 +1,162 @@ +#ifdef USE_ESP32 + +#include "esp32_touch.h" +#include "esphome/core/log.h" +#include + +#include "soc/rtc.h" + +namespace esphome { +namespace esp32_touch { + +static const char *const TAG = "esp32_touch"; + +void ESP32TouchComponent::dump_config_base_() { + const char *lv_s = get_low_voltage_reference_str(this->low_voltage_reference_); + const char *hv_s = get_high_voltage_reference_str(this->high_voltage_reference_); + const char *atten_s = get_voltage_attenuation_str(this->voltage_attenuation_); + + ESP_LOGCONFIG(TAG, + "Config for ESP32 Touch Hub:\n" + " Meas cycle: %.2fms\n" + " Sleep cycle: %.2fms\n" + " Low Voltage Reference: %s\n" + " High Voltage Reference: %s\n" + " Voltage Attenuation: %s\n" + " Release Timeout: %" PRIu32 "ms\n", + this->meas_cycle_ / (8000000.0f / 1000.0f), this->sleep_cycle_ / (150000.0f / 1000.0f), lv_s, hv_s, + atten_s, this->release_timeout_ms_); +} + +void ESP32TouchComponent::dump_config_sensors_() { + for (auto *child : this->children_) { + LOG_BINARY_SENSOR(" ", "Touch Pad", child); + ESP_LOGCONFIG(TAG, + " Pad: T%u\n" + " Threshold: %" PRIu32 "\n" + " Benchmark: %" PRIu32, + (unsigned) child->touch_pad_, child->threshold_, child->benchmark_); + } +} + +bool ESP32TouchComponent::create_touch_queue_() { + // Queue size calculation: children * 4 allows for burst scenarios where ISR + // fires multiple times before main loop processes. + size_t queue_size = this->children_.size() * 4; + if (queue_size < 8) + queue_size = 8; + +#ifdef USE_ESP32_VARIANT_ESP32 + this->touch_queue_ = xQueueCreate(queue_size, sizeof(TouchPadEventV1)); +#else + this->touch_queue_ = xQueueCreate(queue_size, sizeof(TouchPadEventV2)); +#endif + + if (this->touch_queue_ == nullptr) { + ESP_LOGE(TAG, "Failed to create touch event queue of size %" PRIu32, (uint32_t) queue_size); + this->mark_failed(); + return false; + } + return true; +} + +void ESP32TouchComponent::cleanup_touch_queue_() { + if (this->touch_queue_) { + vQueueDelete(this->touch_queue_); + this->touch_queue_ = nullptr; + } +} + +void ESP32TouchComponent::configure_wakeup_pads_() { + bool is_wakeup_source = false; + + // Check if any pad is configured for wakeup + for (auto *child : this->children_) { + if (child->get_wakeup_threshold() != 0) { + is_wakeup_source = true; + +#ifdef USE_ESP32_VARIANT_ESP32 + // ESP32 v1: No filter available when using as wake-up source. + touch_pad_config(child->get_touch_pad(), child->get_wakeup_threshold()); +#else + // ESP32-S2/S3 v2: Set threshold for wakeup + touch_pad_set_thresh(child->get_touch_pad(), child->get_wakeup_threshold()); +#endif + } + } + + if (!is_wakeup_source) { + // If no pad is configured for wakeup, deinitialize touch pad + touch_pad_deinit(); + } +} + +void ESP32TouchComponent::process_setup_mode_logging_(uint32_t now) { + if (this->setup_mode_ && now - this->setup_mode_last_log_print_ > SETUP_MODE_LOG_INTERVAL_MS) { + for (auto *child : this->children_) { +#ifdef USE_ESP32_VARIANT_ESP32 + ESP_LOGD(TAG, "Touch Pad '%s' (T%" PRIu32 "): %" PRIu32, child->get_name().c_str(), + (uint32_t) child->get_touch_pad(), child->value_); +#else + // Read the value being used for touch detection + uint32_t value = this->read_touch_value(child->get_touch_pad()); + ESP_LOGD(TAG, "Touch Pad '%s' (T%d): %d", child->get_name().c_str(), child->get_touch_pad(), value); +#endif + } + this->setup_mode_last_log_print_ = now; + } +} + +bool ESP32TouchComponent::should_check_for_releases_(uint32_t now) { + if (now - this->last_release_check_ < this->release_check_interval_ms_) { + return false; + } + this->last_release_check_ = now; + return true; +} + +void ESP32TouchComponent::publish_initial_state_if_needed_(ESP32TouchBinarySensor *child, uint32_t now) { + if (!child->initial_state_published_) { + // Check if enough time has passed since startup + if (now > this->release_timeout_ms_) { + child->publish_initial_state(false); + child->initial_state_published_ = true; + ESP_LOGV(TAG, "Touch Pad '%s' state: OFF (initial)", child->get_name().c_str()); + } + } +} + +void ESP32TouchComponent::check_and_disable_loop_if_all_released_(size_t pads_off) { + // Disable the loop to save CPU cycles when all pads are off and not in setup mode. + if (pads_off == this->children_.size() && !this->setup_mode_) { + this->disable_loop(); + } +} + +void ESP32TouchComponent::calculate_release_timeout_() { + // Calculate release timeout based on sleep cycle + // Design note: Hardware limitation - interrupts only fire reliably on touch (not release) + // We must use timeout-based detection for release events + // Formula: 3 sleep cycles converted to ms, with MINIMUM_RELEASE_TIME_MS minimum + // Per ESP-IDF docs: t_sleep = sleep_cycle / SOC_CLK_RC_SLOW_FREQ_APPROX + + uint32_t rtc_freq = rtc_clk_slow_freq_get_hz(); + + // Calculate timeout as 3 sleep cycles + this->release_timeout_ms_ = (this->sleep_cycle_ * 1000 * 3) / rtc_freq; + + if (this->release_timeout_ms_ < MINIMUM_RELEASE_TIME_MS) { + this->release_timeout_ms_ = MINIMUM_RELEASE_TIME_MS; + } + + // Check for releases at 1/4 the timeout interval + // Since hardware doesn't generate reliable release interrupts, we must poll + // for releases in the main loop. Checking at 1/4 the timeout interval provides + // a good balance between responsiveness and efficiency. + this->release_check_interval_ms_ = this->release_timeout_ms_ / 4; +} + +} // namespace esp32_touch +} // namespace esphome + +#endif // USE_ESP32 diff --git a/esphome/components/esp32_touch/esp32_touch_v1.cpp b/esphome/components/esp32_touch/esp32_touch_v1.cpp new file mode 100644 index 0000000000..6f05610ed6 --- /dev/null +++ b/esphome/components/esp32_touch/esp32_touch_v1.cpp @@ -0,0 +1,238 @@ +#ifdef USE_ESP32_VARIANT_ESP32 + +#include "esp32_touch.h" +#include "esphome/core/application.h" +#include "esphome/core/log.h" +#include "esphome/core/hal.h" + +#include +#include + +// Include HAL for ISR-safe touch reading +#include "hal/touch_sensor_ll.h" + +namespace esphome { +namespace esp32_touch { + +static const char *const TAG = "esp32_touch"; + +void ESP32TouchComponent::setup() { + // Create queue for touch events + // Queue size calculation: children * 4 allows for burst scenarios where ISR + // fires multiple times before main loop processes. This is important because + // ESP32 v1 scans all pads on each interrupt, potentially sending multiple events. + if (!this->create_touch_queue_()) { + return; + } + + touch_pad_init(); + touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER); + + // Set up IIR filter if enabled + if (this->iir_filter_enabled_()) { + touch_pad_filter_start(this->iir_filter_); + } + + // Configure measurement parameters +#if ESP_IDF_VERSION_MAJOR >= 5 + touch_pad_set_measurement_clock_cycles(this->meas_cycle_); + touch_pad_set_measurement_interval(this->sleep_cycle_); +#else + touch_pad_set_meas_time(this->sleep_cycle_, this->meas_cycle_); +#endif + touch_pad_set_voltage(this->high_voltage_reference_, this->low_voltage_reference_, this->voltage_attenuation_); + + // Configure each touch pad + for (auto *child : this->children_) { + touch_pad_config(child->get_touch_pad(), child->get_threshold()); + } + + // Register ISR handler + esp_err_t err = touch_pad_isr_register(touch_isr_handler, this); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to register touch ISR: %s", esp_err_to_name(err)); + this->cleanup_touch_queue_(); + this->mark_failed(); + return; + } + + // Calculate release timeout based on sleep cycle + this->calculate_release_timeout_(); + + // Enable touch pad interrupt + touch_pad_intr_enable(); +} + +void ESP32TouchComponent::dump_config() { + this->dump_config_base_(); + + if (this->iir_filter_enabled_()) { + ESP_LOGCONFIG(TAG, " IIR Filter: %" PRIu32 "ms", this->iir_filter_); + } else { + ESP_LOGCONFIG(TAG, " IIR Filter DISABLED"); + } + + if (this->setup_mode_) { + ESP_LOGCONFIG(TAG, " Setup Mode ENABLED"); + } + + this->dump_config_sensors_(); +} + +void ESP32TouchComponent::loop() { + const uint32_t now = App.get_loop_component_start_time(); + + // Print debug info for all pads in setup mode + this->process_setup_mode_logging_(now); + + // Process any queued touch events from interrupts + // Note: Events are only sent by ISR for pads that were measured in that cycle (value != 0) + // This is more efficient than sending all pad states every interrupt + TouchPadEventV1 event; + while (xQueueReceive(this->touch_queue_, &event, 0) == pdTRUE) { + // Find the corresponding sensor - O(n) search is acceptable since events are infrequent + for (auto *child : this->children_) { + if (child->get_touch_pad() != event.pad) { + continue; + } + + // Found matching pad - process it + child->value_ = event.value; + + // The interrupt gives us the touch state directly + bool new_state = event.is_touched; + + // Track when we last saw this pad as touched + if (new_state) { + child->last_touch_time_ = now; + } + + // Only publish if state changed - this filters out repeated events + if (new_state != child->last_state_) { + child->last_state_ = new_state; + child->publish_state(new_state); + // Original ESP32: ISR only fires when touched, release is detected by timeout + // Note: ESP32 v1 uses inverted logic - touched when value < threshold + ESP_LOGV(TAG, "Touch Pad '%s' state: ON (value: %" PRIu32 " < threshold: %" PRIu32 ")", + child->get_name().c_str(), event.value, child->get_threshold()); + } + break; // Exit inner loop after processing matching pad + } + } + + // Check for released pads periodically + if (!this->should_check_for_releases_(now)) { + return; + } + + size_t pads_off = 0; + for (auto *child : this->children_) { + // Handle initial state publication after startup + this->publish_initial_state_if_needed_(child, now); + + if (child->last_state_) { + // Pad is currently in touched state - check for release timeout + // Using subtraction handles 32-bit rollover correctly + uint32_t time_diff = now - child->last_touch_time_; + + // Check if we haven't seen this pad recently + if (time_diff > this->release_timeout_ms_) { + // Haven't seen this pad recently, assume it's released + child->last_state_ = false; + child->publish_state(false); + ESP_LOGV(TAG, "Touch Pad '%s' state: OFF (timeout)", child->get_name().c_str()); + pads_off++; + } + } else { + // Pad is already off + pads_off++; + } + } + + // Disable the loop to save CPU cycles when all pads are off and not in setup mode. + // The loop will be re-enabled by the ISR when any touch pad is touched. + // v1 hardware limitations require us to check all pads are off because: + // - v1 only generates interrupts on touch events (not releases) + // - We must poll for release timeouts in the main loop + // - We can only safely disable when no pads need timeout monitoring + this->check_and_disable_loop_if_all_released_(pads_off); +} + +void ESP32TouchComponent::on_shutdown() { + touch_pad_intr_disable(); + touch_pad_isr_deregister(touch_isr_handler, this); + this->cleanup_touch_queue_(); + + if (this->iir_filter_enabled_()) { + touch_pad_filter_stop(); + touch_pad_filter_delete(); + } + + // Configure wakeup pads if any are set + this->configure_wakeup_pads_(); +} + +void IRAM_ATTR ESP32TouchComponent::touch_isr_handler(void *arg) { + ESP32TouchComponent *component = static_cast(arg); + + touch_pad_clear_status(); + + // INTERRUPT BEHAVIOR: On ESP32 v1 hardware, the interrupt fires when ANY configured + // touch pad detects a touch (value goes below threshold). The hardware does NOT + // generate interrupts on release - only on touch events. + // The interrupt will continue to fire periodically (based on sleep_cycle) as long + // as any pad remains touched. This allows us to detect both new touches and + // continued touches, but releases must be detected by timeout in the main loop. + + // Process all configured pads to check their current state + // Note: ESP32 v1 doesn't tell us which specific pad triggered the interrupt, + // so we must scan all configured pads to find which ones were touched + for (auto *child : component->children_) { + touch_pad_t pad = child->get_touch_pad(); + + // Read current value using ISR-safe API + uint32_t value; + if (component->iir_filter_enabled_()) { + uint16_t temp_value = 0; + touch_pad_read_filtered(pad, &temp_value); + value = temp_value; + } else { + // Use low-level HAL function when filter is not enabled + value = touch_ll_read_raw_data(pad); + } + + // Skip pads with 0 value - they haven't been measured in this cycle + // This is important: not all pads are measured every interrupt cycle, + // only those that the hardware has updated + if (value == 0) { + continue; + } + + // IMPORTANT: ESP32 v1 touch detection logic - INVERTED compared to v2! + // ESP32 v1: Touch is detected when capacitance INCREASES, causing the measured value to DECREASE + // Therefore: touched = (value < threshold) + // This is opposite to ESP32-S2/S3 v2 where touched = (value > threshold) + bool is_touched = value < child->get_threshold(); + + // Always send the current state - the main loop will filter for changes + // We send both touched and untouched states because the ISR doesn't + // track previous state (to keep ISR fast and simple) + TouchPadEventV1 event; + event.pad = pad; + event.value = value; + event.is_touched = is_touched; + + // Send to queue from ISR - non-blocking, drops if queue full + BaseType_t x_higher_priority_task_woken = pdFALSE; + xQueueSendFromISR(component->touch_queue_, &event, &x_higher_priority_task_woken); + component->enable_loop_soon_any_context(); + if (x_higher_priority_task_woken) { + portYIELD_FROM_ISR(); + } + } +} + +} // namespace esp32_touch +} // namespace esphome + +#endif // USE_ESP32_VARIANT_ESP32 diff --git a/esphome/components/esp32_touch/esp32_touch_v2.cpp b/esphome/components/esp32_touch/esp32_touch_v2.cpp new file mode 100644 index 0000000000..afd2655fd7 --- /dev/null +++ b/esphome/components/esp32_touch/esp32_touch_v2.cpp @@ -0,0 +1,397 @@ +#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) + +#include "esp32_touch.h" +#include "esphome/core/application.h" +#include "esphome/core/log.h" +#include "esphome/core/hal.h" + +namespace esphome { +namespace esp32_touch { + +static const char *const TAG = "esp32_touch"; + +// Helper to update touch state with a known state +void ESP32TouchComponent::update_touch_state_(ESP32TouchBinarySensor *child, bool is_touched) { + // Always update timer when touched + if (is_touched) { + child->last_touch_time_ = App.get_loop_component_start_time(); + } + + if (child->last_state_ != is_touched) { + child->last_state_ = is_touched; + child->publish_state(is_touched); + if (is_touched) { + // ESP32-S2/S3 v2: touched when value > threshold + ESP_LOGV(TAG, "Touch Pad '%s' state: ON (value: %" PRIu32 " > threshold: %" PRIu32 ")", child->get_name().c_str(), + this->read_touch_value(child->touch_pad_), child->threshold_ + child->benchmark_); + } else { + ESP_LOGV(TAG, "Touch Pad '%s' state: OFF", child->get_name().c_str()); + } + } +} + +// Helper to read touch value and update state for a given child (used for timeout events) +bool ESP32TouchComponent::check_and_update_touch_state_(ESP32TouchBinarySensor *child) { + // Read current touch value + uint32_t value = this->read_touch_value(child->touch_pad_); + + // ESP32-S2/S3 v2: Touch is detected when value > threshold + benchmark + ESP_LOGV(TAG, + "Checking touch state for '%s' (T%d): value = %" PRIu32 ", threshold = %" PRIu32 ", benchmark = %" PRIu32, + child->get_name().c_str(), child->touch_pad_, value, child->threshold_, child->benchmark_); + bool is_touched = value > child->benchmark_ + child->threshold_; + + this->update_touch_state_(child, is_touched); + return is_touched; +} + +void ESP32TouchComponent::setup() { + // Create queue for touch events first + if (!this->create_touch_queue_()) { + return; + } + + // Initialize touch pad peripheral + esp_err_t init_err = touch_pad_init(); + if (init_err != ESP_OK) { + ESP_LOGE(TAG, "Failed to initialize touch pad: %s", esp_err_to_name(init_err)); + this->mark_failed(); + return; + } + + // Configure each touch pad first + for (auto *child : this->children_) { + esp_err_t config_err = touch_pad_config(child->touch_pad_); + if (config_err != ESP_OK) { + ESP_LOGE(TAG, "Failed to configure touch pad %d: %s", child->touch_pad_, esp_err_to_name(config_err)); + } + } + + // Set up filtering if configured + if (this->filter_configured_()) { + touch_filter_config_t filter_info = { + .mode = this->filter_mode_, + .debounce_cnt = this->debounce_count_, + .noise_thr = this->noise_threshold_, + .jitter_step = this->jitter_step_, + .smh_lvl = this->smooth_level_, + }; + touch_pad_filter_set_config(&filter_info); + touch_pad_filter_enable(); + } + + if (this->denoise_configured_()) { + touch_pad_denoise_t denoise = { + .grade = this->grade_, + .cap_level = this->cap_level_, + }; + touch_pad_denoise_set_config(&denoise); + touch_pad_denoise_enable(); + } + + if (this->waterproof_configured_()) { + touch_pad_waterproof_t waterproof = { + .guard_ring_pad = this->waterproof_guard_ring_pad_, + .shield_driver = this->waterproof_shield_driver_, + }; + touch_pad_waterproof_set_config(&waterproof); + touch_pad_waterproof_enable(); + } + + // Configure measurement parameters + touch_pad_set_voltage(this->high_voltage_reference_, this->low_voltage_reference_, this->voltage_attenuation_); + touch_pad_set_charge_discharge_times(this->meas_cycle_); + touch_pad_set_measurement_interval(this->sleep_cycle_); + + // Configure timeout if needed + touch_pad_timeout_set(true, TOUCH_PAD_THRESHOLD_MAX); + + // Register ISR handler with interrupt mask + esp_err_t err = + touch_pad_isr_register(touch_isr_handler, this, static_cast(TOUCH_PAD_INTR_MASK_ALL)); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to register touch ISR: %s", esp_err_to_name(err)); + this->cleanup_touch_queue_(); + this->mark_failed(); + return; + } + + // Set thresholds for each pad BEFORE starting FSM + for (auto *child : this->children_) { + if (child->threshold_ != 0) { + touch_pad_set_thresh(child->touch_pad_, child->threshold_); + } + } + + // Enable interrupts - only ACTIVE and TIMEOUT + // NOTE: We intentionally don't enable INACTIVE interrupts because they are unreliable + // on ESP32-S2/S3 hardware and sometimes don't fire. Instead, we use timeout-based + // release detection with the ability to verify the actual state. + touch_pad_intr_enable(static_cast(TOUCH_PAD_INTR_MASK_ACTIVE | TOUCH_PAD_INTR_MASK_TIMEOUT)); + + // Set FSM mode before starting + touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER); + + // Start FSM + touch_pad_fsm_start(); + + // Calculate release timeout based on sleep cycle + this->calculate_release_timeout_(); +} + +void ESP32TouchComponent::dump_config() { + this->dump_config_base_(); + + if (this->filter_configured_()) { + const char *filter_mode_s; + switch (this->filter_mode_) { + case TOUCH_PAD_FILTER_IIR_4: + filter_mode_s = "IIR_4"; + break; + case TOUCH_PAD_FILTER_IIR_8: + filter_mode_s = "IIR_8"; + break; + case TOUCH_PAD_FILTER_IIR_16: + filter_mode_s = "IIR_16"; + break; + case TOUCH_PAD_FILTER_IIR_32: + filter_mode_s = "IIR_32"; + break; + case TOUCH_PAD_FILTER_IIR_64: + filter_mode_s = "IIR_64"; + break; + case TOUCH_PAD_FILTER_IIR_128: + filter_mode_s = "IIR_128"; + break; + case TOUCH_PAD_FILTER_IIR_256: + filter_mode_s = "IIR_256"; + break; + case TOUCH_PAD_FILTER_JITTER: + filter_mode_s = "JITTER"; + break; + default: + filter_mode_s = "UNKNOWN"; + break; + } + ESP_LOGCONFIG(TAG, + " Filter mode: %s\n" + " Debounce count: %" PRIu32 "\n" + " Noise threshold coefficient: %" PRIu32 "\n" + " Jitter filter step size: %" PRIu32, + filter_mode_s, this->debounce_count_, this->noise_threshold_, this->jitter_step_); + const char *smooth_level_s; + switch (this->smooth_level_) { + case TOUCH_PAD_SMOOTH_OFF: + smooth_level_s = "OFF"; + break; + case TOUCH_PAD_SMOOTH_IIR_2: + smooth_level_s = "IIR_2"; + break; + case TOUCH_PAD_SMOOTH_IIR_4: + smooth_level_s = "IIR_4"; + break; + case TOUCH_PAD_SMOOTH_IIR_8: + smooth_level_s = "IIR_8"; + break; + default: + smooth_level_s = "UNKNOWN"; + break; + } + ESP_LOGCONFIG(TAG, " Smooth level: %s", smooth_level_s); + } + + if (this->denoise_configured_()) { + const char *grade_s; + switch (this->grade_) { + case TOUCH_PAD_DENOISE_BIT12: + grade_s = "BIT12"; + break; + case TOUCH_PAD_DENOISE_BIT10: + grade_s = "BIT10"; + break; + case TOUCH_PAD_DENOISE_BIT8: + grade_s = "BIT8"; + break; + case TOUCH_PAD_DENOISE_BIT4: + grade_s = "BIT4"; + break; + default: + grade_s = "UNKNOWN"; + break; + } + ESP_LOGCONFIG(TAG, " Denoise grade: %s", grade_s); + + const char *cap_level_s; + switch (this->cap_level_) { + case TOUCH_PAD_DENOISE_CAP_L0: + cap_level_s = "L0"; + break; + case TOUCH_PAD_DENOISE_CAP_L1: + cap_level_s = "L1"; + break; + case TOUCH_PAD_DENOISE_CAP_L2: + cap_level_s = "L2"; + break; + case TOUCH_PAD_DENOISE_CAP_L3: + cap_level_s = "L3"; + break; + case TOUCH_PAD_DENOISE_CAP_L4: + cap_level_s = "L4"; + break; + case TOUCH_PAD_DENOISE_CAP_L5: + cap_level_s = "L5"; + break; + case TOUCH_PAD_DENOISE_CAP_L6: + cap_level_s = "L6"; + break; + case TOUCH_PAD_DENOISE_CAP_L7: + cap_level_s = "L7"; + break; + default: + cap_level_s = "UNKNOWN"; + break; + } + ESP_LOGCONFIG(TAG, " Denoise capacitance level: %s", cap_level_s); + } + + if (this->setup_mode_) { + ESP_LOGCONFIG(TAG, " Setup Mode ENABLED"); + } + + this->dump_config_sensors_(); +} + +void ESP32TouchComponent::loop() { + const uint32_t now = App.get_loop_component_start_time(); + + // V2 TOUCH HANDLING: + // Due to unreliable INACTIVE interrupts on ESP32-S2/S3, we use a hybrid approach: + // 1. Process ACTIVE interrupts when pads are touched + // 2. Use timeout-based release detection (like v1) + // 3. But smarter than v1: verify actual state before releasing on timeout + // This prevents false releases if we missed interrupts + + // In setup mode, periodically log all pad values + this->process_setup_mode_logging_(now); + + // Process any queued touch events from interrupts + TouchPadEventV2 event; + while (xQueueReceive(this->touch_queue_, &event, 0) == pdTRUE) { + ESP_LOGD(TAG, "Event received, mask = 0x%" PRIx32 ", pad = %d", event.intr_mask, event.pad); + // Handle timeout events + if (event.intr_mask & TOUCH_PAD_INTR_MASK_TIMEOUT) { + // Resume measurement after timeout + touch_pad_timeout_resume(); + // For timeout events, always check the current state + } else if (!(event.intr_mask & TOUCH_PAD_INTR_MASK_ACTIVE)) { + // Skip if not an active/timeout event + continue; + } + + // Find the child for the pad that triggered the interrupt + for (auto *child : this->children_) { + if (child->touch_pad_ == event.pad) { + if (event.intr_mask & TOUCH_PAD_INTR_MASK_TIMEOUT) { + // For timeout events, we need to read the value to determine state + this->check_and_update_touch_state_(child); + } else if (event.intr_mask & TOUCH_PAD_INTR_MASK_ACTIVE) { + // We only get ACTIVE interrupts now, releases are detected by timeout + this->update_touch_state_(child, true); // Always touched for ACTIVE interrupts + } + break; + } + } + } + + // Check for released pads periodically (like v1) + if (!this->should_check_for_releases_(now)) { + return; + } + + size_t pads_off = 0; + for (auto *child : this->children_) { + if (child->benchmark_ == 0) + touch_pad_read_benchmark(child->touch_pad_, &child->benchmark_); + // Handle initial state publication after startup + this->publish_initial_state_if_needed_(child, now); + + if (child->last_state_) { + // Pad is currently in touched state - check for release timeout + // Using subtraction handles 32-bit rollover correctly + uint32_t time_diff = now - child->last_touch_time_; + + // Check if we haven't seen this pad recently + if (time_diff > this->release_timeout_ms_) { + // Haven't seen this pad recently - verify actual state + // Unlike v1, v2 hardware allows us to read the current state anytime + // This makes v2 smarter: we can verify if it's actually released before + // declaring a timeout, preventing false releases if interrupts were missed + bool still_touched = this->check_and_update_touch_state_(child); + + if (still_touched) { + // Still touched! Timer was reset in update_touch_state_ + ESP_LOGVV(TAG, "Touch Pad '%s' still touched after %" PRIu32 "ms timeout, resetting timer", + child->get_name().c_str(), this->release_timeout_ms_); + } else { + // Actually released - already handled by check_and_update_touch_state_ + pads_off++; + } + } + } else { + // Pad is already off + pads_off++; + } + } + + // Disable the loop when all pads are off and not in setup mode (like v1) + // We need to keep checking for timeouts, so only disable when all pads are confirmed off + this->check_and_disable_loop_if_all_released_(pads_off); +} + +void ESP32TouchComponent::on_shutdown() { + // Disable interrupts + touch_pad_intr_disable(static_cast(TOUCH_PAD_INTR_MASK_ACTIVE | TOUCH_PAD_INTR_MASK_TIMEOUT)); + touch_pad_isr_deregister(touch_isr_handler, this); + this->cleanup_touch_queue_(); + + // Configure wakeup pads if any are set + this->configure_wakeup_pads_(); +} + +void IRAM_ATTR ESP32TouchComponent::touch_isr_handler(void *arg) { + ESP32TouchComponent *component = static_cast(arg); + BaseType_t x_higher_priority_task_woken = pdFALSE; + + // Read interrupt status + TouchPadEventV2 event; + event.intr_mask = touch_pad_read_intr_status_mask(); + event.pad = touch_pad_get_current_meas_channel(); + + // Send event to queue for processing in main loop + xQueueSendFromISR(component->touch_queue_, &event, &x_higher_priority_task_woken); + component->enable_loop_soon_any_context(); + + if (x_higher_priority_task_woken) { + portYIELD_FROM_ISR(); + } +} + +uint32_t ESP32TouchComponent::read_touch_value(touch_pad_t pad) const { + // Unlike ESP32 v1, touch reads on ESP32-S2/S3 v2 are non-blocking operations. + // The hardware continuously samples in the background and we can read the + // latest value at any time without waiting. + uint32_t value = 0; + if (this->filter_configured_()) { + // Read filtered/smoothed value when filter is enabled + touch_pad_filter_read_smooth(pad, &value); + } else { + // Read raw value when filter is not configured + touch_pad_read_raw_data(pad, &value); + } + return value; +} + +} // namespace esp32_touch +} // namespace esphome + +#endif // USE_ESP32_VARIANT_ESP32S2 || USE_ESP32_VARIANT_ESP32S3 diff --git a/esphome/components/ethernet/__init__.py b/esphome/components/ethernet/__init__.py index 8eec9510cc..ac07d02e37 100644 --- a/esphome/components/ethernet/__init__.py +++ b/esphome/components/ethernet/__init__.py @@ -23,8 +23,10 @@ from esphome.const import ( CONF_INTERRUPT_PIN, CONF_MANUAL_IP, CONF_MISO_PIN, + CONF_MODE, CONF_MOSI_PIN, CONF_PAGE_ID, + CONF_PIN, CONF_POLLING_INTERVAL, CONF_RESET_PIN, CONF_SPI, @@ -49,6 +51,7 @@ PHYRegister = ethernet_ns.struct("PHYRegister") CONF_PHY_ADDR = "phy_addr" CONF_MDC_PIN = "mdc_pin" CONF_MDIO_PIN = "mdio_pin" +CONF_CLK = "clk" CONF_CLK_MODE = "clk_mode" CONF_POWER_PIN = "power_pin" CONF_PHY_REGISTERS = "phy_registers" @@ -73,26 +76,18 @@ SPI_ETHERNET_TYPES = ["W5500", "DM9051"] SPI_ETHERNET_DEFAULT_POLLING_INTERVAL = TimePeriodMilliseconds(milliseconds=10) emac_rmii_clock_mode_t = cg.global_ns.enum("emac_rmii_clock_mode_t") -emac_rmii_clock_gpio_t = cg.global_ns.enum("emac_rmii_clock_gpio_t") + CLK_MODES = { - "GPIO0_IN": ( - emac_rmii_clock_mode_t.EMAC_CLK_EXT_IN, - emac_rmii_clock_gpio_t.EMAC_CLK_IN_GPIO, - ), - "GPIO0_OUT": ( - emac_rmii_clock_mode_t.EMAC_CLK_OUT, - emac_rmii_clock_gpio_t.EMAC_APPL_CLK_OUT_GPIO, - ), - "GPIO16_OUT": ( - emac_rmii_clock_mode_t.EMAC_CLK_OUT, - emac_rmii_clock_gpio_t.EMAC_CLK_OUT_GPIO, - ), - "GPIO17_OUT": ( - emac_rmii_clock_mode_t.EMAC_CLK_OUT, - emac_rmii_clock_gpio_t.EMAC_CLK_OUT_180_GPIO, - ), + "CLK_EXT_IN": emac_rmii_clock_mode_t.EMAC_CLK_EXT_IN, + "CLK_OUT": emac_rmii_clock_mode_t.EMAC_CLK_OUT, } +CLK_MODES_DEPRECATED = { + "GPIO0_IN": ("CLK_EXT_IN", 0), + "GPIO0_OUT": ("CLK_OUT", 0), + "GPIO16_OUT": ("CLK_OUT", 16), + "GPIO17_OUT": ("CLK_OUT", 17), +} MANUAL_IP_SCHEMA = cv.Schema( { @@ -154,6 +149,18 @@ def _validate(config): f"({CORE.target_framework} {CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION]}), " f"'{CONF_INTERRUPT_PIN}' is a required option for [ethernet]." ) + elif config[CONF_TYPE] != "OPENETH": + if CONF_CLK_MODE in config: + LOGGER.warning( + "[ethernet] The 'clk_mode' option is deprecated and will be removed in ESPHome 2026.1. " + "Please update your configuration to use 'clk' instead." + ) + mode = CLK_MODES_DEPRECATED[config[CONF_CLK_MODE]] + config[CONF_CLK] = CLK_SCHEMA({CONF_MODE: mode[0], CONF_PIN: mode[1]}) + del config[CONF_CLK_MODE] + elif CONF_CLK not in config: + raise cv.Invalid("'clk' is a required option for [ethernet].") + return config @@ -177,14 +184,21 @@ PHY_REGISTER_SCHEMA = cv.Schema( cv.Optional(CONF_PAGE_ID): cv.hex_int, } ) +CLK_SCHEMA = cv.Schema( + { + cv.Required(CONF_MODE): cv.enum(CLK_MODES, upper=True, space="_"), + cv.Required(CONF_PIN): pins.internal_gpio_pin_number, + } +) RMII_SCHEMA = BASE_SCHEMA.extend( cv.Schema( { cv.Required(CONF_MDC_PIN): pins.internal_gpio_output_pin_number, cv.Required(CONF_MDIO_PIN): pins.internal_gpio_output_pin_number, - cv.Optional(CONF_CLK_MODE, default="GPIO0_IN"): cv.enum( - CLK_MODES, upper=True, space="_" + cv.Optional(CONF_CLK_MODE): cv.enum( + CLK_MODES_DEPRECATED, upper=True, space="_" ), + cv.Optional(CONF_CLK): CLK_SCHEMA, cv.Optional(CONF_PHY_ADDR, default=0): cv.int_range(min=0, max=31), cv.Optional(CONF_POWER_PIN): pins.internal_gpio_output_pin_number, cv.Optional(CONF_PHY_REGISTERS): cv.ensure_list(PHY_REGISTER_SCHEMA), @@ -308,7 +322,8 @@ async def to_code(config): cg.add(var.set_phy_addr(config[CONF_PHY_ADDR])) cg.add(var.set_mdc_pin(config[CONF_MDC_PIN])) cg.add(var.set_mdio_pin(config[CONF_MDIO_PIN])) - cg.add(var.set_clk_mode(*CLK_MODES[config[CONF_CLK_MODE]])) + cg.add(var.set_clk_mode(config[CONF_CLK][CONF_MODE])) + cg.add(var.set_clk_pin(config[CONF_CLK][CONF_PIN])) if CONF_POWER_PIN in config: cg.add(var.set_power_pin(config[CONF_POWER_PIN])) for register_value in config.get(CONF_PHY_REGISTERS, []): diff --git a/esphome/components/ethernet/esp_eth_phy_jl1101.c b/esphome/components/ethernet/esp_eth_phy_jl1101.c index de2a6f4f35..4f31e0a9fd 100644 --- a/esphome/components/ethernet/esp_eth_phy_jl1101.c +++ b/esphome/components/ethernet/esp_eth_phy_jl1101.c @@ -19,11 +19,7 @@ #include #include "esp_log.h" #include "esp_eth.h" -#if ESP_IDF_VERSION_MAJOR >= 5 #include "esp_eth_phy_802_3.h" -#else -#include "eth_phy_regs_struct.h" -#endif #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "driver/gpio.h" @@ -174,11 +170,7 @@ static esp_err_t jl1101_reset_hw(esp_eth_phy_t *phy) { return ESP_OK; } -#if ESP_IDF_VERSION_MAJOR >= 5 static esp_err_t jl1101_negotiate(esp_eth_phy_t *phy, eth_phy_autoneg_cmd_t cmd, bool *nego_state) { -#else -static esp_err_t jl1101_negotiate(esp_eth_phy_t *phy) { -#endif phy_jl1101_t *jl1101 = __containerof(phy, phy_jl1101_t, parent); esp_eth_mediator_t *eth = jl1101->eth; /* in case any link status has changed, let's assume we're in link down status */ @@ -293,11 +285,7 @@ static esp_err_t jl1101_init(esp_eth_phy_t *phy) { esp_eth_mediator_t *eth = jl1101->eth; // Detect PHY address if (jl1101->addr == ESP_ETH_PHY_ADDR_AUTO) { -#if ESP_IDF_VERSION_MAJOR >= 5 PHY_CHECK(esp_eth_phy_802_3_detect_phy_addr(eth, &jl1101->addr) == ESP_OK, "Detect PHY address failed", err); -#else - PHY_CHECK(esp_eth_detect_phy_addr(eth, &jl1101->addr) == ESP_OK, "Detect PHY address failed", err); -#endif } /* Power on Ethernet PHY */ PHY_CHECK(jl1101_pwrctl(phy, true) == ESP_OK, "power control failed", err); @@ -336,11 +324,7 @@ esp_eth_phy_t *esp_eth_phy_new_jl1101(const eth_phy_config_t *config) { jl1101->parent.init = jl1101_init; jl1101->parent.deinit = jl1101_deinit; jl1101->parent.set_mediator = jl1101_set_mediator; -#if ESP_IDF_VERSION_MAJOR >= 5 jl1101->parent.autonego_ctrl = jl1101_negotiate; -#else - jl1101->parent.negotiate = jl1101_negotiate; -#endif jl1101->parent.get_link = jl1101_get_link; jl1101->parent.pwrctl = jl1101_pwrctl; jl1101->parent.get_addr = jl1101_get_addr; diff --git a/esphome/components/ethernet/ethernet_component.cpp b/esphome/components/ethernet/ethernet_component.cpp index 8739269f4a..f8c2f3a72e 100644 --- a/esphome/components/ethernet/ethernet_component.cpp +++ b/esphome/components/ethernet/ethernet_component.cpp @@ -17,6 +17,22 @@ namespace esphome { namespace ethernet { +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 4, 2) +// work around IDF compile issue on P4 https://github.com/espressif/esp-idf/pull/15637 +#ifdef USE_ESP32_VARIANT_ESP32P4 +#undef ETH_ESP32_EMAC_DEFAULT_CONFIG +#define ETH_ESP32_EMAC_DEFAULT_CONFIG() \ + { \ + .smi_gpio = {.mdc_num = 31, .mdio_num = 52}, .interface = EMAC_DATA_INTERFACE_RMII, \ + .clock_config = {.rmii = {.clock_mode = EMAC_CLK_EXT_IN, .clock_gpio = (emac_rmii_clock_gpio_t) 50}}, \ + .dma_burst_len = ETH_DMA_BURST_LEN_32, .intr_priority = 0, \ + .emac_dataif_gpio = \ + {.rmii = {.tx_en_num = 49, .txd0_num = 34, .txd1_num = 35, .crs_dv_num = 28, .rxd0_num = 29, .rxd1_num = 30}}, \ + .clock_config_out_in = {.rmii = {.clock_mode = EMAC_CLK_EXT_IN, .clock_gpio = (emac_rmii_clock_gpio_t) -1}}, \ + } +#endif +#endif + static const char *const TAG = "ethernet"; EthernetComponent *global_eth_component; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) @@ -106,25 +122,12 @@ void EthernetComponent::setup() { .post_cb = nullptr, }; -#if ESP_IDF_VERSION_MAJOR >= 5 #if CONFIG_ETH_SPI_ETHERNET_W5500 eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(host, &devcfg); #endif #if CONFIG_ETH_SPI_ETHERNET_DM9051 eth_dm9051_config_t dm9051_config = ETH_DM9051_DEFAULT_CONFIG(host, &devcfg); #endif -#else - spi_device_handle_t spi_handle = nullptr; - err = spi_bus_add_device(host, &devcfg, &spi_handle); - ESPHL_ERROR_CHECK(err, "SPI bus add device error"); - -#if CONFIG_ETH_SPI_ETHERNET_W5500 - eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(spi_handle); -#endif -#if CONFIG_ETH_SPI_ETHERNET_DM9051 - eth_dm9051_config_t dm9051_config = ETH_DM9051_DEFAULT_CONFIG(spi_handle); -#endif -#endif // ESP_IDF_VERSION_MAJOR >= 5 #if CONFIG_ETH_SPI_ETHERNET_W5500 w5500_config.int_gpio_num = this->interrupt_pin_; @@ -150,22 +153,18 @@ void EthernetComponent::setup() { phy_config.phy_addr = this->phy_addr_; phy_config.reset_gpio_num = this->power_pin_; -#if ESP_IDF_VERSION_MAJOR >= 5 eth_esp32_emac_config_t esp32_emac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG(); +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0) + esp32_emac_config.smi_gpio.mdc_num = this->mdc_pin_; + esp32_emac_config.smi_gpio.mdio_num = this->mdio_pin_; +#else esp32_emac_config.smi_mdc_gpio_num = this->mdc_pin_; esp32_emac_config.smi_mdio_gpio_num = this->mdio_pin_; +#endif esp32_emac_config.clock_config.rmii.clock_mode = this->clk_mode_; - esp32_emac_config.clock_config.rmii.clock_gpio = this->clk_gpio_; + esp32_emac_config.clock_config.rmii.clock_gpio = (emac_rmii_clock_gpio_t) this->clk_pin_; esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config); -#else - mac_config.smi_mdc_gpio_num = this->mdc_pin_; - mac_config.smi_mdio_gpio_num = this->mdio_pin_; - mac_config.clock_config.rmii.clock_mode = this->clk_mode_; - mac_config.clock_config.rmii.clock_gpio = this->clk_gpio_; - - esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config); -#endif #endif switch (this->type_) { @@ -199,11 +198,7 @@ void EthernetComponent::setup() { } case ETHERNET_TYPE_KSZ8081: case ETHERNET_TYPE_KSZ8081RNA: { -#if ESP_IDF_VERSION_MAJOR >= 5 this->phy_ = esp_eth_phy_new_ksz80xx(&phy_config); -#else - this->phy_ = esp_eth_phy_new_ksz8081(&phy_config); -#endif break; } #endif @@ -387,10 +382,11 @@ void EthernetComponent::dump_config() { ESP_LOGCONFIG(TAG, " Power Pin: %u", this->power_pin_); } ESP_LOGCONFIG(TAG, + " CLK Pin: %u\n" " MDC Pin: %u\n" " MDIO Pin: %u\n" " PHY addr: %u", - this->mdc_pin_, this->mdio_pin_, this->phy_addr_); + this->clk_pin_, this->mdc_pin_, this->mdio_pin_, this->phy_addr_); #endif ESP_LOGCONFIG(TAG, " Type: %s", eth_type); } @@ -611,10 +607,8 @@ void EthernetComponent::set_phy_addr(uint8_t phy_addr) { this->phy_addr_ = phy_a void EthernetComponent::set_power_pin(int power_pin) { this->power_pin_ = power_pin; } void EthernetComponent::set_mdc_pin(uint8_t mdc_pin) { this->mdc_pin_ = mdc_pin; } void EthernetComponent::set_mdio_pin(uint8_t mdio_pin) { this->mdio_pin_ = mdio_pin; } -void EthernetComponent::set_clk_mode(emac_rmii_clock_mode_t clk_mode, emac_rmii_clock_gpio_t clk_gpio) { - this->clk_mode_ = clk_mode; - this->clk_gpio_ = clk_gpio; -} +void EthernetComponent::set_clk_pin(uint8_t clk_pin) { this->clk_pin_ = clk_pin; } +void EthernetComponent::set_clk_mode(emac_rmii_clock_mode_t clk_mode) { this->clk_mode_ = clk_mode; } void EthernetComponent::add_phy_register(PHYRegister register_value) { this->phy_registers_.push_back(register_value); } #endif void EthernetComponent::set_type(EthernetType type) { this->type_ = type; } diff --git a/esphome/components/ethernet/ethernet_component.h b/esphome/components/ethernet/ethernet_component.h index 6cdc113aa8..1b347946f5 100644 --- a/esphome/components/ethernet/ethernet_component.h +++ b/esphome/components/ethernet/ethernet_component.h @@ -76,7 +76,8 @@ class EthernetComponent : public Component { void set_power_pin(int power_pin); void set_mdc_pin(uint8_t mdc_pin); void set_mdio_pin(uint8_t mdio_pin); - void set_clk_mode(emac_rmii_clock_mode_t clk_mode, emac_rmii_clock_gpio_t clk_gpio); + void set_clk_pin(uint8_t clk_pin); + void set_clk_mode(emac_rmii_clock_mode_t clk_mode); void add_phy_register(PHYRegister register_value); #endif void set_type(EthernetType type); @@ -123,10 +124,10 @@ class EthernetComponent : public Component { // Group all 32-bit members first int power_pin_{-1}; emac_rmii_clock_mode_t clk_mode_{EMAC_CLK_EXT_IN}; - emac_rmii_clock_gpio_t clk_gpio_{EMAC_CLK_IN_GPIO}; std::vector phy_registers_{}; // Group all 8-bit members together + uint8_t clk_pin_{0}; uint8_t phy_addr_{0}; uint8_t mdc_pin_{23}; uint8_t mdio_pin_{18}; diff --git a/esphome/components/heatpumpir/climate.py b/esphome/components/heatpumpir/climate.py index 9e5a2bf45c..0f9f146ae9 100644 --- a/esphome/components/heatpumpir/climate.py +++ b/esphome/components/heatpumpir/climate.py @@ -70,6 +70,7 @@ PROTOCOLS = { "airway": Protocol.PROTOCOL_AIRWAY, "bgh_aud": Protocol.PROTOCOL_BGH_AUD, "panasonic_altdke": Protocol.PROTOCOL_PANASONIC_ALTDKE, + "philco_phs32": Protocol.PROTOCOL_PHILCO_PHS32, "vaillantvai8": Protocol.PROTOCOL_VAILLANTVAI8, "r51m": Protocol.PROTOCOL_R51M, } diff --git a/esphome/components/heatpumpir/heatpumpir.cpp b/esphome/components/heatpumpir/heatpumpir.cpp index d3476c6a71..f4d2ca6c1d 100644 --- a/esphome/components/heatpumpir/heatpumpir.cpp +++ b/esphome/components/heatpumpir/heatpumpir.cpp @@ -65,6 +65,7 @@ const std::map> PROTOCOL_CONSTRUCTOR_MAP {PROTOCOL_AIRWAY, []() { return new AIRWAYHeatpumpIR(); }}, // NOLINT {PROTOCOL_BGH_AUD, []() { return new BGHHeatpumpIR(); }}, // NOLINT {PROTOCOL_PANASONIC_ALTDKE, []() { return new PanasonicAltDKEHeatpumpIR(); }}, // NOLINT + {PROTOCOL_PHILCO_PHS32, []() { return new PhilcoPHS32HeatpumpIR(); }}, // NOLINT {PROTOCOL_VAILLANTVAI8, []() { return new VaillantHeatpumpIR(); }}, // NOLINT {PROTOCOL_R51M, []() { return new R51MHeatpumpIR(); }}, // NOLINT }; diff --git a/esphome/components/heatpumpir/heatpumpir.h b/esphome/components/heatpumpir/heatpumpir.h index b740d27af7..3e14c11861 100644 --- a/esphome/components/heatpumpir/heatpumpir.h +++ b/esphome/components/heatpumpir/heatpumpir.h @@ -65,6 +65,7 @@ enum Protocol { PROTOCOL_AIRWAY, PROTOCOL_BGH_AUD, PROTOCOL_PANASONIC_ALTDKE, + PROTOCOL_PHILCO_PHS32, PROTOCOL_VAILLANTVAI8, PROTOCOL_R51M, }; diff --git a/esphome/components/host/__init__.py b/esphome/components/host/__init__.py index da75873eaf..d3dbcba6ed 100644 --- a/esphome/components/host/__init__.py +++ b/esphome/components/host/__init__.py @@ -44,3 +44,4 @@ async def to_code(config): cg.add_build_flag("-std=gnu++20") cg.add_define("ESPHOME_BOARD", "host") cg.add_platformio_option("platform", "platformio/native") + cg.add_platformio_option("lib_ldf_mode", "off") diff --git a/esphome/components/http_request/http_request_arduino.cpp b/esphome/components/http_request/http_request_arduino.cpp index b4378cdce6..c009b33c2d 100644 --- a/esphome/components/http_request/http_request_arduino.cpp +++ b/esphome/components/http_request/http_request_arduino.cpp @@ -133,7 +133,6 @@ std::shared_ptr HttpRequestArduino::perform(std::string url, std: std::string header_value = container->client_.header(i).c_str(); ESP_LOGD(TAG, "Received response header, name: %s, value: %s", header_name.c_str(), header_value.c_str()); container->response_headers_[header_name].push_back(header_value); - break; } } diff --git a/esphome/components/http_request/http_request_idf.cpp b/esphome/components/http_request/http_request_idf.cpp index 6a779ba03a..68c06d28f2 100644 --- a/esphome/components/http_request/http_request_idf.cpp +++ b/esphome/components/http_request/http_request_idf.cpp @@ -42,7 +42,6 @@ esp_err_t HttpRequestIDF::http_event_handler(esp_http_client_event_t *evt) { const std::string header_value = evt->header_value; ESP_LOGD(TAG, "Received response header, name: %s, value: %s", header_name.c_str(), header_value.c_str()); user_data->response_headers[header_name].push_back(header_value); - break; } break; } diff --git a/esphome/components/http_request/update/http_request_update.cpp b/esphome/components/http_request/update/http_request_update.cpp index 828fb5bd8b..6bc88ae49a 100644 --- a/esphome/components/http_request/update/http_request_update.cpp +++ b/esphome/components/http_request/update/http_request_update.cpp @@ -57,7 +57,7 @@ void HttpRequestUpdate::update_task(void *params) { RAMAllocator allocator; uint8_t *data = allocator.allocate(container->content_length); if (data == nullptr) { - std::string msg = str_sprintf("Failed to allocate %d bytes for manifest", container->content_length); + std::string msg = str_sprintf("Failed to allocate %zu bytes for manifest", container->content_length); this_update->status_set_error(msg.c_str()); container->end(); UPDATE_RETURN; diff --git a/esphome/components/i2c/__init__.py b/esphome/components/i2c/__init__.py index fae1fa1d22..6adb9b71aa 100644 --- a/esphome/components/i2c/__init__.py +++ b/esphome/components/i2c/__init__.py @@ -9,8 +9,6 @@ from esphome.const import ( CONF_FREQUENCY, CONF_I2C_ID, CONF_ID, - CONF_INPUT, - CONF_OUTPUT, CONF_SCAN, CONF_SCL, CONF_SDA, @@ -73,20 +71,15 @@ def validate_config(config): return config -pin_with_input_and_output_support = pins.internal_gpio_pin_number( - {CONF_OUTPUT: True, CONF_INPUT: True} -) - - CONFIG_SCHEMA = cv.All( cv.Schema( { cv.GenerateID(): _bus_declare_type, - cv.Optional(CONF_SDA, default="SDA"): pin_with_input_and_output_support, + cv.Optional(CONF_SDA, default="SDA"): pins.internal_gpio_pin_number, cv.SplitDefault(CONF_SDA_PULLUP_ENABLED, esp32_idf=True): cv.All( cv.only_with_esp_idf, cv.boolean ), - cv.Optional(CONF_SCL, default="SCL"): pin_with_input_and_output_support, + cv.Optional(CONF_SCL, default="SCL"): pins.internal_gpio_pin_number, cv.SplitDefault(CONF_SCL_PULLUP_ENABLED, esp32_idf=True): cv.All( cv.only_with_esp_idf, cv.boolean ), diff --git a/esphome/components/i2s_audio/__init__.py b/esphome/components/i2s_audio/__init__.py index ef95fd0b41..9a2aa0362f 100644 --- a/esphome/components/i2s_audio/__init__.py +++ b/esphome/components/i2s_audio/__init__.py @@ -9,14 +9,7 @@ from esphome.components.esp32.const import ( VARIANT_ESP32S3, ) import esphome.config_validation as cv -from esphome.const import ( - CONF_BITS_PER_SAMPLE, - CONF_CHANNEL, - CONF_ID, - CONF_SAMPLE_RATE, - KEY_CORE, - KEY_FRAMEWORK_VERSION, -) +from esphome.const import CONF_BITS_PER_SAMPLE, CONF_CHANNEL, CONF_ID, CONF_SAMPLE_RATE from esphome.core import CORE from esphome.cpp_generator import MockObjClass import esphome.final_validate as fv @@ -250,8 +243,7 @@ def _final_validate(_): def use_legacy(): - framework_version = CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION] - if CORE.using_esp_idf and framework_version >= cv.Version(5, 0, 0): + if CORE.using_esp_idf: if not _use_legacy_driver: return False return True diff --git a/esphome/components/i2s_audio/i2s_audio.cpp b/esphome/components/i2s_audio/i2s_audio.cpp index 7ff21bba57..7f233516e6 100644 --- a/esphome/components/i2s_audio/i2s_audio.cpp +++ b/esphome/components/i2s_audio/i2s_audio.cpp @@ -9,15 +9,11 @@ namespace i2s_audio { static const char *const TAG = "i2s_audio"; -#if ESP_IDF_VERSION_MAJOR >= 5 -static const uint8_t I2S_NUM_MAX = SOC_I2S_NUM; // because IDF 5+ took this away :( -#endif - void I2SAudioComponent::setup() { ESP_LOGCONFIG(TAG, "Running setup"); static i2s_port_t next_port_num = I2S_NUM_0; - if (next_port_num >= I2S_NUM_MAX) { + if (next_port_num >= SOC_I2S_NUM) { ESP_LOGE(TAG, "Too many components"); this->mark_failed(); return; diff --git a/esphome/components/improv_serial/improv_serial_component.cpp b/esphome/components/improv_serial/improv_serial_component.cpp index c3a0f2eacc..ae4927828b 100644 --- a/esphome/components/improv_serial/improv_serial_component.cpp +++ b/esphome/components/improv_serial/improv_serial_component.cpp @@ -59,11 +59,7 @@ optional ImprovSerialComponent::read_byte_() { break; #if defined(USE_LOGGER_USB_CDC) && defined(CONFIG_ESP_CONSOLE_USB_CDC) case logger::UART_SELECTION_USB_CDC: -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) if (esp_usb_console_available_for_read()) { -#else - if (esp_usb_console_read_available()) { -#endif esp_usb_console_read_buf((char *) &data, 1); byte = data; } diff --git a/esphome/components/internal_temperature/internal_temperature.cpp b/esphome/components/internal_temperature/internal_temperature.cpp index f503927d8e..85844647f2 100644 --- a/esphome/components/internal_temperature/internal_temperature.cpp +++ b/esphome/components/internal_temperature/internal_temperature.cpp @@ -10,11 +10,7 @@ uint8_t temprature_sens_read(); #elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || \ defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32H2) || \ defined(USE_ESP32_VARIANT_ESP32C2) || defined(USE_ESP32_VARIANT_ESP32P4) -#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) -#include "driver/temp_sensor.h" -#else #include "driver/temperature_sensor.h" -#endif // ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) #endif // USE_ESP32_VARIANT #endif // USE_ESP32 #ifdef USE_RP2040 @@ -31,12 +27,11 @@ namespace internal_temperature { static const char *const TAG = "internal_temperature"; #ifdef USE_ESP32 -#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)) && \ - (defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S2) || \ - defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32H2) || defined(USE_ESP32_VARIANT_ESP32C2) || \ - defined(USE_ESP32_VARIANT_ESP32P4)) +#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S2) || \ + defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32H2) || defined(USE_ESP32_VARIANT_ESP32C2) || \ + defined(USE_ESP32_VARIANT_ESP32P4) static temperature_sensor_handle_t tsensNew = NULL; -#endif // ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) && USE_ESP32_VARIANT +#endif // USE_ESP32_VARIANT #endif // USE_ESP32 void InternalTemperatureSensor::update() { @@ -51,24 +46,11 @@ void InternalTemperatureSensor::update() { #elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || \ defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32H2) || \ defined(USE_ESP32_VARIANT_ESP32C2) || defined(USE_ESP32_VARIANT_ESP32P4) -#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) - temp_sensor_config_t tsens = TSENS_CONFIG_DEFAULT(); - temp_sensor_set_config(tsens); - temp_sensor_start(); -#if defined(USE_ESP32_VARIANT_ESP32S3) && (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 4, 3)) -#error \ - "ESP32-S3 internal temperature sensor requires ESP IDF V4.4.3 or higher. See https://github.com/esphome/issues/issues/4271" -#endif - esp_err_t result = temp_sensor_read_celsius(&temperature); - temp_sensor_stop(); - success = (result == ESP_OK); -#else esp_err_t result = temperature_sensor_get_celsius(tsensNew, &temperature); success = (result == ESP_OK); if (!success) { ESP_LOGE(TAG, "Reading failed (%d)", result); } -#endif // ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) #endif // USE_ESP32_VARIANT #endif // USE_ESP32 #ifdef USE_RP2040 @@ -99,10 +81,9 @@ void InternalTemperatureSensor::update() { void InternalTemperatureSensor::setup() { #ifdef USE_ESP32 -#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)) && \ - (defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S2) || \ - defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32H2) || defined(USE_ESP32_VARIANT_ESP32C2) || \ - defined(USE_ESP32_VARIANT_ESP32P4)) +#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S2) || \ + defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32H2) || defined(USE_ESP32_VARIANT_ESP32C2) || \ + defined(USE_ESP32_VARIANT_ESP32P4) ESP_LOGCONFIG(TAG, "Running setup"); temperature_sensor_config_t tsens_config = TEMPERATURE_SENSOR_CONFIG_DEFAULT(-10, 80); @@ -120,7 +101,7 @@ void InternalTemperatureSensor::setup() { this->mark_failed(); return; } -#endif // ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) && USE_ESP32_VARIANT +#endif // USE_ESP32_VARIANT #endif // USE_ESP32 } diff --git a/esphome/components/internal_temperature/sensor.py b/esphome/components/internal_temperature/sensor.py index 9bfa3739c8..93b98a30f4 100644 --- a/esphome/components/internal_temperature/sensor.py +++ b/esphome/components/internal_temperature/sensor.py @@ -1,46 +1,21 @@ import esphome.codegen as cg from esphome.components import sensor -from esphome.components.esp32 import get_esp32_variant -from esphome.components.esp32.const import VARIANT_ESP32S3 import esphome.config_validation as cv from esphome.const import ( DEVICE_CLASS_TEMPERATURE, ENTITY_CATEGORY_DIAGNOSTIC, - KEY_CORE, - KEY_FRAMEWORK_VERSION, PLATFORM_BK72XX, PLATFORM_ESP32, PLATFORM_RP2040, STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, ) -from esphome.core import CORE internal_temperature_ns = cg.esphome_ns.namespace("internal_temperature") InternalTemperatureSensor = internal_temperature_ns.class_( "InternalTemperatureSensor", sensor.Sensor, cg.PollingComponent ) - -def validate_config(config): - if CORE.is_esp32: - variant = get_esp32_variant() - if variant == VARIANT_ESP32S3: - if CORE.using_arduino and CORE.data[KEY_CORE][ - KEY_FRAMEWORK_VERSION - ] < cv.Version(2, 0, 6): - raise cv.Invalid( - "ESP32-S3 Internal Temperature Sensor requires framework version 2.0.6 or higher. See ." - ) - if CORE.using_esp_idf and CORE.data[KEY_CORE][ - KEY_FRAMEWORK_VERSION - ] < cv.Version(4, 4, 3): - raise cv.Invalid( - "ESP32-S3 Internal Temperature Sensor requires framework version 4.4.3 or higher. See ." - ) - return config - - CONFIG_SCHEMA = cv.All( sensor.sensor_schema( InternalTemperatureSensor, @@ -51,7 +26,6 @@ CONFIG_SCHEMA = cv.All( entity_category=ENTITY_CATEGORY_DIAGNOSTIC, ).extend(cv.polling_component_schema("60s")), cv.only_on([PLATFORM_ESP32, PLATFORM_RP2040, PLATFORM_BK72XX]), - validate_config, ) diff --git a/esphome/components/logger/logger_esp32.cpp b/esphome/components/logger/logger_esp32.cpp index b5ac84a665..41445fa3b4 100644 --- a/esphome/components/logger/logger_esp32.cpp +++ b/esphome/components/logger/logger_esp32.cpp @@ -83,9 +83,7 @@ void init_uart(uart_port_t uart_num, uint32_t baud_rate, int tx_buffer_size) { uart_config.parity = UART_PARITY_DISABLE; uart_config.stop_bits = UART_STOP_BITS_1; uart_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE; -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) uart_config.source_clk = UART_SCLK_DEFAULT; -#endif uart_param_config(uart_num, &uart_config); const int uart_buffer_size = tx_buffer_size; // Install UART driver using an event queue here diff --git a/esphome/components/mdns/__init__.py b/esphome/components/mdns/__init__.py index 2f81068e8a..ed230d43aa 100644 --- a/esphome/components/mdns/__init__.py +++ b/esphome/components/mdns/__init__.py @@ -8,8 +8,6 @@ from esphome.const import ( CONF_PROTOCOL, CONF_SERVICE, CONF_SERVICES, - KEY_CORE, - KEY_FRAMEWORK_VERSION, ) from esphome.core import CORE, coroutine_with_priority @@ -85,9 +83,7 @@ async def to_code(config): elif CORE.is_rp2040: cg.add_library("LEAmDNS", None) - if CORE.using_esp_idf and CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION] >= cv.Version( - 5, 0, 0 - ): + if CORE.using_esp_idf: add_idf_component(name="espressif/mdns", ref="1.8.2") cg.add_define("USE_MDNS") diff --git a/esphome/components/mmc5603/mmc5603.cpp b/esphome/components/mmc5603/mmc5603.cpp index 86b1b23c15..7f78f9592a 100644 --- a/esphome/components/mmc5603/mmc5603.cpp +++ b/esphome/components/mmc5603/mmc5603.cpp @@ -39,7 +39,7 @@ void MMC5603Component::setup() { return; } - if (id != MMC56X3_CHIP_ID) { + if (id != 0 && id != MMC56X3_CHIP_ID) { // ID is not reported correctly by all chips, 0 on some chips ESP_LOGCONFIG(TAG, "Chip Wrong"); this->error_code_ = ID_REGISTERS; this->mark_failed(); diff --git a/esphome/components/modbus/modbus.cpp b/esphome/components/modbus/modbus.cpp index c2efa93fae..6350f43ef6 100644 --- a/esphome/components/modbus/modbus.cpp +++ b/esphome/components/modbus/modbus.cpp @@ -90,15 +90,24 @@ bool Modbus::parse_modbus_byte_(uint8_t byte) { } else { // data starts at 2 and length is 4 for read registers commands - if (this->role == ModbusRole::SERVER && (function_code == 0x1 || function_code == 0x3 || function_code == 0x4)) { - data_offset = 2; - data_len = 4; - } - - // the response for write command mirrors the requests and data starts at offset 2 instead of 3 for read commands - if (function_code == 0x5 || function_code == 0x06 || function_code == 0xF || function_code == 0x10) { - data_offset = 2; - data_len = 4; + if (this->role == ModbusRole::SERVER) { + if (function_code == 0x1 || function_code == 0x3 || function_code == 0x4 || function_code == 0x6) { + data_offset = 2; + data_len = 4; + } else if (function_code == 0x10) { + if (at < 6) { + return true; + } + data_offset = 2; + // starting address (2 bytes) + quantity of registers (2 bytes) + byte count itself (1 byte) + actual byte count + data_len = 2 + 2 + 1 + raw[6]; + } + } else { + // the response for write command mirrors the requests and data starts at offset 2 instead of 3 for read commands + if (function_code == 0x5 || function_code == 0x06 || function_code == 0xF || function_code == 0x10) { + data_offset = 2; + data_len = 4; + } } // Error ( msb indicates error ) @@ -132,6 +141,7 @@ bool Modbus::parse_modbus_byte_(uint8_t byte) { bool found = false; for (auto *device : this->devices_) { if (device->address_ == address) { + found = true; // Is it an error response? if ((function_code & 0x80) == 0x80) { ESP_LOGD(TAG, "Modbus error function code: 0x%X exception: %d", function_code, raw[2]); @@ -141,13 +151,21 @@ bool Modbus::parse_modbus_byte_(uint8_t byte) { // Ignore modbus exception not related to a pending command ESP_LOGD(TAG, "Ignoring Modbus error - not expecting a response"); } - } else if (this->role == ModbusRole::SERVER && (function_code == 0x3 || function_code == 0x4)) { - device->on_modbus_read_registers(function_code, uint16_t(data[1]) | (uint16_t(data[0]) << 8), - uint16_t(data[3]) | (uint16_t(data[2]) << 8)); - } else { - device->on_modbus_data(data); + continue; } - found = true; + if (this->role == ModbusRole::SERVER) { + if (function_code == 0x3 || function_code == 0x4) { + device->on_modbus_read_registers(function_code, uint16_t(data[1]) | (uint16_t(data[0]) << 8), + uint16_t(data[3]) | (uint16_t(data[2]) << 8)); + continue; + } + if (function_code == 0x6 || function_code == 0x10) { + device->on_modbus_write_registers(function_code, data); + continue; + } + } + // fallthrough for other function codes + device->on_modbus_data(data); } } waiting_for_response = 0; diff --git a/esphome/components/modbus/modbus.h b/esphome/components/modbus/modbus.h index aebdbccc78..ec35612690 100644 --- a/esphome/components/modbus/modbus.h +++ b/esphome/components/modbus/modbus.h @@ -59,6 +59,7 @@ class ModbusDevice { virtual void on_modbus_data(const std::vector &data) = 0; virtual void on_modbus_error(uint8_t function_code, uint8_t exception_code) {} virtual void on_modbus_read_registers(uint8_t function_code, uint16_t start_address, uint16_t number_of_registers){}; + virtual void on_modbus_write_registers(uint8_t function_code, const std::vector &data){}; void send(uint8_t function, uint16_t start_address, uint16_t number_of_entities, uint8_t payload_len = 0, const uint8_t *payload = nullptr) { this->parent_->send(this->address_, function, start_address, number_of_entities, payload_len, payload); diff --git a/esphome/components/modbus_controller/__init__.py b/esphome/components/modbus_controller/__init__.py index 8079b824b0..5ab82f5e17 100644 --- a/esphome/components/modbus_controller/__init__.py +++ b/esphome/components/modbus_controller/__init__.py @@ -39,6 +39,7 @@ CODEOWNERS = ["@martgras"] AUTO_LOAD = ["modbus"] CONF_READ_LAMBDA = "read_lambda" +CONF_WRITE_LAMBDA = "write_lambda" CONF_SERVER_REGISTERS = "server_registers" MULTI_CONF = True @@ -148,6 +149,7 @@ ModbusServerRegisterSchema = cv.Schema( cv.Required(CONF_ADDRESS): cv.positive_int, cv.Optional(CONF_VALUE_TYPE, default="U_WORD"): cv.enum(SENSOR_VALUE_TYPE), cv.Required(CONF_READ_LAMBDA): cv.returning_lambda, + cv.Optional(CONF_WRITE_LAMBDA): cv.returning_lambda, } ) @@ -318,6 +320,17 @@ async def to_code(config): ), ) ) + if CONF_WRITE_LAMBDA in server_register: + cg.add( + server_register_var.set_write_lambda( + cg.TemplateArguments(cpp_type), + await cg.process_lambda( + server_register[CONF_WRITE_LAMBDA], + parameters=[(cg.uint16, "address"), (cpp_type, "x")], + return_type=cg.bool_, + ), + ) + ) cg.add(var.add_server_register(server_register_var)) await register_modbus_device(var, config) for conf in config.get(CONF_ON_COMMAND_SENT, []): diff --git a/esphome/components/modbus_controller/modbus_controller.cpp b/esphome/components/modbus_controller/modbus_controller.cpp index 81e9ccf0a6..0f3ddf920d 100644 --- a/esphome/components/modbus_controller/modbus_controller.cpp +++ b/esphome/components/modbus_controller/modbus_controller.cpp @@ -152,6 +152,86 @@ void ModbusController::on_modbus_read_registers(uint8_t function_code, uint16_t this->send(function_code, start_address, number_of_registers, response.size(), response.data()); } +void ModbusController::on_modbus_write_registers(uint8_t function_code, const std::vector &data) { + uint16_t number_of_registers; + uint16_t payload_offset; + + if (function_code == 0x10) { + number_of_registers = uint16_t(data[3]) | (uint16_t(data[2]) << 8); + if (number_of_registers == 0 || number_of_registers > 0x7B) { + ESP_LOGW(TAG, "Invalid number of registers %d. Sending exception response.", number_of_registers); + send_error(function_code, 3); + return; + } + uint16_t payload_size = data[4]; + if (payload_size != number_of_registers * 2) { + ESP_LOGW(TAG, "Payload size of %d bytes is not 2 times the number of registers (%d). Sending exception response.", + payload_size, number_of_registers); + send_error(function_code, 3); + return; + } + payload_offset = 5; + } else if (function_code == 0x06) { + number_of_registers = 1; + payload_offset = 2; + } else { + ESP_LOGW(TAG, "Invalid function code 0x%X. Sending exception response.", function_code); + send_error(function_code, 1); + return; + } + + uint16_t start_address = uint16_t(data[1]) | (uint16_t(data[0]) << 8); + ESP_LOGD(TAG, + "Received write holding registers for device 0x%X. FC: 0x%X. Start address: 0x%X. Number of registers: " + "0x%X.", + this->address_, function_code, start_address, number_of_registers); + + auto for_each_register = [this, start_address, number_of_registers, payload_offset]( + const std::function &callback) -> bool { + uint16_t offset = payload_offset; + for (uint16_t current_address = start_address; current_address < start_address + number_of_registers;) { + bool ok = false; + for (auto *server_register : this->server_registers_) { + if (server_register->address == current_address) { + ok = callback(server_register, offset); + current_address += server_register->register_count; + offset += server_register->register_count * sizeof(uint16_t); + break; + } + } + + if (!ok) { + return false; + } + } + return true; + }; + + // check all registers are writable before writing to any of them: + if (!for_each_register([](ServerRegister *server_register, uint16_t offset) -> bool { + return server_register->write_lambda != nullptr; + })) { + send_error(function_code, 1); + return; + } + + // Actually write to the registers: + if (!for_each_register([&data](ServerRegister *server_register, uint16_t offset) { + int64_t number = payload_to_number(data, server_register->value_type, offset, 0xFFFFFFFF); + return server_register->write_lambda(number); + })) { + send_error(function_code, 4); + return; + } + + std::vector response; + response.reserve(6); + response.push_back(this->address_); + response.push_back(function_code); + response.insert(response.end(), data.begin(), data.begin() + 4); + this->send_raw(response); +} + SensorSet ModbusController::find_sensors_(ModbusRegisterType register_type, uint16_t start_address) const { auto reg_it = std::find_if( std::begin(this->register_ranges_), std::end(this->register_ranges_), diff --git a/esphome/components/modbus_controller/modbus_controller.h b/esphome/components/modbus_controller/modbus_controller.h index 11d27c4025..a86ad1ccb5 100644 --- a/esphome/components/modbus_controller/modbus_controller.h +++ b/esphome/components/modbus_controller/modbus_controller.h @@ -258,6 +258,7 @@ class SensorItem { class ServerRegister { using ReadLambda = std::function; + using WriteLambda = std::function; public: ServerRegister(uint16_t address, SensorValueType value_type, uint8_t register_count) { @@ -277,6 +278,17 @@ class ServerRegister { }; } + template + void set_write_lambda(const std::function &&user_write_lambda) { + this->write_lambda = [this, user_write_lambda](int64_t number) { + if constexpr (std::is_same_v) { + float float_value = bit_cast(static_cast(number)); + return user_write_lambda(this->address, float_value); + } + return user_write_lambda(this->address, static_cast(number)); + }; + } + // Formats a raw value into a string representation based on the value type for debugging std::string format_value(int64_t value) const { switch (this->value_type) { @@ -304,6 +316,7 @@ class ServerRegister { SensorValueType value_type{SensorValueType::RAW}; uint8_t register_count{0}; ReadLambda read_lambda; + WriteLambda write_lambda; }; // ModbusController::create_register_ranges_ tries to optimize register range @@ -485,6 +498,8 @@ class ModbusController : public PollingComponent, public modbus::ModbusDevice { void on_modbus_error(uint8_t function_code, uint8_t exception_code) override; /// called when a modbus request (function code 0x03 or 0x04) was parsed without errors void on_modbus_read_registers(uint8_t function_code, uint16_t start_address, uint16_t number_of_registers) final; + /// called when a modbus request (function code 0x06 or 0x10) was parsed without errors + void on_modbus_write_registers(uint8_t function_code, const std::vector &data) final; /// default delegate called by process_modbus_data when a response has retrieved from the incoming queue void on_register_data(ModbusRegisterType register_type, uint16_t start_address, const std::vector &data); /// default delegate called by process_modbus_data when a response for a write response has retrieved from the diff --git a/esphome/components/mqtt/mqtt_backend_esp32.cpp b/esphome/components/mqtt/mqtt_backend_esp32.cpp index 62b153e676..a096408aa5 100644 --- a/esphome/components/mqtt/mqtt_backend_esp32.cpp +++ b/esphome/components/mqtt/mqtt_backend_esp32.cpp @@ -14,49 +14,6 @@ namespace mqtt { static const char *const TAG = "mqtt.idf"; bool MQTTBackendESP32::initialize_() { -#if ESP_IDF_VERSION_MAJOR < 5 - mqtt_cfg_.user_context = (void *) this; - mqtt_cfg_.buffer_size = MQTT_BUFFER_SIZE; - - mqtt_cfg_.host = this->host_.c_str(); - mqtt_cfg_.port = this->port_; - mqtt_cfg_.keepalive = this->keep_alive_; - mqtt_cfg_.disable_clean_session = !this->clean_session_; - - if (!this->username_.empty()) { - mqtt_cfg_.username = this->username_.c_str(); - if (!this->password_.empty()) { - mqtt_cfg_.password = this->password_.c_str(); - } - } - - if (!this->lwt_topic_.empty()) { - mqtt_cfg_.lwt_topic = this->lwt_topic_.c_str(); - this->mqtt_cfg_.lwt_qos = this->lwt_qos_; - this->mqtt_cfg_.lwt_retain = this->lwt_retain_; - - if (!this->lwt_message_.empty()) { - mqtt_cfg_.lwt_msg = this->lwt_message_.c_str(); - mqtt_cfg_.lwt_msg_len = this->lwt_message_.size(); - } - } - - if (!this->client_id_.empty()) { - mqtt_cfg_.client_id = this->client_id_.c_str(); - } - if (ca_certificate_.has_value()) { - mqtt_cfg_.cert_pem = ca_certificate_.value().c_str(); - mqtt_cfg_.skip_cert_common_name_check = skip_cert_cn_check_; - mqtt_cfg_.transport = MQTT_TRANSPORT_OVER_SSL; - - if (this->cl_certificate_.has_value() && this->cl_key_.has_value()) { - mqtt_cfg_.client_cert_pem = this->cl_certificate_.value().c_str(); - mqtt_cfg_.client_key_pem = this->cl_key_.value().c_str(); - } - } else { - mqtt_cfg_.transport = MQTT_TRANSPORT_OVER_TCP; - } -#else mqtt_cfg_.broker.address.hostname = this->host_.c_str(); mqtt_cfg_.broker.address.port = this->port_; mqtt_cfg_.session.keepalive = this->keep_alive_; @@ -95,7 +52,7 @@ bool MQTTBackendESP32::initialize_() { } else { mqtt_cfg_.broker.address.transport = MQTT_TRANSPORT_OVER_TCP; } -#endif + auto *mqtt_client = esp_mqtt_client_init(&mqtt_cfg_); if (mqtt_client) { handler_.reset(mqtt_client); @@ -163,12 +120,20 @@ void MQTTBackendESP32::mqtt_event_handler_(const Event &event) { case MQTT_EVENT_CONNECTED: ESP_LOGV(TAG, "MQTT_EVENT_CONNECTED"); this->is_connected_ = true; +#if defined(USE_MQTT_IDF_ENQUEUE) + this->last_dropped_log_time_ = 0; + xTaskNotifyGive(this->task_handle_); +#endif this->on_connect_.call(event.session_present); break; case MQTT_EVENT_DISCONNECTED: ESP_LOGV(TAG, "MQTT_EVENT_DISCONNECTED"); // TODO is there a way to get the disconnect reason? this->is_connected_ = false; +#if defined(USE_MQTT_IDF_ENQUEUE) + this->last_dropped_log_time_ = 0; + xTaskNotifyGive(this->task_handle_); +#endif this->on_disconnect_.call(MQTTClientDisconnectReason::TCP_DISCONNECTED); break; diff --git a/esphome/components/mqtt/mqtt_backend_esp32.h b/esphome/components/mqtt/mqtt_backend_esp32.h index 57286a24b2..3611caf554 100644 --- a/esphome/components/mqtt/mqtt_backend_esp32.h +++ b/esphome/components/mqtt/mqtt_backend_esp32.h @@ -116,7 +116,7 @@ struct QueueElement { class MQTTBackendESP32 final : public MQTTBackend { public: static const size_t MQTT_BUFFER_SIZE = 4096; - static const size_t TASK_STACK_SIZE = 2048; + static const size_t TASK_STACK_SIZE = 3072; static const size_t TASK_STACK_SIZE_TLS = 4096; // Larger stack for TLS operations static const ssize_t TASK_PRIORITY = 5; static const uint8_t MQTT_QUEUE_LENGTH = 30; // 30*12 bytes = 360 diff --git a/esphome/components/nextion/nextion.cpp b/esphome/components/nextion/nextion.cpp index 042a595ff8..bb75385d8c 100644 --- a/esphome/components/nextion/nextion.cpp +++ b/esphome/components/nextion/nextion.cpp @@ -164,7 +164,7 @@ void Nextion::dump_config() { #endif // USE_NEXTION_MAX_COMMANDS_PER_LOOP if (this->touch_sleep_timeout_ != 0) { - ESP_LOGCONFIG(TAG, " Touch Timeout: %" PRIu32, this->touch_sleep_timeout_); + ESP_LOGCONFIG(TAG, " Touch Timeout: %" PRIu16, this->touch_sleep_timeout_); } if (this->wake_up_page_ != -1) { @@ -302,11 +302,11 @@ void Nextion::loop() { } // Check if a startup page has been set and send the command - if (this->start_up_page_ != -1) { + if (this->start_up_page_ >= 0) { this->goto_page(this->start_up_page_); } - if (this->wake_up_page_ != -1) { + if (this->wake_up_page_ >= 0) { this->set_wake_up_page(this->wake_up_page_); } @@ -418,12 +418,12 @@ void Nextion::process_nextion_commands_() { ESP_LOGN(TAG, "Add 0xFF"); } - this->nextion_event_ = this->command_data_[0]; + const uint8_t nextion_event = this->command_data_[0]; to_process_length -= 1; to_process = this->command_data_.substr(1, to_process_length); - switch (this->nextion_event_) { + switch (nextion_event) { case 0x00: // instruction sent by user has failed ESP_LOGW(TAG, "Invalid instruction"); this->remove_from_q_(); @@ -562,9 +562,9 @@ void Nextion::process_nextion_commands_() { break; } - uint16_t x = (uint16_t(to_process[0]) << 8) | to_process[1]; - uint16_t y = (uint16_t(to_process[2]) << 8) | to_process[3]; - uint8_t touch_event = to_process[4]; // 0 -> release, 1 -> press + const uint16_t x = (uint16_t(to_process[0]) << 8) | to_process[1]; + const uint16_t y = (uint16_t(to_process[2]) << 8) | to_process[3]; + const uint8_t touch_event = to_process[4]; // 0 -> release, 1 -> press ESP_LOGD(TAG, "Touch %s at %u,%u", touch_event ? "PRESS" : "RELEASE", x, y); break; } @@ -820,15 +820,14 @@ void Nextion::process_nextion_commands_() { break; } default: - ESP_LOGW(TAG, "Unknown event: 0x%02X", this->nextion_event_); + ESP_LOGW(TAG, "Unknown event: 0x%02X", nextion_event); break; } - // ESP_LOGN(TAG, "nextion_event_ deleting from 0 to %d", to_process_length + COMMAND_DELIMITER.length() + 1); this->command_data_.erase(0, to_process_length + COMMAND_DELIMITER.length() + 1); } - uint32_t ms = App.get_loop_component_start_time(); + const uint32_t ms = App.get_loop_component_start_time(); if (!this->nextion_queue_.empty() && this->nextion_queue_.front()->queue_time + this->max_q_age_ms_ < ms) { for (size_t i = 0; i < this->nextion_queue_.size(); i++) { @@ -960,7 +959,6 @@ void Nextion::update_components_by_prefix(const std::string &prefix) { } uint16_t Nextion::recv_ret_string_(std::string &response, uint32_t timeout, bool recv_flag) { - uint16_t ret = 0; uint8_t c = 0; uint8_t nr_of_ff_bytes = 0; bool exit_flag = false; @@ -1003,8 +1001,7 @@ uint16_t Nextion::recv_ret_string_(std::string &response, uint32_t timeout, bool if (ff_flag) response = response.substr(0, response.length() - 3); // Remove last 3 0xFF - ret = response.length(); - return ret; + return response.length(); } /** diff --git a/esphome/components/nextion/nextion.h b/esphome/components/nextion/nextion.h index 0cd559d251..0b77d234f5 100644 --- a/esphome/components/nextion/nextion.h +++ b/esphome/components/nextion/nextion.h @@ -1190,11 +1190,11 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * After 30 seconds the display will go to sleep. Note: the display will only wakeup by a restart or by setting up * `thup`. */ - void set_touch_sleep_timeout(uint32_t touch_sleep_timeout); + void set_touch_sleep_timeout(uint16_t touch_sleep_timeout); /** * Sets which page Nextion loads when exiting sleep mode. Note this can be set even when Nextion is in sleep mode. - * @param wake_up_page The page id, from 0 to the lage page in Nextion. Set 255 (not set to any existing page) to + * @param wake_up_page The page id, from 0 to the last page in Nextion. Set -1 (not set to any existing page) to * wakes up to current page. * * Example: @@ -1204,11 +1204,11 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * * The display will wake up to page 2. */ - void set_wake_up_page(uint8_t wake_up_page = 255); + void set_wake_up_page(int16_t wake_up_page = -1); /** * Sets which page Nextion loads when connecting to ESPHome. - * @param start_up_page The page id, from 0 to the lage page in Nextion. Set 255 (not set to any existing page) to + * @param start_up_page The page id, from 0 to the last page in Nextion. Set -1 (not set to any existing page) to * wakes up to current page. * * Example: @@ -1218,7 +1218,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe * * The display will go to page 2 when it establishes a connection to ESPHome. */ - void set_start_up_page(uint8_t start_up_page = 255) { this->start_up_page_ = start_up_page; } + void set_start_up_page(int16_t start_up_page = -1) { this->start_up_page_ = start_up_page; } /** * Sets if Nextion should auto-wake from sleep when touch press occurs. @@ -1330,7 +1330,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe std::deque waveform_queue_; uint16_t recv_ret_string_(std::string &response, uint32_t timeout, bool recv_flag); void all_components_send_state_(bool force_update = false); - uint64_t comok_sent_ = 0; + uint32_t comok_sent_ = 0; bool remove_from_q_(bool report_empty = true); /** @@ -1340,12 +1340,10 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe bool ignore_is_setup_ = false; bool nextion_reports_is_setup_ = false; - uint8_t nextion_event_; - void process_nextion_commands_(); void process_serial_(); bool is_updating_ = false; - uint32_t touch_sleep_timeout_ = 0; + uint16_t touch_sleep_timeout_ = 0; int16_t wake_up_page_ = -1; int16_t start_up_page_ = -1; bool auto_wake_on_touch_ = true; diff --git a/esphome/components/nextion/nextion_commands.cpp b/esphome/components/nextion/nextion_commands.cpp index 0226e0a13c..84aacd1868 100644 --- a/esphome/components/nextion/nextion_commands.cpp +++ b/esphome/components/nextion/nextion_commands.cpp @@ -10,12 +10,12 @@ static const char *const TAG = "nextion"; // Sleep safe commands void Nextion::soft_reset() { this->send_command_("rest"); } -void Nextion::set_wake_up_page(uint8_t wake_up_page) { +void Nextion::set_wake_up_page(int16_t wake_up_page) { this->wake_up_page_ = wake_up_page; this->add_no_result_to_queue_with_set_internal_("wake_up_page", "wup", wake_up_page, true); } -void Nextion::set_touch_sleep_timeout(uint32_t touch_sleep_timeout) { +void Nextion::set_touch_sleep_timeout(uint16_t touch_sleep_timeout) { if (touch_sleep_timeout < 3) { ESP_LOGD(TAG, "Sleep timeout out of bounds (3-65535)"); return; diff --git a/esphome/components/opentherm/opentherm.cpp b/esphome/components/opentherm/opentherm.cpp index 49482316ee..b2751470b2 100644 --- a/esphome/components/opentherm/opentherm.cpp +++ b/esphome/components/opentherm/opentherm.cpp @@ -272,18 +272,13 @@ bool OpenTherm::init_esp32_timer_() { this->timer_idx_ = timer_idx; timer_config_t const config = { - .alarm_en = TIMER_ALARM_EN, - .counter_en = TIMER_PAUSE, - .intr_type = TIMER_INTR_LEVEL, - .counter_dir = TIMER_COUNT_UP, - .auto_reload = TIMER_AUTORELOAD_EN, -#if ESP_IDF_VERSION_MAJOR >= 5 - .clk_src = TIMER_SRC_CLK_DEFAULT, -#endif - .divider = 80, -#if defined(SOC_TIMER_GROUP_SUPPORT_XTAL) && ESP_IDF_VERSION_MAJOR < 5 - .clk_src = TIMER_SRC_CLK_APB -#endif + .alarm_en = TIMER_ALARM_EN, + .counter_en = TIMER_PAUSE, + .intr_type = TIMER_INTR_LEVEL, + .counter_dir = TIMER_COUNT_UP, + .auto_reload = TIMER_AUTORELOAD_EN, + .clk_src = TIMER_SRC_CLK_DEFAULT, + .divider = 80, }; esp_err_t result; diff --git a/esphome/components/openthread/__init__.py b/esphome/components/openthread/__init__.py index 393c47e720..25e3153d1b 100644 --- a/esphome/components/openthread/__init__.py +++ b/esphome/components/openthread/__init__.py @@ -11,6 +11,7 @@ from esphome.const import CONF_CHANNEL, CONF_ENABLE_IPV6, CONF_ID import esphome.final_validate as fv from .const import ( + CONF_DEVICE_TYPE, CONF_EXT_PAN_ID, CONF_FORCE_DATASET, CONF_MDNS_ID, @@ -22,7 +23,6 @@ from .const import ( CONF_SRP_ID, CONF_TLV, ) -from .tlv import parse_tlv CODEOWNERS = ["@mrene"] @@ -33,6 +33,11 @@ AUTO_LOAD = ["network"] CONFLICTS_WITH = ["wifi"] DEPENDENCIES = ["esp32"] +CONF_DEVICE_TYPES = [ + "FTD", + "MTD", +] + def set_sdkconfig_options(config): # and expose options for using SPI/UART RCPs @@ -43,58 +48,58 @@ def set_sdkconfig_options(config): add_idf_sdkconfig_option("CONFIG_OPENTHREAD_CLI", False) add_idf_sdkconfig_option("CONFIG_OPENTHREAD_ENABLED", True) - add_idf_sdkconfig_option("CONFIG_OPENTHREAD_NETWORK_PANID", config[CONF_PAN_ID]) - add_idf_sdkconfig_option("CONFIG_OPENTHREAD_NETWORK_CHANNEL", config[CONF_CHANNEL]) - add_idf_sdkconfig_option( - "CONFIG_OPENTHREAD_NETWORK_MASTERKEY", f"{config[CONF_NETWORK_KEY]:X}".lower() - ) - if network_name := config.get(CONF_NETWORK_NAME): - add_idf_sdkconfig_option("CONFIG_OPENTHREAD_NETWORK_NAME", network_name) + if tlv := config.get(CONF_TLV): + cg.add_define("USE_OPENTHREAD_TLVS", tlv) + else: + if pan_id := config.get(CONF_PAN_ID): + add_idf_sdkconfig_option("CONFIG_OPENTHREAD_NETWORK_PANID", pan_id) - if (ext_pan_id := config.get(CONF_EXT_PAN_ID)) is not None: - add_idf_sdkconfig_option( - "CONFIG_OPENTHREAD_NETWORK_EXTPANID", f"{ext_pan_id:X}".lower() - ) - if (mesh_local_prefix := config.get(CONF_MESH_LOCAL_PREFIX)) is not None: - add_idf_sdkconfig_option( - "CONFIG_OPENTHREAD_MESH_LOCAL_PREFIX", f"{mesh_local_prefix}".lower() - ) - if (pskc := config.get(CONF_PSKC)) is not None: - add_idf_sdkconfig_option("CONFIG_OPENTHREAD_NETWORK_PSKC", f"{pskc:X}".lower()) + if channel := config.get(CONF_CHANNEL): + add_idf_sdkconfig_option("CONFIG_OPENTHREAD_NETWORK_CHANNEL", channel) - if CONF_FORCE_DATASET in config: - if config[CONF_FORCE_DATASET]: - cg.add_define("CONFIG_OPENTHREAD_FORCE_DATASET") + if network_key := config.get(CONF_NETWORK_KEY): + add_idf_sdkconfig_option( + "CONFIG_OPENTHREAD_NETWORK_MASTERKEY", f"{network_key:X}".lower() + ) + + if network_name := config.get(CONF_NETWORK_NAME): + add_idf_sdkconfig_option("CONFIG_OPENTHREAD_NETWORK_NAME", network_name) + + if (ext_pan_id := config.get(CONF_EXT_PAN_ID)) is not None: + add_idf_sdkconfig_option( + "CONFIG_OPENTHREAD_NETWORK_EXTPANID", f"{ext_pan_id:X}".lower() + ) + if (mesh_local_prefix := config.get(CONF_MESH_LOCAL_PREFIX)) is not None: + add_idf_sdkconfig_option( + "CONFIG_OPENTHREAD_MESH_LOCAL_PREFIX", f"{mesh_local_prefix}".lower() + ) + if (pskc := config.get(CONF_PSKC)) is not None: + add_idf_sdkconfig_option( + "CONFIG_OPENTHREAD_NETWORK_PSKC", f"{pskc:X}".lower() + ) + + if force_dataset := config.get(CONF_FORCE_DATASET): + if force_dataset: + cg.add_define("USE_OPENTHREAD_FORCE_DATASET") add_idf_sdkconfig_option("CONFIG_OPENTHREAD_DNS64_CLIENT", True) add_idf_sdkconfig_option("CONFIG_OPENTHREAD_SRP_CLIENT", True) add_idf_sdkconfig_option("CONFIG_OPENTHREAD_SRP_CLIENT_MAX_SERVICES", 5) # TODO: Add suport for sleepy end devices - add_idf_sdkconfig_option("CONFIG_OPENTHREAD_FTD", True) # Full Thread Device + add_idf_sdkconfig_option(f"CONFIG_OPENTHREAD_{config.get(CONF_DEVICE_TYPE)}", True) openthread_ns = cg.esphome_ns.namespace("openthread") OpenThreadComponent = openthread_ns.class_("OpenThreadComponent", cg.Component) OpenThreadSrpComponent = openthread_ns.class_("OpenThreadSrpComponent", cg.Component) - -def _convert_tlv(config): - if tlv := config.get(CONF_TLV): - config = config.copy() - parsed_tlv = parse_tlv(tlv) - validated = _CONNECTION_SCHEMA(parsed_tlv) - config.update(validated) - del config[CONF_TLV] - return config - - _CONNECTION_SCHEMA = cv.Schema( { - cv.Inclusive(CONF_PAN_ID, "manual"): cv.hex_int, - cv.Inclusive(CONF_CHANNEL, "manual"): cv.int_, - cv.Inclusive(CONF_NETWORK_KEY, "manual"): cv.hex_int, + cv.Optional(CONF_PAN_ID): cv.hex_int, + cv.Optional(CONF_CHANNEL): cv.int_, + cv.Optional(CONF_NETWORK_KEY): cv.hex_int, cv.Optional(CONF_EXT_PAN_ID): cv.hex_int, cv.Optional(CONF_NETWORK_NAME): cv.string_strict, cv.Optional(CONF_PSKC): cv.hex_int, @@ -108,12 +113,14 @@ CONFIG_SCHEMA = cv.All( cv.GenerateID(): cv.declare_id(OpenThreadComponent), cv.GenerateID(CONF_SRP_ID): cv.declare_id(OpenThreadSrpComponent), cv.GenerateID(CONF_MDNS_ID): cv.use_id(MDNSComponent), + cv.Optional(CONF_DEVICE_TYPE, default="FTD"): cv.one_of( + *CONF_DEVICE_TYPES, upper=True + ), cv.Optional(CONF_FORCE_DATASET): cv.boolean, cv.Optional(CONF_TLV): cv.string_strict, } ).extend(_CONNECTION_SCHEMA), - cv.has_exactly_one_key(CONF_PAN_ID, CONF_TLV), - _convert_tlv, + cv.has_exactly_one_key(CONF_NETWORK_KEY, CONF_TLV), cv.only_with_esp_idf, only_on_variant(supported=[VARIANT_ESP32C6, VARIANT_ESP32H2]), ) diff --git a/esphome/components/openthread/const.py b/esphome/components/openthread/const.py index 7837e69eea..7a6ffb2df4 100644 --- a/esphome/components/openthread/const.py +++ b/esphome/components/openthread/const.py @@ -1,3 +1,4 @@ +CONF_DEVICE_TYPE = "device_type" CONF_EXT_PAN_ID = "ext_pan_id" CONF_FORCE_DATASET = "force_dataset" CONF_MDNS_ID = "mdns_id" diff --git a/esphome/components/openthread/openthread_esp.cpp b/esphome/components/openthread/openthread_esp.cpp index c5c817382f..dc303cef17 100644 --- a/esphome/components/openthread/openthread_esp.cpp +++ b/esphome/components/openthread/openthread_esp.cpp @@ -111,14 +111,36 @@ void OpenThreadComponent::ot_main() { esp_openthread_cli_create_task(); #endif ESP_LOGI(TAG, "Activating dataset..."); - otOperationalDatasetTlvs dataset; + otOperationalDatasetTlvs dataset = {}; -#ifdef CONFIG_OPENTHREAD_FORCE_DATASET - ESP_ERROR_CHECK(esp_openthread_auto_start(NULL)); -#else +#ifndef USE_OPENTHREAD_FORCE_DATASET + // Check if openthread has a valid dataset from a previous execution otError error = otDatasetGetActiveTlvs(esp_openthread_get_instance(), &dataset); - ESP_ERROR_CHECK(esp_openthread_auto_start((error == OT_ERROR_NONE) ? &dataset : NULL)); + if (error != OT_ERROR_NONE) { + // Make sure the length is 0 so we fallback to the configuration + dataset.mLength = 0; + } else { + ESP_LOGI(TAG, "Found OpenThread-managed dataset, ignoring esphome configuration"); + ESP_LOGI(TAG, "(set force_dataset: true to override)"); + } #endif + +#ifdef USE_OPENTHREAD_TLVS + if (dataset.mLength == 0) { + // If we didn't have an active dataset, and we have tlvs, parse it and pass it to esp_openthread_auto_start + size_t len = (sizeof(USE_OPENTHREAD_TLVS) - 1) / 2; + if (len > sizeof(dataset.mTlvs)) { + ESP_LOGW(TAG, "TLV buffer too small, truncating"); + len = sizeof(dataset.mTlvs); + } + parse_hex(USE_OPENTHREAD_TLVS, sizeof(USE_OPENTHREAD_TLVS) - 1, dataset.mTlvs, len); + dataset.mLength = len; + } +#endif + + // Pass the existing dataset, or NULL which will use the preprocessor definitions + ESP_ERROR_CHECK(esp_openthread_auto_start(dataset.mLength > 0 ? &dataset : nullptr)); + esp_openthread_launch_mainloop(); // Clean up diff --git a/esphome/components/openthread/tlv.py b/esphome/components/openthread/tlv.py deleted file mode 100644 index 4a7d21c47d..0000000000 --- a/esphome/components/openthread/tlv.py +++ /dev/null @@ -1,65 +0,0 @@ -# Sourced from https://gist.github.com/agners/0338576e0003318b63ec1ea75adc90f9 -import binascii -import ipaddress - -from esphome.const import CONF_CHANNEL - -from . import ( - CONF_EXT_PAN_ID, - CONF_MESH_LOCAL_PREFIX, - CONF_NETWORK_KEY, - CONF_NETWORK_NAME, - CONF_PAN_ID, - CONF_PSKC, -) - -TLV_TYPES = { - 0: CONF_CHANNEL, - 1: CONF_PAN_ID, - 2: CONF_EXT_PAN_ID, - 3: CONF_NETWORK_NAME, - 4: CONF_PSKC, - 5: CONF_NETWORK_KEY, - 7: CONF_MESH_LOCAL_PREFIX, -} - - -def parse_tlv(tlv) -> dict: - data = binascii.a2b_hex(tlv) - output = {} - pos = 0 - while pos < len(data): - tag = data[pos] - pos += 1 - _len = data[pos] - pos += 1 - val = data[pos : pos + _len] - pos += _len - if tag in TLV_TYPES: - if tag == 3: - output[TLV_TYPES[tag]] = val.decode("utf-8") - elif tag == 7: - mesh_local_prefix = binascii.hexlify(val).decode("utf-8") - mesh_local_prefix_str = f"{mesh_local_prefix}0000000000000000" - ipv6_bytes = bytes.fromhex(mesh_local_prefix_str) - ipv6_address = ipaddress.IPv6Address(ipv6_bytes) - output[TLV_TYPES[tag]] = f"{ipv6_address}/64" - else: - output[TLV_TYPES[tag]] = int.from_bytes(val) - return output - - -def main(): - import sys - - args = sys.argv[1:] - parsed = parse_tlv(args[0]) - # print the parsed TLV data - for key, value in parsed.items(): - if isinstance(value, bytes): - value = value.hex() - print(f"{key}: {value}") - - -if __name__ == "__main__": - main() diff --git a/esphome/components/ota/ota_backend.h b/esphome/components/ota/ota_backend.h index bc8ab46643..372f24df5e 100644 --- a/esphome/components/ota/ota_backend.h +++ b/esphome/components/ota/ota_backend.h @@ -67,7 +67,28 @@ class OTAComponent : public Component { } protected: - CallbackManager state_callback_{}; + /** Extended callback manager with deferred call support. + * + * This adds a call_deferred() method for thread-safe execution from other tasks. + */ + class StateCallbackManager : public CallbackManager { + public: + StateCallbackManager(OTAComponent *component) : component_(component) {} + + /** Call callbacks with deferral to main loop (for thread safety). + * + * This should be used by OTA implementations that run in separate tasks + * (like web_server OTA) to ensure callbacks execute in the main loop. + */ + void call_deferred(ota::OTAState state, float progress, uint8_t error) { + component_->defer([this, state, progress, error]() { this->call(state, progress, error); }); + } + + private: + OTAComponent *component_; + }; + + StateCallbackManager state_callback_{this}; #endif }; @@ -89,6 +110,11 @@ class OTAGlobalCallback { OTAGlobalCallback *get_global_ota_callback(); void register_ota_platform(OTAComponent *ota_caller); + +// OTA implementations should use: +// - state_callback_.call() when already in main loop (e.g., esphome OTA) +// - state_callback_.call_deferred() when in separate task (e.g., web_server OTA) +// This ensures proper callback execution in all contexts. #endif std::unique_ptr make_ota_backend(); diff --git a/esphome/components/ota/ota_backend_arduino_esp32.cpp b/esphome/components/ota/ota_backend_arduino_esp32.cpp index 15dfc98a6c..5c6230f2ce 100644 --- a/esphome/components/ota/ota_backend_arduino_esp32.cpp +++ b/esphome/components/ota/ota_backend_arduino_esp32.cpp @@ -15,6 +15,11 @@ static const char *const TAG = "ota.arduino_esp32"; std::unique_ptr make_ota_backend() { return make_unique(); } OTAResponseTypes ArduinoESP32OTABackend::begin(size_t image_size) { + // Handle UPDATE_SIZE_UNKNOWN (0) which is used by web server OTA + // where the exact firmware size is unknown due to multipart encoding + if (image_size == 0) { + image_size = UPDATE_SIZE_UNKNOWN; + } bool ret = Update.begin(image_size, U_FLASH); if (ret) { return OTA_RESPONSE_OK; @@ -29,7 +34,10 @@ OTAResponseTypes ArduinoESP32OTABackend::begin(size_t image_size) { return OTA_RESPONSE_ERROR_UNKNOWN; } -void ArduinoESP32OTABackend::set_update_md5(const char *md5) { Update.setMD5(md5); } +void ArduinoESP32OTABackend::set_update_md5(const char *md5) { + Update.setMD5(md5); + this->md5_set_ = true; +} OTAResponseTypes ArduinoESP32OTABackend::write(uint8_t *data, size_t len) { size_t written = Update.write(data, len); @@ -44,7 +52,9 @@ OTAResponseTypes ArduinoESP32OTABackend::write(uint8_t *data, size_t len) { } OTAResponseTypes ArduinoESP32OTABackend::end() { - if (Update.end()) { + // Use strict validation (false) when MD5 is set, lenient validation (true) when no MD5 + // This matches the behavior of the old web_server OTA implementation + if (Update.end(!this->md5_set_)) { return OTA_RESPONSE_OK; } diff --git a/esphome/components/ota/ota_backend_arduino_esp32.h b/esphome/components/ota/ota_backend_arduino_esp32.h index ac7fe9f14f..6615cf3dc0 100644 --- a/esphome/components/ota/ota_backend_arduino_esp32.h +++ b/esphome/components/ota/ota_backend_arduino_esp32.h @@ -16,6 +16,9 @@ class ArduinoESP32OTABackend : public OTABackend { OTAResponseTypes end() override; void abort() override; bool supports_compression() override { return false; } + + private: + bool md5_set_{false}; }; } // namespace ota diff --git a/esphome/components/ota/ota_backend_arduino_esp8266.cpp b/esphome/components/ota/ota_backend_arduino_esp8266.cpp index 42edbf5d2b..375c4e7200 100644 --- a/esphome/components/ota/ota_backend_arduino_esp8266.cpp +++ b/esphome/components/ota/ota_backend_arduino_esp8266.cpp @@ -17,6 +17,11 @@ static const char *const TAG = "ota.arduino_esp8266"; std::unique_ptr make_ota_backend() { return make_unique(); } OTAResponseTypes ArduinoESP8266OTABackend::begin(size_t image_size) { + // Handle UPDATE_SIZE_UNKNOWN (0) by calculating available space + if (image_size == 0) { + // NOLINTNEXTLINE(readability-static-accessed-through-instance) + image_size = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000; + } bool ret = Update.begin(image_size, U_FLASH); if (ret) { esp8266::preferences_prevent_write(true); @@ -38,7 +43,10 @@ OTAResponseTypes ArduinoESP8266OTABackend::begin(size_t image_size) { return OTA_RESPONSE_ERROR_UNKNOWN; } -void ArduinoESP8266OTABackend::set_update_md5(const char *md5) { Update.setMD5(md5); } +void ArduinoESP8266OTABackend::set_update_md5(const char *md5) { + Update.setMD5(md5); + this->md5_set_ = true; +} OTAResponseTypes ArduinoESP8266OTABackend::write(uint8_t *data, size_t len) { size_t written = Update.write(data, len); @@ -53,13 +61,19 @@ OTAResponseTypes ArduinoESP8266OTABackend::write(uint8_t *data, size_t len) { } OTAResponseTypes ArduinoESP8266OTABackend::end() { - if (Update.end()) { + // Use strict validation (false) when MD5 is set, lenient validation (true) when no MD5 + // This matches the behavior of the old web_server OTA implementation + bool success = Update.end(!this->md5_set_); + + // On ESP8266, Update.end() might return false even with error code 0 + // Check the actual error code to determine success + uint8_t error = Update.getError(); + + if (success || error == UPDATE_ERROR_OK) { return OTA_RESPONSE_OK; } - uint8_t error = Update.getError(); ESP_LOGE(TAG, "End error: %d", error); - return OTA_RESPONSE_ERROR_UPDATE_END; } diff --git a/esphome/components/ota/ota_backend_arduino_esp8266.h b/esphome/components/ota/ota_backend_arduino_esp8266.h index 7f44d7c965..e1b9015cc7 100644 --- a/esphome/components/ota/ota_backend_arduino_esp8266.h +++ b/esphome/components/ota/ota_backend_arduino_esp8266.h @@ -21,6 +21,9 @@ class ArduinoESP8266OTABackend : public OTABackend { #else bool supports_compression() override { return false; } #endif + + private: + bool md5_set_{false}; }; } // namespace ota diff --git a/esphome/components/ota/ota_backend_arduino_libretiny.cpp b/esphome/components/ota/ota_backend_arduino_libretiny.cpp index 6b2cf80684..b4ecad1227 100644 --- a/esphome/components/ota/ota_backend_arduino_libretiny.cpp +++ b/esphome/components/ota/ota_backend_arduino_libretiny.cpp @@ -15,6 +15,11 @@ static const char *const TAG = "ota.arduino_libretiny"; std::unique_ptr make_ota_backend() { return make_unique(); } OTAResponseTypes ArduinoLibreTinyOTABackend::begin(size_t image_size) { + // Handle UPDATE_SIZE_UNKNOWN (0) which is used by web server OTA + // where the exact firmware size is unknown due to multipart encoding + if (image_size == 0) { + image_size = UPDATE_SIZE_UNKNOWN; + } bool ret = Update.begin(image_size, U_FLASH); if (ret) { return OTA_RESPONSE_OK; @@ -29,7 +34,10 @@ OTAResponseTypes ArduinoLibreTinyOTABackend::begin(size_t image_size) { return OTA_RESPONSE_ERROR_UNKNOWN; } -void ArduinoLibreTinyOTABackend::set_update_md5(const char *md5) { Update.setMD5(md5); } +void ArduinoLibreTinyOTABackend::set_update_md5(const char *md5) { + Update.setMD5(md5); + this->md5_set_ = true; +} OTAResponseTypes ArduinoLibreTinyOTABackend::write(uint8_t *data, size_t len) { size_t written = Update.write(data, len); @@ -44,7 +52,9 @@ OTAResponseTypes ArduinoLibreTinyOTABackend::write(uint8_t *data, size_t len) { } OTAResponseTypes ArduinoLibreTinyOTABackend::end() { - if (Update.end()) { + // Use strict validation (false) when MD5 is set, lenient validation (true) when no MD5 + // This matches the behavior of the old web_server OTA implementation + if (Update.end(!this->md5_set_)) { return OTA_RESPONSE_OK; } diff --git a/esphome/components/ota/ota_backend_arduino_libretiny.h b/esphome/components/ota/ota_backend_arduino_libretiny.h index 11deb6e2f2..6d9b7a96d5 100644 --- a/esphome/components/ota/ota_backend_arduino_libretiny.h +++ b/esphome/components/ota/ota_backend_arduino_libretiny.h @@ -15,6 +15,9 @@ class ArduinoLibreTinyOTABackend : public OTABackend { OTAResponseTypes end() override; void abort() override; bool supports_compression() override { return false; } + + private: + bool md5_set_{false}; }; } // namespace ota diff --git a/esphome/components/ota/ota_backend_arduino_rp2040.cpp b/esphome/components/ota/ota_backend_arduino_rp2040.cpp index ffeab2e93f..ee1ba48d50 100644 --- a/esphome/components/ota/ota_backend_arduino_rp2040.cpp +++ b/esphome/components/ota/ota_backend_arduino_rp2040.cpp @@ -17,6 +17,8 @@ static const char *const TAG = "ota.arduino_rp2040"; std::unique_ptr make_ota_backend() { return make_unique(); } OTAResponseTypes ArduinoRP2040OTABackend::begin(size_t image_size) { + // OTA size of 0 is not currently handled, but + // web_server is not supported for RP2040, so this is not an issue. bool ret = Update.begin(image_size, U_FLASH); if (ret) { rp2040::preferences_prevent_write(true); @@ -38,7 +40,10 @@ OTAResponseTypes ArduinoRP2040OTABackend::begin(size_t image_size) { return OTA_RESPONSE_ERROR_UNKNOWN; } -void ArduinoRP2040OTABackend::set_update_md5(const char *md5) { Update.setMD5(md5); } +void ArduinoRP2040OTABackend::set_update_md5(const char *md5) { + Update.setMD5(md5); + this->md5_set_ = true; +} OTAResponseTypes ArduinoRP2040OTABackend::write(uint8_t *data, size_t len) { size_t written = Update.write(data, len); @@ -53,7 +58,9 @@ OTAResponseTypes ArduinoRP2040OTABackend::write(uint8_t *data, size_t len) { } OTAResponseTypes ArduinoRP2040OTABackend::end() { - if (Update.end()) { + // Use strict validation (false) when MD5 is set, lenient validation (true) when no MD5 + // This matches the behavior of the old web_server OTA implementation + if (Update.end(!this->md5_set_)) { return OTA_RESPONSE_OK; } diff --git a/esphome/components/ota/ota_backend_arduino_rp2040.h b/esphome/components/ota/ota_backend_arduino_rp2040.h index b189964ab3..b9e10d506c 100644 --- a/esphome/components/ota/ota_backend_arduino_rp2040.h +++ b/esphome/components/ota/ota_backend_arduino_rp2040.h @@ -17,6 +17,9 @@ class ArduinoRP2040OTABackend : public OTABackend { OTAResponseTypes end() override; void abort() override; bool supports_compression() override { return false; } + + private: + bool md5_set_{false}; }; } // namespace ota diff --git a/esphome/components/ota/ota_backend_esp_idf.cpp b/esphome/components/ota/ota_backend_esp_idf.cpp index 6f45fb75e4..97aae09bd9 100644 --- a/esphome/components/ota/ota_backend_esp_idf.cpp +++ b/esphome/components/ota/ota_backend_esp_idf.cpp @@ -6,10 +6,7 @@ #include #include - -#if ESP_IDF_VERSION_MAJOR >= 5 #include -#endif namespace esphome { namespace ota { @@ -24,7 +21,6 @@ OTAResponseTypes IDFOTABackend::begin(size_t image_size) { #if CONFIG_ESP_TASK_WDT_TIMEOUT_S < 15 // The following function takes longer than the 5 seconds timeout of WDT -#if ESP_IDF_VERSION_MAJOR >= 5 esp_task_wdt_config_t wdtc; wdtc.idle_core_mask = 0; #if CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0 @@ -36,21 +32,14 @@ OTAResponseTypes IDFOTABackend::begin(size_t image_size) { wdtc.timeout_ms = 15000; wdtc.trigger_panic = false; esp_task_wdt_reconfigure(&wdtc); -#else - esp_task_wdt_init(15, false); -#endif #endif esp_err_t err = esp_ota_begin(this->partition_, image_size, &this->update_handle_); #if CONFIG_ESP_TASK_WDT_TIMEOUT_S < 15 // Set the WDT back to the configured timeout -#if ESP_IDF_VERSION_MAJOR >= 5 wdtc.timeout_ms = CONFIG_ESP_TASK_WDT_TIMEOUT_S * 1000; esp_task_wdt_reconfigure(&wdtc); -#else - esp_task_wdt_init(CONFIG_ESP_TASK_WDT_TIMEOUT_S, false); -#endif #endif if (err != ESP_OK) { @@ -67,7 +56,10 @@ OTAResponseTypes IDFOTABackend::begin(size_t image_size) { return OTA_RESPONSE_OK; } -void IDFOTABackend::set_update_md5(const char *expected_md5) { memcpy(this->expected_bin_md5_, expected_md5, 32); } +void IDFOTABackend::set_update_md5(const char *expected_md5) { + memcpy(this->expected_bin_md5_, expected_md5, 32); + this->md5_set_ = true; +} OTAResponseTypes IDFOTABackend::write(uint8_t *data, size_t len) { esp_err_t err = esp_ota_write(this->update_handle_, data, len); @@ -84,10 +76,12 @@ OTAResponseTypes IDFOTABackend::write(uint8_t *data, size_t len) { } OTAResponseTypes IDFOTABackend::end() { - this->md5_.calculate(); - if (!this->md5_.equals_hex(this->expected_bin_md5_)) { - this->abort(); - return OTA_RESPONSE_ERROR_MD5_MISMATCH; + if (this->md5_set_) { + this->md5_.calculate(); + if (!this->md5_.equals_hex(this->expected_bin_md5_)) { + this->abort(); + return OTA_RESPONSE_ERROR_MD5_MISMATCH; + } } esp_err_t err = esp_ota_end(this->update_handle_); this->update_handle_ = 0; diff --git a/esphome/components/ota/ota_backend_esp_idf.h b/esphome/components/ota/ota_backend_esp_idf.h index ed66d9b970..6e93982131 100644 --- a/esphome/components/ota/ota_backend_esp_idf.h +++ b/esphome/components/ota/ota_backend_esp_idf.h @@ -24,6 +24,7 @@ class IDFOTABackend : public OTABackend { const esp_partition_t *partition_; md5::MD5Digest md5_{}; char expected_bin_md5_[32]; + bool md5_set_{false}; }; } // namespace ota diff --git a/esphome/components/packages/__init__.py b/esphome/components/packages/__init__.py index 08ae798282..6eb746ec63 100644 --- a/esphome/components/packages/__init__.py +++ b/esphome/components/packages/__init__.py @@ -74,7 +74,7 @@ BASE_SCHEMA = cv.All( { cv.Required(CONF_PATH): validate_yaml_filename, cv.Optional(CONF_VARS, default={}): cv.Schema( - {cv.string: cv.string} + {cv.string: object} ), } ), @@ -148,7 +148,6 @@ def _process_base_package(config: dict) -> dict: raise cv.Invalid( f"Current ESPHome Version is too old to use this package: {ESPHOME_VERSION} < {min_version}" ) - vars = {k: str(v) for k, v in vars.items()} new_yaml = yaml_util.substitute_vars(new_yaml, vars) packages[f"{filename}{idx}"] = new_yaml except EsphomeError as e: diff --git a/esphome/components/psram/psram.cpp b/esphome/components/psram/psram.cpp index 162543545e..6c110a577d 100644 --- a/esphome/components/psram/psram.cpp +++ b/esphome/components/psram/psram.cpp @@ -2,9 +2,7 @@ #ifdef USE_ESP32 #include "psram.h" #include -#if defined(USE_ESP_IDF) && ESP_IDF_VERSION_MAJOR >= 5 #include -#endif // USE_ESP_IDF #include "esphome/core/log.h" @@ -16,7 +14,6 @@ static const char *const TAG = "psram"; void PsramComponent::dump_config() { ESP_LOGCONFIG(TAG, "PSRAM:"); -#if defined(USE_ESP_IDF) && ESP_IDF_VERSION_MAJOR >= 5 bool available = esp_psram_is_initialized(); ESP_LOGCONFIG(TAG, " Available: %s", YESNO(available)); @@ -26,23 +23,6 @@ void PsramComponent::dump_config() { ESP_LOGCONFIG(TAG, " ECC enabled: YES"); #endif } -#else - // Technically this can be false if the PSRAM is full, but heap_caps_get_total_size() isn't always available, and it's - // very unlikely for the PSRAM to be full. - bool available = heap_caps_get_free_size(MALLOC_CAP_SPIRAM) > 0; - ESP_LOGCONFIG(TAG, " Available: %s", YESNO(available)); - - if (available) { - const size_t psram_total_size_bytes = heap_caps_get_total_size(MALLOC_CAP_SPIRAM); - const float psram_total_size_kb = psram_total_size_bytes / 1024.0f; - - if (abs(std::round(psram_total_size_kb) - psram_total_size_kb) < 0.05f) { - ESP_LOGCONFIG(TAG, " Size: %.0f KB", psram_total_size_kb); - } else { - ESP_LOGCONFIG(TAG, " Size: %zu bytes", psram_total_size_bytes); - } - } -#endif // USE_ESP_IDF } } // namespace psram diff --git a/esphome/components/pulse_meter/pulse_meter_sensor.cpp b/esphome/components/pulse_meter/pulse_meter_sensor.cpp index 81ecf22c71..9a7630a7be 100644 --- a/esphome/components/pulse_meter/pulse_meter_sensor.cpp +++ b/esphome/components/pulse_meter/pulse_meter_sensor.cpp @@ -31,6 +31,10 @@ void PulseMeterSensor::setup() { this->pulse_state_.latched_ = this->last_pin_val_; this->pin_->attach_interrupt(PulseMeterSensor::pulse_intr, this, gpio::INTERRUPT_ANY_EDGE); } + + if (this->total_sensor_ != nullptr) { + this->total_sensor_->publish_state(this->total_pulses_); + } } void PulseMeterSensor::loop() { diff --git a/esphome/components/pvvx_mithermometer/display/pvvx_display.cpp b/esphome/components/pvvx_mithermometer/display/pvvx_display.cpp index 74f63a9640..4b6c11b332 100644 --- a/esphome/components/pvvx_mithermometer/display/pvvx_display.cpp +++ b/esphome/components/pvvx_mithermometer/display/pvvx_display.cpp @@ -146,11 +146,7 @@ void PVVXDisplay::sync_time_() { } time.recalc_timestamp_utc(true); // calculate timestamp of local time uint8_t blk[5] = {}; -#if ESP_IDF_VERSION_MAJOR >= 5 ESP_LOGD(TAG, "[%s] Sync time with timestamp %" PRIu64 ".", this->parent_->address_str().c_str(), time.timestamp); -#else - ESP_LOGD(TAG, "[%s] Sync time with timestamp %lu.", this->parent_->address_str().c_str(), time.timestamp); -#endif blk[0] = 0x23; blk[1] = time.timestamp & 0xff; blk[2] = (time.timestamp >> 8) & 0xff; diff --git a/esphome/components/qr_code/__init__.py b/esphome/components/qr_code/__init__.py index 1c5e0471b0..6ff92b8a7f 100644 --- a/esphome/components/qr_code/__init__.py +++ b/esphome/components/qr_code/__init__.py @@ -21,21 +21,24 @@ ECC = { "HIGH": qrcodegen_Ecc.qrcodegen_Ecc_HIGH, } -CONFIG_SCHEMA = cv.Schema( - { - cv.Required(CONF_ID): cv.declare_id(QRCode), - cv.Required(CONF_VALUE): cv.string, - cv.Optional(CONF_ECC, default="LOW"): cv.enum(ECC, upper=True), - } +CONFIG_SCHEMA = cv.ensure_list( + cv.Schema( + { + cv.Required(CONF_ID): cv.declare_id(QRCode), + cv.Required(CONF_VALUE): cv.string, + cv.Optional(CONF_ECC, default="LOW"): cv.enum(ECC, upper=True), + } + ) ) async def to_code(config): cg.add_library("wjtje/qr-code-generator-library", "^1.7.0") - var = cg.new_Pvariable(config[CONF_ID]) - cg.add(var.set_value(config[CONF_VALUE])) - cg.add(var.set_ecc(ECC[config[CONF_ECC]])) - await cg.register_component(var, config) + for entry in config: + var = cg.new_Pvariable(entry[CONF_ID]) + cg.add(var.set_value(entry[CONF_VALUE])) + cg.add(var.set_ecc(ECC[entry[CONF_ECC]])) + await cg.register_component(var, entry) cg.add_define("USE_QR_CODE") diff --git a/esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.cpp b/esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.cpp index 666bac354d..91eb947a3e 100644 --- a/esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.cpp +++ b/esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.cpp @@ -10,10 +10,8 @@ void RpiDpiRgb::setup() { this->reset_display_(); esp_lcd_rgb_panel_config_t config{}; config.flags.fb_in_psram = 1; -#if ESP_IDF_VERSION_MAJOR >= 5 config.bounce_buffer_size_px = this->width_ * 10; config.num_fbs = 1; -#endif // ESP_IDF_VERSION_MAJOR config.timings.h_res = this->width_; config.timings.v_res = this->height_; config.timings.hsync_pulse_width = this->hsync_pulse_width_; @@ -47,10 +45,8 @@ void RpiDpiRgb::setup() { ESP_LOGCONFIG(TAG, "RPI_DPI_RGB setup complete"); } void RpiDpiRgb::loop() { -#if ESP_IDF_VERSION_MAJOR >= 5 if (this->handle_ != nullptr) esp_lcd_rgb_panel_restart(this->handle_); -#endif // ESP_IDF_VERSION_MAJOR } void RpiDpiRgb::draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, display::ColorOrder order, diff --git a/esphome/components/rtttl/rtttl.cpp b/esphome/components/rtttl/rtttl.cpp index 2c4a0f917f..65a3af1bbc 100644 --- a/esphome/components/rtttl/rtttl.cpp +++ b/esphome/components/rtttl/rtttl.cpp @@ -371,6 +371,7 @@ void Rtttl::finish_() { ESP_LOGD(TAG, "Playback finished"); } +#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_DEBUG static const LogString *state_to_string(State state) { switch (state) { case STATE_STOPPED: @@ -387,6 +388,7 @@ static const LogString *state_to_string(State state) { return LOG_STR("UNKNOWN"); } }; +#endif void Rtttl::set_state_(State state) { State old_state = this->state_; diff --git a/esphome/components/smt100/sensor.py b/esphome/components/smt100/sensor.py index ea42499379..f877ce2af0 100644 --- a/esphome/components/smt100/sensor.py +++ b/esphome/components/smt100/sensor.py @@ -6,6 +6,7 @@ from esphome.const import ( CONF_DIELECTRIC_CONSTANT, CONF_ID, CONF_MOISTURE, + CONF_PERMITTIVITY, CONF_TEMPERATURE, CONF_VOLTAGE, DEVICE_CLASS_TEMPERATURE, @@ -33,7 +34,10 @@ CONFIG_SCHEMA = ( accuracy_decimals=0, state_class=STATE_CLASS_MEASUREMENT, ), - cv.Optional(CONF_DIELECTRIC_CONSTANT): sensor.sensor_schema( + cv.Optional(CONF_DIELECTRIC_CONSTANT): cv.invalid( + "Use 'permittivity' instead" + ), + cv.Optional(CONF_PERMITTIVITY): sensor.sensor_schema( unit_of_measurement=UNIT_EMPTY, accuracy_decimals=2, state_class=STATE_CLASS_MEASUREMENT, @@ -76,9 +80,9 @@ async def to_code(config): sens = await sensor.new_sensor(config[CONF_COUNTS]) cg.add(var.set_counts_sensor(sens)) - if CONF_DIELECTRIC_CONSTANT in config: - sens = await sensor.new_sensor(config[CONF_DIELECTRIC_CONSTANT]) - cg.add(var.set_dielectric_constant_sensor(sens)) + if CONF_PERMITTIVITY in config: + sens = await sensor.new_sensor(config[CONF_PERMITTIVITY]) + cg.add(var.set_permittivity_sensor(sens)) if CONF_TEMPERATURE in config: sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) diff --git a/esphome/components/smt100/smt100.cpp b/esphome/components/smt100/smt100.cpp index 24ba05b894..c8dfb4c7bd 100644 --- a/esphome/components/smt100/smt100.cpp +++ b/esphome/components/smt100/smt100.cpp @@ -16,7 +16,7 @@ void SMT100Component::loop() { while (this->available() != 0) { if (readline_(read(), buffer, MAX_LINE_LENGTH) > 0) { int counts = (int) strtol((strtok(buffer, ",")), nullptr, 10); - float dielectric_constant = (float) strtod((strtok(nullptr, ",")), nullptr); + float permittivity = (float) strtod((strtok(nullptr, ",")), nullptr); float moisture = (float) strtod((strtok(nullptr, ",")), nullptr); float temperature = (float) strtod((strtok(nullptr, ",")), nullptr); float voltage = (float) strtod((strtok(nullptr, ",")), nullptr); @@ -25,8 +25,8 @@ void SMT100Component::loop() { counts_sensor_->publish_state(counts); } - if (this->dielectric_constant_sensor_ != nullptr) { - dielectric_constant_sensor_->publish_state(dielectric_constant); + if (this->permittivity_sensor_ != nullptr) { + permittivity_sensor_->publish_state(permittivity); } if (this->moisture_sensor_ != nullptr) { @@ -49,8 +49,8 @@ float SMT100Component::get_setup_priority() const { return setup_priority::DATA; void SMT100Component::dump_config() { ESP_LOGCONFIG(TAG, "SMT100:"); - LOG_SENSOR(TAG, "Counts", this->temperature_sensor_); - LOG_SENSOR(TAG, "Dielectric Constant", this->temperature_sensor_); + LOG_SENSOR(TAG, "Counts", this->counts_sensor_); + LOG_SENSOR(TAG, "Permittivity", this->permittivity_sensor_); LOG_SENSOR(TAG, "Temperature", this->temperature_sensor_); LOG_SENSOR(TAG, "Moisture", this->moisture_sensor_); LOG_UPDATE_INTERVAL(this); diff --git a/esphome/components/smt100/smt100.h b/esphome/components/smt100/smt100.h index 017818bdcf..86827607dc 100644 --- a/esphome/components/smt100/smt100.h +++ b/esphome/components/smt100/smt100.h @@ -20,8 +20,8 @@ class SMT100Component : public PollingComponent, public uart::UARTDevice { float get_setup_priority() const override; void set_counts_sensor(sensor::Sensor *counts_sensor) { this->counts_sensor_ = counts_sensor; } - void set_dielectric_constant_sensor(sensor::Sensor *dielectric_constant_sensor) { - this->dielectric_constant_sensor_ = dielectric_constant_sensor; + void set_permittivity_sensor(sensor::Sensor *permittivity_sensor) { + this->permittivity_sensor_ = permittivity_sensor; } void set_temperature_sensor(sensor::Sensor *temperature_sensor) { this->temperature_sensor_ = temperature_sensor; } void set_moisture_sensor(sensor::Sensor *moisture_sensor) { this->moisture_sensor_ = moisture_sensor; } @@ -31,7 +31,7 @@ class SMT100Component : public PollingComponent, public uart::UARTDevice { int readline_(int readch, char *buffer, int len); sensor::Sensor *counts_sensor_{nullptr}; - sensor::Sensor *dielectric_constant_sensor_{nullptr}; + sensor::Sensor *permittivity_sensor_{nullptr}; sensor::Sensor *moisture_sensor_{nullptr}; sensor::Sensor *temperature_sensor_{nullptr}; sensor::Sensor *voltage_sensor_{nullptr}; diff --git a/esphome/components/st7701s/st7701s.cpp b/esphome/components/st7701s/st7701s.cpp index 6261f33b77..46509a7f9f 100644 --- a/esphome/components/st7701s/st7701s.cpp +++ b/esphome/components/st7701s/st7701s.cpp @@ -12,10 +12,8 @@ void ST7701S::setup() { esp_lcd_rgb_panel_config_t config{}; config.flags.fb_in_psram = 1; -#if ESP_IDF_VERSION_MAJOR >= 5 config.bounce_buffer_size_px = this->width_ * 10; config.num_fbs = 1; -#endif // ESP_IDF_VERSION_MAJOR config.timings.h_res = this->width_; config.timings.v_res = this->height_; config.timings.hsync_pulse_width = this->hsync_pulse_width_; @@ -48,10 +46,8 @@ void ST7701S::setup() { } void ST7701S::loop() { -#if ESP_IDF_VERSION_MAJOR >= 5 if (this->handle_ != nullptr) esp_lcd_rgb_panel_restart(this->handle_); -#endif // ESP_IDF_VERSION_MAJOR } void ST7701S::draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, display::ColorOrder order, diff --git a/esphome/components/substitutions/__init__.py b/esphome/components/substitutions/__init__.py index 41e49f70db..5878af43b2 100644 --- a/esphome/components/substitutions/__init__.py +++ b/esphome/components/substitutions/__init__.py @@ -5,6 +5,13 @@ from esphome.config_helpers import Extend, Remove, merge_config import esphome.config_validation as cv from esphome.const import CONF_SUBSTITUTIONS, VALID_SUBSTITUTIONS_CHARACTERS from esphome.yaml_util import ESPHomeDataBase, make_data_base +from .jinja import ( + Jinja, + JinjaStr, + has_jinja, + TemplateError, + TemplateRuntimeError, +) CODEOWNERS = ["@esphome/core"] _LOGGER = logging.getLogger(__name__) @@ -28,7 +35,7 @@ def validate_substitution_key(value): CONFIG_SCHEMA = cv.Schema( { - validate_substitution_key: cv.string_strict, + validate_substitution_key: object, } ) @@ -37,7 +44,42 @@ async def to_code(config): pass -def _expand_substitutions(substitutions, value, path, ignore_missing): +def _expand_jinja(value, orig_value, path, jinja, ignore_missing): + if has_jinja(value): + # If the original value passed in to this function is a JinjaStr, it means it contains an unresolved + # Jinja expression from a previous pass. + if isinstance(orig_value, JinjaStr): + # Rebuild the JinjaStr in case it was lost while replacing substitutions. + value = JinjaStr(value, orig_value.upvalues) + try: + # Invoke the jinja engine to evaluate the expression. + value, err = jinja.expand(value) + if err is not None: + if not ignore_missing and "password" not in path: + _LOGGER.warning( + "Found '%s' (see %s) which looks like an expression," + " but could not resolve all the variables: %s", + value, + "->".join(str(x) for x in path), + err.message, + ) + except ( + TemplateError, + TemplateRuntimeError, + RuntimeError, + ArithmeticError, + AttributeError, + TypeError, + ) as err: + raise cv.Invalid( + f"{type(err).__name__} Error evaluating jinja expression '{value}': {str(err)}." + f" See {'->'.join(str(x) for x in path)}", + path, + ) + return value + + +def _expand_substitutions(substitutions, value, path, jinja, ignore_missing): if "$" not in value: return value @@ -47,7 +89,8 @@ def _expand_substitutions(substitutions, value, path, ignore_missing): while True: m = cv.VARIABLE_PROG.search(value, i) if not m: - # Nothing more to match. Done + # No more variable substitutions found. See if the remainder looks like a jinja template + value = _expand_jinja(value, orig_value, path, jinja, ignore_missing) break i, j = m.span(0) @@ -67,8 +110,15 @@ def _expand_substitutions(substitutions, value, path, ignore_missing): continue sub = substitutions[name] + + if i == 0 and j == len(value): + # The variable spans the whole expression, e.g., "${varName}". Return its resolved value directly + # to conserve its type. + value = sub + break + tail = value[j:] - value = value[:i] + sub + value = value[:i] + str(sub) i = len(value) value += tail @@ -77,36 +127,40 @@ def _expand_substitutions(substitutions, value, path, ignore_missing): if isinstance(orig_value, ESPHomeDataBase): # even though string can get larger or smaller, the range should point # to original document marks - return make_data_base(value, orig_value) + value = make_data_base(value, orig_value) return value -def _substitute_item(substitutions, item, path, ignore_missing): +def _substitute_item(substitutions, item, path, jinja, ignore_missing): if isinstance(item, list): for i, it in enumerate(item): - sub = _substitute_item(substitutions, it, path + [i], ignore_missing) + sub = _substitute_item(substitutions, it, path + [i], jinja, ignore_missing) if sub is not None: item[i] = sub elif isinstance(item, dict): replace_keys = [] for k, v in item.items(): if path or k != CONF_SUBSTITUTIONS: - sub = _substitute_item(substitutions, k, path + [k], ignore_missing) + sub = _substitute_item( + substitutions, k, path + [k], jinja, ignore_missing + ) if sub is not None: replace_keys.append((k, sub)) - sub = _substitute_item(substitutions, v, path + [k], ignore_missing) + sub = _substitute_item(substitutions, v, path + [k], jinja, ignore_missing) if sub is not None: item[k] = sub for old, new in replace_keys: item[new] = merge_config(item.get(old), item.get(new)) del item[old] elif isinstance(item, str): - sub = _expand_substitutions(substitutions, item, path, ignore_missing) - if sub != item: + sub = _expand_substitutions(substitutions, item, path, jinja, ignore_missing) + if isinstance(sub, JinjaStr) or sub != item: return sub elif isinstance(item, (core.Lambda, Extend, Remove)): - sub = _expand_substitutions(substitutions, item.value, path, ignore_missing) + sub = _expand_substitutions( + substitutions, item.value, path, jinja, ignore_missing + ) if sub != item: item.value = sub return None @@ -116,11 +170,11 @@ def do_substitution_pass(config, command_line_substitutions, ignore_missing=Fals if CONF_SUBSTITUTIONS not in config and not command_line_substitutions: return - substitutions = config.get(CONF_SUBSTITUTIONS) - if substitutions is None: - substitutions = command_line_substitutions - elif command_line_substitutions: - substitutions = {**substitutions, **command_line_substitutions} + # Merge substitutions in config, overriding with substitutions coming from command line: + substitutions = { + **config.get(CONF_SUBSTITUTIONS, {}), + **(command_line_substitutions or {}), + } with cv.prepend_path("substitutions"): if not isinstance(substitutions, dict): raise cv.Invalid( @@ -133,7 +187,7 @@ def do_substitution_pass(config, command_line_substitutions, ignore_missing=Fals sub = validate_substitution_key(key) if sub != key: replace_keys.append((key, sub)) - substitutions[key] = cv.string_strict(value) + substitutions[key] = value for old, new in replace_keys: substitutions[new] = substitutions[old] del substitutions[old] @@ -141,4 +195,7 @@ def do_substitution_pass(config, command_line_substitutions, ignore_missing=Fals config[CONF_SUBSTITUTIONS] = substitutions # Move substitutions to the first place to replace substitutions in them correctly config.move_to_end(CONF_SUBSTITUTIONS, False) - _substitute_item(substitutions, config, [], ignore_missing) + + # Create a Jinja environment that will consider substitutions in scope: + jinja = Jinja(substitutions) + _substitute_item(substitutions, config, [], jinja, ignore_missing) diff --git a/esphome/components/substitutions/jinja.py b/esphome/components/substitutions/jinja.py new file mode 100644 index 0000000000..9ecdbab844 --- /dev/null +++ b/esphome/components/substitutions/jinja.py @@ -0,0 +1,99 @@ +import logging +import math +import re +import jinja2 as jinja +from jinja2.nativetypes import NativeEnvironment + +TemplateError = jinja.TemplateError +TemplateSyntaxError = jinja.TemplateSyntaxError +TemplateRuntimeError = jinja.TemplateRuntimeError +UndefinedError = jinja.UndefinedError +Undefined = jinja.Undefined + +_LOGGER = logging.getLogger(__name__) + +DETECT_JINJA = r"(\$\{)" +detect_jinja_re = re.compile( + r"<%.+?%>" # Block form expression: <% ... %> + r"|\$\{[^}]+\}", # Braced form expression: ${ ... } + flags=re.MULTILINE, +) + + +def has_jinja(st): + return detect_jinja_re.search(st) is not None + + +class JinjaStr(str): + """ + Wraps a string containing an unresolved Jinja expression, + storing the variables visible to it when it failed to resolve. + For example, an expression inside a package, `${ A * B }` may fail + to resolve at package parsing time if `A` is a local package var + but `B` is a substitution defined in the root yaml. + Therefore, we store the value of `A` as an upvalue bound + to the original string so we may be able to resolve `${ A * B }` + later in the main substitutions pass. + """ + + def __new__(cls, value: str, upvalues=None): + obj = super().__new__(cls, value) + obj.upvalues = upvalues or {} + return obj + + def __init__(self, value: str, upvalues=None): + self.upvalues = upvalues or {} + + +class Jinja: + """ + Wraps a Jinja environment + """ + + def __init__(self, context_vars): + self.env = NativeEnvironment( + trim_blocks=True, + lstrip_blocks=True, + block_start_string="<%", + block_end_string="%>", + line_statement_prefix="#", + line_comment_prefix="##", + variable_start_string="${", + variable_end_string="}", + undefined=jinja.StrictUndefined, + ) + self.env.add_extension("jinja2.ext.do") + self.env.globals["math"] = math # Inject entire math module + self.context_vars = {**context_vars} + self.env.globals = {**self.env.globals, **self.context_vars} + + def expand(self, content_str): + """ + Renders a string that may contain Jinja expressions or statements + Returns the resulting processed string if all values could be resolved. + Otherwise, it returns a tagged (JinjaStr) string that captures variables + in scope (upvalues), like a closure for later evaluation. + """ + result = None + override_vars = {} + if isinstance(content_str, JinjaStr): + # If `value` is already a JinjaStr, it means we are trying to evaluate it again + # in a parent pass. + # Hopefully, all required variables are visible now. + override_vars = content_str.upvalues + try: + template = self.env.from_string(content_str) + result = template.render(override_vars) + if isinstance(result, Undefined): + # This happens when the expression is simply an undefined variable. Jinja does not + # raise an exception, instead we get "Undefined". + # Trigger an UndefinedError exception so we skip to below. + print("" + result) + except (TemplateSyntaxError, UndefinedError) as err: + # `content_str` contains a Jinja expression that refers to a variable that is undefined + # in this scope. Perhaps it refers to a root substitution that is not visible yet. + # Therefore, return the original `content_str` as a JinjaStr, which contains the variables + # that are actually visible to it at this point to postpone evaluation. + return JinjaStr(content_str, {**self.context_vars, **override_vars}), err + + return result, None diff --git a/esphome/components/time/__init__.py b/esphome/components/time/__init__.py index 6b3ff6f4d3..ab821d457b 100644 --- a/esphome/components/time/__init__.py +++ b/esphome/components/time/__init__.py @@ -268,7 +268,19 @@ def validate_tz(value: str) -> str: TIME_SCHEMA = cv.Schema( { - cv.Optional(CONF_TIMEZONE, default=detect_tz): validate_tz, + cv.SplitDefault( + CONF_TIMEZONE, + esp8266=detect_tz, + esp32=detect_tz, + rp2040=detect_tz, + bk72xx=detect_tz, + rtl87xx=detect_tz, + ln882x=detect_tz, + host=detect_tz, + ): cv.All( + cv.only_with_framework(["arduino", "esp-idf", "host"]), + validate_tz, + ), cv.Optional(CONF_ON_TIME): automation.validate_automation( { cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(CronTrigger), @@ -293,7 +305,9 @@ TIME_SCHEMA = cv.Schema( async def setup_time_core_(time_var, config): - cg.add(time_var.set_timezone(config[CONF_TIMEZONE])) + if timezone := config.get(CONF_TIMEZONE): + cg.add(time_var.set_timezone(timezone)) + cg.add_define("USE_TIME_TIMEZONE") for conf in config.get(CONF_ON_TIME, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], time_var) diff --git a/esphome/components/time/real_time_clock.cpp b/esphome/components/time/real_time_clock.cpp index 11e39e8f67..61391d2c6b 100644 --- a/esphome/components/time/real_time_clock.cpp +++ b/esphome/components/time/real_time_clock.cpp @@ -35,8 +35,10 @@ void RealTimeClock::synchronize_epoch_(uint32_t epoch) { ret = settimeofday(&timev, nullptr); } +#ifdef USE_TIME_TIMEZONE // Move timezone back to local timezone. this->apply_timezone_(); +#endif if (ret != 0) { ESP_LOGW(TAG, "setimeofday() failed with code %d", ret); @@ -49,10 +51,12 @@ void RealTimeClock::synchronize_epoch_(uint32_t epoch) { this->time_sync_callback_.call(); } +#ifdef USE_TIME_TIMEZONE void RealTimeClock::apply_timezone_() { setenv("TZ", this->timezone_.c_str(), 1); tzset(); } +#endif } // namespace time } // namespace esphome diff --git a/esphome/components/time/real_time_clock.h b/esphome/components/time/real_time_clock.h index 401798a568..4b98a88975 100644 --- a/esphome/components/time/real_time_clock.h +++ b/esphome/components/time/real_time_clock.h @@ -20,6 +20,7 @@ class RealTimeClock : public PollingComponent { public: explicit RealTimeClock(); +#ifdef USE_TIME_TIMEZONE /// Set the time zone. void set_timezone(const std::string &tz) { this->timezone_ = tz; @@ -28,6 +29,7 @@ class RealTimeClock : public PollingComponent { /// Get the time zone currently in use. std::string get_timezone() { return this->timezone_; } +#endif /// Get the time in the currently defined timezone. ESPTime now() { return ESPTime::from_epoch_local(this->timestamp_now()); } @@ -38,7 +40,7 @@ class RealTimeClock : public PollingComponent { /// Get the current time as the UTC epoch since January 1st 1970. time_t timestamp_now() { return ::time(nullptr); } - void add_on_time_sync_callback(std::function callback) { + void add_on_time_sync_callback(std::function &&callback) { this->time_sync_callback_.add(std::move(callback)); }; @@ -46,8 +48,10 @@ class RealTimeClock : public PollingComponent { /// Report a unix epoch as current time. void synchronize_epoch_(uint32_t epoch); +#ifdef USE_TIME_TIMEZONE std::string timezone_{}; void apply_timezone_(); +#endif CallbackManager time_sync_callback_; }; diff --git a/esphome/components/uart/uart_component_esp_idf.cpp b/esphome/components/uart/uart_component_esp_idf.cpp index 8fae63a603..63b2579c3f 100644 --- a/esphome/components/uart/uart_component_esp_idf.cpp +++ b/esphome/components/uart/uart_component_esp_idf.cpp @@ -48,11 +48,7 @@ uart_config_t IDFUARTComponent::get_config_() { uart_config.parity = parity; uart_config.stop_bits = this->stop_bits_ == 1 ? UART_STOP_BITS_1 : UART_STOP_BITS_2; uart_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE; -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) uart_config.source_clk = UART_SCLK_DEFAULT; -#else - uart_config.source_clk = UART_SCLK_APB; -#endif uart_config.rx_flow_ctrl_thresh = 122; return uart_config; diff --git a/esphome/components/watchdog/watchdog.cpp b/esphome/components/watchdog/watchdog.cpp index f6f2992a11..2ce46756e4 100644 --- a/esphome/components/watchdog/watchdog.cpp +++ b/esphome/components/watchdog/watchdog.cpp @@ -38,16 +38,12 @@ WatchdogManager::~WatchdogManager() { void WatchdogManager::set_timeout_(uint32_t timeout_ms) { ESP_LOGV(TAG, "Adjusting WDT to %" PRIu32 "ms", timeout_ms); #ifdef USE_ESP32 -#if ESP_IDF_VERSION_MAJOR >= 5 esp_task_wdt_config_t wdt_config = { .timeout_ms = timeout_ms, .idle_core_mask = (1 << SOC_CPU_CORES_NUM) - 1, .trigger_panic = true, }; esp_task_wdt_reconfigure(&wdt_config); -#else - esp_task_wdt_init(timeout_ms / 1000, true); -#endif // ESP_IDF_VERSION_MAJOR #endif // USE_ESP32 #ifdef USE_RP2040 diff --git a/esphome/components/web_server/__init__.py b/esphome/components/web_server/__init__.py index f2c1824028..6890f60014 100644 --- a/esphome/components/web_server/__init__.py +++ b/esphome/components/web_server/__init__.py @@ -33,6 +33,7 @@ from esphome.const import ( ) from esphome.core import CORE, coroutine_with_priority import esphome.final_validate as fv +from esphome.types import ConfigType AUTO_LOAD = ["json", "web_server_base"] @@ -40,13 +41,14 @@ CONF_SORTING_GROUP_ID = "sorting_group_id" CONF_SORTING_GROUPS = "sorting_groups" CONF_SORTING_WEIGHT = "sorting_weight" + web_server_ns = cg.esphome_ns.namespace("web_server") WebServer = web_server_ns.class_("WebServer", cg.Component, cg.Controller) sorting_groups = {} -def default_url(config): +def default_url(config: ConfigType) -> ConfigType: config = config.copy() if config[CONF_VERSION] == 1: if CONF_CSS_URL not in config: @@ -66,19 +68,27 @@ def default_url(config): return config -def validate_local(config): +def validate_local(config: ConfigType) -> ConfigType: if CONF_LOCAL in config and config[CONF_VERSION] == 1: raise cv.Invalid("'local' is not supported in version 1") return config -def validate_ota(config): - if CORE.using_esp_idf and config[CONF_OTA]: - raise cv.Invalid("Enabling 'ota' is not supported for IDF framework yet") +def validate_ota_removed(config: ConfigType) -> ConfigType: + # Only raise error if OTA is explicitly enabled (True) + # If it's False or not specified, we can safely ignore it + if config.get(CONF_OTA): + raise cv.Invalid( + f"The '{CONF_OTA}' option has been removed from 'web_server'. " + f"Please use the new OTA platform structure instead:\n\n" + f"ota:\n" + f" - platform: web_server\n\n" + f"See https://esphome.io/components/ota for more information." + ) return config -def validate_sorting_groups(config): +def validate_sorting_groups(config: ConfigType) -> ConfigType: if CONF_SORTING_GROUPS in config and config[CONF_VERSION] != 3: raise cv.Invalid( f"'{CONF_SORTING_GROUPS}' is only supported in 'web_server' version 3" @@ -89,7 +99,7 @@ def validate_sorting_groups(config): def _validate_no_sorting_component( sorting_component: str, webserver_version: int, - config: dict, + config: ConfigType, path: list[str] | None = None, ) -> None: if path is None: @@ -112,7 +122,7 @@ def _validate_no_sorting_component( ) -def _final_validate_sorting(config): +def _final_validate_sorting(config: ConfigType) -> ConfigType: if (webserver_version := config.get(CONF_VERSION)) != 3: _validate_no_sorting_component( CONF_SORTING_WEIGHT, webserver_version, fv.full_config.get() @@ -175,15 +185,7 @@ CONFIG_SCHEMA = cv.All( web_server_base.WebServerBase ), cv.Optional(CONF_INCLUDE_INTERNAL, default=False): cv.boolean, - cv.SplitDefault( - CONF_OTA, - esp8266=True, - esp32_arduino=True, - esp32_idf=False, - bk72xx=True, - ln882x=True, - rtl87xx=True, - ): cv.boolean, + cv.Optional(CONF_OTA, default=False): cv.boolean, cv.Optional(CONF_LOG, default=True): cv.boolean, cv.Optional(CONF_LOCAL): cv.boolean, cv.Optional(CONF_SORTING_GROUPS): cv.ensure_list(sorting_group), @@ -200,8 +202,8 @@ CONFIG_SCHEMA = cv.All( ), default_url, validate_local, - validate_ota, validate_sorting_groups, + validate_ota_removed, ) @@ -285,7 +287,8 @@ async def to_code(config): else: cg.add(var.set_css_url(config[CONF_CSS_URL])) cg.add(var.set_js_url(config[CONF_JS_URL])) - cg.add(var.set_allow_ota(config[CONF_OTA])) + # OTA is now handled by the web_server OTA platform + # The CONF_OTA option is kept only for backwards compatibility validation cg.add(var.set_expose_log(config[CONF_LOG])) if config[CONF_ENABLE_PRIVATE_NETWORK_ACCESS]: cg.add_define("USE_WEBSERVER_PRIVATE_NETWORK_ACCESS") diff --git a/esphome/components/web_server/ota/__init__.py b/esphome/components/web_server/ota/__init__.py new file mode 100644 index 0000000000..3af14fd453 --- /dev/null +++ b/esphome/components/web_server/ota/__init__.py @@ -0,0 +1,32 @@ +import esphome.codegen as cg +from esphome.components.esp32 import add_idf_component +from esphome.components.ota import BASE_OTA_SCHEMA, OTAComponent, ota_to_code +import esphome.config_validation as cv +from esphome.const import CONF_ID +from esphome.core import CORE, coroutine_with_priority + +CODEOWNERS = ["@esphome/core"] +DEPENDENCIES = ["network", "web_server_base"] + +web_server_ns = cg.esphome_ns.namespace("web_server") +WebServerOTAComponent = web_server_ns.class_("WebServerOTAComponent", OTAComponent) + +CONFIG_SCHEMA = ( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(WebServerOTAComponent), + } + ) + .extend(BASE_OTA_SCHEMA) + .extend(cv.COMPONENT_SCHEMA) +) + + +@coroutine_with_priority(52.0) +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await ota_to_code(var, config) + await cg.register_component(var, config) + cg.add_define("USE_WEBSERVER_OTA") + if CORE.using_esp_idf: + add_idf_component(name="zorxx/multipart-parser", ref="1.0.1") diff --git a/esphome/components/web_server/ota/ota_web_server.cpp b/esphome/components/web_server/ota/ota_web_server.cpp new file mode 100644 index 0000000000..4f8f6fda17 --- /dev/null +++ b/esphome/components/web_server/ota/ota_web_server.cpp @@ -0,0 +1,210 @@ +#include "ota_web_server.h" +#ifdef USE_WEBSERVER_OTA + +#include "esphome/components/ota/ota_backend.h" +#include "esphome/core/application.h" +#include "esphome/core/log.h" + +#ifdef USE_ARDUINO +#ifdef USE_ESP8266 +#include +#elif defined(USE_ESP32) || defined(USE_LIBRETINY) +#include +#endif +#endif // USE_ARDUINO + +namespace esphome { +namespace web_server { + +static const char *const TAG = "web_server.ota"; + +class OTARequestHandler : public AsyncWebHandler { + public: + OTARequestHandler(WebServerOTAComponent *parent) : parent_(parent) {} + void handleRequest(AsyncWebServerRequest *request) override; + void handleUpload(AsyncWebServerRequest *request, const String &filename, size_t index, uint8_t *data, size_t len, + bool final) override; + bool canHandle(AsyncWebServerRequest *request) const override { + return request->url() == "/update" && request->method() == HTTP_POST; + } + + // NOLINTNEXTLINE(readability-identifier-naming) + bool isRequestHandlerTrivial() const override { return false; } + + protected: + void report_ota_progress_(AsyncWebServerRequest *request); + void schedule_ota_reboot_(); + void ota_init_(const char *filename); + + uint32_t last_ota_progress_{0}; + uint32_t ota_read_length_{0}; + WebServerOTAComponent *parent_; + bool ota_success_{false}; + + private: + std::unique_ptr ota_backend_{nullptr}; +}; + +void OTARequestHandler::report_ota_progress_(AsyncWebServerRequest *request) { + const uint32_t now = millis(); + if (now - this->last_ota_progress_ > 1000) { + float percentage = 0.0f; + if (request->contentLength() != 0) { + // Note: Using contentLength() for progress calculation is technically wrong as it includes + // multipart headers/boundaries, but it's only off by a small amount and we don't have + // access to the actual firmware size until the upload is complete. This is intentional + // as it still gives the user a reasonable progress indication. + percentage = (this->ota_read_length_ * 100.0f) / request->contentLength(); + ESP_LOGD(TAG, "OTA in progress: %0.1f%%", percentage); + } else { + ESP_LOGD(TAG, "OTA in progress: %u bytes read", this->ota_read_length_); + } +#ifdef USE_OTA_STATE_CALLBACK + // Report progress - use call_deferred since we're in web server task + this->parent_->state_callback_.call_deferred(ota::OTA_IN_PROGRESS, percentage, 0); +#endif + this->last_ota_progress_ = now; + } +} + +void OTARequestHandler::schedule_ota_reboot_() { + ESP_LOGI(TAG, "OTA update successful!"); + this->parent_->set_timeout(100, []() { + ESP_LOGI(TAG, "Performing OTA reboot now"); + App.safe_reboot(); + }); +} + +void OTARequestHandler::ota_init_(const char *filename) { + ESP_LOGI(TAG, "OTA Update Start: %s", filename); + this->ota_read_length_ = 0; + this->ota_success_ = false; +} + +void OTARequestHandler::handleUpload(AsyncWebServerRequest *request, const String &filename, size_t index, + uint8_t *data, size_t len, bool final) { + ota::OTAResponseTypes error_code = ota::OTA_RESPONSE_OK; + + if (index == 0 && !this->ota_backend_) { + // Initialize OTA on first call + this->ota_init_(filename.c_str()); + +#ifdef USE_OTA_STATE_CALLBACK + // Notify OTA started - use call_deferred since we're in web server task + this->parent_->state_callback_.call_deferred(ota::OTA_STARTED, 0.0f, 0); +#endif + + // Platform-specific pre-initialization +#ifdef USE_ARDUINO +#ifdef USE_ESP8266 + Update.runAsync(true); +#endif +#if defined(USE_ESP32) || defined(USE_LIBRETINY) + if (Update.isRunning()) { + Update.abort(); + } +#endif +#endif // USE_ARDUINO + + this->ota_backend_ = ota::make_ota_backend(); + if (!this->ota_backend_) { + ESP_LOGE(TAG, "Failed to create OTA backend"); +#ifdef USE_OTA_STATE_CALLBACK + this->parent_->state_callback_.call_deferred(ota::OTA_ERROR, 0.0f, + static_cast(ota::OTA_RESPONSE_ERROR_UNKNOWN)); +#endif + return; + } + + // Web server OTA uses multipart uploads where the actual firmware size + // is unknown (contentLength includes multipart overhead) + // Pass 0 to indicate unknown size + error_code = this->ota_backend_->begin(0); + if (error_code != ota::OTA_RESPONSE_OK) { + ESP_LOGE(TAG, "OTA begin failed: %d", error_code); + this->ota_backend_.reset(); +#ifdef USE_OTA_STATE_CALLBACK + this->parent_->state_callback_.call_deferred(ota::OTA_ERROR, 0.0f, static_cast(error_code)); +#endif + return; + } + } + + if (!this->ota_backend_) { + return; + } + + // Process data + if (len > 0) { + error_code = this->ota_backend_->write(data, len); + if (error_code != ota::OTA_RESPONSE_OK) { + ESP_LOGE(TAG, "OTA write failed: %d", error_code); + this->ota_backend_->abort(); + this->ota_backend_.reset(); +#ifdef USE_OTA_STATE_CALLBACK + this->parent_->state_callback_.call_deferred(ota::OTA_ERROR, 0.0f, static_cast(error_code)); +#endif + return; + } + this->ota_read_length_ += len; + this->report_ota_progress_(request); + } + + // Finalize + if (final) { + ESP_LOGD(TAG, "OTA final chunk: index=%u, len=%u, total_read=%u, contentLength=%u", index, len, + this->ota_read_length_, request->contentLength()); + + // For Arduino framework, the Update library tracks expected size from firmware header + // If we haven't received enough data, calling end() will fail + // This can happen if the upload is interrupted or the client disconnects + error_code = this->ota_backend_->end(); + if (error_code == ota::OTA_RESPONSE_OK) { + this->ota_success_ = true; +#ifdef USE_OTA_STATE_CALLBACK + // Report completion before reboot - use call_deferred since we're in web server task + this->parent_->state_callback_.call_deferred(ota::OTA_COMPLETED, 100.0f, 0); +#endif + this->schedule_ota_reboot_(); + } else { + ESP_LOGE(TAG, "OTA end failed: %d", error_code); +#ifdef USE_OTA_STATE_CALLBACK + this->parent_->state_callback_.call_deferred(ota::OTA_ERROR, 0.0f, static_cast(error_code)); +#endif + } + this->ota_backend_.reset(); + } +} + +void OTARequestHandler::handleRequest(AsyncWebServerRequest *request) { + AsyncWebServerResponse *response; + // Use the ota_success_ flag to determine the actual result + const char *msg = this->ota_success_ ? "Update Successful!" : "Update Failed!"; + response = request->beginResponse(200, "text/plain", msg); + response->addHeader("Connection", "close"); + request->send(response); +} + +void WebServerOTAComponent::setup() { + // Get the global web server base instance and register our handler + auto *base = web_server_base::global_web_server_base; + if (base == nullptr) { + ESP_LOGE(TAG, "WebServerBase not found"); + this->mark_failed(); + return; + } + + // AsyncWebServer takes ownership of the handler and will delete it when the server is destroyed + base->add_handler(new OTARequestHandler(this)); // NOLINT +#ifdef USE_OTA_STATE_CALLBACK + // Register with global OTA callback system + ota::register_ota_platform(this); +#endif +} + +void WebServerOTAComponent::dump_config() { ESP_LOGCONFIG(TAG, "Web Server OTA"); } + +} // namespace web_server +} // namespace esphome + +#endif // USE_WEBSERVER_OTA diff --git a/esphome/components/web_server/ota/ota_web_server.h b/esphome/components/web_server/ota/ota_web_server.h new file mode 100644 index 0000000000..a7170c0e34 --- /dev/null +++ b/esphome/components/web_server/ota/ota_web_server.h @@ -0,0 +1,26 @@ +#pragma once + +#include "esphome/core/defines.h" +#ifdef USE_WEBSERVER_OTA + +#include "esphome/components/ota/ota_backend.h" +#include "esphome/components/web_server_base/web_server_base.h" +#include "esphome/core/component.h" + +namespace esphome { +namespace web_server { + +class WebServerOTAComponent : public ota::OTAComponent { + public: + void setup() override; + void dump_config() override; + float get_setup_priority() const override { return setup_priority::AFTER_WIFI; } + + protected: + friend class OTARequestHandler; +}; + +} // namespace web_server +} // namespace esphome + +#endif // USE_WEBSERVER_OTA diff --git a/esphome/components/web_server/web_server.cpp b/esphome/components/web_server/web_server.cpp index 669bfbf279..d5ded2a02c 100644 --- a/esphome/components/web_server/web_server.cpp +++ b/esphome/components/web_server/web_server.cpp @@ -273,7 +273,11 @@ std::string WebServer::get_config_json() { return json::build_json([this](JsonObject root) { root["title"] = App.get_friendly_name().empty() ? App.get_name() : App.get_friendly_name(); root["comment"] = App.get_comment(); - root["ota"] = this->allow_ota_; +#ifdef USE_WEBSERVER_OTA + root["ota"] = true; // web_server OTA platform is configured +#else + root["ota"] = false; +#endif root["log"] = this->expose_log_; root["lang"] = "en"; }); @@ -299,8 +303,7 @@ void WebServer::setup() { #endif this->base_->add_handler(this); - if (this->allow_ota_) - this->base_->add_ota_handler(); + // OTA is now handled by the web_server OTA platform // doesn't need defer functionality - if the queue is full, the client JS knows it's alive because it's clearly // getting a lot of events @@ -2030,6 +2033,10 @@ void WebServer::handleRequest(AsyncWebServerRequest *request) { return; } #endif + + // No matching handler found - send 404 + ESP_LOGV(TAG, "Request for unknown URL: %s", request->url().c_str()); + request->send(404, "text/plain", "Not Found"); } bool WebServer::isRequestHandlerTrivial() const { return false; } diff --git a/esphome/components/web_server/web_server.h b/esphome/components/web_server/web_server.h index 991bca6fa7..5f175b6bdd 100644 --- a/esphome/components/web_server/web_server.h +++ b/esphome/components/web_server/web_server.h @@ -212,11 +212,6 @@ class WebServer : public Controller, public Component, public AsyncWebHandler { * @param include_internal Whether internal components should be displayed. */ void set_include_internal(bool include_internal) { include_internal_ = include_internal; } - /** Set whether or not the webserver should expose the OTA form and handler. - * - * @param allow_ota. - */ - void set_allow_ota(bool allow_ota) { this->allow_ota_ = allow_ota; } /** Set whether or not the webserver should expose the Log. * * @param expose_log. @@ -525,7 +520,6 @@ class WebServer : public Controller, public Component, public AsyncWebHandler { #ifdef USE_WEBSERVER_JS_INCLUDE const char *js_include_{nullptr}; #endif - bool allow_ota_{true}; bool expose_log_{true}; #ifdef USE_ESP32 std::deque> to_schedule_; diff --git a/esphome/components/web_server/web_server_v1.cpp b/esphome/components/web_server/web_server_v1.cpp index c9b38a2dc4..5db0f1cae9 100644 --- a/esphome/components/web_server/web_server_v1.cpp +++ b/esphome/components/web_server/web_server_v1.cpp @@ -192,11 +192,10 @@ void WebServer::handle_index_request(AsyncWebServerRequest *request) { stream->print(F("

See ESPHome Web API for " "REST API documentation.

")); - if (this->allow_ota_) { - stream->print( - F("

OTA Update

")); - } +#ifdef USE_WEBSERVER_OTA + stream->print(F("

OTA Update

")); +#endif stream->print(F("

Debug Log

"));
 #ifdef USE_WEBSERVER_JS_INCLUDE
   if (this->js_include_ != nullptr) {
diff --git a/esphome/components/web_server_base/__init__.py b/esphome/components/web_server_base/__init__.py
index c17bab2128..754bf7d433 100644
--- a/esphome/components/web_server_base/__init__.py
+++ b/esphome/components/web_server_base/__init__.py
@@ -30,6 +30,7 @@ CONFIG_SCHEMA = cv.Schema(
 async def to_code(config):
     var = cg.new_Pvariable(config[CONF_ID])
     await cg.register_component(var, config)
+    cg.add(cg.RawExpression(f"{web_server_base_ns}::global_web_server_base = {var}"))
 
     if CORE.using_arduino:
         if CORE.is_esp32:
diff --git a/esphome/components/web_server_base/web_server_base.cpp b/esphome/components/web_server_base/web_server_base.cpp
index 2835585387..e1c2bc0b25 100644
--- a/esphome/components/web_server_base/web_server_base.cpp
+++ b/esphome/components/web_server_base/web_server_base.cpp
@@ -4,21 +4,13 @@
 #include "esphome/core/helpers.h"
 #include "esphome/core/log.h"
 
-#ifdef USE_ARDUINO
-#include 
-#if defined(USE_ESP32) || defined(USE_LIBRETINY)
-#include 
-#endif
-#ifdef USE_ESP8266
-#include 
-#endif
-#endif
-
 namespace esphome {
 namespace web_server_base {
 
 static const char *const TAG = "web_server_base";
 
+WebServerBase *global_web_server_base = nullptr;  // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
+
 void WebServerBase::add_handler(AsyncWebHandler *handler) {
   // remove all handlers
 
@@ -31,90 +23,6 @@ void WebServerBase::add_handler(AsyncWebHandler *handler) {
   }
 }
 
-void report_ota_error() {
-#ifdef USE_ARDUINO
-  StreamString ss;
-  Update.printError(ss);
-  ESP_LOGW(TAG, "OTA Update failed! Error: %s", ss.c_str());
-#endif
-}
-
-void OTARequestHandler::handleUpload(AsyncWebServerRequest *request, const String &filename, size_t index,
-                                     uint8_t *data, size_t len, bool final) {
-#ifdef USE_ARDUINO
-  bool success;
-  if (index == 0) {
-    ESP_LOGI(TAG, "OTA Update Start: %s", filename.c_str());
-    this->ota_read_length_ = 0;
-#ifdef USE_ESP8266
-    Update.runAsync(true);
-    // NOLINTNEXTLINE(readability-static-accessed-through-instance)
-    success = Update.begin((ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000);
-#endif
-#if defined(USE_ESP32_FRAMEWORK_ARDUINO) || defined(USE_LIBRETINY)
-    if (Update.isRunning()) {
-      Update.abort();
-    }
-    success = Update.begin(UPDATE_SIZE_UNKNOWN, U_FLASH);
-#endif
-    if (!success) {
-      report_ota_error();
-      return;
-    }
-  } else if (Update.hasError()) {
-    // don't spam logs with errors if something failed at start
-    return;
-  }
-
-  success = Update.write(data, len) == len;
-  if (!success) {
-    report_ota_error();
-    return;
-  }
-  this->ota_read_length_ += len;
-
-  const uint32_t now = millis();
-  if (now - this->last_ota_progress_ > 1000) {
-    if (request->contentLength() != 0) {
-      float percentage = (this->ota_read_length_ * 100.0f) / request->contentLength();
-      ESP_LOGD(TAG, "OTA in progress: %0.1f%%", percentage);
-    } else {
-      ESP_LOGD(TAG, "OTA in progress: %u bytes read", this->ota_read_length_);
-    }
-    this->last_ota_progress_ = now;
-  }
-
-  if (final) {
-    if (Update.end(true)) {
-      ESP_LOGI(TAG, "OTA update successful!");
-      this->parent_->set_timeout(100, []() { App.safe_reboot(); });
-    } else {
-      report_ota_error();
-    }
-  }
-#endif
-}
-void OTARequestHandler::handleRequest(AsyncWebServerRequest *request) {
-#ifdef USE_ARDUINO
-  AsyncWebServerResponse *response;
-  if (!Update.hasError()) {
-    response = request->beginResponse(200, "text/plain", "Update Successful!");
-  } else {
-    StreamString ss;
-    ss.print("Update Failed: ");
-    Update.printError(ss);
-    response = request->beginResponse(200, "text/plain", ss);
-  }
-  response->addHeader("Connection", "close");
-  request->send(response);
-#endif
-}
-
-void WebServerBase::add_ota_handler() {
-#ifdef USE_ARDUINO
-  this->add_handler(new OTARequestHandler(this));  // NOLINT
-#endif
-}
 float WebServerBase::get_setup_priority() const {
   // Before WiFi (captive portal)
   return setup_priority::WIFI + 2.0f;
diff --git a/esphome/components/web_server_base/web_server_base.h b/esphome/components/web_server_base/web_server_base.h
index 641006cb99..a475238a37 100644
--- a/esphome/components/web_server_base/web_server_base.h
+++ b/esphome/components/web_server_base/web_server_base.h
@@ -17,6 +17,9 @@
 namespace esphome {
 namespace web_server_base {
 
+class WebServerBase;
+extern WebServerBase *global_web_server_base;  // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
+
 namespace internal {
 
 class MiddlewareHandler : public AsyncWebHandler {
@@ -110,14 +113,10 @@ class WebServerBase : public Component {
 
   void add_handler(AsyncWebHandler *handler);
 
-  void add_ota_handler();
-
   void set_port(uint16_t port) { port_ = port; }
   uint16_t get_port() const { return port_; }
 
  protected:
-  friend class OTARequestHandler;
-
   int initialized_{0};
   uint16_t port_{80};
   std::shared_ptr server_{nullptr};
@@ -125,25 +124,6 @@ class WebServerBase : public Component {
   internal::Credentials credentials_;
 };
 
-class OTARequestHandler : public AsyncWebHandler {
- public:
-  OTARequestHandler(WebServerBase *parent) : parent_(parent) {}
-  void handleRequest(AsyncWebServerRequest *request) override;
-  void handleUpload(AsyncWebServerRequest *request, const String &filename, size_t index, uint8_t *data, size_t len,
-                    bool final) override;
-  bool canHandle(AsyncWebServerRequest *request) const override {
-    return request->url() == "/update" && request->method() == HTTP_POST;
-  }
-
-  // NOLINTNEXTLINE(readability-identifier-naming)
-  bool isRequestHandlerTrivial() const override { return false; }
-
- protected:
-  uint32_t last_ota_progress_{0};
-  uint32_t ota_read_length_{0};
-  WebServerBase *parent_;
-};
-
 }  // namespace web_server_base
 }  // namespace esphome
 #endif
diff --git a/esphome/components/web_server_idf/multipart.cpp b/esphome/components/web_server_idf/multipart.cpp
new file mode 100644
index 0000000000..8655226ab9
--- /dev/null
+++ b/esphome/components/web_server_idf/multipart.cpp
@@ -0,0 +1,254 @@
+#include "esphome/core/defines.h"
+#if defined(USE_ESP_IDF) && defined(USE_WEBSERVER_OTA)
+#include "multipart.h"
+#include "utils.h"
+#include "esphome/core/log.h"
+#include 
+#include "multipart_parser.h"
+
+namespace esphome {
+namespace web_server_idf {
+
+static const char *const TAG = "multipart";
+
+// ========== MultipartReader Implementation ==========
+
+MultipartReader::MultipartReader(const std::string &boundary) {
+  // Initialize settings with callbacks
+  memset(&settings_, 0, sizeof(settings_));
+  settings_.on_header_field = on_header_field;
+  settings_.on_header_value = on_header_value;
+  settings_.on_part_data = on_part_data;
+  settings_.on_part_data_end = on_part_data_end;
+
+  ESP_LOGV(TAG, "Initializing multipart parser with boundary: '%s' (len: %zu)", boundary.c_str(), boundary.length());
+
+  // Create parser with boundary
+  parser_ = multipart_parser_init(boundary.c_str(), &settings_);
+  if (parser_) {
+    multipart_parser_set_data(parser_, this);
+  } else {
+    ESP_LOGE(TAG, "Failed to initialize multipart parser");
+  }
+}
+
+MultipartReader::~MultipartReader() {
+  if (parser_) {
+    multipart_parser_free(parser_);
+  }
+}
+
+size_t MultipartReader::parse(const char *data, size_t len) {
+  if (!parser_) {
+    ESP_LOGE(TAG, "Parser not initialized");
+    return 0;
+  }
+
+  size_t parsed = multipart_parser_execute(parser_, data, len);
+
+  if (parsed != len) {
+    ESP_LOGW(TAG, "Parser consumed %zu of %zu bytes - possible error", parsed, len);
+  }
+
+  return parsed;
+}
+
+void MultipartReader::process_header_(const char *value, size_t length) {
+  // Process the completed header (field + value pair)
+  std::string value_str(value, length);
+
+  if (str_startswith_case_insensitive(current_header_field_, "content-disposition")) {
+    // Parse name and filename from Content-Disposition
+    current_part_.name = extract_header_param(value_str, "name");
+    current_part_.filename = extract_header_param(value_str, "filename");
+  } else if (str_startswith_case_insensitive(current_header_field_, "content-type")) {
+    current_part_.content_type = str_trim(value_str);
+  }
+
+  // Clear field for next header
+  current_header_field_.clear();
+}
+
+int MultipartReader::on_header_field(multipart_parser *parser, const char *at, size_t length) {
+  MultipartReader *reader = static_cast(multipart_parser_get_data(parser));
+  reader->current_header_field_.assign(at, length);
+  return 0;
+}
+
+int MultipartReader::on_header_value(multipart_parser *parser, const char *at, size_t length) {
+  MultipartReader *reader = static_cast(multipart_parser_get_data(parser));
+  reader->process_header_(at, length);
+  return 0;
+}
+
+int MultipartReader::on_part_data(multipart_parser *parser, const char *at, size_t length) {
+  MultipartReader *reader = static_cast(multipart_parser_get_data(parser));
+  // Only process file uploads
+  if (reader->has_file() && reader->data_callback_) {
+    // IMPORTANT: The 'at' pointer points to data within the parser's input buffer.
+    // This data is only valid during this callback. The callback handler MUST
+    // process or copy the data immediately - it cannot store the pointer for
+    // later use as the buffer will be overwritten.
+    reader->data_callback_(reinterpret_cast(at), length);
+  }
+  return 0;
+}
+
+int MultipartReader::on_part_data_end(multipart_parser *parser) {
+  MultipartReader *reader = static_cast(multipart_parser_get_data(parser));
+  ESP_LOGV(TAG, "Part data end");
+  if (reader->part_complete_callback_) {
+    reader->part_complete_callback_();
+  }
+  // Clear part info for next part
+  reader->current_part_ = Part{};
+  return 0;
+}
+
+// ========== Utility Functions ==========
+
+// Case-insensitive string prefix check
+bool str_startswith_case_insensitive(const std::string &str, const std::string &prefix) {
+  if (str.length() < prefix.length()) {
+    return false;
+  }
+  return str_ncmp_ci(str.c_str(), prefix.c_str(), prefix.length());
+}
+
+// Extract a parameter value from a header line
+// Handles both quoted and unquoted values
+std::string extract_header_param(const std::string &header, const std::string ¶m) {
+  size_t search_pos = 0;
+
+  while (search_pos < header.length()) {
+    // Look for param name
+    const char *found = stristr(header.c_str() + search_pos, param.c_str());
+    if (!found) {
+      return "";
+    }
+    size_t pos = found - header.c_str();
+
+    // Check if this is a word boundary (not part of another parameter)
+    if (pos > 0 && header[pos - 1] != ' ' && header[pos - 1] != ';' && header[pos - 1] != '\t') {
+      search_pos = pos + 1;
+      continue;
+    }
+
+    // Move past param name
+    pos += param.length();
+
+    // Skip whitespace and find '='
+    while (pos < header.length() && (header[pos] == ' ' || header[pos] == '\t')) {
+      pos++;
+    }
+
+    if (pos >= header.length() || header[pos] != '=') {
+      search_pos = pos;
+      continue;
+    }
+
+    pos++;  // Skip '='
+
+    // Skip whitespace after '='
+    while (pos < header.length() && (header[pos] == ' ' || header[pos] == '\t')) {
+      pos++;
+    }
+
+    if (pos >= header.length()) {
+      return "";
+    }
+
+    // Check if value is quoted
+    if (header[pos] == '"') {
+      pos++;
+      size_t end = header.find('"', pos);
+      if (end != std::string::npos) {
+        return header.substr(pos, end - pos);
+      }
+      // Malformed - no closing quote
+      return "";
+    }
+
+    // Unquoted value - find the end (semicolon, comma, or end of string)
+    size_t end = pos;
+    while (end < header.length() && header[end] != ';' && header[end] != ',' && header[end] != ' ' &&
+           header[end] != '\t') {
+      end++;
+    }
+
+    return header.substr(pos, end - pos);
+  }
+
+  return "";
+}
+
+// Parse boundary from Content-Type header
+// Returns true if boundary found, false otherwise
+// boundary_start and boundary_len will point to the boundary value
+bool parse_multipart_boundary(const char *content_type, const char **boundary_start, size_t *boundary_len) {
+  if (!content_type) {
+    return false;
+  }
+
+  // Check for multipart/form-data (case-insensitive)
+  if (!stristr(content_type, "multipart/form-data")) {
+    return false;
+  }
+
+  // Look for boundary parameter
+  const char *b = stristr(content_type, "boundary=");
+  if (!b) {
+    return false;
+  }
+
+  const char *start = b + 9;  // Skip "boundary="
+
+  // Skip whitespace
+  while (*start == ' ' || *start == '\t') {
+    start++;
+  }
+
+  if (!*start) {
+    return false;
+  }
+
+  // Find end of boundary
+  const char *end = start;
+  if (*end == '"') {
+    // Quoted boundary
+    start++;
+    end++;
+    while (*end && *end != '"') {
+      end++;
+    }
+    *boundary_len = end - start;
+  } else {
+    // Unquoted boundary
+    while (*end && *end != ' ' && *end != ';' && *end != '\r' && *end != '\n' && *end != '\t') {
+      end++;
+    }
+    *boundary_len = end - start;
+  }
+
+  if (*boundary_len == 0) {
+    return false;
+  }
+
+  *boundary_start = start;
+
+  return true;
+}
+
+// Trim whitespace from both ends of a string
+std::string str_trim(const std::string &str) {
+  size_t start = str.find_first_not_of(" \t\r\n");
+  if (start == std::string::npos) {
+    return "";
+  }
+  size_t end = str.find_last_not_of(" \t\r\n");
+  return str.substr(start, end - start + 1);
+}
+
+}  // namespace web_server_idf
+}  // namespace esphome
+#endif  // defined(USE_ESP_IDF) && defined(USE_WEBSERVER_OTA)
diff --git a/esphome/components/web_server_idf/multipart.h b/esphome/components/web_server_idf/multipart.h
new file mode 100644
index 0000000000..967c72ffa5
--- /dev/null
+++ b/esphome/components/web_server_idf/multipart.h
@@ -0,0 +1,86 @@
+#pragma once
+#include "esphome/core/defines.h"
+#if defined(USE_ESP_IDF) && defined(USE_WEBSERVER_OTA)
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+namespace esphome {
+namespace web_server_idf {
+
+// Wrapper around zorxx/multipart-parser for ESP-IDF OTA uploads
+class MultipartReader {
+ public:
+  struct Part {
+    std::string name;
+    std::string filename;
+    std::string content_type;
+  };
+
+  // IMPORTANT: The data pointer in DataCallback is only valid during the callback!
+  // The multipart parser passes pointers to its internal buffer which will be
+  // overwritten after the callback returns. Callbacks MUST process or copy the
+  // data immediately - storing the pointer for deferred processing will result
+  // in use-after-free bugs.
+  using DataCallback = std::function;
+  using PartCompleteCallback = std::function;
+
+  explicit MultipartReader(const std::string &boundary);
+  ~MultipartReader();
+
+  // Set callbacks for handling data
+  void set_data_callback(DataCallback callback) { data_callback_ = std::move(callback); }
+  void set_part_complete_callback(PartCompleteCallback callback) { part_complete_callback_ = std::move(callback); }
+
+  // Parse incoming data
+  size_t parse(const char *data, size_t len);
+
+  // Get current part info
+  const Part &get_current_part() const { return current_part_; }
+
+  // Check if we found a file upload
+  bool has_file() const { return !current_part_.filename.empty(); }
+
+ private:
+  static int on_header_field(multipart_parser *parser, const char *at, size_t length);
+  static int on_header_value(multipart_parser *parser, const char *at, size_t length);
+  static int on_part_data(multipart_parser *parser, const char *at, size_t length);
+  static int on_part_data_end(multipart_parser *parser);
+
+  multipart_parser *parser_{nullptr};
+  multipart_parser_settings settings_{};
+
+  Part current_part_;
+  std::string current_header_field_;
+
+  DataCallback data_callback_;
+  PartCompleteCallback part_complete_callback_;
+
+  void process_header_(const char *value, size_t length);
+};
+
+// ========== Utility Functions ==========
+
+// Case-insensitive string prefix check
+bool str_startswith_case_insensitive(const std::string &str, const std::string &prefix);
+
+// Extract a parameter value from a header line
+// Handles both quoted and unquoted values
+std::string extract_header_param(const std::string &header, const std::string ¶m);
+
+// Parse boundary from Content-Type header
+// Returns true if boundary found, false otherwise
+// boundary_start and boundary_len will point to the boundary value
+bool parse_multipart_boundary(const char *content_type, const char **boundary_start, size_t *boundary_len);
+
+// Trim whitespace from both ends of a string
+std::string str_trim(const std::string &str);
+
+}  // namespace web_server_idf
+}  // namespace esphome
+#endif  // defined(USE_ESP_IDF) && defined(USE_WEBSERVER_OTA)
diff --git a/esphome/components/web_server_idf/utils.cpp b/esphome/components/web_server_idf/utils.cpp
index 349acce50d..ac5df90bb8 100644
--- a/esphome/components/web_server_idf/utils.cpp
+++ b/esphome/components/web_server_idf/utils.cpp
@@ -1,5 +1,7 @@
 #ifdef USE_ESP_IDF
 #include 
+#include 
+#include 
 #include "esphome/core/helpers.h"
 #include "esphome/core/log.h"
 #include "http_parser.h"
@@ -88,6 +90,36 @@ optional query_key_value(const std::string &query_url, const std::s
   return {val.get()};
 }
 
+// Helper function for case-insensitive string region comparison
+bool str_ncmp_ci(const char *s1, const char *s2, size_t n) {
+  for (size_t i = 0; i < n; i++) {
+    if (!char_equals_ci(s1[i], s2[i])) {
+      return false;
+    }
+  }
+  return true;
+}
+
+// Case-insensitive string search (like strstr but case-insensitive)
+const char *stristr(const char *haystack, const char *needle) {
+  if (!haystack) {
+    return nullptr;
+  }
+
+  size_t needle_len = strlen(needle);
+  if (needle_len == 0) {
+    return haystack;
+  }
+
+  for (const char *p = haystack; *p; p++) {
+    if (str_ncmp_ci(p, needle, needle_len)) {
+      return p;
+    }
+  }
+
+  return nullptr;
+}
+
 }  // namespace web_server_idf
 }  // namespace esphome
 #endif  // USE_ESP_IDF
diff --git a/esphome/components/web_server_idf/utils.h b/esphome/components/web_server_idf/utils.h
index 9ed17c1d50..988b962d72 100644
--- a/esphome/components/web_server_idf/utils.h
+++ b/esphome/components/web_server_idf/utils.h
@@ -2,6 +2,7 @@
 #ifdef USE_ESP_IDF
 
 #include 
+#include 
 #include "esphome/core/helpers.h"
 
 namespace esphome {
@@ -12,6 +13,15 @@ optional request_get_header(httpd_req_t *req, const char *name);
 optional request_get_url_query(httpd_req_t *req);
 optional query_key_value(const std::string &query_url, const std::string &key);
 
+// Helper function for case-insensitive character comparison
+inline bool char_equals_ci(char a, char b) { return ::tolower(a) == ::tolower(b); }
+
+// Helper function for case-insensitive string region comparison
+bool str_ncmp_ci(const char *s1, const char *s2, size_t n);
+
+// Case-insensitive string search (like strstr but case-insensitive)
+const char *stristr(const char *haystack, const char *needle);
+
 }  // namespace web_server_idf
 }  // namespace esphome
 #endif  // USE_ESP_IDF
diff --git a/esphome/components/web_server_idf/web_server_idf.cpp b/esphome/components/web_server_idf/web_server_idf.cpp
index 409230806c..9478e4748c 100644
--- a/esphome/components/web_server_idf/web_server_idf.cpp
+++ b/esphome/components/web_server_idf/web_server_idf.cpp
@@ -1,16 +1,25 @@
 #ifdef USE_ESP_IDF
 
 #include 
+#include 
+#include 
+#include 
 
 #include "esphome/core/helpers.h"
 #include "esphome/core/log.h"
 
 #include "esp_tls_crypto.h"
+#include 
+#include 
 
 #include "utils.h"
-
 #include "web_server_idf.h"
 
+#ifdef USE_WEBSERVER_OTA
+#include 
+#include "multipart.h"  // For parse_multipart_boundary and other utils
+#endif
+
 #ifdef USE_WEBSERVER
 #include "esphome/components/web_server/web_server.h"
 #include "esphome/components/web_server/list_entities.h"
@@ -72,18 +81,32 @@ void AsyncWebServer::begin() {
 esp_err_t AsyncWebServer::request_post_handler(httpd_req_t *r) {
   ESP_LOGVV(TAG, "Enter AsyncWebServer::request_post_handler. uri=%s", r->uri);
   auto content_type = request_get_header(r, "Content-Type");
-  if (content_type.has_value() && *content_type != "application/x-www-form-urlencoded") {
-    ESP_LOGW(TAG, "Only application/x-www-form-urlencoded supported for POST request");
-    // fallback to get handler to support backward compatibility
-    return AsyncWebServer::request_handler(r);
-  }
 
   if (!request_has_header(r, "Content-Length")) {
-    ESP_LOGW(TAG, "Content length is requred for post: %s", r->uri);
+    ESP_LOGW(TAG, "Content length is required for post: %s", r->uri);
     httpd_resp_send_err(r, HTTPD_411_LENGTH_REQUIRED, nullptr);
     return ESP_OK;
   }
 
+  if (content_type.has_value()) {
+    const char *content_type_char = content_type.value().c_str();
+
+    // Check most common case first
+    if (stristr(content_type_char, "application/x-www-form-urlencoded") != nullptr) {
+      // Normal form data - proceed with regular handling
+#ifdef USE_WEBSERVER_OTA
+    } else if (stristr(content_type_char, "multipart/form-data") != nullptr) {
+      auto *server = static_cast(r->user_ctx);
+      return server->handle_multipart_upload_(r, content_type_char);
+#endif
+    } else {
+      ESP_LOGW(TAG, "Unsupported content type for POST: %s", content_type_char);
+      // fallback to get handler to support backward compatibility
+      return AsyncWebServer::request_handler(r);
+    }
+  }
+
+  // Handle regular form data
   if (r->content_len > HTTPD_MAX_REQ_HDR_LEN) {
     ESP_LOGW(TAG, "Request size is to big: %zu", r->content_len);
     httpd_resp_send_err(r, HTTPD_400_BAD_REQUEST, nullptr);
@@ -539,6 +562,97 @@ void AsyncEventSourceResponse::deferrable_send_state(void *source, const char *e
 }
 #endif
 
+#ifdef USE_WEBSERVER_OTA
+esp_err_t AsyncWebServer::handle_multipart_upload_(httpd_req_t *r, const char *content_type) {
+  static constexpr size_t MULTIPART_CHUNK_SIZE = 1460;       // Match Arduino AsyncWebServer buffer size
+  static constexpr size_t YIELD_INTERVAL_BYTES = 16 * 1024;  // Yield every 16KB to prevent watchdog
+
+  // Parse boundary and create reader
+  const char *boundary_start;
+  size_t boundary_len;
+  if (!parse_multipart_boundary(content_type, &boundary_start, &boundary_len)) {
+    ESP_LOGE(TAG, "Failed to parse multipart boundary");
+    httpd_resp_send_err(r, HTTPD_400_BAD_REQUEST, nullptr);
+    return ESP_FAIL;
+  }
+
+  AsyncWebServerRequest req(r);
+  AsyncWebHandler *handler = nullptr;
+  for (auto *h : this->handlers_) {
+    if (h->canHandle(&req)) {
+      handler = h;
+      break;
+    }
+  }
+
+  if (!handler) {
+    ESP_LOGW(TAG, "No handler found for OTA request");
+    httpd_resp_send_err(r, HTTPD_404_NOT_FOUND, nullptr);
+    return ESP_OK;
+  }
+
+  // Upload state
+  std::string filename;
+  size_t index = 0;
+  // Create reader on heap to reduce stack usage
+  auto reader = std::make_unique("--" + std::string(boundary_start, boundary_len));
+
+  // Configure callbacks
+  reader->set_data_callback([&](const uint8_t *data, size_t len) {
+    if (!reader->has_file() || !len)
+      return;
+
+    if (filename.empty()) {
+      filename = reader->get_current_part().filename;
+      ESP_LOGV(TAG, "Processing file: '%s'", filename.c_str());
+      handler->handleUpload(&req, filename, 0, nullptr, 0, false);  // Start
+    }
+
+    handler->handleUpload(&req, filename, index, const_cast(data), len, false);
+    index += len;
+  });
+
+  reader->set_part_complete_callback([&]() {
+    if (index > 0) {
+      handler->handleUpload(&req, filename, index, nullptr, 0, true);  // End
+      filename.clear();
+      index = 0;
+    }
+  });
+
+  // Process data
+  std::unique_ptr buffer(new char[MULTIPART_CHUNK_SIZE]);
+  size_t bytes_since_yield = 0;
+
+  for (size_t remaining = r->content_len; remaining > 0;) {
+    int recv_len = httpd_req_recv(r, buffer.get(), std::min(remaining, MULTIPART_CHUNK_SIZE));
+
+    if (recv_len <= 0) {
+      httpd_resp_send_err(r, recv_len == HTTPD_SOCK_ERR_TIMEOUT ? HTTPD_408_REQ_TIMEOUT : HTTPD_400_BAD_REQUEST,
+                          nullptr);
+      return recv_len == HTTPD_SOCK_ERR_TIMEOUT ? ESP_ERR_TIMEOUT : ESP_FAIL;
+    }
+
+    if (reader->parse(buffer.get(), recv_len) != static_cast(recv_len)) {
+      ESP_LOGW(TAG, "Multipart parser error");
+      httpd_resp_send_err(r, HTTPD_400_BAD_REQUEST, nullptr);
+      return ESP_FAIL;
+    }
+
+    remaining -= recv_len;
+    bytes_since_yield += recv_len;
+
+    if (bytes_since_yield > YIELD_INTERVAL_BYTES) {
+      vTaskDelay(1);
+      bytes_since_yield = 0;
+    }
+  }
+
+  handler->handleRequest(&req);
+  return ESP_OK;
+}
+#endif  // USE_WEBSERVER_OTA
+
 }  // namespace web_server_idf
 }  // namespace esphome
 
diff --git a/esphome/components/web_server_idf/web_server_idf.h b/esphome/components/web_server_idf/web_server_idf.h
index 7547117224..8de25c8e96 100644
--- a/esphome/components/web_server_idf/web_server_idf.h
+++ b/esphome/components/web_server_idf/web_server_idf.h
@@ -204,6 +204,9 @@ class AsyncWebServer {
   static esp_err_t request_handler(httpd_req_t *r);
   static esp_err_t request_post_handler(httpd_req_t *r);
   esp_err_t request_handler_(AsyncWebServerRequest *request) const;
+#ifdef USE_WEBSERVER_OTA
+  esp_err_t handle_multipart_upload_(httpd_req_t *r, const char *content_type);
+#endif
   std::vector handlers_;
   std::function on_not_found_{};
 };
diff --git a/esphome/components/wireguard/__init__.py b/esphome/components/wireguard/__init__.py
index fc0e4e0538..8eff8e7b2a 100644
--- a/esphome/components/wireguard/__init__.py
+++ b/esphome/components/wireguard/__init__.py
@@ -6,14 +6,7 @@ import esphome.codegen as cg
 from esphome.components import time
 from esphome.components.esp32 import CORE, add_idf_sdkconfig_option
 import esphome.config_validation as cv
-from esphome.const import (
-    CONF_ADDRESS,
-    CONF_ID,
-    CONF_REBOOT_TIMEOUT,
-    CONF_TIME_ID,
-    KEY_CORE,
-    KEY_FRAMEWORK_VERSION,
-)
+from esphome.const import CONF_ADDRESS, CONF_ID, CONF_REBOOT_TIMEOUT, CONF_TIME_ID
 from esphome.core import TimePeriod
 
 CONF_NETMASK = "netmask"
@@ -125,9 +118,7 @@ async def to_code(config):
 
     # Workaround for crash on IDF 5+
     # See https://github.com/trombik/esp_wireguard/issues/33#issuecomment-1568503651
-    if CORE.using_esp_idf and CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION] >= cv.Version(
-        5, 0, 0
-    ):
+    if CORE.using_esp_idf:
         add_idf_sdkconfig_option("CONFIG_LWIP_PPP_SUPPORT", True)
 
     # This flag is added here because the esp_wireguard library statically
diff --git a/esphome/config.py b/esphome/config.py
index ca3686a0e6..c4aa9aea24 100644
--- a/esphome/config.py
+++ b/esphome/config.py
@@ -67,6 +67,42 @@ ConfigPath = list[str | int]
 path_context = contextvars.ContextVar("Config path")
 
 
+def _process_platform_config(
+    result: Config,
+    component_name: str,
+    platform_name: str,
+    platform_config: ConfigType,
+    path: ConfigPath,
+) -> None:
+    """Process a platform configuration and add necessary validation steps.
+
+    This is shared between LoadValidationStep and AutoLoadValidationStep to avoid duplication.
+    """
+    # Get the platform manifest
+    platform = get_platform(component_name, platform_name)
+    if platform is None:
+        result.add_str_error(
+            f"Platform not found: '{component_name}.{platform_name}'", path
+        )
+        return
+
+    # Add platform to loaded integrations
+    CORE.loaded_integrations.add(platform_name)
+    CORE.loaded_platforms.add(f"{component_name}/{platform_name}")
+
+    # Process platform's AUTO_LOAD
+    for load in platform.auto_load:
+        if load not in result:
+            result.add_validation_step(AutoLoadValidationStep(load))
+
+    # Add validation steps for the platform
+    p_domain = f"{component_name}.{platform_name}"
+    result.add_output_path(path, p_domain)
+    result.add_validation_step(
+        MetadataValidationStep(path, p_domain, platform_config, platform)
+    )
+
+
 def _path_begins_with(path: ConfigPath, other: ConfigPath) -> bool:
     if len(path) < len(other):
         return False
@@ -379,26 +415,11 @@ class LoadValidationStep(ConfigValidationStep):
                     path,
                 )
                 continue
-            # Remove temp output path and construct new one
+            # Remove temp output path
             result.remove_output_path(path, p_domain)
-            p_domain = f"{self.domain}.{p_name}"
-            result.add_output_path(path, p_domain)
-            # Try Load platform
-            platform = get_platform(self.domain, p_name)
-            if platform is None:
-                result.add_str_error(f"Platform not found: '{p_domain}'", path)
-                continue
-            CORE.loaded_integrations.add(p_name)
-            CORE.loaded_platforms.add(f"{self.domain}/{p_name}")
 
-            # Process AUTO_LOAD
-            for load in platform.auto_load:
-                if load not in result:
-                    result.add_validation_step(AutoLoadValidationStep(load))
-
-            result.add_validation_step(
-                MetadataValidationStep(path, p_domain, p_config, platform)
-            )
+            # Process the platform configuration
+            _process_platform_config(result, self.domain, p_name, p_config, path)
 
 
 class AutoLoadValidationStep(ConfigValidationStep):
@@ -413,10 +434,56 @@ class AutoLoadValidationStep(ConfigValidationStep):
         self.domain = domain
 
     def run(self, result: Config) -> None:
-        if self.domain in result:
-            # already loaded
+        # Regular component auto-load (no platform)
+        if "." not in self.domain:
+            if self.domain in result:
+                # already loaded
+                return
+            result.add_validation_step(LoadValidationStep(self.domain, core.AutoLoad()))
             return
-        result.add_validation_step(LoadValidationStep(self.domain, core.AutoLoad()))
+
+        # Platform-specific auto-load (e.g., "ota.web_server")
+        component_name, _, platform_name = self.domain.partition(".")
+
+        # Check if component exists
+        if component_name not in result:
+            # Component doesn't exist, load it first
+            result.add_validation_step(LoadValidationStep(component_name, []))
+            # Re-run this step after the component is loaded
+            result.add_validation_step(AutoLoadValidationStep(self.domain))
+            return
+
+        # Component exists, check if it's a platform component
+        component = get_component(component_name)
+        if component is None or not component.is_platform_component:
+            result.add_str_error(
+                f"Component {component_name} is not a platform component, "
+                f"cannot auto-load platform {platform_name}",
+                [component_name],
+            )
+            return
+
+        # Ensure the component config is a list
+        component_conf = result.get(component_name)
+        if not isinstance(component_conf, list):
+            component_conf = result[component_name] = []
+
+        # Check if platform already exists
+        if any(
+            isinstance(conf, dict) and conf.get(CONF_PLATFORM) == platform_name
+            for conf in component_conf
+        ):
+            return
+
+        # Add and process the platform configuration
+        platform_conf = core.AutoLoad()
+        platform_conf[CONF_PLATFORM] = platform_name
+        component_conf.append(platform_conf)
+
+        path = [component_name, len(component_conf) - 1]
+        _process_platform_config(
+            result, component_name, platform_name, platform_conf, path
+        )
 
 
 class MetadataValidationStep(ConfigValidationStep):
@@ -789,7 +856,6 @@ def validate_config(
         result.add_output_path([CONF_SUBSTITUTIONS], CONF_SUBSTITUTIONS)
         try:
             substitutions.do_substitution_pass(config, command_line_substitutions)
-            substitutions.do_substitution_pass(config, command_line_substitutions)
         except vol.Invalid as err:
             result.add_error(err)
             return result
diff --git a/esphome/const.py b/esphome/const.py
index b167935d12..4aeb5179e6 100644
--- a/esphome/const.py
+++ b/esphome/const.py
@@ -654,6 +654,7 @@ CONF_PAYLOAD = "payload"
 CONF_PAYLOAD_AVAILABLE = "payload_available"
 CONF_PAYLOAD_NOT_AVAILABLE = "payload_not_available"
 CONF_PERIOD = "period"
+CONF_PERMITTIVITY = "permittivity"
 CONF_PH = "ph"
 CONF_PHASE_A = "phase_a"
 CONF_PHASE_ANGLE = "phase_angle"
diff --git a/esphome/core/application.cpp b/esphome/core/application.cpp
index 1599c648e7..d6fab018cc 100644
--- a/esphome/core/application.cpp
+++ b/esphome/core/application.cpp
@@ -84,6 +84,10 @@ void Application::setup() {
   }
 
   ESP_LOGI(TAG, "setup() finished successfully!");
+
+  // Clear setup priority overrides to free memory
+  clear_setup_priority_overrides();
+
   this->schedule_dump_config();
   this->calculate_looping_components_();
 }
diff --git a/esphome/core/component.cpp b/esphome/core/component.cpp
index 6661223e35..aba5dc729c 100644
--- a/esphome/core/component.cpp
+++ b/esphome/core/component.cpp
@@ -2,7 +2,9 @@
 
 #include 
 #include 
+#include 
 #include 
+#include 
 #include "esphome/core/application.h"
 #include "esphome/core/hal.h"
 #include "esphome/core/helpers.h"
@@ -12,6 +14,30 @@ namespace esphome {
 
 static const char *const TAG = "component";
 
+// Global vectors for component data that doesn't belong in every instance.
+// Using vector instead of unordered_map for both because:
+// - Much lower memory overhead (8 bytes per entry vs 20+ for unordered_map)
+// - Linear search is fine for small n (typically < 5 entries)
+// - These are rarely accessed (setup only or error cases only)
+
+// Component error messages - only stores messages for failed components
+// Lazy allocated since most configs have zero failures
+// Note: We don't clear this vector because:
+// 1. Components are never destroyed in ESPHome
+// 2. Failed components remain failed (no recovery mechanism)
+// 3. Memory usage is minimal (only failures with custom messages are stored)
+static std::unique_ptr>> &get_component_error_messages() {
+  static std::unique_ptr>> instance;
+  return instance;
+}
+
+// Setup priority overrides - freed after setup completes
+// Typically < 5 entries, lazy allocated
+static std::unique_ptr>> &get_setup_priority_overrides() {
+  static std::unique_ptr>> instance;
+  return instance;
+}
+
 namespace setup_priority {
 
 const float BUS = 1000.0f;
@@ -102,8 +128,17 @@ void Component::call_setup() { this->setup(); }
 void Component::call_dump_config() {
   this->dump_config();
   if (this->is_failed()) {
-    ESP_LOGE(TAG, "  Component %s is marked FAILED: %s", this->get_component_source(),
-             this->error_message_ ? this->error_message_ : "unspecified");
+    // Look up error message from global vector
+    const char *error_msg = "unspecified";
+    if (get_component_error_messages()) {
+      for (const auto &pair : *get_component_error_messages()) {
+        if (pair.first == this) {
+          error_msg = pair.second;
+          break;
+        }
+      }
+    }
+    ESP_LOGE(TAG, "  Component %s is marked FAILED: %s", this->get_component_source(), error_msg);
   }
 }
 
@@ -245,8 +280,21 @@ void Component::status_set_error(const char *message) {
   this->component_state_ |= STATUS_LED_ERROR;
   App.app_state_ |= STATUS_LED_ERROR;
   ESP_LOGE(TAG, "Component %s set Error flag: %s", this->get_component_source(), message);
-  if (strcmp(message, "unspecified") != 0)
-    this->error_message_ = message;
+  if (strcmp(message, "unspecified") != 0) {
+    // Lazy allocate the error messages vector if needed
+    if (!get_component_error_messages()) {
+      get_component_error_messages() = std::make_unique>>();
+    }
+    // Check if this component already has an error message
+    for (auto &pair : *get_component_error_messages()) {
+      if (pair.first == this) {
+        pair.second = message;
+        return;
+      }
+    }
+    // Add new error message
+    get_component_error_messages()->emplace_back(this, message);
+  }
 }
 void Component::status_clear_warning() {
   if ((this->component_state_ & STATUS_LED_WARNING) == 0)
@@ -270,11 +318,36 @@ void Component::status_momentary_error(const std::string &name, uint32_t length)
 }
 void Component::dump_config() {}
 float Component::get_actual_setup_priority() const {
-  if (std::isnan(this->setup_priority_override_))
-    return this->get_setup_priority();
-  return this->setup_priority_override_;
+  // Check if there's an override in the global vector
+  if (get_setup_priority_overrides()) {
+    // Linear search is fine for small n (typically < 5 overrides)
+    for (const auto &pair : *get_setup_priority_overrides()) {
+      if (pair.first == this) {
+        return pair.second;
+      }
+    }
+  }
+  return this->get_setup_priority();
+}
+void Component::set_setup_priority(float priority) {
+  // Lazy allocate the vector if needed
+  if (!get_setup_priority_overrides()) {
+    get_setup_priority_overrides() = std::make_unique>>();
+    // Reserve some space to avoid reallocations (most configs have < 10 overrides)
+    get_setup_priority_overrides()->reserve(10);
+  }
+
+  // Check if this component already has an override
+  for (auto &pair : *get_setup_priority_overrides()) {
+    if (pair.first == this) {
+      pair.second = priority;
+      return;
+    }
+  }
+
+  // Add new override
+  get_setup_priority_overrides()->emplace_back(this, priority);
 }
-void Component::set_setup_priority(float priority) { this->setup_priority_override_ = priority; }
 
 bool Component::has_overridden_loop() const {
 #if defined(USE_HOST) || defined(CLANG_TIDY)
@@ -336,4 +409,9 @@ uint32_t WarnIfComponentBlockingGuard::finish() {
 
 WarnIfComponentBlockingGuard::~WarnIfComponentBlockingGuard() {}
 
+void clear_setup_priority_overrides() {
+  // Free the setup priority map completely
+  get_setup_priority_overrides().reset();
+}
+
 }  // namespace esphome
diff --git a/esphome/core/component.h b/esphome/core/component.h
index 5b37deeb68..ab30466e2d 100644
--- a/esphome/core/component.h
+++ b/esphome/core/component.h
@@ -387,9 +387,7 @@ class Component {
   bool cancel_defer(const std::string &name);  // NOLINT
 
   // Ordered for optimal packing on 32-bit systems
-  float setup_priority_override_{NAN};
   const char *component_source_{nullptr};
-  const char *error_message_{nullptr};
   uint16_t warn_if_blocking_over_{WARN_IF_BLOCKING_OVER_MS};  ///< Warn if blocked for this many ms (max 65.5s)
   /// State of this component - each bit has a purpose:
   /// Bits 0-1: Component state (0x00=CONSTRUCTION, 0x01=SETUP, 0x02=LOOP, 0x03=FAILED)
@@ -459,4 +457,7 @@ class WarnIfComponentBlockingGuard {
   Component *component_;
 };
 
+// Function to clear setup priority overrides after all components are set up
+void clear_setup_priority_overrides();
+
 }  // namespace esphome
diff --git a/esphome/core/defines.h b/esphome/core/defines.h
index 5c0ecca663..4f3ce84399 100644
--- a/esphome/core/defines.h
+++ b/esphome/core/defines.h
@@ -117,6 +117,7 @@
 #define USE_OTA_PASSWORD
 #define USE_OTA_STATE_CALLBACK
 #define USE_OTA_VERSION 2
+#define USE_TIME_TIMEZONE
 #define USE_WIFI
 #define USE_WIFI_AP
 #define USE_WIREGUARD
@@ -153,6 +154,7 @@
 #define USE_SPI
 #define USE_VOICE_ASSISTANT
 #define USE_WEBSERVER
+#define USE_WEBSERVER_OTA
 #define USE_WEBSERVER_PORT 80  // NOLINT
 #define USE_WEBSERVER_SORTING
 #define USE_WIFI_11KV_SUPPORT
diff --git a/esphome/core/entity_helpers.py b/esphome/core/entity_helpers.py
index c95acebbf9..2442fbca4b 100644
--- a/esphome/core/entity_helpers.py
+++ b/esphome/core/entity_helpers.py
@@ -184,25 +184,27 @@ def entity_duplicate_validator(platform: str) -> Callable[[ConfigType], ConfigTy
             # No name to validate
             return config
 
-        # Get the entity name and device info
+        # Get the entity name
         entity_name = config[CONF_NAME]
-        device_id = ""  # Empty string for main device
 
+        # Get device name if entity is on a sub-device
+        device_name = None
         if CONF_DEVICE_ID in config:
             device_id_obj = config[CONF_DEVICE_ID]
-            # Use the device ID string directly for uniqueness
-            device_id = device_id_obj.id
+            device_name = device_id_obj.id
 
-        # For duplicate detection, just use the sanitized name
-        name_key = sanitize(snake_case(entity_name))
+        # Calculate what object_id will actually be used
+        # This handles empty names correctly by using device/friendly names
+        name_key = get_base_entity_object_id(
+            entity_name, CORE.friendly_name, device_name
+        )
 
         # Check for duplicates
-        unique_key = (device_id, platform, name_key)
+        unique_key = (platform, name_key)
         if unique_key in CORE.unique_ids:
-            device_prefix = f" on device '{device_id}'" if device_id else ""
             raise cv.Invalid(
-                f"Duplicate {platform} entity with name '{entity_name}' found{device_prefix}. "
-                f"Each entity on a device must have a unique name within its platform."
+                f"Duplicate {platform} entity with name '{entity_name}' found. "
+                f"Each entity must have a unique name within its platform across all devices."
             )
 
         # Add to tracking set
diff --git a/esphome/core/helpers.cpp b/esphome/core/helpers.cpp
index fc91d83972..b4923c7af0 100644
--- a/esphome/core/helpers.cpp
+++ b/esphome/core/helpers.cpp
@@ -4,13 +4,13 @@
 #include "esphome/core/hal.h"
 #include "esphome/core/log.h"
 
+#include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
-#include 
 
 #ifdef USE_HOST
 #ifndef _WIN32
@@ -43,10 +43,10 @@
 #include 
 #endif
 #ifdef USE_ESP32
-#include "rom/crc.h"
-#include "esp_mac.h"
 #include "esp_efuse.h"
 #include "esp_efuse_table.h"
+#include "esp_mac.h"
+#include "rom/crc.h"
 #endif
 
 #ifdef USE_LIBRETINY
@@ -393,6 +393,21 @@ std::string format_hex_pretty(const uint16_t *data, size_t length) {
   return ret;
 }
 std::string format_hex_pretty(const std::vector &data) { return format_hex_pretty(data.data(), data.size()); }
+std::string format_hex_pretty(const std::string &data) {
+  if (data.empty())
+    return "";
+  std::string ret;
+  ret.resize(3 * data.length() - 1);
+  for (size_t i = 0; i < data.length(); i++) {
+    ret[3 * i] = format_hex_pretty_char((data[i] & 0xF0) >> 4);
+    ret[3 * i + 1] = format_hex_pretty_char(data[i] & 0x0F);
+    if (i != data.length() - 1)
+      ret[3 * i + 2] = '.';
+  }
+  if (data.length() > 4)
+    return ret + " (" + std::to_string(data.length()) + ")";
+  return ret;
+}
 
 std::string format_bin(const uint8_t *data, size_t length) {
   std::string result;
diff --git a/esphome/core/helpers.h b/esphome/core/helpers.h
index 7d5366f323..362f3d1fa4 100644
--- a/esphome/core/helpers.h
+++ b/esphome/core/helpers.h
@@ -348,6 +348,8 @@ std::string format_hex_pretty(const uint16_t *data, size_t length);
 std::string format_hex_pretty(const std::vector &data);
 /// Format the vector \p data in pretty-printed, human-readable hex.
 std::string format_hex_pretty(const std::vector &data);
+/// Format the string \p data in pretty-printed, human-readable hex.
+std::string format_hex_pretty(const std::string &data);
 /// Format an unsigned integer in pretty-printed, human-readable hex, starting with the most significant byte.
 template::value, int> = 0> std::string format_hex_pretty(T val) {
   val = convert_big_endian(val);
diff --git a/esphome/idf_component.yml b/esphome/idf_component.yml
index 6299909033..c43b622684 100644
--- a/esphome/idf_component.yml
+++ b/esphome/idf_component.yml
@@ -17,3 +17,5 @@ dependencies:
     version: 2.0.11
     rules:
       - if: "target in [esp32h2, esp32p4]"
+  zorxx/multipart-parser:
+    version: 1.0.1
diff --git a/esphome/pins.py b/esphome/pins.py
index 0dfd5a245b..4f9b4859a1 100644
--- a/esphome/pins.py
+++ b/esphome/pins.py
@@ -220,7 +220,9 @@ def gpio_flags_expr(mode):
 
 
 gpio_pin_schema = _schema_creator
-internal_gpio_pin_number = _internal_number_creator
+internal_gpio_pin_number = _internal_number_creator(
+    {CONF_OUTPUT: True, CONF_INPUT: True}
+)
 gpio_output_pin_schema = _schema_creator(
     {
         CONF_OUTPUT: True,
diff --git a/esphome/writer.py b/esphome/writer.py
index 7a5089e384..943dfa78cc 100644
--- a/esphome/writer.py
+++ b/esphome/writer.py
@@ -107,6 +107,11 @@ def storage_should_clean(old: StorageJSON, new: StorageJSON) -> bool:
         return True
     if old.build_path != new.build_path:
         return True
+
+    return False
+
+
+def storage_should_update_cmake_cache(old: StorageJSON, new: StorageJSON) -> bool:
     if (
         old.loaded_integrations != new.loaded_integrations
         or old.loaded_platforms != new.loaded_platforms
@@ -126,10 +131,11 @@ def update_storage_json():
         return
 
     if storage_should_clean(old, new):
-        _LOGGER.info(
-            "Core config, version or integrations changed, cleaning build files..."
-        )
+        _LOGGER.info("Core config, version changed, cleaning build files...")
         clean_build()
+    elif storage_should_update_cmake_cache(old, new):
+        _LOGGER.info("Integrations changed, cleaning cmake cache...")
+        clean_cmake_cache()
 
     new.save(path)
 
@@ -353,6 +359,15 @@ def write_cpp(code_s):
     write_file_if_changed(path, full_file)
 
 
+def clean_cmake_cache():
+    pioenvs = CORE.relative_pioenvs_path()
+    if os.path.isdir(pioenvs):
+        pioenvs_cmake_path = CORE.relative_pioenvs_path(CORE.name, "CMakeCache.txt")
+        if os.path.isfile(pioenvs_cmake_path):
+            _LOGGER.info("Deleting %s", pioenvs_cmake_path)
+            os.remove(pioenvs_cmake_path)
+
+
 def clean_build():
     import shutil
 
diff --git a/esphome/yaml_util.py b/esphome/yaml_util.py
index bd1806affc..e52fc9e788 100644
--- a/esphome/yaml_util.py
+++ b/esphome/yaml_util.py
@@ -292,8 +292,6 @@ class ESPHomeLoaderMixin:
             if file is None:
                 raise yaml.MarkedYAMLError("Must include 'file'", node.start_mark)
             vars = fields.get(CONF_VARS)
-            if vars:
-                vars = {k: str(v) for k, v in vars.items()}
             return file, vars
 
         if isinstance(node, yaml.nodes.MappingNode):
diff --git a/requirements.txt b/requirements.txt
index 12f3b84359..1010a311d6 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -21,6 +21,7 @@ esphome-glyphsets==0.2.0
 pillow==10.4.0
 cairosvg==2.8.2
 freetype-py==2.5.1
+jinja2==3.1.6
 
 # esp-idf requires this, but doesn't bundle it by default
 # https://github.com/espressif/esp-idf/blob/220590d599e134d7a5e7f1e683cc4550349ffbf8/requirements.txt#L24
diff --git a/script/api_protobuf/api_protobuf.py b/script/api_protobuf/api_protobuf.py
index ad8e41ba5e..2266dda81c 100755
--- a/script/api_protobuf/api_protobuf.py
+++ b/script/api_protobuf/api_protobuf.py
@@ -526,11 +526,15 @@ class BytesType(TypeInfo):
     reference_type = "std::string &"
     const_reference_type = "const std::string &"
     decode_length = "value.as_string()"
-    encode_func = "encode_string"
+    encode_func = "encode_bytes"
     wire_type = WireType.LENGTH_DELIMITED  # Uses wire type 2
 
+    @property
+    def encode_content(self) -> str:
+        return f"buffer.encode_bytes({self.number}, reinterpret_cast(this->{self.field_name}.data()), this->{self.field_name}.size());"
+
     def dump(self, name: str) -> str:
-        o = f'out.append("\'").append({name}).append("\'");'
+        o = f"out.append(format_hex_pretty({name}));"
         return o
 
     def get_size_calculation(self, name: str, force: bool = False) -> str:
@@ -809,27 +813,137 @@ class RepeatedTypeInfo(TypeInfo):
         return underlying_size * 2
 
 
-def build_enum_type(desc) -> tuple[str, str]:
-    """Builds the enum type."""
+def build_type_usage_map(
+    file_desc: descriptor.FileDescriptorProto,
+) -> tuple[dict[str, str | None], dict[str, str | None]]:
+    """Build mappings for both enums and messages to their ifdefs based on usage.
+
+    Returns:
+        tuple: (enum_ifdef_map, message_ifdef_map)
+    """
+    enum_ifdef_map: dict[str, str | None] = {}
+    message_ifdef_map: dict[str, str | None] = {}
+
+    # Build maps of which types are used by which messages
+    enum_usage: dict[
+        str, set[str]
+    ] = {}  # enum_name -> set of message names that use it
+    message_usage: dict[
+        str, set[str]
+    ] = {}  # message_name -> set of message names that use it
+
+    # Build message name to ifdef mapping for quick lookup
+    message_to_ifdef: dict[str, str | None] = {
+        msg.name: get_opt(msg, pb.ifdef) for msg in file_desc.message_type
+    }
+
+    # Analyze field usage
+    for message in file_desc.message_type:
+        for field in message.field:
+            type_name = field.type_name.split(".")[-1] if field.type_name else None
+            if not type_name:
+                continue
+
+            # Track enum usage
+            if field.type == 14:  # TYPE_ENUM
+                enum_usage.setdefault(type_name, set()).add(message.name)
+            # Track message usage
+            elif field.type == 11:  # TYPE_MESSAGE
+                message_usage.setdefault(type_name, set()).add(message.name)
+
+    # Helper to get unique ifdef from a set of messages
+    def get_unique_ifdef(message_names: set[str]) -> str | None:
+        ifdefs: set[str] = {
+            message_to_ifdef[name]
+            for name in message_names
+            if message_to_ifdef.get(name)
+        }
+        return ifdefs.pop() if len(ifdefs) == 1 else None
+
+    # Build enum ifdef map
+    for enum in file_desc.enum_type:
+        if enum.name in enum_usage:
+            enum_ifdef_map[enum.name] = get_unique_ifdef(enum_usage[enum.name])
+        else:
+            enum_ifdef_map[enum.name] = None
+
+    # Build message ifdef map
+    for message in file_desc.message_type:
+        # Explicit ifdef takes precedence
+        explicit_ifdef = message_to_ifdef.get(message.name)
+        if explicit_ifdef:
+            message_ifdef_map[message.name] = explicit_ifdef
+        elif message.name in message_usage:
+            # Inherit ifdef if all parent messages have the same one
+            message_ifdef_map[message.name] = get_unique_ifdef(
+                message_usage[message.name]
+            )
+        else:
+            message_ifdef_map[message.name] = None
+
+    # Second pass: propagate ifdefs recursively
+    # Keep iterating until no more changes are made
+    changed = True
+    iterations = 0
+    while changed and iterations < 10:  # Add safety limit
+        changed = False
+        iterations += 1
+        for message in file_desc.message_type:
+            # Skip if already has an ifdef
+            if message_ifdef_map.get(message.name):
+                continue
+
+            # Check if this message is used by other messages
+            if message.name not in message_usage:
+                continue
+
+            # Get ifdefs from all messages that use this one
+            parent_ifdefs: set[str] = {
+                message_ifdef_map.get(parent)
+                for parent in message_usage[message.name]
+                if message_ifdef_map.get(parent)
+            }
+
+            # If all parents have the same ifdef, inherit it
+            if len(parent_ifdefs) == 1 and None not in parent_ifdefs:
+                message_ifdef_map[message.name] = parent_ifdefs.pop()
+                changed = True
+
+    return enum_ifdef_map, message_ifdef_map
+
+
+def build_enum_type(desc, enum_ifdef_map) -> tuple[str, str, str]:
+    """Builds the enum type.
+
+    Args:
+        desc: The enum descriptor
+        enum_ifdef_map: Mapping of enum names to their ifdefs
+
+    Returns:
+        tuple: (header_content, cpp_content, dump_cpp_content)
+    """
     name = desc.name
+
     out = f"enum {name} : uint32_t {{\n"
     for v in desc.value:
         out += f"  {v.name} = {v.number},\n"
     out += "};\n"
 
-    cpp = "#ifdef HAS_PROTO_MESSAGE_DUMP\n"
-    cpp += f"template<> const char *proto_enum_to_string(enums::{name} value) {{\n"
-    cpp += "  switch (value) {\n"
-    for v in desc.value:
-        cpp += f"    case enums::{v.name}:\n"
-        cpp += f'      return "{v.name}";\n'
-    cpp += "    default:\n"
-    cpp += '      return "UNKNOWN";\n'
-    cpp += "  }\n"
-    cpp += "}\n"
-    cpp += "#endif\n"
+    # Regular cpp file has no enum content anymore
+    cpp = ""
 
-    return out, cpp
+    # Dump cpp content for enum string conversion
+    dump_cpp = f"template<> const char *proto_enum_to_string(enums::{name} value) {{\n"
+    dump_cpp += "  switch (value) {\n"
+    for v in desc.value:
+        dump_cpp += f"    case enums::{v.name}:\n"
+        dump_cpp += f'      return "{v.name}";\n'
+    dump_cpp += "    default:\n"
+    dump_cpp += '      return "UNKNOWN";\n'
+    dump_cpp += "  }\n"
+    dump_cpp += "}\n"
+
+    return out, cpp, dump_cpp
 
 
 def calculate_message_estimated_size(desc: descriptor.DescriptorProto) -> int:
@@ -851,7 +965,7 @@ def calculate_message_estimated_size(desc: descriptor.DescriptorProto) -> int:
 def build_message_type(
     desc: descriptor.DescriptorProto,
     base_class_fields: dict[str, list[descriptor.FieldDescriptorProto]] = None,
-) -> tuple[str, str]:
+) -> tuple[str, str, str]:
     public_content: list[str] = []
     protected_content: list[str] = []
     decode_varint: list[str] = []
@@ -882,7 +996,7 @@ def build_message_type(
             f"static constexpr uint16_t ESTIMATED_SIZE = {estimated_size};"
         )
 
-        # Add message_name method for debugging
+        # Add message_name method inline in header
         public_content.append("#ifdef HAS_PROTO_MESSAGE_DUMP")
         snake_name = camel_to_snake(desc.name)
         public_content.append(
@@ -989,32 +1103,32 @@ def build_message_type(
         public_content.append(prot)
     # If no fields to calculate size for, the default implementation in ProtoMessage will be used
 
-    o = f"void {desc.name}::dump_to(std::string &out) const {{"
-    if dump:
-        if len(dump) == 1 and len(dump[0]) + len(o) + 3 < 120:
-            o += f" {dump[0]} "
-        else:
-            o += "\n"
-            o += "  __attribute__((unused)) char buffer[64];\n"
-            o += f'  out.append("{desc.name} {{\\n");\n'
-            o += indent("\n".join(dump)) + "\n"
-            o += '  out.append("}");\n'
-    else:
-        o2 = f'out.append("{desc.name} {{}}");'
-        if len(o) + len(o2) + 3 < 120:
-            o += f" {o2} "
-        else:
-            o += "\n"
-            o += f"  {o2}\n"
-    o += "}\n"
-    cpp += "#ifdef HAS_PROTO_MESSAGE_DUMP\n"
-    cpp += o
-    cpp += "#endif\n"
+    # dump_to method declaration in header
     prot = "#ifdef HAS_PROTO_MESSAGE_DUMP\n"
     prot += "void dump_to(std::string &out) const override;\n"
     prot += "#endif\n"
     public_content.append(prot)
 
+    # dump_to implementation will go in dump_cpp
+    dump_impl = f"void {desc.name}::dump_to(std::string &out) const {{"
+    if dump:
+        if len(dump) == 1 and len(dump[0]) + len(dump_impl) + 3 < 120:
+            dump_impl += f" {dump[0]} "
+        else:
+            dump_impl += "\n"
+            dump_impl += "  __attribute__((unused)) char buffer[64];\n"
+            dump_impl += f'  out.append("{desc.name} {{\\n");\n'
+            dump_impl += indent("\n".join(dump)) + "\n"
+            dump_impl += '  out.append("}");\n'
+    else:
+        o2 = f'out.append("{desc.name} {{}}");'
+        if len(dump_impl) + len(o2) + 3 < 120:
+            dump_impl += f" {o2} "
+        else:
+            dump_impl += "\n"
+            dump_impl += f"  {o2}\n"
+    dump_impl += "}\n"
+
     if base_class:
         out = f"class {desc.name} : public {base_class} {{\n"
     else:
@@ -1027,7 +1141,11 @@ def build_message_type(
     if len(protected_content) > 0:
         out += "\n"
     out += "};\n"
-    return out, cpp
+
+    # Build dump_cpp content with dump_to implementation
+    dump_cpp = dump_impl
+
+    return out, cpp, dump_cpp
 
 
 SOURCE_BOTH = 0
@@ -1115,7 +1233,7 @@ def find_common_fields(
 def build_base_class(
     base_class_name: str,
     common_fields: list[descriptor.FieldDescriptorProto],
-) -> tuple[str, str]:
+) -> tuple[str, str, str]:
     """Build the base class definition and implementation."""
     public_content = []
     protected_content = []
@@ -1152,16 +1270,18 @@ def build_base_class(
     out += "};\n"
 
     # No implementation needed for base classes
+    dump_cpp = ""
 
-    return out, cpp
+    return out, cpp, dump_cpp
 
 
 def generate_base_classes(
     base_class_groups: dict[str, list[descriptor.DescriptorProto]],
-) -> tuple[str, str]:
+) -> tuple[str, str, str]:
     """Generate all base classes."""
     all_headers = []
     all_cpp = []
+    all_dump_cpp = []
 
     for base_class_name, messages in base_class_groups.items():
         # Find common fields
@@ -1169,11 +1289,12 @@ def generate_base_classes(
 
         if common_fields:
             # Generate base class
-            header, cpp = build_base_class(base_class_name, common_fields)
+            header, cpp, dump_cpp = build_base_class(base_class_name, common_fields)
             all_headers.append(header)
             all_cpp.append(cpp)
+            all_dump_cpp.append(dump_cpp)
 
-    return "\n".join(all_headers), "\n".join(all_cpp)
+    return "\n".join(all_headers), "\n".join(all_cpp), "\n".join(all_dump_cpp)
 
 
 def build_service_message_type(
@@ -1240,35 +1361,75 @@ def main() -> None:
     file = d.file[0]
     content = FILE_HEADER
     content += """\
-    #pragma once
+#pragma once
 
-    #include "proto.h"
-    #include "api_pb2_size.h"
+#include "esphome/core/defines.h"
 
-    namespace esphome {
-    namespace api {
+#include "proto.h"
+#include "api_pb2_size.h"
 
-    """
+namespace esphome {
+namespace api {
+
+"""
 
     cpp = FILE_HEADER
     cpp += """\
     #include "api_pb2.h"
     #include "api_pb2_size.h"
     #include "esphome/core/log.h"
+    #include "esphome/core/helpers.h"
 
-    #include 
+namespace esphome {
+namespace api {
 
-    namespace esphome {
-    namespace api {
+"""
 
-    """
+    # Initialize dump cpp content
+    dump_cpp = FILE_HEADER
+    dump_cpp += """\
+#include "api_pb2.h"
+#include "esphome/core/helpers.h"
+
+#include 
+
+#ifdef HAS_PROTO_MESSAGE_DUMP
+
+namespace esphome {
+namespace api {
+
+"""
 
     content += "namespace enums {\n\n"
 
+    # Build dynamic ifdef mappings for both enums and messages
+    enum_ifdef_map, message_ifdef_map = build_type_usage_map(file)
+
+    # Simple grouping of enums by ifdef
+    current_ifdef = None
+
     for enum in file.enum_type:
-        s, c = build_enum_type(enum)
+        s, c, dc = build_enum_type(enum, enum_ifdef_map)
+        enum_ifdef = enum_ifdef_map.get(enum.name)
+
+        # Handle ifdef changes
+        if enum_ifdef != current_ifdef:
+            if current_ifdef is not None:
+                content += "#endif\n"
+                dump_cpp += "#endif\n"
+            if enum_ifdef is not None:
+                content += f"#ifdef {enum_ifdef}\n"
+                dump_cpp += f"#ifdef {enum_ifdef}\n"
+            current_ifdef = enum_ifdef
+
         content += s
         cpp += c
+        dump_cpp += dc
+
+    # Close last ifdef
+    if current_ifdef is not None:
+        content += "#endif\n"
+        dump_cpp += "#endif\n"
 
     content += "\n}  // namespace enums\n\n"
 
@@ -1286,26 +1447,61 @@ def main() -> None:
 
     # Generate base classes
     if base_class_fields:
-        base_headers, base_cpp = generate_base_classes(base_class_groups)
+        base_headers, base_cpp, base_dump_cpp = generate_base_classes(base_class_groups)
         content += base_headers
         cpp += base_cpp
+        dump_cpp += base_dump_cpp
 
     # Generate message types with base class information
+    # Simple grouping by ifdef
+    current_ifdef = None
+
     for m in mt:
-        s, c = build_message_type(m, base_class_fields)
+        s, c, dc = build_message_type(m, base_class_fields)
+        msg_ifdef = message_ifdef_map.get(m.name)
+
+        # Handle ifdef changes
+        if msg_ifdef != current_ifdef:
+            if current_ifdef is not None:
+                content += "#endif\n"
+                if cpp:
+                    cpp += "#endif\n"
+                if dump_cpp:
+                    dump_cpp += "#endif\n"
+            if msg_ifdef is not None:
+                content += f"#ifdef {msg_ifdef}\n"
+                cpp += f"#ifdef {msg_ifdef}\n"
+                dump_cpp += f"#ifdef {msg_ifdef}\n"
+            current_ifdef = msg_ifdef
+
         content += s
         cpp += c
+        dump_cpp += dc
+
+    # Close last ifdef
+    if current_ifdef is not None:
+        content += "#endif\n"
+        cpp += "#endif\n"
+        dump_cpp += "#endif\n"
 
     content += """\
 
-    }  // namespace api
-    }  // namespace esphome
-    """
+}  // namespace api
+}  // namespace esphome
+"""
     cpp += """\
 
-    }  // namespace api
-    }  // namespace esphome
-    """
+}  // namespace api
+}  // namespace esphome
+"""
+
+    dump_cpp += """\
+
+}  // namespace api
+}  // namespace esphome
+
+#endif  // HAS_PROTO_MESSAGE_DUMP
+"""
 
     with open(root / "api_pb2.h", "w", encoding="utf-8") as f:
         f.write(content)
@@ -1313,29 +1509,33 @@ def main() -> None:
     with open(root / "api_pb2.cpp", "w", encoding="utf-8") as f:
         f.write(cpp)
 
+    with open(root / "api_pb2_dump.cpp", "w", encoding="utf-8") as f:
+        f.write(dump_cpp)
+
     hpp = FILE_HEADER
     hpp += """\
-    #pragma once
+#pragma once
 
-    #include "api_pb2.h"
-    #include "esphome/core/defines.h"
+#include "esphome/core/defines.h"
 
-    namespace esphome {
-    namespace api {
+#include "api_pb2.h"
 
-    """
+namespace esphome {
+namespace api {
+
+"""
 
     cpp = FILE_HEADER
     cpp += """\
-    #include "api_pb2_service.h"
-    #include "esphome/core/log.h"
+#include "api_pb2_service.h"
+#include "esphome/core/log.h"
 
-    namespace esphome {
-    namespace api {
+namespace esphome {
+namespace api {
 
-    static const char *const TAG = "api.service";
+static const char *const TAG = "api.service";
 
-    """
+"""
 
     class_name = "APIServerConnectionBase"
 
@@ -1414,7 +1614,7 @@ def main() -> None:
         needs_conn = get_opt(m, pb.needs_setup_connection, True)
         needs_auth = get_opt(m, pb.needs_authentication, True)
 
-        ifdef = ifdefs.get(inp, None)
+        ifdef = message_ifdef_map.get(inp, ifdefs.get(inp, None))
 
         if ifdef is not None:
             hpp += f"#ifdef {ifdef}\n"
@@ -1471,14 +1671,14 @@ def main() -> None:
 
     hpp += """\
 
-    }  // namespace api
-    }  // namespace esphome
-    """
+}  // namespace api
+}  // namespace esphome
+"""
     cpp += """\
 
-    }  // namespace api
-    }  // namespace esphome
-    """
+}  // namespace api
+}  // namespace esphome
+"""
 
     with open(root / "api_pb2_service.h", "w", encoding="utf-8") as f:
         f.write(hpp)
@@ -1501,6 +1701,8 @@ def main() -> None:
         exec_clang_format(root / "api_pb2_service.cpp")
         exec_clang_format(root / "api_pb2.h")
         exec_clang_format(root / "api_pb2.cpp")
+        exec_clang_format(root / "api_pb2_dump.h")
+        exec_clang_format(root / "api_pb2_dump.cpp")
     except ImportError:
         pass
 
diff --git a/tests/component_tests/ota/test_web_server_ota.py b/tests/component_tests/ota/test_web_server_ota.py
new file mode 100644
index 0000000000..0d8ff6f134
--- /dev/null
+++ b/tests/component_tests/ota/test_web_server_ota.py
@@ -0,0 +1,102 @@
+"""Tests for the web_server OTA platform."""
+
+from collections.abc import Callable
+
+
+def test_web_server_ota_generated(generate_main: Callable[[str], str]) -> None:
+    """Test that web_server OTA platform generates correct code."""
+    main_cpp = generate_main("tests/component_tests/ota/test_web_server_ota.yaml")
+
+    # Check that the web server OTA component is included
+    assert "WebServerOTAComponent" in main_cpp
+    assert "web_server::WebServerOTAComponent" in main_cpp
+
+    # Check that global web server base is referenced
+    assert "global_web_server_base" in main_cpp
+
+    # Check component is registered
+    assert "App.register_component(web_server_webserverotacomponent_id)" in main_cpp
+
+
+def test_web_server_ota_with_callbacks(generate_main: Callable[[str], str]) -> None:
+    """Test web_server OTA with state callbacks."""
+    main_cpp = generate_main(
+        "tests/component_tests/ota/test_web_server_ota_callbacks.yaml"
+    )
+
+    # Check that web server OTA component is present
+    assert "WebServerOTAComponent" in main_cpp
+
+    # Check that callbacks are configured
+    # The actual callback code is in the component implementation, not main.cpp
+    # But we can check that logger.log statements are present from the callbacks
+    assert "logger.log" in main_cpp
+    assert "OTA started" in main_cpp
+    assert "OTA completed" in main_cpp
+    assert "OTA error" in main_cpp
+
+
+def test_web_server_ota_idf_multipart(generate_main: Callable[[str], str]) -> None:
+    """Test that ESP-IDF builds include multipart parser dependency."""
+    main_cpp = generate_main("tests/component_tests/ota/test_web_server_ota_idf.yaml")
+
+    # Check that web server OTA component is present
+    assert "WebServerOTAComponent" in main_cpp
+
+    # For ESP-IDF builds, the framework type is esp-idf
+    # The multipart parser dependency is added by web_server_idf
+    assert "web_server::WebServerOTAComponent" in main_cpp
+
+
+def test_web_server_ota_without_web_server_fails(
+    generate_main: Callable[[str], str],
+) -> None:
+    """Test that web_server OTA requires web_server component."""
+    # This should fail during validation since web_server_base is required
+    # but we can't test validation failures with generate_main
+    # Instead, verify that both components are needed in valid config
+    main_cpp = generate_main("tests/component_tests/ota/test_web_server_ota.yaml")
+
+    # Both web server and OTA components should be present
+    assert "WebServer" in main_cpp
+    assert "WebServerOTAComponent" in main_cpp
+
+
+def test_multiple_ota_platforms(generate_main: Callable[[str], str]) -> None:
+    """Test multiple OTA platforms can coexist."""
+    main_cpp = generate_main("tests/component_tests/ota/test_web_server_ota_multi.yaml")
+
+    # Check all OTA platforms are included
+    assert "WebServerOTAComponent" in main_cpp
+    assert "ESPHomeOTAComponent" in main_cpp
+    assert "OtaHttpRequestComponent" in main_cpp
+
+    # Check components are from correct namespaces
+    assert "web_server::WebServerOTAComponent" in main_cpp
+    assert "esphome::ESPHomeOTAComponent" in main_cpp
+    assert "http_request::OtaHttpRequestComponent" in main_cpp
+
+
+def test_web_server_ota_arduino_with_auth(generate_main: Callable[[str], str]) -> None:
+    """Test web_server OTA with Arduino framework and authentication."""
+    main_cpp = generate_main(
+        "tests/component_tests/ota/test_web_server_ota_arduino.yaml"
+    )
+
+    # Check web server OTA component is present
+    assert "WebServerOTAComponent" in main_cpp
+
+    # Check authentication is set up for web server
+    assert "set_auth_username" in main_cpp
+    assert "set_auth_password" in main_cpp
+
+
+def test_web_server_ota_esp8266(generate_main: Callable[[str], str]) -> None:
+    """Test web_server OTA on ESP8266 platform."""
+    main_cpp = generate_main(
+        "tests/component_tests/ota/test_web_server_ota_esp8266.yaml"
+    )
+
+    # Check web server OTA component is present
+    assert "WebServerOTAComponent" in main_cpp
+    assert "web_server::WebServerOTAComponent" in main_cpp
diff --git a/tests/component_tests/ota/test_web_server_ota.yaml b/tests/component_tests/ota/test_web_server_ota.yaml
new file mode 100644
index 0000000000..e0fda3d0b5
--- /dev/null
+++ b/tests/component_tests/ota/test_web_server_ota.yaml
@@ -0,0 +1,15 @@
+esphome:
+  name: test_web_server_ota
+
+esp32:
+  board: esp32dev
+
+wifi:
+  ssid: MySSID
+  password: password1
+
+web_server:
+  port: 80
+
+ota:
+  - platform: web_server
diff --git a/tests/component_tests/ota/test_web_server_ota_arduino.yaml b/tests/component_tests/ota/test_web_server_ota_arduino.yaml
new file mode 100644
index 0000000000..9462548cc8
--- /dev/null
+++ b/tests/component_tests/ota/test_web_server_ota_arduino.yaml
@@ -0,0 +1,18 @@
+esphome:
+  name: test_web_server_ota_arduino
+
+esp32:
+  board: esp32dev
+
+wifi:
+  ssid: MySSID
+  password: password1
+
+web_server:
+  port: 80
+  auth:
+    username: admin
+    password: admin
+
+ota:
+  - platform: web_server
diff --git a/tests/component_tests/ota/test_web_server_ota_callbacks.yaml b/tests/component_tests/ota/test_web_server_ota_callbacks.yaml
new file mode 100644
index 0000000000..c2fd9e0f19
--- /dev/null
+++ b/tests/component_tests/ota/test_web_server_ota_callbacks.yaml
@@ -0,0 +1,31 @@
+esphome:
+  name: test_web_server_ota_callbacks
+
+esp32:
+  board: esp32dev
+
+wifi:
+  ssid: MySSID
+  password: password1
+
+logger:
+
+web_server:
+  port: 80
+
+ota:
+  - platform: web_server
+    on_begin:
+      - logger.log: "OTA started"
+    on_progress:
+      - logger.log:
+          format: "OTA progress: %.1f%%"
+          args: ["x"]
+    on_end:
+      - logger.log: "OTA completed"
+    on_error:
+      - logger.log:
+          format: "OTA error: %d"
+          args: ["x"]
+    on_state_change:
+      - logger.log: "OTA state changed"
diff --git a/tests/component_tests/ota/test_web_server_ota_esp8266.yaml b/tests/component_tests/ota/test_web_server_ota_esp8266.yaml
new file mode 100644
index 0000000000..a1b66a5b53
--- /dev/null
+++ b/tests/component_tests/ota/test_web_server_ota_esp8266.yaml
@@ -0,0 +1,15 @@
+esphome:
+  name: test_web_server_ota_esp8266
+
+esp8266:
+  board: nodemcuv2
+
+wifi:
+  ssid: MySSID
+  password: password1
+
+web_server:
+  port: 80
+
+ota:
+  - platform: web_server
diff --git a/tests/component_tests/ota/test_web_server_ota_idf.yaml b/tests/component_tests/ota/test_web_server_ota_idf.yaml
new file mode 100644
index 0000000000..18b639347c
--- /dev/null
+++ b/tests/component_tests/ota/test_web_server_ota_idf.yaml
@@ -0,0 +1,17 @@
+esphome:
+  name: test_web_server_ota_idf
+
+esp32:
+  board: esp32dev
+  framework:
+    type: esp-idf
+
+wifi:
+  ssid: MySSID
+  password: password1
+
+web_server:
+  port: 80
+
+ota:
+  - platform: web_server
diff --git a/tests/component_tests/ota/test_web_server_ota_multi.yaml b/tests/component_tests/ota/test_web_server_ota_multi.yaml
new file mode 100644
index 0000000000..7926b09c71
--- /dev/null
+++ b/tests/component_tests/ota/test_web_server_ota_multi.yaml
@@ -0,0 +1,21 @@
+esphome:
+  name: test_web_server_ota_multi
+
+esp32:
+  board: esp32dev
+
+wifi:
+  ssid: MySSID
+  password: password1
+
+web_server:
+  port: 80
+
+http_request:
+  verify_ssl: false
+
+ota:
+  - platform: esphome
+    password: "test_password"
+  - platform: web_server
+  - platform: http_request
diff --git a/tests/component_tests/web_server/test_ota_migration.py b/tests/component_tests/web_server/test_ota_migration.py
new file mode 100644
index 0000000000..7f34ec75f6
--- /dev/null
+++ b/tests/component_tests/web_server/test_ota_migration.py
@@ -0,0 +1,38 @@
+"""Tests for web_server OTA migration validation."""
+
+import pytest
+
+from esphome import config_validation as cv
+from esphome.types import ConfigType
+
+
+def test_web_server_ota_true_fails_validation() -> None:
+    """Test that web_server with ota: true fails validation with helpful message."""
+    from esphome.components.web_server import validate_ota_removed
+
+    # Config with ota: true should fail
+    config: ConfigType = {"ota": True}
+
+    with pytest.raises(cv.Invalid) as exc_info:
+        validate_ota_removed(config)
+
+    # Check error message contains migration instructions
+    error_msg = str(exc_info.value)
+    assert "has been removed from 'web_server'" in error_msg
+    assert "platform: web_server" in error_msg
+    assert "ota:" in error_msg
+
+
+def test_web_server_ota_false_passes_validation() -> None:
+    """Test that web_server with ota: false passes validation."""
+    from esphome.components.web_server import validate_ota_removed
+
+    # Config with ota: false should pass
+    config: ConfigType = {"ota": False}
+    result = validate_ota_removed(config)
+    assert result == config
+
+    # Config without ota should also pass
+    config: ConfigType = {}
+    result = validate_ota_removed(config)
+    assert result == config
diff --git a/tests/components/ds2484/common.yaml b/tests/components/ds2484/common.yaml
new file mode 100644
index 0000000000..9d2882a3c0
--- /dev/null
+++ b/tests/components/ds2484/common.yaml
@@ -0,0 +1,11 @@
+i2c:
+  - id: i2c_ds2484
+    scl: ${scl_pin}
+    sda: ${sda_pin}
+
+one_wire:
+  platform: ds2484
+  i2c_id: i2c_ds2484
+  address: 0x18
+  active_pullup: true
+  strong_pullup: false
diff --git a/tests/components/ds2484/test.esp32-ard.yaml b/tests/components/ds2484/test.esp32-ard.yaml
new file mode 100644
index 0000000000..63c3bd6afd
--- /dev/null
+++ b/tests/components/ds2484/test.esp32-ard.yaml
@@ -0,0 +1,5 @@
+substitutions:
+  scl_pin: GPIO16
+  sda_pin: GPIO17
+
+<<: !include common.yaml
diff --git a/tests/components/ds2484/test.esp32-c3-ard.yaml b/tests/components/ds2484/test.esp32-c3-ard.yaml
new file mode 100644
index 0000000000..ee2c29ca4e
--- /dev/null
+++ b/tests/components/ds2484/test.esp32-c3-ard.yaml
@@ -0,0 +1,5 @@
+substitutions:
+  scl_pin: GPIO5
+  sda_pin: GPIO4
+
+<<: !include common.yaml
diff --git a/tests/components/ds2484/test.esp32-c3-idf.yaml b/tests/components/ds2484/test.esp32-c3-idf.yaml
new file mode 100644
index 0000000000..ee2c29ca4e
--- /dev/null
+++ b/tests/components/ds2484/test.esp32-c3-idf.yaml
@@ -0,0 +1,5 @@
+substitutions:
+  scl_pin: GPIO5
+  sda_pin: GPIO4
+
+<<: !include common.yaml
diff --git a/tests/components/ds2484/test.esp32-idf.yaml b/tests/components/ds2484/test.esp32-idf.yaml
new file mode 100644
index 0000000000..63c3bd6afd
--- /dev/null
+++ b/tests/components/ds2484/test.esp32-idf.yaml
@@ -0,0 +1,5 @@
+substitutions:
+  scl_pin: GPIO16
+  sda_pin: GPIO17
+
+<<: !include common.yaml
diff --git a/tests/components/ds2484/test.esp8266-ard.yaml b/tests/components/ds2484/test.esp8266-ard.yaml
new file mode 100644
index 0000000000..ee2c29ca4e
--- /dev/null
+++ b/tests/components/ds2484/test.esp8266-ard.yaml
@@ -0,0 +1,5 @@
+substitutions:
+  scl_pin: GPIO5
+  sda_pin: GPIO4
+
+<<: !include common.yaml
diff --git a/tests/components/ds2484/test.rp2040-ard.yaml b/tests/components/ds2484/test.rp2040-ard.yaml
new file mode 100644
index 0000000000..ee2c29ca4e
--- /dev/null
+++ b/tests/components/ds2484/test.rp2040-ard.yaml
@@ -0,0 +1,5 @@
+substitutions:
+  scl_pin: GPIO5
+  sda_pin: GPIO4
+
+<<: !include common.yaml
diff --git a/tests/components/ethernet/common-dp83848.yaml b/tests/components/ethernet/common-dp83848.yaml
index 5b6ed3e8d0..140c7d0d1b 100644
--- a/tests/components/ethernet/common-dp83848.yaml
+++ b/tests/components/ethernet/common-dp83848.yaml
@@ -2,7 +2,9 @@ ethernet:
   type: DP83848
   mdc_pin: 23
   mdio_pin: 25
-  clk_mode: GPIO0_IN
+  clk:
+    pin: 0
+    mode: CLK_EXT_IN
   phy_addr: 0
   power_pin: 26
   manual_ip:
diff --git a/tests/components/ethernet/common-ip101.yaml b/tests/components/ethernet/common-ip101.yaml
index 5ca369cce1..b5589220de 100644
--- a/tests/components/ethernet/common-ip101.yaml
+++ b/tests/components/ethernet/common-ip101.yaml
@@ -2,7 +2,9 @@ ethernet:
   type: IP101
   mdc_pin: 23
   mdio_pin: 25
-  clk_mode: GPIO0_IN
+  clk:
+    pin: 0
+    mode: CLK_EXT_IN
   phy_addr: 0
   power_pin: 26
   manual_ip:
diff --git a/tests/components/ethernet/common-jl1101.yaml b/tests/components/ethernet/common-jl1101.yaml
index 639542d807..2ada9495a0 100644
--- a/tests/components/ethernet/common-jl1101.yaml
+++ b/tests/components/ethernet/common-jl1101.yaml
@@ -2,7 +2,9 @@ ethernet:
   type: JL1101
   mdc_pin: 23
   mdio_pin: 25
-  clk_mode: GPIO0_IN
+  clk:
+    pin: 0
+    mode: CLK_EXT_IN
   phy_addr: 0
   power_pin: 26
   manual_ip:
diff --git a/tests/components/ethernet/common-ksz8081.yaml b/tests/components/ethernet/common-ksz8081.yaml
index 167606a1eb..7da8adb09a 100644
--- a/tests/components/ethernet/common-ksz8081.yaml
+++ b/tests/components/ethernet/common-ksz8081.yaml
@@ -2,7 +2,9 @@ ethernet:
   type: KSZ8081
   mdc_pin: 23
   mdio_pin: 25
-  clk_mode: GPIO0_IN
+  clk:
+    pin: 0
+    mode: CLK_EXT_IN
   phy_addr: 0
   power_pin: 26
   manual_ip:
diff --git a/tests/components/ethernet/common-ksz8081rna.yaml b/tests/components/ethernet/common-ksz8081rna.yaml
index f506906b1b..df04f06132 100644
--- a/tests/components/ethernet/common-ksz8081rna.yaml
+++ b/tests/components/ethernet/common-ksz8081rna.yaml
@@ -2,7 +2,9 @@ ethernet:
   type: KSZ8081RNA
   mdc_pin: 23
   mdio_pin: 25
-  clk_mode: GPIO0_IN
+  clk:
+    pin: 0
+    mode: CLK_EXT_IN
   phy_addr: 0
   power_pin: 26
   manual_ip:
diff --git a/tests/components/ethernet/common-lan8720.yaml b/tests/components/ethernet/common-lan8720.yaml
index b9ed9cb036..f227752f42 100644
--- a/tests/components/ethernet/common-lan8720.yaml
+++ b/tests/components/ethernet/common-lan8720.yaml
@@ -2,7 +2,9 @@ ethernet:
   type: LAN8720
   mdc_pin: 23
   mdio_pin: 25
-  clk_mode: GPIO0_IN
+  clk:
+    pin: 0
+    mode: CLK_EXT_IN
   phy_addr: 0
   power_pin: 26
   manual_ip:
diff --git a/tests/components/ethernet/common-rtl8201.yaml b/tests/components/ethernet/common-rtl8201.yaml
index 43842e7c9f..7c9c9d913c 100644
--- a/tests/components/ethernet/common-rtl8201.yaml
+++ b/tests/components/ethernet/common-rtl8201.yaml
@@ -2,7 +2,9 @@ ethernet:
   type: RTL8201
   mdc_pin: 23
   mdio_pin: 25
-  clk_mode: GPIO0_IN
+  clk:
+    pin: 0
+    mode: CLK_EXT_IN
   phy_addr: 0
   power_pin: 26
   manual_ip:
diff --git a/tests/components/ethernet_info/common.yaml b/tests/components/ethernet_info/common.yaml
index d9a6f515b1..f45f345316 100644
--- a/tests/components/ethernet_info/common.yaml
+++ b/tests/components/ethernet_info/common.yaml
@@ -2,7 +2,9 @@ ethernet:
   type: LAN8720
   mdc_pin: 23
   mdio_pin: 25
-  clk_mode: GPIO0_IN
+  clk:
+    pin: 0
+    mode: CLK_EXT_IN
   phy_addr: 0
   power_pin: 26
   manual_ip:
diff --git a/tests/components/modbus_controller/common.yaml b/tests/components/modbus_controller/common.yaml
index 7fa9f8dae3..7d342ee353 100644
--- a/tests/components/modbus_controller/common.yaml
+++ b/tests/components/modbus_controller/common.yaml
@@ -33,7 +33,18 @@ modbus_controller:
         read_lambda: |-
           return 42.3;
     max_cmd_retries: 0
-
+  - id: modbus_controller3
+    address: 0x3
+    modbus_id: mod_bus2
+    server_registers:
+      - address: 0x0009
+        value_type: S_DWORD
+        read_lambda: |-
+          return 31;
+        write_lambda: |-
+          printf("address=%d, value=%d", x);
+          return true;
+    max_cmd_retries: 0
 binary_sensor:
   - platform: modbus_controller
     modbus_controller_id: modbus_controller1
diff --git a/tests/components/openthread/test.esp32-c6-idf.yaml b/tests/components/openthread/test.esp32-c6-idf.yaml
index f53b323bec..bbcf48efa5 100644
--- a/tests/components/openthread/test.esp32-c6-idf.yaml
+++ b/tests/components/openthread/test.esp32-c6-idf.yaml
@@ -2,6 +2,7 @@ network:
   enable_ipv6: true
 
 openthread:
+  device_type: FTD
   channel: 13
   network_name: OpenThread-8f28
   network_key: 0xdfd34f0f05cad978ec4e32b0413038ff
diff --git a/tests/components/smt100/common.yaml b/tests/components/smt100/common.yaml
index f86bd762e7..b12d7198fd 100644
--- a/tests/components/smt100/common.yaml
+++ b/tests/components/smt100/common.yaml
@@ -8,8 +8,8 @@ sensor:
   - platform: smt100
     counts:
       name: Counts
-    dielectric_constant:
-      name: Dielectric Constant
+    permittivity:
+      name: Permittivity
     temperature:
       name: Temperature
     moisture:
diff --git a/tests/components/web_server/test_no_ota.esp32-idf.yaml b/tests/components/web_server/test_no_ota.esp32-idf.yaml
new file mode 100644
index 0000000000..4064f518cf
--- /dev/null
+++ b/tests/components/web_server/test_no_ota.esp32-idf.yaml
@@ -0,0 +1,16 @@
+esphome:
+  name: test-web-server-no-ota-idf
+
+esp32:
+  board: esp32dev
+  framework:
+    type: esp-idf
+
+packages:
+  device_base: !include common.yaml
+
+# No OTA component defined for this test
+
+web_server:
+  port: 8080
+  version: 2
diff --git a/tests/components/web_server/test_ota.esp32-idf.yaml b/tests/components/web_server/test_ota.esp32-idf.yaml
new file mode 100644
index 0000000000..37838b3d34
--- /dev/null
+++ b/tests/components/web_server/test_ota.esp32-idf.yaml
@@ -0,0 +1,30 @@
+esphome:
+  name: test-web-server-ota-idf
+
+esp32:
+  board: esp32dev
+  framework:
+    type: esp-idf
+
+packages:
+  device_base: !include common.yaml
+
+# Enable OTA for multipart upload testing
+ota:
+  - platform: esphome
+    password: "test_ota_password"
+  - platform: web_server
+
+# Web server configuration
+web_server:
+  port: 8080
+  version: 2
+  include_internal: true
+
+# Enable debug logging for OTA
+logger:
+  level: VERBOSE
+  logs:
+    web_server: VERBOSE
+    web_server_idf: VERBOSE
+
diff --git a/tests/components/web_server/test_ota_disabled.esp32-idf.yaml b/tests/components/web_server/test_ota_disabled.esp32-idf.yaml
new file mode 100644
index 0000000000..b88b845db7
--- /dev/null
+++ b/tests/components/web_server/test_ota_disabled.esp32-idf.yaml
@@ -0,0 +1,18 @@
+esphome:
+  name: test-ws-ota-disabled-idf
+
+esp32:
+  board: esp32dev
+  framework:
+    type: esp-idf
+
+packages:
+  device_base: !include common.yaml
+
+# OTA is configured but web_server OTA is NOT included
+ota:
+  - platform: esphome
+
+web_server:
+  port: 8080
+  version: 2
diff --git a/tests/integration/fixtures/duplicate_entities_on_different_devices.yaml b/tests/integration/fixtures/duplicate_entities_not_allowed_on_different_devices.yaml
similarity index 61%
rename from tests/integration/fixtures/duplicate_entities_on_different_devices.yaml
rename to tests/integration/fixtures/duplicate_entities_not_allowed_on_different_devices.yaml
index ecc502ad28..f7d017a0ae 100644
--- a/tests/integration/fixtures/duplicate_entities_on_different_devices.yaml
+++ b/tests/integration/fixtures/duplicate_entities_not_allowed_on_different_devices.yaml
@@ -1,6 +1,6 @@
 esphome:
   name: duplicate-entities-test
-  # Define devices to test multi-device duplicate handling
+  # Define devices to test multi-device unique name validation
   devices:
     - id: controller_1
       name: Controller 1
@@ -13,31 +13,31 @@ host:
 api:  # Port will be automatically injected
 logger:
 
-# Test that duplicate entity names are allowed on different devices
+# Test that duplicate entity names are NOT allowed on different devices
 
-# Scenario 1: Same sensor name on different devices (allowed)
+# Scenario 1: Different sensor names on different devices (allowed)
 sensor:
   - platform: template
-    name: Temperature
+    name: Temperature Controller 1
     device_id: controller_1
     lambda: return 21.0;
     update_interval: 0.1s
 
   - platform: template
-    name: Temperature
+    name: Temperature Controller 2
     device_id: controller_2
     lambda: return 22.0;
     update_interval: 0.1s
 
   - platform: template
-    name: Temperature
+    name: Temperature Controller 3
     device_id: controller_3
     lambda: return 23.0;
     update_interval: 0.1s
 
   # Main device sensor (no device_id)
   - platform: template
-    name: Temperature
+    name: Temperature Main
     lambda: return 20.0;
     update_interval: 0.1s
 
@@ -47,20 +47,20 @@ sensor:
     lambda: return 60.0;
     update_interval: 0.1s
 
-# Scenario 2: Same binary sensor name on different devices (allowed)
+# Scenario 2: Different binary sensor names on different devices
 binary_sensor:
   - platform: template
-    name: Status
+    name: Status Controller 1
     device_id: controller_1
     lambda: return true;
 
   - platform: template
-    name: Status
+    name: Status Controller 2
     device_id: controller_2
     lambda: return false;
 
   - platform: template
-    name: Status
+    name: Status Main
     lambda: return true;  # Main device
 
   # Different platform can have same name as sensor
@@ -68,43 +68,43 @@ binary_sensor:
     name: Temperature
     lambda: return true;
 
-# Scenario 3: Same text sensor name on different devices
+# Scenario 3: Different text sensor names on different devices
 text_sensor:
   - platform: template
-    name: Device Info
+    name: Device Info Controller 1
     device_id: controller_1
     lambda: return {"Controller 1 Active"};
     update_interval: 0.1s
 
   - platform: template
-    name: Device Info
+    name: Device Info Controller 2
     device_id: controller_2
     lambda: return {"Controller 2 Active"};
     update_interval: 0.1s
 
   - platform: template
-    name: Device Info
+    name: Device Info Main
     lambda: return {"Main Device Active"};
     update_interval: 0.1s
 
-# Scenario 4: Same switch name on different devices
+# Scenario 4: Different switch names on different devices
 switch:
   - platform: template
-    name: Power
+    name: Power Controller 1
     device_id: controller_1
     lambda: return false;
     turn_on_action: []
     turn_off_action: []
 
   - platform: template
-    name: Power
+    name: Power Controller 2
     device_id: controller_2
     lambda: return true;
     turn_on_action: []
     turn_off_action: []
 
   - platform: template
-    name: Power
+    name: Power Controller 3
     device_id: controller_3
     lambda: return false;
     turn_on_action: []
@@ -117,26 +117,54 @@ switch:
     turn_on_action: []
     turn_off_action: []
 
-# Scenario 5: Empty names on different devices (should use device name)
+# Scenario 5: Buttons with unique names
 button:
   - platform: template
-    name: ""
+    name: "Reset Controller 1"
     device_id: controller_1
     on_press: []
 
   - platform: template
-    name: ""
+    name: "Reset Controller 2"
     device_id: controller_2
     on_press: []
 
   - platform: template
-    name: ""
+    name: "Reset Main"
     on_press: []  # Main device
 
-# Scenario 6: Special characters in names
+# Scenario 6: Empty names (should use device names)
+select:
+  - platform: template
+    name: ""
+    device_id: controller_1
+    options:
+      - "Option 1"
+      - "Option 2"
+    lambda: return {"Option 1"};
+    set_action: []
+
+  - platform: template
+    name: ""
+    device_id: controller_2
+    options:
+      - "Option 1"
+      - "Option 2"
+    lambda: return {"Option 1"};
+    set_action: []
+
+  - platform: template
+    name: ""  # Main device
+    options:
+      - "Option 1"
+      - "Option 2"
+    lambda: return {"Option 1"};
+    set_action: []
+
+# Scenario 7: Special characters in names - now with unique names
 number:
   - platform: template
-    name: "Temperature Setpoint!"
+    name: "Temperature Setpoint! Controller 1"
     device_id: controller_1
     min_value: 10.0
     max_value: 30.0
@@ -145,7 +173,7 @@ number:
     set_action: []
 
   - platform: template
-    name: "Temperature Setpoint!"
+    name: "Temperature Setpoint! Controller 2"
     device_id: controller_2
     min_value: 10.0
     max_value: 30.0
diff --git a/tests/integration/test_api_conditional_memory.py b/tests/integration/test_api_conditional_memory.py
index b85e8d91af..8048624f70 100644
--- a/tests/integration/test_api_conditional_memory.py
+++ b/tests/integration/test_api_conditional_memory.py
@@ -177,19 +177,22 @@ async def test_api_conditional_memory(
         async with api_client_connected() as client2:
             # Subscribe to states with new client
             states2: dict[int, EntityState] = {}
-            connected_future: asyncio.Future[None] = loop.create_future()
+            states_ready_future: asyncio.Future[None] = loop.create_future()
 
             def on_state2(state: EntityState) -> None:
                 states2[state.key] = state
-                # Check for reconnection
-                if state.key == client_connected.key and state.state is True:
-                    if not connected_future.done():
-                        connected_future.set_result(None)
+                # Check if we have received both required states
+                if (
+                    client_connected.key in states2
+                    and client_disconnected_event.key in states2
+                    and not states_ready_future.done()
+                ):
+                    states_ready_future.set_result(None)
 
             client2.subscribe_states(on_state2)
 
-            # Wait for connected state
-            await asyncio.wait_for(connected_future, timeout=5.0)
+            # Wait for both connected and disconnected event states
+            await asyncio.wait_for(states_ready_future, timeout=5.0)
 
             # Verify client is connected again (on_client_connected fired)
             assert states2[client_connected.key].state is True, (
diff --git a/tests/integration/test_duplicate_entities.py b/tests/integration/test_duplicate_entities.py
index 99968204d4..b7ee8dd478 100644
--- a/tests/integration/test_duplicate_entities.py
+++ b/tests/integration/test_duplicate_entities.py
@@ -11,12 +11,12 @@ from .types import APIClientConnectedFactory, RunCompiledFunction
 
 
 @pytest.mark.asyncio
-async def test_duplicate_entities_on_different_devices(
+async def test_duplicate_entities_not_allowed_on_different_devices(
     yaml_config: str,
     run_compiled: RunCompiledFunction,
     api_client_connected: APIClientConnectedFactory,
 ) -> None:
-    """Test that duplicate entity names are allowed on different devices."""
+    """Test that duplicate entity names are NOT allowed on different devices."""
     async with run_compiled(yaml_config), api_client_connected() as client:
         # Get device info
         device_info = await client.device_info()
@@ -52,42 +52,46 @@ async def test_duplicate_entities_on_different_devices(
         switches = [e for e in all_entities if e.__class__.__name__ == "SwitchInfo"]
         buttons = [e for e in all_entities if e.__class__.__name__ == "ButtonInfo"]
         numbers = [e for e in all_entities if e.__class__.__name__ == "NumberInfo"]
+        selects = [e for e in all_entities if e.__class__.__name__ == "SelectInfo"]
 
-        # Scenario 1: Check sensors with same "Temperature" name on different devices
-        temp_sensors = [s for s in sensors if s.name == "Temperature"]
+        # Scenario 1: Check that temperature sensors have unique names per device
+        temp_sensors = [s for s in sensors if "Temperature" in s.name]
         assert len(temp_sensors) == 4, (
             f"Expected exactly 4 temperature sensors, got {len(temp_sensors)}"
         )
 
-        # Verify each sensor is on a different device
-        temp_device_ids = set()
+        # Verify each sensor has a unique name
+        temp_names = set()
         temp_object_ids = set()
 
         for sensor in temp_sensors:
-            temp_device_ids.add(sensor.device_id)
+            temp_names.add(sensor.name)
             temp_object_ids.add(sensor.object_id)
 
-            # All should have object_id "temperature" (no suffix)
-            assert sensor.object_id == "temperature", (
-                f"Expected object_id 'temperature', got '{sensor.object_id}'"
-            )
-
-        # Should have 4 different device IDs (including None for main device)
-        assert len(temp_device_ids) == 4, (
-            f"Temperature sensors should be on different devices, got {temp_device_ids}"
+        # Should have 4 unique names
+        assert len(temp_names) == 4, (
+            f"Temperature sensors should have unique names, got {temp_names}"
         )
 
-        # Scenario 2: Check binary sensors "Status" on different devices
-        status_binary = [b for b in binary_sensors if b.name == "Status"]
+        # Object IDs should also be unique
+        assert len(temp_object_ids) == 4, (
+            f"Temperature sensors should have unique object_ids, got {temp_object_ids}"
+        )
+
+        # Scenario 2: Check binary sensors have unique names
+        status_binary = [b for b in binary_sensors if "Status" in b.name]
         assert len(status_binary) == 3, (
             f"Expected exactly 3 status binary sensors, got {len(status_binary)}"
         )
 
-        # All should have object_id "status"
+        # All should have unique object_ids
+        status_names = set()
         for binary in status_binary:
-            assert binary.object_id == "status", (
-                f"Expected object_id 'status', got '{binary.object_id}'"
-            )
+            status_names.add(binary.name)
+
+        assert len(status_names) == 3, (
+            f"Status binary sensors should have unique names, got {status_names}"
+        )
 
         # Scenario 3: Check that sensor and binary_sensor can have same name
         temp_binary = [b for b in binary_sensors if b.name == "Temperature"]
@@ -96,62 +100,86 @@ async def test_duplicate_entities_on_different_devices(
         )
         assert temp_binary[0].object_id == "temperature"
 
-        # Scenario 4: Check text sensors "Device Info" on different devices
-        info_text = [t for t in text_sensors if t.name == "Device Info"]
+        # Scenario 4: Check text sensors have unique names
+        info_text = [t for t in text_sensors if "Device Info" in t.name]
         assert len(info_text) == 3, (
             f"Expected exactly 3 device info text sensors, got {len(info_text)}"
         )
 
-        # All should have object_id "device_info"
+        # All should have unique names and object_ids
+        info_names = set()
         for text in info_text:
-            assert text.object_id == "device_info", (
-                f"Expected object_id 'device_info', got '{text.object_id}'"
-            )
+            info_names.add(text.name)
 
-        # Scenario 5: Check switches "Power" on different devices
-        power_switches = [s for s in switches if s.name == "Power"]
-        assert len(power_switches) == 3, (
-            f"Expected exactly 3 power switches, got {len(power_switches)}"
+        assert len(info_names) == 3, (
+            f"Device info text sensors should have unique names, got {info_names}"
         )
 
-        # All should have object_id "power"
-        for switch in power_switches:
-            assert switch.object_id == "power", (
-                f"Expected object_id 'power', got '{switch.object_id}'"
-            )
+        # Scenario 5: Check switches have unique names
+        power_switches = [s for s in switches if "Power" in s.name]
+        assert len(power_switches) == 4, (
+            f"Expected exactly 4 power switches, got {len(power_switches)}"
+        )
 
-        # Scenario 6: Check empty name buttons (should use device name)
-        empty_buttons = [b for b in buttons if b.name == ""]
-        assert len(empty_buttons) == 3, (
-            f"Expected exactly 3 empty name buttons, got {len(empty_buttons)}"
+        # All should have unique names
+        power_names = set()
+        for switch in power_switches:
+            power_names.add(switch.name)
+
+        assert len(power_names) == 4, (
+            f"Power switches should have unique names, got {power_names}"
+        )
+
+        # Scenario 6: Check reset buttons have unique names
+        reset_buttons = [b for b in buttons if "Reset" in b.name]
+        assert len(reset_buttons) == 3, (
+            f"Expected exactly 3 reset buttons, got {len(reset_buttons)}"
+        )
+
+        # All should have unique names
+        reset_names = set()
+        for button in reset_buttons:
+            reset_names.add(button.name)
+
+        assert len(reset_names) == 3, (
+            f"Reset buttons should have unique names, got {reset_names}"
+        )
+
+        # Scenario 7: Check empty name selects (should use device names)
+        empty_selects = [s for s in selects if s.name == ""]
+        assert len(empty_selects) == 3, (
+            f"Expected exactly 3 empty name selects, got {len(empty_selects)}"
         )
 
         # Group by device
-        c1_buttons = [b for b in empty_buttons if b.device_id == controller_1.device_id]
-        c2_buttons = [b for b in empty_buttons if b.device_id == controller_2.device_id]
+        c1_selects = [s for s in empty_selects if s.device_id == controller_1.device_id]
+        c2_selects = [s for s in empty_selects if s.device_id == controller_2.device_id]
 
         # For main device, device_id is 0
-        main_buttons = [b for b in empty_buttons if b.device_id == 0]
+        main_selects = [s for s in empty_selects if s.device_id == 0]
 
-        # Check object IDs for empty name entities
-        assert len(c1_buttons) == 1 and c1_buttons[0].object_id == "controller_1"
-        assert len(c2_buttons) == 1 and c2_buttons[0].object_id == "controller_2"
+        # Check object IDs for empty name entities - they should use device names
+        assert len(c1_selects) == 1 and c1_selects[0].object_id == "controller_1"
+        assert len(c2_selects) == 1 and c2_selects[0].object_id == "controller_2"
         assert (
-            len(main_buttons) == 1
-            and main_buttons[0].object_id == "duplicate-entities-test"
+            len(main_selects) == 1
+            and main_selects[0].object_id == "duplicate-entities-test"
         )
 
-        # Scenario 7: Check special characters in number names
-        temp_numbers = [n for n in numbers if n.name == "Temperature Setpoint!"]
+        # Scenario 8: Check special characters in number names - now unique
+        temp_numbers = [n for n in numbers if "Temperature Setpoint!" in n.name]
         assert len(temp_numbers) == 2, (
             f"Expected exactly 2 temperature setpoint numbers, got {len(temp_numbers)}"
         )
 
-        # Special characters should be sanitized to _ in object_id
+        # Should have unique names
+        setpoint_names = set()
         for number in temp_numbers:
-            assert number.object_id == "temperature_setpoint_", (
-                f"Expected object_id 'temperature_setpoint_', got '{number.object_id}'"
-            )
+            setpoint_names.add(number.name)
+
+        assert len(setpoint_names) == 2, (
+            f"Temperature setpoint numbers should have unique names, got {setpoint_names}"
+        )
 
         # Verify we can get states for all entities (ensures they're functional)
         loop = asyncio.get_running_loop()
@@ -164,6 +192,7 @@ async def test_duplicate_entities_on_different_devices(
             + len(switches)
             + len(buttons)
             + len(numbers)
+            + len(selects)
         )
 
         def on_state(state) -> None:
diff --git a/tests/unit_tests/core/test_entity_helpers.py b/tests/unit_tests/core/test_entity_helpers.py
index e166eeedee..0dcdd84507 100644
--- a/tests/unit_tests/core/test_entity_helpers.py
+++ b/tests/unit_tests/core/test_entity_helpers.py
@@ -505,13 +505,13 @@ def test_entity_duplicate_validator() -> None:
     config1 = {CONF_NAME: "Temperature"}
     validated1 = validator(config1)
     assert validated1 == config1
-    assert ("", "sensor", "temperature") in CORE.unique_ids
+    assert ("sensor", "temperature") in CORE.unique_ids
 
     # Second entity with different name should pass
     config2 = {CONF_NAME: "Humidity"}
     validated2 = validator(config2)
     assert validated2 == config2
-    assert ("", "sensor", "humidity") in CORE.unique_ids
+    assert ("sensor", "humidity") in CORE.unique_ids
 
     # Duplicate entity should fail
     config3 = {CONF_NAME: "Temperature"}
@@ -535,24 +535,36 @@ def test_entity_duplicate_validator_with_devices() -> None:
     device1 = ID("device1", type="Device")
     device2 = ID("device2", type="Device")
 
-    # Same name on different devices should pass
+    # First entity on device1 should pass
     config1 = {CONF_NAME: "Temperature", CONF_DEVICE_ID: device1}
     validated1 = validator(config1)
     assert validated1 == config1
-    assert ("device1", "sensor", "temperature") in CORE.unique_ids
+    assert ("sensor", "temperature") in CORE.unique_ids
 
+    # Same name on different device should now fail
     config2 = {CONF_NAME: "Temperature", CONF_DEVICE_ID: device2}
-    validated2 = validator(config2)
-    assert validated2 == config2
-    assert ("device2", "sensor", "temperature") in CORE.unique_ids
-
-    # Duplicate on same device should fail
-    config3 = {CONF_NAME: "Temperature", CONF_DEVICE_ID: device1}
     with pytest.raises(
         Invalid,
-        match=r"Duplicate sensor entity with name 'Temperature' found on device 'device1'",
+        match=r"Duplicate sensor entity with name 'Temperature' found. Each entity must have a unique name within its platform across all devices.",
     ):
-        validator(config3)
+        validator(config2)
+
+    # Different name on device2 should pass
+    config3 = {CONF_NAME: "Humidity", CONF_DEVICE_ID: device2}
+    validated3 = validator(config3)
+    assert validated3 == config3
+    assert ("sensor", "humidity") in CORE.unique_ids
+
+    # Empty names should use device names and be allowed
+    config4 = {CONF_NAME: "", CONF_DEVICE_ID: device1}
+    validated4 = validator(config4)
+    assert validated4 == config4
+    assert ("sensor", "device1") in CORE.unique_ids
+
+    config5 = {CONF_NAME: "", CONF_DEVICE_ID: device2}
+    validated5 = validator(config5)
+    assert validated5 == config5
+    assert ("sensor", "device2") in CORE.unique_ids
 
 
 def test_duplicate_entity_yaml_validation(
@@ -576,10 +588,10 @@ def test_duplicate_entity_with_devices_yaml_validation(
     )
     assert result is None
 
-    # Check for the duplicate entity error message with device
+    # Check for the duplicate entity error message
     captured = capsys.readouterr()
     assert (
-        "Duplicate sensor entity with name 'Temperature' found on device 'device1'"
+        "Duplicate sensor entity with name 'Temperature' found. Each entity must have a unique name within its platform across all devices."
         in captured.out
     )
 
diff --git a/tests/unit_tests/fixtures/substitutions/.gitignore b/tests/unit_tests/fixtures/substitutions/.gitignore
new file mode 100644
index 0000000000..0b15cdb2b7
--- /dev/null
+++ b/tests/unit_tests/fixtures/substitutions/.gitignore
@@ -0,0 +1 @@
+*.received.yaml
\ No newline at end of file
diff --git a/tests/unit_tests/fixtures/substitutions/00-simple_var.approved.yaml b/tests/unit_tests/fixtures/substitutions/00-simple_var.approved.yaml
new file mode 100644
index 0000000000..c031399c37
--- /dev/null
+++ b/tests/unit_tests/fixtures/substitutions/00-simple_var.approved.yaml
@@ -0,0 +1,19 @@
+substitutions:
+  var1: '1'
+  var2: '2'
+  var21: '79'
+esphome:
+  name: test
+test_list:
+  - '1'
+  - '1'
+  - '1'
+  - '1'
+  - 'Values: 1 2'
+  - 'Value: 79'
+  - 1 + 2
+  - 1 * 2
+  - 'Undefined var: ${undefined_var}'
+  - ${undefined_var}
+  - $undefined_var
+  - ${ undefined_var }
diff --git a/tests/unit_tests/fixtures/substitutions/00-simple_var.input.yaml b/tests/unit_tests/fixtures/substitutions/00-simple_var.input.yaml
new file mode 100644
index 0000000000..88a4ffb991
--- /dev/null
+++ b/tests/unit_tests/fixtures/substitutions/00-simple_var.input.yaml
@@ -0,0 +1,21 @@
+esphome:
+  name: test
+
+substitutions:
+  var1: "1"
+  var2: "2"
+  var21: "79"
+
+test_list:
+  - "$var1"
+  - "${var1}"
+  - $var1
+  - ${var1}
+  - "Values: $var1 ${var2}"
+  - "Value: ${var2${var1}}"
+  - "$var1 + $var2"
+  - "${ var1 } * ${ var2 }"
+  - "Undefined var: ${undefined_var}"
+  - ${undefined_var}
+  - $undefined_var
+  - ${ undefined_var }
diff --git a/tests/unit_tests/fixtures/substitutions/01-include.approved.yaml b/tests/unit_tests/fixtures/substitutions/01-include.approved.yaml
new file mode 100644
index 0000000000..a812fedcfd
--- /dev/null
+++ b/tests/unit_tests/fixtures/substitutions/01-include.approved.yaml
@@ -0,0 +1,15 @@
+substitutions:
+  var1: '1'
+  var2: '2'
+  a: alpha
+test_list:
+  - values:
+      - var1: '1'
+      - a: A
+      - b: B-default
+      - c: The value of C is C
+  - values:
+      - var1: '1'
+      - a: alpha
+      - b: beta
+      - c: The value of C is $c
diff --git a/tests/unit_tests/fixtures/substitutions/01-include.input.yaml b/tests/unit_tests/fixtures/substitutions/01-include.input.yaml
new file mode 100644
index 0000000000..d3daa681a4
--- /dev/null
+++ b/tests/unit_tests/fixtures/substitutions/01-include.input.yaml
@@ -0,0 +1,15 @@
+substitutions:
+  var1: "1"
+  var2: "2"
+  a: "alpha"
+
+test_list:
+  - !include
+    file: inc1.yaml
+    vars:
+      a: "A"
+      c: "C"
+  - !include
+    file: inc1.yaml
+    vars:
+      b: "beta"
diff --git a/tests/unit_tests/fixtures/substitutions/02-expressions.approved.yaml b/tests/unit_tests/fixtures/substitutions/02-expressions.approved.yaml
new file mode 100644
index 0000000000..9e401ec5d6
--- /dev/null
+++ b/tests/unit_tests/fixtures/substitutions/02-expressions.approved.yaml
@@ -0,0 +1,24 @@
+substitutions:
+  width: 7
+  height: 8
+  enabled: true
+  pin: &id001
+    number: 18
+    inverted: true
+  area: 25
+  numberOne: 1
+  var1: 79
+test_list:
+  - The area is 56
+  - 56
+  - 56 + 1
+  - ENABLED
+  - list:
+      - 7
+      - 8
+  - width: 7
+    height: 8
+  - *id001
+  - The pin number is 18
+  - The square root is: 5.0
+  - The number is 80
diff --git a/tests/unit_tests/fixtures/substitutions/02-expressions.input.yaml b/tests/unit_tests/fixtures/substitutions/02-expressions.input.yaml
new file mode 100644
index 0000000000..1777b46f67
--- /dev/null
+++ b/tests/unit_tests/fixtures/substitutions/02-expressions.input.yaml
@@ -0,0 +1,22 @@
+substitutions:
+  width: 7
+  height: 8
+  enabled: true
+  pin:
+    number: 18
+    inverted: true
+  area: 25
+  numberOne: 1
+  var1: 79
+
+test_list:
+  - "The area is ${width * height}"
+  - ${width * height}
+  - ${width * height} + 1
+  - ${enabled and "ENABLED" or "DISABLED"}
+  - list: ${ [width, height] }
+  - "${ {'width': width, 'height': height} }"
+  - ${pin}
+  - The pin number is ${pin.number}
+  - The square root is: ${math.sqrt(area)}
+  - The number is ${var${numberOne} + 1}
diff --git a/tests/unit_tests/fixtures/substitutions/03-closures.approved.yaml b/tests/unit_tests/fixtures/substitutions/03-closures.approved.yaml
new file mode 100644
index 0000000000..c8f7d9976c
--- /dev/null
+++ b/tests/unit_tests/fixtures/substitutions/03-closures.approved.yaml
@@ -0,0 +1,17 @@
+substitutions:
+  B: 5
+  var7: 79
+package_result:
+  - The value of A*B is 35, where A is a package var and B is a substitution in the
+    root file
+  - Double substitution also works; the value of var7 is 79, where A is a package
+    var
+local_results:
+  - The value of B is 5
+  - 'You will see, however, that
+
+    ${A} is not substituted here, since
+
+    it is out of scope.
+
+    '
diff --git a/tests/unit_tests/fixtures/substitutions/03-closures.input.yaml b/tests/unit_tests/fixtures/substitutions/03-closures.input.yaml
new file mode 100644
index 0000000000..e0b2c39e52
--- /dev/null
+++ b/tests/unit_tests/fixtures/substitutions/03-closures.input.yaml
@@ -0,0 +1,16 @@
+substitutions:
+  B: 5
+  var7: 79
+
+packages:
+  closures_package: !include
+    file: closures_package.yaml
+    vars:
+      A: 7
+
+local_results:
+  - The value of B is ${B}
+  - |
+    You will see, however, that
+    ${A} is not substituted here, since
+    it is out of scope.
diff --git a/tests/unit_tests/fixtures/substitutions/04-display_example.approved.yaml b/tests/unit_tests/fixtures/substitutions/04-display_example.approved.yaml
new file mode 100644
index 0000000000..f559181b45
--- /dev/null
+++ b/tests/unit_tests/fixtures/substitutions/04-display_example.approved.yaml
@@ -0,0 +1,5 @@
+display:
+  - platform: ili9xxx
+    dimensions:
+      width: 960
+      height: 544
diff --git a/tests/unit_tests/fixtures/substitutions/04-display_example.input.yaml b/tests/unit_tests/fixtures/substitutions/04-display_example.input.yaml
new file mode 100644
index 0000000000..9d8f64a253
--- /dev/null
+++ b/tests/unit_tests/fixtures/substitutions/04-display_example.input.yaml
@@ -0,0 +1,7 @@
+# main.yaml
+packages:
+  my_display: !include
+    file: display.yaml
+    vars:
+      high_dpi: true
+      native_height: 272
diff --git a/tests/unit_tests/fixtures/substitutions/closures_package.yaml b/tests/unit_tests/fixtures/substitutions/closures_package.yaml
new file mode 100644
index 0000000000..e87908814d
--- /dev/null
+++ b/tests/unit_tests/fixtures/substitutions/closures_package.yaml
@@ -0,0 +1,3 @@
+package_result:
+  - The value of A*B is ${A * B}, where A is a package var and B is a substitution in the root file
+  - Double substitution also works; the value of var7 is ${var$A}, where A is a package var
diff --git a/tests/unit_tests/fixtures/substitutions/display.yaml b/tests/unit_tests/fixtures/substitutions/display.yaml
new file mode 100644
index 0000000000..1e2249dddb
--- /dev/null
+++ b/tests/unit_tests/fixtures/substitutions/display.yaml
@@ -0,0 +1,11 @@
+# display.yaml
+
+defaults:
+  native_width: 480
+  native_height: 480
+
+display:
+  - platform: ili9xxx
+    dimensions:
+      width: ${high_dpi and native_width * 2 or native_width}
+      height: ${high_dpi and native_height * 2 or native_height}
diff --git a/tests/unit_tests/fixtures/substitutions/inc1.yaml b/tests/unit_tests/fixtures/substitutions/inc1.yaml
new file mode 100644
index 0000000000..65b91a5e16
--- /dev/null
+++ b/tests/unit_tests/fixtures/substitutions/inc1.yaml
@@ -0,0 +1,8 @@
+defaults:
+  b: "B-default"
+
+values:
+  - var1: $var1
+  - a: $a
+  - b: ${b}
+  - c: The value of C is $c
diff --git a/tests/unit_tests/test_substitutions.py b/tests/unit_tests/test_substitutions.py
new file mode 100644
index 0000000000..b377499d29
--- /dev/null
+++ b/tests/unit_tests/test_substitutions.py
@@ -0,0 +1,125 @@
+import glob
+import logging
+import os
+
+from esphome import yaml_util
+from esphome.components import substitutions
+from esphome.const import CONF_PACKAGES
+
+_LOGGER = logging.getLogger(__name__)
+
+# Set to True for dev mode behavior
+# This will generate the expected version of the test files.
+
+DEV_MODE = False
+
+
+def sort_dicts(obj):
+    """Recursively sort dictionaries for order-insensitive comparison."""
+    if isinstance(obj, dict):
+        return {k: sort_dicts(obj[k]) for k in sorted(obj)}
+    elif isinstance(obj, list):
+        # Lists are not sorted; we preserve order
+        return [sort_dicts(i) for i in obj]
+    else:
+        return obj
+
+
+def dict_diff(a, b, path=""):
+    """Recursively find differences between two dict/list structures."""
+    diffs = []
+    if isinstance(a, dict) and isinstance(b, dict):
+        a_keys = set(a)
+        b_keys = set(b)
+        for key in a_keys - b_keys:
+            diffs.append(f"{path}/{key} only in actual")
+        for key in b_keys - a_keys:
+            diffs.append(f"{path}/{key} only in expected")
+        for key in a_keys & b_keys:
+            diffs.extend(dict_diff(a[key], b[key], f"{path}/{key}"))
+    elif isinstance(a, list) and isinstance(b, list):
+        min_len = min(len(a), len(b))
+        for i in range(min_len):
+            diffs.extend(dict_diff(a[i], b[i], f"{path}[{i}]"))
+        if len(a) > len(b):
+            for i in range(min_len, len(a)):
+                diffs.append(f"{path}[{i}] only in actual: {a[i]!r}")
+        elif len(b) > len(a):
+            for i in range(min_len, len(b)):
+                diffs.append(f"{path}[{i}] only in expected: {b[i]!r}")
+    else:
+        if a != b:
+            diffs.append(f"\t{path}: actual={a!r} expected={b!r}")
+    return diffs
+
+
+def write_yaml(path, data):
+    with open(path, "w", encoding="utf-8") as f:
+        f.write(yaml_util.dump(data))
+
+
+def test_substitutions_fixtures(fixture_path):
+    base_dir = fixture_path / "substitutions"
+    sources = sorted(glob.glob(str(base_dir / "*.input.yaml")))
+    assert sources, f"No input YAML files found in {base_dir}"
+
+    failures = []
+    for source_path in sources:
+        try:
+            expected_path = source_path.replace(".input.yaml", ".approved.yaml")
+            test_case = os.path.splitext(os.path.basename(source_path))[0].replace(
+                ".input", ""
+            )
+
+            # Load using ESPHome's YAML loader
+            config = yaml_util.load_yaml(source_path)
+
+            if CONF_PACKAGES in config:
+                from esphome.components.packages import do_packages_pass
+
+                config = do_packages_pass(config)
+
+            substitutions.do_substitution_pass(config, None)
+
+            # Also load expected using ESPHome's loader, or use {} if missing and DEV_MODE
+            if os.path.isfile(expected_path):
+                expected = yaml_util.load_yaml(expected_path)
+            elif DEV_MODE:
+                expected = {}
+            else:
+                assert os.path.isfile(expected_path), (
+                    f"Expected file missing: {expected_path}"
+                )
+
+            # Sort dicts only (not lists) for comparison
+            got_sorted = sort_dicts(config)
+            expected_sorted = sort_dicts(expected)
+
+            if got_sorted != expected_sorted:
+                diff = "\n".join(dict_diff(got_sorted, expected_sorted))
+                msg = (
+                    f"Substitution result mismatch for {os.path.basename(source_path)}\n"
+                    f"Diff:\n{diff}\n\n"
+                    f"Got:      {got_sorted}\n"
+                    f"Expected: {expected_sorted}"
+                )
+                # Write out the received file when test fails
+                if DEV_MODE:
+                    received_path = os.path.join(
+                        os.path.dirname(source_path), f"{test_case}.received.yaml"
+                    )
+                    write_yaml(received_path, config)
+                    print(msg)
+                    failures.append(msg)
+                else:
+                    raise AssertionError(msg)
+        except Exception as err:
+            _LOGGER.error("Error in test file %s", source_path)
+            raise err
+
+    if DEV_MODE and failures:
+        print(f"\n{len(failures)} substitution test case(s) failed.")
+
+    if DEV_MODE:
+        _LOGGER.error("Tests passed, but Dev mode is enabled.")
+    assert not DEV_MODE  # make sure DEV_MODE is disabled after you are finished.