From 253e3ec6f63b16ca3ee4030e77a0236557360efe Mon Sep 17 00:00:00 2001 From: Nate Clark Date: Mon, 28 Apr 2025 00:27:39 -0400 Subject: [PATCH] [mdns] Support templatable config options for MDNS extra services (#8606) --- esphome/components/mdns/__init__.py | 16 +++++++++++----- esphome/components/mdns/mdns_component.cpp | 6 ++++-- esphome/components/mdns/mdns_component.h | 5 +++-- esphome/components/mdns/mdns_esp32.cpp | 7 ++++--- esphome/components/mdns/mdns_esp8266.cpp | 6 ++++-- esphome/components/mdns/mdns_libretiny.cpp | 6 ++++-- esphome/components/mdns/mdns_rp2040.cpp | 6 ++++-- esphome/core/automation.h | 7 ++++--- tests/components/mdns/common-enabled.yaml | 7 +++++++ 9 files changed, 45 insertions(+), 21 deletions(-) diff --git a/esphome/components/mdns/__init__.py b/esphome/components/mdns/__init__.py index e8902d5222..4b5e40dfea 100644 --- a/esphome/components/mdns/__init__.py +++ b/esphome/components/mdns/__init__.py @@ -35,8 +35,8 @@ SERVICE_SCHEMA = cv.Schema( { cv.Required(CONF_SERVICE): cv.string, cv.Required(CONF_PROTOCOL): cv.string, - cv.Optional(CONF_PORT, default=0): cv.Any(0, cv.port), - cv.Optional(CONF_TXT, default={}): {cv.string: cv.string}, + cv.Optional(CONF_PORT, default=0): cv.templatable(cv.Any(0, cv.port)), + cv.Optional(CONF_TXT, default={}): {cv.string: cv.templatable(cv.string)}, } ) @@ -102,12 +102,18 @@ async def to_code(config): for service in config[CONF_SERVICES]: txt = [ - mdns_txt_record(txt_key, txt_value) + cg.StructInitializer( + MDNSTXTRecord, + ("key", txt_key), + ("value", await cg.templatable(txt_value, [], cg.std_string)), + ) for txt_key, txt_value in service[CONF_TXT].items() ] - exp = mdns_service( - service[CONF_SERVICE], service[CONF_PROTOCOL], service[CONF_PORT], txt + service[CONF_SERVICE], + service[CONF_PROTOCOL], + await cg.templatable(service[CONF_PORT], [], cg.uint16), + txt, ) cg.add(var.add_extra_service(exp)) diff --git a/esphome/components/mdns/mdns_component.cpp b/esphome/components/mdns/mdns_component.cpp index 7f4b749456..ffc668e218 100644 --- a/esphome/components/mdns/mdns_component.cpp +++ b/esphome/components/mdns/mdns_component.cpp @@ -121,9 +121,11 @@ void MDNSComponent::dump_config() { ESP_LOGCONFIG(TAG, " Hostname: %s", this->hostname_.c_str()); ESP_LOGV(TAG, " Services:"); for (const auto &service : this->services_) { - ESP_LOGV(TAG, " - %s, %s, %d", service.service_type.c_str(), service.proto.c_str(), service.port); + 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) { - ESP_LOGV(TAG, " TXT: %s = %s", record.key.c_str(), record.value.c_str()); + ESP_LOGV(TAG, " TXT: %s = %s", record.key.c_str(), + const_cast &>(record.value).value().c_str()); } } } diff --git a/esphome/components/mdns/mdns_component.h b/esphome/components/mdns/mdns_component.h index dfb5b72292..9eb2ba11d0 100644 --- a/esphome/components/mdns/mdns_component.h +++ b/esphome/components/mdns/mdns_component.h @@ -3,6 +3,7 @@ #ifdef USE_MDNS #include #include +#include "esphome/core/automation.h" #include "esphome/core/component.h" namespace esphome { @@ -10,7 +11,7 @@ namespace mdns { struct MDNSTXTRecord { std::string key; - std::string value; + TemplatableValue value; }; struct MDNSService { @@ -20,7 +21,7 @@ struct MDNSService { // second label indicating protocol _including_ underscore character prefix // as defined in RFC6763 Section 7, like "_tcp" or "_udp" std::string proto; - uint16_t port; + TemplatableValue port; std::vector txt_records; }; diff --git a/esphome/components/mdns/mdns_esp32.cpp b/esphome/components/mdns/mdns_esp32.cpp index 8006eb27f1..fed18d3630 100644 --- a/esphome/components/mdns/mdns_esp32.cpp +++ b/esphome/components/mdns/mdns_esp32.cpp @@ -31,11 +31,12 @@ void MDNSComponent::setup() { mdns_txt_item_t it{}; // dup strings to ensure the pointer is valid even after the record loop it.key = strdup(record.key.c_str()); - it.value = strdup(record.value.c_str()); + it.value = strdup(const_cast &>(record.value).value().c_str()); txt_records.push_back(it); } - err = mdns_service_add(nullptr, service.service_type.c_str(), service.proto.c_str(), service.port, - txt_records.data(), txt_records.size()); + uint16_t port = const_cast &>(service.port).value(); + err = mdns_service_add(nullptr, service.service_type.c_str(), service.proto.c_str(), port, txt_records.data(), + txt_records.size()); // free records for (const auto &it : txt_records) { diff --git a/esphome/components/mdns/mdns_esp8266.cpp b/esphome/components/mdns/mdns_esp8266.cpp index 7b6e7ec448..2c90d57021 100644 --- a/esphome/components/mdns/mdns_esp8266.cpp +++ b/esphome/components/mdns/mdns_esp8266.cpp @@ -29,9 +29,11 @@ void MDNSComponent::setup() { while (*service_type == '_') { service_type++; } - MDNS.addService(service_type, proto, service.port); + uint16_t port = const_cast &>(service.port).value(); + MDNS.addService(service_type, proto, port); for (const auto &record : service.txt_records) { - MDNS.addServiceTxt(service_type, proto, record.key.c_str(), record.value.c_str()); + MDNS.addServiceTxt(service_type, proto, record.key.c_str(), + const_cast &>(record.value).value().c_str()); } } } diff --git a/esphome/components/mdns/mdns_libretiny.cpp b/esphome/components/mdns/mdns_libretiny.cpp index c9a9a289dd..7a41ec9dce 100644 --- a/esphome/components/mdns/mdns_libretiny.cpp +++ b/esphome/components/mdns/mdns_libretiny.cpp @@ -29,9 +29,11 @@ void MDNSComponent::setup() { while (*service_type == '_') { service_type++; } - MDNS.addService(service_type, proto, service.port); + uint16_t port_ = const_cast &>(service.port).value(); + MDNS.addService(service_type, proto, port_); for (const auto &record : service.txt_records) { - MDNS.addServiceTxt(service_type, proto, record.key.c_str(), record.value.c_str()); + MDNS.addServiceTxt(service_type, proto, record.key.c_str(), + const_cast &>(record.value).value().c_str()); } } } diff --git a/esphome/components/mdns/mdns_rp2040.cpp b/esphome/components/mdns/mdns_rp2040.cpp index 89e668ee59..95894323f4 100644 --- a/esphome/components/mdns/mdns_rp2040.cpp +++ b/esphome/components/mdns/mdns_rp2040.cpp @@ -29,9 +29,11 @@ void MDNSComponent::setup() { while (*service_type == '_') { service_type++; } - MDNS.addService(service_type, proto, service.port); + uint16_t port = const_cast &>(service.port).value(); + MDNS.addService(service_type, proto, port); for (const auto &record : service.txt_records) { - MDNS.addServiceTxt(service_type, proto, record.key.c_str(), record.value.c_str()); + MDNS.addServiceTxt(service_type, proto, record.key.c_str(), + const_cast &>(record.value).value().c_str()); } } } diff --git a/esphome/core/automation.h b/esphome/core/automation.h index e77e453431..02c9d44f16 100644 --- a/esphome/core/automation.h +++ b/esphome/core/automation.h @@ -1,10 +1,11 @@ #pragma once -#include #include "esphome/core/component.h" -#include "esphome/core/helpers.h" #include "esphome/core/defines.h" +#include "esphome/core/helpers.h" #include "esphome/core/preferences.h" +#include +#include namespace esphome { @@ -27,7 +28,7 @@ template class TemplatableValue { TemplatableValue() : type_(NONE) {} template::value, int> = 0> - TemplatableValue(F value) : type_(VALUE), value_(value) {} + TemplatableValue(F value) : type_(VALUE), value_(std::move(value)) {} template::value, int> = 0> TemplatableValue(F f) : type_(LAMBDA), f_(f) {} diff --git a/tests/components/mdns/common-enabled.yaml b/tests/components/mdns/common-enabled.yaml index bc31e32783..8b3d81cf69 100644 --- a/tests/components/mdns/common-enabled.yaml +++ b/tests/components/mdns/common-enabled.yaml @@ -4,3 +4,10 @@ wifi: mdns: disabled: false + services: + - service: _test_service + protocol: _tcp + port: 8888 + txt: + static_string: Anything + templated_string: !lambda return "Something else";