mirror of
https://github.com/esphome/esphome.git
synced 2026-02-18 23:45:40 -07:00
[mdns] Throttle MDNS.update() polling on ESP8266 and RP2040
On ESP8266 and RP2040, MDNS.update() is called every loop iteration (~120 Hz) but only manages timer-driven probe/announce state machines. Incoming mDNS packets are handled independently via the lwIP onRx UDP callback and are unaffected by update() frequency. The shortest internal timer is the 250ms probe interval (RFC 6762). Throttling to 50ms provides sufficient resolution while reducing CPU overhead by ~84% (from ~360ms to ~60ms per 60s measurement period).
This commit is contained in:
@@ -48,6 +48,25 @@ class MDNSComponent : public Component {
|
||||
#if (defined(USE_ESP8266) || defined(USE_RP2040)) && defined(USE_ARDUINO)
|
||||
void loop() override;
|
||||
#endif
|
||||
|
||||
// Throttle interval for MDNS.update() on platforms that require polling (ESP8266, RP2040).
|
||||
//
|
||||
// On these platforms, MDNS.update() calls _process(true) which only manages timer-driven
|
||||
// state machines (probe/announce timeouts and service query cache TTLs). Incoming mDNS
|
||||
// packets are handled independently via the lwIP onRx UDP callback and are NOT affected
|
||||
// by how often update() is called.
|
||||
//
|
||||
// The shortest internal timer is the 250ms probe interval (RFC 6762 Section 8.1).
|
||||
// Announcement intervals are 1000ms and cache TTL checks are on the order of seconds
|
||||
// to minutes. A 50ms polling interval provides sufficient resolution for all timers
|
||||
// while reducing CPU overhead by ~84% compared to calling every loop iteration.
|
||||
//
|
||||
// In steady state (after the ~8 second boot probe/announce phase completes), update()
|
||||
// checks timers that are set to never expire, making every call pure overhead.
|
||||
//
|
||||
// Tasmota uses a 50ms main loop cycle with mDNS working correctly, confirming this
|
||||
// interval is safe in production.
|
||||
static constexpr uint32_t MDNS_UPDATE_INTERVAL_MS = 50;
|
||||
float get_setup_priority() const override { return setup_priority::AFTER_CONNECTION; }
|
||||
|
||||
#ifdef USE_MDNS_EXTRA_SERVICES
|
||||
@@ -110,6 +129,9 @@ class MDNSComponent : public Component {
|
||||
#endif
|
||||
#ifdef USE_MDNS_STORE_SERVICES
|
||||
StaticVector<MDNSService, MDNS_SERVICE_COUNT> services_{};
|
||||
#endif
|
||||
#if (defined(USE_ESP8266) || defined(USE_RP2040)) && defined(USE_ARDUINO)
|
||||
uint32_t last_update_{0};
|
||||
#endif
|
||||
void compile_records_(StaticVector<MDNSService, MDNS_SERVICE_COUNT> &services, char *mac_address_buf);
|
||||
};
|
||||
|
||||
@@ -38,7 +38,17 @@ static void register_esp8266(MDNSComponent *, StaticVector<MDNSService, MDNS_SER
|
||||
|
||||
void MDNSComponent::setup() { this->setup_buffers_and_register_(register_esp8266); }
|
||||
|
||||
void MDNSComponent::loop() { MDNS.update(); }
|
||||
void MDNSComponent::loop() {
|
||||
// Throttle MDNS.update() to avoid calling it every loop iteration (~120 Hz).
|
||||
// The update() function only manages timer-driven probe/announce state machines
|
||||
// and service query cache TTLs. Incoming mDNS packets are processed independently
|
||||
// via the lwIP onRx callback and do not depend on update() frequency.
|
||||
const uint32_t now = App.get_loop_component_start_time();
|
||||
if (now - this->last_update_ < MDNS_UPDATE_INTERVAL_MS)
|
||||
return;
|
||||
this->last_update_ = now;
|
||||
MDNS.update();
|
||||
}
|
||||
|
||||
void MDNSComponent::on_shutdown() {
|
||||
MDNS.close();
|
||||
|
||||
@@ -37,7 +37,17 @@ static void register_rp2040(MDNSComponent *, StaticVector<MDNSService, MDNS_SERV
|
||||
|
||||
void MDNSComponent::setup() { this->setup_buffers_and_register_(register_rp2040); }
|
||||
|
||||
void MDNSComponent::loop() { MDNS.update(); }
|
||||
void MDNSComponent::loop() {
|
||||
// Throttle MDNS.update() to avoid calling it every loop iteration (~120 Hz).
|
||||
// The update() function only manages timer-driven probe/announce state machines
|
||||
// and service query cache TTLs. Incoming mDNS packets are processed independently
|
||||
// via the lwIP onRx callback and do not depend on update() frequency.
|
||||
const uint32_t now = App.get_loop_component_start_time();
|
||||
if (now - this->last_update_ < MDNS_UPDATE_INTERVAL_MS)
|
||||
return;
|
||||
this->last_update_ = now;
|
||||
MDNS.update();
|
||||
}
|
||||
|
||||
void MDNSComponent::on_shutdown() {
|
||||
MDNS.close();
|
||||
|
||||
Reference in New Issue
Block a user