mirror of
https://github.com/home-assistant/core.git
synced 2025-07-15 17:27:10 +00:00
Use system zeroconf singleton for homekit (#35502)
Zeroconf instances are expensive so we share a single instance instead of running multiple.
This commit is contained in:
parent
48899c7a1c
commit
751529feca
@ -7,6 +7,7 @@ from aiohttp import web
|
|||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
from zeroconf import InterfaceChoice
|
from zeroconf import InterfaceChoice
|
||||||
|
|
||||||
|
from homeassistant.components import zeroconf
|
||||||
from homeassistant.components.binary_sensor import DEVICE_CLASS_BATTERY_CHARGING
|
from homeassistant.components.binary_sensor import DEVICE_CLASS_BATTERY_CHARGING
|
||||||
from homeassistant.components.http import HomeAssistantView
|
from homeassistant.components.http import HomeAssistantView
|
||||||
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
|
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
|
||||||
@ -242,6 +243,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
|
|||||||
entry.entry_id,
|
entry.entry_id,
|
||||||
)
|
)
|
||||||
await hass.async_add_executor_job(homekit.setup)
|
await hass.async_add_executor_job(homekit.setup)
|
||||||
|
await homekit.async_setup_zeroconf()
|
||||||
|
|
||||||
undo_listener = entry.add_update_listener(_async_update_listener)
|
undo_listener = entry.add_update_listener(_async_update_listener)
|
||||||
|
|
||||||
@ -420,6 +422,7 @@ class HomeKit:
|
|||||||
self.hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, self.async_stop)
|
self.hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, self.async_stop)
|
||||||
ip_addr = self._ip_address or get_local_ip()
|
ip_addr = self._ip_address or get_local_ip()
|
||||||
persist_file = get_persist_fullpath_for_entry_id(self.hass, self._entry_id)
|
persist_file = get_persist_fullpath_for_entry_id(self.hass, self._entry_id)
|
||||||
|
|
||||||
self.driver = HomeDriver(
|
self.driver = HomeDriver(
|
||||||
self.hass,
|
self.hass,
|
||||||
self._entry_id,
|
self._entry_id,
|
||||||
@ -430,11 +433,18 @@ class HomeKit:
|
|||||||
advertised_address=self._advertise_ip,
|
advertised_address=self._advertise_ip,
|
||||||
interface_choice=self._interface_choice,
|
interface_choice=self._interface_choice,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.bridge = HomeBridge(self.hass, self.driver, self._name)
|
self.bridge = HomeBridge(self.hass, self.driver, self._name)
|
||||||
if self._safe_mode:
|
if self._safe_mode:
|
||||||
_LOGGER.debug("Safe_mode selected for %s", self._name)
|
_LOGGER.debug("Safe_mode selected for %s", self._name)
|
||||||
self.driver.safe_mode = True
|
self.driver.safe_mode = True
|
||||||
|
|
||||||
|
async def async_setup_zeroconf(self):
|
||||||
|
"""Share the system zeroconf instance."""
|
||||||
|
# Replace the existing zeroconf instance.
|
||||||
|
await self.hass.async_add_executor_job(self.driver.advertiser.close)
|
||||||
|
self.driver.advertiser = await zeroconf.async_get_instance(self.hass)
|
||||||
|
|
||||||
def reset_accessories(self, entity_ids):
|
def reset_accessories(self, entity_ids):
|
||||||
"""Reset the accessory to load the latest configuration."""
|
"""Reset the accessory to load the latest configuration."""
|
||||||
aid_storage = self.hass.data[DOMAIN][self._entry_id][AID_STORAGE]
|
aid_storage = self.hass.data[DOMAIN][self._entry_id][AID_STORAGE]
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
"documentation": "https://www.home-assistant.io/integrations/homekit",
|
"documentation": "https://www.home-assistant.io/integrations/homekit",
|
||||||
"requirements": ["HAP-python==2.8.3","fnvhash==0.1.0","PyQRCode==1.2.1","base36==0.1.1","PyTurboJPEG==1.4.0"],
|
"requirements": ["HAP-python==2.8.3","fnvhash==0.1.0","PyQRCode==1.2.1","base36==0.1.1","PyTurboJPEG==1.4.0"],
|
||||||
"dependencies": ["http", "camera", "ffmpeg"],
|
"dependencies": ["http", "camera", "ffmpeg"],
|
||||||
"after_dependencies": ["logbook"],
|
"after_dependencies": ["logbook", "zeroconf"],
|
||||||
"codeowners": ["@bdraco"],
|
"codeowners": ["@bdraco"],
|
||||||
"config_flow": true
|
"config_flow": true
|
||||||
}
|
}
|
||||||
|
@ -29,3 +29,10 @@ def events(hass):
|
|||||||
EVENT_HOMEKIT_CHANGED, ha_callback(lambda e: events.append(e))
|
EVENT_HOMEKIT_CHANGED, ha_callback(lambda e: events.append(e))
|
||||||
)
|
)
|
||||||
yield events
|
yield events
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def mock_zeroconf():
|
||||||
|
"""Mock zeroconf."""
|
||||||
|
with patch("homeassistant.components.zeroconf.HaZeroconf") as mock_zc:
|
||||||
|
yield mock_zc.return_value
|
||||||
|
@ -5,6 +5,7 @@ from typing import Dict
|
|||||||
import pytest
|
import pytest
|
||||||
from zeroconf import InterfaceChoice
|
from zeroconf import InterfaceChoice
|
||||||
|
|
||||||
|
from homeassistant.components import zeroconf
|
||||||
from homeassistant.components.binary_sensor import DEVICE_CLASS_BATTERY_CHARGING
|
from homeassistant.components.binary_sensor import DEVICE_CLASS_BATTERY_CHARGING
|
||||||
from homeassistant.components.homekit import (
|
from homeassistant.components.homekit import (
|
||||||
MAX_DEVICES,
|
MAX_DEVICES,
|
||||||
@ -94,6 +95,7 @@ async def test_setup_min(hass):
|
|||||||
with patch(f"{PATH_HOMEKIT}.HomeKit") as mock_homekit:
|
with patch(f"{PATH_HOMEKIT}.HomeKit") as mock_homekit:
|
||||||
mock_homekit.return_value = homekit = Mock()
|
mock_homekit.return_value = homekit = Mock()
|
||||||
type(homekit).async_start = AsyncMock()
|
type(homekit).async_start = AsyncMock()
|
||||||
|
type(homekit).async_setup_zeroconf = AsyncMock()
|
||||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
@ -135,6 +137,7 @@ async def test_setup_auto_start_disabled(hass):
|
|||||||
with patch(f"{PATH_HOMEKIT}.HomeKit") as mock_homekit:
|
with patch(f"{PATH_HOMEKIT}.HomeKit") as mock_homekit:
|
||||||
mock_homekit.return_value = homekit = Mock()
|
mock_homekit.return_value = homekit = Mock()
|
||||||
type(homekit).async_start = AsyncMock()
|
type(homekit).async_start = AsyncMock()
|
||||||
|
type(homekit).async_setup_zeroconf = AsyncMock()
|
||||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
@ -787,6 +790,7 @@ async def test_setup_imported(hass):
|
|||||||
with patch(f"{PATH_HOMEKIT}.HomeKit") as mock_homekit:
|
with patch(f"{PATH_HOMEKIT}.HomeKit") as mock_homekit:
|
||||||
mock_homekit.return_value = homekit = Mock()
|
mock_homekit.return_value = homekit = Mock()
|
||||||
type(homekit).async_start = AsyncMock()
|
type(homekit).async_start = AsyncMock()
|
||||||
|
type(homekit).async_setup_zeroconf = AsyncMock()
|
||||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
@ -841,6 +845,7 @@ async def test_yaml_updates_update_config_entry_for_name(hass):
|
|||||||
with patch(f"{PATH_HOMEKIT}.HomeKit") as mock_homekit:
|
with patch(f"{PATH_HOMEKIT}.HomeKit") as mock_homekit:
|
||||||
mock_homekit.return_value = homekit = Mock()
|
mock_homekit.return_value = homekit = Mock()
|
||||||
type(homekit).async_start = AsyncMock()
|
type(homekit).async_start = AsyncMock()
|
||||||
|
type(homekit).async_setup_zeroconf = AsyncMock()
|
||||||
assert await async_setup_component(
|
assert await async_setup_component(
|
||||||
hass, "homekit", {"homekit": {CONF_NAME: BRIDGE_NAME, CONF_PORT: 12345}}
|
hass, "homekit", {"homekit": {CONF_NAME: BRIDGE_NAME, CONF_PORT: 12345}}
|
||||||
)
|
)
|
||||||
@ -885,6 +890,24 @@ async def test_raise_config_entry_not_ready(hass):
|
|||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
|
||||||
|
async def test_homekit_uses_system_zeroconf(hass, hk_driver, mock_zeroconf):
|
||||||
|
"""Test HomeKit uses system zeroconf."""
|
||||||
|
entry = MockConfigEntry(
|
||||||
|
domain=DOMAIN,
|
||||||
|
data={CONF_NAME: BRIDGE_NAME, CONF_PORT: DEFAULT_PORT},
|
||||||
|
options={},
|
||||||
|
)
|
||||||
|
system_zc = await zeroconf.async_get_instance(hass)
|
||||||
|
|
||||||
|
with patch(f"{PATH_HOMEKIT}.accessories.HomeDriver", return_value=hk_driver), patch(
|
||||||
|
f"{PATH_HOMEKIT}.HomeKit.async_start"
|
||||||
|
):
|
||||||
|
entry.add_to_hass(hass)
|
||||||
|
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert hk_driver.advertiser == system_zc
|
||||||
|
|
||||||
|
|
||||||
def _write_data(path: str, data: Dict) -> None:
|
def _write_data(path: str, data: Dict) -> None:
|
||||||
"""Write the data."""
|
"""Write the data."""
|
||||||
if not os.path.isdir(os.path.dirname(path)):
|
if not os.path.isdir(os.path.dirname(path)):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user