diff --git a/esphome/components/mdns/__init__.py b/esphome/components/mdns/__init__.py index 469fe8ada6..d22e630d8c 100644 --- a/esphome/components/mdns/__init__.py +++ b/esphome/components/mdns/__init__.py @@ -90,12 +90,38 @@ async def to_code(config): cg.add_define("USE_MDNS") + # Count how many services we'll have at compile time + service_count = 0 + + # Check if API is enabled (USE_API is defined by api component) + if "api" in CORE.config: + service_count += 1 + + # Check if Prometheus is enabled (USE_PROMETHEUS is defined by prometheus component) + if "prometheus" in CORE.config: + service_count += 1 + + # Check if Web Server is enabled (USE_WEBSERVER is defined by web_server component) + if "web_server" in CORE.config: + service_count += 1 + + # Count extra services from config + extra_service_count = len(config.get(CONF_SERVICES, [])) + if extra_service_count > 0: + service_count += extra_service_count + cg.add_define("USE_MDNS_EXTRA_SERVICES") + cg.add_define("MDNS_EXTRA_SERVICE_COUNT", extra_service_count) + + # If no services, we'll add a fallback HTTP service + if service_count == 0: + service_count = 1 + + # Define the total service count + 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 640750720d..356533b9ba 100644 --- a/esphome/components/mdns/mdns_component.cpp +++ b/esphome/components/mdns/mdns_component.cpp @@ -24,7 +24,8 @@ static const char *const TAG = "mdns"; void MDNSComponent::compile_records_() { this->hostname_ = App.get_name(); - this->services_.clear(); + this->service_count_ = 0; + #ifdef USE_API if (api::global_api_server != nullptr) { MDNSService service{}; @@ -80,7 +81,7 @@ void MDNSComponent::compile_records_() { service.txt_records.push_back({"package_import_url", dashboard_import::get_package_import_url()}); #endif - this->services_.push_back(service); + this->services_[this->service_count_++] = service; } #endif // USE_API @@ -90,7 +91,7 @@ void MDNSComponent::compile_records_() { service.service_type = "_prometheus-http"; service.proto = "_tcp"; service.port = USE_WEBSERVER_PORT; - this->services_.push_back(service); + this->services_[this->service_count_++] = service; } #endif @@ -100,15 +101,17 @@ void MDNSComponent::compile_records_() { service.service_type = "_http"; service.proto = "_tcp"; service.port = USE_WEBSERVER_PORT; - this->services_.push_back(service); + this->services_[this->service_count_++] = service; } #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->service_count_++] = extra_service; + } #endif - if (this->services_.empty()) { + if (this->service_count_ == 0) { // Publish "http" service if not using native API // This is just to have *some* mDNS service so that .local resolution works MDNSService service{}; @@ -116,7 +119,7 @@ void MDNSComponent::compile_records_() { service.proto = "_tcp"; service.port = USE_WEBSERVER_PORT; service.txt_records.push_back({"version", ESPHOME_VERSION}); - this->services_.push_back(service); + this->services_[this->service_count_++] = service; } } @@ -126,7 +129,8 @@ void MDNSComponent::dump_config() { " Hostname: %s", this->hostname_.c_str()); ESP_LOGV(TAG, " Services:"); - for (const auto &service : this->services_) { + for (size_t i = 0; i < this->service_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) { @@ -136,8 +140,6 @@ void MDNSComponent::dump_config() { } } -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..1fec7f5efd 100644 --- a/esphome/components/mdns/mdns_component.h +++ b/esphome/components/mdns/mdns_component.h @@ -1,6 +1,7 @@ #pragma once #include "esphome/core/defines.h" #ifdef USE_MDNS +#include #include #include #include "esphome/core/automation.h" @@ -39,7 +40,8 @@ class MDNSComponent : public Component { void add_extra_service(MDNSService service) { services_extra_.push_back(std::move(service)); } #endif - std::vector get_services(); + const std::array &get_services() const { return this->services_; } + size_t get_service_count() const { return this->service_count_; } void on_shutdown() override; @@ -47,7 +49,8 @@ class MDNSComponent : public Component { #ifdef USE_MDNS_EXTRA_SERVICES std::vector services_extra_{}; #endif - std::vector services_{}; + std::array services_{}; + size_t service_count_{0}; // Track how many services are actually populated std::string hostname_; void compile_records_(); }; diff --git a/esphome/components/openthread/openthread.cpp b/esphome/components/openthread/openthread.cpp index 322ff43238..729403ff15 100644 --- a/esphome/components/openthread/openthread.cpp +++ b/esphome/components/openthread/openthread.cpp @@ -125,11 +125,14 @@ 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_) { + // Get the mdns services directly from the component + // No lifetime concerns since OpenThread runs after MDNS component (enforced by get_setup_priority) + // and the services array in MDNS component lives for the entire application lifetime + const auto &services = this->mdns_->get_services(); + size_t service_count = this->mdns_->get_service_count(); + ESP_LOGD(TAG, "Setting up SRP services. count = %d\n", service_count); + for (size_t i = 0; i < service_count; i++) { + const auto &service = 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 a0ea1b3f3a..7c248b6249 100644 --- a/esphome/components/openthread/openthread.h +++ b/esphome/components/openthread/openthread.h @@ -46,7 +46,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); };