Use async zeroconf registration functions (#50168)
This commit is contained in:
parent
e616583bad
commit
909a20b36d
4 changed files with 44 additions and 18 deletions
|
@ -4,7 +4,6 @@ from __future__ import annotations
|
||||||
from collections.abc import Iterable
|
from collections.abc import Iterable
|
||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
import fnmatch
|
import fnmatch
|
||||||
from functools import partial
|
|
||||||
import ipaddress
|
import ipaddress
|
||||||
from ipaddress import ip_address
|
from ipaddress import ip_address
|
||||||
import logging
|
import logging
|
||||||
|
@ -33,11 +32,10 @@ from homeassistant.const import (
|
||||||
from homeassistant.core import Event, HomeAssistant
|
from homeassistant.core import Event, HomeAssistant
|
||||||
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
|
from homeassistant.loader import async_get_homekit, async_get_zeroconf, bind_hass
|
||||||
from homeassistant.loader import async_get_homekit, async_get_zeroconf
|
|
||||||
from homeassistant.util.network import is_loopback
|
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
|
from .usage import install_multiple_zeroconf_catcher
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
@ -92,16 +90,26 @@ class HaServiceInfo(TypedDict):
|
||||||
properties: dict[str, Any]
|
properties: dict[str, Any]
|
||||||
|
|
||||||
|
|
||||||
@singleton(DOMAIN)
|
@bind_hass
|
||||||
async def async_get_instance(hass: HomeAssistant) -> HaZeroconf:
|
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."""
|
"""Zeroconf instance to be shared with other integrations that use it."""
|
||||||
return await _async_get_instance(hass)
|
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)
|
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)
|
install_multiple_zeroconf_catcher(zeroconf)
|
||||||
|
|
||||||
|
@ -110,8 +118,9 @@ async def _async_get_instance(hass: HomeAssistant, **zcargs: Any) -> HaZeroconf:
|
||||||
zeroconf.ha_close()
|
zeroconf.ha_close()
|
||||||
|
|
||||||
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, _stop_zeroconf)
|
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:
|
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):
|
if not zc_config.get(CONF_IPV6, DEFAULT_IPV6):
|
||||||
zc_args["ip_version"] = IPVersion.V4Only
|
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:
|
async def _async_zeroconf_hass_start(_event: Event) -> None:
|
||||||
"""Expose Home Assistant on zeroconf when it starts.
|
"""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.
|
Wait till started or otherwise HTTP is not up and running.
|
||||||
"""
|
"""
|
||||||
uuid = await hass.helpers.instance_id.async_get()
|
uuid = await hass.helpers.instance_id.async_get()
|
||||||
await hass.async_add_executor_job(
|
await _async_register_hass_zc_service(hass, aio_zc, uuid)
|
||||||
_register_hass_zc_service, hass, zeroconf, uuid
|
|
||||||
)
|
|
||||||
|
|
||||||
async def _async_zeroconf_hass_started(_event: Event) -> None:
|
async def _async_zeroconf_hass_started(_event: Event) -> None:
|
||||||
"""Start the service browser."""
|
"""Start the service browser."""
|
||||||
|
@ -196,8 +204,8 @@ async def async_setup(hass: HomeAssistant, config: dict) -> bool:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def _register_hass_zc_service(
|
async def _async_register_hass_zc_service(
|
||||||
hass: HomeAssistant, zeroconf: HaZeroconf, uuid: str
|
hass: HomeAssistant, aio_zc: HaAsyncZeroconf, uuid: str
|
||||||
) -> None:
|
) -> None:
|
||||||
# Get instance UUID
|
# Get instance UUID
|
||||||
valid_location_name = _truncate_location_name_to_valid(hass.config.location_name)
|
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")
|
_LOGGER.info("Starting Zeroconf broadcast")
|
||||||
try:
|
try:
|
||||||
zeroconf.register_service(info)
|
await aio_zc.async_register_service(info)
|
||||||
except NonUniqueNameException:
|
except NonUniqueNameException:
|
||||||
_LOGGER.error(
|
_LOGGER.error(
|
||||||
"Home Assistant instance with identical name present in the local network"
|
"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(
|
async def _async_start_zeroconf_browser(
|
||||||
hass: HomeAssistant, zeroconf: HaZeroconf
|
hass: HomeAssistant, zeroconf: Zeroconf
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Start the zeroconf browser."""
|
"""Start the zeroconf browser."""
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
"""Models for Zeroconf."""
|
"""Models for Zeroconf."""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from zeroconf import DNSPointer, DNSRecord, ServiceBrowser, Zeroconf
|
from zeroconf import DNSPointer, DNSRecord, ServiceBrowser, Zeroconf
|
||||||
|
from zeroconf.asyncio import AsyncZeroconf
|
||||||
|
|
||||||
|
|
||||||
class HaZeroconf(Zeroconf):
|
class HaZeroconf(Zeroconf):
|
||||||
|
@ -12,6 +16,20 @@ class HaZeroconf(Zeroconf):
|
||||||
ha_close = Zeroconf.close
|
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):
|
class HaServiceBrowser(ServiceBrowser):
|
||||||
"""ServiceBrowser that only consumes DNSPointer records."""
|
"""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)
|
@pytest.fixture(autouse=True)
|
||||||
def mock_zeroconf():
|
def mock_zeroconf():
|
||||||
"""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
|
yield mock_zc.return_value
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -478,7 +478,7 @@ async def mqtt_mock(hass, mqtt_client_mock, mqtt_config):
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def mock_zeroconf():
|
def mock_zeroconf():
|
||||||
"""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
|
yield mock_zc.return_value
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue