Use async zeroconf registration functions (#50168)
parent
e616583bad
commit
909a20b36d
|
@ -4,7 +4,6 @@ from __future__ import annotations
|
|||
from collections.abc import Iterable
|
||||
from contextlib import suppress
|
||||
import fnmatch
|
||||
from functools import partial
|
||||
import ipaddress
|
||||
from ipaddress import ip_address
|
||||
import logging
|
||||
|
@ -33,11 +32,10 @@ from homeassistant.const import (
|
|||
from homeassistant.core import Event, HomeAssistant
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.network import NoURLAvailableError, get_url
|
||||
from homeassistant.helpers.singleton import singleton
|
||||
from homeassistant.loader import async_get_homekit, async_get_zeroconf
|
||||
from homeassistant.loader import async_get_homekit, async_get_zeroconf, bind_hass
|
||||
from homeassistant.util.network import is_loopback
|
||||
|
||||
from .models import HaServiceBrowser, HaZeroconf
|
||||
from .models import HaAsyncZeroconf, HaServiceBrowser, HaZeroconf
|
||||
from .usage import install_multiple_zeroconf_catcher
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
@ -92,16 +90,26 @@ class HaServiceInfo(TypedDict):
|
|||
properties: dict[str, Any]
|
||||
|
||||
|
||||
@singleton(DOMAIN)
|
||||
@bind_hass
|
||||
async def async_get_instance(hass: HomeAssistant) -> HaZeroconf:
|
||||
"""Zeroconf instance to be shared with other integrations that use it."""
|
||||
return cast(HaZeroconf, (await _async_get_instance(hass)).zeroconf)
|
||||
|
||||
|
||||
@bind_hass
|
||||
async def async_get_async_instance(hass: HomeAssistant) -> HaAsyncZeroconf:
|
||||
"""Zeroconf instance to be shared with other integrations that use it."""
|
||||
return await _async_get_instance(hass)
|
||||
|
||||
|
||||
async def _async_get_instance(hass: HomeAssistant, **zcargs: Any) -> HaZeroconf:
|
||||
async def _async_get_instance(hass: HomeAssistant, **zcargs: Any) -> HaAsyncZeroconf:
|
||||
if DOMAIN in hass.data:
|
||||
return cast(HaAsyncZeroconf, hass.data[DOMAIN])
|
||||
|
||||
logging.getLogger("zeroconf").setLevel(logging.NOTSET)
|
||||
|
||||
zeroconf = await hass.async_add_executor_job(partial(HaZeroconf, **zcargs))
|
||||
aio_zc = HaAsyncZeroconf(**zcargs)
|
||||
zeroconf = cast(HaZeroconf, aio_zc.zeroconf)
|
||||
|
||||
install_multiple_zeroconf_catcher(zeroconf)
|
||||
|
||||
|
@ -110,8 +118,9 @@ async def _async_get_instance(hass: HomeAssistant, **zcargs: Any) -> HaZeroconf:
|
|||
zeroconf.ha_close()
|
||||
|
||||
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, _stop_zeroconf)
|
||||
hass.data[DOMAIN] = aio_zc
|
||||
|
||||
return zeroconf
|
||||
return aio_zc
|
||||
|
||||
|
||||
def _get_ip_route(dst_ip: str) -> Any:
|
||||
|
@ -171,7 +180,8 @@ async def async_setup(hass: HomeAssistant, config: dict) -> bool:
|
|||
if not zc_config.get(CONF_IPV6, DEFAULT_IPV6):
|
||||
zc_args["ip_version"] = IPVersion.V4Only
|
||||
|
||||
zeroconf = hass.data[DOMAIN] = await _async_get_instance(hass, **zc_args)
|
||||
aio_zc = await _async_get_instance(hass, **zc_args)
|
||||
zeroconf = aio_zc.zeroconf
|
||||
|
||||
async def _async_zeroconf_hass_start(_event: Event) -> None:
|
||||
"""Expose Home Assistant on zeroconf when it starts.
|
||||
|
@ -179,9 +189,7 @@ async def async_setup(hass: HomeAssistant, config: dict) -> bool:
|
|||
Wait till started or otherwise HTTP is not up and running.
|
||||
"""
|
||||
uuid = await hass.helpers.instance_id.async_get()
|
||||
await hass.async_add_executor_job(
|
||||
_register_hass_zc_service, hass, zeroconf, uuid
|
||||
)
|
||||
await _async_register_hass_zc_service(hass, aio_zc, uuid)
|
||||
|
||||
async def _async_zeroconf_hass_started(_event: Event) -> None:
|
||||
"""Start the service browser."""
|
||||
|
@ -196,8 +204,8 @@ async def async_setup(hass: HomeAssistant, config: dict) -> bool:
|
|||
return True
|
||||
|
||||
|
||||
def _register_hass_zc_service(
|
||||
hass: HomeAssistant, zeroconf: HaZeroconf, uuid: str
|
||||
async def _async_register_hass_zc_service(
|
||||
hass: HomeAssistant, aio_zc: HaAsyncZeroconf, uuid: str
|
||||
) -> None:
|
||||
# Get instance UUID
|
||||
valid_location_name = _truncate_location_name_to_valid(hass.config.location_name)
|
||||
|
@ -244,7 +252,7 @@ def _register_hass_zc_service(
|
|||
|
||||
_LOGGER.info("Starting Zeroconf broadcast")
|
||||
try:
|
||||
zeroconf.register_service(info)
|
||||
await aio_zc.async_register_service(info)
|
||||
except NonUniqueNameException:
|
||||
_LOGGER.error(
|
||||
"Home Assistant instance with identical name present in the local network"
|
||||
|
@ -252,7 +260,7 @@ def _register_hass_zc_service(
|
|||
|
||||
|
||||
async def _async_start_zeroconf_browser(
|
||||
hass: HomeAssistant, zeroconf: HaZeroconf
|
||||
hass: HomeAssistant, zeroconf: Zeroconf
|
||||
) -> None:
|
||||
"""Start the zeroconf browser."""
|
||||
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
"""Models for Zeroconf."""
|
||||
|
||||
import asyncio
|
||||
from typing import Any
|
||||
|
||||
from zeroconf import DNSPointer, DNSRecord, ServiceBrowser, Zeroconf
|
||||
from zeroconf.asyncio import AsyncZeroconf
|
||||
|
||||
|
||||
class HaZeroconf(Zeroconf):
|
||||
|
@ -12,6 +16,20 @@ class HaZeroconf(Zeroconf):
|
|||
ha_close = Zeroconf.close
|
||||
|
||||
|
||||
class HaAsyncZeroconf(AsyncZeroconf):
|
||||
"""Home Assistant version of AsyncZeroconf."""
|
||||
|
||||
def __init__( # pylint: disable=super-init-not-called
|
||||
self, *args: Any, **kwargs: Any
|
||||
) -> None:
|
||||
"""Wrap AsyncZeroconf."""
|
||||
self.zeroconf = HaZeroconf(*args, **kwargs)
|
||||
self.loop = asyncio.get_running_loop()
|
||||
|
||||
async def async_close(self) -> None:
|
||||
"""Fake method to avoid integrations closing it."""
|
||||
|
||||
|
||||
class HaServiceBrowser(ServiceBrowser):
|
||||
"""ServiceBrowser that only consumes DNSPointer records."""
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ from tests.components.light.conftest import mock_light_profiles # noqa: F401
|
|||
@pytest.fixture(autouse=True)
|
||||
def mock_zeroconf():
|
||||
"""Mock zeroconf."""
|
||||
with mock.patch("homeassistant.components.zeroconf.HaZeroconf") as mock_zc:
|
||||
with mock.patch("homeassistant.components.zeroconf.models.HaZeroconf") as mock_zc:
|
||||
yield mock_zc.return_value
|
||||
|
||||
|
||||
|
|
|
@ -478,7 +478,7 @@ async def mqtt_mock(hass, mqtt_client_mock, mqtt_config):
|
|||
@pytest.fixture
|
||||
def mock_zeroconf():
|
||||
"""Mock zeroconf."""
|
||||
with patch("homeassistant.components.zeroconf.HaZeroconf") as mock_zc:
|
||||
with patch("homeassistant.components.zeroconf.models.HaZeroconf") as mock_zc:
|
||||
yield mock_zc.return_value
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue