From ae414275237ec29f6783900954ff44a430c5cf51 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 23 Apr 2026 20:11:48 -0500 Subject: [PATCH] [mdns] Enforce network-interface availability at config time on ESP8266/RP2040 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses Copilot review feedback: if someone enables mdns on ESP8266 or RP2040 without wifi (or ethernet on RP2040), the listener-based setup() is a no-op and the user sees a silent failure rather than a helpful error. FINAL_VALIDATE_SCHEMA rejects mdns on these platforms when no compatible network component is present, naming the specific options that would satisfy the requirement. The existing DEPENDENCIES = ["network"] covers most misconfigurations indirectly, but an explicit network: alone (without wifi or ethernet) slips past that check — now it fails with a clear message. --- esphome/components/mdns/__init__.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/esphome/components/mdns/__init__.py b/esphome/components/mdns/__init__.py index b15a778b59f..e7e1323f402 100644 --- a/esphome/components/mdns/__init__.py +++ b/esphome/components/mdns/__init__.py @@ -14,6 +14,7 @@ from esphome.const import ( from esphome.core import CORE, Lambda, coroutine_with_priority from esphome.coroutine import CoroPriority from esphome.cpp_generator import LambdaExpression +import esphome.final_validate as fv from esphome.types import ConfigType CODEOWNERS = ["@esphome/core"] @@ -61,6 +62,29 @@ def _consume_mdns_sockets(config: ConfigType) -> ConfigType: return config +def _require_network_interface(config: ConfigType) -> ConfigType: + """Require a network interface for mDNS on Arduino/LEAmDNS platforms. + + On ESP8266 and RP2040 the C++ implementation needs at least one IP state + listener (WiFi on ESP8266; WiFi or Ethernet on RP2040) to arm its polling + window. Reject at config time rather than silently producing a component + that never initializes. + """ + if config.get(CONF_DISABLED): + return config + if not CORE.using_arduino or not (CORE.is_esp8266 or CORE.is_rp2040): + return config + full_config = fv.full_config.get() + has_wifi = "wifi" in full_config + has_ethernet = CORE.is_rp2040 and "ethernet" in full_config + if not (has_wifi or has_ethernet): + options = "'wifi'" if CORE.is_esp8266 else "'wifi' or 'ethernet'" + raise cv.Invalid( + f"mdns on this platform requires a network interface — add a {options} component to your configuration." + ) + return config + + CONFIG_SCHEMA = cv.All( cv.Schema( { @@ -74,6 +98,9 @@ CONFIG_SCHEMA = cv.All( ) +FINAL_VALIDATE_SCHEMA = _require_network_interface + + def mdns_txt_record(key: str, value: str) -> cg.RawExpression: """Create a mDNS TXT record.