ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
mdns_esp32.cpp
Go to the documentation of this file.
2#if defined(USE_ESP32) && defined(USE_MDNS)
3
4#include <mdns.h>
5#include <cstring>
7#include "esphome/core/hal.h"
8#include "esphome/core/log.h"
9#include "mdns_component.h"
10
11namespace esphome::mdns {
12
13ESPHOME_LOG_TAG(TAG, "mdns");
14
15#ifndef USE_OPENTHREAD_SRP
16static esp_err_t add_service(const MDNSService &service) {
17 // Stack buffer for up to 16 txt records, heap fallback for more
18 SmallBufferWithHeapFallback<16, mdns_txt_item_t> txt_records(service.txt_records.size());
19 for (size_t i = 0; i < service.txt_records.size(); i++) {
20 const auto &record = service.txt_records[i];
21 // key and value are either compile-time string literals in flash or pointers to dynamic_txt_values_
22 // Both remain valid for the lifetime of this function, and ESP-IDF makes internal copies
23 txt_records.get()[i].key = MDNS_STR_ARG(record.key);
24 txt_records.get()[i].value = MDNS_STR_ARG(record.value);
25 }
26 uint16_t port = service.port.value();
27 return mdns_service_add(nullptr, MDNS_STR_ARG(service.service_type), MDNS_STR_ARG(service.proto), port,
28 txt_records.get(), service.txt_records.size());
29}
30#endif
31
32static void register_esp32(MDNSComponent *comp, StaticVector<MDNSService, MDNS_SERVICE_COUNT> &services) {
33#ifdef USE_OPENTHREAD_SRP
34 // OpenThread handles service registration via SRP client
35 // Services are compiled by MDNSComponent::compile_records_() and consumed by OpenThreadSrpComponent
36#else
37 esp_err_t err = mdns_init();
38 if (err != ESP_OK) {
39 ESP_LOGW(TAG, "Init failed: %s", esp_err_to_name(err));
40 comp->mark_failed();
41 return;
42 }
43
44 const char *hostname = App.get_name().c_str();
45 mdns_hostname_set(hostname);
46 mdns_instance_name_set(hostname);
47
48 for (auto &service : services) {
49#ifdef USE_MDNS_SUPPORTS_ENABLE_DISABLE
50 if (!service.enabled)
51 continue;
52#endif
53 err = add_service(service);
54 if (err != ESP_OK) {
55 ESP_LOGW(TAG, "Failed to register service %s: %s", MDNS_STR_ARG(service.service_type), esp_err_to_name(err));
56#ifdef USE_MDNS_SUPPORTS_ENABLE_DISABLE
57 // Let a later enable call retry
58 service.enabled = false;
59#endif
60 }
61 }
62#endif
63}
64
65#if defined(USE_MDNS_SUPPORTS_ENABLE_DISABLE) && !defined(USE_OPENTHREAD_SRP)
66bool MDNSComponent::set_service_enabled(const char *service_type, const char *proto, bool enabled) {
67 // services_ is compiled in setup()
68 if (!this->is_ready()) {
69 ESP_LOGW(TAG, "Cannot %s service %s before setup", enabled ? "enable" : "disable", service_type);
70 return false;
71 }
72 for (auto &service : this->services_) {
73 if (strcmp(MDNS_STR_ARG(service.service_type), service_type) != 0 ||
74 strcmp(MDNS_STR_ARG(service.proto), proto) != 0) {
75 continue;
76 }
77 if (service.enabled == enabled)
78 return true;
79 esp_err_t err = enabled ? add_service(service) : mdns_service_remove(service_type, proto);
80 if (err != ESP_OK) {
81 ESP_LOGW(TAG, "Failed to %s service %s: %s", enabled ? "enable" : "disable", service_type, esp_err_to_name(err));
82 return false;
83 }
84 service.enabled = enabled;
85 return true;
86 }
87 ESP_LOGW(TAG, "Service %s not found", service_type);
88 return false;
89}
90#endif // USE_MDNS_SUPPORTS_ENABLE_DISABLE && !USE_OPENTHREAD_SRP
91
92#ifdef USE_MDNS_DYNAMIC_NETWORK_TXT
93bool MDNSComponent::publish_network_txt_(const char *network) {
94 // ESP-IDF copies the value and announces the changed record
95 esp_err_t err = mdns_service_txt_item_set("_esphomelib", "_tcp", "network", network);
96 if (err != ESP_OK) {
97 ESP_LOGW(TAG, "Failed to update network TXT: %s", esp_err_to_name(err));
98 return false;
99 }
100 return true;
101}
102#endif
103
105 this->setup_buffers_and_register_(register_esp32);
106#if defined(USE_MDNS_DYNAMIC_NETWORK_TXT) && !defined(USE_MDNS_ACTIVE_INTERFACE_LISTENER)
108 [this]() { this->update_network_txt_(this->connected_network_()); });
109#endif
110}
111
113#ifndef USE_OPENTHREAD_SRP
114 mdns_free();
115 delay(40); // Allow the mdns packets announcing service removal to be sent
116#endif
117}
118
119} // namespace esphome::mdns
120
121#endif // USE_ESP32
const StringRef & get_name() const
Get the name of this Application set by pre_setup().
bool is_ready() const
void set_interval(const char *name, uint32_t interval, std::function< void()> &&f)
Set an interval function with a const char* name.
Definition component.cpp:88
constexpr const char * c_str() const
Definition string_ref.h:78
const char * connected_network_() const
The first connected interface in network: priority order ("ethernet" or "wifi"), else nullptr.
bool set_service_enabled(const char *service_type, const char *proto, bool enabled)
Enable or disable a compiled-in service, matched by type and proto (e.g.
void setup_buffers_and_register_(PlatformRegisterFn platform_register)
void update_network_txt_(const char *network)
Publish network as the "network" TXT value if it changed; nullptr keeps the current value.
static constexpr uint32_t NETWORK_TXT_CHECK_INTERVAL_MS
bool publish_network_txt_(const char *network)
Platform-specific: replace the "network" TXT value of the registered _esphomelib service.
StaticVector< MDNSService, MDNS_SERVICE_COUNT > services_
const char * esp_err_to_name(esp_err_t err)
ESPHOME_LOG_TAG(TAG, "mdns")
void HOT delay(uint32_t ms)
Definition hal.cpp:85
Application App
Global storage of Application pointer - only one Application can exist.