Cleanup homekit and remove aid storage from hass.data (#47488)

This commit is contained in:
J. Nick Koston 2021-03-11 20:05:03 -10:00 committed by GitHub
parent 33c4eb3434
commit f4b775b125
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 147 additions and 205 deletions

View File

@ -34,7 +34,7 @@ from homeassistant.const import (
SERVICE_RELOAD, SERVICE_RELOAD,
) )
from homeassistant.core import CoreState, HomeAssistant, callback from homeassistant.core import CoreState, HomeAssistant, callback
from homeassistant.exceptions import ConfigEntryNotReady, Unauthorized from homeassistant.exceptions import Unauthorized
from homeassistant.helpers import device_registry, entity_registry from homeassistant.helpers import device_registry, entity_registry
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entityfilter import BASE_FILTER_SCHEMA, FILTER_SCHEMA from homeassistant.helpers.entityfilter import BASE_FILTER_SCHEMA, FILTER_SCHEMA
@ -58,7 +58,6 @@ from . import ( # noqa: F401
from .accessories import HomeBridge, HomeDriver, get_accessory from .accessories import HomeBridge, HomeDriver, get_accessory
from .aidmanager import AccessoryAidStorage from .aidmanager import AccessoryAidStorage
from .const import ( from .const import (
AID_STORAGE,
ATTR_INTERGRATION, ATTR_INTERGRATION,
ATTR_MANUFACTURER, ATTR_MANUFACTURER,
ATTR_MODEL, ATTR_MODEL,
@ -241,9 +240,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
port = conf[CONF_PORT] port = conf[CONF_PORT]
_LOGGER.debug("Begin setup HomeKit for %s", name) _LOGGER.debug("Begin setup HomeKit for %s", name)
aid_storage = AccessoryAidStorage(hass, entry.entry_id)
await aid_storage.async_initialize()
# ip_address and advertise_ip are yaml only # ip_address and advertise_ip are yaml only
ip_address = conf.get(CONF_IP_ADDRESS) ip_address = conf.get(CONF_IP_ADDRESS)
advertise_ip = conf.get(CONF_ADVERTISE_IP) advertise_ip = conf.get(CONF_ADVERTISE_IP)
@ -276,26 +272,14 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
entry.entry_id, entry.entry_id,
entry.title, entry.title,
) )
zeroconf_instance = await zeroconf.async_get_instance(hass)
# If the previous instance hasn't cleaned up yet
# we need to wait a bit
try:
await hass.async_add_executor_job(homekit.setup, zeroconf_instance)
except (OSError, AttributeError) as ex:
_LOGGER.warning(
"%s could not be setup because the local port %s is in use", name, port
)
raise ConfigEntryNotReady from ex
undo_listener = entry.add_update_listener(_async_update_listener)
hass.data[DOMAIN][entry.entry_id] = { hass.data[DOMAIN][entry.entry_id] = {
AID_STORAGE: aid_storage,
HOMEKIT: homekit, HOMEKIT: homekit,
UNDO_UPDATE_LISTENER: undo_listener, UNDO_UPDATE_LISTENER: entry.add_update_listener(_async_update_listener),
} }
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, homekit.async_stop)
if hass.state == CoreState.running: if hass.state == CoreState.running:
await homekit.async_start() await homekit.async_start()
elif auto_start: elif auto_start:
@ -463,6 +447,7 @@ class HomeKit:
self._entry_id = entry_id self._entry_id = entry_id
self._entry_title = entry_title self._entry_title = entry_title
self._homekit_mode = homekit_mode self._homekit_mode = homekit_mode
self.aid_storage = None
self.status = STATUS_READY self.status = STATUS_READY
self.bridge = None self.bridge = None
@ -470,7 +455,6 @@ class HomeKit:
def setup(self, zeroconf_instance): def setup(self, zeroconf_instance):
"""Set up bridge and accessory driver.""" """Set up bridge and accessory driver."""
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)
@ -503,10 +487,9 @@ class HomeKit:
self.driver.config_changed() self.driver.config_changed()
return return
aid_storage = self.hass.data[DOMAIN][self._entry_id][AID_STORAGE]
removed = [] removed = []
for entity_id in entity_ids: for entity_id in entity_ids:
aid = aid_storage.get_or_allocate_aid_for_entity_id(entity_id) aid = self.aid_storage.get_or_allocate_aid_for_entity_id(entity_id)
if aid not in self.bridge.accessories: if aid not in self.bridge.accessories:
continue continue
@ -531,9 +514,6 @@ class HomeKit:
def add_bridge_accessory(self, state): def add_bridge_accessory(self, state):
"""Try adding accessory to bridge if configured beforehand.""" """Try adding accessory to bridge if configured beforehand."""
if not self._filter(state.entity_id):
return
# The bridge itself counts as an accessory # The bridge itself counts as an accessory
if len(self.bridge.accessories) + 1 >= MAX_DEVICES: if len(self.bridge.accessories) + 1 >= MAX_DEVICES:
_LOGGER.warning( _LOGGER.warning(
@ -555,9 +535,7 @@ class HomeKit:
state.entity_id, state.entity_id,
) )
aid = self.hass.data[DOMAIN][self._entry_id][ aid = self.aid_storage.get_or_allocate_aid_for_entity_id(state.entity_id)
AID_STORAGE
].get_or_allocate_aid_for_entity_id(state.entity_id)
conf = self._config.pop(state.entity_id, {}) conf = self._config.pop(state.entity_id, {})
# If an accessory cannot be created or added due to an exception # If an accessory cannot be created or added due to an exception
# of any kind (usually in pyhap) it should not prevent # of any kind (usually in pyhap) it should not prevent
@ -578,15 +556,10 @@ class HomeKit:
acc = self.bridge.accessories.pop(aid) acc = self.bridge.accessories.pop(aid)
return acc return acc
async def async_start(self, *args): async def async_configure_accessories(self):
"""Start the accessory driver.""" """Configure accessories for the included states."""
if self.status != STATUS_READY: dev_reg = device_registry.async_get(self.hass)
return ent_reg = entity_registry.async_get(self.hass)
self.status = STATUS_WAIT
ent_reg = await entity_registry.async_get_registry(self.hass)
dev_reg = await device_registry.async_get_registry(self.hass)
device_lookup = ent_reg.async_get_device_class_lookup( device_lookup = ent_reg.async_get_device_class_lookup(
{ {
(BINARY_SENSOR_DOMAIN, DEVICE_CLASS_BATTERY_CHARGING), (BINARY_SENSOR_DOMAIN, DEVICE_CLASS_BATTERY_CHARGING),
@ -597,10 +570,9 @@ class HomeKit:
} }
) )
bridged_states = [] entity_states = []
for state in self.hass.states.async_all(): for state in self.hass.states.async_all():
entity_id = state.entity_id entity_id = state.entity_id
if not self._filter(entity_id): if not self._filter(entity_id):
continue continue
@ -611,17 +583,40 @@ class HomeKit:
) )
self._async_configure_linked_sensors(ent_reg_ent, device_lookup, state) self._async_configure_linked_sensors(ent_reg_ent, device_lookup, state)
bridged_states.append(state) entity_states.append(state)
self._async_register_bridge(dev_reg) return entity_states
await self._async_start(bridged_states)
async def async_start(self, *args):
"""Load storage and start."""
if self.status != STATUS_READY:
return
self.status = STATUS_WAIT
zc_instance = await zeroconf.async_get_instance(self.hass)
await self.hass.async_add_executor_job(self.setup, zc_instance)
self.aid_storage = AccessoryAidStorage(self.hass, self._entry_id)
await self.aid_storage.async_initialize()
await self._async_create_accessories()
self._async_register_bridge()
_LOGGER.debug("Driver start for %s", self._name) _LOGGER.debug("Driver start for %s", self._name)
await self.driver.async_start() await self.driver.async_start()
self.status = STATUS_RUNNING self.status = STATUS_RUNNING
if self.driver.state.paired:
return
show_setup_message(
self.hass,
self._entry_id,
accessory_friendly_name(self._entry_title, self.driver.accessory),
self.driver.state.pincode,
self.driver.accessory.xhm_uri(),
)
@callback @callback
def _async_register_bridge(self, dev_reg): def _async_register_bridge(self):
"""Register the bridge as a device so homekit_controller and exclude it from discovery.""" """Register the bridge as a device so homekit_controller and exclude it from discovery."""
dev_reg = device_registry.async_get(self.hass)
formatted_mac = device_registry.format_mac(self.driver.state.mac) formatted_mac = device_registry.format_mac(self.driver.state.mac)
# Connections and identifiers are both used here. # Connections and identifiers are both used here.
# #
@ -645,8 +640,9 @@ class HomeKit:
identifiers={identifier}, identifiers={identifier},
connections={connection}, connections={connection},
manufacturer=MANUFACTURER, manufacturer=MANUFACTURER,
name=self._name, name=accessory_friendly_name(self._entry_title, self.driver.accessory),
model=f"Home Assistant HomeKit {hk_mode_name}", model=f"HomeKit {hk_mode_name}",
entry_type="service",
) )
@callback @callback
@ -663,14 +659,13 @@ class HomeKit:
for device_id in devices_to_purge: for device_id in devices_to_purge:
dev_reg.async_remove_device(device_id) dev_reg.async_remove_device(device_id)
async def _async_start(self, entity_states): async def _async_create_accessories(self):
"""Start the accessory.""" """Create the accessories."""
entity_states = await self.async_configure_accessories()
if self._homekit_mode == HOMEKIT_MODE_ACCESSORY: if self._homekit_mode == HOMEKIT_MODE_ACCESSORY:
state = entity_states[0] state = entity_states[0]
conf = self._config.pop(state.entity_id, {}) conf = self._config.pop(state.entity_id, {})
acc = get_accessory(self.hass, self.driver, state, STANDALONE_AID, conf) acc = get_accessory(self.hass, self.driver, state, STANDALONE_AID, conf)
self.driver.add_accessory(acc)
else: else:
self.bridge = HomeBridge(self.hass, self.driver, self._name) self.bridge = HomeBridge(self.hass, self.driver, self._name)
for state in entity_states: for state in entity_states:
@ -679,15 +674,6 @@ class HomeKit:
await self.hass.async_add_executor_job(self.driver.add_accessory, acc) await self.hass.async_add_executor_job(self.driver.add_accessory, acc)
if not self.driver.state.paired:
show_setup_message(
self.hass,
self._entry_id,
accessory_friendly_name(self._entry_title, self.driver.accessory),
self.driver.state.pincode,
self.driver.accessory.xhm_uri(),
)
async def async_stop(self, *args): async def async_stop(self, *args):
"""Stop the accessory driver.""" """Stop the accessory driver."""
if self.status != STATUS_RUNNING: if self.status != STATUS_RUNNING:

