[mdns] Fix RP2040 mDNS not restarting after WiFi reconnect (#14737)

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
J. Nick Koston
2026-03-12 15:12:22 -10:00
committed by GitHub
parent 59c1368440
commit a744261934
5 changed files with 30 additions and 31 deletions
+4
View File
@@ -129,6 +129,10 @@ class MDNSComponent final : public Component {
#endif
#ifdef USE_MDNS_STORE_SERVICES
StaticVector<MDNSService, MDNS_SERVICE_COUNT> services_{};
#endif
#ifdef USE_RP2040
bool was_connected_{false};
bool initialized_{false};
#endif
void compile_records_(StaticVector<MDNSService, MDNS_SERVICE_COUNT> &services, char *mac_address_buf);
};
+26 -6
View File
@@ -36,12 +36,32 @@ static void register_rp2040(MDNSComponent *, StaticVector<MDNSService, MDNS_SERV
}
void MDNSComponent::setup() {
this->setup_buffers_and_register_(register_rp2040);
// Schedule MDNS.update() via set_interval() instead of overriding loop().
// This removes the component from the per-iteration loop list entirely,
// eliminating virtual dispatch overhead on every main loop cycle.
// See MDNS_UPDATE_INTERVAL_MS comment in mdns_component.h for safety analysis.
this->set_interval(MDNS_UPDATE_INTERVAL_MS, []() { MDNS.update(); });
// RP2040's LEAmDNS library registers a LwipIntf::stateUpCB() callback to restart
// mDNS when the network interface reconnects. However, stateUpCB() is stubbed out
// in arduino-pico's LwipIntfCB.cpp because the original ESP8266 implementation used
// schedule_function() which doesn't exist in arduino-pico, and the callback can't
// safely run directly since netif status callbacks fire from IRQ context
// (PICO_CYW43_ARCH_THREADSAFE_BACKGROUND) while _restart() allocates UDP sockets.
//
// Workaround: defer MDNS.begin() and service registration until the network is
// connected (has an IP), then call notifyAPChange() on subsequent reconnects to
// restart mDNS probing and announcing — all from main loop context so it's
// thread-safe.
this->set_interval(MDNS_UPDATE_INTERVAL_MS, [this]() {
bool connected = network::is_connected();
if (connected && !this->was_connected_) {
if (!this->initialized_) {
this->setup_buffers_and_register_(register_rp2040);
this->initialized_ = true;
} else {
MDNS.notifyAPChange();
}
}
this->was_connected_ = connected;
if (this->initialized_) {
MDNS.update();
}
});
}
void MDNSComponent::on_shutdown() {
-7
View File
@@ -563,13 +563,6 @@ async def to_code(config):
cg.add_library("ESP8266WiFi", None)
elif CORE.is_rp2040:
cg.add_library("WiFi", None)
# RP2040's mDNS library (LEAmDNS) relies on LwipIntf::stateUpCB() to restart
# mDNS when the network interface reconnects. However, this callback is disabled
# in the arduino-pico framework. As a workaround, we block component setup until
# WiFi is connected via can_proceed(), ensuring mDNS.begin() is called with an
# active connection. This define enables the loop priority sorting infrastructure
# used during the setup blocking phase.
cg.add_define("USE_LOOP_PRIORITY")
if CORE.is_esp32:
if config[CONF_ENABLE_BTM] or config[CONF_ENABLE_RRM]:
@@ -2109,20 +2109,6 @@ void WiFiComponent::retry_connect() {
}
}
#ifdef USE_RP2040
// RP2040's mDNS library (LEAmDNS) relies on LwipIntf::stateUpCB() to restart
// mDNS when the network interface reconnects. However, this callback is disabled
// in the arduino-pico framework. As a workaround, we block component setup until
// WiFi is connected, ensuring mDNS.begin() is called with an active connection.
bool WiFiComponent::can_proceed() {
if (!this->has_sta() || this->state_ == WIFI_COMPONENT_STATE_DISABLED || this->ap_setup_) {
return true;
}
return this->is_connected_();
}
#endif
void WiFiComponent::set_reboot_timeout(uint32_t reboot_timeout) { this->reboot_timeout_ = reboot_timeout; }
bool WiFiComponent::is_connected_() const {
return this->state_ == WIFI_COMPONENT_STATE_STA_CONNECTED &&
-4
View File
@@ -437,10 +437,6 @@ class WiFiComponent : public Component {
void retry_connect();
#ifdef USE_RP2040
bool can_proceed() override;
#endif
void set_reboot_timeout(uint32_t reboot_timeout);
bool is_connected() const { return this->connected_; }