mirror of
https://github.com/home-assistant/core.git
synced 2025-07-15 01:07:10 +00:00
Allow zeroconf instance sharing (#35484)
This commit is contained in:
parent
8b9bd67da7
commit
9d83059f14
@ -23,6 +23,7 @@ from homeassistant.const import (
|
|||||||
from homeassistant.generated.zeroconf import HOMEKIT, ZEROCONF
|
from homeassistant.generated.zeroconf import HOMEKIT, ZEROCONF
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers.network import NoURLAvailableError, get_url
|
from homeassistant.helpers.network import NoURLAvailableError, get_url
|
||||||
|
from homeassistant.helpers.singleton import singleton
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -54,12 +55,40 @@ CONFIG_SCHEMA = vol.Schema(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@singleton(DOMAIN)
|
||||||
|
async def async_get_instance(hass):
|
||||||
|
"""Zeroconf instance to be shared with other integrations that use it."""
|
||||||
|
return await hass.async_add_executor_job(_get_instance, hass)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_instance(hass, default_interface=False):
|
||||||
|
"""Create an instance."""
|
||||||
|
args = [InterfaceChoice.Default] if default_interface else []
|
||||||
|
zeroconf = HaZeroconf(*args)
|
||||||
|
|
||||||
|
def stop_zeroconf(_):
|
||||||
|
"""Stop Zeroconf."""
|
||||||
|
zeroconf.ha_close()
|
||||||
|
|
||||||
|
hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_zeroconf)
|
||||||
|
|
||||||
|
return zeroconf
|
||||||
|
|
||||||
|
|
||||||
|
class HaZeroconf(Zeroconf):
|
||||||
|
"""Zeroconf that cannot be closed."""
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
"""Fake method to avoid integrations closing it."""
|
||||||
|
|
||||||
|
ha_close = Zeroconf.close
|
||||||
|
|
||||||
|
|
||||||
def setup(hass, config):
|
def setup(hass, config):
|
||||||
"""Set up Zeroconf and make Home Assistant discoverable."""
|
"""Set up Zeroconf and make Home Assistant discoverable."""
|
||||||
if DOMAIN in config and config[DOMAIN].get(CONF_DEFAULT_INTERFACE):
|
zeroconf = hass.data[DOMAIN] = _get_instance(
|
||||||
zeroconf = Zeroconf(interfaces=InterfaceChoice.Default)
|
hass, config.get(DOMAIN, {}).get(CONF_DEFAULT_INTERFACE)
|
||||||
else:
|
)
|
||||||
zeroconf = Zeroconf()
|
|
||||||
zeroconf_name = f"{hass.config.location_name}.{ZEROCONF_TYPE}"
|
zeroconf_name = f"{hass.config.location_name}.{ZEROCONF_TYPE}"
|
||||||
|
|
||||||
params = {
|
params = {
|
||||||
@ -142,12 +171,6 @@ def setup(hass, config):
|
|||||||
if HOMEKIT_TYPE not in ZEROCONF:
|
if HOMEKIT_TYPE not in ZEROCONF:
|
||||||
ServiceBrowser(zeroconf, HOMEKIT_TYPE, handlers=[service_update])
|
ServiceBrowser(zeroconf, HOMEKIT_TYPE, handlers=[service_update])
|
||||||
|
|
||||||
def stop_zeroconf(_):
|
|
||||||
"""Stop Zeroconf."""
|
|
||||||
zeroconf.close()
|
|
||||||
|
|
||||||
hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_zeroconf)
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ from zeroconf import InterfaceChoice, ServiceInfo, ServiceStateChange
|
|||||||
|
|
||||||
from homeassistant.components import zeroconf
|
from homeassistant.components import zeroconf
|
||||||
from homeassistant.components.zeroconf import CONF_DEFAULT_INTERFACE
|
from homeassistant.components.zeroconf import CONF_DEFAULT_INTERFACE
|
||||||
|
from homeassistant.const import EVENT_HOMEASSISTANT_STOP
|
||||||
from homeassistant.generated import zeroconf as zc_gen
|
from homeassistant.generated import zeroconf as zc_gen
|
||||||
from homeassistant.setup import async_setup_component
|
from homeassistant.setup import async_setup_component
|
||||||
|
|
||||||
@ -21,7 +22,7 @@ PROPERTIES = {
|
|||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def mock_zeroconf():
|
def mock_zeroconf():
|
||||||
"""Mock zeroconf."""
|
"""Mock zeroconf."""
|
||||||
with patch("homeassistant.components.zeroconf.Zeroconf") as mock_zc:
|
with patch("homeassistant.components.zeroconf.HaZeroconf") as mock_zc:
|
||||||
yield mock_zc.return_value
|
yield mock_zc.return_value
|
||||||
|
|
||||||
|
|
||||||
@ -78,6 +79,10 @@ async def test_setup(hass, mock_zeroconf):
|
|||||||
expected_flow_calls += len(matching_components)
|
expected_flow_calls += len(matching_components)
|
||||||
assert len(mock_config_flow.mock_calls) == expected_flow_calls
|
assert len(mock_config_flow.mock_calls) == expected_flow_calls
|
||||||
|
|
||||||
|
# Test instance is set.
|
||||||
|
assert "zeroconf" in hass.data
|
||||||
|
assert await hass.components.zeroconf.async_get_instance() is mock_zeroconf
|
||||||
|
|
||||||
|
|
||||||
async def test_setup_with_default_interface(hass, mock_zeroconf):
|
async def test_setup_with_default_interface(hass, mock_zeroconf):
|
||||||
"""Test default interface config."""
|
"""Test default interface config."""
|
||||||
@ -171,3 +176,11 @@ async def test_info_from_service_non_utf8(hass):
|
|||||||
assert len(info["properties"]) <= len(raw_info)
|
assert len(info["properties"]) <= len(raw_info)
|
||||||
assert "non-utf8-value" not in info["properties"]
|
assert "non-utf8-value" not in info["properties"]
|
||||||
assert raw_info["non-utf8-value"] is NON_UTF8_VALUE
|
assert raw_info["non-utf8-value"] is NON_UTF8_VALUE
|
||||||
|
|
||||||
|
|
||||||
|
async def test_get_instance(hass, mock_zeroconf):
|
||||||
|
"""Test we get an instance."""
|
||||||
|
assert await hass.components.zeroconf.async_get_instance() is mock_zeroconf
|
||||||
|
hass.bus.async_fire(EVENT_HOMEASSISTANT_STOP)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert len(mock_zeroconf.ha_close.mock_calls) == 1
|
||||||
|
Loading…
x
Reference in New Issue
Block a user