ESPHome 2026.5.1
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_RP2040)) && \
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
25namespace esphome::mdns {
26
27// Helper struct that identifies strings that may be stored in flash storage (similar to LogString)
28struct MDNSString;
29
30// Macro to cast string literals to MDNSString* (works on all platforms)
31#define MDNS_STR(name) (reinterpret_cast<const esphome::mdns::MDNSString *>(name))
32
33#ifdef USE_ESP8266
34#include <pgmspace.h>
35#define MDNS_STR_ARG(s) ((PGM_P) (s))
36#else
37#define MDNS_STR_ARG(s) (reinterpret_cast<const char *>(s))
38#endif
39
40// Service count is calculated at compile time by Python codegen
41// MDNS_SERVICE_COUNT will always be defined
42
44 const MDNSString *key;
45 const MDNSString *value;
46};
47
49 // service name _including_ underscore character prefix
50 // as defined in RFC6763 Section 7
51 const MDNSString *service_type;
52 // second label indicating protocol _including_ underscore character prefix
53 // as defined in RFC6763 Section 7, like "_tcp" or "_udp"
54 const MDNSString *proto;
57};
58
59class MDNSComponent final : public Component
60#ifdef USE_MDNS_WIFI_LISTENER
61 ,
63#endif
64#ifdef USE_MDNS_ETHERNET_LISTENER
65 ,
67#endif
68{
69 public:
70 void setup() override;
71 void dump_config() override;
72
74 static constexpr size_t CONFIG_HASH_STR_SIZE = format_hex_size(sizeof(uint32_t));
75
76#ifdef USE_MDNS_EVENT_DRIVEN_POLLING
77 // LEAmDNS has meaningful work only during the probe+announce phase (3×250ms probes +
78 // 8×1000ms announces, ~9s). Afterwards every internal timer is resetToNeverExpires()
79 // and update() becomes pure overhead. We arm a bounded polling window from IP state
80 // listener events so update() runs only during that phase.
81 static constexpr uint32_t MDNS_UPDATE_INTERVAL_MS = 50;
82 // Must exceed LEAmDNS's longest restart-to-announce-complete path:
83 // MDNS_PROBE_DELAY (250ms) × MDNS_PROBE_COUNT (3) = 750ms probing
84 // + MDNS_ANNOUNCE_DELAY (1000ms) × MDNS_ANNOUNCE_COUNT (8) = 8000ms announcing
85 // + rand() % MDNS_PROBE_DELAY jitter on first probe (0–250ms)
86 // + debounced schedule_function() hop when statusChangeCB fires on ESP8266
87 // ≈ 9s nominal. 15s gives ~6s margin to absorb main-loop blocking (long
88 // component setup, WiFi scan, flash writes) that could stretch the deadlines
89 // between our polls. If LEAmDNS ever extends its phase (upstream library
90 // update) this constant needs to grow. Constants defined in LEAmDNS_Priv.h
91 // (ESP8266 core 3.1.2 / arduino-pico 5.5.1).
92 static constexpr uint32_t MDNS_POLL_WINDOW_MS = 15000;
93 static constexpr uint32_t MDNS_POLL_ID = 0;
94 static constexpr uint32_t MDNS_POLL_STOP_ID = 1;
95#endif
96 float get_setup_priority() const override { return setup_priority::AFTER_CONNECTION; }
97
98#ifdef USE_MDNS_EXTRA_SERVICES
99 void add_extra_service(MDNSService service) { this->services_.emplace_next() = std::move(service); }
100#endif
101
102#ifdef USE_MDNS_STORE_SERVICES
104#endif
105
106 void on_shutdown() override;
107
108#ifdef USE_MDNS_DYNAMIC_TXT
110 const char *add_dynamic_txt_value(const std::string &value) {
111 this->dynamic_txt_values_.push_back(value);
112 return this->dynamic_txt_values_[this->dynamic_txt_values_.size() - 1].c_str();
113 }
114#endif
115
116#ifdef USE_MDNS_EVENT_DRIVEN_POLLING
117 void on_ip_state(const network::IPAddresses &ips, const network::IPAddress &dns1,
118 const network::IPAddress &dns2) override;
119#endif
120
121 protected:
122#ifdef USE_MDNS_EVENT_DRIVEN_POLLING
126#endif
129
130 void setup_buffers_and_register_(PlatformRegisterFn platform_register);
131
132#ifdef USE_MDNS_DYNAMIC_TXT
137#endif
138
139#if defined(USE_API) && defined(USE_MDNS_STORE_SERVICES)
141 char mac_address_[MAC_ADDRESS_BUFFER_SIZE];
144#endif
145#ifdef USE_MDNS_STORE_SERVICES
147#endif
148#if defined(USE_RP2040) && defined(USE_MDNS_EVENT_DRIVEN_POLLING)
149 // RP2040 defers MDNS.begin() until the first IP-up event; this tracks that.
150 bool initialized_{false};
151#endif
152 void compile_records_(StaticVector<MDNSService, MDNS_SERVICE_COUNT> &services, char *mac_address_buf,
153 char *config_hash_buf);
154};
155
156} // namespace esphome::mdns
157#endif
Fixed-capacity vector - allocates once at runtime, never reallocates This avoids std::vector template...
Definition helpers.h:529
Minimal static vector - saves memory by avoiding std::vector overhead.
Definition helpers.h:217
size_t size() const
Definition helpers.h:277
void push_back(const T &value)
Definition helpers.h:250
Function-pointer-only templatable storage (4 bytes on 32-bit).
Definition automation.h:40
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)
static constexpr uint32_t MDNS_POLL_WINDOW_MS
void setup_buffers_and_register_(PlatformRegisterFn platform_register)
void compile_records_(StaticVector< MDNSService, MDNS_SERVICE_COUNT > &services, char *mac_address_buf, char *config_hash_buf)
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:187
constexpr float AFTER_CONNECTION
For components that should be initialized after a data connection (API/MQTT) is connected.
Definition component.h:55
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:1360
static void uint32_t
FixedVector< MDNSTXTRecord > txt_records
const MDNSString * proto
TemplatableFn< uint16_t > port
const MDNSString * service_type