From d027dde76902638928e03bc861754129861e7fe5 Mon Sep 17 00:00:00 2001 From: Tucker Kern Date: Fri, 8 Nov 2024 22:57:49 +0000 Subject: [PATCH] Add setting to use default interface for Zeroconf instead of all --- esphome/dashboard/core.py | 2 +- esphome/dashboard/settings.py | 4 ++++ esphome/dashboard/status/mdns.py | 5 +++-- esphome/helpers.py | 5 ++++- esphome/zeroconf.py | 22 +++++++++++++++++++++- 5 files changed, 33 insertions(+), 5 deletions(-) diff --git a/esphome/dashboard/core.py b/esphome/dashboard/core.py index 563ca1506d..2846677cfa 100644 --- a/esphome/dashboard/core.py +++ b/esphome/dashboard/core.py @@ -136,7 +136,7 @@ class ESPHomeDashboard: else: from .status.mdns import MDNSStatus - mdns_status = MDNSStatus() + mdns_status = MDNSStatus(settings.zeroconf_default_interface) await mdns_status.async_refresh_hosts() self.mdns_status = mdns_status mdns_task = asyncio.create_task(mdns_status.async_run()) diff --git a/esphome/dashboard/settings.py b/esphome/dashboard/settings.py index 1f05abab4c..878a20d8b9 100644 --- a/esphome/dashboard/settings.py +++ b/esphome/dashboard/settings.py @@ -54,6 +54,10 @@ class DashboardSettings: def relative_url(self) -> str: return os.getenv("ESPHOME_DASHBOARD_RELATIVE_URL") or "/" + @property + def zeroconf_default_interface(self): + return get_bool_env("ESPHOME_DASHBOARD_ZEROCONF_DEFAULT_INTERFACE") + @property def status_use_ping(self): return get_bool_env("ESPHOME_DASHBOARD_USE_PING") diff --git a/esphome/dashboard/status/mdns.py b/esphome/dashboard/status/mdns.py index bd212bc563..526674129b 100644 --- a/esphome/dashboard/status/mdns.py +++ b/esphome/dashboard/status/mdns.py @@ -18,10 +18,11 @@ from ..entries import DashboardEntry, bool_to_entry_state class MDNSStatus: """Class that updates the mdns status.""" - def __init__(self) -> None: + def __init__(self, default_interface=False) -> None: """Initialize the MDNSStatus class.""" super().__init__() self.aiozc: AsyncEsphomeZeroconf | None = None + self._zc_default_interface: bool = default_interface # This is the current mdns state for each host (True, False, None) self.host_mdns_state: dict[str, bool | None] = {} self._loop = asyncio.get_running_loop() @@ -64,7 +65,7 @@ class MDNSStatus: async def async_run(self) -> None: dashboard = DASHBOARD entries = dashboard.entries - aiozc = AsyncEsphomeZeroconf() + aiozc = AsyncEsphomeZeroconf(default_interface=self._zc_default_interface) self.aiozc = aiozc host_mdns_state = self.host_mdns_state diff --git a/esphome/helpers.py b/esphome/helpers.py index 8aae43c2bb..ac347d4f39 100644 --- a/esphome/helpers.py +++ b/esphome/helpers.py @@ -101,10 +101,13 @@ def is_ip_address(host): def _resolve_with_zeroconf(host): from esphome.core import EsphomeError + from esphome.dashboard.core import DASHBOARD from esphome.zeroconf import EsphomeZeroconf try: - zc = EsphomeZeroconf() + zc = EsphomeZeroconf( + default_interface=DASHBOARD.settings.zeroconf_default_interface + ) except Exception as err: raise EsphomeError( "Cannot start mDNS sockets, is this a docker container without " diff --git a/esphome/zeroconf.py b/esphome/zeroconf.py index 76049fa776..6a2d438924 100644 --- a/esphome/zeroconf.py +++ b/esphome/zeroconf.py @@ -5,7 +5,13 @@ from dataclasses import dataclass import logging from typing import Callable -from zeroconf import IPVersion, ServiceInfo, ServiceStateChange, Zeroconf +from zeroconf import ( + InterfaceChoice, + IPVersion, + ServiceInfo, + ServiceStateChange, + Zeroconf, +) from zeroconf.asyncio import AsyncServiceBrowser, AsyncServiceInfo, AsyncZeroconf from esphome.storage_json import StorageJSON, ext_storage_path @@ -176,6 +182,13 @@ def _make_host_resolver(host: str) -> HostResolver: class EsphomeZeroconf(Zeroconf): + def __init__(self, default_interface=False) -> None: + super().__init__( + interfaces=( + InterfaceChoice.Default if default_interface else InterfaceChoice.All + ) + ) + def resolve_host(self, host: str, timeout: float = 3.0) -> str | None: """Resolve a host name to an IP address.""" info = _make_host_resolver(host) @@ -188,6 +201,13 @@ class EsphomeZeroconf(Zeroconf): class AsyncEsphomeZeroconf(AsyncZeroconf): + def __init__(self, default_interface=False) -> None: + super().__init__( + interfaces=( + InterfaceChoice.Default if default_interface else InterfaceChoice.All + ) + ) + async def async_resolve_host(self, host: str, timeout: float = 3.0) -> str | None: """Resolve a host name to an IP address.""" info = _make_host_resolver(host)