[mdns] Support templatable config options for MDNS extra services (#8606)

This commit is contained in:
Nate Clark 2025-04-28 00:27:39 -04:00 committed by GitHub
parent fdc4ec8a57
commit 253e3ec6f6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 45 additions and 21 deletions

View File

@ -35,8 +35,8 @@ SERVICE_SCHEMA = cv.Schema(
{ {
cv.Required(CONF_SERVICE): cv.string, cv.Required(CONF_SERVICE): cv.string,
cv.Required(CONF_PROTOCOL): cv.string, cv.Required(CONF_PROTOCOL): cv.string,
cv.Optional(CONF_PORT, default=0): cv.Any(0, cv.port), cv.Optional(CONF_PORT, default=0): cv.templatable(cv.Any(0, cv.port)),
cv.Optional(CONF_TXT, default={}): {cv.string: cv.string}, 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]: for service in config[CONF_SERVICES]:
txt = [ 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() for txt_key, txt_value in service[CONF_TXT].items()
] ]
exp = mdns_service( 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)) cg.add(var.add_extra_service(exp))

View File

@ -121,9 +121,11 @@ void MDNSComponent::dump_config() {
ESP_LOGCONFIG(TAG, " Hostname: %s", this->hostname_.c_str()); ESP_LOGCONFIG(TAG, " Hostname: %s", this->hostname_.c_str());
ESP_LOGV(TAG, " Services:"); ESP_LOGV(TAG, " Services:");
for (const auto &service : this->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<TemplatableValue<uint16_t> &>(service.port).value());
for (const auto &record : service.txt_records) { 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<TemplatableValue<std::string> &>(record.value).value().c_str());
} }
} }
} }

View File

@ -3,6 +3,7 @@
#ifdef USE_MDNS #ifdef USE_MDNS
#include <string> #include <string>
#include <vector> #include <vector>
#include "esphome/core/automation.h"
#include "esphome/core/component.h" #include "esphome/core/component.h"
namespace esphome { namespace esphome {
@ -10,7 +11,7 @@ namespace mdns {
struct MDNSTXTRecord { struct MDNSTXTRecord {
std::string key; std::string key;
std::string value; TemplatableValue<std::string> value;
}; };
struct MDNSService { struct MDNSService {
@ -20,7 +21,7 @@ struct MDNSService {
// second label indicating protocol _including_ underscore character prefix // second label indicating protocol _including_ underscore character prefix
// as defined in RFC6763 Section 7, like "_tcp" or "_udp" // as defined in RFC6763 Section 7, like "_tcp" or "_udp"
std::string proto; std::string proto;
uint16_t port; TemplatableValue<uint16_t> port;
std::vector<MDNSTXTRecord> txt_records; std::vector<MDNSTXTRecord> txt_records;
}; };

View File

@ -31,11 +31,12 @@ void MDNSComponent::setup() {
mdns_txt_item_t it{}; mdns_txt_item_t it{};
// dup strings to ensure the pointer is valid even after the record loop // dup strings to ensure the pointer is valid even after the record loop
it.key = strdup(record.key.c_str()); it.key = strdup(record.key.c_str());
it.value = strdup(record.value.c_str()); it.value = strdup(const_cast<TemplatableValue<std::string> &>(record.value).value().c_str());
txt_records.push_back(it); txt_records.push_back(it);
} }
err = mdns_service_add(nullptr, service.service_type.c_str(), service.proto.c_str(), service.port, uint16_t port = const_cast<TemplatableValue<uint16_t> &>(service.port).value();
txt_records.data(), txt_records.size()); err = mdns_service_add(nullptr, service.service_type.c_str(), service.proto.c_str(), port, txt_records.data(),
txt_records.size());
// free records // free records
for (const auto &it : txt_records) { for (const auto &it : txt_records) {

View File

@ -29,9 +29,11 @@ void MDNSComponent::setup() {
while (*service_type == '_') { while (*service_type == '_') {
service_type++; service_type++;
} }
MDNS.addService(service_type, proto, service.port); uint16_t port = const_cast<TemplatableValue<uint16_t> &>(service.port).value();
MDNS.addService(service_type, proto, port);
for (const auto &record : service.txt_records) { 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<TemplatableValue<std::string> &>(record.value).value().c_str());
} }
} }
} }

View File

@ -29,9 +29,11 @@ void MDNSComponent::setup() {
while (*service_type == '_') { while (*service_type == '_') {
service_type++; service_type++;
} }
MDNS.addService(service_type, proto, service.port); uint16_t port_ = const_cast<TemplatableValue<uint16_t> &>(service.port).value();
MDNS.addService(service_type, proto, port_);
for (const auto &record : service.txt_records) { 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<TemplatableValue<std::string> &>(record.value).value().c_str());
} }
} }
} }

View File

@ -29,9 +29,11 @@ void MDNSComponent::setup() {
while (*service_type == '_') { while (*service_type == '_') {
service_type++; service_type++;
} }
MDNS.addService(service_type, proto, service.port); uint16_t port = const_cast<TemplatableValue<uint16_t> &>(service.port).value();
MDNS.addService(service_type, proto, port);
for (const auto &record : service.txt_records) { 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<TemplatableValue<std::string> &>(record.value).value().c_str());
} }
} }
} }

View File

@ -1,10 +1,11 @@
#pragma once #pragma once
#include <vector>
#include "esphome/core/component.h" #include "esphome/core/component.h"
#include "esphome/core/helpers.h"
#include "esphome/core/defines.h" #include "esphome/core/defines.h"
#include "esphome/core/helpers.h"
#include "esphome/core/preferences.h" #include "esphome/core/preferences.h"
#include <utility>
#include <vector>
namespace esphome { namespace esphome {
@ -27,7 +28,7 @@ template<typename T, typename... X> class TemplatableValue {
TemplatableValue() : type_(NONE) {} TemplatableValue() : type_(NONE) {}
template<typename F, enable_if_t<!is_invocable<F, X...>::value, int> = 0> template<typename F, enable_if_t<!is_invocable<F, X...>::value, int> = 0>
TemplatableValue(F value) : type_(VALUE), value_(value) {} TemplatableValue(F value) : type_(VALUE), value_(std::move(value)) {}
template<typename F, enable_if_t<is_invocable<F, X...>::value, int> = 0> template<typename F, enable_if_t<is_invocable<F, X...>::value, int> = 0>
TemplatableValue(F f) : type_(LAMBDA), f_(f) {} TemplatableValue(F f) : type_(LAMBDA), f_(f) {}

View File

@ -4,3 +4,10 @@ wifi:
mdns: mdns:
disabled: false disabled: false
services:
- service: _test_service
protocol: _tcp
port: 8888
txt:
static_string: Anything
templated_string: !lambda return "Something else";