ESPHome 2026.2.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
9namespace esphome::mdns {
10
11// Helper struct that identifies strings that may be stored in flash storage (similar to LogString)
12struct MDNSString;
13
14// Macro to cast string literals to MDNSString* (works on all platforms)
15#define MDNS_STR(name) (reinterpret_cast<const esphome::mdns::MDNSString *>(name))
16
17#ifdef USE_ESP8266
18#include <pgmspace.h>
19#define MDNS_STR_ARG(s) ((PGM_P) (s))
20#else
21#define MDNS_STR_ARG(s) (reinterpret_cast<const char *>(s))
22#endif
23
24// Service count is calculated at compile time by Python codegen
25// MDNS_SERVICE_COUNT will always be defined
26
28 const MDNSString *key;
29 const MDNSString *value;
30};
31
33 // service name _including_ underscore character prefix
34 // as defined in RFC6763 Section 7
35 const MDNSString *service_type;
36 // second label indicating protocol _including_ underscore character prefix
37 // as defined in RFC6763 Section 7, like "_tcp" or "_udp"
38 const MDNSString *proto;
41};
42
43class MDNSComponent : public Component {
44 public:
45 void setup() override;
46 void dump_config() override;
47
48 // Polling interval for MDNS.update() on platforms that require it (ESP8266, RP2040).
49 //
50 // On these platforms, MDNS.update() calls _process(true) which only manages timer-driven
51 // state machines (probe/announce timeouts and service query cache TTLs). Incoming mDNS
52 // packets are handled independently via the lwIP onRx UDP callback and are NOT affected
53 // by how often update() is called.
54 //
55 // The shortest internal timer is the 250ms probe interval (RFC 6762 Section 8.1).
56 // Announcement intervals are 1000ms and cache TTL checks are on the order of seconds
57 // to minutes. A 50ms polling interval provides sufficient resolution for all timers
58 // while completely removing mDNS from the per-iteration loop list.
59 //
60 // In steady state (after the ~8 second boot probe/announce phase completes), update()
61 // checks timers that are set to never expire, making every call pure overhead.
62 //
63 // Tasmota uses a 50ms main loop cycle with mDNS working correctly, confirming this
64 // interval is safe in production.
65 //
66 // By using set_interval() instead of overriding loop(), the component is excluded from
67 // the main loop list via has_overridden_loop(), eliminating all per-iteration overhead
68 // including virtual dispatch.
69 static constexpr uint32_t MDNS_UPDATE_INTERVAL_MS = 50;
70 float get_setup_priority() const override { return setup_priority::AFTER_CONNECTION; }
71
72#ifdef USE_MDNS_EXTRA_SERVICES
73 void add_extra_service(MDNSService service) { this->services_.emplace_next() = std::move(service); }
74#endif
75
76#ifdef USE_MDNS_STORE_SERVICES
78#endif
79
80 void on_shutdown() override;
81
82#ifdef USE_MDNS_DYNAMIC_TXT
84 const char *add_dynamic_txt_value(const std::string &value) {
85 this->dynamic_txt_values_.push_back(value);
86 return this->dynamic_txt_values_[this->dynamic_txt_values_.size() - 1].c_str();
87 }
88#endif
89
90 protected:
93
95#ifdef USE_MDNS_STORE_SERVICES
96 auto &services = this->services_;
97#else
99 auto &services = services_storage;
100#endif
101
102#ifdef USE_API
103#ifdef USE_MDNS_STORE_SERVICES
105 char *mac_ptr = this->mac_address_;
106#else
107 char mac_address[MAC_ADDRESS_BUFFER_SIZE];
108 get_mac_address_into_buffer(mac_address);
109 char *mac_ptr = mac_address;
110#endif
111#else
112 char *mac_ptr = nullptr;
113#endif
114
115 this->compile_records_(services, mac_ptr);
116 platform_register(this, services);
117 }
118
119#ifdef USE_MDNS_DYNAMIC_TXT
124#endif
125
126#if defined(USE_API) && defined(USE_MDNS_STORE_SERVICES)
128 char mac_address_[MAC_ADDRESS_BUFFER_SIZE];
129#endif
130#ifdef USE_MDNS_STORE_SERVICES
132#endif
133 void compile_records_(StaticVector<MDNSService, MDNS_SERVICE_COUNT> &services, char *mac_address_buf);
134};
135
136} // namespace esphome::mdns
137#endif
Fixed-capacity vector - allocates once at runtime, never reallocates This avoids std::vector template...
Definition helpers.h:227
Minimal static vector - saves memory by avoiding std::vector overhead.
Definition helpers.h:137
size_t size() const
Definition helpers.h:197
void push_back(const T &value)
Definition helpers.h:170
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...
float get_setup_priority() const 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.
void compile_records_(StaticVector< MDNSService, MDNS_SERVICE_COUNT > &services, char *mac_address_buf)
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_UPDATE_INTERVAL_MS
const StaticVector< MDNSService, MDNS_SERVICE_COUNT > & get_services() const
StaticVector< MDNSService, MDNS_SERVICE_COUNT > services_
const float AFTER_CONNECTION
For components that should be initialized after a data connection (API/MQTT) is connected.
Definition component.cpp:92
void get_mac_address_into_buffer(std::span< char, MAC_ADDRESS_BUFFER_SIZE > buf)
Get the device MAC address into the given buffer, in lowercase hex notation.
Definition helpers.cpp:813
TemplatableValue< uint16_t > port
FixedVector< MDNSTXTRecord > txt_records
const MDNSString * proto
const MDNSString * service_type