diff --git a/esphome/components/mdns/__init__.py b/esphome/components/mdns/__init__.py index a84fe5a249..f023f84750 100644 --- a/esphome/components/mdns/__init__.py +++ b/esphome/components/mdns/__init__.py @@ -91,12 +91,36 @@ async def to_code(config): cg.add_define("USE_MDNS") + # Calculate compile-time service count + service_count = 0 + + # Check if API component is enabled (it may create a service at runtime) + if cg.is_defined("USE_API"): + service_count += 1 + + # Check for prometheus + if cg.is_defined("USE_PROMETHEUS"): + service_count += 1 + + # Check for web_server + if cg.is_defined("USE_WEBSERVER"): + service_count += 1 + + # Count extra services from config + extra_services_count = len(config[CONF_SERVICES]) + if extra_services_count > 0: + service_count += extra_services_count + cg.add_define("USE_MDNS_EXTRA_SERVICES") + + # Ensure at least 1 service (fallback service) + if service_count == 0: + service_count = 1 + + cg.add_define("MDNS_SERVICE_COUNT", service_count) + var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) - if config[CONF_SERVICES]: - cg.add_define("USE_MDNS_EXTRA_SERVICES") - for service in config[CONF_SERVICES]: txt = [ cg.StructInitializer( diff --git a/esphome/components/mdns/mdns_component.cpp b/esphome/components/mdns/mdns_component.cpp index 5d9788198f..5a5286c5bc 100644 --- a/esphome/components/mdns/mdns_component.cpp +++ b/esphome/components/mdns/mdns_component.cpp @@ -73,33 +73,11 @@ MDNS_STATIC_CONST_CHAR(NETWORK_THREAD, "thread"); void MDNSComponent::compile_records_() { this->hostname_ = App.get_name(); - - // Calculate exact capacity needed for services vector - size_t services_count = 0; -#ifdef USE_API - if (api::global_api_server != nullptr) { - services_count++; - } -#endif -#ifdef USE_PROMETHEUS - services_count++; -#endif -#ifdef USE_WEBSERVER - services_count++; -#endif -#ifdef USE_MDNS_EXTRA_SERVICES - services_count += this->services_extra_.size(); -#endif - // Reserve for fallback service if needed - if (services_count == 0) { - services_count = 1; - } - this->services_.reserve(services_count); + this->services_count_ = 0; #ifdef USE_API if (api::global_api_server != nullptr) { - this->services_.emplace_back(); - auto &service = this->services_.back(); + auto &service = this->services_[this->services_count_++]; service.service_type = MDNS_STR(SERVICE_ESPHOMELIB); service.proto = MDNS_STR(SERVICE_TCP); service.port = api::global_api_server->get_port(); @@ -178,30 +156,29 @@ void MDNSComponent::compile_records_() { #endif // USE_API #ifdef USE_PROMETHEUS - this->services_.emplace_back(); - auto &prom_service = this->services_.back(); + auto &prom_service = this->services_[this->services_count_++]; prom_service.service_type = MDNS_STR(SERVICE_PROMETHEUS); prom_service.proto = MDNS_STR(SERVICE_TCP); prom_service.port = USE_WEBSERVER_PORT; #endif #ifdef USE_WEBSERVER - this->services_.emplace_back(); - auto &web_service = this->services_.back(); + auto &web_service = this->services_[this->services_count_++]; web_service.service_type = MDNS_STR(SERVICE_HTTP); web_service.proto = MDNS_STR(SERVICE_TCP); web_service.port = USE_WEBSERVER_PORT; #endif #ifdef USE_MDNS_EXTRA_SERVICES - this->services_.insert(this->services_.end(), this->services_extra_.begin(), this->services_extra_.end()); + for (const auto &extra_service : this->services_extra_) { + this->services_[this->services_count_++] = extra_service; + } #endif #if !defined(USE_API) && !defined(USE_PROMETHEUS) && !defined(USE_WEBSERVER) && !defined(USE_MDNS_EXTRA_SERVICES) // Publish "http" service if not using native API or any other services // This is just to have *some* mDNS service so that .local resolution works - this->services_.emplace_back(); - auto &fallback_service = this->services_.back(); + auto &fallback_service = this->services_[this->services_count_++]; fallback_service.service_type = "_http"; fallback_service.proto = "_tcp"; fallback_service.port = USE_WEBSERVER_PORT; @@ -209,6 +186,12 @@ void MDNSComponent::compile_records_() { #endif } +#ifdef USE_MDNS_EXTRA_SERVICES +void MDNSComponent::add_extra_service(MDNSService service) { + this->services_[this->services_count_++] = std::move(service); +} +#endif + void MDNSComponent::dump_config() { ESP_LOGCONFIG(TAG, "mDNS:\n" @@ -216,7 +199,8 @@ void MDNSComponent::dump_config() { this->hostname_.c_str()); #if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE ESP_LOGV(TAG, " Services:"); - for (const auto &service : this->services_) { + for (uint8_t i = 0; i < this->services_count_; i++) { + const auto &service = this->services_[i]; ESP_LOGV(TAG, " - %s, %s, %d", service.service_type.c_str(), service.proto.c_str(), const_cast &>(service.port).value()); for (const auto &record : service.txt_records) { @@ -227,8 +211,6 @@ void MDNSComponent::dump_config() { #endif } -std::vector MDNSComponent::get_services() { return this->services_; } - } // namespace mdns } // namespace esphome #endif diff --git a/esphome/components/mdns/mdns_component.h b/esphome/components/mdns/mdns_component.h index f87ef08bcd..e653e9384f 100644 --- a/esphome/components/mdns/mdns_component.h +++ b/esphome/components/mdns/mdns_component.h @@ -1,14 +1,17 @@ #pragma once #include "esphome/core/defines.h" #ifdef USE_MDNS +#include #include -#include #include "esphome/core/automation.h" #include "esphome/core/component.h" namespace esphome { namespace mdns { +// Service count is calculated at compile time by Python codegen +// MDNS_SERVICE_COUNT will always be defined + struct MDNSTXTRecord { std::string key; TemplatableValue value; @@ -36,18 +39,17 @@ class MDNSComponent : public Component { float get_setup_priority() const override { return setup_priority::AFTER_CONNECTION; } #ifdef USE_MDNS_EXTRA_SERVICES - void add_extra_service(MDNSService service) { services_extra_.push_back(std::move(service)); } + void add_extra_service(MDNSService service); #endif - std::vector get_services(); + const std::array &get_services() const { return services_; } + uint8_t get_services_count() const { return services_count_; } void on_shutdown() override; protected: -#ifdef USE_MDNS_EXTRA_SERVICES - std::vector services_extra_{}; -#endif - std::vector services_{}; + std::array services_{}; + uint8_t services_count_{0}; std::string hostname_; void compile_records_(); }; diff --git a/esphome/components/openthread/openthread.cpp b/esphome/components/openthread/openthread.cpp index 5b5c113f83..3caec9b698 100644 --- a/esphome/components/openthread/openthread.cpp +++ b/esphome/components/openthread/openthread.cpp @@ -143,11 +143,12 @@ void OpenThreadSrpComponent::setup() { return; } - // Copy the mdns services to our local instance so that the c_str pointers remain valid for the lifetime of this - // component - this->mdns_services_ = this->mdns_->get_services(); - ESP_LOGD(TAG, "Setting up SRP services. count = %d\n", this->mdns_services_.size()); - for (const auto &service : this->mdns_services_) { + // Use mdns services directly - they remain valid for the lifetime of the mdns component + const auto &mdns_services = this->mdns_->get_services(); + uint8_t mdns_count = this->mdns_->get_services_count(); + ESP_LOGD(TAG, "Setting up SRP services. count = %d\n", mdns_count); + for (uint8_t i = 0; i < mdns_count; i++) { + const auto &service = mdns_services[i]; otSrpClientBuffersServiceEntry *entry = otSrpClientBuffersAllocateService(instance); if (!entry) { ESP_LOGW(TAG, "Failed to allocate service entry"); diff --git a/esphome/components/openthread/openthread.h b/esphome/components/openthread/openthread.h index a9aff78e56..5d139c633d 100644 --- a/esphome/components/openthread/openthread.h +++ b/esphome/components/openthread/openthread.h @@ -57,7 +57,6 @@ class OpenThreadSrpComponent : public Component { protected: esphome::mdns::MDNSComponent *mdns_{nullptr}; - std::vector mdns_services_; std::vector> memory_pool_; void *pool_alloc_(size_t size); };