mirror of
https://github.com/esphome/esphome.git
synced 2026-09-19 11:08:38 +00:00
[mdns] Simplify listener logic: always re-arm on IP notify, drop transition tracking
ESPHome's WiFiIPStateListener only notifies on IP acquisition (GOT_IP events), not on IP loss — on disconnect, only the WiFiConnectStateListener's disconnect path fires (see wifi_component_esp8266.cpp:952-962 and wifi_component_pico_w.cpp:340). The previous commit's `ip_was_up_` transition tracking was broken: after the first IP-up event, `ip_was_up_` latched to true and never reset, so subsequent disconnect+reconnect cycles would see has_ip=true && ip_was_up_=true and skip re-arming the polling window. Fix: always re-arm on any IP notification. The scheduler's set_interval/set_timeout with a uint32_t ID already performs atomic cancel-and-add for matching IDs (Scheduler::set_timer_common_ line 232-234), so start_polling_window_ is idempotent and needs no explicit cancel. Drop the ip_was_up_ field and cancel_polling_window_ helper entirely. The !has_ip branch (cancel on disconnect) was dead code: it would never fire because the listener doesn't receive disconnect events. Removing it; the polling window will naturally expire on its own (at most 12s of harmless MDNS.update() calls during a disconnect that isn't followed by reconnect within the window).
This commit is contained in:
@@ -192,16 +192,12 @@ void MDNSComponent::compile_records_(StaticVector<MDNSService, MDNS_SERVICE_COUN
|
||||
|
||||
#ifdef USE_MDNS_EVENT_DRIVEN_POLLING
|
||||
void MDNSComponent::start_polling_window_() {
|
||||
// Re-arming replaces the previous window; cancel any active schedulers first.
|
||||
this->cancel_polling_window_();
|
||||
// Re-arming replaces the previous window. The scheduler's set_interval/set_timeout
|
||||
// with a uint32_t ID already does atomic cancel-and-add for items sharing that ID
|
||||
// (see Scheduler::set_timer_common_), so no explicit cancel is needed.
|
||||
this->set_interval(MDNS_POLL_ID, MDNS_UPDATE_INTERVAL_MS, mdns_pump_update);
|
||||
this->set_timeout(MDNS_POLL_STOP_ID, MDNS_POLL_WINDOW_MS, [this]() { this->cancel_interval(MDNS_POLL_ID); });
|
||||
}
|
||||
|
||||
void MDNSComponent::cancel_polling_window_() {
|
||||
this->cancel_interval(MDNS_POLL_ID);
|
||||
this->cancel_timeout(MDNS_POLL_STOP_ID);
|
||||
}
|
||||
#endif
|
||||
|
||||
void MDNSComponent::dump_config() {
|
||||
|
||||
@@ -122,9 +122,6 @@ class MDNSComponent final : public Component
|
||||
/// Arm a bounded polling window so MDNS.update() runs at MDNS_UPDATE_INTERVAL_MS
|
||||
/// for MDNS_POLL_WINDOW_MS. A subsequent call replaces the previous window.
|
||||
void start_polling_window_();
|
||||
/// Cancel any active polling window.
|
||||
void cancel_polling_window_();
|
||||
bool ip_was_up_{false};
|
||||
#endif
|
||||
/// Helper to set up services and MAC buffers, then call platform-specific registration
|
||||
using PlatformRegisterFn = void (*)(MDNSComponent *, StaticVector<MDNSService, MDNS_SERVICE_COUNT> &);
|
||||
|
||||
@@ -51,16 +51,14 @@ void MDNSComponent::setup() {
|
||||
|
||||
void MDNSComponent::on_ip_state(const network::IPAddresses &ips, const network::IPAddress &,
|
||||
const network::IPAddress &) {
|
||||
const bool has_ip = ips[0].is_set();
|
||||
if (has_ip && !this->ip_was_up_) {
|
||||
// IP came up. LEAmDNS's internal lwIP callback will call _restart() shortly after
|
||||
// (if it hasn't already) — arm the polling window so the probe/announce phase is
|
||||
// serviced regardless of our relative timing vs the library's callback.
|
||||
// ESPHome's WiFiIPStateListener only notifies on IP acquisition (GOT_IP events on
|
||||
// ESP8266 — see wifi_component_esp8266.cpp), not on IP loss, so every notification
|
||||
// represents a fresh IP that the LEAmDNS library's lwIP callback will trigger a
|
||||
// _restart() for. Always re-arm the polling window — start_polling_window_() is
|
||||
// idempotent (scheduler does atomic cancel-and-add on matching IDs).
|
||||
if (ips[0].is_set()) {
|
||||
this->start_polling_window_();
|
||||
} else if (!has_ip && this->ip_was_up_) {
|
||||
this->cancel_polling_window_();
|
||||
}
|
||||
this->ip_was_up_ = has_ip;
|
||||
}
|
||||
|
||||
void MDNSComponent::on_shutdown() {
|
||||
|
||||
@@ -91,19 +91,21 @@ void MDNSComponent::setup() {
|
||||
#ifdef USE_MDNS_EVENT_DRIVEN_POLLING
|
||||
void MDNSComponent::on_ip_state(const network::IPAddresses &ips, const network::IPAddress &,
|
||||
const network::IPAddress &) {
|
||||
const bool has_ip = ips[0].is_set();
|
||||
if (has_ip && !this->ip_was_up_) {
|
||||
if (!this->initialized_) {
|
||||
this->setup_buffers_and_register_(register_rp2040);
|
||||
this->initialized_ = true;
|
||||
} else {
|
||||
MDNS.notifyAPChange();
|
||||
}
|
||||
this->start_polling_window_();
|
||||
} else if (!has_ip && this->ip_was_up_) {
|
||||
this->cancel_polling_window_();
|
||||
// ESPHome's WiFiIPStateListener only notifies on IP acquisition (see
|
||||
// wifi_component_pico_w.cpp), not on IP loss, so every notification represents a
|
||||
// fresh IP that needs a probe/announce cycle. The library's internal
|
||||
// LwipIntf::stateUpCB is stubbed out on arduino-pico (see setup()), so we drive
|
||||
// begin/restart ourselves from this callback.
|
||||
if (!ips[0].is_set()) {
|
||||
return;
|
||||
}
|
||||
this->ip_was_up_ = has_ip;
|
||||
if (!this->initialized_) {
|
||||
this->setup_buffers_and_register_(register_rp2040);
|
||||
this->initialized_ = true;
|
||||
} else {
|
||||
MDNS.notifyAPChange();
|
||||
}
|
||||
this->start_polling_window_();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
Reference in New Issue
Block a user