2018-02-25 09:58:13 +00:00
|
|
|
"""Tests for the HomeKit component."""
|
2021-03-18 14:13:22 +00:00
|
|
|
from __future__ import annotations
|
|
|
|
|
2021-03-12 06:05:03 +00:00
|
|
|
import asyncio
|
2020-05-01 04:05:06 +00:00
|
|
|
import os
|
2021-01-01 21:31:56 +00:00
|
|
|
from unittest.mock import ANY, AsyncMock, MagicMock, Mock, patch
|
2018-05-10 23:21:59 +00:00
|
|
|
|
2020-10-15 16:59:50 +00:00
|
|
|
from pyhap.accessory import Accessory
|
2021-01-10 19:38:41 +00:00
|
|
|
from pyhap.const import CATEGORY_CAMERA, CATEGORY_TELEVISION
|
2018-05-10 23:21:59 +00:00
|
|
|
import pytest
|
2018-03-01 23:20:02 +00:00
|
|
|
|
2020-08-28 14:46:45 +00:00
|
|
|
from homeassistant import config as hass_config
|
2021-03-15 04:14:46 +00:00
|
|
|
from homeassistant.components import homekit as homekit_base, zeroconf
|
2021-12-20 18:53:44 +00:00
|
|
|
from homeassistant.components.binary_sensor import BinarySensorDeviceClass
|
2018-05-04 14:46:00 +00:00
|
|
|
from homeassistant.components.homekit import (
|
2019-07-31 19:25:30 +00:00
|
|
|
MAX_DEVICES,
|
|
|
|
STATUS_READY,
|
|
|
|
STATUS_RUNNING,
|
|
|
|
STATUS_STOPPED,
|
|
|
|
STATUS_WAIT,
|
2019-12-08 17:16:49 +00:00
|
|
|
HomeKit,
|
2019-07-31 19:25:30 +00:00
|
|
|
)
|
2018-03-15 01:48:21 +00:00
|
|
|
from homeassistant.components.homekit.accessories import HomeBridge
|
|
|
|
from homeassistant.components.homekit.const import (
|
2019-12-08 17:16:49 +00:00
|
|
|
BRIDGE_NAME,
|
2020-05-25 16:17:30 +00:00
|
|
|
BRIDGE_SERIAL_NUMBER,
|
2019-07-31 19:25:30 +00:00
|
|
|
DEFAULT_PORT,
|
|
|
|
DOMAIN,
|
2020-06-02 22:47:39 +00:00
|
|
|
HOMEKIT,
|
2020-10-15 16:59:50 +00:00
|
|
|
HOMEKIT_MODE_ACCESSORY,
|
|
|
|
HOMEKIT_MODE_BRIDGE,
|
2019-07-31 19:25:30 +00:00
|
|
|
SERVICE_HOMEKIT_RESET_ACCESSORY,
|
2021-07-22 10:44:36 +00:00
|
|
|
SERVICE_HOMEKIT_UNPAIR,
|
2019-07-31 19:25:30 +00:00
|
|
|
)
|
2021-08-25 14:47:39 +00:00
|
|
|
from homeassistant.components.homekit.type_triggers import DeviceTriggerAccessory
|
2021-02-16 07:37:43 +00:00
|
|
|
from homeassistant.components.homekit.util import get_persist_fullpath_for_entry_id
|
2021-12-20 18:53:44 +00:00
|
|
|
from homeassistant.components.sensor import SensorDeviceClass
|
2020-05-01 04:05:06 +00:00
|
|
|
from homeassistant.config_entries import SOURCE_IMPORT
|
2018-02-19 22:46:22 +00:00
|
|
|
from homeassistant.const import (
|
2020-04-22 00:43:49 +00:00
|
|
|
ATTR_DEVICE_CLASS,
|
2021-07-22 10:44:36 +00:00
|
|
|
ATTR_DEVICE_ID,
|
2019-07-31 19:25:30 +00:00
|
|
|
ATTR_ENTITY_ID,
|
2020-07-02 17:53:11 +00:00
|
|
|
ATTR_UNIT_OF_MEASUREMENT,
|
2019-12-08 17:16:49 +00:00
|
|
|
CONF_NAME,
|
2019-07-31 19:25:30 +00:00
|
|
|
CONF_PORT,
|
2021-02-12 18:45:19 +00:00
|
|
|
EVENT_HOMEASSISTANT_STARTED,
|
2020-09-05 19:09:14 +00:00
|
|
|
PERCENTAGE,
|
2020-08-28 14:46:45 +00:00
|
|
|
SERVICE_RELOAD,
|
2020-04-22 00:43:49 +00:00
|
|
|
STATE_ON,
|
2019-07-31 19:25:30 +00:00
|
|
|
)
|
2021-07-22 10:44:36 +00:00
|
|
|
from homeassistant.core import HomeAssistantError, State
|
2022-03-23 09:32:51 +00:00
|
|
|
from homeassistant.helpers import device_registry, entity_registry as er
|
2021-06-13 22:27:04 +00:00
|
|
|
from homeassistant.helpers.entityfilter import (
|
|
|
|
CONF_EXCLUDE_DOMAINS,
|
|
|
|
CONF_EXCLUDE_ENTITIES,
|
|
|
|
CONF_EXCLUDE_ENTITY_GLOBS,
|
|
|
|
CONF_INCLUDE_DOMAINS,
|
|
|
|
CONF_INCLUDE_ENTITIES,
|
|
|
|
CONF_INCLUDE_ENTITY_GLOBS,
|
|
|
|
convert_filter,
|
|
|
|
)
|
2020-05-01 04:05:06 +00:00
|
|
|
from homeassistant.setup import async_setup_component
|
|
|
|
from homeassistant.util import json as json_util
|
|
|
|
|
|
|
|
from .util import PATH_HOMEKIT, async_init_entry, async_init_integration
|
2018-02-19 22:46:22 +00:00
|
|
|
|
2021-11-02 03:47:05 +00:00
|
|
|
from tests.common import MockConfigEntry, get_fixture_path
|
2018-02-19 22:46:22 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
IP_ADDRESS = "127.0.0.1"
|
2018-02-19 22:46:22 +00:00
|
|
|
|
|
|
|
|
2021-06-13 22:27:04 +00:00
|
|
|
def generate_filter(
|
|
|
|
include_domains,
|
|
|
|
include_entities,
|
|
|
|
exclude_domains,
|
|
|
|
exclude_entites,
|
|
|
|
include_globs=None,
|
|
|
|
exclude_globs=None,
|
|
|
|
):
|
|
|
|
"""Generate an entity filter using the standard method."""
|
|
|
|
return convert_filter(
|
|
|
|
{
|
|
|
|
CONF_INCLUDE_DOMAINS: include_domains,
|
|
|
|
CONF_INCLUDE_ENTITIES: include_entities,
|
|
|
|
CONF_EXCLUDE_DOMAINS: exclude_domains,
|
|
|
|
CONF_EXCLUDE_ENTITIES: exclude_entites,
|
|
|
|
CONF_INCLUDE_ENTITY_GLOBS: include_globs or [],
|
|
|
|
CONF_EXCLUDE_ENTITY_GLOBS: exclude_globs or [],
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2020-07-06 22:58:53 +00:00
|
|
|
@pytest.fixture(autouse=True)
|
|
|
|
def always_patch_driver(hk_driver):
|
|
|
|
"""Load the hk_driver fixture."""
|
|
|
|
|
|
|
|
|
2021-09-02 18:44:50 +00:00
|
|
|
@pytest.fixture(autouse=True)
|
|
|
|
def patch_source_ip(mock_get_source_ip):
|
|
|
|
"""Patch homeassistant and pyhap functions for getting local address."""
|
|
|
|
with patch("pyhap.util.get_local_address", return_value="10.10.10.10"):
|
|
|
|
yield
|
|
|
|
|
|
|
|
|
2021-08-25 14:47:39 +00:00
|
|
|
def _mock_homekit(hass, entry, homekit_mode, entity_filter=None, devices=None):
|
2021-02-24 00:22:23 +00:00
|
|
|
return HomeKit(
|
|
|
|
hass=hass,
|
|
|
|
name=BRIDGE_NAME,
|
|
|
|
port=DEFAULT_PORT,
|
|
|
|
ip_address=None,
|
|
|
|
entity_filter=entity_filter or generate_filter([], [], [], []),
|
|
|
|
exclude_accessory_mode=False,
|
|
|
|
entity_config={},
|
|
|
|
homekit_mode=homekit_mode,
|
|
|
|
advertise_ip=None,
|
|
|
|
entry_id=entry.entry_id,
|
|
|
|
entry_title=entry.title,
|
2021-08-25 14:47:39 +00:00
|
|
|
devices=devices,
|
2021-02-24 00:22:23 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
2021-03-12 06:05:03 +00:00
|
|
|
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"
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2021-11-19 04:23:20 +00:00
|
|
|
async def test_setup_min(hass, mock_async_zeroconf):
|
2018-05-10 23:21:59 +00:00
|
|
|
"""Test async_setup with min config options."""
|
2021-10-07 10:58:00 +00:00
|
|
|
|
2020-05-01 04:05:06 +00:00
|
|
|
entry = MockConfigEntry(
|
|
|
|
domain=DOMAIN,
|
|
|
|
data={CONF_NAME: BRIDGE_NAME, CONF_PORT: DEFAULT_PORT},
|
|
|
|
options={},
|
|
|
|
)
|
|
|
|
entry.add_to_hass(hass)
|
|
|
|
|
2021-07-14 09:44:58 +00:00
|
|
|
with patch(f"{PATH_HOMEKIT}.HomeKit") as mock_homekit, patch(
|
|
|
|
"homeassistant.components.network.async_get_source_ip", return_value="1.2.3.4"
|
|
|
|
):
|
2020-05-01 04:05:06 +00:00
|
|
|
mock_homekit.return_value = homekit = Mock()
|
|
|
|
type(homekit).async_start = AsyncMock()
|
|
|
|
assert await hass.config_entries.async_setup(entry.entry_id)
|
|
|
|
await hass.async_block_till_done()
|
2018-03-01 23:20:02 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
mock_homekit.assert_any_call(
|
2020-05-01 04:05:06 +00:00
|
|
|
hass,
|
|
|
|
BRIDGE_NAME,
|
|
|
|
DEFAULT_PORT,
|
2021-07-14 09:44:58 +00:00
|
|
|
"1.2.3.4",
|
2020-05-01 04:05:06 +00:00
|
|
|
ANY,
|
2021-02-24 00:22:23 +00:00
|
|
|
ANY,
|
2020-05-01 04:05:06 +00:00
|
|
|
{},
|
2020-10-15 16:59:50 +00:00
|
|
|
HOMEKIT_MODE_BRIDGE,
|
2020-05-01 04:05:06 +00:00
|
|
|
None,
|
|
|
|
entry.entry_id,
|
2021-02-24 00:22:23 +00:00
|
|
|
entry.title,
|
2021-08-25 14:47:39 +00:00
|
|
|
devices=[],
|
2019-07-31 19:25:30 +00:00
|
|
|
)
|
2018-02-19 22:46:22 +00:00
|
|
|
|
2018-05-10 23:21:59 +00:00
|
|
|
# Test auto start enabled
|
2021-02-12 18:45:19 +00:00
|
|
|
hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
|
2018-05-10 23:21:59 +00:00
|
|
|
await hass.async_block_till_done()
|
2021-03-12 06:05:03 +00:00
|
|
|
assert mock_homekit().async_start.called is True
|
2018-02-19 22:46:22 +00:00
|
|
|
|
|
|
|
|
2021-11-19 04:23:20 +00:00
|
|
|
async def test_homekit_setup(hass, hk_driver, mock_async_zeroconf):
|
2018-05-10 23:21:59 +00:00
|
|
|
"""Test setup of bridge and driver."""
|
2020-05-01 04:05:06 +00:00
|
|
|
entry = MockConfigEntry(
|
|
|
|
domain=DOMAIN,
|
|
|
|
data={CONF_NAME: "mock_name", CONF_PORT: 12345},
|
|
|
|
source=SOURCE_IMPORT,
|
|
|
|
)
|
|
|
|
homekit = HomeKit(
|
|
|
|
hass,
|
|
|
|
BRIDGE_NAME,
|
|
|
|
DEFAULT_PORT,
|
2021-07-14 09:44:58 +00:00
|
|
|
IP_ADDRESS,
|
2021-02-24 00:22:23 +00:00
|
|
|
True,
|
2020-05-01 04:05:06 +00:00
|
|
|
{},
|
|
|
|
{},
|
2020-10-15 16:59:50 +00:00
|
|
|
HOMEKIT_MODE_BRIDGE,
|
2020-05-01 04:05:06 +00:00
|
|
|
advertise_ip=None,
|
|
|
|
entry_id=entry.entry_id,
|
2021-02-24 00:22:23 +00:00
|
|
|
entry_title=entry.title,
|
2020-05-01 04:05:06 +00:00
|
|
|
)
|
2018-05-10 23:21:59 +00:00
|
|
|
|
2020-10-15 16:59:50 +00:00
|
|
|
hass.states.async_set("light.demo", "on")
|
|
|
|
hass.states.async_set("light.demo2", "on")
|
2020-06-02 22:47:39 +00:00
|
|
|
zeroconf_mock = MagicMock()
|
2021-09-12 02:00:26 +00:00
|
|
|
uuid = await hass.helpers.instance_id.async_get()
|
2021-07-14 09:44:58 +00:00
|
|
|
with patch(f"{PATH_HOMEKIT}.HomeDriver", return_value=hk_driver) as mock_driver:
|
2021-09-12 02:00:26 +00:00
|
|
|
await hass.async_add_executor_job(homekit.setup, zeroconf_mock, uuid)
|
2018-05-10 23:21:59 +00:00
|
|
|
|
2020-05-01 04:05:06 +00:00
|
|
|
path = get_persist_fullpath_for_entry_id(hass, entry.entry_id)
|
2018-05-10 23:21:59 +00:00
|
|
|
mock_driver.assert_called_with(
|
2019-10-23 05:06:21 +00:00
|
|
|
hass,
|
2020-05-01 04:05:06 +00:00
|
|
|
entry.entry_id,
|
|
|
|
BRIDGE_NAME,
|
2021-02-24 00:22:23 +00:00
|
|
|
entry.title,
|
2020-07-05 17:27:07 +00:00
|
|
|
loop=hass.loop,
|
2019-10-23 05:06:21 +00:00
|
|
|
address=IP_ADDRESS,
|
|
|
|
port=DEFAULT_PORT,
|
|
|
|
persist_file=path,
|
|
|
|
advertised_address=None,
|
2021-05-31 18:47:12 +00:00
|
|
|
async_zeroconf_instance=zeroconf_mock,
|
2021-09-12 02:00:26 +00:00
|
|
|
zeroconf_server=f"{uuid}-hap.local.",
|
2022-04-21 20:54:44 +00:00
|
|
|
loader=ANY,
|
2019-07-31 19:25:30 +00:00
|
|
|
)
|
2018-11-16 10:08:39 +00:00
|
|
|
assert homekit.driver.safe_mode is False
|
2018-05-10 23:21:59 +00:00
|
|
|
|
|
|
|
|
2021-11-19 04:23:20 +00:00
|
|
|
async def test_homekit_setup_ip_address(hass, hk_driver, mock_async_zeroconf):
|
2018-05-10 23:21:59 +00:00
|
|
|
"""Test setup with given IP address."""
|
2020-05-01 04:05:06 +00:00
|
|
|
entry = MockConfigEntry(
|
|
|
|
domain=DOMAIN,
|
|
|
|
data={CONF_NAME: "mock_name", CONF_PORT: 12345},
|
|
|
|
source=SOURCE_IMPORT,
|
|
|
|
)
|
|
|
|
homekit = HomeKit(
|
|
|
|
hass,
|
|
|
|
BRIDGE_NAME,
|
|
|
|
DEFAULT_PORT,
|
|
|
|
"172.0.0.0",
|
2021-02-24 00:22:23 +00:00
|
|
|
True,
|
2020-05-01 04:05:06 +00:00
|
|
|
{},
|
|
|
|
{},
|
2020-10-15 16:59:50 +00:00
|
|
|
HOMEKIT_MODE_BRIDGE,
|
2020-05-01 04:05:06 +00:00
|
|
|
None,
|
|
|
|
entry_id=entry.entry_id,
|
2021-02-24 00:22:23 +00:00
|
|
|
entry_title=entry.title,
|
2020-05-01 04:05:06 +00:00
|
|
|
)
|
2018-05-10 23:21:59 +00:00
|
|
|
|
2020-05-01 04:05:06 +00:00
|
|
|
path = get_persist_fullpath_for_entry_id(hass, entry.entry_id)
|
2021-09-12 02:00:26 +00:00
|
|
|
uuid = await hass.helpers.instance_id.async_get()
|
2021-01-31 21:36:19 +00:00
|
|
|
with patch(f"{PATH_HOMEKIT}.HomeDriver", return_value=hk_driver) as mock_driver:
|
2021-11-19 04:23:20 +00:00
|
|
|
await hass.async_add_executor_job(homekit.setup, mock_async_zeroconf, uuid)
|
2018-05-18 14:32:57 +00:00
|
|
|
mock_driver.assert_called_with(
|
2019-10-23 05:06:21 +00:00
|
|
|
hass,
|
2020-05-01 04:05:06 +00:00
|
|
|
entry.entry_id,
|
|
|
|
BRIDGE_NAME,
|
2021-02-24 00:22:23 +00:00
|
|
|
entry.title,
|
2020-07-05 17:27:07 +00:00
|
|
|
loop=hass.loop,
|
2019-10-23 05:06:21 +00:00
|
|
|
address="172.0.0.0",
|
|
|
|
port=DEFAULT_PORT,
|
2020-05-01 04:05:06 +00:00
|
|
|
persist_file=path,
|
2019-10-23 05:06:21 +00:00
|
|
|
advertised_address=None,
|
2021-11-19 04:23:20 +00:00
|
|
|
async_zeroconf_instance=mock_async_zeroconf,
|
2021-09-12 02:00:26 +00:00
|
|
|
zeroconf_server=f"{uuid}-hap.local.",
|
2022-04-21 20:54:44 +00:00
|
|
|
loader=ANY,
|
2019-10-23 05:06:21 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
2021-11-19 04:23:20 +00:00
|
|
|
async def test_homekit_setup_advertise_ip(hass, hk_driver, mock_async_zeroconf):
|
2019-10-23 05:06:21 +00:00
|
|
|
"""Test setup with given IP address to advertise."""
|
2020-05-01 04:05:06 +00:00
|
|
|
entry = MockConfigEntry(
|
|
|
|
domain=DOMAIN,
|
|
|
|
data={CONF_NAME: "mock_name", CONF_PORT: 12345},
|
|
|
|
source=SOURCE_IMPORT,
|
|
|
|
)
|
2019-10-23 05:06:21 +00:00
|
|
|
homekit = HomeKit(
|
2020-05-01 04:05:06 +00:00
|
|
|
hass,
|
|
|
|
BRIDGE_NAME,
|
|
|
|
DEFAULT_PORT,
|
|
|
|
"0.0.0.0",
|
2021-02-24 00:22:23 +00:00
|
|
|
True,
|
2020-05-01 04:05:06 +00:00
|
|
|
{},
|
|
|
|
{},
|
2020-10-15 16:59:50 +00:00
|
|
|
HOMEKIT_MODE_BRIDGE,
|
2020-05-01 04:05:06 +00:00
|
|
|
"192.168.1.100",
|
|
|
|
entry_id=entry.entry_id,
|
2021-02-24 00:22:23 +00:00
|
|
|
entry_title=entry.title,
|
2019-10-23 05:06:21 +00:00
|
|
|
)
|
|
|
|
|
2021-05-31 18:47:12 +00:00
|
|
|
async_zeroconf_instance = MagicMock()
|
2020-05-01 04:05:06 +00:00
|
|
|
path = get_persist_fullpath_for_entry_id(hass, entry.entry_id)
|
2021-09-12 02:00:26 +00:00
|
|
|
uuid = await hass.helpers.instance_id.async_get()
|
2021-01-31 21:36:19 +00:00
|
|
|
with patch(f"{PATH_HOMEKIT}.HomeDriver", return_value=hk_driver) as mock_driver:
|
2021-09-12 02:00:26 +00:00
|
|
|
await hass.async_add_executor_job(homekit.setup, async_zeroconf_instance, uuid)
|
2019-10-23 05:06:21 +00:00
|
|
|
mock_driver.assert_called_with(
|
|
|
|
hass,
|
2020-05-01 04:05:06 +00:00
|
|
|
entry.entry_id,
|
|
|
|
BRIDGE_NAME,
|
2021-02-24 00:22:23 +00:00
|
|
|
entry.title,
|
2020-07-05 17:27:07 +00:00
|
|
|
loop=hass.loop,
|
2019-10-23 05:06:21 +00:00
|
|
|
address="0.0.0.0",
|
|
|
|
port=DEFAULT_PORT,
|
2020-05-01 04:05:06 +00:00
|
|
|
persist_file=path,
|
2019-10-23 05:06:21 +00:00
|
|
|
advertised_address="192.168.1.100",
|
2021-05-31 18:47:12 +00:00
|
|
|
async_zeroconf_instance=async_zeroconf_instance,
|
2021-09-12 02:00:26 +00:00
|
|
|
zeroconf_server=f"{uuid}-hap.local.",
|
2022-04-21 20:54:44 +00:00
|
|
|
loader=ANY,
|
2019-07-31 19:25:30 +00:00
|
|
|
)
|
2018-05-10 23:21:59 +00:00
|
|
|
|
|
|
|
|
2021-11-19 04:23:20 +00:00
|
|
|
async def test_homekit_add_accessory(hass, mock_async_zeroconf):
|
2018-05-10 23:21:59 +00:00
|
|
|
"""Add accessory if config exists and get_acc returns an accessory."""
|
2021-10-07 10:58:00 +00:00
|
|
|
|
2021-02-24 00:22:23 +00:00
|
|
|
entry = MockConfigEntry(
|
|
|
|
domain=DOMAIN, data={CONF_NAME: "mock_name", CONF_PORT: 12345}
|
2020-05-01 04:05:06 +00:00
|
|
|
)
|
2021-02-24 00:22:23 +00:00
|
|
|
entry.add_to_hass(hass)
|
|
|
|
|
2021-03-12 06:05:03 +00:00
|
|
|
homekit = _mock_homekit_bridge(hass, entry)
|
|
|
|
mock_acc = Mock(category="any")
|
2018-05-10 23:21:59 +00:00
|
|
|
|
2021-02-24 00:22:23 +00:00
|
|
|
with patch(f"{PATH_HOMEKIT}.HomeKit", return_value=homekit):
|
|
|
|
assert await hass.config_entries.async_setup(entry.entry_id)
|
|
|
|
await hass.async_block_till_done()
|
2021-01-10 19:38:41 +00:00
|
|
|
|
2021-03-12 06:05:03 +00:00
|
|
|
homekit.bridge = _mock_pyhap_bridge()
|
2018-05-10 23:21:59 +00:00
|
|
|
|
2020-04-19 18:51:09 +00:00
|
|
|
with patch(f"{PATH_HOMEKIT}.get_accessory") as mock_get_acc:
|
2021-01-10 19:38:41 +00:00
|
|
|
mock_get_acc.side_effect = [None, mock_acc, None]
|
2021-02-24 00:22:23 +00:00
|
|
|
state = State("light.demo", "on")
|
|
|
|
homekit.add_bridge_accessory(state)
|
|
|
|
mock_get_acc.assert_called_with(hass, ANY, ANY, 1403373688, {})
|
2021-03-12 06:05:03 +00:00
|
|
|
assert not homekit.bridge.add_accessory.called
|
2018-05-10 23:21:59 +00:00
|
|
|
|
2021-02-24 00:22:23 +00:00
|
|
|
state = State("demo.test", "on")
|
|
|
|
homekit.add_bridge_accessory(state)
|
|
|
|
mock_get_acc.assert_called_with(hass, ANY, ANY, 600325356, {})
|
2021-03-12 06:05:03 +00:00
|
|
|
assert homekit.bridge.add_accessory.called
|
2018-05-10 23:21:59 +00:00
|
|
|
|
2021-02-24 00:22:23 +00:00
|
|
|
state = State("demo.test_2", "on")
|
|
|
|
homekit.add_bridge_accessory(state)
|
|
|
|
mock_get_acc.assert_called_with(hass, ANY, ANY, 1467253281, {})
|
2021-03-12 06:05:03 +00:00
|
|
|
assert homekit.bridge.add_accessory.called
|
2021-01-10 19:38:41 +00:00
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize("acc_category", [CATEGORY_TELEVISION, CATEGORY_CAMERA])
|
|
|
|
async def test_homekit_warn_add_accessory_bridge(
|
2021-11-19 04:23:20 +00:00
|
|
|
hass, acc_category, mock_async_zeroconf, caplog
|
2021-01-10 19:38:41 +00:00
|
|
|
):
|
|
|
|
"""Test we warn when adding cameras or tvs to a bridge."""
|
2021-10-07 10:58:00 +00:00
|
|
|
|
2021-02-24 00:22:23 +00:00
|
|
|
entry = MockConfigEntry(
|
|
|
|
domain=DOMAIN, data={CONF_NAME: "mock_name", CONF_PORT: 12345}
|
2021-01-10 19:38:41 +00:00
|
|
|
)
|
2021-02-24 00:22:23 +00:00
|
|
|
entry.add_to_hass(hass)
|
|
|
|
|
2021-03-12 06:05:03 +00:00
|
|
|
homekit = _mock_homekit_bridge(hass, entry)
|
2021-01-10 19:38:41 +00:00
|
|
|
|
2021-02-24 00:22:23 +00:00
|
|
|
with patch(f"{PATH_HOMEKIT}.HomeKit", return_value=homekit):
|
|
|
|
assert await hass.config_entries.async_setup(entry.entry_id)
|
|
|
|
await hass.async_block_till_done()
|
2021-01-10 19:38:41 +00:00
|
|
|
|
2021-02-24 00:22:23 +00:00
|
|
|
mock_camera_acc = Mock(category=acc_category)
|
2021-03-12 06:05:03 +00:00
|
|
|
homekit.bridge = _mock_pyhap_bridge()
|
2021-01-10 19:38:41 +00:00
|
|
|
|
|
|
|
with patch(f"{PATH_HOMEKIT}.get_accessory") as mock_get_acc:
|
|
|
|
mock_get_acc.side_effect = [None, mock_camera_acc, None]
|
2021-02-24 00:22:23 +00:00
|
|
|
state = State("camera.test", "on")
|
|
|
|
homekit.add_bridge_accessory(state)
|
|
|
|
mock_get_acc.assert_called_with(hass, ANY, ANY, 1508819236, {})
|
2021-03-12 06:05:03 +00:00
|
|
|
assert not homekit.bridge.add_accessory.called
|
2021-01-10 19:38:41 +00:00
|
|
|
|
|
|
|
assert "accessory mode" in caplog.text
|
2018-05-10 23:21:59 +00:00
|
|
|
|
|
|
|
|
2021-11-19 04:23:20 +00:00
|
|
|
async def test_homekit_remove_accessory(hass, mock_async_zeroconf):
|
2019-07-16 01:43:37 +00:00
|
|
|
"""Remove accessory from bridge."""
|
2020-05-01 04:05:06 +00:00
|
|
|
entry = await async_init_integration(hass)
|
|
|
|
|
2021-02-24 00:22:23 +00:00
|
|
|
homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_BRIDGE)
|
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
homekit.driver = "driver"
|
2021-03-12 06:05:03 +00:00
|
|
|
homekit.bridge = _mock_pyhap_bridge()
|
2021-07-21 04:45:21 +00:00
|
|
|
acc_mock = MagicMock()
|
2021-09-12 22:06:03 +00:00
|
|
|
acc_mock.stop = AsyncMock()
|
2021-07-21 04:45:21 +00:00
|
|
|
homekit.bridge.accessories = {6: acc_mock}
|
2019-07-16 01:43:37 +00:00
|
|
|
|
2021-09-12 22:06:03 +00:00
|
|
|
acc = await homekit.async_remove_bridge_accessory(6)
|
2021-07-21 04:45:21 +00:00
|
|
|
assert acc is acc_mock
|
2021-09-12 22:06:03 +00:00
|
|
|
assert acc_mock.stop.called
|
2021-03-12 06:05:03 +00:00
|
|
|
assert len(homekit.bridge.accessories) == 0
|
2019-07-16 01:43:37 +00:00
|
|
|
|
|
|
|
|
2021-11-19 04:23:20 +00:00
|
|
|
async def test_homekit_entity_filter(hass, mock_async_zeroconf):
|
2018-05-10 23:21:59 +00:00
|
|
|
"""Test the entity filter."""
|
2020-05-01 04:05:06 +00:00
|
|
|
entry = await async_init_integration(hass)
|
2020-04-19 18:51:09 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
entity_filter = generate_filter(["cover"], ["demo.test"], [], [])
|
2021-02-24 00:22:23 +00:00
|
|
|
homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_BRIDGE, entity_filter)
|
|
|
|
|
2020-04-19 18:51:09 +00:00
|
|
|
homekit.bridge = Mock()
|
|
|
|
homekit.bridge.accessories = {}
|
2021-03-12 06:05:03 +00:00
|
|
|
hass.states.async_set("cover.test", "open")
|
|
|
|
hass.states.async_set("demo.test", "on")
|
|
|
|
hass.states.async_set("light.demo", "on")
|
2018-05-10 23:21:59 +00:00
|
|
|
|
2021-03-12 06:05:03 +00:00
|
|
|
filtered_states = await homekit.async_configure_accessories()
|
|
|
|
assert hass.states.get("cover.test") in filtered_states
|
|
|
|
assert hass.states.get("demo.test") in filtered_states
|
|
|
|
assert hass.states.get("light.demo") not in filtered_states
|
2018-05-10 23:21:59 +00:00
|
|
|
|
|
|
|
|
2021-11-19 04:23:20 +00:00
|
|
|
async def test_homekit_entity_glob_filter(hass, mock_async_zeroconf):
|
2020-06-24 01:02:29 +00:00
|
|
|
"""Test the entity filter."""
|
|
|
|
entry = await async_init_integration(hass)
|
|
|
|
|
|
|
|
entity_filter = generate_filter(
|
|
|
|
["cover"], ["demo.test"], [], [], ["*.included_*"], ["*.excluded_*"]
|
|
|
|
)
|
2021-02-24 00:22:23 +00:00
|
|
|
homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_BRIDGE, entity_filter)
|
|
|
|
|
2020-06-24 01:02:29 +00:00
|
|
|
homekit.bridge = Mock()
|
|
|
|
homekit.bridge.accessories = {}
|
|
|
|
|
2021-03-12 06:05:03 +00:00
|
|
|
hass.states.async_set("cover.test", "open")
|
|
|
|
hass.states.async_set("demo.test", "on")
|
|
|
|
hass.states.async_set("cover.excluded_test", "open")
|
|
|
|
hass.states.async_set("light.included_test", "on")
|
2020-06-24 01:02:29 +00:00
|
|
|
|
2021-03-12 06:05:03 +00:00
|
|
|
filtered_states = await homekit.async_configure_accessories()
|
|
|
|
assert hass.states.get("cover.test") in filtered_states
|
|
|
|
assert hass.states.get("demo.test") in filtered_states
|
|
|
|
assert hass.states.get("cover.excluded_test") not in filtered_states
|
|
|
|
assert hass.states.get("light.included_test") in filtered_states
|
2020-06-24 01:02:29 +00:00
|
|
|
|
|
|
|
|
2022-01-20 07:48:50 +00:00
|
|
|
async def test_homekit_entity_glob_filter_with_config_entities(
|
|
|
|
hass, mock_async_zeroconf, entity_reg
|
|
|
|
):
|
|
|
|
"""Test the entity filter with configuration entities."""
|
|
|
|
entry = await async_init_integration(hass)
|
|
|
|
|
|
|
|
from homeassistant.helpers.entity import EntityCategory
|
|
|
|
from homeassistant.helpers.entity_registry import RegistryEntry
|
|
|
|
|
|
|
|
select_config_entity: RegistryEntry = entity_reg.async_get_or_create(
|
|
|
|
"select",
|
|
|
|
"any",
|
|
|
|
"any",
|
|
|
|
device_id="1234",
|
|
|
|
entity_category=EntityCategory.CONFIG,
|
|
|
|
)
|
|
|
|
hass.states.async_set(select_config_entity.entity_id, "off")
|
|
|
|
|
|
|
|
switch_config_entity: RegistryEntry = entity_reg.async_get_or_create(
|
|
|
|
"switch",
|
|
|
|
"any",
|
|
|
|
"any",
|
|
|
|
device_id="1234",
|
|
|
|
entity_category=EntityCategory.CONFIG,
|
|
|
|
)
|
|
|
|
hass.states.async_set(switch_config_entity.entity_id, "off")
|
|
|
|
hass.states.async_set("select.keep", "open")
|
|
|
|
|
|
|
|
hass.states.async_set("cover.excluded_test", "open")
|
|
|
|
hass.states.async_set("light.included_test", "on")
|
|
|
|
|
|
|
|
entity_filter = generate_filter(
|
|
|
|
["select"],
|
|
|
|
["switch.test", switch_config_entity.entity_id],
|
|
|
|
[],
|
|
|
|
[],
|
|
|
|
["*.included_*"],
|
|
|
|
["*.excluded_*"],
|
|
|
|
)
|
|
|
|
homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_BRIDGE, entity_filter)
|
|
|
|
|
|
|
|
homekit.bridge = Mock()
|
|
|
|
homekit.bridge.accessories = {}
|
|
|
|
|
|
|
|
filtered_states = await homekit.async_configure_accessories()
|
|
|
|
assert (
|
|
|
|
hass.states.get(switch_config_entity.entity_id) in filtered_states
|
|
|
|
) # explicitly included
|
|
|
|
assert (
|
|
|
|
hass.states.get(select_config_entity.entity_id) not in filtered_states
|
|
|
|
) # not explicted included and its a config entity
|
|
|
|
assert hass.states.get("cover.excluded_test") not in filtered_states
|
|
|
|
assert hass.states.get("light.included_test") in filtered_states
|
|
|
|
assert hass.states.get("select.keep") in filtered_states
|
|
|
|
|
|
|
|
|
2022-03-23 09:32:51 +00:00
|
|
|
async def test_homekit_entity_glob_filter_with_hidden_entities(
|
|
|
|
hass, mock_async_zeroconf, entity_reg
|
|
|
|
):
|
|
|
|
"""Test the entity filter with hidden entities."""
|
|
|
|
entry = await async_init_integration(hass)
|
|
|
|
|
|
|
|
from homeassistant.helpers.entity_registry import RegistryEntry
|
|
|
|
|
|
|
|
select_config_entity: RegistryEntry = entity_reg.async_get_or_create(
|
|
|
|
"select",
|
|
|
|
"any",
|
|
|
|
"any",
|
|
|
|
device_id="1234",
|
|
|
|
hidden_by=er.RegistryEntryHider.INTEGRATION,
|
|
|
|
)
|
|
|
|
hass.states.async_set(select_config_entity.entity_id, "off")
|
|
|
|
|
|
|
|
switch_config_entity: RegistryEntry = entity_reg.async_get_or_create(
|
|
|
|
"switch",
|
|
|
|
"any",
|
|
|
|
"any",
|
|
|
|
device_id="1234",
|
|
|
|
hidden_by=er.RegistryEntryHider.INTEGRATION,
|
|
|
|
)
|
|
|
|
hass.states.async_set(switch_config_entity.entity_id, "off")
|
|
|
|
hass.states.async_set("select.keep", "open")
|
|
|
|
|
|
|
|
hass.states.async_set("cover.excluded_test", "open")
|
|
|
|
hass.states.async_set("light.included_test", "on")
|
|
|
|
|
|
|
|
entity_filter = generate_filter(
|
|
|
|
["select"],
|
|
|
|
["switch.test", switch_config_entity.entity_id],
|
|
|
|
[],
|
|
|
|
[],
|
|
|
|
["*.included_*"],
|
|
|
|
["*.excluded_*"],
|
|
|
|
)
|
|
|
|
homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_BRIDGE, entity_filter)
|
|
|
|
|
|
|
|
homekit.bridge = Mock()
|
|
|
|
homekit.bridge.accessories = {}
|
|
|
|
|
|
|
|
filtered_states = await homekit.async_configure_accessories()
|
|
|
|
assert (
|
|
|
|
hass.states.get(switch_config_entity.entity_id) in filtered_states
|
|
|
|
) # explicitly included
|
|
|
|
assert (
|
|
|
|
hass.states.get(select_config_entity.entity_id) not in filtered_states
|
|
|
|
) # not explicted included and its a hidden entity
|
|
|
|
assert hass.states.get("cover.excluded_test") not in filtered_states
|
|
|
|
assert hass.states.get("light.included_test") in filtered_states
|
|
|
|
assert hass.states.get("select.keep") in filtered_states
|
|
|
|
|
|
|
|
|
2021-11-19 04:23:20 +00:00
|
|
|
async def test_homekit_start(hass, hk_driver, mock_async_zeroconf, device_reg):
|
2018-05-10 23:21:59 +00:00
|
|
|
"""Test HomeKit start method."""
|
2020-05-01 04:05:06 +00:00
|
|
|
entry = await async_init_integration(hass)
|
|
|
|
|
2021-02-24 00:22:23 +00:00
|
|
|
homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_BRIDGE)
|
|
|
|
|
2018-10-05 10:32:26 +00:00
|
|
|
homekit.bridge = Mock()
|
|
|
|
homekit.bridge.accessories = []
|
2018-05-29 20:43:26 +00:00
|
|
|
homekit.driver = hk_driver
|
2021-03-12 06:05:03 +00:00
|
|
|
acc = Accessory(hk_driver, "any")
|
|
|
|
homekit.driver.accessory = acc
|
2018-05-10 23:21:59 +00:00
|
|
|
|
2020-05-25 16:17:30 +00:00
|
|
|
connection = (device_registry.CONNECTION_NETWORK_MAC, "AA:BB:CC:DD:EE:FF")
|
|
|
|
bridge_with_wrong_mac = device_reg.async_get_or_create(
|
|
|
|
config_entry_id=entry.entry_id,
|
|
|
|
connections={connection},
|
|
|
|
manufacturer="Any",
|
|
|
|
name="Any",
|
|
|
|
model="Home Assistant HomeKit Bridge",
|
|
|
|
)
|
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
hass.states.async_set("light.demo", "on")
|
2020-10-15 16:59:50 +00:00
|
|
|
hass.states.async_set("light.demo2", "on")
|
2018-05-10 23:21:59 +00:00
|
|
|
state = hass.states.async_all()[0]
|
|
|
|
|
2020-04-05 22:34:24 +00:00
|
|
|
with patch(f"{PATH_HOMEKIT}.HomeKit.add_bridge_accessory") as mock_add_acc, patch(
|
2021-11-23 17:40:20 +00:00
|
|
|
f"{PATH_HOMEKIT}.async_show_setup_message"
|
2019-07-31 19:25:30 +00:00
|
|
|
) as mock_setup_msg, patch(
|
2021-03-07 00:30:57 +00:00
|
|
|
"pyhap.accessory_driver.AccessoryDriver.async_start"
|
2019-07-31 19:25:30 +00:00
|
|
|
) as hk_driver_start:
|
2020-04-22 00:43:49 +00:00
|
|
|
await homekit.async_start()
|
2018-05-10 23:21:59 +00:00
|
|
|
|
2020-04-28 22:10:23 +00:00
|
|
|
await hass.async_block_till_done()
|
2020-10-15 16:59:50 +00:00
|
|
|
mock_add_acc.assert_any_call(state)
|
2021-02-24 00:22:23 +00:00
|
|
|
mock_setup_msg.assert_called_with(
|
2021-03-12 06:05:03 +00:00
|
|
|
hass, entry.entry_id, "Mock Title (Home Assistant Bridge)", ANY, ANY
|
2021-02-24 00:22:23 +00:00
|
|
|
)
|
2018-05-29 20:43:26 +00:00
|
|
|
assert hk_driver_start.called
|
2018-05-10 23:21:59 +00:00
|
|
|
assert homekit.status == STATUS_RUNNING
|
|
|
|
|
|
|
|
# Test start() if already started
|
2018-05-29 20:43:26 +00:00
|
|
|
hk_driver_start.reset_mock()
|
2020-04-22 00:43:49 +00:00
|
|
|
await homekit.async_start()
|
2020-04-28 22:10:23 +00:00
|
|
|
await hass.async_block_till_done()
|
2018-05-29 20:43:26 +00:00
|
|
|
assert not hk_driver_start.called
|
2018-05-10 23:21:59 +00:00
|
|
|
|
2020-05-25 16:17:30 +00:00
|
|
|
assert device_reg.async_get(bridge_with_wrong_mac.id) is None
|
|
|
|
|
|
|
|
device = device_reg.async_get_device(
|
2021-01-07 12:49:45 +00:00
|
|
|
{(DOMAIN, entry.entry_id, BRIDGE_SERIAL_NUMBER)}
|
2020-05-25 16:17:30 +00:00
|
|
|
)
|
|
|
|
assert device
|
|
|
|
formatted_mac = device_registry.format_mac(homekit.driver.state.mac)
|
|
|
|
assert (device_registry.CONNECTION_NETWORK_MAC, formatted_mac) in device.connections
|
|
|
|
|
|
|
|
# Start again to make sure the registry entry is kept
|
|
|
|
homekit.status = STATUS_READY
|
|
|
|
with patch(f"{PATH_HOMEKIT}.HomeKit.add_bridge_accessory") as mock_add_acc, patch(
|
2021-11-23 17:40:20 +00:00
|
|
|
f"{PATH_HOMEKIT}.async_show_setup_message"
|
2020-05-25 16:17:30 +00:00
|
|
|
) as mock_setup_msg, patch(
|
2021-03-07 00:30:57 +00:00
|
|
|
"pyhap.accessory_driver.AccessoryDriver.async_start"
|
2020-05-25 16:17:30 +00:00
|
|
|
) as hk_driver_start:
|
|
|
|
await homekit.async_start()
|
|
|
|
|
|
|
|
device = device_reg.async_get_device(
|
2021-01-07 12:49:45 +00:00
|
|
|
{(DOMAIN, entry.entry_id, BRIDGE_SERIAL_NUMBER)}
|
2020-05-25 16:17:30 +00:00
|
|
|
)
|
|
|
|
assert device
|
|
|
|
formatted_mac = device_registry.format_mac(homekit.driver.state.mac)
|
|
|
|
assert (device_registry.CONNECTION_NETWORK_MAC, formatted_mac) in device.connections
|
|
|
|
|
|
|
|
assert len(device_reg.devices) == 1
|
2021-08-23 19:00:26 +00:00
|
|
|
assert homekit.driver.state.config_version == 1
|
2020-05-25 16:17:30 +00:00
|
|
|
|
2018-05-10 23:21:59 +00:00
|
|
|
|
2021-11-19 04:23:20 +00:00
|
|
|
async def test_homekit_start_with_a_broken_accessory(
|
|
|
|
hass, hk_driver, mock_async_zeroconf
|
|
|
|
):
|
2020-04-16 02:40:38 +00:00
|
|
|
"""Test HomeKit start method."""
|
2020-05-01 04:05:06 +00:00
|
|
|
entry = MockConfigEntry(
|
|
|
|
domain=DOMAIN, data={CONF_NAME: "mock_name", CONF_PORT: 12345}
|
|
|
|
)
|
2020-04-16 02:40:38 +00:00
|
|
|
entity_filter = generate_filter(["cover", "light"], ["demo.test"], [], [])
|
|
|
|
|
2020-05-01 04:05:06 +00:00
|
|
|
await async_init_entry(hass, entry)
|
2021-02-24 00:22:23 +00:00
|
|
|
homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_BRIDGE, entity_filter)
|
2020-04-19 18:51:09 +00:00
|
|
|
|
2020-04-16 02:40:38 +00:00
|
|
|
homekit.bridge = Mock()
|
|
|
|
homekit.bridge.accessories = []
|
|
|
|
homekit.driver = hk_driver
|
2020-10-15 16:59:50 +00:00
|
|
|
homekit.driver.accessory = Accessory(hk_driver, "any")
|
2020-04-16 02:40:38 +00:00
|
|
|
|
|
|
|
hass.states.async_set("light.demo", "on")
|
|
|
|
hass.states.async_set("light.broken", "on")
|
|
|
|
|
|
|
|
with patch(f"{PATH_HOMEKIT}.get_accessory", side_effect=Exception), patch(
|
2021-11-23 17:40:20 +00:00
|
|
|
f"{PATH_HOMEKIT}.async_show_setup_message"
|
2020-04-16 02:40:38 +00:00
|
|
|
) as mock_setup_msg, patch(
|
2021-03-07 00:30:57 +00:00
|
|
|
"pyhap.accessory_driver.AccessoryDriver.async_start"
|
2020-04-16 02:40:38 +00:00
|
|
|
) as hk_driver_start:
|
2020-04-22 00:43:49 +00:00
|
|
|
await homekit.async_start()
|
2020-04-16 02:40:38 +00:00
|
|
|
|
2020-04-28 22:10:23 +00:00
|
|
|
await hass.async_block_till_done()
|
2021-02-24 00:22:23 +00:00
|
|
|
mock_setup_msg.assert_called_with(
|
2021-03-12 06:05:03 +00:00
|
|
|
hass, entry.entry_id, "Mock Title (Home Assistant Bridge)", ANY, ANY
|
2021-02-24 00:22:23 +00:00
|
|
|
)
|
2020-04-16 02:40:38 +00:00
|
|
|
assert hk_driver_start.called
|
|
|
|
assert homekit.status == STATUS_RUNNING
|
|
|
|
|
|
|
|
# Test start() if already started
|
|
|
|
hk_driver_start.reset_mock()
|
2020-04-22 00:43:49 +00:00
|
|
|
await homekit.async_start()
|
2020-04-28 22:10:23 +00:00
|
|
|
await hass.async_block_till_done()
|
2020-04-16 02:40:38 +00:00
|
|
|
assert not hk_driver_start.called
|
|
|
|
|
|
|
|
|
2021-08-25 14:47:39 +00:00
|
|
|
async def test_homekit_start_with_a_device(
|
2021-11-19 04:23:20 +00:00
|
|
|
hass, hk_driver, mock_async_zeroconf, demo_cleanup, device_reg, entity_reg
|
2021-08-25 14:47:39 +00:00
|
|
|
):
|
|
|
|
"""Test HomeKit start method with a device."""
|
|
|
|
|
|
|
|
entry = MockConfigEntry(
|
|
|
|
domain=DOMAIN, data={CONF_NAME: "mock_name", CONF_PORT: 12345}
|
|
|
|
)
|
|
|
|
assert await async_setup_component(hass, "demo", {"demo": {}})
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
|
|
|
|
reg_entry = entity_reg.async_get("light.ceiling_lights")
|
|
|
|
assert reg_entry is not None
|
|
|
|
device_id = reg_entry.device_id
|
|
|
|
await async_init_entry(hass, entry)
|
|
|
|
homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_BRIDGE, None, devices=[device_id])
|
|
|
|
homekit.driver = hk_driver
|
|
|
|
|
|
|
|
with patch(f"{PATH_HOMEKIT}.get_accessory", side_effect=Exception), patch(
|
2021-11-23 17:40:20 +00:00
|
|
|
f"{PATH_HOMEKIT}.async_show_setup_message"
|
2021-08-25 14:47:39 +00:00
|
|
|
) as mock_setup_msg:
|
|
|
|
await homekit.async_start()
|
|
|
|
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
mock_setup_msg.assert_called_with(
|
|
|
|
hass, entry.entry_id, "Mock Title (Home Assistant Bridge)", ANY, ANY
|
|
|
|
)
|
|
|
|
assert homekit.status == STATUS_RUNNING
|
|
|
|
|
|
|
|
assert isinstance(
|
|
|
|
list(homekit.driver.accessory.accessories.values())[0], DeviceTriggerAccessory
|
|
|
|
)
|
|
|
|
await homekit.async_stop()
|
|
|
|
|
|
|
|
|
2018-05-10 23:21:59 +00:00
|
|
|
async def test_homekit_stop(hass):
|
|
|
|
"""Test HomeKit stop method."""
|
2020-05-01 04:05:06 +00:00
|
|
|
entry = await async_init_integration(hass)
|
2021-02-24 00:22:23 +00:00
|
|
|
homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_BRIDGE)
|
2020-05-01 04:05:06 +00:00
|
|
|
|
2018-05-10 23:21:59 +00:00
|
|
|
homekit.driver = Mock()
|
2020-07-05 17:27:07 +00:00
|
|
|
homekit.driver.async_stop = AsyncMock()
|
2020-06-29 16:25:26 +00:00
|
|
|
homekit.bridge = Mock()
|
|
|
|
homekit.bridge.accessories = {}
|
2018-05-10 23:21:59 +00:00
|
|
|
|
|
|
|
assert homekit.status == STATUS_READY
|
2020-04-22 00:43:49 +00:00
|
|
|
await homekit.async_stop()
|
|
|
|
await hass.async_block_till_done()
|
2018-05-10 23:21:59 +00:00
|
|
|
homekit.status = STATUS_WAIT
|
2020-04-22 00:43:49 +00:00
|
|
|
await homekit.async_stop()
|
|
|
|
await hass.async_block_till_done()
|
2018-05-10 23:21:59 +00:00
|
|
|
homekit.status = STATUS_STOPPED
|
2020-04-22 00:43:49 +00:00
|
|
|
await homekit.async_stop()
|
|
|
|
await hass.async_block_till_done()
|
2020-07-05 17:27:07 +00:00
|
|
|
assert homekit.driver.async_stop.called is False
|
2018-03-15 01:48:21 +00:00
|
|
|
|
2018-05-10 23:21:59 +00:00
|
|
|
# Test if driver is started
|
|
|
|
homekit.status = STATUS_RUNNING
|
2020-04-22 00:43:49 +00:00
|
|
|
await homekit.async_stop()
|
|
|
|
await hass.async_block_till_done()
|
2020-07-05 17:27:07 +00:00
|
|
|
assert homekit.driver.async_stop.called is True
|
2018-10-05 10:32:26 +00:00
|
|
|
|
|
|
|
|
2021-11-19 04:23:20 +00:00
|
|
|
async def test_homekit_reset_accessories(hass, mock_async_zeroconf):
|
2021-07-21 04:45:21 +00:00
|
|
|
"""Test resetting HomeKit accessories."""
|
2021-10-07 10:58:00 +00:00
|
|
|
|
2020-05-01 04:05:06 +00:00
|
|
|
entry = MockConfigEntry(
|
|
|
|
domain=DOMAIN, data={CONF_NAME: "mock_name", CONF_PORT: 12345}
|
|
|
|
)
|
2019-07-31 19:25:30 +00:00
|
|
|
entity_id = "light.demo"
|
2021-07-21 04:45:21 +00:00
|
|
|
hass.states.async_set("light.demo", "on")
|
2021-02-24 00:22:23 +00:00
|
|
|
homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_BRIDGE)
|
|
|
|
|
2020-04-05 22:34:24 +00:00
|
|
|
with patch(f"{PATH_HOMEKIT}.HomeKit", return_value=homekit), patch(
|
2021-03-12 06:05:03 +00:00
|
|
|
"pyhap.accessory.Bridge.add_accessory"
|
|
|
|
) as mock_add_accessory, patch(
|
2019-07-31 19:25:30 +00:00
|
|
|
"pyhap.accessory_driver.AccessoryDriver.config_changed"
|
2020-05-01 04:05:06 +00:00
|
|
|
) as hk_driver_config_changed, patch(
|
2021-03-07 00:30:57 +00:00
|
|
|
"pyhap.accessory_driver.AccessoryDriver.async_start"
|
2021-07-24 14:31:30 +00:00
|
|
|
), patch(
|
|
|
|
f"{PATH_HOMEKIT}.accessories.HomeAccessory.run"
|
|
|
|
) as mock_run, patch.object(
|
2021-07-21 04:45:21 +00:00
|
|
|
homekit_base, "_HOMEKIT_CONFIG_UPDATE_TIME", 0
|
2020-05-01 04:05:06 +00:00
|
|
|
):
|
|
|
|
await async_init_entry(hass, entry)
|
2019-07-16 01:43:37 +00:00
|
|
|
|
2021-07-21 04:45:21 +00:00
|
|
|
acc_mock = MagicMock()
|
|
|
|
acc_mock.entity_id = entity_id
|
2021-09-12 22:06:03 +00:00
|
|
|
acc_mock.stop = AsyncMock()
|
2021-03-12 06:05:03 +00:00
|
|
|
aid = homekit.aid_storage.get_or_allocate_aid_for_entity_id(entity_id)
|
2021-07-21 04:45:21 +00:00
|
|
|
homekit.bridge.accessories = {aid: acc_mock}
|
2019-07-16 01:43:37 +00:00
|
|
|
homekit.status = STATUS_RUNNING
|
2021-09-12 22:06:03 +00:00
|
|
|
homekit.driver.aio_stop_event = MagicMock()
|
2019-07-16 01:43:37 +00:00
|
|
|
|
|
|
|
await hass.services.async_call(
|
2019-07-31 19:25:30 +00:00
|
|
|
DOMAIN,
|
|
|
|
SERVICE_HOMEKIT_RESET_ACCESSORY,
|
|
|
|
{ATTR_ENTITY_ID: entity_id},
|
|
|
|
blocking=True,
|
|
|
|
)
|
2019-07-16 01:43:37 +00:00
|
|
|
await hass.async_block_till_done()
|
|
|
|
|
2020-06-24 01:02:29 +00:00
|
|
|
assert hk_driver_config_changed.call_count == 2
|
2019-07-16 01:43:37 +00:00
|
|
|
assert mock_add_accessory.called
|
2021-07-24 14:31:30 +00:00
|
|
|
assert mock_run.called
|
2019-07-16 01:43:37 +00:00
|
|
|
homekit.status = STATUS_READY
|
|
|
|
|
|
|
|
|
2021-11-19 04:23:20 +00:00
|
|
|
async def test_homekit_unpair(hass, device_reg, mock_async_zeroconf):
|
2021-07-22 10:44:36 +00:00
|
|
|
"""Test unpairing HomeKit accessories."""
|
2021-10-07 10:58:00 +00:00
|
|
|
|
2021-07-22 10:44:36 +00:00
|
|
|
entry = MockConfigEntry(
|
|
|
|
domain=DOMAIN, data={CONF_NAME: "mock_name", CONF_PORT: 12345}
|
|
|
|
)
|
|
|
|
entity_id = "light.demo"
|
|
|
|
hass.states.async_set("light.demo", "on")
|
|
|
|
homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_BRIDGE)
|
|
|
|
|
|
|
|
with patch(f"{PATH_HOMEKIT}.HomeKit", return_value=homekit), patch(
|
|
|
|
"pyhap.accessory_driver.AccessoryDriver.async_start"
|
|
|
|
):
|
|
|
|
await async_init_entry(hass, entry)
|
|
|
|
|
|
|
|
acc_mock = MagicMock()
|
|
|
|
acc_mock.entity_id = entity_id
|
2021-09-12 22:06:03 +00:00
|
|
|
acc_mock.stop = AsyncMock()
|
|
|
|
|
2021-07-22 10:44:36 +00:00
|
|
|
aid = homekit.aid_storage.get_or_allocate_aid_for_entity_id(entity_id)
|
|
|
|
homekit.bridge.accessories = {aid: acc_mock}
|
|
|
|
homekit.status = STATUS_RUNNING
|
2021-09-12 22:06:03 +00:00
|
|
|
homekit.driver.aio_stop_event = MagicMock()
|
2021-07-22 10:44:36 +00:00
|
|
|
|
|
|
|
state = homekit.driver.state
|
2021-08-23 19:00:26 +00:00
|
|
|
state.add_paired_client("client1", "any", b"1")
|
2022-01-07 18:47:14 +00:00
|
|
|
state.add_paired_client("client2", "any", b"0")
|
|
|
|
state.add_paired_client("client3", "any", b"1")
|
|
|
|
state.add_paired_client("client4", "any", b"0")
|
|
|
|
state.add_paired_client("client5", "any", b"0")
|
|
|
|
|
2021-07-22 10:44:36 +00:00
|
|
|
formatted_mac = device_registry.format_mac(state.mac)
|
|
|
|
hk_bridge_dev = device_reg.async_get_device(
|
|
|
|
{}, {(device_registry.CONNECTION_NETWORK_MAC, formatted_mac)}
|
|
|
|
)
|
|
|
|
|
|
|
|
await hass.services.async_call(
|
|
|
|
DOMAIN,
|
|
|
|
SERVICE_HOMEKIT_UNPAIR,
|
|
|
|
{ATTR_DEVICE_ID: hk_bridge_dev.id},
|
|
|
|
blocking=True,
|
|
|
|
)
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
assert state.paired_clients == {}
|
|
|
|
homekit.status = STATUS_STOPPED
|
|
|
|
|
|
|
|
|
2021-11-19 04:23:20 +00:00
|
|
|
async def test_homekit_unpair_missing_device_id(hass, device_reg, mock_async_zeroconf):
|
2021-07-22 10:44:36 +00:00
|
|
|
"""Test unpairing HomeKit accessories with invalid device id."""
|
2021-10-07 10:58:00 +00:00
|
|
|
|
2021-07-22 10:44:36 +00:00
|
|
|
entry = MockConfigEntry(
|
|
|
|
domain=DOMAIN, data={CONF_NAME: "mock_name", CONF_PORT: 12345}
|
|
|
|
)
|
|
|
|
entity_id = "light.demo"
|
|
|
|
hass.states.async_set("light.demo", "on")
|
|
|
|
homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_BRIDGE)
|
|
|
|
|
|
|
|
with patch(f"{PATH_HOMEKIT}.HomeKit", return_value=homekit), patch(
|
|
|
|
"pyhap.accessory_driver.AccessoryDriver.async_start"
|
|
|
|
):
|
|
|
|
await async_init_entry(hass, entry)
|
|
|
|
|
|
|
|
acc_mock = MagicMock()
|
|
|
|
acc_mock.entity_id = entity_id
|
2021-09-12 22:06:03 +00:00
|
|
|
acc_mock.stop = AsyncMock()
|
|
|
|
|
2021-07-22 10:44:36 +00:00
|
|
|
aid = homekit.aid_storage.get_or_allocate_aid_for_entity_id(entity_id)
|
|
|
|
homekit.bridge.accessories = {aid: acc_mock}
|
|
|
|
homekit.status = STATUS_RUNNING
|
2021-09-12 22:06:03 +00:00
|
|
|
homekit.driver.aio_stop_event = MagicMock()
|
2021-07-22 10:44:36 +00:00
|
|
|
|
|
|
|
state = homekit.driver.state
|
2021-08-23 19:00:26 +00:00
|
|
|
state.add_paired_client("client1", "any", b"1")
|
2021-07-22 10:44:36 +00:00
|
|
|
with pytest.raises(HomeAssistantError):
|
|
|
|
await hass.services.async_call(
|
|
|
|
DOMAIN,
|
|
|
|
SERVICE_HOMEKIT_UNPAIR,
|
|
|
|
{ATTR_DEVICE_ID: "notvalid"},
|
|
|
|
blocking=True,
|
|
|
|
)
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
state.paired_clients = {"client1": "any"}
|
|
|
|
homekit.status = STATUS_STOPPED
|
|
|
|
|
|
|
|
|
2021-11-19 04:23:20 +00:00
|
|
|
async def test_homekit_unpair_not_homekit_device(hass, device_reg, mock_async_zeroconf):
|
2021-07-22 10:44:36 +00:00
|
|
|
"""Test unpairing HomeKit accessories with a non-homekit device id."""
|
2021-10-07 10:58:00 +00:00
|
|
|
|
2021-07-22 10:44:36 +00:00
|
|
|
entry = MockConfigEntry(
|
|
|
|
domain=DOMAIN, data={CONF_NAME: "mock_name", CONF_PORT: 12345}
|
|
|
|
)
|
|
|
|
not_homekit_entry = MockConfigEntry(
|
|
|
|
domain="not_homekit", data={CONF_NAME: "mock_name", CONF_PORT: 12345}
|
|
|
|
)
|
|
|
|
entity_id = "light.demo"
|
|
|
|
hass.states.async_set("light.demo", "on")
|
|
|
|
homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_BRIDGE)
|
|
|
|
|
|
|
|
with patch(f"{PATH_HOMEKIT}.HomeKit", return_value=homekit), patch(
|
|
|
|
"pyhap.accessory_driver.AccessoryDriver.async_start"
|
|
|
|
):
|
|
|
|
await async_init_entry(hass, entry)
|
|
|
|
|
|
|
|
acc_mock = MagicMock()
|
|
|
|
acc_mock.entity_id = entity_id
|
2021-09-12 22:06:03 +00:00
|
|
|
acc_mock.stop = AsyncMock()
|
|
|
|
|
2021-07-22 10:44:36 +00:00
|
|
|
aid = homekit.aid_storage.get_or_allocate_aid_for_entity_id(entity_id)
|
|
|
|
homekit.bridge.accessories = {aid: acc_mock}
|
|
|
|
homekit.status = STATUS_RUNNING
|
|
|
|
|
|
|
|
device_entry = device_reg.async_get_or_create(
|
|
|
|
config_entry_id=not_homekit_entry.entry_id,
|
|
|
|
sw_version="0.16.0",
|
|
|
|
model="Powerwall 2",
|
|
|
|
manufacturer="Tesla",
|
|
|
|
connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")},
|
|
|
|
)
|
|
|
|
|
|
|
|
state = homekit.driver.state
|
2021-08-23 19:00:26 +00:00
|
|
|
state.add_paired_client("client1", "any", b"1")
|
2021-07-22 10:44:36 +00:00
|
|
|
with pytest.raises(HomeAssistantError):
|
|
|
|
await hass.services.async_call(
|
|
|
|
DOMAIN,
|
|
|
|
SERVICE_HOMEKIT_UNPAIR,
|
|
|
|
{ATTR_DEVICE_ID: device_entry.id},
|
|
|
|
blocking=True,
|
|
|
|
)
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
state.paired_clients = {"client1": "any"}
|
|
|
|
homekit.status = STATUS_STOPPED
|
|
|
|
|
|
|
|
|
2021-11-19 04:23:20 +00:00
|
|
|
async def test_homekit_reset_accessories_not_supported(hass, mock_async_zeroconf):
|
2021-07-21 04:45:21 +00:00
|
|
|
"""Test resetting HomeKit accessories with an unsupported entity."""
|
2021-10-07 10:58:00 +00:00
|
|
|
|
2021-07-21 04:45:21 +00:00
|
|
|
entry = MockConfigEntry(
|
|
|
|
domain=DOMAIN, data={CONF_NAME: "mock_name", CONF_PORT: 12345}
|
|
|
|
)
|
|
|
|
entity_id = "not_supported.demo"
|
|
|
|
hass.states.async_set("not_supported.demo", "on")
|
|
|
|
homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_BRIDGE)
|
|
|
|
|
|
|
|
with patch(f"{PATH_HOMEKIT}.HomeKit", return_value=homekit), patch(
|
|
|
|
"pyhap.accessory.Bridge.add_accessory"
|
|
|
|
) as mock_add_accessory, patch(
|
|
|
|
"pyhap.accessory_driver.AccessoryDriver.config_changed"
|
|
|
|
) as hk_driver_config_changed, patch(
|
|
|
|
"pyhap.accessory_driver.AccessoryDriver.async_start"
|
|
|
|
), patch.object(
|
|
|
|
homekit_base, "_HOMEKIT_CONFIG_UPDATE_TIME", 0
|
|
|
|
):
|
|
|
|
await async_init_entry(hass, entry)
|
|
|
|
|
|
|
|
acc_mock = MagicMock()
|
|
|
|
acc_mock.entity_id = entity_id
|
2021-09-12 22:06:03 +00:00
|
|
|
acc_mock.stop = AsyncMock()
|
|
|
|
|
2021-07-21 04:45:21 +00:00
|
|
|
aid = homekit.aid_storage.get_or_allocate_aid_for_entity_id(entity_id)
|
|
|
|
homekit.bridge.accessories = {aid: acc_mock}
|
|
|
|
homekit.status = STATUS_RUNNING
|
2021-09-12 22:06:03 +00:00
|
|
|
homekit.driver.aio_stop_event = MagicMock()
|
2021-07-21 04:45:21 +00:00
|
|
|
|
|
|
|
await hass.services.async_call(
|
|
|
|
DOMAIN,
|
|
|
|
SERVICE_HOMEKIT_RESET_ACCESSORY,
|
|
|
|
{ATTR_ENTITY_ID: entity_id},
|
|
|
|
blocking=True,
|
|
|
|
)
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
|
|
|
|
assert hk_driver_config_changed.call_count == 2
|
|
|
|
assert not mock_add_accessory.called
|
|
|
|
assert len(homekit.bridge.accessories) == 0
|
|
|
|
homekit.status = STATUS_STOPPED
|
|
|
|
|
|
|
|
|
2021-11-19 04:23:20 +00:00
|
|
|
async def test_homekit_reset_accessories_state_missing(hass, mock_async_zeroconf):
|
2021-07-21 04:45:21 +00:00
|
|
|
"""Test resetting HomeKit accessories when the state goes missing."""
|
2021-10-07 10:58:00 +00:00
|
|
|
|
2021-07-21 04:45:21 +00:00
|
|
|
entry = MockConfigEntry(
|
|
|
|
domain=DOMAIN, data={CONF_NAME: "mock_name", CONF_PORT: 12345}
|
|
|
|
)
|
|
|
|
entity_id = "light.demo"
|
|
|
|
homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_BRIDGE)
|
|
|
|
|
|
|
|
with patch(f"{PATH_HOMEKIT}.HomeKit", return_value=homekit), patch(
|
|
|
|
"pyhap.accessory.Bridge.add_accessory"
|
|
|
|
) as mock_add_accessory, patch(
|
|
|
|
"pyhap.accessory_driver.AccessoryDriver.config_changed"
|
|
|
|
) as hk_driver_config_changed, patch(
|
|
|
|
"pyhap.accessory_driver.AccessoryDriver.async_start"
|
|
|
|
), patch.object(
|
|
|
|
homekit_base, "_HOMEKIT_CONFIG_UPDATE_TIME", 0
|
|
|
|
):
|
|
|
|
await async_init_entry(hass, entry)
|
|
|
|
|
|
|
|
acc_mock = MagicMock()
|
|
|
|
acc_mock.entity_id = entity_id
|
2021-09-12 22:06:03 +00:00
|
|
|
acc_mock.stop = AsyncMock()
|
|
|
|
|
2021-07-21 04:45:21 +00:00
|
|
|
aid = homekit.aid_storage.get_or_allocate_aid_for_entity_id(entity_id)
|
|
|
|
homekit.bridge.accessories = {aid: acc_mock}
|
|
|
|
homekit.status = STATUS_RUNNING
|
2021-09-12 22:06:03 +00:00
|
|
|
homekit.driver.aio_stop_event = MagicMock()
|
2021-07-21 04:45:21 +00:00
|
|
|
|
|
|
|
await hass.services.async_call(
|
|
|
|
DOMAIN,
|
|
|
|
SERVICE_HOMEKIT_RESET_ACCESSORY,
|
|
|
|
{ATTR_ENTITY_ID: entity_id},
|
|
|
|
blocking=True,
|
|
|
|
)
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
|
|
|
|
assert hk_driver_config_changed.call_count == 0
|
|
|
|
assert not mock_add_accessory.called
|
|
|
|
homekit.status = STATUS_STOPPED
|
|
|
|
|
|
|
|
|
2021-11-19 04:23:20 +00:00
|
|
|
async def test_homekit_reset_accessories_not_bridged(hass, mock_async_zeroconf):
|
2021-07-21 04:45:21 +00:00
|
|
|
"""Test resetting HomeKit accessories when the state is not bridged."""
|
2021-10-07 10:58:00 +00:00
|
|
|
|
2021-07-21 04:45:21 +00:00
|
|
|
entry = MockConfigEntry(
|
|
|
|
domain=DOMAIN, data={CONF_NAME: "mock_name", CONF_PORT: 12345}
|
|
|
|
)
|
|
|
|
entity_id = "light.demo"
|
|
|
|
homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_BRIDGE)
|
|
|
|
|
|
|
|
with patch(f"{PATH_HOMEKIT}.HomeKit", return_value=homekit), patch(
|
|
|
|
"pyhap.accessory.Bridge.add_accessory"
|
|
|
|
) as mock_add_accessory, patch(
|
|
|
|
"pyhap.accessory_driver.AccessoryDriver.config_changed"
|
|
|
|
) as hk_driver_config_changed, patch(
|
|
|
|
"pyhap.accessory_driver.AccessoryDriver.async_start"
|
|
|
|
), patch.object(
|
|
|
|
homekit_base, "_HOMEKIT_CONFIG_UPDATE_TIME", 0
|
|
|
|
):
|
|
|
|
await async_init_entry(hass, entry)
|
|
|
|
|
|
|
|
acc_mock = MagicMock()
|
|
|
|
acc_mock.entity_id = entity_id
|
2021-09-12 22:06:03 +00:00
|
|
|
acc_mock.stop = AsyncMock()
|
|
|
|
|
2021-07-21 04:45:21 +00:00
|
|
|
aid = homekit.aid_storage.get_or_allocate_aid_for_entity_id(entity_id)
|
|
|
|
homekit.bridge.accessories = {aid: acc_mock}
|
|
|
|
homekit.status = STATUS_RUNNING
|
2021-09-12 22:06:03 +00:00
|
|
|
homekit.driver.aio_stop_event = MagicMock()
|
2021-07-21 04:45:21 +00:00
|
|
|
|
|
|
|
await hass.services.async_call(
|
|
|
|
DOMAIN,
|
|
|
|
SERVICE_HOMEKIT_RESET_ACCESSORY,
|
|
|
|
{ATTR_ENTITY_ID: "light.not_bridged"},
|
|
|
|
blocking=True,
|
|
|
|
)
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
|
|
|
|
assert hk_driver_config_changed.call_count == 0
|
|
|
|
assert not mock_add_accessory.called
|
|
|
|
homekit.status = STATUS_STOPPED
|
|
|
|
|
|
|
|
|
2021-11-19 04:23:20 +00:00
|
|
|
async def test_homekit_reset_single_accessory(hass, mock_async_zeroconf):
|
2021-07-21 04:45:21 +00:00
|
|
|
"""Test resetting HomeKit single accessory."""
|
2021-10-07 10:58:00 +00:00
|
|
|
|
2021-07-21 04:45:21 +00:00
|
|
|
entry = MockConfigEntry(
|
|
|
|
domain=DOMAIN, data={CONF_NAME: "mock_name", CONF_PORT: 12345}
|
|
|
|
)
|
|
|
|
entity_id = "light.demo"
|
|
|
|
hass.states.async_set("light.demo", "on")
|
|
|
|
homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_ACCESSORY)
|
|
|
|
|
|
|
|
with patch(f"{PATH_HOMEKIT}.HomeKit", return_value=homekit), patch(
|
|
|
|
"pyhap.accessory_driver.AccessoryDriver.config_changed"
|
|
|
|
) as hk_driver_config_changed, patch(
|
|
|
|
"pyhap.accessory_driver.AccessoryDriver.async_start"
|
2021-07-24 14:31:30 +00:00
|
|
|
), patch(
|
|
|
|
f"{PATH_HOMEKIT}.accessories.HomeAccessory.run"
|
|
|
|
) as mock_run:
|
2021-07-21 04:45:21 +00:00
|
|
|
await async_init_entry(hass, entry)
|
|
|
|
|
|
|
|
homekit.status = STATUS_RUNNING
|
|
|
|
acc_mock = MagicMock()
|
|
|
|
acc_mock.entity_id = entity_id
|
2021-09-12 22:06:03 +00:00
|
|
|
acc_mock.stop = AsyncMock()
|
|
|
|
|
2021-07-21 04:45:21 +00:00
|
|
|
homekit.driver.accessory = acc_mock
|
2021-09-12 22:06:03 +00:00
|
|
|
homekit.driver.aio_stop_event = MagicMock()
|
2021-07-21 04:45:21 +00:00
|
|
|
|
|
|
|
await hass.services.async_call(
|
|
|
|
DOMAIN,
|
|
|
|
SERVICE_HOMEKIT_RESET_ACCESSORY,
|
|
|
|
{ATTR_ENTITY_ID: entity_id},
|
|
|
|
blocking=True,
|
|
|
|
)
|
|
|
|
await hass.async_block_till_done()
|
2021-07-24 14:31:30 +00:00
|
|
|
assert mock_run.called
|
2021-07-21 04:45:21 +00:00
|
|
|
assert hk_driver_config_changed.call_count == 1
|
|
|
|
homekit.status = STATUS_READY
|
|
|
|
|
|
|
|
|
2021-11-19 04:23:20 +00:00
|
|
|
async def test_homekit_reset_single_accessory_unsupported(hass, mock_async_zeroconf):
|
2021-07-21 04:45:21 +00:00
|
|
|
"""Test resetting HomeKit single accessory with an unsupported entity."""
|
2021-10-07 10:58:00 +00:00
|
|
|
|
2021-07-21 04:45:21 +00:00
|
|
|
entry = MockConfigEntry(
|
|
|
|
domain=DOMAIN, data={CONF_NAME: "mock_name", CONF_PORT: 12345}
|
|
|
|
)
|
|
|
|
entity_id = "not_supported.demo"
|
|
|
|
hass.states.async_set("not_supported.demo", "on")
|
|
|
|
homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_ACCESSORY)
|
|
|
|
|
|
|
|
with patch(f"{PATH_HOMEKIT}.HomeKit", return_value=homekit), patch(
|
|
|
|
"pyhap.accessory_driver.AccessoryDriver.config_changed"
|
|
|
|
) as hk_driver_config_changed, patch(
|
|
|
|
"pyhap.accessory_driver.AccessoryDriver.async_start"
|
|
|
|
):
|
|
|
|
await async_init_entry(hass, entry)
|
|
|
|
|
|
|
|
homekit.status = STATUS_RUNNING
|
|
|
|
acc_mock = MagicMock()
|
|
|
|
acc_mock.entity_id = entity_id
|
2021-09-12 22:06:03 +00:00
|
|
|
acc_mock.stop = AsyncMock()
|
|
|
|
|
2021-07-21 04:45:21 +00:00
|
|
|
homekit.driver.accessory = acc_mock
|
2021-09-12 22:06:03 +00:00
|
|
|
homekit.driver.aio_stop_event = MagicMock()
|
2021-07-21 04:45:21 +00:00
|
|
|
|
|
|
|
await hass.services.async_call(
|
|
|
|
DOMAIN,
|
|
|
|
SERVICE_HOMEKIT_RESET_ACCESSORY,
|
|
|
|
{ATTR_ENTITY_ID: entity_id},
|
|
|
|
blocking=True,
|
|
|
|
)
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
|
|
|
|
assert hk_driver_config_changed.call_count == 0
|
|
|
|
homekit.status = STATUS_STOPPED
|
|
|
|
|
|
|
|
|
2021-11-19 04:23:20 +00:00
|
|
|
async def test_homekit_reset_single_accessory_state_missing(hass, mock_async_zeroconf):
|
2021-07-21 04:45:21 +00:00
|
|
|
"""Test resetting HomeKit single accessory when the state goes missing."""
|
2021-10-07 10:58:00 +00:00
|
|
|
|
2021-07-21 04:45:21 +00:00
|
|
|
entry = MockConfigEntry(
|
|
|
|
domain=DOMAIN, data={CONF_NAME: "mock_name", CONF_PORT: 12345}
|
|
|
|
)
|
|
|
|
entity_id = "light.demo"
|
|
|
|
homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_ACCESSORY)
|
|
|
|
|
|
|
|
with patch(f"{PATH_HOMEKIT}.HomeKit", return_value=homekit), patch(
|
|
|
|
"pyhap.accessory_driver.AccessoryDriver.config_changed"
|
|
|
|
) as hk_driver_config_changed, patch(
|
|
|
|
"pyhap.accessory_driver.AccessoryDriver.async_start"
|
|
|
|
):
|
|
|
|
await async_init_entry(hass, entry)
|
|
|
|
|
|
|
|
homekit.status = STATUS_RUNNING
|
|
|
|
acc_mock = MagicMock()
|
|
|
|
acc_mock.entity_id = entity_id
|
2021-09-12 22:06:03 +00:00
|
|
|
acc_mock.stop = AsyncMock()
|
|
|
|
|
2021-07-21 04:45:21 +00:00
|
|
|
homekit.driver.accessory = acc_mock
|
2021-09-12 22:06:03 +00:00
|
|
|
homekit.driver.aio_stop_event = MagicMock()
|
2021-07-21 04:45:21 +00:00
|
|
|
|
|
|
|
await hass.services.async_call(
|
|
|
|
DOMAIN,
|
|
|
|
SERVICE_HOMEKIT_RESET_ACCESSORY,
|
|
|
|
{ATTR_ENTITY_ID: entity_id},
|
|
|
|
blocking=True,
|
|
|
|
)
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
|
|
|
|
assert hk_driver_config_changed.call_count == 0
|
|
|
|
homekit.status = STATUS_STOPPED
|
|
|
|
|
|
|
|
|
2021-11-19 04:23:20 +00:00
|
|
|
async def test_homekit_reset_single_accessory_no_match(hass, mock_async_zeroconf):
|
2021-07-21 04:45:21 +00:00
|
|
|
"""Test resetting HomeKit single accessory when the entity id does not match."""
|
2021-10-07 10:58:00 +00:00
|
|
|
|
2021-07-21 04:45:21 +00:00
|
|
|
entry = MockConfigEntry(
|
|
|
|
domain=DOMAIN, data={CONF_NAME: "mock_name", CONF_PORT: 12345}
|
|
|
|
)
|
|
|
|
entity_id = "light.demo"
|
|
|
|
homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_ACCESSORY)
|
|
|
|
|
|
|
|
with patch(f"{PATH_HOMEKIT}.HomeKit", return_value=homekit), patch(
|
|
|
|
"pyhap.accessory_driver.AccessoryDriver.config_changed"
|
|
|
|
) as hk_driver_config_changed, patch(
|
|
|
|
"pyhap.accessory_driver.AccessoryDriver.async_start"
|
|
|
|
):
|
|
|
|
await async_init_entry(hass, entry)
|
|
|
|
|
|
|
|
homekit.status = STATUS_RUNNING
|
|
|
|
acc_mock = MagicMock()
|
|
|
|
acc_mock.entity_id = entity_id
|
2021-09-12 22:06:03 +00:00
|
|
|
acc_mock.stop = AsyncMock()
|
|
|
|
|
2021-07-21 04:45:21 +00:00
|
|
|
homekit.driver.accessory = acc_mock
|
2021-09-12 22:06:03 +00:00
|
|
|
homekit.driver.aio_stop_event = MagicMock()
|
2021-07-21 04:45:21 +00:00
|
|
|
|
|
|
|
await hass.services.async_call(
|
|
|
|
DOMAIN,
|
|
|
|
SERVICE_HOMEKIT_RESET_ACCESSORY,
|
|
|
|
{ATTR_ENTITY_ID: "light.no_match"},
|
|
|
|
blocking=True,
|
|
|
|
)
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
|
|
|
|
assert hk_driver_config_changed.call_count == 0
|
|
|
|
homekit.status = STATUS_STOPPED
|
|
|
|
|
|
|
|
|
2021-11-19 04:23:20 +00:00
|
|
|
async def test_homekit_too_many_accessories(
|
|
|
|
hass, hk_driver, caplog, mock_async_zeroconf
|
|
|
|
):
|
2018-10-05 10:32:26 +00:00
|
|
|
"""Test adding too many accessories to HomeKit."""
|
2020-05-01 04:05:06 +00:00
|
|
|
entry = await async_init_integration(hass)
|
2020-04-19 18:51:09 +00:00
|
|
|
|
|
|
|
entity_filter = generate_filter(["cover", "light"], ["demo.test"], [], [])
|
|
|
|
|
2021-02-24 00:22:23 +00:00
|
|
|
homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_BRIDGE, entity_filter)
|
2020-10-15 16:59:50 +00:00
|
|
|
|
|
|
|
def _mock_bridge(*_):
|
|
|
|
mock_bridge = HomeBridge(hass, hk_driver, "mock_bridge")
|
|
|
|
# The bridge itself counts as an accessory
|
|
|
|
mock_bridge.accessories = range(MAX_DEVICES)
|
|
|
|
return mock_bridge
|
|
|
|
|
2018-10-05 10:32:26 +00:00
|
|
|
homekit.driver = hk_driver
|
2020-10-15 16:59:50 +00:00
|
|
|
homekit.driver.accessory = Accessory(hk_driver, "any")
|
2018-10-05 10:32:26 +00:00
|
|
|
|
2020-04-19 18:51:09 +00:00
|
|
|
hass.states.async_set("light.demo", "on")
|
2020-10-15 16:59:50 +00:00
|
|
|
hass.states.async_set("light.demo2", "on")
|
|
|
|
hass.states.async_set("light.demo3", "on")
|
2020-04-19 18:51:09 +00:00
|
|
|
|
2021-03-07 00:30:57 +00:00
|
|
|
with patch("pyhap.accessory_driver.AccessoryDriver.async_start"), patch(
|
2021-11-23 17:40:20 +00:00
|
|
|
f"{PATH_HOMEKIT}.async_show_setup_message"
|
2021-03-12 06:05:03 +00:00
|
|
|
), patch(f"{PATH_HOMEKIT}.HomeBridge", _mock_bridge):
|
2020-04-22 00:43:49 +00:00
|
|
|
await homekit.async_start()
|
|
|
|
await hass.async_block_till_done()
|
2020-11-01 13:51:56 +00:00
|
|
|
assert "would exceed" in caplog.text
|
2020-04-22 00:43:49 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def test_homekit_finds_linked_batteries(
|
2021-11-19 04:23:20 +00:00
|
|
|
hass, hk_driver, device_reg, entity_reg, mock_async_zeroconf
|
2020-04-22 00:43:49 +00:00
|
|
|
):
|
|
|
|
"""Test HomeKit start method."""
|
2020-05-01 04:05:06 +00:00
|
|
|
entry = await async_init_integration(hass)
|
2020-04-22 00:43:49 +00:00
|
|
|
|
2021-02-24 00:22:23 +00:00
|
|
|
homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_BRIDGE)
|
|
|
|
|
2020-04-22 00:43:49 +00:00
|
|
|
homekit.driver = hk_driver
|
2021-03-12 06:05:03 +00:00
|
|
|
homekit.bridge = MagicMock()
|
2020-04-22 00:43:49 +00:00
|
|
|
|
|
|
|
config_entry = MockConfigEntry(domain="test", data={})
|
|
|
|
config_entry.add_to_hass(hass)
|
|
|
|
device_entry = device_reg.async_get_or_create(
|
|
|
|
config_entry_id=config_entry.entry_id,
|
2020-05-11 14:09:48 +00:00
|
|
|
sw_version="0.16.0",
|
2022-01-04 15:19:12 +00:00
|
|
|
hw_version="2.34",
|
2020-05-11 14:09:48 +00:00
|
|
|
model="Powerwall 2",
|
|
|
|
manufacturer="Tesla",
|
2020-04-22 00:43:49 +00:00
|
|
|
connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")},
|
|
|
|
)
|
|
|
|
|
|
|
|
binary_charging_sensor = entity_reg.async_get_or_create(
|
|
|
|
"binary_sensor",
|
2020-05-11 14:09:48 +00:00
|
|
|
"powerwall",
|
2020-04-22 00:43:49 +00:00
|
|
|
"battery_charging",
|
|
|
|
device_id=device_entry.id,
|
2021-12-20 18:53:44 +00:00
|
|
|
original_device_class=BinarySensorDeviceClass.BATTERY_CHARGING,
|
2020-04-22 00:43:49 +00:00
|
|
|
)
|
|
|
|
battery_sensor = entity_reg.async_get_or_create(
|
|
|
|
"sensor",
|
2020-05-11 14:09:48 +00:00
|
|
|
"powerwall",
|
2020-04-22 00:43:49 +00:00
|
|
|
"battery",
|
|
|
|
device_id=device_entry.id,
|
2021-12-20 18:53:44 +00:00
|
|
|
original_device_class=SensorDeviceClass.BATTERY,
|
2020-04-22 00:43:49 +00:00
|
|
|
)
|
|
|
|
light = entity_reg.async_get_or_create(
|
2020-05-11 14:09:48 +00:00
|
|
|
"light", "powerwall", "demo", device_id=device_entry.id
|
2020-04-22 00:43:49 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
hass.states.async_set(
|
|
|
|
binary_charging_sensor.entity_id,
|
|
|
|
STATE_ON,
|
2021-12-20 18:53:44 +00:00
|
|
|
{ATTR_DEVICE_CLASS: BinarySensorDeviceClass.BATTERY_CHARGING},
|
2020-04-22 00:43:49 +00:00
|
|
|
)
|
|
|
|
hass.states.async_set(
|
2021-12-20 18:53:44 +00:00
|
|
|
battery_sensor.entity_id, 30, {ATTR_DEVICE_CLASS: SensorDeviceClass.BATTERY}
|
2020-04-22 00:43:49 +00:00
|
|
|
)
|
|
|
|
hass.states.async_set(light.entity_id, STATE_ON)
|
|
|
|
|
2021-11-23 17:40:20 +00:00
|
|
|
with patch(f"{PATH_HOMEKIT}.async_show_setup_message"), patch(
|
2021-03-12 06:05:03 +00:00
|
|
|
f"{PATH_HOMEKIT}.get_accessory"
|
|
|
|
) as mock_get_acc, patch("pyhap.accessory_driver.AccessoryDriver.async_start"):
|
2020-04-22 00:43:49 +00:00
|
|
|
await homekit.async_start()
|
2020-04-28 22:10:23 +00:00
|
|
|
await hass.async_block_till_done()
|
2020-04-22 00:43:49 +00:00
|
|
|
|
|
|
|
mock_get_acc.assert_called_with(
|
|
|
|
hass,
|
2021-03-12 06:05:03 +00:00
|
|
|
ANY,
|
2020-04-22 00:43:49 +00:00
|
|
|
ANY,
|
|
|
|
ANY,
|
|
|
|
{
|
2020-05-11 14:09:48 +00:00
|
|
|
"manufacturer": "Tesla",
|
|
|
|
"model": "Powerwall 2",
|
|
|
|
"sw_version": "0.16.0",
|
2022-01-04 15:19:12 +00:00
|
|
|
"hw_version": "2.34",
|
2021-08-25 14:47:39 +00:00
|
|
|
"platform": "test",
|
2020-05-11 14:09:48 +00:00
|
|
|
"linked_battery_charging_sensor": "binary_sensor.powerwall_battery_charging",
|
|
|
|
"linked_battery_sensor": "sensor.powerwall_battery",
|
2020-04-22 00:43:49 +00:00
|
|
|
},
|
|
|
|
)
|
2020-05-01 04:05:06 +00:00
|
|
|
|
|
|
|
|
2020-09-10 21:19:11 +00:00
|
|
|
async def test_homekit_async_get_integration_fails(
|
2021-11-19 04:23:20 +00:00
|
|
|
hass, hk_driver, device_reg, entity_reg, mock_async_zeroconf
|
2020-09-10 21:19:11 +00:00
|
|
|
):
|
|
|
|
"""Test that we continue if async_get_integration fails."""
|
|
|
|
entry = await async_init_integration(hass)
|
2021-02-24 00:22:23 +00:00
|
|
|
homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_BRIDGE)
|
2020-09-10 21:19:11 +00:00
|
|
|
|
|
|
|
homekit.driver = hk_driver
|
|
|
|
homekit.bridge = HomeBridge(hass, hk_driver, "mock_bridge")
|
|
|
|
|
|
|
|
config_entry = MockConfigEntry(domain="test", data={})
|
|
|
|
config_entry.add_to_hass(hass)
|
|
|
|
device_entry = device_reg.async_get_or_create(
|
|
|
|
config_entry_id=config_entry.entry_id,
|
|
|
|
sw_version="0.16.0",
|
|
|
|
model="Powerwall 2",
|
|
|
|
connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")},
|
|
|
|
)
|
|
|
|
|
|
|
|
binary_charging_sensor = entity_reg.async_get_or_create(
|
|
|
|
"binary_sensor",
|
|
|
|
"invalid_integration_does_not_exist",
|
|
|
|
"battery_charging",
|
|
|
|
device_id=device_entry.id,
|
2021-12-20 18:53:44 +00:00
|
|
|
original_device_class=BinarySensorDeviceClass.BATTERY_CHARGING,
|
2020-09-10 21:19:11 +00:00
|
|
|
)
|
|
|
|
battery_sensor = entity_reg.async_get_or_create(
|
|
|
|
"sensor",
|
|
|
|
"invalid_integration_does_not_exist",
|
|
|
|
"battery",
|
|
|
|
device_id=device_entry.id,
|
2021-12-20 18:53:44 +00:00
|
|
|
original_device_class=SensorDeviceClass.BATTERY,
|
2020-09-10 21:19:11 +00:00
|
|
|
)
|
|
|
|
light = entity_reg.async_get_or_create(
|
|
|
|
"light", "invalid_integration_does_not_exist", "demo", device_id=device_entry.id
|
|
|
|
)
|
|
|
|
|
|
|
|
hass.states.async_set(
|
|
|
|
binary_charging_sensor.entity_id,
|
|
|
|
STATE_ON,
|
2021-12-20 18:53:44 +00:00
|
|
|
{ATTR_DEVICE_CLASS: BinarySensorDeviceClass.BATTERY_CHARGING},
|
2020-09-10 21:19:11 +00:00
|
|
|
)
|
|
|
|
hass.states.async_set(
|
2021-12-20 18:53:44 +00:00
|
|
|
battery_sensor.entity_id, 30, {ATTR_DEVICE_CLASS: SensorDeviceClass.BATTERY}
|
2020-09-10 21:19:11 +00:00
|
|
|
)
|
|
|
|
hass.states.async_set(light.entity_id, STATE_ON)
|
|
|
|
|
|
|
|
with patch.object(homekit.bridge, "add_accessory"), patch(
|
2021-11-23 17:40:20 +00:00
|
|
|
f"{PATH_HOMEKIT}.async_show_setup_message"
|
2020-09-10 21:19:11 +00:00
|
|
|
), patch(f"{PATH_HOMEKIT}.get_accessory") as mock_get_acc, patch(
|
2021-03-07 00:30:57 +00:00
|
|
|
"pyhap.accessory_driver.AccessoryDriver.async_start"
|
2020-09-10 21:19:11 +00:00
|
|
|
):
|
|
|
|
await homekit.async_start()
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
|
|
|
|
mock_get_acc.assert_called_with(
|
|
|
|
hass,
|
2021-03-12 06:05:03 +00:00
|
|
|
ANY,
|
2020-09-10 21:19:11 +00:00
|
|
|
ANY,
|
|
|
|
ANY,
|
|
|
|
{
|
|
|
|
"model": "Powerwall 2",
|
|
|
|
"sw_version": "0.16.0",
|
|
|
|
"platform": "invalid_integration_does_not_exist",
|
|
|
|
"linked_battery_charging_sensor": "binary_sensor.invalid_integration_does_not_exist_battery_charging",
|
|
|
|
"linked_battery_sensor": "sensor.invalid_integration_does_not_exist_battery",
|
|
|
|
},
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2021-11-19 04:23:20 +00:00
|
|
|
async def test_yaml_updates_update_config_entry_for_name(hass, mock_async_zeroconf):
|
2020-05-01 04:05:06 +00:00
|
|
|
"""Test async_setup with imported config."""
|
2021-10-07 10:58:00 +00:00
|
|
|
|
2020-05-01 04:05:06 +00:00
|
|
|
entry = MockConfigEntry(
|
|
|
|
domain=DOMAIN,
|
|
|
|
source=SOURCE_IMPORT,
|
|
|
|
data={CONF_NAME: BRIDGE_NAME, CONF_PORT: DEFAULT_PORT},
|
|
|
|
options={},
|
|
|
|
)
|
|
|
|
entry.add_to_hass(hass)
|
|
|
|
|
2021-07-14 09:44:58 +00:00
|
|
|
with patch(f"{PATH_HOMEKIT}.HomeKit") as mock_homekit, patch(
|
|
|
|
"homeassistant.components.network.async_get_source_ip", return_value="1.2.3.4"
|
|
|
|
):
|
2020-05-01 04:05:06 +00:00
|
|
|
mock_homekit.return_value = homekit = Mock()
|
|
|
|
type(homekit).async_start = AsyncMock()
|
|
|
|
assert await async_setup_component(
|
|
|
|
hass, "homekit", {"homekit": {CONF_NAME: BRIDGE_NAME, CONF_PORT: 12345}}
|
|
|
|
)
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
|
|
|
|
mock_homekit.assert_any_call(
|
|
|
|
hass,
|
|
|
|
BRIDGE_NAME,
|
|
|
|
12345,
|
2021-07-14 09:44:58 +00:00
|
|
|
"1.2.3.4",
|
2020-05-01 04:05:06 +00:00
|
|
|
ANY,
|
2021-02-24 00:22:23 +00:00
|
|
|
ANY,
|
2020-05-01 04:05:06 +00:00
|
|
|
{},
|
2020-10-15 16:59:50 +00:00
|
|
|
HOMEKIT_MODE_BRIDGE,
|
2020-05-01 04:05:06 +00:00
|
|
|
None,
|
|
|
|
entry.entry_id,
|
2021-02-24 00:22:23 +00:00
|
|
|
entry.title,
|
2021-08-25 14:47:39 +00:00
|
|
|
devices=[],
|
2020-05-01 04:05:06 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
# Test auto start enabled
|
|
|
|
mock_homekit.reset_mock()
|
2021-02-12 18:45:19 +00:00
|
|
|
hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
|
2020-05-01 04:05:06 +00:00
|
|
|
await hass.async_block_till_done()
|
|
|
|
|
|
|
|
mock_homekit().async_start.assert_called()
|
|
|
|
|
|
|
|
|
2021-11-19 04:23:20 +00:00
|
|
|
async def test_homekit_uses_system_zeroconf(hass, hk_driver, mock_async_zeroconf):
|
2020-05-11 18:21:16 +00:00
|
|
|
"""Test HomeKit uses system zeroconf."""
|
|
|
|
entry = MockConfigEntry(
|
|
|
|
domain=DOMAIN,
|
|
|
|
data={CONF_NAME: BRIDGE_NAME, CONF_PORT: DEFAULT_PORT},
|
|
|
|
options={},
|
|
|
|
)
|
2020-09-13 23:06:19 +00:00
|
|
|
assert await async_setup_component(hass, "zeroconf", {"zeroconf": {}})
|
2021-05-31 18:47:12 +00:00
|
|
|
system_async_zc = await zeroconf.async_get_async_instance(hass)
|
2020-05-11 18:21:16 +00:00
|
|
|
|
2021-03-07 00:30:57 +00:00
|
|
|
with patch("pyhap.accessory_driver.AccessoryDriver.async_start"), patch(
|
2020-07-07 22:14:58 +00:00
|
|
|
f"{PATH_HOMEKIT}.HomeKit.async_stop"
|
2021-09-04 03:15:28 +00:00
|
|
|
), patch(f"{PATH_HOMEKIT}.async_port_is_available"):
|
2020-07-07 22:14:58 +00:00
|
|
|
entry.add_to_hass(hass)
|
|
|
|
assert await hass.config_entries.async_setup(entry.entry_id)
|
|
|
|
await hass.async_block_till_done()
|
2021-05-31 18:47:12 +00:00
|
|
|
assert (
|
|
|
|
hass.data[DOMAIN][entry.entry_id][HOMEKIT].driver.advertiser
|
|
|
|
== system_async_zc
|
|
|
|
)
|
2020-07-07 22:14:58 +00:00
|
|
|
assert await hass.config_entries.async_unload(entry.entry_id)
|
|
|
|
await hass.async_block_till_done()
|
2020-05-11 18:21:16 +00:00
|
|
|
|
|
|
|
|
2021-03-18 14:13:22 +00:00
|
|
|
def _write_data(path: str, data: dict) -> None:
|
2020-05-01 04:05:06 +00:00
|
|
|
"""Write the data."""
|
2021-12-23 08:59:31 +00:00
|
|
|
os.makedirs(os.path.dirname(path), exist_ok=True)
|
2020-05-01 04:05:06 +00:00
|
|
|
json_util.save_json(path, data)
|
2020-05-21 08:30:18 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def test_homekit_ignored_missing_devices(
|
2021-11-19 04:23:20 +00:00
|
|
|
hass, hk_driver, device_reg, entity_reg, mock_async_zeroconf
|
2020-05-21 08:30:18 +00:00
|
|
|
):
|
|
|
|
"""Test HomeKit handles a device in the entity registry but missing from the device registry."""
|
2021-10-07 10:58:00 +00:00
|
|
|
|
2020-05-21 08:30:18 +00:00
|
|
|
entry = await async_init_integration(hass)
|
2021-02-24 00:22:23 +00:00
|
|
|
homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_BRIDGE)
|
2020-05-21 08:30:18 +00:00
|
|
|
|
|
|
|
homekit.driver = hk_driver
|
2021-03-12 06:05:03 +00:00
|
|
|
homekit.bridge = _mock_pyhap_bridge()
|
2020-05-21 08:30:18 +00:00
|
|
|
|
|
|
|
config_entry = MockConfigEntry(domain="test", data={})
|
|
|
|
config_entry.add_to_hass(hass)
|
|
|
|
device_entry = device_reg.async_get_or_create(
|
|
|
|
config_entry_id=config_entry.entry_id,
|
|
|
|
sw_version="0.16.0",
|
|
|
|
model="Powerwall 2",
|
|
|
|
manufacturer="Tesla",
|
|
|
|
connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")},
|
|
|
|
)
|
|
|
|
|
|
|
|
entity_reg.async_get_or_create(
|
|
|
|
"binary_sensor",
|
|
|
|
"powerwall",
|
|
|
|
"battery_charging",
|
|
|
|
device_id=device_entry.id,
|
2021-12-20 18:53:44 +00:00
|
|
|
original_device_class=BinarySensorDeviceClass.BATTERY_CHARGING,
|
2020-05-21 08:30:18 +00:00
|
|
|
)
|
|
|
|
entity_reg.async_get_or_create(
|
|
|
|
"sensor",
|
|
|
|
"powerwall",
|
|
|
|
"battery",
|
|
|
|
device_id=device_entry.id,
|
2021-12-20 18:53:44 +00:00
|
|
|
original_device_class=SensorDeviceClass.BATTERY,
|
2020-05-21 08:30:18 +00:00
|
|
|
)
|
|
|
|
light = entity_reg.async_get_or_create(
|
|
|
|
"light", "powerwall", "demo", device_id=device_entry.id
|
|
|
|
)
|
2021-03-12 06:05:03 +00:00
|
|
|
before_removal = entity_reg.entities.copy()
|
2020-05-21 08:30:18 +00:00
|
|
|
# Delete the device to make sure we fallback
|
|
|
|
# to using the platform
|
|
|
|
device_reg.async_remove_device(device_entry.id)
|
2021-03-12 06:05:03 +00:00
|
|
|
# Wait for the entities to be removed
|
|
|
|
await asyncio.sleep(0)
|
|
|
|
await asyncio.sleep(0)
|
|
|
|
# Restore the registry
|
|
|
|
entity_reg.entities = before_removal
|
2020-05-21 08:30:18 +00:00
|
|
|
|
|
|
|
hass.states.async_set(light.entity_id, STATE_ON)
|
2020-10-15 16:59:50 +00:00
|
|
|
hass.states.async_set("light.two", STATE_ON)
|
2020-05-21 08:30:18 +00:00
|
|
|
|
2021-03-12 06:05:03 +00:00
|
|
|
with patch(f"{PATH_HOMEKIT}.get_accessory") as mock_get_acc, patch(
|
|
|
|
f"{PATH_HOMEKIT}.HomeBridge", return_value=homekit.bridge
|
|
|
|
), patch("pyhap.accessory_driver.AccessoryDriver.async_start"):
|
2020-05-21 08:30:18 +00:00
|
|
|
await homekit.async_start()
|
2021-03-12 06:05:03 +00:00
|
|
|
await hass.async_block_till_done()
|
2020-05-21 08:30:18 +00:00
|
|
|
|
2020-10-15 16:59:50 +00:00
|
|
|
mock_get_acc.assert_any_call(
|
2020-05-21 08:30:18 +00:00
|
|
|
hass,
|
2021-03-12 06:05:03 +00:00
|
|
|
ANY,
|
2020-05-21 08:30:18 +00:00
|
|
|
ANY,
|
|
|
|
ANY,
|
|
|
|
{
|
|
|
|
"platform": "Tesla Powerwall",
|
|
|
|
"linked_battery_charging_sensor": "binary_sensor.powerwall_battery_charging",
|
|
|
|
"linked_battery_sensor": "sensor.powerwall_battery",
|
|
|
|
},
|
|
|
|
)
|
2020-05-25 23:05:38 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def test_homekit_finds_linked_motion_sensors(
|
2021-11-19 04:23:20 +00:00
|
|
|
hass, hk_driver, device_reg, entity_reg, mock_async_zeroconf
|
2020-05-25 23:05:38 +00:00
|
|
|
):
|
|
|
|
"""Test HomeKit start method."""
|
|
|
|
entry = await async_init_integration(hass)
|
|
|
|
|
2021-02-24 00:22:23 +00:00
|
|
|
homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_BRIDGE)
|
|
|
|
|
2020-05-25 23:05:38 +00:00
|
|
|
homekit.driver = hk_driver
|
|
|
|
homekit.bridge = HomeBridge(hass, hk_driver, "mock_bridge")
|
|
|
|
|
|
|
|
config_entry = MockConfigEntry(domain="test", data={})
|
|
|
|
config_entry.add_to_hass(hass)
|
|
|
|
device_entry = device_reg.async_get_or_create(
|
|
|
|
config_entry_id=config_entry.entry_id,
|
|
|
|
sw_version="0.16.0",
|
|
|
|
model="Camera Server",
|
|
|
|
manufacturer="Ubq",
|
|
|
|
connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")},
|
|
|
|
)
|
|
|
|
|
|
|
|
binary_motion_sensor = entity_reg.async_get_or_create(
|
|
|
|
"binary_sensor",
|
|
|
|
"camera",
|
|
|
|
"motion_sensor",
|
|
|
|
device_id=device_entry.id,
|
2021-12-20 18:53:44 +00:00
|
|
|
original_device_class=BinarySensorDeviceClass.MOTION,
|
2020-05-25 23:05:38 +00:00
|
|
|
)
|
|
|
|
camera = entity_reg.async_get_or_create(
|
|
|
|
"camera", "camera", "demo", device_id=device_entry.id
|
|
|
|
)
|
|
|
|
|
|
|
|
hass.states.async_set(
|
|
|
|
binary_motion_sensor.entity_id,
|
|
|
|
STATE_ON,
|
2021-12-20 18:53:44 +00:00
|
|
|
{ATTR_DEVICE_CLASS: BinarySensorDeviceClass.MOTION},
|
2020-05-25 23:05:38 +00:00
|
|
|
)
|
|
|
|
hass.states.async_set(camera.entity_id, STATE_ON)
|
|
|
|
|
|
|
|
with patch.object(homekit.bridge, "add_accessory"), patch(
|
2021-11-23 17:40:20 +00:00
|
|
|
f"{PATH_HOMEKIT}.async_show_setup_message"
|
2020-05-25 23:05:38 +00:00
|
|
|
), patch(f"{PATH_HOMEKIT}.get_accessory") as mock_get_acc, patch(
|
2021-03-07 00:30:57 +00:00
|
|
|
"pyhap.accessory_driver.AccessoryDriver.async_start"
|
2020-05-25 23:05:38 +00:00
|
|
|
):
|
|
|
|
await homekit.async_start()
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
|
|
|
|
mock_get_acc.assert_called_with(
|
|
|
|
hass,
|
2021-03-12 06:05:03 +00:00
|
|
|
ANY,
|
2020-05-25 23:05:38 +00:00
|
|
|
ANY,
|
|
|
|
ANY,
|
|
|
|
{
|
|
|
|
"manufacturer": "Ubq",
|
|
|
|
"model": "Camera Server",
|
2021-08-25 14:47:39 +00:00
|
|
|
"platform": "test",
|
2020-05-25 23:05:38 +00:00
|
|
|
"sw_version": "0.16.0",
|
|
|
|
"linked_motion_sensor": "binary_sensor.camera_motion_sensor",
|
|
|
|
},
|
|
|
|
)
|
2020-07-02 17:53:11 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def test_homekit_finds_linked_humidity_sensors(
|
2021-11-19 04:23:20 +00:00
|
|
|
hass, hk_driver, device_reg, entity_reg, mock_async_zeroconf
|
2020-07-02 17:53:11 +00:00
|
|
|
):
|
|
|
|
"""Test HomeKit start method."""
|
|
|
|
entry = await async_init_integration(hass)
|
|
|
|
|
2021-02-24 00:22:23 +00:00
|
|
|
homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_BRIDGE)
|
|
|
|
|
2020-07-02 17:53:11 +00:00
|
|
|
homekit.driver = hk_driver
|
|
|
|
homekit.bridge = HomeBridge(hass, hk_driver, "mock_bridge")
|
|
|
|
|
|
|
|
config_entry = MockConfigEntry(domain="test", data={})
|
|
|
|
config_entry.add_to_hass(hass)
|
|
|
|
device_entry = device_reg.async_get_or_create(
|
|
|
|
config_entry_id=config_entry.entry_id,
|
|
|
|
sw_version="0.16.1",
|
|
|
|
model="Smart Brainy Clever Humidifier",
|
|
|
|
manufacturer="Home Assistant",
|
|
|
|
connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")},
|
|
|
|
)
|
|
|
|
|
|
|
|
humidity_sensor = entity_reg.async_get_or_create(
|
|
|
|
"sensor",
|
|
|
|
"humidifier",
|
|
|
|
"humidity_sensor",
|
|
|
|
device_id=device_entry.id,
|
2021-12-20 18:53:44 +00:00
|
|
|
original_device_class=SensorDeviceClass.HUMIDITY,
|
2020-07-02 17:53:11 +00:00
|
|
|
)
|
|
|
|
humidifier = entity_reg.async_get_or_create(
|
|
|
|
"humidifier", "humidifier", "demo", device_id=device_entry.id
|
|
|
|
)
|
|
|
|
|
|
|
|
hass.states.async_set(
|
|
|
|
humidity_sensor.entity_id,
|
|
|
|
"42",
|
|
|
|
{
|
2021-12-20 18:53:44 +00:00
|
|
|
ATTR_DEVICE_CLASS: SensorDeviceClass.HUMIDITY,
|
2020-09-05 19:09:14 +00:00
|
|
|
ATTR_UNIT_OF_MEASUREMENT: PERCENTAGE,
|
2020-07-02 17:53:11 +00:00
|
|
|
},
|
|
|
|
)
|
|
|
|
hass.states.async_set(humidifier.entity_id, STATE_ON)
|
|
|
|
|
|
|
|
with patch.object(homekit.bridge, "add_accessory"), patch(
|
2021-11-23 17:40:20 +00:00
|
|
|
f"{PATH_HOMEKIT}.async_show_setup_message"
|
2020-07-02 17:53:11 +00:00
|
|
|
), patch(f"{PATH_HOMEKIT}.get_accessory") as mock_get_acc, patch(
|
2021-03-07 00:30:57 +00:00
|
|
|
"pyhap.accessory_driver.AccessoryDriver.async_start"
|
2020-07-02 17:53:11 +00:00
|
|
|
):
|
|
|
|
await homekit.async_start()
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
|
|
|
|
mock_get_acc.assert_called_with(
|
|
|
|
hass,
|
2021-03-12 06:05:03 +00:00
|
|
|
ANY,
|
2020-07-02 17:53:11 +00:00
|
|
|
ANY,
|
|
|
|
ANY,
|
|
|
|
{
|
|
|
|
"manufacturer": "Home Assistant",
|
|
|
|
"model": "Smart Brainy Clever Humidifier",
|
2021-08-25 14:47:39 +00:00
|
|
|
"platform": "test",
|
2020-07-02 17:53:11 +00:00
|
|
|
"sw_version": "0.16.1",
|
|
|
|
"linked_humidity_sensor": "sensor.humidifier_humidity_sensor",
|
|
|
|
},
|
|
|
|
)
|
2020-08-28 14:46:45 +00:00
|
|
|
|
|
|
|
|
2021-11-19 04:23:20 +00:00
|
|
|
async def test_reload(hass, mock_async_zeroconf):
|
2020-08-28 14:46:45 +00:00
|
|
|
"""Test we can reload from yaml."""
|
2021-10-07 10:58:00 +00:00
|
|
|
|
2020-08-28 14:46:45 +00:00
|
|
|
entry = MockConfigEntry(
|
|
|
|
domain=DOMAIN,
|
|
|
|
source=SOURCE_IMPORT,
|
|
|
|
data={CONF_NAME: "reloadable", CONF_PORT: 12345},
|
|
|
|
options={},
|
|
|
|
)
|
|
|
|
entry.add_to_hass(hass)
|
|
|
|
|
2021-07-14 09:44:58 +00:00
|
|
|
with patch(f"{PATH_HOMEKIT}.HomeKit") as mock_homekit, patch(
|
|
|
|
"homeassistant.components.network.async_get_source_ip", return_value="1.2.3.4"
|
|
|
|
):
|
2020-08-28 14:46:45 +00:00
|
|
|
mock_homekit.return_value = homekit = Mock()
|
|
|
|
assert await async_setup_component(
|
|
|
|
hass, "homekit", {"homekit": {CONF_NAME: "reloadable", CONF_PORT: 12345}}
|
|
|
|
)
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
|
|
|
|
mock_homekit.assert_any_call(
|
|
|
|
hass,
|
|
|
|
"reloadable",
|
|
|
|
12345,
|
2021-07-14 09:44:58 +00:00
|
|
|
"1.2.3.4",
|
2020-08-28 14:46:45 +00:00
|
|
|
ANY,
|
2021-02-24 00:22:23 +00:00
|
|
|
False,
|
2020-08-28 14:46:45 +00:00
|
|
|
{},
|
2020-10-15 16:59:50 +00:00
|
|
|
HOMEKIT_MODE_BRIDGE,
|
2020-08-28 14:46:45 +00:00
|
|
|
None,
|
|
|
|
entry.entry_id,
|
2021-02-24 00:22:23 +00:00
|
|
|
entry.title,
|
2021-08-25 14:47:39 +00:00
|
|
|
devices=[],
|
2020-08-28 14:46:45 +00:00
|
|
|
)
|
2021-11-02 03:47:05 +00:00
|
|
|
yaml_path = get_fixture_path("configuration.yaml", "homekit")
|
2020-08-28 14:46:45 +00:00
|
|
|
with patch.object(hass_config, "YAML_CONFIG_FILE", yaml_path), patch(
|
|
|
|
f"{PATH_HOMEKIT}.HomeKit"
|
2020-09-10 21:19:11 +00:00
|
|
|
) as mock_homekit2, patch.object(homekit.bridge, "add_accessory"), patch(
|
2021-11-23 17:40:20 +00:00
|
|
|
f"{PATH_HOMEKIT}.async_show_setup_message"
|
2020-09-10 21:19:11 +00:00
|
|
|
), patch(
|
|
|
|
f"{PATH_HOMEKIT}.get_accessory"
|
|
|
|
), patch(
|
2021-03-07 00:30:57 +00:00
|
|
|
"pyhap.accessory_driver.AccessoryDriver.async_start"
|
2021-07-14 09:44:58 +00:00
|
|
|
), patch(
|
|
|
|
"homeassistant.components.network.async_get_source_ip", return_value="1.2.3.4"
|
2020-09-10 21:19:11 +00:00
|
|
|
):
|
2020-08-28 14:46:45 +00:00
|
|
|
mock_homekit2.return_value = homekit = Mock()
|
|
|
|
await hass.services.async_call(
|
|
|
|
"homekit",
|
|
|
|
SERVICE_RELOAD,
|
|
|
|
{},
|
|
|
|
blocking=True,
|
|
|
|
)
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
|
|
|
|
mock_homekit2.assert_any_call(
|
|
|
|
hass,
|
|
|
|
"reloadable",
|
|
|
|
45678,
|
2021-07-14 09:44:58 +00:00
|
|
|
"1.2.3.4",
|
2020-08-28 14:46:45 +00:00
|
|
|
ANY,
|
2021-02-24 00:22:23 +00:00
|
|
|
False,
|
2020-08-28 14:46:45 +00:00
|
|
|
{},
|
2020-10-15 16:59:50 +00:00
|
|
|
HOMEKIT_MODE_BRIDGE,
|
2020-08-28 14:46:45 +00:00
|
|
|
None,
|
|
|
|
entry.entry_id,
|
2021-02-24 00:22:23 +00:00
|
|
|
entry.title,
|
2021-08-25 14:47:39 +00:00
|
|
|
devices=[],
|
2020-08-28 14:46:45 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
2021-03-12 06:05:03 +00:00
|
|
|
async def test_homekit_start_in_accessory_mode(
|
2021-11-19 04:23:20 +00:00
|
|
|
hass, hk_driver, mock_async_zeroconf, device_reg
|
2021-03-12 06:05:03 +00:00
|
|
|
):
|
2020-10-15 16:59:50 +00:00
|
|
|
"""Test HomeKit start method in accessory mode."""
|
|
|
|
entry = await async_init_integration(hass)
|
|
|
|
|
2021-02-24 00:22:23 +00:00
|
|
|
homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_ACCESSORY)
|
|
|
|
|
2020-10-15 16:59:50 +00:00
|
|
|
homekit.bridge = Mock()
|
|
|
|
homekit.bridge.accessories = []
|
|
|
|
homekit.driver = hk_driver
|
|
|
|
homekit.driver.accessory = Accessory(hk_driver, "any")
|
|
|
|
|
|
|
|
hass.states.async_set("light.demo", "on")
|
|
|
|
|
|
|
|
with patch(f"{PATH_HOMEKIT}.HomeKit.add_bridge_accessory") as mock_add_acc, patch(
|
2021-11-23 17:40:20 +00:00
|
|
|
f"{PATH_HOMEKIT}.async_show_setup_message"
|
2021-03-12 06:05:03 +00:00
|
|
|
) as mock_setup_msg, patch(
|
2021-03-07 00:30:57 +00:00
|
|
|
"pyhap.accessory_driver.AccessoryDriver.async_start"
|
2020-10-15 16:59:50 +00:00
|
|
|
) as hk_driver_start:
|
|
|
|
await homekit.async_start()
|
|
|
|
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
mock_add_acc.assert_not_called()
|
2021-02-24 00:22:23 +00:00
|
|
|
mock_setup_msg.assert_called_with(
|
2021-03-12 06:05:03 +00:00
|
|
|
hass, entry.entry_id, "Mock Title (demo)", ANY, ANY
|
2021-02-24 00:22:23 +00:00
|
|
|
)
|
2020-10-15 16:59:50 +00:00
|
|
|
assert hk_driver_start.called
|
|
|
|
assert homekit.status == STATUS_RUNNING
|
2021-03-15 04:14:46 +00:00
|
|
|
|
|
|
|
|
2021-07-18 19:27:25 +00:00
|
|
|
async def test_homekit_start_in_accessory_mode_unsupported_entity(
|
2021-11-19 04:23:20 +00:00
|
|
|
hass, hk_driver, mock_async_zeroconf, device_reg, caplog
|
2021-07-18 19:27:25 +00:00
|
|
|
):
|
|
|
|
"""Test HomeKit start method in accessory mode with an unsupported entity."""
|
|
|
|
entry = await async_init_integration(hass)
|
|
|
|
|
|
|
|
homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_ACCESSORY)
|
|
|
|
|
|
|
|
homekit.bridge = Mock()
|
|
|
|
homekit.bridge.accessories = []
|
|
|
|
homekit.driver = hk_driver
|
|
|
|
homekit.driver.accessory = Accessory(hk_driver, "any")
|
|
|
|
|
|
|
|
hass.states.async_set("notsupported.demo", "on")
|
|
|
|
|
|
|
|
with patch(f"{PATH_HOMEKIT}.HomeKit.add_bridge_accessory") as mock_add_acc, patch(
|
2021-11-23 17:40:20 +00:00
|
|
|
f"{PATH_HOMEKIT}.async_show_setup_message"
|
2021-07-18 19:27:25 +00:00
|
|
|
) as mock_setup_msg, patch(
|
|
|
|
"pyhap.accessory_driver.AccessoryDriver.async_start"
|
|
|
|
) as hk_driver_start:
|
|
|
|
await homekit.async_start()
|
|
|
|
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
assert not mock_add_acc.called
|
|
|
|
assert not mock_setup_msg.called
|
|
|
|
assert not hk_driver_start.called
|
|
|
|
assert homekit.status == STATUS_WAIT
|
|
|
|
assert "entity not supported" in caplog.text
|
|
|
|
|
|
|
|
|
2021-06-13 22:27:04 +00:00
|
|
|
async def test_homekit_start_in_accessory_mode_missing_entity(
|
2021-11-19 04:23:20 +00:00
|
|
|
hass, hk_driver, mock_async_zeroconf, device_reg, caplog
|
2021-06-13 22:27:04 +00:00
|
|
|
):
|
|
|
|
"""Test HomeKit start method in accessory mode when entity is not available."""
|
|
|
|
entry = await async_init_integration(hass)
|
|
|
|
|
|
|
|
homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_ACCESSORY)
|
|
|
|
|
|
|
|
homekit.bridge = Mock()
|
|
|
|
homekit.bridge.accessories = []
|
|
|
|
homekit.driver = hk_driver
|
|
|
|
homekit.driver.accessory = Accessory(hk_driver, "any")
|
|
|
|
|
|
|
|
with patch(f"{PATH_HOMEKIT}.HomeKit.add_bridge_accessory") as mock_add_acc, patch(
|
2021-11-23 17:40:20 +00:00
|
|
|
f"{PATH_HOMEKIT}.async_show_setup_message"
|
2021-06-13 22:27:04 +00:00
|
|
|
), patch("pyhap.accessory_driver.AccessoryDriver.async_start"):
|
|
|
|
await homekit.async_start()
|
|
|
|
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
mock_add_acc.assert_not_called()
|
|
|
|
assert homekit.status == STATUS_WAIT
|
|
|
|
|
|
|
|
assert "entity not available" in caplog.text
|
|
|
|
|
|
|
|
|
2021-11-19 04:23:20 +00:00
|
|
|
async def test_wait_for_port_to_free(hass, hk_driver, mock_async_zeroconf, caplog):
|
2021-03-15 04:14:46 +00:00
|
|
|
"""Test we wait for the port to free before declaring unload success."""
|
2021-10-07 10:58:00 +00:00
|
|
|
|
2021-03-15 04:14:46 +00:00
|
|
|
entry = MockConfigEntry(
|
|
|
|
domain=DOMAIN,
|
|
|
|
data={CONF_NAME: BRIDGE_NAME, CONF_PORT: DEFAULT_PORT},
|
|
|
|
options={},
|
|
|
|
)
|
|
|
|
entry.add_to_hass(hass)
|
|
|
|
|
|
|
|
with patch("pyhap.accessory_driver.AccessoryDriver.async_start"), patch(
|
|
|
|
f"{PATH_HOMEKIT}.HomeKit.async_stop"
|
2021-09-04 03:15:28 +00:00
|
|
|
), patch(f"{PATH_HOMEKIT}.async_port_is_available", return_value=True) as port_mock:
|
2021-03-15 04:14:46 +00:00
|
|
|
assert await hass.config_entries.async_setup(entry.entry_id)
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
assert await hass.config_entries.async_unload(entry.entry_id)
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
assert "Waiting for the HomeKit server to shutdown" not in caplog.text
|
|
|
|
assert port_mock.called
|
|
|
|
|
|
|
|
with patch("pyhap.accessory_driver.AccessoryDriver.async_start"), patch(
|
|
|
|
f"{PATH_HOMEKIT}.HomeKit.async_stop"
|
|
|
|
), patch.object(homekit_base, "PORT_CLEANUP_CHECK_INTERVAL_SECS", 0), patch(
|
2021-09-04 03:15:28 +00:00
|
|
|
f"{PATH_HOMEKIT}.async_port_is_available", return_value=False
|
2021-03-15 04:14:46 +00:00
|
|
|
) as port_mock:
|
|
|
|
assert await hass.config_entries.async_setup(entry.entry_id)
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
assert await hass.config_entries.async_unload(entry.entry_id)
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
assert "Waiting for the HomeKit server to shutdown" in caplog.text
|
|
|
|
assert port_mock.called
|