[mdns] Enforce network-interface availability at config time on ESP8266/RP2040

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.
This commit is contained in:
J. Nick Koston
2026-04-23 20:11:48 -05:00
parent 6938f2b400
commit ae41427523
+27
View File
@@ -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.