ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
mdns_component.h
Go to the documentation of this file.
1#pragma once
3#ifdef USE_MDNS
4#include <string>
9// On ESP8266 and RP2040 the scheduler-backed MDNS.update() polling window is armed by
10// IP state listener events on whichever network interface is configured.
11#if (defined(USE_ESP8266) || defined(USE_RP2)) && \
12 ((defined(USE_WIFI) && defined(USE_WIFI_IP_STATE_LISTENERS)) || \
13 (defined(USE_ETHERNET) && defined(USE_ETHERNET_IP_STATE_LISTENERS)))
15#define USE_MDNS_EVENT_DRIVEN_POLLING
16#if defined(USE_WIFI) && defined(USE_WIFI_IP_STATE_LISTENERS)
18#define USE_MDNS_WIFI_LISTENER
19#endif
20#if defined(USE_ETHERNET) && defined(USE_ETHERNET_IP_STATE_LISTENERS)
22#define USE_MDNS_ETHERNET_LISTENER
23#endif
24#endif
25
26// Device info TXT records (version, mac, config_hash) are published on the _esphomelib service
27// when the native API is enabled, otherwise on the _http service (web_server's or the fallback one).
28// When neither applies (only prometheus, sendspin or user-defined services are configured), no
29// device info records are published and the buffers below are not needed.
30#if defined(USE_API) || defined(USE_WEBSERVER) || \
31 (!defined(USE_PROMETHEUS) && !defined(USE_SENDSPIN) && !defined(USE_MDNS_EXTRA_SERVICES))
32#define USE_MDNS_DEVICE_INFO_TXT
33#endif
34
35// USE_MDNS_DYNAMIC_NETWORK_TXT (wifi + ethernet + api): the _esphomelib "network" TXT value follows the
36// connected interface. With USE_MDNS_ACTIVE_INTERFACE_LISTENER (ESP32) the network component reports
37// default route changes; otherwise the value is checked every NETWORK_TXT_CHECK_INTERVAL_MS.
38#ifdef USE_MDNS_ACTIVE_INTERFACE_LISTENER
40#endif
41
42namespace esphome::mdns {
43
44// Helper struct that identifies strings that may be stored in flash storage (similar to LogString)
45struct MDNSString;
46
47// Macro to cast string literals to MDNSString* (works on all platforms)
48#define MDNS_STR(name) (reinterpret_cast<const esphome::mdns::MDNSString *>(name))
49
50#define MDNS_STR_ARG(s) (reinterpret_cast<ESPHOME_PGM_P>(s))
51
52// Service count is calculated at compile time by Python codegen
53// MDNS_SERVICE_COUNT will always be defined
54
56 const MDNSString *key;
57 const MDNSString *value;
58};
59
61 // service name _including_ underscore character prefix
62 // as defined in RFC6763 Section 7
63 const MDNSString *service_type;
64 // second label indicating protocol _including_ underscore character prefix
65 // as defined in RFC6763 Section 7, like "_tcp" or "_udp"
66 const MDNSString *proto;
69#ifdef USE_MDNS_SUPPORTS_ENABLE_DISABLE
70 bool enabled{true};
71#endif
72};
73
74class MDNSComponent final : public Component
75#ifdef USE_MDNS_WIFI_LISTENER
76 ,
78#endif
79#ifdef USE_MDNS_ETHERNET_LISTENER
80 ,
82#endif
83#ifdef USE_MDNS_ACTIVE_INTERFACE_LISTENER
84 ,
86#endif
87{
88 public:
89 void setup() override;
90 void dump_config() override;
91
93 static constexpr size_t CONFIG_HASH_STR_SIZE = format_hex_size(sizeof(uint32_t));
94
95#ifdef USE_MDNS_EVENT_DRIVEN_POLLING
96 // LEAmDNS has meaningful work only during the probe+announce phase (3×250ms probes +
97 // 8×1000ms announces, ~9s). Afterwards every internal timer is resetToNeverExpires()
98 // and update() becomes pure overhead. We arm a bounded polling window from IP state
99 // listener events so update() runs only during that phase.
100 static constexpr uint32_t MDNS_UPDATE_INTERVAL_MS = 50;
101 // Must exceed LEAmDNS's longest restart-to-announce-complete path:
102 // MDNS_PROBE_DELAY (250ms) × MDNS_PROBE_COUNT (3) = 750ms probing
103 // + MDNS_ANNOUNCE_DELAY (1000ms) × MDNS_ANNOUNCE_COUNT (8) = 8000ms announcing
104 // + rand() % MDNS_PROBE_DELAY jitter on first probe (0–250ms)
105 // + debounced schedule_function() hop when statusChangeCB fires on ESP8266
106 // ≈ 9s nominal. 15s gives ~6s margin to absorb main-loop blocking (long
107 // component setup, WiFi scan, flash writes) that could stretch the deadlines
108 // between our polls. If LEAmDNS ever extends its phase (upstream library
109 // update) this constant needs to grow. Constants defined in LEAmDNS_Priv.h
110 // (ESP8266 core 3.1.2 / arduino-pico 5.5.1).
111 static constexpr uint32_t MDNS_POLL_WINDOW_MS = 15000;
112 static constexpr uint32_t MDNS_POLL_ID = 0;
113 static constexpr uint32_t MDNS_POLL_STOP_ID = 1;
114#endif
115 float get_setup_priority() const override { return setup_priority::AFTER_CONNECTION; }
116
117#ifdef USE_MDNS_EXTRA_SERVICES
118 void add_extra_service(MDNSService service) { this->services_.emplace_next() = std::move(service); }
119#endif
120
121#ifdef USE_MDNS_STORE_SERVICES
123#endif
124
125#ifdef USE_MDNS_SUPPORTS_ENABLE_DISABLE
126#ifndef USE_MDNS_STORE_SERVICES
127#error "USE_MDNS_SUPPORTS_ENABLE_DISABLE requires USE_MDNS_STORE_SERVICES"
128#endif
129#ifdef USE_OPENTHREAD_SRP
130#error "USE_MDNS_SUPPORTS_ENABLE_DISABLE is not supported with the OpenThread SRP client"
131#endif
135 bool set_service_enabled(const char *service_type, const char *proto, bool enabled);
136#endif
137
138 void on_shutdown() override;
139
140#ifdef USE_MDNS_DYNAMIC_TXT
142 const char *add_dynamic_txt_value(const std::string &value) {
143 this->dynamic_txt_values_.push_back(value);
144 return this->dynamic_txt_values_[this->dynamic_txt_values_.size() - 1].c_str();
145 }
146#endif
147
148#ifdef USE_MDNS_ACTIVE_INTERFACE_LISTENER
149 void on_active_interface(network::NetworkInterface interface) override;
150#endif
151
152#ifdef USE_MDNS_EVENT_DRIVEN_POLLING
153 void on_ip_state(const network::IPAddresses &ips, const network::IPAddress &dns1,
154 const network::IPAddress &dns2) override;
155#endif
156
157 protected:
158#ifdef USE_MDNS_EVENT_DRIVEN_POLLING
162#endif
165
166 void setup_buffers_and_register_(PlatformRegisterFn platform_register);
167
168#ifdef USE_MDNS_DYNAMIC_NETWORK_TXT
171 const char *connected_network_() const;
173 void update_network_txt_(const char *network);
175 bool publish_network_txt_(const char *network);
177 const char *network_txt_{nullptr};
178#ifdef USE_MDNS_STORE_SERVICES
181#endif
182#endif
183
184#ifdef USE_MDNS_DYNAMIC_TXT
189#endif
190
191#if defined(USE_MDNS_DEVICE_INFO_TXT) && defined(USE_MDNS_STORE_SERVICES)
193 char mac_address_[MAC_ADDRESS_BUFFER_SIZE];
196#endif
197#ifdef USE_MDNS_STORE_SERVICES
199#endif
200#if defined(USE_RP2) && defined(USE_MDNS_EVENT_DRIVEN_POLLING)
201 // RP2040 defers MDNS.begin() until the first IP-up event; this tracks that.
202 bool initialized_{false};
203#endif
204 void compile_records_(StaticVector<MDNSService, MDNS_SERVICE_COUNT> &services, const char *mac_address_buf,
205 const char *config_hash_buf);
206};
207
208} // namespace esphome::mdns
209#endif
Fixed-capacity vector - sized once through init() or try_init(); push_back never reallocates This avo...
Definition helpers.h:624
Minimal static vector - saves memory by avoiding std::vector overhead.
Definition helpers.h:286
size_t size() const
Definition helpers.h:355
void push_back(const T &value)
Definition helpers.h:325
Function-pointer-only templatable storage (4 bytes on 32-bit).
Definition automation.h:20
Listener interface for Ethernet IP state changes.
const char * connected_network_() const
The first connected interface in network: priority order ("ethernet" or "wifi"), else nullptr.
const char * network_txt_
Advertised value; nullptr until the _esphomelib service is registered, and after a failed publish.
StaticVector< std::string, MDNS_DYNAMIC_TXT_COUNT > dynamic_txt_values_
Storage for runtime-generated TXT values from user lambdas Pre-sized at compile time via MDNS_DYNAMIC...
static constexpr uint32_t MDNS_POLL_STOP_ID
void on_active_interface(network::NetworkInterface interface) override
void start_polling_window_()
Arm a fresh MDNS_POLL_WINDOW_MS polling window.
float get_setup_priority() const override
void on_ip_state(const network::IPAddresses &ips, const network::IPAddress &dns1, const network::IPAddress &dns2) override
const char * add_dynamic_txt_value(const std::string &value)
Add a dynamic TXT value and return pointer to it for use in MDNSTXTRecord.
char config_hash_str_[CONFIG_HASH_STR_SIZE]
Fixed buffer for config hash hex string (only needed when services are stored)
static constexpr size_t CONFIG_HASH_STR_SIZE
Size of buffer required for config hash hex string (8 hex chars + null terminator)
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 compile_records_(StaticVector< MDNSService, MDNS_SERVICE_COUNT > &services, const char *mac_address_buf, const char *config_hash_buf)
static constexpr uint32_t MDNS_POLL_WINDOW_MS
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.
char mac_address_[MAC_ADDRESS_BUFFER_SIZE]
Fixed buffer for MAC address (only needed when services are stored)
void(*)(MDNSComponent *, StaticVector< MDNSService, MDNS_SERVICE_COUNT > &) PlatformRegisterFn
Helper to set up services and MAC buffers, then call platform-specific registration.
void add_extra_service(MDNSService service)
static constexpr uint32_t MDNS_POLL_ID
MDNSTXTRecord * network_record_
The "network" record in services_, kept in step with network_txt_.
static constexpr uint32_t MDNS_UPDATE_INTERVAL_MS
static constexpr uint32_t NETWORK_TXT_CHECK_INTERVAL_MS
const StaticVector< MDNSService, MDNS_SERVICE_COUNT > & get_services() const
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_
Notified from the main loop when the interface holding the default route changes.
Listener interface for WiFi IP state changes.
std::array< IPAddress, 5 > IPAddresses
Definition ip_address.h:369
NetworkInterface
The interface holding the default route.
constexpr float AFTER_CONNECTION
For components that should be initialized after a data connection (API/MQTT) is connected.
Definition component.h:57
constexpr size_t format_hex_size(size_t byte_count)
Calculate buffer size needed for format_hex_to: "XXXXXXXX...\0" = bytes * 2 + 1.
Definition helpers.h:1583
static void uint32_t
FixedVector< MDNSTXTRecord > txt_records
const MDNSString * proto
TemplatableFn< uint16_t > port
const MDNSString * service_type