diff --git a/homeassistant/components/homekit/__init__.py b/homeassistant/components/homekit/__init__.py index 4fdad670f09..c2ba5a46525 100644 --- a/homeassistant/components/homekit/__init__.py +++ b/homeassistant/components/homekit/__init__.py @@ -4,6 +4,7 @@ import logging from zlib import adler32 import voluptuous as vol +from zeroconf import InterfaceChoice from homeassistant.components import cover from homeassistant.components.cover import DEVICE_CLASS_GARAGE, DEVICE_CLASS_GATE @@ -39,9 +40,11 @@ from .const import ( CONF_FEATURE_LIST, CONF_FILTER, CONF_SAFE_MODE, + CONF_ZEROCONF_DEFAULT_INTERFACE, DEFAULT_AUTO_START, DEFAULT_PORT, DEFAULT_SAFE_MODE, + DEFAULT_ZEROCONF_DEFAULT_INTERFACE, DEVICE_CLASS_CO, DEVICE_CLASS_CO2, DEVICE_CLASS_PM25, @@ -98,6 +101,10 @@ CONFIG_SCHEMA = vol.Schema( vol.Optional(CONF_SAFE_MODE, default=DEFAULT_SAFE_MODE): cv.boolean, vol.Optional(CONF_FILTER, default={}): FILTER_SCHEMA, vol.Optional(CONF_ENTITY_CONFIG, default={}): validate_entity_config, + vol.Optional( + CONF_ZEROCONF_DEFAULT_INTERFACE, + default=DEFAULT_ZEROCONF_DEFAULT_INTERFACE, + ): cv.boolean, } ) }, @@ -122,6 +129,9 @@ async def async_setup(hass, config): safe_mode = conf[CONF_SAFE_MODE] entity_filter = conf[CONF_FILTER] entity_config = conf[CONF_ENTITY_CONFIG] + interface_choice = ( + InterfaceChoice.Default if config.get(CONF_ZEROCONF_DEFAULT_INTERFACE) else None + ) homekit = HomeKit( hass, @@ -132,6 +142,7 @@ async def async_setup(hass, config): entity_config, safe_mode, advertise_ip, + interface_choice, ) await hass.async_add_executor_job(homekit.setup) @@ -287,6 +298,7 @@ class HomeKit: entity_config, safe_mode, advertise_ip=None, + interface_choice=None, ): """Initialize a HomeKit object.""" self.hass = hass @@ -297,6 +309,7 @@ class HomeKit: self._config = entity_config self._safe_mode = safe_mode self._advertise_ip = advertise_ip + self._interface_choice = interface_choice self.status = STATUS_READY self.bridge = None @@ -317,6 +330,7 @@ class HomeKit: port=self._port, persist_file=path, advertised_address=self._advertise_ip, + interface_choice=self._interface_choice, ) self.bridge = HomeBridge(self.hass, self.driver, self._name) if self._safe_mode: diff --git a/homeassistant/components/homekit/const.py b/homeassistant/components/homekit/const.py index c0f0abe8177..ccce082044b 100644 --- a/homeassistant/components/homekit/const.py +++ b/homeassistant/components/homekit/const.py @@ -21,12 +21,14 @@ CONF_FILTER = "filter" CONF_LINKED_BATTERY_SENSOR = "linked_battery_sensor" CONF_LOW_BATTERY_THRESHOLD = "low_battery_threshold" CONF_SAFE_MODE = "safe_mode" +CONF_ZEROCONF_DEFAULT_INTERFACE = "zeroconf_default_interface" # #### Config Defaults #### DEFAULT_AUTO_START = True DEFAULT_LOW_BATTERY_THRESHOLD = 20 DEFAULT_PORT = 51827 DEFAULT_SAFE_MODE = False +DEFAULT_ZEROCONF_DEFAULT_INTERFACE = False # #### Features #### FEATURE_ON_OFF = "on_off" diff --git a/tests/components/homekit/test_homekit.py b/tests/components/homekit/test_homekit.py index d984eef5fdc..124366ba241 100644 --- a/tests/components/homekit/test_homekit.py +++ b/tests/components/homekit/test_homekit.py @@ -2,6 +2,7 @@ from unittest.mock import ANY, Mock, patch import pytest +from zeroconf import InterfaceChoice from homeassistant import setup from homeassistant.components.homekit import ( @@ -67,7 +68,7 @@ async def test_setup_min(hass): assert await setup.async_setup_component(hass, DOMAIN, {DOMAIN: {}}) mock_homekit.assert_any_call( - hass, BRIDGE_NAME, DEFAULT_PORT, None, ANY, {}, DEFAULT_SAFE_MODE, None + hass, BRIDGE_NAME, DEFAULT_PORT, None, ANY, {}, DEFAULT_SAFE_MODE, None, None ) assert mock_homekit().setup.called is True @@ -96,7 +97,7 @@ async def test_setup_auto_start_disabled(hass): assert await setup.async_setup_component(hass, DOMAIN, config) mock_homekit.assert_any_call( - hass, "Test Name", 11111, "172.0.0.0", ANY, {}, DEFAULT_SAFE_MODE, None + hass, "Test Name", 11111, "172.0.0.0", ANY, {}, DEFAULT_SAFE_MODE, None, None ) assert mock_homekit().setup.called is True @@ -139,6 +140,7 @@ async def test_homekit_setup(hass, hk_driver): port=DEFAULT_PORT, persist_file=path, advertised_address=None, + interface_choice=None, ) assert homekit.driver.safe_mode is False @@ -160,6 +162,7 @@ async def test_homekit_setup_ip_address(hass, hk_driver): port=DEFAULT_PORT, persist_file=ANY, advertised_address=None, + interface_choice=None, ) @@ -179,12 +182,41 @@ async def test_homekit_setup_advertise_ip(hass, hk_driver): port=DEFAULT_PORT, persist_file=ANY, advertised_address="192.168.1.100", + interface_choice=None, + ) + + +async def test_homekit_setup_interface_choice(hass, hk_driver): + """Test setup with interface choice of Default.""" + homekit = HomeKit( + hass, + BRIDGE_NAME, + DEFAULT_PORT, + "0.0.0.0", + {}, + {}, + None, + None, + InterfaceChoice.Default, + ) + + with patch( + f"{PATH_HOMEKIT}.accessories.HomeDriver", return_value=hk_driver + ) as mock_driver: + await hass.async_add_executor_job(homekit.setup) + mock_driver.assert_called_with( + hass, + address="0.0.0.0", + port=DEFAULT_PORT, + persist_file=ANY, + advertised_address=None, + interface_choice=InterfaceChoice.Default, ) async def test_homekit_setup_safe_mode(hass, hk_driver): """Test if safe_mode flag is set.""" - homekit = HomeKit(hass, BRIDGE_NAME, DEFAULT_PORT, None, {}, {}, True) + homekit = HomeKit(hass, BRIDGE_NAME, DEFAULT_PORT, None, {}, {}, True, None) with patch(f"{PATH_HOMEKIT}.accessories.HomeDriver", return_value=hk_driver): await hass.async_add_executor_job(homekit.setup) @@ -193,7 +225,7 @@ async def test_homekit_setup_safe_mode(hass, hk_driver): async def test_homekit_add_accessory(): """Add accessory if config exists and get_acc returns an accessory.""" - homekit = HomeKit("hass", None, None, None, lambda entity_id: True, {}, None) + homekit = HomeKit("hass", None, None, None, lambda entity_id: True, {}, None, None) homekit.driver = "driver" homekit.bridge = mock_bridge = Mock() @@ -215,7 +247,7 @@ async def test_homekit_add_accessory(): async def test_homekit_remove_accessory(): """Remove accessory from bridge.""" - homekit = HomeKit("hass", None, None, None, lambda entity_id: True, {}, None) + homekit = HomeKit("hass", None, None, None, lambda entity_id: True, {}, None, None) homekit.driver = "driver" homekit.bridge = mock_bridge = Mock() mock_bridge.accessories = {"light.demo": "acc"} @@ -228,7 +260,7 @@ async def test_homekit_remove_accessory(): async def test_homekit_entity_filter(hass): """Test the entity filter.""" entity_filter = generate_filter(["cover"], ["demo.test"], [], []) - homekit = HomeKit(hass, None, None, None, entity_filter, {}, None) + homekit = HomeKit(hass, None, None, None, entity_filter, {}, None, None) with patch(f"{PATH_HOMEKIT}.get_accessory") as mock_get_acc: mock_get_acc.return_value = None @@ -248,7 +280,7 @@ async def test_homekit_entity_filter(hass): async def test_homekit_start(hass, hk_driver, debounce_patcher): """Test HomeKit start method.""" pin = b"123-45-678" - homekit = HomeKit(hass, None, None, None, {}, {"cover.demo": {}}, None) + homekit = HomeKit(hass, None, None, None, {}, {"cover.demo": {}}, None, None) homekit.bridge = Mock() homekit.bridge.accessories = [] homekit.driver = hk_driver