Resolve homekit cover adjustment slowness (#45730)
This commit is contained in:
parent
8be357ff4f
commit
dac9626112
8 changed files with 72 additions and 220 deletions
|
@ -1,7 +1,4 @@
|
|||
"""Extend the basic Accessory and Bridge functions."""
|
||||
from datetime import timedelta
|
||||
from functools import partial, wraps
|
||||
from inspect import getmodule
|
||||
import logging
|
||||
|
||||
from pyhap.accessory import Accessory, Bridge
|
||||
|
@ -37,11 +34,7 @@ from homeassistant.const import (
|
|||
__version__,
|
||||
)
|
||||
from homeassistant.core import Context, callback as ha_callback, split_entity_id
|
||||
from homeassistant.helpers.event import (
|
||||
async_track_state_change_event,
|
||||
track_point_in_utc_time,
|
||||
)
|
||||
from homeassistant.util import dt as dt_util
|
||||
from homeassistant.helpers.event import async_track_state_change_event
|
||||
from homeassistant.util.decorator import Registry
|
||||
|
||||
from .const import (
|
||||
|
@ -60,7 +53,6 @@ from .const import (
|
|||
CONF_LINKED_BATTERY_CHARGING_SENSOR,
|
||||
CONF_LINKED_BATTERY_SENSOR,
|
||||
CONF_LOW_BATTERY_THRESHOLD,
|
||||
DEBOUNCE_TIMEOUT,
|
||||
DEFAULT_LOW_BATTERY_THRESHOLD,
|
||||
DEVICE_CLASS_CO,
|
||||
DEVICE_CLASS_CO2,
|
||||
|
@ -98,37 +90,6 @@ SWITCH_TYPES = {
|
|||
TYPES = Registry()
|
||||
|
||||
|
||||
def debounce(func):
|
||||
"""Decorate function to debounce callbacks from HomeKit."""
|
||||
|
||||
@ha_callback
|
||||
def call_later_listener(self, *args):
|
||||
"""Handle call_later callback."""
|
||||
debounce_params = self.debounce.pop(func.__name__, None)
|
||||
if debounce_params:
|
||||
self.hass.async_add_executor_job(func, self, *debounce_params[1:])
|
||||
|
||||
@wraps(func)
|
||||
def wrapper(self, *args):
|
||||
"""Start async timer."""
|
||||
debounce_params = self.debounce.pop(func.__name__, None)
|
||||
if debounce_params:
|
||||
debounce_params[0]() # remove listener
|
||||
remove_listener = track_point_in_utc_time(
|
||||
self.hass,
|
||||
partial(call_later_listener, self),
|
||||
dt_util.utcnow() + timedelta(seconds=DEBOUNCE_TIMEOUT),
|
||||
)
|
||||
self.debounce[func.__name__] = (remove_listener, *args)
|
||||
logger.debug(
|
||||
"%s: Start %s timeout", self.entity_id, func.__name__.replace("set_", "")
|
||||
)
|
||||
|
||||
name = getmodule(func).__name__
|
||||
logger = logging.getLogger(name)
|
||||
return wrapper
|
||||
|
||||
|
||||
def get_accessory(hass, driver, state, aid, config):
|
||||
"""Take state and return an accessory object if supported."""
|
||||
if not aid:
|
||||
|
@ -278,7 +239,6 @@ class HomeAccessory(Accessory):
|
|||
self.category = category
|
||||
self.entity_id = entity_id
|
||||
self.hass = hass
|
||||
self.debounce = {}
|
||||
self._subscriptions = []
|
||||
self._char_battery = None
|
||||
self._char_charging = None
|
||||
|
|
|
@ -33,7 +33,7 @@ from homeassistant.const import (
|
|||
from homeassistant.core import callback
|
||||
from homeassistant.helpers.event import async_track_state_change_event
|
||||
|
||||
from .accessories import TYPES, HomeAccessory, debounce
|
||||
from .accessories import TYPES, HomeAccessory
|
||||
from .const import (
|
||||
ATTR_OBSTRUCTION_DETECTED,
|
||||
CHAR_CURRENT_DOOR_STATE,
|
||||
|
@ -233,7 +233,6 @@ class OpeningDeviceBase(HomeAccessory):
|
|||
return
|
||||
self.call_service(DOMAIN, SERVICE_STOP_COVER, {ATTR_ENTITY_ID: self.entity_id})
|
||||
|
||||
@debounce
|
||||
def set_tilt(self, value):
|
||||
"""Set tilt to value if call came from HomeKit."""
|
||||
_LOGGER.info("%s: Set tilt to %d", self.entity_id, value)
|
||||
|
@ -284,7 +283,6 @@ class OpeningDevice(OpeningDeviceBase, HomeAccessory):
|
|||
)
|
||||
self.async_update_state(state)
|
||||
|
||||
@debounce
|
||||
def move_cover(self, value):
|
||||
"""Move cover to value if call came from HomeKit."""
|
||||
_LOGGER.debug("%s: Set position to %d", self.entity_id, value)
|
||||
|
@ -360,7 +358,6 @@ class WindowCoveringBasic(OpeningDeviceBase, HomeAccessory):
|
|||
)
|
||||
self.async_update_state(state)
|
||||
|
||||
@debounce
|
||||
def move_cover(self, value):
|
||||
"""Move cover to value if call came from HomeKit."""
|
||||
_LOGGER.debug("%s: Set position to %d", self.entity_id, value)
|
||||
|
|
|
@ -1,17 +1,9 @@
|
|||
"""Collection of fixtures and functions for the HomeKit tests."""
|
||||
from unittest.mock import Mock, patch
|
||||
from unittest.mock import Mock
|
||||
|
||||
EMPTY_8_6_JPEG = b"empty_8_6"
|
||||
|
||||
|
||||
def patch_debounce():
|
||||
"""Return patch for debounce method."""
|
||||
return patch(
|
||||
"homeassistant.components.homekit.accessories.debounce",
|
||||
lambda f: lambda *args, **kwargs: f(*args, **kwargs),
|
||||
)
|
||||
|
||||
|
||||
def mock_turbo_jpeg(
|
||||
first_width=None, second_width=None, first_height=None, second_height=None
|
||||
):
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
This includes tests for all mock object types.
|
||||
"""
|
||||
from datetime import timedelta
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
import pytest
|
||||
|
@ -11,7 +10,6 @@ from homeassistant.components.homekit.accessories import (
|
|||
HomeAccessory,
|
||||
HomeBridge,
|
||||
HomeDriver,
|
||||
debounce,
|
||||
)
|
||||
from homeassistant.components.homekit.const import (
|
||||
ATTR_DISPLAY_NAME,
|
||||
|
@ -45,41 +43,8 @@ from homeassistant.const import (
|
|||
__version__,
|
||||
)
|
||||
from homeassistant.helpers.event import TRACK_STATE_CHANGE_CALLBACKS
|
||||
import homeassistant.util.dt as dt_util
|
||||
|
||||
from tests.common import async_fire_time_changed, async_mock_service
|
||||
|
||||
|
||||
async def test_debounce(hass):
|
||||
"""Test add_timeout decorator function."""
|
||||
|
||||
def demo_func(*args):
|
||||
nonlocal arguments, counter
|
||||
counter += 1
|
||||
arguments = args
|
||||
|
||||
arguments = None
|
||||
counter = 0
|
||||
mock = Mock(hass=hass, debounce={})
|
||||
|
||||
debounce_demo = debounce(demo_func)
|
||||
assert debounce_demo.__name__ == "demo_func"
|
||||
now = dt_util.utcnow()
|
||||
|
||||
with patch("homeassistant.util.dt.utcnow", return_value=now):
|
||||
await hass.async_add_executor_job(debounce_demo, mock, "value")
|
||||
async_fire_time_changed(hass, now + timedelta(seconds=3))
|
||||
await hass.async_block_till_done()
|
||||
assert counter == 1
|
||||
assert len(arguments) == 2
|
||||
|
||||
with patch("homeassistant.util.dt.utcnow", return_value=now):
|
||||
await hass.async_add_executor_job(debounce_demo, mock, "value")
|
||||
await hass.async_add_executor_job(debounce_demo, mock, "value")
|
||||
|
||||
async_fire_time_changed(hass, now + timedelta(seconds=3))
|
||||
await hass.async_block_till_done()
|
||||
assert counter == 2
|
||||
from tests.common import async_mock_service
|
||||
|
||||
|
||||
async def test_accessory_cancels_track_state_change_on_stop(hass, hk_driver):
|
||||
|
|
|
@ -67,7 +67,6 @@ from homeassistant.util import json as json_util
|
|||
from .util import PATH_HOMEKIT, async_init_entry, async_init_integration
|
||||
|
||||
from tests.common import MockConfigEntry, mock_device_registry, mock_registry
|
||||
from tests.components.homekit.common import patch_debounce
|
||||
|
||||
IP_ADDRESS = "127.0.0.1"
|
||||
|
||||
|
@ -89,14 +88,6 @@ def entity_reg_fixture(hass):
|
|||
return mock_registry(hass)
|
||||
|
||||
|
||||
@pytest.fixture(name="debounce_patcher", scope="module")
|
||||
def debounce_patcher_fixture():
|
||||
"""Patch debounce method."""
|
||||
patcher = patch_debounce()
|
||||
yield patcher.start()
|
||||
patcher.stop()
|
||||
|
||||
|
||||
async def test_setup_min(hass, mock_zeroconf):
|
||||
"""Test async_setup with min config options."""
|
||||
entry = MockConfigEntry(
|
||||
|
@ -485,7 +476,7 @@ async def test_homekit_entity_glob_filter(hass, mock_zeroconf):
|
|||
mock_get_acc.reset_mock()
|
||||
|
||||
|
||||
async def test_homekit_start(hass, hk_driver, device_reg, debounce_patcher):
|
||||
async def test_homekit_start(hass, hk_driver, device_reg):
|
||||
"""Test HomeKit start method."""
|
||||
entry = await async_init_integration(hass)
|
||||
|
||||
|
@ -573,9 +564,7 @@ async def test_homekit_start(hass, hk_driver, device_reg, debounce_patcher):
|
|||
assert len(device_reg.devices) == 1
|
||||
|
||||
|
||||
async def test_homekit_start_with_a_broken_accessory(
|
||||
hass, hk_driver, debounce_patcher, mock_zeroconf
|
||||
):
|
||||
async def test_homekit_start_with_a_broken_accessory(hass, hk_driver, mock_zeroconf):
|
||||
"""Test HomeKit start method."""
|
||||
pin = b"123-45-678"
|
||||
entry = MockConfigEntry(
|
||||
|
@ -754,7 +743,7 @@ async def test_homekit_too_many_accessories(hass, hk_driver, caplog, mock_zeroco
|
|||
|
||||
|
||||
async def test_homekit_finds_linked_batteries(
|
||||
hass, hk_driver, debounce_patcher, device_reg, entity_reg, mock_zeroconf
|
||||
hass, hk_driver, device_reg, entity_reg, mock_zeroconf
|
||||
):
|
||||
"""Test HomeKit start method."""
|
||||
entry = await async_init_integration(hass)
|
||||
|
@ -840,7 +829,7 @@ async def test_homekit_finds_linked_batteries(
|
|||
|
||||
|
||||
async def test_homekit_async_get_integration_fails(
|
||||
hass, hk_driver, debounce_patcher, device_reg, entity_reg, mock_zeroconf
|
||||
hass, hk_driver, device_reg, entity_reg, mock_zeroconf
|
||||
):
|
||||
"""Test that we continue if async_get_integration fails."""
|
||||
entry = await async_init_integration(hass)
|
||||
|
@ -1072,7 +1061,7 @@ def _write_data(path: str, data: Dict) -> None:
|
|||
|
||||
|
||||
async def test_homekit_ignored_missing_devices(
|
||||
hass, hk_driver, debounce_patcher, 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."""
|
||||
entry = await async_init_integration(hass)
|
||||
|
@ -1153,7 +1142,7 @@ async def test_homekit_ignored_missing_devices(
|
|||
|
||||
|
||||
async def test_homekit_finds_linked_motion_sensors(
|
||||
hass, hk_driver, debounce_patcher, device_reg, entity_reg, mock_zeroconf
|
||||
hass, hk_driver, device_reg, entity_reg, mock_zeroconf
|
||||
):
|
||||
"""Test HomeKit start method."""
|
||||
entry = await async_init_integration(hass)
|
||||
|
@ -1228,7 +1217,7 @@ async def test_homekit_finds_linked_motion_sensors(
|
|||
|
||||
|
||||
async def test_homekit_finds_linked_humidity_sensors(
|
||||
hass, hk_driver, debounce_patcher, device_reg, entity_reg, mock_zeroconf
|
||||
hass, hk_driver, device_reg, entity_reg, mock_zeroconf
|
||||
):
|
||||
"""Test HomeKit start method."""
|
||||
entry = await async_init_integration(hass)
|
||||
|
@ -1376,9 +1365,7 @@ def _get_fixtures_base_path():
|
|||
return os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
|
||||
|
||||
|
||||
async def test_homekit_start_in_accessory_mode(
|
||||
hass, hk_driver, device_reg, debounce_patcher
|
||||
):
|
||||
async def test_homekit_start_in_accessory_mode(hass, hk_driver, device_reg):
|
||||
"""Test HomeKit start method in accessory mode."""
|
||||
entry = await async_init_integration(hass)
|
||||
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
"""Test different accessory types: Covers."""
|
||||
from collections import namedtuple
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.cover import (
|
||||
ATTR_CURRENT_POSITION,
|
||||
|
@ -22,6 +19,12 @@ from homeassistant.components.homekit.const import (
|
|||
HK_DOOR_OPEN,
|
||||
HK_DOOR_OPENING,
|
||||
)
|
||||
from homeassistant.components.homekit.type_covers import (
|
||||
GarageDoorOpener,
|
||||
Window,
|
||||
WindowCovering,
|
||||
WindowCoveringBasic,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
ATTR_ENTITY_ID,
|
||||
ATTR_SUPPORTED_FEATURES,
|
||||
|
@ -40,37 +43,15 @@ from homeassistant.core import CoreState
|
|||
from homeassistant.helpers import entity_registry
|
||||
|
||||
from tests.common import async_mock_service
|
||||
from tests.components.homekit.common import patch_debounce
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def cls():
|
||||
"""Patch debounce decorator during import of type_covers."""
|
||||
patcher = patch_debounce()
|
||||
patcher.start()
|
||||
_import = __import__(
|
||||
"homeassistant.components.homekit.type_covers",
|
||||
fromlist=["GarageDoorOpener", "WindowCovering", "WindowCoveringBasic"],
|
||||
)
|
||||
patcher_tuple = namedtuple(
|
||||
"Cls", ["window", "windowcovering", "windowcovering_basic", "garage"]
|
||||
)
|
||||
yield patcher_tuple(
|
||||
window=_import.Window,
|
||||
windowcovering=_import.WindowCovering,
|
||||
windowcovering_basic=_import.WindowCoveringBasic,
|
||||
garage=_import.GarageDoorOpener,
|
||||
)
|
||||
patcher.stop()
|
||||
|
||||
|
||||
async def test_garage_door_open_close(hass, hk_driver, cls, events):
|
||||
async def test_garage_door_open_close(hass, hk_driver, events):
|
||||
"""Test if accessory and HA are updated accordingly."""
|
||||
entity_id = "cover.garage_door"
|
||||
|
||||
hass.states.async_set(entity_id, None)
|
||||
await hass.async_block_till_done()
|
||||
acc = cls.garage(hass, hk_driver, "Garage Door", entity_id, 2, None)
|
||||
acc = GarageDoorOpener(hass, hk_driver, "Garage Door", entity_id, 2, None)
|
||||
await acc.run_handler()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
|
@ -148,13 +129,13 @@ async def test_garage_door_open_close(hass, hk_driver, cls, events):
|
|||
assert events[-1].data[ATTR_VALUE] is None
|
||||
|
||||
|
||||
async def test_windowcovering_set_cover_position(hass, hk_driver, cls, events):
|
||||
async def test_windowcovering_set_cover_position(hass, hk_driver, events):
|
||||
"""Test if accessory and HA are updated accordingly."""
|
||||
entity_id = "cover.window"
|
||||
|
||||
hass.states.async_set(entity_id, None)
|
||||
await hass.async_block_till_done()
|
||||
acc = cls.windowcovering(hass, hk_driver, "Cover", entity_id, 2, None)
|
||||
acc = WindowCovering(hass, hk_driver, "Cover", entity_id, 2, None)
|
||||
await acc.run_handler()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
|
@ -218,13 +199,13 @@ async def test_windowcovering_set_cover_position(hass, hk_driver, cls, events):
|
|||
assert events[-1].data[ATTR_VALUE] == 75
|
||||
|
||||
|
||||
async def test_window_instantiate(hass, hk_driver, cls, events):
|
||||
async def test_window_instantiate(hass, hk_driver, events):
|
||||
"""Test if Window accessory is instantiated correctly."""
|
||||
entity_id = "cover.window"
|
||||
|
||||
hass.states.async_set(entity_id, None)
|
||||
await hass.async_block_till_done()
|
||||
acc = cls.window(hass, hk_driver, "Window", entity_id, 2, None)
|
||||
acc = Window(hass, hk_driver, "Window", entity_id, 2, None)
|
||||
await acc.run_handler()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
|
@ -235,7 +216,7 @@ async def test_window_instantiate(hass, hk_driver, cls, events):
|
|||
assert acc.char_target_position.value == 0
|
||||
|
||||
|
||||
async def test_windowcovering_cover_set_tilt(hass, hk_driver, cls, events):
|
||||
async def test_windowcovering_cover_set_tilt(hass, hk_driver, events):
|
||||
"""Test if accessory and HA update slat tilt accordingly."""
|
||||
entity_id = "cover.window"
|
||||
|
||||
|
@ -243,7 +224,7 @@ async def test_windowcovering_cover_set_tilt(hass, hk_driver, cls, events):
|
|||
entity_id, STATE_UNKNOWN, {ATTR_SUPPORTED_FEATURES: SUPPORT_SET_TILT_POSITION}
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
acc = cls.windowcovering(hass, hk_driver, "Cover", entity_id, 2, None)
|
||||
acc = WindowCovering(hass, hk_driver, "Cover", entity_id, 2, None)
|
||||
await acc.run_handler()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
|
@ -302,12 +283,12 @@ async def test_windowcovering_cover_set_tilt(hass, hk_driver, cls, events):
|
|||
assert events[-1].data[ATTR_VALUE] == 75
|
||||
|
||||
|
||||
async def test_windowcovering_open_close(hass, hk_driver, cls, events):
|
||||
async def test_windowcovering_open_close(hass, hk_driver, events):
|
||||
"""Test if accessory and HA are updated accordingly."""
|
||||
entity_id = "cover.window"
|
||||
|
||||
hass.states.async_set(entity_id, STATE_UNKNOWN, {ATTR_SUPPORTED_FEATURES: 0})
|
||||
acc = cls.windowcovering_basic(hass, hk_driver, "Cover", entity_id, 2, None)
|
||||
acc = WindowCoveringBasic(hass, hk_driver, "Cover", entity_id, 2, None)
|
||||
await acc.run_handler()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
|
@ -383,14 +364,14 @@ async def test_windowcovering_open_close(hass, hk_driver, cls, events):
|
|||
assert events[-1].data[ATTR_VALUE] is None
|
||||
|
||||
|
||||
async def test_windowcovering_open_close_stop(hass, hk_driver, cls, events):
|
||||
async def test_windowcovering_open_close_stop(hass, hk_driver, events):
|
||||
"""Test if accessory and HA are updated accordingly."""
|
||||
entity_id = "cover.window"
|
||||
|
||||
hass.states.async_set(
|
||||
entity_id, STATE_UNKNOWN, {ATTR_SUPPORTED_FEATURES: SUPPORT_STOP}
|
||||
)
|
||||
acc = cls.windowcovering_basic(hass, hk_driver, "Cover", entity_id, 2, None)
|
||||
acc = WindowCoveringBasic(hass, hk_driver, "Cover", entity_id, 2, None)
|
||||
await acc.run_handler()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
|
@ -431,7 +412,7 @@ async def test_windowcovering_open_close_stop(hass, hk_driver, cls, events):
|
|||
|
||||
|
||||
async def test_windowcovering_open_close_with_position_and_stop(
|
||||
hass, hk_driver, cls, events
|
||||
hass, hk_driver, events
|
||||
):
|
||||
"""Test if accessory and HA are updated accordingly."""
|
||||
entity_id = "cover.stop_window"
|
||||
|
@ -441,7 +422,7 @@ async def test_windowcovering_open_close_with_position_and_stop(
|
|||
STATE_UNKNOWN,
|
||||
{ATTR_SUPPORTED_FEATURES: SUPPORT_STOP | SUPPORT_SET_POSITION},
|
||||
)
|
||||
acc = cls.windowcovering(hass, hk_driver, "Cover", entity_id, 2, None)
|
||||
acc = WindowCovering(hass, hk_driver, "Cover", entity_id, 2, None)
|
||||
await acc.run_handler()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
|
@ -461,7 +442,7 @@ async def test_windowcovering_open_close_with_position_and_stop(
|
|||
assert events[-1].data[ATTR_VALUE] is None
|
||||
|
||||
|
||||
async def test_windowcovering_basic_restore(hass, hk_driver, cls, events):
|
||||
async def test_windowcovering_basic_restore(hass, hk_driver, events):
|
||||
"""Test setting up an entity from state in the event registry."""
|
||||
hass.state = CoreState.not_running
|
||||
|
||||
|
@ -486,22 +467,20 @@ async def test_windowcovering_basic_restore(hass, hk_driver, cls, events):
|
|||
hass.bus.async_fire(EVENT_HOMEASSISTANT_START, {})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
acc = cls.windowcovering_basic(hass, hk_driver, "Cover", "cover.simple", 2, None)
|
||||
acc = WindowCoveringBasic(hass, hk_driver, "Cover", "cover.simple", 2, None)
|
||||
assert acc.category == 14
|
||||
assert acc.char_current_position is not None
|
||||
assert acc.char_target_position is not None
|
||||
assert acc.char_position_state is not None
|
||||
|
||||
acc = cls.windowcovering_basic(
|
||||
hass, hk_driver, "Cover", "cover.all_info_set", 2, None
|
||||
)
|
||||
acc = WindowCoveringBasic(hass, hk_driver, "Cover", "cover.all_info_set", 2, None)
|
||||
assert acc.category == 14
|
||||
assert acc.char_current_position is not None
|
||||
assert acc.char_target_position is not None
|
||||
assert acc.char_position_state is not None
|
||||
|
||||
|
||||
async def test_windowcovering_restore(hass, hk_driver, cls, events):
|
||||
async def test_windowcovering_restore(hass, hk_driver, events):
|
||||
"""Test setting up an entity from state in the event registry."""
|
||||
hass.state = CoreState.not_running
|
||||
|
||||
|
@ -526,20 +505,20 @@ async def test_windowcovering_restore(hass, hk_driver, cls, events):
|
|||
hass.bus.async_fire(EVENT_HOMEASSISTANT_START, {})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
acc = cls.windowcovering(hass, hk_driver, "Cover", "cover.simple", 2, None)
|
||||
acc = WindowCovering(hass, hk_driver, "Cover", "cover.simple", 2, None)
|
||||
assert acc.category == 14
|
||||
assert acc.char_current_position is not None
|
||||
assert acc.char_target_position is not None
|
||||
assert acc.char_position_state is not None
|
||||
|
||||
acc = cls.windowcovering(hass, hk_driver, "Cover", "cover.all_info_set", 2, None)
|
||||
acc = WindowCovering(hass, hk_driver, "Cover", "cover.all_info_set", 2, None)
|
||||
assert acc.category == 14
|
||||
assert acc.char_current_position is not None
|
||||
assert acc.char_target_position is not None
|
||||
assert acc.char_position_state is not None
|
||||
|
||||
|
||||
async def test_garage_door_with_linked_obstruction_sensor(hass, hk_driver, cls, events):
|
||||
async def test_garage_door_with_linked_obstruction_sensor(hass, hk_driver, events):
|
||||
"""Test if accessory and HA are updated accordingly with a linked obstruction sensor."""
|
||||
linked_obstruction_sensor_entity_id = "binary_sensor.obstruction"
|
||||
entity_id = "cover.garage_door"
|
||||
|
@ -547,7 +526,7 @@ async def test_garage_door_with_linked_obstruction_sensor(hass, hk_driver, cls,
|
|||
hass.states.async_set(linked_obstruction_sensor_entity_id, STATE_OFF)
|
||||
hass.states.async_set(entity_id, None)
|
||||
await hass.async_block_till_done()
|
||||
acc = cls.garage(
|
||||
acc = GarageDoorOpener(
|
||||
hass,
|
||||
hk_driver,
|
||||
"Garage Door",
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
"""Test different accessory types: Fans."""
|
||||
from collections import namedtuple
|
||||
|
||||
from pyhap.const import HAP_REPR_AID, HAP_REPR_CHARS, HAP_REPR_IID, HAP_REPR_VALUE
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.fan import (
|
||||
ATTR_DIRECTION,
|
||||
|
@ -16,6 +14,7 @@ from homeassistant.components.fan import (
|
|||
SUPPORT_SET_SPEED,
|
||||
)
|
||||
from homeassistant.components.homekit.const import ATTR_VALUE
|
||||
from homeassistant.components.homekit.type_fans import Fan
|
||||
from homeassistant.const import (
|
||||
ATTR_ENTITY_ID,
|
||||
ATTR_SUPPORTED_FEATURES,
|
||||
|
@ -28,27 +27,15 @@ from homeassistant.core import CoreState
|
|||
from homeassistant.helpers import entity_registry
|
||||
|
||||
from tests.common import async_mock_service
|
||||
from tests.components.homekit.common import patch_debounce
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def cls():
|
||||
"""Patch debounce decorator during import of type_fans."""
|
||||
patcher = patch_debounce()
|
||||
patcher.start()
|
||||
_import = __import__("homeassistant.components.homekit.type_fans", fromlist=["Fan"])
|
||||
patcher_tuple = namedtuple("Cls", ["fan"])
|
||||
yield patcher_tuple(fan=_import.Fan)
|
||||
patcher.stop()
|
||||
|
||||
|
||||
async def test_fan_basic(hass, hk_driver, cls, events):
|
||||
async def test_fan_basic(hass, hk_driver, events):
|
||||
"""Test fan with char state."""
|
||||
entity_id = "fan.demo"
|
||||
|
||||
hass.states.async_set(entity_id, STATE_ON, {ATTR_SUPPORTED_FEATURES: 0})
|
||||
await hass.async_block_till_done()
|
||||
acc = cls.fan(hass, hk_driver, "Fan", entity_id, 1, None)
|
||||
acc = Fan(hass, hk_driver, "Fan", entity_id, 1, None)
|
||||
hk_driver.add_accessory(acc)
|
||||
|
||||
assert acc.aid == 1
|
||||
|
@ -120,7 +107,7 @@ async def test_fan_basic(hass, hk_driver, cls, events):
|
|||
assert events[-1].data[ATTR_VALUE] is None
|
||||
|
||||
|
||||
async def test_fan_direction(hass, hk_driver, cls, events):
|
||||
async def test_fan_direction(hass, hk_driver, events):
|
||||
"""Test fan with direction."""
|
||||
entity_id = "fan.demo"
|
||||
|
||||
|
@ -130,7 +117,7 @@ async def test_fan_direction(hass, hk_driver, cls, events):
|
|||
{ATTR_SUPPORTED_FEATURES: SUPPORT_DIRECTION, ATTR_DIRECTION: DIRECTION_FORWARD},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
acc = cls.fan(hass, hk_driver, "Fan", entity_id, 1, None)
|
||||
acc = Fan(hass, hk_driver, "Fan", entity_id, 1, None)
|
||||
hk_driver.add_accessory(acc)
|
||||
|
||||
assert acc.char_direction.value == 0
|
||||
|
@ -188,7 +175,7 @@ async def test_fan_direction(hass, hk_driver, cls, events):
|
|||
assert events[-1].data[ATTR_VALUE] == DIRECTION_REVERSE
|
||||
|
||||
|
||||
async def test_fan_oscillate(hass, hk_driver, cls, events):
|
||||
async def test_fan_oscillate(hass, hk_driver, events):
|
||||
"""Test fan with oscillate."""
|
||||
entity_id = "fan.demo"
|
||||
|
||||
|
@ -198,7 +185,7 @@ async def test_fan_oscillate(hass, hk_driver, cls, events):
|
|||
{ATTR_SUPPORTED_FEATURES: SUPPORT_OSCILLATE, ATTR_OSCILLATING: False},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
acc = cls.fan(hass, hk_driver, "Fan", entity_id, 1, None)
|
||||
acc = Fan(hass, hk_driver, "Fan", entity_id, 1, None)
|
||||
hk_driver.add_accessory(acc)
|
||||
|
||||
assert acc.char_swing.value == 0
|
||||
|
@ -257,7 +244,7 @@ async def test_fan_oscillate(hass, hk_driver, cls, events):
|
|||
assert events[-1].data[ATTR_VALUE] is True
|
||||
|
||||
|
||||
async def test_fan_speed(hass, hk_driver, cls, events):
|
||||
async def test_fan_speed(hass, hk_driver, events):
|
||||
"""Test fan with speed."""
|
||||
entity_id = "fan.demo"
|
||||
|
||||
|
@ -270,7 +257,7 @@ async def test_fan_speed(hass, hk_driver, cls, events):
|
|||
},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
acc = cls.fan(hass, hk_driver, "Fan", entity_id, 1, None)
|
||||
acc = Fan(hass, hk_driver, "Fan", entity_id, 1, None)
|
||||
hk_driver.add_accessory(acc)
|
||||
|
||||
# Initial value can be anything but 0. If it is 0, it might cause HomeKit to set the
|
||||
|
@ -336,7 +323,7 @@ async def test_fan_speed(hass, hk_driver, cls, events):
|
|||
assert acc.char_active.value == 1
|
||||
|
||||
|
||||
async def test_fan_set_all_one_shot(hass, hk_driver, cls, events):
|
||||
async def test_fan_set_all_one_shot(hass, hk_driver, events):
|
||||
"""Test fan with speed."""
|
||||
entity_id = "fan.demo"
|
||||
|
||||
|
@ -353,7 +340,7 @@ async def test_fan_set_all_one_shot(hass, hk_driver, cls, events):
|
|||
},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
acc = cls.fan(hass, hk_driver, "Fan", entity_id, 1, None)
|
||||
acc = Fan(hass, hk_driver, "Fan", entity_id, 1, None)
|
||||
hk_driver.add_accessory(acc)
|
||||
|
||||
# Initial value can be anything but 0. If it is 0, it might cause HomeKit to set the
|
||||
|
@ -529,7 +516,7 @@ async def test_fan_set_all_one_shot(hass, hk_driver, cls, events):
|
|||
assert len(call_set_direction) == 2
|
||||
|
||||
|
||||
async def test_fan_restore(hass, hk_driver, cls, events):
|
||||
async def test_fan_restore(hass, hk_driver, events):
|
||||
"""Test setting up an entity from state in the event registry."""
|
||||
hass.state = CoreState.not_running
|
||||
|
||||
|
@ -554,14 +541,14 @@ async def test_fan_restore(hass, hk_driver, cls, events):
|
|||
hass.bus.async_fire(EVENT_HOMEASSISTANT_START, {})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
acc = cls.fan(hass, hk_driver, "Fan", "fan.simple", 2, None)
|
||||
acc = Fan(hass, hk_driver, "Fan", "fan.simple", 2, None)
|
||||
assert acc.category == 3
|
||||
assert acc.char_active is not None
|
||||
assert acc.char_direction is None
|
||||
assert acc.char_speed is None
|
||||
assert acc.char_swing is None
|
||||
|
||||
acc = cls.fan(hass, hk_driver, "Fan", "fan.all_info_set", 2, None)
|
||||
acc = Fan(hass, hk_driver, "Fan", "fan.all_info_set", 2, None)
|
||||
assert acc.category == 3
|
||||
assert acc.char_active is not None
|
||||
assert acc.char_direction is not None
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
"""Test different accessory types: Lights."""
|
||||
from collections import namedtuple
|
||||
|
||||
from pyhap.const import HAP_REPR_AID, HAP_REPR_CHARS, HAP_REPR_IID, HAP_REPR_VALUE
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.homekit.const import ATTR_VALUE
|
||||
from homeassistant.components.homekit.type_lights import Light
|
||||
from homeassistant.components.light import (
|
||||
ATTR_BRIGHTNESS,
|
||||
ATTR_BRIGHTNESS_PCT,
|
||||
|
@ -28,29 +27,15 @@ from homeassistant.core import CoreState
|
|||
from homeassistant.helpers import entity_registry
|
||||
|
||||
from tests.common import async_mock_service
|
||||
from tests.components.homekit.common import patch_debounce
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def cls():
|
||||
"""Patch debounce decorator during import of type_lights."""
|
||||
patcher = patch_debounce()
|
||||
patcher.start()
|
||||
_import = __import__(
|
||||
"homeassistant.components.homekit.type_lights", fromlist=["Light"]
|
||||
)
|
||||
patcher_tuple = namedtuple("Cls", ["light"])
|
||||
yield patcher_tuple(light=_import.Light)
|
||||
patcher.stop()
|
||||
|
||||
|
||||
async def test_light_basic(hass, hk_driver, cls, events):
|
||||
async def test_light_basic(hass, hk_driver, events):
|
||||
"""Test light with char state."""
|
||||
entity_id = "light.demo"
|
||||
|
||||
hass.states.async_set(entity_id, STATE_ON, {ATTR_SUPPORTED_FEATURES: 0})
|
||||
await hass.async_block_till_done()
|
||||
acc = cls.light(hass, hk_driver, "Light", entity_id, 1, None)
|
||||
acc = Light(hass, hk_driver, "Light", entity_id, 1, None)
|
||||
hk_driver.add_accessory(acc)
|
||||
|
||||
assert acc.aid == 1
|
||||
|
@ -113,7 +98,7 @@ async def test_light_basic(hass, hk_driver, cls, events):
|
|||
assert events[-1].data[ATTR_VALUE] == "Set state to 0"
|
||||
|
||||
|
||||
async def test_light_brightness(hass, hk_driver, cls, events):
|
||||
async def test_light_brightness(hass, hk_driver, events):
|
||||
"""Test light with brightness."""
|
||||
entity_id = "light.demo"
|
||||
|
||||
|
@ -123,7 +108,7 @@ async def test_light_brightness(hass, hk_driver, cls, events):
|
|||
{ATTR_SUPPORTED_FEATURES: SUPPORT_BRIGHTNESS, ATTR_BRIGHTNESS: 255},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
acc = cls.light(hass, hk_driver, "Light", entity_id, 1, None)
|
||||
acc = Light(hass, hk_driver, "Light", entity_id, 1, None)
|
||||
hk_driver.add_accessory(acc)
|
||||
|
||||
# Initial value can be anything but 0. If it is 0, it might cause HomeKit to set the
|
||||
|
@ -231,7 +216,7 @@ async def test_light_brightness(hass, hk_driver, cls, events):
|
|||
assert acc.char_brightness.value == 1
|
||||
|
||||
|
||||
async def test_light_color_temperature(hass, hk_driver, cls, events):
|
||||
async def test_light_color_temperature(hass, hk_driver, events):
|
||||
"""Test light with color temperature."""
|
||||
entity_id = "light.demo"
|
||||
|
||||
|
@ -241,7 +226,7 @@ async def test_light_color_temperature(hass, hk_driver, cls, events):
|
|||
{ATTR_SUPPORTED_FEATURES: SUPPORT_COLOR_TEMP, ATTR_COLOR_TEMP: 190},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
acc = cls.light(hass, hk_driver, "Light", entity_id, 1, None)
|
||||
acc = Light(hass, hk_driver, "Light", entity_id, 1, None)
|
||||
hk_driver.add_accessory(acc)
|
||||
|
||||
assert acc.char_color_temperature.value == 190
|
||||
|
@ -278,7 +263,7 @@ async def test_light_color_temperature(hass, hk_driver, cls, events):
|
|||
assert events[-1].data[ATTR_VALUE] == "color temperature at 250"
|
||||
|
||||
|
||||
async def test_light_color_temperature_and_rgb_color(hass, hk_driver, cls, events):
|
||||
async def test_light_color_temperature_and_rgb_color(hass, hk_driver, events):
|
||||
"""Test light with color temperature and rgb color not exposing temperature."""
|
||||
entity_id = "light.demo"
|
||||
|
||||
|
@ -292,7 +277,7 @@ async def test_light_color_temperature_and_rgb_color(hass, hk_driver, cls, event
|
|||
},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
acc = cls.light(hass, hk_driver, "Light", entity_id, 2, None)
|
||||
acc = Light(hass, hk_driver, "Light", entity_id, 2, None)
|
||||
assert acc.char_hue.value == 260
|
||||
assert acc.char_saturation.value == 90
|
||||
|
||||
|
@ -313,7 +298,7 @@ async def test_light_color_temperature_and_rgb_color(hass, hk_driver, cls, event
|
|||
assert acc.char_saturation.value == 61
|
||||
|
||||
|
||||
async def test_light_rgb_color(hass, hk_driver, cls, events):
|
||||
async def test_light_rgb_color(hass, hk_driver, events):
|
||||
"""Test light with rgb_color."""
|
||||
entity_id = "light.demo"
|
||||
|
||||
|
@ -323,7 +308,7 @@ async def test_light_rgb_color(hass, hk_driver, cls, events):
|
|||
{ATTR_SUPPORTED_FEATURES: SUPPORT_COLOR, ATTR_HS_COLOR: (260, 90)},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
acc = cls.light(hass, hk_driver, "Light", entity_id, 1, None)
|
||||
acc = Light(hass, hk_driver, "Light", entity_id, 1, None)
|
||||
hk_driver.add_accessory(acc)
|
||||
|
||||
assert acc.char_hue.value == 260
|
||||
|
@ -365,7 +350,7 @@ async def test_light_rgb_color(hass, hk_driver, cls, events):
|
|||
assert events[-1].data[ATTR_VALUE] == "set color at (145, 75)"
|
||||
|
||||
|
||||
async def test_light_restore(hass, hk_driver, cls, events):
|
||||
async def test_light_restore(hass, hk_driver, events):
|
||||
"""Test setting up an entity from state in the event registry."""
|
||||
hass.state = CoreState.not_running
|
||||
|
||||
|
@ -385,20 +370,20 @@ async def test_light_restore(hass, hk_driver, cls, events):
|
|||
hass.bus.async_fire(EVENT_HOMEASSISTANT_START, {})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
acc = cls.light(hass, hk_driver, "Light", "light.simple", 1, None)
|
||||
acc = Light(hass, hk_driver, "Light", "light.simple", 1, None)
|
||||
hk_driver.add_accessory(acc)
|
||||
|
||||
assert acc.category == 5 # Lightbulb
|
||||
assert acc.chars == []
|
||||
assert acc.char_on.value == 0
|
||||
|
||||
acc = cls.light(hass, hk_driver, "Light", "light.all_info_set", 2, None)
|
||||
acc = Light(hass, hk_driver, "Light", "light.all_info_set", 2, None)
|
||||
assert acc.category == 5 # Lightbulb
|
||||
assert acc.chars == ["Brightness"]
|
||||
assert acc.char_on.value == 0
|
||||
|
||||
|
||||
async def test_light_set_brightness_and_color(hass, hk_driver, cls, events):
|
||||
async def test_light_set_brightness_and_color(hass, hk_driver, events):
|
||||
"""Test light with all chars in one go."""
|
||||
entity_id = "light.demo"
|
||||
|
||||
|
@ -411,7 +396,7 @@ async def test_light_set_brightness_and_color(hass, hk_driver, cls, events):
|
|||
},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
acc = cls.light(hass, hk_driver, "Light", entity_id, 1, None)
|
||||
acc = Light(hass, hk_driver, "Light", entity_id, 1, None)
|
||||
hk_driver.add_accessory(acc)
|
||||
|
||||
# Initial value can be anything but 0. If it is 0, it might cause HomeKit to set the
|
||||
|
@ -474,7 +459,7 @@ async def test_light_set_brightness_and_color(hass, hk_driver, cls, events):
|
|||
)
|
||||
|
||||
|
||||
async def test_light_set_brightness_and_color_temp(hass, hk_driver, cls, events):
|
||||
async def test_light_set_brightness_and_color_temp(hass, hk_driver, events):
|
||||
"""Test light with all chars in one go."""
|
||||
entity_id = "light.demo"
|
||||
|
||||
|
@ -487,7 +472,7 @@ async def test_light_set_brightness_and_color_temp(hass, hk_driver, cls, events)
|
|||
},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
acc = cls.light(hass, hk_driver, "Light", entity_id, 1, None)
|
||||
acc = Light(hass, hk_driver, "Light", entity_id, 1, None)
|
||||
hk_driver.add_accessory(acc)
|
||||
|
||||
# Initial value can be anything but 0. If it is 0, it might cause HomeKit to set the
|
||||
|
|
Loading…
Add table
Reference in a new issue