View File

@ -5,7 +5,6 @@ DEBOUNCE_TIMEOUT = 0.5
DEVICE_PRECISION_LEEWAY = 6 DEVICE_PRECISION_LEEWAY = 6
DOMAIN = "homekit" DOMAIN = "homekit"
HOMEKIT_FILE = ".homekit.state" HOMEKIT_FILE = ".homekit.state"
AID_STORAGE = "homekit-aid-allocations"
HOMEKIT_PAIRING_QR = "homekit-pairing-qr" HOMEKIT_PAIRING_QR = "homekit-pairing-qr"
HOMEKIT_PAIRING_QR_SECRET = "homekit-pairing-qr-secret" HOMEKIT_PAIRING_QR_SECRET = "homekit-pairing-qr-secret"
HOMEKIT = "homekit" HOMEKIT = "homekit"

View File

@ -487,8 +487,10 @@ def accessory_friendly_name(hass_name, accessory):
see both to identify the accessory. see both to identify the accessory.
""" """
accessory_mdns_name = accessory.display_name accessory_mdns_name = accessory.display_name
if hass_name.startswith(accessory_mdns_name): if hass_name.casefold().startswith(accessory_mdns_name.casefold()):
return hass_name return hass_name
if accessory_mdns_name.casefold().startswith(hass_name.casefold()):
return accessory_mdns_name
return f"{hass_name} ({accessory_mdns_name})" return f"{hass_name} ({accessory_mdns_name})"

