Add configuration for Zeroconf discovery interfaces (#2880)
authorSimon Vos <vossim@users.noreply.github.com>
Fri, 2 Jan 2026 12:09:21 +0000 (13:09 +0100)
committerGitHub <noreply@github.com>
Fri, 2 Jan 2026 12:09:21 +0000 (13:09 +0100)
feat(core): Add configuration for Zeroconf discovery interfaces

- Add `zeroconf_interfaces` setting to allow choosing between 'default' and 'all' network interfaces for mDNS discovery.
- Move ConfigController setup before AsyncZeroconf initialization in `MusicAssistant` to ensure config is available.
- Initialize `AsyncZeroconf` based on the configured interface choice (`InterfaceChoice.All` vs `InterfaceChoice.Default`).

music_assistant/constants.py
music_assistant/controllers/streams/streams_controller.py
music_assistant/mass.py

index 906d4154ffb744ac7c98df9e85d8d5f090b07b54..d9a5515a7130474590ca6f6b942ba9197614f5f6 100644 (file)
@@ -101,6 +101,7 @@ CONF_USE_SSL: Final[str] = "use_ssl"
 CONF_VERIFY_SSL: Final[str] = "verify_ssl"
 CONF_SSL_FINGERPRINT: Final[str] = "ssl_fingerprint"
 CONF_AUTH_ALLOW_SELF_REGISTRATION: Final[str] = "auth_allow_self_registration"
+CONF_ZEROCONF_INTERFACES: Final[str] = "zeroconf_interfaces"
 CONF_ENABLED: Final[str] = "enabled"
 
 # config default values
@@ -688,6 +689,25 @@ CONF_ENTRY_LIBRARY_SYNC_ARTISTS = ConfigEntry(
     default_value=True,
     category="sync_options",
 )
+
+
+CONF_ENTRY_ZEROCONF_INTERFACES = ConfigEntry(
+    key=CONF_ZEROCONF_INTERFACES,
+    type=ConfigEntryType.STRING,
+    label="Mdns/Zeroconf discovery interface(s)",
+    description="In normal circumstances, Music Assistant will automatically "
+    "discover all players on the network using multicast discovery on the "
+    "(L2) local network, such as mDNS or UPNP.\n\n"
+    "By default, Music Assistant will only listen on the default interface. "
+    "If you have multiple network interfaces and you want to discover players "
+    "on all interfaces, you can change this setting to 'All interfaces'.",
+    options=[
+        ConfigValueOption("Default interface", "default"),
+        ConfigValueOption("All interfaces", "all"),
+    ],
+    default_value="default",
+    category="advanced",
+)
 CONF_ENTRY_LIBRARY_SYNC_ALBUMS = ConfigEntry(
     key="library_sync_albums",
     type=ConfigEntryType.BOOLEAN,
index b1ca238da7a8e9968afd59018168f2d2f3cc913c..8989641228a46b7ff8462c051625fced3b35ae11 100644 (file)
@@ -45,6 +45,7 @@ from music_assistant.constants import (
     CONF_ENTRY_ENABLE_ICY_METADATA,
     CONF_ENTRY_LOG_LEVEL,
     CONF_ENTRY_SUPPORT_GAPLESS_DIFFERENT_SAMPLE_RATES,
+    CONF_ENTRY_ZEROCONF_INTERFACES,
     CONF_HTTP_PROFILE,
     CONF_OUTPUT_CHANNELS,
     CONF_OUTPUT_CODEC,
@@ -294,6 +295,7 @@ class StreamsController(CoreController):
                 default_value="GLOBAL",
                 category="advanced",
             ),
+            CONF_ENTRY_ZEROCONF_INTERFACES,
         )
 
     async def setup(self, config: CoreConfig) -> None:
index 645e3c9e7df2dd3297d3853a693ca06d84fa9a05..11743541c2dffa626da26ce2c3713f72bfb2fd17 100644 (file)
@@ -33,6 +33,7 @@ from music_assistant.constants import (
     API_SCHEMA_VERSION,
     CONF_PROVIDERS,
     CONF_SERVER_ID,
+    CONF_ZEROCONF_INTERFACES,
     CONFIGURABLE_CORE_CONTROLLERS,
     MASS_LOGGER_NAME,
     MIN_SCHEMA_VERSION,
@@ -143,14 +144,22 @@ class MusicAssistant:
         self.loop_thread_id = getattr(self.loop, "_thread_id")  # noqa: B009
         self.running_as_hass_addon = await is_hass_supervisor()
         self.version = await get_package_version("music_assistant") or "0.0.0"
+        # setup config controller first and fetch important config values
+        self.config = ConfigController(self)
+        await self.config.setup()
         # create shared zeroconf instance
         # TODO: enumerate interfaces and enable IPv6 support
-        self.aiozc = AsyncZeroconf(ip_version=IPVersion.V4Only, interfaces=InterfaceChoice.Default)
+        zeroconf_interfaces = self.config.get_raw_core_config_value(
+            "streams", CONF_ZEROCONF_INTERFACES, "default"
+        )
+        self.aiozc = AsyncZeroconf(
+            ip_version=IPVersion.V4Only,
+            interfaces=InterfaceChoice.All
+            if zeroconf_interfaces == "all"
+            else InterfaceChoice.Default,
+        )
         # load all available providers from manifest files
         await self.__load_provider_manifests()
-        # setup config controller first and fetch important config values
-        self.config = ConfigController(self)
-        await self.config.setup()
         # setup/migrate storage
         await self._setup_storage()
         LOGGER.info(