ESPHome 2026.8.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>
8// On ESP8266 and RP2040 the scheduler-backed MDNS.update() polling window is armed by
9// IP state listener events on whichever network interface is configured.
10#if (defined(USE_ESP8266) || defined(USE_RP2)) && \
11 ((defined(USE_WIFI) && defined(USE_WIFI_IP_STATE_LISTENERS)) || \
12 (defined(USE_ETHERNET) && defined(USE_ETHERNET_IP_STATE_LISTENERS)))
14#define USE_MDNS_EVENT_DRIVEN_POLLING
15#if defined(USE_WIFI) && defined(USE_WIFI_IP_STATE_LISTENERS)
17#define USE_MDNS_WIFI_LISTENER
18#endif
19#if defined(USE_ETHERNET) && defined(USE_ETHERNET_IP_STATE_LISTENERS)
21#define USE_MDNS_ETHERNET_LISTENER
22#endif
23#endif
24
25// Device info TXT records (version, mac, config_hash) are published on the _esphomelib service
26// when the native API is enabled, otherwise on the _http service (web_server's or the fallback one).
27// When neither applies (only prometheus, sendspin or user-defined services are configured), no
28// device info records are published and the buffers below are not needed.
29#if defined(USE_API) || defined(USE_WEBSERVER) || \
30 (!defined(USE_PROMETHEUS) && !defined(USE_SENDSPIN) && !defined(USE_MDNS_EXTRA_SERVICES))
31#define USE_MDNS_DEVICE_INFO_TXT
32#endif
33
34namespace esphome::mdns {
35
36// Helper struct that identifies strings that may be stored in flash storage (similar to LogString)
37struct MDNSString;
38
39// Macro to cast string literals to MDNSString* (works on all platforms)
40#define MDNS_STR(name) (reinterpret_cast<const esphome::mdns::MDNSString *>(name))
41
42#ifdef USE_ESP8266
43#include <pgmspace.h>
44#define MDNS_STR_ARG(s) ((PGM_P) (s))
45#else
46#define MDNS_STR_ARG(s) (reinterpret_cast<const char *>(s))
47#endif
48
49// Service count is calculated at compile time by Python codegen
50// MDNS_SERVICE_COUNT will always be defined
51
53 const MDNSString *key;
54 const MDNSString *value;
55};
56
58 // service name _including_ underscore character prefix
59 // as defined in RFC6763 Section 7
60 const MDNSString *service_type;
61 // second label indicating protocol _including_ underscore character prefix
62 // as defined in RFC6763 Section 7, like "_tcp" or "_udp"
63 const MDNSString *proto;
66};
67
68class MDNSComponent final : public Component
69#ifdef USE_MDNS_WIFI_LISTENER
70 ,
72#endif
73#ifdef USE_MDNS_ETHERNET_LISTENER
74 ,
76#endif
77{
78 public:
79 void setup() override;
80 void dump_config() override;
81
83 static constexpr size_t CONFIG_HASH_STR_SIZE = format_hex_size(sizeof(uint32_t));
84
85#ifdef USE_MDNS_EVENT_DRIVEN_POLLING
86 // LEAmDNS has meaningful work only during the probe+announce phase (3×250ms probes +
87 // 8×1000ms announces, ~9s). Afterwards every internal timer is resetToNeverExpires()
88 // and update() becomes pure overhead. We arm a bounded polling window from IP state
89 // listener events so update() runs only during that phase.
90 static constexpr uint32_t MDNS_UPDATE_INTERVAL_MS = 50;
91 // Must exceed LEAmDNS's longest restart-to-announce-complete path:
92 // MDNS_PROBE_DELAY (250ms) × MDNS_PROBE_COUNT (3) = 750ms probing
93 // + MDNS_ANNOUNCE_DELAY (1000ms) × MDNS_ANNOUNCE_COUNT (8) = 8000ms announcing
94 // + rand() % MDNS_PROBE_DELAY jitter on first probe (0–250ms)
95 // + debounced schedule_function() hop when statusChangeCB fires on ESP8266
96 // ≈ 9s nominal. 15s gives ~6s margin to absorb main-loop blocking (long
97 // component setup, WiFi scan, flash writes) that could stretch the deadlines
98 // between our polls. If LEAmDNS ever extends its phase (upstream library
99 // update) this constant needs to grow. Constants defined in LEAmDNS_Priv.h
100 // (ESP8266 core 3.1.2 / arduino-pico 5.5.1).
101 static constexpr uint32_t MDNS_POLL_WINDOW_MS = 15000;
102 static constexpr uint32_t MDNS_POLL_ID = 0;
103 static constexpr uint32_t MDNS_POLL_STOP_ID = 1;
104#endif
105 float get_setup_priority() const override { return setup_priority::AFTER_CONNECTION; }
106
107#ifdef USE_MDNS_EXTRA_SERVICES
108 void add_extra_service(MDNSService service) { this->services_.emplace_next() = std::move(service); }
109#endif
110
111#ifdef USE_MDNS_STORE_SERVICES
113#endif
114
115 void on_shutdown() override;
116
117#ifdef USE_MDNS_DYNAMIC_TXT
119 const char *add_dynamic_txt_value(const std::string &value) {
120 this->dynamic_txt_values_.push_back(value);
121 return this->dynamic_txt_values_[this->dynamic_txt_values_.size() - 1].c_str();
122 }
123#endif
124
125#ifdef USE_MDNS_EVENT_DRIVEN_POLLING
126 void on_ip_state(const network::IPAddresses &ips, const network::IPAddress &dns1,
127 const network::IPAddress &dns2) override;
128#endif
129
130 protected:
131#ifdef USE_MDNS_EVENT_DRIVEN_POLLING
135#endif
138
139 void setup_buffers_and_register_(PlatformRegisterFn platform_register);
140
141#ifdef USE_MDNS_DYNAMIC_TXT
146#endif
147
148#if defined(USE_MDNS_DEVICE_INFO_TXT) && defined(USE_MDNS_STORE_SERVICES)
150 char mac_address_[MAC_ADDRESS_BUFFER_SIZE];
153#endif
154#ifdef USE_MDNS_STORE_SERVICES
156#endif
157#if defined(USE_RP2) && defined(USE_MDNS_EVENT_DRIVEN_POLLING)
158 // RP2040 defers MDNS.begin() until the first IP-up event; this tracks that.
159 bool initialized_{false};
160#endif
161 void compile_records_(StaticVector<MDNSService, MDNS_SERVICE_COUNT> &services, const char *mac_address_buf,
162 const char *config_hash_buf);
163};
164
165} // namespace esphome::mdns
166#endif
Fixed-capacity vector - allocates once at runtime, never reallocates This avoids std::vector template...
Definition helpers.h:534
Minimal static vector - saves memory by avoiding std::vector overhead.
Definition helpers.h:222
size_t size() const
Definition helpers.h:282
void push_back(const T &value)
Definition helpers.h:255
Function-pointer-only templatable storage (4 bytes on 32-bit).
Definition automation.h:19
Listener interface for Ethernet IP state changes.
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 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)
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)
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
static constexpr uint32_t MDNS_UPDATE_INTERVAL_MS
const StaticVector< MDNSService, MDNS_SERVICE_COUNT > & get_services() const
StaticVector< MDNSService, MDNS_SERVICE_COUNT > services_
Listener interface for WiFi IP state changes.
std::array< IPAddress, 5 > IPAddresses
Definition ip_address.h:299
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:1374
static void uint32_t
FixedVector< MDNSTXTRecord > txt_records
const MDNSString * proto
TemplatableFn< uint16_t > port
const MDNSString * service_type