View File

@ -14,7 +14,9 @@ def hk_driver(loop):
"""Return a custom AccessoryDriver instance for HomeKit accessory init.""" """Return a custom AccessoryDriver instance for HomeKit accessory init."""
with patch("pyhap.accessory_driver.Zeroconf"), patch( with patch("pyhap.accessory_driver.Zeroconf"), patch(
"pyhap.accessory_driver.AccessoryEncoder" "pyhap.accessory_driver.AccessoryEncoder"
), patch("pyhap.accessory_driver.HAPServer"), patch( ), patch("pyhap.accessory_driver.HAPServer.async_stop"), patch(
"pyhap.accessory_driver.HAPServer.async_start"
), patch(
"pyhap.accessory_driver.AccessoryDriver.publish" "pyhap.accessory_driver.AccessoryDriver.publish"
), patch( ), patch(
"pyhap.accessory_driver.AccessoryDriver.persist" "pyhap.accessory_driver.AccessoryDriver.persist"

View File

@ -1,4 +1,5 @@
"""Tests for the HomeKit component.""" """Tests for the HomeKit component."""
import asyncio
import os import os
from typing import Dict from typing import Dict
from unittest.mock import ANY, AsyncMock, MagicMock, Mock, patch from unittest.mock import ANY, AsyncMock, MagicMock, Mock, patch
@ -23,7 +24,6 @@ from homeassistant.components.homekit import (
) )
from homeassistant.components.homekit.accessories import HomeBridge from homeassistant.components.homekit.accessories import HomeBridge
from homeassistant.components.homekit.const import ( from homeassistant.components.homekit.const import (
AID_STORAGE,
BRIDGE_NAME, BRIDGE_NAME,
BRIDGE_SERIAL_NUMBER, BRIDGE_SERIAL_NUMBER,
CONF_AUTO_START, CONF_AUTO_START,
@ -47,7 +47,6 @@ from homeassistant.const import (
DEVICE_CLASS_BATTERY, DEVICE_CLASS_BATTERY,
DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_HUMIDITY,
EVENT_HOMEASSISTANT_STARTED, EVENT_HOMEASSISTANT_STARTED,
EVENT_HOMEASSISTANT_STOP,
PERCENTAGE, PERCENTAGE,
SERVICE_RELOAD, SERVICE_RELOAD,
STATE_ON, STATE_ON,
@ -98,8 +97,28 @@ def _mock_homekit(hass, entry, homekit_mode, entity_filter=None):
) )
def _mock_homekit_bridge(hass, entry):
homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_BRIDGE)
homekit.driver = MagicMock()
return homekit
def _mock_accessories(accessory_count):
accessories = {}
for idx in range(accessory_count + 1):
accessories[idx + 1000] = MagicMock(async_stop=AsyncMock())
return accessories
def _mock_pyhap_bridge():
return MagicMock(
aid=1, accessories=_mock_accessories(10), display_name="HomeKit Bridge"
)
async def test_setup_min(hass, mock_zeroconf): async def test_setup_min(hass, mock_zeroconf):
"""Test async_setup with min config options.""" """Test async_setup with min config options."""
await async_setup_component(hass, "persistent_notification", {})
entry = MockConfigEntry( entry = MockConfigEntry(
domain=DOMAIN, domain=DOMAIN,
data={CONF_NAME: BRIDGE_NAME, CONF_PORT: DEFAULT_PORT}, data={CONF_NAME: BRIDGE_NAME, CONF_PORT: DEFAULT_PORT},
@ -126,18 +145,16 @@ async def test_setup_min(hass, mock_zeroconf):
entry.entry_id, entry.entry_id,
entry.title, entry.title,
) )
assert mock_homekit().setup.called is True
# Test auto start enabled # Test auto start enabled
mock_homekit.reset_mock()
hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED) hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
await hass.async_block_till_done() await hass.async_block_till_done()
assert mock_homekit().async_start.called is True
mock_homekit().async_start.assert_called()
async def test_setup_auto_start_disabled(hass, mock_zeroconf): async def test_setup_auto_start_disabled(hass, mock_zeroconf):
"""Test async_setup with auto start disabled and test service calls.""" """Test async_setup with auto start disabled and test service calls."""
await async_setup_component(hass, "persistent_notification", {})
entry = MockConfigEntry( entry = MockConfigEntry(
domain=DOMAIN, domain=DOMAIN,
data={CONF_NAME: "Test Name", CONF_PORT: 11111, CONF_IP_ADDRESS: "172.0.0.0"}, data={CONF_NAME: "Test Name", CONF_PORT: 11111, CONF_IP_ADDRESS: "172.0.0.0"},
@ -164,7 +181,6 @@ async def test_setup_auto_start_disabled(hass, mock_zeroconf):
entry.entry_id, entry.entry_id,
entry.title, entry.title,
) )
assert mock_homekit().setup.called is True
# Test auto_start disabled # Test auto_start disabled
homekit.reset_mock() homekit.reset_mock()
@ -237,9 +253,6 @@ async def test_homekit_setup(hass, hk_driver, mock_zeroconf):
) )
assert homekit.driver.safe_mode is False assert homekit.driver.safe_mode is False
# Test if stop listener is setup
assert hass.bus.async_listeners().get(EVENT_HOMEASSISTANT_STOP) == 1
async def test_homekit_setup_ip_address(hass, hk_driver, mock_zeroconf): async def test_homekit_setup_ip_address(hass, hk_driver, mock_zeroconf):
"""Test setup with given IP address.""" """Test setup with given IP address."""
@ -321,40 +334,37 @@ async def test_homekit_setup_advertise_ip(hass, hk_driver, mock_zeroconf):
async def test_homekit_add_accessory(hass, mock_zeroconf): async def test_homekit_add_accessory(hass, mock_zeroconf):
"""Add accessory if config exists and get_acc returns an accessory.""" """Add accessory if config exists and get_acc returns an accessory."""
await async_setup_component(hass, "persistent_notification", {})
entry = MockConfigEntry( entry = MockConfigEntry(
domain=DOMAIN, data={CONF_NAME: "mock_name", CONF_PORT: 12345} domain=DOMAIN, data={CONF_NAME: "mock_name", CONF_PORT: 12345}
) )
entry.add_to_hass(hass) entry.add_to_hass(hass)
homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_BRIDGE) homekit = _mock_homekit_bridge(hass, entry)
homekit.driver = "driver" mock_acc = Mock(category="any")
homekit.bridge = mock_bridge = Mock()
homekit.bridge.accessories = range(10)
homekit.async_start = AsyncMock()
with patch(f"{PATH_HOMEKIT}.HomeKit", return_value=homekit): with patch(f"{PATH_HOMEKIT}.HomeKit", return_value=homekit):
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()
mock_acc = Mock(category="any") homekit.bridge = _mock_pyhap_bridge()
with patch(f"{PATH_HOMEKIT}.get_accessory") as mock_get_acc: with patch(f"{PATH_HOMEKIT}.get_accessory") as mock_get_acc:
mock_get_acc.side_effect = [None, mock_acc, None] mock_get_acc.side_effect = [None, mock_acc, None]
state = State("light.demo", "on") state = State("light.demo", "on")
homekit.add_bridge_accessory(state) homekit.add_bridge_accessory(state)
mock_get_acc.assert_called_with(hass, ANY, ANY, 1403373688, {}) mock_get_acc.assert_called_with(hass, ANY, ANY, 1403373688, {})
assert not mock_bridge.add_accessory.called assert not homekit.bridge.add_accessory.called
state = State("demo.test", "on") state = State("demo.test", "on")
homekit.add_bridge_accessory(state) homekit.add_bridge_accessory(state)
mock_get_acc.assert_called_with(hass, ANY, ANY, 600325356, {}) mock_get_acc.assert_called_with(hass, ANY, ANY, 600325356, {})
assert mock_bridge.add_accessory.called assert homekit.bridge.add_accessory.called
state = State("demo.test_2", "on") state = State("demo.test_2", "on")
homekit.add_bridge_accessory(state) homekit.add_bridge_accessory(state)
mock_get_acc.assert_called_with(hass, ANY, ANY, 1467253281, {}) mock_get_acc.assert_called_with(hass, ANY, ANY, 1467253281, {})
assert mock_bridge.add_accessory.called assert homekit.bridge.add_accessory.called
@pytest.mark.parametrize("acc_category", [CATEGORY_TELEVISION, CATEGORY_CAMERA]) @pytest.mark.parametrize("acc_category", [CATEGORY_TELEVISION, CATEGORY_CAMERA])
@ -362,29 +372,27 @@ async def test_homekit_warn_add_accessory_bridge(
hass, acc_category, mock_zeroconf, caplog hass, acc_category, mock_zeroconf, caplog
): ):
"""Test we warn when adding cameras or tvs to a bridge.""" """Test we warn when adding cameras or tvs to a bridge."""
await async_setup_component(hass, "persistent_notification", {})
entry = MockConfigEntry( entry = MockConfigEntry(
domain=DOMAIN, data={CONF_NAME: "mock_name", CONF_PORT: 12345} domain=DOMAIN, data={CONF_NAME: "mock_name", CONF_PORT: 12345}
) )
entry.add_to_hass(hass) entry.add_to_hass(hass)
homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_BRIDGE) homekit = _mock_homekit_bridge(hass, entry)
homekit.driver = "driver"
homekit.bridge = mock_bridge = Mock()
homekit.bridge.accessories = range(10)
homekit.async_start = AsyncMock()
with patch(f"{PATH_HOMEKIT}.HomeKit", return_value=homekit): with patch(f"{PATH_HOMEKIT}.HomeKit", return_value=homekit):
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()
mock_camera_acc = Mock(category=acc_category) mock_camera_acc = Mock(category=acc_category)
homekit.bridge = _mock_pyhap_bridge()
with patch(f"{PATH_HOMEKIT}.get_accessory") as mock_get_acc: with patch(f"{PATH_HOMEKIT}.get_accessory") as mock_get_acc:
mock_get_acc.side_effect = [None, mock_camera_acc, None] mock_get_acc.side_effect = [None, mock_camera_acc, None]
state = State("camera.test", "on") state = State("camera.test", "on")
homekit.add_bridge_accessory(state) homekit.add_bridge_accessory(state)
mock_get_acc.assert_called_with(hass, ANY, ANY, 1508819236, {}) mock_get_acc.assert_called_with(hass, ANY, ANY, 1508819236, {})
assert not mock_bridge.add_accessory.called assert not homekit.bridge.add_accessory.called
assert "accessory mode" in caplog.text assert "accessory mode" in caplog.text
@ -396,12 +404,12 @@ async def test_homekit_remove_accessory(hass, mock_zeroconf):
homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_BRIDGE) homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_BRIDGE)
homekit.driver = "driver" homekit.driver = "driver"
homekit.bridge = mock_bridge = Mock() homekit.bridge = _mock_pyhap_bridge()
mock_bridge.accessories = {"light.demo": "acc"} homekit.bridge.accessories = {"light.demo": "acc"}
acc = homekit.remove_bridge_accessory("light.demo") acc = homekit.remove_bridge_accessory("light.demo")
assert acc == "acc" assert acc == "acc"
assert len(mock_bridge.accessories) == 0 assert len(homekit.bridge.accessories) == 0
async def test_homekit_entity_filter(hass, mock_zeroconf): async def test_homekit_entity_filter(hass, mock_zeroconf):
@ -413,20 +421,14 @@ async def test_homekit_entity_filter(hass, mock_zeroconf):
homekit.bridge = Mock() homekit.bridge = Mock()
homekit.bridge.accessories = {} homekit.bridge.accessories = {}
hass.states.async_set("cover.test", "open")
hass.states.async_set("demo.test", "on")
hass.states.async_set("light.demo", "on")
with patch(f"{PATH_HOMEKIT}.get_accessory") as mock_get_acc: filtered_states = await homekit.async_configure_accessories()
mock_get_acc.return_value = None assert hass.states.get("cover.test") in filtered_states
assert hass.states.get("demo.test") in filtered_states
homekit.add_bridge_accessory(State("cover.test", "open")) assert hass.states.get("light.demo") not in filtered_states
assert mock_get_acc.called is True
mock_get_acc.reset_mock()
homekit.add_bridge_accessory(State("demo.test", "on"))
assert mock_get_acc.called is True
mock_get_acc.reset_mock()
homekit.add_bridge_accessory(State("light.demo", "light"))
assert mock_get_acc.called is False
async def test_homekit_entity_glob_filter(hass, mock_zeroconf): async def test_homekit_entity_glob_filter(hass, mock_zeroconf):
@ -441,39 +443,29 @@ async def test_homekit_entity_glob_filter(hass, mock_zeroconf):
homekit.bridge = Mock() homekit.bridge = Mock()
homekit.bridge.accessories = {} homekit.bridge.accessories = {}
with patch(f"{PATH_HOMEKIT}.get_accessory") as mock_get_acc: hass.states.async_set("cover.test", "open")
mock_get_acc.return_value = None hass.states.async_set("demo.test", "on")
hass.states.async_set("cover.excluded_test", "open")
hass.states.async_set("light.included_test", "on")
homekit.add_bridge_accessory(State("cover.test", "open")) filtered_states = await homekit.async_configure_accessories()
assert mock_get_acc.called is True assert hass.states.get("cover.test") in filtered_states
mock_get_acc.reset_mock() assert hass.states.get("demo.test") in filtered_states
assert hass.states.get("cover.excluded_test") not in filtered_states
homekit.add_bridge_accessory(State("demo.test", "on")) assert hass.states.get("light.included_test") in filtered_states
assert mock_get_acc.called is True
mock_get_acc.reset_mock()
homekit.add_bridge_accessory(State("cover.excluded_test", "open"))
assert mock_get_acc.called is False
mock_get_acc.reset_mock()
homekit.add_bridge_accessory(State("light.included_test", "light"))
assert mock_get_acc.called is True
mock_get_acc.reset_mock()
async def test_homekit_start(hass, hk_driver, device_reg): async def test_homekit_start(hass, hk_driver, mock_zeroconf, device_reg):
"""Test HomeKit start method.""" """Test HomeKit start method."""
entry = await async_init_integration(hass) entry = await async_init_integration(hass)
pin = b"123-45-678"
homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_BRIDGE) homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_BRIDGE)
homekit.bridge = Mock() homekit.bridge = Mock()
homekit.bridge.accessories = [] homekit.bridge.accessories = []
homekit.driver = hk_driver homekit.driver = hk_driver
# pylint: disable=protected-access acc = Accessory(hk_driver, "any")
homekit._filter = Mock(return_value=True) homekit.driver.accessory = acc
homekit.driver.accessory = Accessory(hk_driver, "any")
connection = (device_registry.CONNECTION_NETWORK_MAC, "AA:BB:CC:DD:EE:FF") connection = (device_registry.CONNECTION_NETWORK_MAC, "AA:BB:CC:DD:EE:FF")
bridge_with_wrong_mac = device_reg.async_get_or_create( bridge_with_wrong_mac = device_reg.async_get_or_create(
@ -491,8 +483,6 @@ async def test_homekit_start(hass, hk_driver, device_reg):
with patch(f"{PATH_HOMEKIT}.HomeKit.add_bridge_accessory") as mock_add_acc, patch( with patch(f"{PATH_HOMEKIT}.HomeKit.add_bridge_accessory") as mock_add_acc, patch(
f"{PATH_HOMEKIT}.show_setup_message" f"{PATH_HOMEKIT}.show_setup_message"
) as mock_setup_msg, patch( ) as mock_setup_msg, patch(
"pyhap.accessory_driver.AccessoryDriver.add_accessory"
) as hk_driver_add_acc, patch(
"pyhap.accessory_driver.AccessoryDriver.async_start" "pyhap.accessory_driver.AccessoryDriver.async_start"
) as hk_driver_start: ) as hk_driver_start:
await homekit.async_start() await homekit.async_start()
@ -500,9 +490,8 @@ async def test_homekit_start(hass, hk_driver, device_reg):
await hass.async_block_till_done() await hass.async_block_till_done()
mock_add_acc.assert_any_call(state) mock_add_acc.assert_any_call(state)
mock_setup_msg.assert_called_with( mock_setup_msg.assert_called_with(
hass, entry.entry_id, "Mock Title (any)", pin, ANY hass, entry.entry_id, "Mock Title (Home Assistant Bridge)", ANY, ANY
) )
hk_driver_add_acc.assert_called_with(homekit.bridge)
assert hk_driver_start.called assert hk_driver_start.called
assert homekit.status == STATUS_RUNNING assert homekit.status == STATUS_RUNNING
@ -526,8 +515,6 @@ async def test_homekit_start(hass, hk_driver, device_reg):
with patch(f"{PATH_HOMEKIT}.HomeKit.add_bridge_accessory") as mock_add_acc, patch( with patch(f"{PATH_HOMEKIT}.HomeKit.add_bridge_accessory") as mock_add_acc, patch(
f"{PATH_HOMEKIT}.show_setup_message" f"{PATH_HOMEKIT}.show_setup_message"
) as mock_setup_msg, patch( ) as mock_setup_msg, patch(
"pyhap.accessory_driver.AccessoryDriver.add_accessory"
) as hk_driver_add_acc, patch(
"pyhap.accessory_driver.AccessoryDriver.async_start" "pyhap.accessory_driver.AccessoryDriver.async_start"
) as hk_driver_start: ) as hk_driver_start:
await homekit.async_start() await homekit.async_start()
@ -545,7 +532,6 @@ async def test_homekit_start(hass, hk_driver, device_reg):
async def test_homekit_start_with_a_broken_accessory(hass, hk_driver, mock_zeroconf): async def test_homekit_start_with_a_broken_accessory(hass, hk_driver, mock_zeroconf):
"""Test HomeKit start method.""" """Test HomeKit start method."""
pin = b"123-45-678"
entry = MockConfigEntry( entry = MockConfigEntry(
domain=DOMAIN, data={CONF_NAME: "mock_name", CONF_PORT: 12345} domain=DOMAIN, data={CONF_NAME: "mock_name", CONF_PORT: 12345}
) )
@ -565,17 +551,14 @@ async def test_homekit_start_with_a_broken_accessory(hass, hk_driver, mock_zeroc
with patch(f"{PATH_HOMEKIT}.get_accessory", side_effect=Exception), patch( with patch(f"{PATH_HOMEKIT}.get_accessory", side_effect=Exception), patch(
f"{PATH_HOMEKIT}.show_setup_message" f"{PATH_HOMEKIT}.show_setup_message"
) as mock_setup_msg, patch( ) as mock_setup_msg, patch(
"pyhap.accessory_driver.AccessoryDriver.add_accessory",
) as hk_driver_add_acc, patch(
"pyhap.accessory_driver.AccessoryDriver.async_start" "pyhap.accessory_driver.AccessoryDriver.async_start"
) as hk_driver_start: ) as hk_driver_start:
await homekit.async_start() await homekit.async_start()
await hass.async_block_till_done() await hass.async_block_till_done()
mock_setup_msg.assert_called_with( mock_setup_msg.assert_called_with(
hass, entry.entry_id, "Mock Title (any)", pin, ANY hass, entry.entry_id, "Mock Title (Home Assistant Bridge)", ANY, ANY
) )
hk_driver_add_acc.assert_called_with(homekit.bridge)
assert hk_driver_start.called assert hk_driver_start.called
assert homekit.status == STATUS_RUNNING assert homekit.status == STATUS_RUNNING
@ -616,27 +599,23 @@ async def test_homekit_stop(hass):
async def test_homekit_reset_accessories(hass, mock_zeroconf): async def test_homekit_reset_accessories(hass, mock_zeroconf):
"""Test adding too many accessories to HomeKit.""" """Test adding too many accessories to HomeKit."""
await async_setup_component(hass, "persistent_notification", {})
entry = MockConfigEntry( entry = MockConfigEntry(
domain=DOMAIN, data={CONF_NAME: "mock_name", CONF_PORT: 12345} domain=DOMAIN, data={CONF_NAME: "mock_name", CONF_PORT: 12345}
) )
entity_id = "light.demo" entity_id = "light.demo"
homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_BRIDGE) homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_BRIDGE)
homekit.bridge = Mock()
homekit.bridge.accessories = {}
with patch(f"{PATH_HOMEKIT}.HomeKit", return_value=homekit), patch( with patch(f"{PATH_HOMEKIT}.HomeKit", return_value=homekit), patch(
f"{PATH_HOMEKIT}.HomeKit.setup" "pyhap.accessory.Bridge.add_accessory"
), patch("pyhap.accessory.Bridge.add_accessory") as mock_add_accessory, patch( ) as mock_add_accessory, patch(
"pyhap.accessory_driver.AccessoryDriver.config_changed" "pyhap.accessory_driver.AccessoryDriver.config_changed"
) as hk_driver_config_changed, patch( ) as hk_driver_config_changed, patch(
"pyhap.accessory_driver.AccessoryDriver.async_start" "pyhap.accessory_driver.AccessoryDriver.async_start"
): ):
await async_init_entry(hass, entry) await async_init_entry(hass, entry)
aid = hass.data[DOMAIN][entry.entry_id][ aid = homekit.aid_storage.get_or_allocate_aid_for_entity_id(entity_id)
AID_STORAGE
].get_or_allocate_aid_for_entity_id(entity_id)
homekit.bridge.accessories = {aid: "acc"} homekit.bridge.accessories = {aid: "acc"}
homekit.status = STATUS_RUNNING homekit.status = STATUS_RUNNING
@ -675,10 +654,8 @@ async def test_homekit_too_many_accessories(hass, hk_driver, caplog, mock_zeroco
hass.states.async_set("light.demo3", "on") hass.states.async_set("light.demo3", "on")
with patch("pyhap.accessory_driver.AccessoryDriver.async_start"), patch( with patch("pyhap.accessory_driver.AccessoryDriver.async_start"), patch(
"pyhap.accessory_driver.AccessoryDriver.add_accessory" f"{PATH_HOMEKIT}.show_setup_message"
), patch(f"{PATH_HOMEKIT}.show_setup_message"), patch( ), patch(f"{PATH_HOMEKIT}.HomeBridge", _mock_bridge):
f"{PATH_HOMEKIT}.HomeBridge", _mock_bridge
):
await homekit.async_start() await homekit.async_start()
await hass.async_block_till_done() await hass.async_block_till_done()
assert "would exceed" in caplog.text assert "would exceed" in caplog.text
@ -693,9 +670,7 @@ async def test_homekit_finds_linked_batteries(
homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_BRIDGE) homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_BRIDGE)
homekit.driver = hk_driver homekit.driver = hk_driver
# pylint: disable=protected-access homekit.bridge = MagicMock()
homekit._filter = Mock(return_value=True)
homekit.bridge = HomeBridge(hass, hk_driver, "mock_bridge")
config_entry = MockConfigEntry(domain="test", data={}) config_entry = MockConfigEntry(domain="test", data={})
config_entry.add_to_hass(hass) config_entry.add_to_hass(hass)
@ -735,17 +710,15 @@ async def test_homekit_finds_linked_batteries(
) )
hass.states.async_set(light.entity_id, STATE_ON) hass.states.async_set(light.entity_id, STATE_ON)
with patch.object(homekit.bridge, "add_accessory"), patch( with patch(f"{PATH_HOMEKIT}.show_setup_message"), patch(
f"{PATH_HOMEKIT}.show_setup_message" f"{PATH_HOMEKIT}.get_accessory"
), patch(f"{PATH_HOMEKIT}.get_accessory") as mock_get_acc, patch( ) as mock_get_acc, patch("pyhap.accessory_driver.AccessoryDriver.async_start"):
"pyhap.accessory_driver.AccessoryDriver.async_start"
):
await homekit.async_start() await homekit.async_start()
await hass.async_block_till_done() await hass.async_block_till_done()
mock_get_acc.assert_called_with( mock_get_acc.assert_called_with(
hass, hass,
hk_driver, ANY,
ANY, ANY,
ANY, ANY,
{ {
@ -766,8 +739,6 @@ async def test_homekit_async_get_integration_fails(
homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_BRIDGE) homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_BRIDGE)
homekit.driver = hk_driver homekit.driver = hk_driver
# pylint: disable=protected-access
homekit._filter = Mock(return_value=True)
homekit.bridge = HomeBridge(hass, hk_driver, "mock_bridge") homekit.bridge = HomeBridge(hass, hk_driver, "mock_bridge")
config_entry = MockConfigEntry(domain="test", data={}) config_entry = MockConfigEntry(domain="test", data={})
@ -817,7 +788,7 @@ async def test_homekit_async_get_integration_fails(
mock_get_acc.assert_called_with( mock_get_acc.assert_called_with(
hass, hass,
hk_driver, ANY,
ANY, ANY,
ANY, ANY,
{ {
@ -832,6 +803,7 @@ async def test_homekit_async_get_integration_fails(
async def test_yaml_updates_update_config_entry_for_name(hass, mock_zeroconf): async def test_yaml_updates_update_config_entry_for_name(hass, mock_zeroconf):
"""Test async_setup with imported config.""" """Test async_setup with imported config."""
await async_setup_component(hass, "persistent_notification", {})
entry = MockConfigEntry( entry = MockConfigEntry(
domain=DOMAIN, domain=DOMAIN,
source=SOURCE_IMPORT, source=SOURCE_IMPORT,
@ -861,7 +833,6 @@ async def test_yaml_updates_update_config_entry_for_name(hass, mock_zeroconf):
entry.entry_id, entry.entry_id,
entry.title, entry.title,
) )
assert mock_homekit().setup.called is True
# Test auto start enabled # Test auto start enabled
mock_homekit.reset_mock() mock_homekit.reset_mock()
@ -871,20 +842,6 @@ async def test_yaml_updates_update_config_entry_for_name(hass, mock_zeroconf):
mock_homekit().async_start.assert_called() mock_homekit().async_start.assert_called()
async def test_raise_config_entry_not_ready(hass, mock_zeroconf):
"""Test async_setup when the port is not available."""
entry = MockConfigEntry(
domain=DOMAIN,
data={CONF_NAME: BRIDGE_NAME, CONF_PORT: DEFAULT_PORT},
options={},
)
entry.add_to_hass(hass)
with patch(f"{PATH_HOMEKIT}.HomeKit.setup", side_effect=OSError):
assert not await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
async def test_homekit_uses_system_zeroconf(hass, hk_driver, mock_zeroconf): async def test_homekit_uses_system_zeroconf(hass, hk_driver, mock_zeroconf):
"""Test HomeKit uses system zeroconf.""" """Test HomeKit uses system zeroconf."""
entry = MockConfigEntry( entry = MockConfigEntry(
@ -917,13 +874,12 @@ async def test_homekit_ignored_missing_devices(
hass, hk_driver, device_reg, entity_reg, mock_zeroconf hass, hk_driver, device_reg, entity_reg, mock_zeroconf
): ):
"""Test HomeKit handles a device in the entity registry but missing from the device registry.""" """Test HomeKit handles a device in the entity registry but missing from the device registry."""
await async_setup_component(hass, "persistent_notification", {})
entry = await async_init_integration(hass) entry = await async_init_integration(hass)
homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_BRIDGE) homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_BRIDGE)
homekit.driver = hk_driver homekit.driver = hk_driver
# pylint: disable=protected-access homekit.bridge = _mock_pyhap_bridge()
homekit._filter = Mock(return_value=True)
homekit.bridge = HomeBridge(hass, hk_driver, "mock_bridge")
config_entry = MockConfigEntry(domain="test", data={}) config_entry = MockConfigEntry(domain="test", data={})
config_entry.add_to_hass(hass) config_entry.add_to_hass(hass)
@ -952,25 +908,28 @@ async def test_homekit_ignored_missing_devices(
light = entity_reg.async_get_or_create( light = entity_reg.async_get_or_create(
"light", "powerwall", "demo", device_id=device_entry.id "light", "powerwall", "demo", device_id=device_entry.id
) )
before_removal = entity_reg.entities.copy()
# Delete the device to make sure we fallback # Delete the device to make sure we fallback
# to using the platform # to using the platform
device_reg.async_remove_device(device_entry.id) device_reg.async_remove_device(device_entry.id)
# Wait for the entities to be removed
await asyncio.sleep(0)
await asyncio.sleep(0)
# Restore the registry
entity_reg.entities = before_removal
hass.states.async_set(light.entity_id, STATE_ON) hass.states.async_set(light.entity_id, STATE_ON)
hass.states.async_set("light.two", STATE_ON) hass.states.async_set("light.two", STATE_ON)
with patch.object(homekit.bridge, "add_accessory"), patch( with patch(f"{PATH_HOMEKIT}.get_accessory") as mock_get_acc, patch(
f"{PATH_HOMEKIT}.show_setup_message" f"{PATH_HOMEKIT}.HomeBridge", return_value=homekit.bridge
), patch(f"{PATH_HOMEKIT}.get_accessory") as mock_get_acc, patch( ), patch("pyhap.accessory_driver.AccessoryDriver.async_start"):
"pyhap.accessory_driver.AccessoryDriver.async_start"
):
await homekit.async_start() await homekit.async_start()
await hass.async_block_till_done() await hass.async_block_till_done()
mock_get_acc.assert_any_call( mock_get_acc.assert_any_call(
hass, hass,
hk_driver, ANY,
ANY, ANY,
ANY, ANY,
{ {
@ -990,8 +949,6 @@ async def test_homekit_finds_linked_motion_sensors(
homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_BRIDGE) homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_BRIDGE)
homekit.driver = hk_driver homekit.driver = hk_driver
# pylint: disable=protected-access
homekit._filter = Mock(return_value=True)
homekit.bridge = HomeBridge(hass, hk_driver, "mock_bridge") homekit.bridge = HomeBridge(hass, hk_driver, "mock_bridge")
config_entry = MockConfigEntry(domain="test", data={}) config_entry = MockConfigEntry(domain="test", data={})
@ -1032,7 +989,7 @@ async def test_homekit_finds_linked_motion_sensors(
mock_get_acc.assert_called_with( mock_get_acc.assert_called_with(
hass, hass,
hk_driver, ANY,
ANY, ANY,
ANY, ANY,
{ {
@ -1053,7 +1010,6 @@ async def test_homekit_finds_linked_humidity_sensors(
homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_BRIDGE) homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_BRIDGE)
homekit.driver = hk_driver homekit.driver = hk_driver
homekit._filter = Mock(return_value=True)
homekit.bridge = HomeBridge(hass, hk_driver, "mock_bridge") homekit.bridge = HomeBridge(hass, hk_driver, "mock_bridge")
config_entry = MockConfigEntry(domain="test", data={}) config_entry = MockConfigEntry(domain="test", data={})
@ -1097,7 +1053,7 @@ async def test_homekit_finds_linked_humidity_sensors(
mock_get_acc.assert_called_with( mock_get_acc.assert_called_with(
hass, hass,
hk_driver, ANY,
ANY, ANY,
ANY, ANY,
{ {
@ -1111,6 +1067,7 @@ async def test_homekit_finds_linked_humidity_sensors(
async def test_reload(hass, mock_zeroconf): async def test_reload(hass, mock_zeroconf):
"""Test we can reload from yaml.""" """Test we can reload from yaml."""
await async_setup_component(hass, "persistent_notification", {})
entry = MockConfigEntry( entry = MockConfigEntry(
domain=DOMAIN, domain=DOMAIN,
source=SOURCE_IMPORT, source=SOURCE_IMPORT,
@ -1121,7 +1078,6 @@ async def test_reload(hass, mock_zeroconf):
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()
assert await async_setup_component( assert await async_setup_component(
hass, "homekit", {"homekit": {CONF_NAME: "reloadable", CONF_PORT: 12345}} hass, "homekit", {"homekit": {CONF_NAME: "reloadable", CONF_PORT: 12345}}
) )
@ -1140,7 +1096,6 @@ async def test_reload(hass, mock_zeroconf):
entry.entry_id, entry.entry_id,
entry.title, entry.title,
) )
assert mock_homekit().setup.called is True
yaml_path = os.path.join( yaml_path = os.path.join(
_get_fixtures_base_path(), _get_fixtures_base_path(),
"fixtures", "fixtures",
@ -1156,7 +1111,6 @@ async def test_reload(hass, mock_zeroconf):
"pyhap.accessory_driver.AccessoryDriver.async_start" "pyhap.accessory_driver.AccessoryDriver.async_start"
): ):
mock_homekit2.return_value = homekit = Mock() mock_homekit2.return_value = homekit = Mock()
type(homekit).async_start = AsyncMock()
await hass.services.async_call( await hass.services.async_call(
"homekit", "homekit",
SERVICE_RELOAD, SERVICE_RELOAD,
@ -1178,33 +1132,30 @@ async def test_reload(hass, mock_zeroconf):
entry.entry_id, entry.entry_id,
entry.title, entry.title,
) )
assert mock_homekit2().setup.called is True
def _get_fixtures_base_path(): def _get_fixtures_base_path():
return os.path.dirname(os.path.dirname(os.path.dirname(__file__))) return os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
async def test_homekit_start_in_accessory_mode(hass, hk_driver, device_reg): async def test_homekit_start_in_accessory_mode(
hass, hk_driver, mock_zeroconf, device_reg
):
"""Test HomeKit start method in accessory mode.""" """Test HomeKit start method in accessory mode."""
entry = await async_init_integration(hass) entry = await async_init_integration(hass)
pin = b"123-45-678"
homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_ACCESSORY) homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_ACCESSORY)
homekit.bridge = Mock() homekit.bridge = Mock()
homekit.bridge.accessories = [] homekit.bridge.accessories = []
homekit.driver = hk_driver homekit.driver = hk_driver
# pylint: disable=protected-access
homekit._filter = Mock(return_value=True)
homekit.driver.accessory = Accessory(hk_driver, "any") homekit.driver.accessory = Accessory(hk_driver, "any")
hass.states.async_set("light.demo", "on") hass.states.async_set("light.demo", "on")
with patch(f"{PATH_HOMEKIT}.HomeKit.add_bridge_accessory") as mock_add_acc, patch( with patch(f"{PATH_HOMEKIT}.HomeKit.add_bridge_accessory") as mock_add_acc, patch(
"pyhap.accessory_driver.AccessoryDriver.add_accessory" f"{PATH_HOMEKIT}.show_setup_message"
), patch(f"{PATH_HOMEKIT}.show_setup_message") as mock_setup_msg, patch( ) as mock_setup_msg, patch(
"pyhap.accessory_driver.AccessoryDriver.async_start" "pyhap.accessory_driver.AccessoryDriver.async_start"
) as hk_driver_start: ) as hk_driver_start:
await homekit.async_start() await homekit.async_start()
@ -1212,7 +1163,7 @@ async def test_homekit_start_in_accessory_mode(hass, hk_driver, device_reg):
await hass.async_block_till_done() await hass.async_block_till_done()
mock_add_acc.assert_not_called() mock_add_acc.assert_not_called()
mock_setup_msg.assert_called_with( mock_setup_msg.assert_called_with(
hass, entry.entry_id, "Mock Title (any)", pin, ANY hass, entry.entry_id, "Mock Title (demo)", ANY, ANY
) )
assert hk_driver_start.called assert hk_driver_start.called
assert homekit.status == STATUS_RUNNING assert homekit.status == STATUS_RUNNING

View File

@ -294,5 +294,7 @@ async def test_accessory_friendly_name():
accessory = Mock() accessory = Mock()
accessory.display_name = "same" accessory.display_name = "same"
assert accessory_friendly_name("same", accessory) == "same" assert accessory_friendly_name("Same", accessory) == "Same"
assert accessory_friendly_name("hass title", accessory) == "hass title (same)" assert accessory_friendly_name("hass title", accessory) == "hass title (same)"
accessory.display_name = "Hass title 123"
assert accessory_friendly_name("hass title", accessory) == "Hass title 123"