mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 05:07:41 +00:00
Convert homekit fans to use service callbacks (#34229)
* Convert homekit fans to use service callbacks * Convert homekit fans to use service callbacks Service callbacks allow us ensure that we call fan services in the correct order. * Avoid calling turn_on if a speed is sent and the device is on * Fix test to not leave files behind * Fix test * Update homeassistant/components/homekit/type_fans.py Co-Authored-By: Paulus Schoutsen <paulus@home-assistant.io> Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
This commit is contained in:
parent
d6a47cb3e0
commit
e8710002b1
@ -28,7 +28,7 @@ from homeassistant.const import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from . import TYPES
|
from . import TYPES
|
||||||
from .accessories import HomeAccessory, debounce
|
from .accessories import HomeAccessory
|
||||||
from .const import (
|
from .const import (
|
||||||
CHAR_ACTIVE,
|
CHAR_ACTIVE,
|
||||||
CHAR_ROTATION_DIRECTION,
|
CHAR_ROTATION_DIRECTION,
|
||||||
@ -51,17 +51,11 @@ class Fan(HomeAccessory):
|
|||||||
def __init__(self, *args):
|
def __init__(self, *args):
|
||||||
"""Initialize a new Light accessory object."""
|
"""Initialize a new Light accessory object."""
|
||||||
super().__init__(*args, category=CATEGORY_FAN)
|
super().__init__(*args, category=CATEGORY_FAN)
|
||||||
self._flag = {
|
|
||||||
CHAR_ACTIVE: False,
|
|
||||||
CHAR_ROTATION_DIRECTION: False,
|
|
||||||
CHAR_SWING_MODE: False,
|
|
||||||
}
|
|
||||||
self._state = 0
|
|
||||||
|
|
||||||
chars = []
|
chars = []
|
||||||
features = self.hass.states.get(self.entity_id).attributes.get(
|
state = self.hass.states.get(self.entity_id)
|
||||||
ATTR_SUPPORTED_FEATURES
|
|
||||||
)
|
features = state.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
|
||||||
|
|
||||||
if features & SUPPORT_DIRECTION:
|
if features & SUPPORT_DIRECTION:
|
||||||
chars.append(CHAR_ROTATION_DIRECTION)
|
chars.append(CHAR_ROTATION_DIRECTION)
|
||||||
if features & SUPPORT_OSCILLATE:
|
if features & SUPPORT_OSCILLATE:
|
||||||
@ -74,9 +68,7 @@ class Fan(HomeAccessory):
|
|||||||
chars.append(CHAR_ROTATION_SPEED)
|
chars.append(CHAR_ROTATION_SPEED)
|
||||||
|
|
||||||
serv_fan = self.add_preload_service(SERV_FANV2, chars)
|
serv_fan = self.add_preload_service(SERV_FANV2, chars)
|
||||||
self.char_active = serv_fan.configure_char(
|
self.char_active = serv_fan.configure_char(CHAR_ACTIVE, value=0)
|
||||||
CHAR_ACTIVE, value=0, setter_callback=self.set_state
|
|
||||||
)
|
|
||||||
|
|
||||||
self.char_direction = None
|
self.char_direction = None
|
||||||
self.char_speed = None
|
self.char_speed = None
|
||||||
@ -84,26 +76,52 @@ class Fan(HomeAccessory):
|
|||||||
|
|
||||||
if CHAR_ROTATION_DIRECTION in chars:
|
if CHAR_ROTATION_DIRECTION in chars:
|
||||||
self.char_direction = serv_fan.configure_char(
|
self.char_direction = serv_fan.configure_char(
|
||||||
CHAR_ROTATION_DIRECTION, value=0, setter_callback=self.set_direction
|
CHAR_ROTATION_DIRECTION, value=0
|
||||||
)
|
)
|
||||||
|
|
||||||
if CHAR_ROTATION_SPEED in chars:
|
if CHAR_ROTATION_SPEED in chars:
|
||||||
# Initial value is set to 100 because 0 is a special value (off). 100 is
|
# Initial value is set to 100 because 0 is a special value (off). 100 is
|
||||||
# an arbitrary non-zero value. It is updated immediately by update_state
|
# an arbitrary non-zero value. It is updated immediately by update_state
|
||||||
# to set to the correct initial value.
|
# to set to the correct initial value.
|
||||||
self.char_speed = serv_fan.configure_char(
|
self.char_speed = serv_fan.configure_char(CHAR_ROTATION_SPEED, value=100)
|
||||||
CHAR_ROTATION_SPEED, value=100, setter_callback=self.set_speed
|
|
||||||
)
|
|
||||||
|
|
||||||
if CHAR_SWING_MODE in chars:
|
if CHAR_SWING_MODE in chars:
|
||||||
self.char_swing = serv_fan.configure_char(
|
self.char_swing = serv_fan.configure_char(CHAR_SWING_MODE, value=0)
|
||||||
CHAR_SWING_MODE, value=0, setter_callback=self.set_oscillating
|
self.update_state(state)
|
||||||
)
|
serv_fan.setter_callback = self._set_chars
|
||||||
|
|
||||||
|
def _set_chars(self, char_values):
|
||||||
|
_LOGGER.debug("Fan _set_chars: %s", char_values)
|
||||||
|
if CHAR_ACTIVE in char_values:
|
||||||
|
if char_values[CHAR_ACTIVE]:
|
||||||
|
is_on = False
|
||||||
|
state = self.hass.states.get(self.entity_id)
|
||||||
|
if state and state.state == STATE_ON:
|
||||||
|
is_on = True
|
||||||
|
# Only set the state to active if we
|
||||||
|
# did not get a rotation speed or its off
|
||||||
|
if not is_on or CHAR_ROTATION_SPEED not in char_values:
|
||||||
|
self.set_state(1)
|
||||||
|
else:
|
||||||
|
# Its off, nothing more to do as setting the
|
||||||
|
# other chars will likely turn it back on which
|
||||||
|
# is what we want to avoid
|
||||||
|
self.set_state(0)
|
||||||
|
return
|
||||||
|
|
||||||
|
if CHAR_SWING_MODE in char_values:
|
||||||
|
self.set_oscillating(char_values[CHAR_SWING_MODE])
|
||||||
|
if CHAR_ROTATION_DIRECTION in char_values:
|
||||||
|
self.set_direction(char_values[CHAR_ROTATION_DIRECTION])
|
||||||
|
|
||||||
|
# We always do this LAST to ensure they
|
||||||
|
# get the speed they asked for
|
||||||
|
if CHAR_ROTATION_SPEED in char_values:
|
||||||
|
self.set_speed(char_values[CHAR_ROTATION_SPEED])
|
||||||
|
|
||||||
def set_state(self, value):
|
def set_state(self, value):
|
||||||
"""Set state if call came from HomeKit."""
|
"""Set state if call came from HomeKit."""
|
||||||
_LOGGER.debug("%s: Set state to %d", self.entity_id, value)
|
_LOGGER.debug("%s: Set state to %d", self.entity_id, value)
|
||||||
self._flag[CHAR_ACTIVE] = True
|
|
||||||
service = SERVICE_TURN_ON if value == 1 else SERVICE_TURN_OFF
|
service = SERVICE_TURN_ON if value == 1 else SERVICE_TURN_OFF
|
||||||
params = {ATTR_ENTITY_ID: self.entity_id}
|
params = {ATTR_ENTITY_ID: self.entity_id}
|
||||||
self.call_service(DOMAIN, service, params)
|
self.call_service(DOMAIN, service, params)
|
||||||
@ -111,7 +129,6 @@ class Fan(HomeAccessory):
|
|||||||
def set_direction(self, value):
|
def set_direction(self, value):
|
||||||
"""Set state if call came from HomeKit."""
|
"""Set state if call came from HomeKit."""
|
||||||
_LOGGER.debug("%s: Set direction to %d", self.entity_id, value)
|
_LOGGER.debug("%s: Set direction to %d", self.entity_id, value)
|
||||||
self._flag[CHAR_ROTATION_DIRECTION] = True
|
|
||||||
direction = DIRECTION_REVERSE if value == 1 else DIRECTION_FORWARD
|
direction = DIRECTION_REVERSE if value == 1 else DIRECTION_FORWARD
|
||||||
params = {ATTR_ENTITY_ID: self.entity_id, ATTR_DIRECTION: direction}
|
params = {ATTR_ENTITY_ID: self.entity_id, ATTR_DIRECTION: direction}
|
||||||
self.call_service(DOMAIN, SERVICE_SET_DIRECTION, params, direction)
|
self.call_service(DOMAIN, SERVICE_SET_DIRECTION, params, direction)
|
||||||
@ -119,12 +136,10 @@ class Fan(HomeAccessory):
|
|||||||
def set_oscillating(self, value):
|
def set_oscillating(self, value):
|
||||||
"""Set state if call came from HomeKit."""
|
"""Set state if call came from HomeKit."""
|
||||||
_LOGGER.debug("%s: Set oscillating to %d", self.entity_id, value)
|
_LOGGER.debug("%s: Set oscillating to %d", self.entity_id, value)
|
||||||
self._flag[CHAR_SWING_MODE] = True
|
|
||||||
oscillating = value == 1
|
oscillating = value == 1
|
||||||
params = {ATTR_ENTITY_ID: self.entity_id, ATTR_OSCILLATING: oscillating}
|
params = {ATTR_ENTITY_ID: self.entity_id, ATTR_OSCILLATING: oscillating}
|
||||||
self.call_service(DOMAIN, SERVICE_OSCILLATE, params, oscillating)
|
self.call_service(DOMAIN, SERVICE_OSCILLATE, params, oscillating)
|
||||||
|
|
||||||
@debounce
|
|
||||||
def set_speed(self, value):
|
def set_speed(self, value):
|
||||||
"""Set state if call came from HomeKit."""
|
"""Set state if call came from HomeKit."""
|
||||||
_LOGGER.debug("%s: Set speed to %d", self.entity_id, value)
|
_LOGGER.debug("%s: Set speed to %d", self.entity_id, value)
|
||||||
@ -138,21 +153,16 @@ class Fan(HomeAccessory):
|
|||||||
state = new_state.state
|
state = new_state.state
|
||||||
if state in (STATE_ON, STATE_OFF):
|
if state in (STATE_ON, STATE_OFF):
|
||||||
self._state = 1 if state == STATE_ON else 0
|
self._state = 1 if state == STATE_ON else 0
|
||||||
if not self._flag[CHAR_ACTIVE] and self.char_active.value != self._state:
|
if self.char_active.value != self._state:
|
||||||
self.char_active.set_value(self._state)
|
self.char_active.set_value(self._state)
|
||||||
self._flag[CHAR_ACTIVE] = False
|
|
||||||
|
|
||||||
# Handle Direction
|
# Handle Direction
|
||||||
if self.char_direction is not None:
|
if self.char_direction is not None:
|
||||||
direction = new_state.attributes.get(ATTR_DIRECTION)
|
direction = new_state.attributes.get(ATTR_DIRECTION)
|
||||||
if not self._flag[CHAR_ROTATION_DIRECTION] and direction in (
|
if direction in (DIRECTION_FORWARD, DIRECTION_REVERSE):
|
||||||
DIRECTION_FORWARD,
|
|
||||||
DIRECTION_REVERSE,
|
|
||||||
):
|
|
||||||
hk_direction = 1 if direction == DIRECTION_REVERSE else 0
|
hk_direction = 1 if direction == DIRECTION_REVERSE else 0
|
||||||
if self.char_direction.value != hk_direction:
|
if self.char_direction.value != hk_direction:
|
||||||
self.char_direction.set_value(hk_direction)
|
self.char_direction.set_value(hk_direction)
|
||||||
self._flag[CHAR_ROTATION_DIRECTION] = False
|
|
||||||
|
|
||||||
# Handle Speed
|
# Handle Speed
|
||||||
if self.char_speed is not None:
|
if self.char_speed is not None:
|
||||||
@ -170,17 +180,15 @@ class Fan(HomeAccessory):
|
|||||||
# Therefore, if the hk_speed_value is 0 and the device is still on,
|
# Therefore, if the hk_speed_value is 0 and the device is still on,
|
||||||
# the rotation speed is mapped to 1 otherwise the update is ignored
|
# the rotation speed is mapped to 1 otherwise the update is ignored
|
||||||
# in order to avoid this incorrect behavior.
|
# in order to avoid this incorrect behavior.
|
||||||
if hk_speed_value == 0:
|
if hk_speed_value == 0 and state == STATE_ON:
|
||||||
if state == STATE_ON:
|
hk_speed_value = 1
|
||||||
self.char_speed.set_value(1)
|
if self.char_speed.value != hk_speed_value:
|
||||||
else:
|
|
||||||
self.char_speed.set_value(hk_speed_value)
|
self.char_speed.set_value(hk_speed_value)
|
||||||
|
|
||||||
# Handle Oscillating
|
# Handle Oscillating
|
||||||
if self.char_swing is not None:
|
if self.char_swing is not None:
|
||||||
oscillating = new_state.attributes.get(ATTR_OSCILLATING)
|
oscillating = new_state.attributes.get(ATTR_OSCILLATING)
|
||||||
if not self._flag[CHAR_SWING_MODE] and oscillating in (True, False):
|
if isinstance(oscillating, bool):
|
||||||
hk_oscillating = 1 if oscillating else 0
|
hk_oscillating = 1 if oscillating else 0
|
||||||
if self.char_swing.value != hk_oscillating:
|
if self.char_swing.value != hk_oscillating:
|
||||||
self.char_swing.set_value(hk_oscillating)
|
self.char_swing.set_value(hk_oscillating)
|
||||||
self._flag[CHAR_SWING_MODE] = False
|
|
||||||
|
@ -15,8 +15,10 @@ def hk_driver():
|
|||||||
"pyhap.accessory_driver.AccessoryEncoder"
|
"pyhap.accessory_driver.AccessoryEncoder"
|
||||||
), patch("pyhap.accessory_driver.HAPServer"), patch(
|
), patch("pyhap.accessory_driver.HAPServer"), patch(
|
||||||
"pyhap.accessory_driver.AccessoryDriver.publish"
|
"pyhap.accessory_driver.AccessoryDriver.publish"
|
||||||
|
), patch(
|
||||||
|
"pyhap.accessory_driver.AccessoryDriver.persist"
|
||||||
):
|
):
|
||||||
return AccessoryDriver(pincode=b"123-45-678", address="127.0.0.1")
|
yield AccessoryDriver(pincode=b"123-45-678", address="127.0.0.1")
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from unittest.mock import Mock
|
from unittest.mock import Mock
|
||||||
|
|
||||||
|
from pyhap.const import HAP_REPR_AID, HAP_REPR_CHARS, HAP_REPR_IID, HAP_REPR_VALUE
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant.components.fan import (
|
from homeassistant.components.fan import (
|
||||||
@ -53,11 +54,12 @@ async def test_fan_basic(hass, hk_driver, cls, events):
|
|||||||
|
|
||||||
hass.states.async_set(entity_id, STATE_ON, {ATTR_SUPPORTED_FEATURES: 0})
|
hass.states.async_set(entity_id, STATE_ON, {ATTR_SUPPORTED_FEATURES: 0})
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
acc = cls.fan(hass, hk_driver, "Fan", entity_id, 2, None)
|
acc = cls.fan(hass, hk_driver, "Fan", entity_id, 1, None)
|
||||||
|
hk_driver.add_accessory(acc)
|
||||||
|
|
||||||
assert acc.aid == 2
|
assert acc.aid == 1
|
||||||
assert acc.category == 3 # Fan
|
assert acc.category == 3 # Fan
|
||||||
assert acc.char_active.value == 0
|
assert acc.char_active.value == 1
|
||||||
|
|
||||||
# If there are no speed_list values, then HomeKit speed is unsupported
|
# If there are no speed_list values, then HomeKit speed is unsupported
|
||||||
assert acc.char_speed is None
|
assert acc.char_speed is None
|
||||||
@ -82,7 +84,20 @@ async def test_fan_basic(hass, hk_driver, cls, events):
|
|||||||
call_turn_on = async_mock_service(hass, DOMAIN, "turn_on")
|
call_turn_on = async_mock_service(hass, DOMAIN, "turn_on")
|
||||||
call_turn_off = async_mock_service(hass, DOMAIN, "turn_off")
|
call_turn_off = async_mock_service(hass, DOMAIN, "turn_off")
|
||||||
|
|
||||||
await hass.async_add_executor_job(acc.char_active.client_update_value, 1)
|
char_active_iid = acc.char_active.to_HAP()[HAP_REPR_IID]
|
||||||
|
|
||||||
|
hk_driver.set_characteristics(
|
||||||
|
{
|
||||||
|
HAP_REPR_CHARS: [
|
||||||
|
{
|
||||||
|
HAP_REPR_AID: acc.aid,
|
||||||
|
HAP_REPR_IID: char_active_iid,
|
||||||
|
HAP_REPR_VALUE: 1,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"mock_addr",
|
||||||
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert call_turn_on
|
assert call_turn_on
|
||||||
assert call_turn_on[0].data[ATTR_ENTITY_ID] == entity_id
|
assert call_turn_on[0].data[ATTR_ENTITY_ID] == entity_id
|
||||||
@ -92,7 +107,18 @@ async def test_fan_basic(hass, hk_driver, cls, events):
|
|||||||
hass.states.async_set(entity_id, STATE_ON)
|
hass.states.async_set(entity_id, STATE_ON)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
await hass.async_add_executor_job(acc.char_active.client_update_value, 0)
|
hk_driver.set_characteristics(
|
||||||
|
{
|
||||||
|
HAP_REPR_CHARS: [
|
||||||
|
{
|
||||||
|
HAP_REPR_AID: acc.aid,
|
||||||
|
HAP_REPR_IID: char_active_iid,
|
||||||
|
HAP_REPR_VALUE: 0,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"mock_addr",
|
||||||
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert call_turn_off
|
assert call_turn_off
|
||||||
assert call_turn_off[0].data[ATTR_ENTITY_ID] == entity_id
|
assert call_turn_off[0].data[ATTR_ENTITY_ID] == entity_id
|
||||||
@ -110,7 +136,8 @@ async def test_fan_direction(hass, hk_driver, cls, events):
|
|||||||
{ATTR_SUPPORTED_FEATURES: SUPPORT_DIRECTION, ATTR_DIRECTION: DIRECTION_FORWARD},
|
{ATTR_SUPPORTED_FEATURES: SUPPORT_DIRECTION, ATTR_DIRECTION: DIRECTION_FORWARD},
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
acc = cls.fan(hass, hk_driver, "Fan", entity_id, 2, None)
|
acc = cls.fan(hass, hk_driver, "Fan", entity_id, 1, None)
|
||||||
|
hk_driver.add_accessory(acc)
|
||||||
|
|
||||||
assert acc.char_direction.value == 0
|
assert acc.char_direction.value == 0
|
||||||
|
|
||||||
@ -125,7 +152,20 @@ async def test_fan_direction(hass, hk_driver, cls, events):
|
|||||||
# Set from HomeKit
|
# Set from HomeKit
|
||||||
call_set_direction = async_mock_service(hass, DOMAIN, "set_direction")
|
call_set_direction = async_mock_service(hass, DOMAIN, "set_direction")
|
||||||
|
|
||||||
await hass.async_add_executor_job(acc.char_direction.client_update_value, 0)
|
char_direction_iid = acc.char_direction.to_HAP()[HAP_REPR_IID]
|
||||||
|
|
||||||
|
hk_driver.set_characteristics(
|
||||||
|
{
|
||||||
|
HAP_REPR_CHARS: [
|
||||||
|
{
|
||||||
|
HAP_REPR_AID: acc.aid,
|
||||||
|
HAP_REPR_IID: char_direction_iid,
|
||||||
|
HAP_REPR_VALUE: 0,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"mock_addr",
|
||||||
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert call_set_direction[0]
|
assert call_set_direction[0]
|
||||||
assert call_set_direction[0].data[ATTR_ENTITY_ID] == entity_id
|
assert call_set_direction[0].data[ATTR_ENTITY_ID] == entity_id
|
||||||
@ -133,6 +173,18 @@ async def test_fan_direction(hass, hk_driver, cls, events):
|
|||||||
assert len(events) == 1
|
assert len(events) == 1
|
||||||
assert events[-1].data[ATTR_VALUE] == DIRECTION_FORWARD
|
assert events[-1].data[ATTR_VALUE] == DIRECTION_FORWARD
|
||||||
|
|
||||||
|
hk_driver.set_characteristics(
|
||||||
|
{
|
||||||
|
HAP_REPR_CHARS: [
|
||||||
|
{
|
||||||
|
HAP_REPR_AID: acc.aid,
|
||||||
|
HAP_REPR_IID: char_direction_iid,
|
||||||
|
HAP_REPR_VALUE: 1,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"mock_addr",
|
||||||
|
)
|
||||||
await hass.async_add_executor_job(acc.char_direction.client_update_value, 1)
|
await hass.async_add_executor_job(acc.char_direction.client_update_value, 1)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert call_set_direction[1]
|
assert call_set_direction[1]
|
||||||
@ -152,7 +204,8 @@ async def test_fan_oscillate(hass, hk_driver, cls, events):
|
|||||||
{ATTR_SUPPORTED_FEATURES: SUPPORT_OSCILLATE, ATTR_OSCILLATING: False},
|
{ATTR_SUPPORTED_FEATURES: SUPPORT_OSCILLATE, ATTR_OSCILLATING: False},
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
acc = cls.fan(hass, hk_driver, "Fan", entity_id, 2, None)
|
acc = cls.fan(hass, hk_driver, "Fan", entity_id, 1, None)
|
||||||
|
hk_driver.add_accessory(acc)
|
||||||
|
|
||||||
assert acc.char_swing.value == 0
|
assert acc.char_swing.value == 0
|
||||||
|
|
||||||
@ -167,6 +220,20 @@ async def test_fan_oscillate(hass, hk_driver, cls, events):
|
|||||||
# Set from HomeKit
|
# Set from HomeKit
|
||||||
call_oscillate = async_mock_service(hass, DOMAIN, "oscillate")
|
call_oscillate = async_mock_service(hass, DOMAIN, "oscillate")
|
||||||
|
|
||||||
|
char_swing_iid = acc.char_swing.to_HAP()[HAP_REPR_IID]
|
||||||
|
|
||||||
|
hk_driver.set_characteristics(
|
||||||
|
{
|
||||||
|
HAP_REPR_CHARS: [
|
||||||
|
{
|
||||||
|
HAP_REPR_AID: acc.aid,
|
||||||
|
HAP_REPR_IID: char_swing_iid,
|
||||||
|
HAP_REPR_VALUE: 0,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"mock_addr",
|
||||||
|
)
|
||||||
await hass.async_add_executor_job(acc.char_swing.client_update_value, 0)
|
await hass.async_add_executor_job(acc.char_swing.client_update_value, 0)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert call_oscillate[0]
|
assert call_oscillate[0]
|
||||||
@ -175,6 +242,18 @@ async def test_fan_oscillate(hass, hk_driver, cls, events):
|
|||||||
assert len(events) == 1
|
assert len(events) == 1
|
||||||
assert events[-1].data[ATTR_VALUE] is False
|
assert events[-1].data[ATTR_VALUE] is False
|
||||||
|
|
||||||
|
hk_driver.set_characteristics(
|
||||||
|
{
|
||||||
|
HAP_REPR_CHARS: [
|
||||||
|
{
|
||||||
|
HAP_REPR_AID: acc.aid,
|
||||||
|
HAP_REPR_IID: char_swing_iid,
|
||||||
|
HAP_REPR_VALUE: 1,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"mock_addr",
|
||||||
|
)
|
||||||
await hass.async_add_executor_job(acc.char_swing.client_update_value, 1)
|
await hass.async_add_executor_job(acc.char_swing.client_update_value, 1)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert call_oscillate[1]
|
assert call_oscillate[1]
|
||||||
@ -199,7 +278,8 @@ async def test_fan_speed(hass, hk_driver, cls, events):
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
acc = cls.fan(hass, hk_driver, "Fan", entity_id, 2, None)
|
acc = cls.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
|
# Initial value can be anything but 0. If it is 0, it might cause HomeKit to set the
|
||||||
# speed to 100 when turning on a fan on a freshly booted up server.
|
# speed to 100 when turning on a fan on a freshly booted up server.
|
||||||
@ -221,6 +301,20 @@ async def test_fan_speed(hass, hk_driver, cls, events):
|
|||||||
# Set from HomeKit
|
# Set from HomeKit
|
||||||
call_set_speed = async_mock_service(hass, DOMAIN, "set_speed")
|
call_set_speed = async_mock_service(hass, DOMAIN, "set_speed")
|
||||||
|
|
||||||
|
char_speed_iid = acc.char_speed.to_HAP()[HAP_REPR_IID]
|
||||||
|
|
||||||
|
hk_driver.set_characteristics(
|
||||||
|
{
|
||||||
|
HAP_REPR_CHARS: [
|
||||||
|
{
|
||||||
|
HAP_REPR_AID: acc.aid,
|
||||||
|
HAP_REPR_IID: char_speed_iid,
|
||||||
|
HAP_REPR_VALUE: 42,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"mock_addr",
|
||||||
|
)
|
||||||
await hass.async_add_executor_job(acc.char_speed.client_update_value, 42)
|
await hass.async_add_executor_job(acc.char_speed.client_update_value, 42)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
acc.speed_mapping.speed_to_states.assert_called_with(42)
|
acc.speed_mapping.speed_to_states.assert_called_with(42)
|
||||||
@ -231,6 +325,211 @@ async def test_fan_speed(hass, hk_driver, cls, events):
|
|||||||
assert events[-1].data[ATTR_VALUE] == "ludicrous"
|
assert events[-1].data[ATTR_VALUE] == "ludicrous"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_fan_set_all_one_shot(hass, hk_driver, cls, events):
|
||||||
|
"""Test fan with speed."""
|
||||||
|
entity_id = "fan.demo"
|
||||||
|
speed_list = [SPEED_OFF, SPEED_LOW, SPEED_HIGH]
|
||||||
|
|
||||||
|
hass.states.async_set(
|
||||||
|
entity_id,
|
||||||
|
STATE_ON,
|
||||||
|
{
|
||||||
|
ATTR_SUPPORTED_FEATURES: SUPPORT_SET_SPEED
|
||||||
|
| SUPPORT_OSCILLATE
|
||||||
|
| SUPPORT_DIRECTION,
|
||||||
|
ATTR_SPEED: SPEED_OFF,
|
||||||
|
ATTR_OSCILLATING: False,
|
||||||
|
ATTR_DIRECTION: DIRECTION_FORWARD,
|
||||||
|
ATTR_SPEED_LIST: speed_list,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
acc = cls.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
|
||||||
|
# speed to 100 when turning on a fan on a freshly booted up server.
|
||||||
|
assert acc.char_speed.value != 0
|
||||||
|
await acc.run_handler()
|
||||||
|
assert (
|
||||||
|
acc.speed_mapping.speed_ranges == HomeKitSpeedMapping(speed_list).speed_ranges
|
||||||
|
)
|
||||||
|
|
||||||
|
acc.speed_mapping.speed_to_homekit = Mock(return_value=42)
|
||||||
|
acc.speed_mapping.speed_to_states = Mock(return_value="ludicrous")
|
||||||
|
|
||||||
|
hass.states.async_set(
|
||||||
|
entity_id,
|
||||||
|
STATE_OFF,
|
||||||
|
{
|
||||||
|
ATTR_SUPPORTED_FEATURES: SUPPORT_SET_SPEED
|
||||||
|
| SUPPORT_OSCILLATE
|
||||||
|
| SUPPORT_DIRECTION,
|
||||||
|
ATTR_SPEED: SPEED_OFF,
|
||||||
|
ATTR_OSCILLATING: False,
|
||||||
|
ATTR_DIRECTION: DIRECTION_FORWARD,
|
||||||
|
ATTR_SPEED_LIST: speed_list,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert hass.states.get(entity_id).state == STATE_OFF
|
||||||
|
|
||||||
|
# Set from HomeKit
|
||||||
|
call_set_speed = async_mock_service(hass, DOMAIN, "set_speed")
|
||||||
|
call_oscillate = async_mock_service(hass, DOMAIN, "oscillate")
|
||||||
|
call_set_direction = async_mock_service(hass, DOMAIN, "set_direction")
|
||||||
|
call_turn_on = async_mock_service(hass, DOMAIN, "turn_on")
|
||||||
|
call_turn_off = async_mock_service(hass, DOMAIN, "turn_off")
|
||||||
|
|
||||||
|
char_active_iid = acc.char_active.to_HAP()[HAP_REPR_IID]
|
||||||
|
char_direction_iid = acc.char_direction.to_HAP()[HAP_REPR_IID]
|
||||||
|
char_swing_iid = acc.char_swing.to_HAP()[HAP_REPR_IID]
|
||||||
|
char_speed_iid = acc.char_speed.to_HAP()[HAP_REPR_IID]
|
||||||
|
|
||||||
|
hk_driver.set_characteristics(
|
||||||
|
{
|
||||||
|
HAP_REPR_CHARS: [
|
||||||
|
{
|
||||||
|
HAP_REPR_AID: acc.aid,
|
||||||
|
HAP_REPR_IID: char_active_iid,
|
||||||
|
HAP_REPR_VALUE: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
HAP_REPR_AID: acc.aid,
|
||||||
|
HAP_REPR_IID: char_speed_iid,
|
||||||
|
HAP_REPR_VALUE: 42,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
HAP_REPR_AID: acc.aid,
|
||||||
|
HAP_REPR_IID: char_swing_iid,
|
||||||
|
HAP_REPR_VALUE: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
HAP_REPR_AID: acc.aid,
|
||||||
|
HAP_REPR_IID: char_direction_iid,
|
||||||
|
HAP_REPR_VALUE: 1,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"mock_addr",
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
acc.speed_mapping.speed_to_states.assert_called_with(42)
|
||||||
|
assert call_turn_on
|
||||||
|
assert call_turn_on[0].data[ATTR_ENTITY_ID] == entity_id
|
||||||
|
assert call_set_speed[0]
|
||||||
|
assert call_set_speed[0].data[ATTR_ENTITY_ID] == entity_id
|
||||||
|
assert call_set_speed[0].data[ATTR_SPEED] == "ludicrous"
|
||||||
|
assert call_oscillate[0]
|
||||||
|
assert call_oscillate[0].data[ATTR_ENTITY_ID] == entity_id
|
||||||
|
assert call_oscillate[0].data[ATTR_OSCILLATING] is True
|
||||||
|
assert call_set_direction[0]
|
||||||
|
assert call_set_direction[0].data[ATTR_ENTITY_ID] == entity_id
|
||||||
|
assert call_set_direction[0].data[ATTR_DIRECTION] == DIRECTION_REVERSE
|
||||||
|
assert len(events) == 4
|
||||||
|
|
||||||
|
assert events[1].data[ATTR_VALUE] is True
|
||||||
|
assert events[2].data[ATTR_VALUE] == DIRECTION_REVERSE
|
||||||
|
assert events[3].data[ATTR_VALUE] == "ludicrous"
|
||||||
|
|
||||||
|
hass.states.async_set(
|
||||||
|
entity_id,
|
||||||
|
STATE_ON,
|
||||||
|
{
|
||||||
|
ATTR_SUPPORTED_FEATURES: SUPPORT_SET_SPEED
|
||||||
|
| SUPPORT_OSCILLATE
|
||||||
|
| SUPPORT_DIRECTION,
|
||||||
|
ATTR_SPEED: SPEED_OFF,
|
||||||
|
ATTR_OSCILLATING: False,
|
||||||
|
ATTR_DIRECTION: DIRECTION_FORWARD,
|
||||||
|
ATTR_SPEED_LIST: speed_list,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
hk_driver.set_characteristics(
|
||||||
|
{
|
||||||
|
HAP_REPR_CHARS: [
|
||||||
|
{
|
||||||
|
HAP_REPR_AID: acc.aid,
|
||||||
|
HAP_REPR_IID: char_active_iid,
|
||||||
|
HAP_REPR_VALUE: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
HAP_REPR_AID: acc.aid,
|
||||||
|
HAP_REPR_IID: char_speed_iid,
|
||||||
|
HAP_REPR_VALUE: 42,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
HAP_REPR_AID: acc.aid,
|
||||||
|
HAP_REPR_IID: char_swing_iid,
|
||||||
|
HAP_REPR_VALUE: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
HAP_REPR_AID: acc.aid,
|
||||||
|
HAP_REPR_IID: char_direction_iid,
|
||||||
|
HAP_REPR_VALUE: 1,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"mock_addr",
|
||||||
|
)
|
||||||
|
# Turn on should not be called if its already on
|
||||||
|
# and we set a fan speed
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
acc.speed_mapping.speed_to_states.assert_called_with(42)
|
||||||
|
assert len(events) == 7
|
||||||
|
assert call_set_speed[1]
|
||||||
|
assert call_set_speed[1].data[ATTR_ENTITY_ID] == entity_id
|
||||||
|
assert call_set_speed[1].data[ATTR_SPEED] == "ludicrous"
|
||||||
|
assert call_oscillate[1]
|
||||||
|
assert call_oscillate[1].data[ATTR_ENTITY_ID] == entity_id
|
||||||
|
assert call_oscillate[1].data[ATTR_OSCILLATING] is True
|
||||||
|
assert call_set_direction[1]
|
||||||
|
assert call_set_direction[1].data[ATTR_ENTITY_ID] == entity_id
|
||||||
|
assert call_set_direction[1].data[ATTR_DIRECTION] == DIRECTION_REVERSE
|
||||||
|
|
||||||
|
assert events[-3].data[ATTR_VALUE] is True
|
||||||
|
assert events[-2].data[ATTR_VALUE] == DIRECTION_REVERSE
|
||||||
|
assert events[-1].data[ATTR_VALUE] == "ludicrous"
|
||||||
|
|
||||||
|
hk_driver.set_characteristics(
|
||||||
|
{
|
||||||
|
HAP_REPR_CHARS: [
|
||||||
|
{
|
||||||
|
HAP_REPR_AID: acc.aid,
|
||||||
|
HAP_REPR_IID: char_active_iid,
|
||||||
|
HAP_REPR_VALUE: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
HAP_REPR_AID: acc.aid,
|
||||||
|
HAP_REPR_IID: char_speed_iid,
|
||||||
|
HAP_REPR_VALUE: 42,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
HAP_REPR_AID: acc.aid,
|
||||||
|
HAP_REPR_IID: char_swing_iid,
|
||||||
|
HAP_REPR_VALUE: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
HAP_REPR_AID: acc.aid,
|
||||||
|
HAP_REPR_IID: char_direction_iid,
|
||||||
|
HAP_REPR_VALUE: 1,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"mock_addr",
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert len(events) == 8
|
||||||
|
assert call_turn_off
|
||||||
|
assert call_turn_off[0].data[ATTR_ENTITY_ID] == entity_id
|
||||||
|
assert len(call_set_speed) == 2
|
||||||
|
assert len(call_oscillate) == 2
|
||||||
|
assert len(call_set_direction) == 2
|
||||||
|
|
||||||
|
|
||||||
async def test_fan_restore(hass, hk_driver, cls, events):
|
async def test_fan_restore(hass, hk_driver, cls, events):
|
||||||
"""Test setting up an entity from state in the event registry."""
|
"""Test setting up an entity from state in the event registry."""
|
||||||
hass.state = CoreState.not_running
|
hass.state = CoreState.not_running
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
"""Test different accessory types: Lights."""
|
"""Test different accessory types: Lights."""
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
|
||||||
from asynctest import patch
|
|
||||||
from pyhap.accessory_driver import AccessoryDriver
|
|
||||||
from pyhap.const import HAP_REPR_AID, HAP_REPR_CHARS, HAP_REPR_IID, HAP_REPR_VALUE
|
from pyhap.const import HAP_REPR_AID, HAP_REPR_CHARS, HAP_REPR_IID, HAP_REPR_VALUE
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
@ -33,15 +31,6 @@ from tests.common import async_mock_service
|
|||||||
from tests.components.homekit.common import patch_debounce
|
from tests.components.homekit.common import patch_debounce
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def driver():
|
|
||||||
"""Patch AccessoryDriver without zeroconf or HAPServer."""
|
|
||||||
with patch("pyhap.accessory_driver.HAPServer"), patch(
|
|
||||||
"pyhap.accessory_driver.Zeroconf"
|
|
||||||
), patch("pyhap.accessory_driver.AccessoryDriver.persist"):
|
|
||||||
yield AccessoryDriver()
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
@pytest.fixture(scope="module")
|
||||||
def cls():
|
def cls():
|
||||||
"""Patch debounce decorator during import of type_lights."""
|
"""Patch debounce decorator during import of type_lights."""
|
||||||
@ -55,14 +44,14 @@ def cls():
|
|||||||
patcher.stop()
|
patcher.stop()
|
||||||
|
|
||||||
|
|
||||||
async def test_light_basic(hass, hk_driver, cls, events, driver):
|
async def test_light_basic(hass, hk_driver, cls, events):
|
||||||
"""Test light with char state."""
|
"""Test light with char state."""
|
||||||
entity_id = "light.demo"
|
entity_id = "light.demo"
|
||||||
|
|
||||||
hass.states.async_set(entity_id, STATE_ON, {ATTR_SUPPORTED_FEATURES: 0})
|
hass.states.async_set(entity_id, STATE_ON, {ATTR_SUPPORTED_FEATURES: 0})
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
acc = cls.light(hass, hk_driver, "Light", entity_id, 1, None)
|
acc = cls.light(hass, hk_driver, "Light", entity_id, 1, None)
|
||||||
driver.add_accessory(acc)
|
hk_driver.add_accessory(acc)
|
||||||
|
|
||||||
assert acc.aid == 1
|
assert acc.aid == 1
|
||||||
assert acc.category == 5 # Lightbulb
|
assert acc.category == 5 # Lightbulb
|
||||||
@ -90,7 +79,7 @@ async def test_light_basic(hass, hk_driver, cls, events, driver):
|
|||||||
|
|
||||||
char_on_iid = acc.char_on.to_HAP()[HAP_REPR_IID]
|
char_on_iid = acc.char_on.to_HAP()[HAP_REPR_IID]
|
||||||
|
|
||||||
driver.set_characteristics(
|
hk_driver.set_characteristics(
|
||||||
{
|
{
|
||||||
HAP_REPR_CHARS: [
|
HAP_REPR_CHARS: [
|
||||||
{HAP_REPR_AID: acc.aid, HAP_REPR_IID: char_on_iid, HAP_REPR_VALUE: 1}
|
{HAP_REPR_AID: acc.aid, HAP_REPR_IID: char_on_iid, HAP_REPR_VALUE: 1}
|
||||||
@ -109,7 +98,7 @@ async def test_light_basic(hass, hk_driver, cls, events, driver):
|
|||||||
hass.states.async_set(entity_id, STATE_ON)
|
hass.states.async_set(entity_id, STATE_ON)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
driver.set_characteristics(
|
hk_driver.set_characteristics(
|
||||||
{
|
{
|
||||||
HAP_REPR_CHARS: [
|
HAP_REPR_CHARS: [
|
||||||
{HAP_REPR_AID: acc.aid, HAP_REPR_IID: char_on_iid, HAP_REPR_VALUE: 0}
|
{HAP_REPR_AID: acc.aid, HAP_REPR_IID: char_on_iid, HAP_REPR_VALUE: 0}
|
||||||
@ -124,7 +113,7 @@ async def test_light_basic(hass, hk_driver, cls, events, driver):
|
|||||||
assert events[-1].data[ATTR_VALUE] == "Set state to 0"
|
assert events[-1].data[ATTR_VALUE] == "Set state to 0"
|
||||||
|
|
||||||
|
|
||||||
async def test_light_brightness(hass, hk_driver, cls, events, driver):
|
async def test_light_brightness(hass, hk_driver, cls, events):
|
||||||
"""Test light with brightness."""
|
"""Test light with brightness."""
|
||||||
entity_id = "light.demo"
|
entity_id = "light.demo"
|
||||||
|
|
||||||
@ -135,7 +124,7 @@ async def test_light_brightness(hass, hk_driver, cls, events, driver):
|
|||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
acc = cls.light(hass, hk_driver, "Light", entity_id, 1, None)
|
acc = cls.light(hass, hk_driver, "Light", entity_id, 1, None)
|
||||||
driver.add_accessory(acc)
|
hk_driver.add_accessory(acc)
|
||||||
|
|
||||||
# Initial value can be anything but 0. If it is 0, it might cause HomeKit to set the
|
# Initial value can be anything but 0. If it is 0, it might cause HomeKit to set the
|
||||||
# brightness to 100 when turning on a light on a freshly booted up server.
|
# brightness to 100 when turning on a light on a freshly booted up server.
|
||||||
@ -155,7 +144,7 @@ async def test_light_brightness(hass, hk_driver, cls, events, driver):
|
|||||||
call_turn_on = async_mock_service(hass, DOMAIN, "turn_on")
|
call_turn_on = async_mock_service(hass, DOMAIN, "turn_on")
|
||||||
call_turn_off = async_mock_service(hass, DOMAIN, "turn_off")
|
call_turn_off = async_mock_service(hass, DOMAIN, "turn_off")
|
||||||
|
|
||||||
driver.set_characteristics(
|
hk_driver.set_characteristics(
|
||||||
{
|
{
|
||||||
HAP_REPR_CHARS: [
|
HAP_REPR_CHARS: [
|
||||||
{HAP_REPR_AID: acc.aid, HAP_REPR_IID: char_on_iid, HAP_REPR_VALUE: 1},
|
{HAP_REPR_AID: acc.aid, HAP_REPR_IID: char_on_iid, HAP_REPR_VALUE: 1},
|
||||||
@ -178,7 +167,7 @@ async def test_light_brightness(hass, hk_driver, cls, events, driver):
|
|||||||
== f"Set state to 1, brightness at 20{UNIT_PERCENTAGE}"
|
== f"Set state to 1, brightness at 20{UNIT_PERCENTAGE}"
|
||||||
)
|
)
|
||||||
|
|
||||||
driver.set_characteristics(
|
hk_driver.set_characteristics(
|
||||||
{
|
{
|
||||||
HAP_REPR_CHARS: [
|
HAP_REPR_CHARS: [
|
||||||
{HAP_REPR_AID: acc.aid, HAP_REPR_IID: char_on_iid, HAP_REPR_VALUE: 1},
|
{HAP_REPR_AID: acc.aid, HAP_REPR_IID: char_on_iid, HAP_REPR_VALUE: 1},
|
||||||
@ -201,7 +190,7 @@ async def test_light_brightness(hass, hk_driver, cls, events, driver):
|
|||||||
== f"Set state to 1, brightness at 40{UNIT_PERCENTAGE}"
|
== f"Set state to 1, brightness at 40{UNIT_PERCENTAGE}"
|
||||||
)
|
)
|
||||||
|
|
||||||
driver.set_characteristics(
|
hk_driver.set_characteristics(
|
||||||
{
|
{
|
||||||
HAP_REPR_CHARS: [
|
HAP_REPR_CHARS: [
|
||||||
{HAP_REPR_AID: acc.aid, HAP_REPR_IID: char_on_iid, HAP_REPR_VALUE: 1},
|
{HAP_REPR_AID: acc.aid, HAP_REPR_IID: char_on_iid, HAP_REPR_VALUE: 1},
|
||||||
@ -247,7 +236,7 @@ async def test_light_brightness(hass, hk_driver, cls, events, driver):
|
|||||||
assert acc.char_brightness.value == 1
|
assert acc.char_brightness.value == 1
|
||||||
|
|
||||||
|
|
||||||
async def test_light_color_temperature(hass, hk_driver, cls, events, driver):
|
async def test_light_color_temperature(hass, hk_driver, cls, events):
|
||||||
"""Test light with color temperature."""
|
"""Test light with color temperature."""
|
||||||
entity_id = "light.demo"
|
entity_id = "light.demo"
|
||||||
|
|
||||||
@ -258,7 +247,7 @@ async def test_light_color_temperature(hass, hk_driver, cls, events, driver):
|
|||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
acc = cls.light(hass, hk_driver, "Light", entity_id, 1, None)
|
acc = cls.light(hass, hk_driver, "Light", entity_id, 1, None)
|
||||||
driver.add_accessory(acc)
|
hk_driver.add_accessory(acc)
|
||||||
|
|
||||||
assert acc.char_color_temperature.value == 190
|
assert acc.char_color_temperature.value == 190
|
||||||
|
|
||||||
@ -271,7 +260,7 @@ async def test_light_color_temperature(hass, hk_driver, cls, events, driver):
|
|||||||
|
|
||||||
char_color_temperature_iid = acc.char_color_temperature.to_HAP()[HAP_REPR_IID]
|
char_color_temperature_iid = acc.char_color_temperature.to_HAP()[HAP_REPR_IID]
|
||||||
|
|
||||||
driver.set_characteristics(
|
hk_driver.set_characteristics(
|
||||||
{
|
{
|
||||||
HAP_REPR_CHARS: [
|
HAP_REPR_CHARS: [
|
||||||
{
|
{
|
||||||
@ -313,7 +302,7 @@ async def test_light_color_temperature_and_rgb_color(hass, hk_driver, cls, event
|
|||||||
assert not hasattr(acc, "char_color_temperature")
|
assert not hasattr(acc, "char_color_temperature")
|
||||||
|
|
||||||
|
|
||||||
async def test_light_rgb_color(hass, hk_driver, cls, events, driver):
|
async def test_light_rgb_color(hass, hk_driver, cls, events):
|
||||||
"""Test light with rgb_color."""
|
"""Test light with rgb_color."""
|
||||||
entity_id = "light.demo"
|
entity_id = "light.demo"
|
||||||
|
|
||||||
@ -324,7 +313,7 @@ async def test_light_rgb_color(hass, hk_driver, cls, events, driver):
|
|||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
acc = cls.light(hass, hk_driver, "Light", entity_id, 1, None)
|
acc = cls.light(hass, hk_driver, "Light", entity_id, 1, None)
|
||||||
driver.add_accessory(acc)
|
hk_driver.add_accessory(acc)
|
||||||
|
|
||||||
assert acc.char_hue.value == 260
|
assert acc.char_hue.value == 260
|
||||||
assert acc.char_saturation.value == 90
|
assert acc.char_saturation.value == 90
|
||||||
@ -340,7 +329,7 @@ async def test_light_rgb_color(hass, hk_driver, cls, events, driver):
|
|||||||
char_hue_iid = acc.char_hue.to_HAP()[HAP_REPR_IID]
|
char_hue_iid = acc.char_hue.to_HAP()[HAP_REPR_IID]
|
||||||
char_saturation_iid = acc.char_saturation.to_HAP()[HAP_REPR_IID]
|
char_saturation_iid = acc.char_saturation.to_HAP()[HAP_REPR_IID]
|
||||||
|
|
||||||
driver.set_characteristics(
|
hk_driver.set_characteristics(
|
||||||
{
|
{
|
||||||
HAP_REPR_CHARS: [
|
HAP_REPR_CHARS: [
|
||||||
{
|
{
|
||||||
@ -365,7 +354,7 @@ async def test_light_rgb_color(hass, hk_driver, cls, events, driver):
|
|||||||
assert events[-1].data[ATTR_VALUE] == "set color at (145, 75)"
|
assert events[-1].data[ATTR_VALUE] == "set color at (145, 75)"
|
||||||
|
|
||||||
|
|
||||||
async def test_light_restore(hass, hk_driver, cls, events, driver):
|
async def test_light_restore(hass, hk_driver, cls, events):
|
||||||
"""Test setting up an entity from state in the event registry."""
|
"""Test setting up an entity from state in the event registry."""
|
||||||
hass.state = CoreState.not_running
|
hass.state = CoreState.not_running
|
||||||
|
|
||||||
@ -386,7 +375,7 @@ async def test_light_restore(hass, hk_driver, cls, events, driver):
|
|||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
acc = cls.light(hass, hk_driver, "Light", "light.simple", 1, None)
|
acc = cls.light(hass, hk_driver, "Light", "light.simple", 1, None)
|
||||||
driver.add_accessory(acc)
|
hk_driver.add_accessory(acc)
|
||||||
|
|
||||||
assert acc.category == 5 # Lightbulb
|
assert acc.category == 5 # Lightbulb
|
||||||
assert acc.chars == []
|
assert acc.chars == []
|
||||||
@ -398,7 +387,7 @@ async def test_light_restore(hass, hk_driver, cls, events, driver):
|
|||||||
assert acc.char_on.value == 0
|
assert acc.char_on.value == 0
|
||||||
|
|
||||||
|
|
||||||
async def test_light_set_brightness_and_color(hass, hk_driver, cls, events, driver):
|
async def test_light_set_brightness_and_color(hass, hk_driver, cls, events):
|
||||||
"""Test light with all chars in one go."""
|
"""Test light with all chars in one go."""
|
||||||
entity_id = "light.demo"
|
entity_id = "light.demo"
|
||||||
|
|
||||||
@ -412,7 +401,7 @@ async def test_light_set_brightness_and_color(hass, hk_driver, cls, events, driv
|
|||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
acc = cls.light(hass, hk_driver, "Light", entity_id, 1, None)
|
acc = cls.light(hass, hk_driver, "Light", entity_id, 1, None)
|
||||||
driver.add_accessory(acc)
|
hk_driver.add_accessory(acc)
|
||||||
|
|
||||||
# Initial value can be anything but 0. If it is 0, it might cause HomeKit to set the
|
# Initial value can be anything but 0. If it is 0, it might cause HomeKit to set the
|
||||||
# brightness to 100 when turning on a light on a freshly booted up server.
|
# brightness to 100 when turning on a light on a freshly booted up server.
|
||||||
@ -438,7 +427,7 @@ async def test_light_set_brightness_and_color(hass, hk_driver, cls, events, driv
|
|||||||
# Set from HomeKit
|
# Set from HomeKit
|
||||||
call_turn_on = async_mock_service(hass, DOMAIN, "turn_on")
|
call_turn_on = async_mock_service(hass, DOMAIN, "turn_on")
|
||||||
|
|
||||||
driver.set_characteristics(
|
hk_driver.set_characteristics(
|
||||||
{
|
{
|
||||||
HAP_REPR_CHARS: [
|
HAP_REPR_CHARS: [
|
||||||
{HAP_REPR_AID: acc.aid, HAP_REPR_IID: char_on_iid, HAP_REPR_VALUE: 1},
|
{HAP_REPR_AID: acc.aid, HAP_REPR_IID: char_on_iid, HAP_REPR_VALUE: 1},
|
||||||
@ -474,9 +463,7 @@ async def test_light_set_brightness_and_color(hass, hk_driver, cls, events, driv
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def test_light_set_brightness_and_color_temp(
|
async def test_light_set_brightness_and_color_temp(hass, hk_driver, cls, events):
|
||||||
hass, hk_driver, cls, events, driver
|
|
||||||
):
|
|
||||||
"""Test light with all chars in one go."""
|
"""Test light with all chars in one go."""
|
||||||
entity_id = "light.demo"
|
entity_id = "light.demo"
|
||||||
|
|
||||||
@ -490,7 +477,7 @@ async def test_light_set_brightness_and_color_temp(
|
|||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
acc = cls.light(hass, hk_driver, "Light", entity_id, 1, None)
|
acc = cls.light(hass, hk_driver, "Light", entity_id, 1, None)
|
||||||
driver.add_accessory(acc)
|
hk_driver.add_accessory(acc)
|
||||||
|
|
||||||
# Initial value can be anything but 0. If it is 0, it might cause HomeKit to set the
|
# Initial value can be anything but 0. If it is 0, it might cause HomeKit to set the
|
||||||
# brightness to 100 when turning on a light on a freshly booted up server.
|
# brightness to 100 when turning on a light on a freshly booted up server.
|
||||||
@ -514,7 +501,7 @@ async def test_light_set_brightness_and_color_temp(
|
|||||||
# Set from HomeKit
|
# Set from HomeKit
|
||||||
call_turn_on = async_mock_service(hass, DOMAIN, "turn_on")
|
call_turn_on = async_mock_service(hass, DOMAIN, "turn_on")
|
||||||
|
|
||||||
driver.set_characteristics(
|
hk_driver.set_characteristics(
|
||||||
{
|
{
|
||||||
HAP_REPR_CHARS: [
|
HAP_REPR_CHARS: [
|
||||||
{HAP_REPR_AID: acc.aid, HAP_REPR_IID: char_on_iid, HAP_REPR_VALUE: 1},
|
{HAP_REPR_AID: acc.aid, HAP_REPR_IID: char_on_iid, HAP_REPR_VALUE: 1},
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
from pyhap.accessory_driver import AccessoryDriver
|
|
||||||
from pyhap.const import HAP_REPR_AID, HAP_REPR_CHARS, HAP_REPR_IID, HAP_REPR_VALUE
|
from pyhap.const import HAP_REPR_AID, HAP_REPR_CHARS, HAP_REPR_IID, HAP_REPR_VALUE
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
@ -62,15 +61,6 @@ from tests.common import async_mock_service
|
|||||||
from tests.components.homekit.common import patch_debounce
|
from tests.components.homekit.common import patch_debounce
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def driver():
|
|
||||||
"""Patch AccessoryDriver without zeroconf or HAPServer."""
|
|
||||||
with patch("pyhap.accessory_driver.HAPServer"), patch(
|
|
||||||
"pyhap.accessory_driver.Zeroconf"
|
|
||||||
), patch("pyhap.accessory_driver.AccessoryDriver.persist"):
|
|
||||||
yield AccessoryDriver()
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
@pytest.fixture(scope="module")
|
||||||
def cls():
|
def cls():
|
||||||
"""Patch debounce decorator during import of type_thermostats."""
|
"""Patch debounce decorator during import of type_thermostats."""
|
||||||
@ -85,7 +75,7 @@ def cls():
|
|||||||
patcher.stop()
|
patcher.stop()
|
||||||
|
|
||||||
|
|
||||||
async def test_thermostat(hass, hk_driver, cls, events, driver):
|
async def test_thermostat(hass, hk_driver, cls, events):
|
||||||
"""Test if accessory and HA are updated accordingly."""
|
"""Test if accessory and HA are updated accordingly."""
|
||||||
entity_id = "climate.test"
|
entity_id = "climate.test"
|
||||||
|
|
||||||
@ -106,7 +96,7 @@ async def test_thermostat(hass, hk_driver, cls, events, driver):
|
|||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
acc = cls.thermostat(hass, hk_driver, "Climate", entity_id, 1, None)
|
acc = cls.thermostat(hass, hk_driver, "Climate", entity_id, 1, None)
|
||||||
driver.add_accessory(acc)
|
hk_driver.add_accessory(acc)
|
||||||
|
|
||||||
await acc.run_handler()
|
await acc.run_handler()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
@ -293,7 +283,7 @@ async def test_thermostat(hass, hk_driver, cls, events, driver):
|
|||||||
char_target_temp_iid = acc.char_target_temp.to_HAP()[HAP_REPR_IID]
|
char_target_temp_iid = acc.char_target_temp.to_HAP()[HAP_REPR_IID]
|
||||||
char_heat_cool_iid = acc.char_target_heat_cool.to_HAP()[HAP_REPR_IID]
|
char_heat_cool_iid = acc.char_target_heat_cool.to_HAP()[HAP_REPR_IID]
|
||||||
|
|
||||||
driver.set_characteristics(
|
hk_driver.set_characteristics(
|
||||||
{
|
{
|
||||||
HAP_REPR_CHARS: [
|
HAP_REPR_CHARS: [
|
||||||
{
|
{
|
||||||
@ -313,7 +303,7 @@ async def test_thermostat(hass, hk_driver, cls, events, driver):
|
|||||||
assert len(events) == 1
|
assert len(events) == 1
|
||||||
assert events[-1].data[ATTR_VALUE] == "TargetTemperature to 19.0°C"
|
assert events[-1].data[ATTR_VALUE] == "TargetTemperature to 19.0°C"
|
||||||
|
|
||||||
driver.set_characteristics(
|
hk_driver.set_characteristics(
|
||||||
{
|
{
|
||||||
HAP_REPR_CHARS: [
|
HAP_REPR_CHARS: [
|
||||||
{
|
{
|
||||||
@ -328,7 +318,7 @@ async def test_thermostat(hass, hk_driver, cls, events, driver):
|
|||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert not call_set_hvac_mode
|
assert not call_set_hvac_mode
|
||||||
|
|
||||||
driver.set_characteristics(
|
hk_driver.set_characteristics(
|
||||||
{
|
{
|
||||||
HAP_REPR_CHARS: [
|
HAP_REPR_CHARS: [
|
||||||
{
|
{
|
||||||
@ -348,7 +338,7 @@ async def test_thermostat(hass, hk_driver, cls, events, driver):
|
|||||||
assert len(events) == 2
|
assert len(events) == 2
|
||||||
assert events[-1].data[ATTR_VALUE] == "TargetHeatingCoolingState to 1"
|
assert events[-1].data[ATTR_VALUE] == "TargetHeatingCoolingState to 1"
|
||||||
|
|
||||||
driver.set_characteristics(
|
hk_driver.set_characteristics(
|
||||||
{
|
{
|
||||||
HAP_REPR_CHARS: [
|
HAP_REPR_CHARS: [
|
||||||
{
|
{
|
||||||
@ -369,7 +359,7 @@ async def test_thermostat(hass, hk_driver, cls, events, driver):
|
|||||||
assert events[-1].data[ATTR_VALUE] == "TargetHeatingCoolingState to 3"
|
assert events[-1].data[ATTR_VALUE] == "TargetHeatingCoolingState to 3"
|
||||||
|
|
||||||
|
|
||||||
async def test_thermostat_auto(hass, hk_driver, cls, events, driver):
|
async def test_thermostat_auto(hass, hk_driver, cls, events):
|
||||||
"""Test if accessory and HA are updated accordingly."""
|
"""Test if accessory and HA are updated accordingly."""
|
||||||
entity_id = "climate.test"
|
entity_id = "climate.test"
|
||||||
|
|
||||||
@ -384,7 +374,7 @@ async def test_thermostat_auto(hass, hk_driver, cls, events, driver):
|
|||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
acc = cls.thermostat(hass, hk_driver, "Climate", entity_id, 1, None)
|
acc = cls.thermostat(hass, hk_driver, "Climate", entity_id, 1, None)
|
||||||
driver.add_accessory(acc)
|
hk_driver.add_accessory(acc)
|
||||||
|
|
||||||
await acc.run_handler()
|
await acc.run_handler()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
@ -459,7 +449,7 @@ async def test_thermostat_auto(hass, hk_driver, cls, events, driver):
|
|||||||
char_heating_thresh_temp_iid = acc.char_heating_thresh_temp.to_HAP()[HAP_REPR_IID]
|
char_heating_thresh_temp_iid = acc.char_heating_thresh_temp.to_HAP()[HAP_REPR_IID]
|
||||||
char_cooling_thresh_temp_iid = acc.char_cooling_thresh_temp.to_HAP()[HAP_REPR_IID]
|
char_cooling_thresh_temp_iid = acc.char_cooling_thresh_temp.to_HAP()[HAP_REPR_IID]
|
||||||
|
|
||||||
driver.set_characteristics(
|
hk_driver.set_characteristics(
|
||||||
{
|
{
|
||||||
HAP_REPR_CHARS: [
|
HAP_REPR_CHARS: [
|
||||||
{
|
{
|
||||||
@ -491,7 +481,7 @@ async def test_thermostat_auto(hass, hk_driver, cls, events, driver):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def test_thermostat_humidity(hass, hk_driver, cls, events, driver):
|
async def test_thermostat_humidity(hass, hk_driver, cls, events):
|
||||||
"""Test if accessory and HA are updated accordingly with humidity."""
|
"""Test if accessory and HA are updated accordingly with humidity."""
|
||||||
entity_id = "climate.test"
|
entity_id = "climate.test"
|
||||||
|
|
||||||
@ -499,7 +489,7 @@ async def test_thermostat_humidity(hass, hk_driver, cls, events, driver):
|
|||||||
hass.states.async_set(entity_id, HVAC_MODE_OFF, {ATTR_SUPPORTED_FEATURES: 4})
|
hass.states.async_set(entity_id, HVAC_MODE_OFF, {ATTR_SUPPORTED_FEATURES: 4})
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
acc = cls.thermostat(hass, hk_driver, "Climate", entity_id, 1, None)
|
acc = cls.thermostat(hass, hk_driver, "Climate", entity_id, 1, None)
|
||||||
driver.add_accessory(acc)
|
hk_driver.add_accessory(acc)
|
||||||
|
|
||||||
await acc.run_handler()
|
await acc.run_handler()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
@ -528,7 +518,7 @@ async def test_thermostat_humidity(hass, hk_driver, cls, events, driver):
|
|||||||
|
|
||||||
char_target_humidity_iid = acc.char_target_humidity.to_HAP()[HAP_REPR_IID]
|
char_target_humidity_iid = acc.char_target_humidity.to_HAP()[HAP_REPR_IID]
|
||||||
|
|
||||||
driver.set_characteristics(
|
hk_driver.set_characteristics(
|
||||||
{
|
{
|
||||||
HAP_REPR_CHARS: [
|
HAP_REPR_CHARS: [
|
||||||
{
|
{
|
||||||
@ -550,7 +540,7 @@ async def test_thermostat_humidity(hass, hk_driver, cls, events, driver):
|
|||||||
assert events[-1].data[ATTR_VALUE] == "35%"
|
assert events[-1].data[ATTR_VALUE] == "35%"
|
||||||
|
|
||||||
|
|
||||||
async def test_thermostat_power_state(hass, hk_driver, cls, events, driver):
|
async def test_thermostat_power_state(hass, hk_driver, cls, events):
|
||||||
"""Test if accessory and HA are updated accordingly."""
|
"""Test if accessory and HA are updated accordingly."""
|
||||||
entity_id = "climate.test"
|
entity_id = "climate.test"
|
||||||
|
|
||||||
@ -574,7 +564,7 @@ async def test_thermostat_power_state(hass, hk_driver, cls, events, driver):
|
|||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
acc = cls.thermostat(hass, hk_driver, "Climate", entity_id, 1, None)
|
acc = cls.thermostat(hass, hk_driver, "Climate", entity_id, 1, None)
|
||||||
driver.add_accessory(acc)
|
hk_driver.add_accessory(acc)
|
||||||
|
|
||||||
await acc.run_handler()
|
await acc.run_handler()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
@ -627,7 +617,7 @@ async def test_thermostat_power_state(hass, hk_driver, cls, events, driver):
|
|||||||
|
|
||||||
char_target_heat_cool_iid = acc.char_target_heat_cool.to_HAP()[HAP_REPR_IID]
|
char_target_heat_cool_iid = acc.char_target_heat_cool.to_HAP()[HAP_REPR_IID]
|
||||||
|
|
||||||
driver.set_characteristics(
|
hk_driver.set_characteristics(
|
||||||
{
|
{
|
||||||
HAP_REPR_CHARS: [
|
HAP_REPR_CHARS: [
|
||||||
{
|
{
|
||||||
@ -648,7 +638,7 @@ async def test_thermostat_power_state(hass, hk_driver, cls, events, driver):
|
|||||||
assert len(events) == 1
|
assert len(events) == 1
|
||||||
assert events[-1].data[ATTR_VALUE] == "TargetHeatingCoolingState to 1"
|
assert events[-1].data[ATTR_VALUE] == "TargetHeatingCoolingState to 1"
|
||||||
|
|
||||||
driver.set_characteristics(
|
hk_driver.set_characteristics(
|
||||||
{
|
{
|
||||||
HAP_REPR_CHARS: [
|
HAP_REPR_CHARS: [
|
||||||
{
|
{
|
||||||
@ -670,7 +660,7 @@ async def test_thermostat_power_state(hass, hk_driver, cls, events, driver):
|
|||||||
assert acc.char_target_heat_cool.value == 2
|
assert acc.char_target_heat_cool.value == 2
|
||||||
|
|
||||||
|
|
||||||
async def test_thermostat_fahrenheit(hass, hk_driver, cls, events, driver):
|
async def test_thermostat_fahrenheit(hass, hk_driver, cls, events):
|
||||||
"""Test if accessory and HA are updated accordingly."""
|
"""Test if accessory and HA are updated accordingly."""
|
||||||
entity_id = "climate.test"
|
entity_id = "climate.test"
|
||||||
|
|
||||||
@ -686,7 +676,7 @@ async def test_thermostat_fahrenheit(hass, hk_driver, cls, events, driver):
|
|||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
with patch.object(hass.config.units, CONF_TEMPERATURE_UNIT, new=TEMP_FAHRENHEIT):
|
with patch.object(hass.config.units, CONF_TEMPERATURE_UNIT, new=TEMP_FAHRENHEIT):
|
||||||
acc = cls.thermostat(hass, hk_driver, "Climate", entity_id, 1, None)
|
acc = cls.thermostat(hass, hk_driver, "Climate", entity_id, 1, None)
|
||||||
driver.add_accessory(acc)
|
hk_driver.add_accessory(acc)
|
||||||
await acc.run_handler()
|
await acc.run_handler()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
@ -717,7 +707,7 @@ async def test_thermostat_fahrenheit(hass, hk_driver, cls, events, driver):
|
|||||||
char_heating_thresh_temp_iid = acc.char_heating_thresh_temp.to_HAP()[HAP_REPR_IID]
|
char_heating_thresh_temp_iid = acc.char_heating_thresh_temp.to_HAP()[HAP_REPR_IID]
|
||||||
char_target_temp_iid = acc.char_target_temp.to_HAP()[HAP_REPR_IID]
|
char_target_temp_iid = acc.char_target_temp.to_HAP()[HAP_REPR_IID]
|
||||||
|
|
||||||
driver.set_characteristics(
|
hk_driver.set_characteristics(
|
||||||
{
|
{
|
||||||
HAP_REPR_CHARS: [
|
HAP_REPR_CHARS: [
|
||||||
{
|
{
|
||||||
@ -738,7 +728,7 @@ async def test_thermostat_fahrenheit(hass, hk_driver, cls, events, driver):
|
|||||||
assert len(events) == 1
|
assert len(events) == 1
|
||||||
assert events[-1].data[ATTR_VALUE] == "CoolingThresholdTemperature to 23°C"
|
assert events[-1].data[ATTR_VALUE] == "CoolingThresholdTemperature to 23°C"
|
||||||
|
|
||||||
driver.set_characteristics(
|
hk_driver.set_characteristics(
|
||||||
{
|
{
|
||||||
HAP_REPR_CHARS: [
|
HAP_REPR_CHARS: [
|
||||||
{
|
{
|
||||||
@ -759,7 +749,7 @@ async def test_thermostat_fahrenheit(hass, hk_driver, cls, events, driver):
|
|||||||
assert len(events) == 2
|
assert len(events) == 2
|
||||||
assert events[-1].data[ATTR_VALUE] == "HeatingThresholdTemperature to 22°C"
|
assert events[-1].data[ATTR_VALUE] == "HeatingThresholdTemperature to 22°C"
|
||||||
|
|
||||||
driver.set_characteristics(
|
hk_driver.set_characteristics(
|
||||||
{
|
{
|
||||||
HAP_REPR_CHARS: [
|
HAP_REPR_CHARS: [
|
||||||
{
|
{
|
||||||
@ -779,7 +769,7 @@ async def test_thermostat_fahrenheit(hass, hk_driver, cls, events, driver):
|
|||||||
assert events[-1].data[ATTR_VALUE] == "TargetTemperature to 24.0°C"
|
assert events[-1].data[ATTR_VALUE] == "TargetTemperature to 24.0°C"
|
||||||
|
|
||||||
|
|
||||||
async def test_thermostat_get_temperature_range(hass, hk_driver, cls, driver):
|
async def test_thermostat_get_temperature_range(hass, hk_driver, cls):
|
||||||
"""Test if temperature range is evaluated correctly."""
|
"""Test if temperature range is evaluated correctly."""
|
||||||
entity_id = "climate.test"
|
entity_id = "climate.test"
|
||||||
|
|
||||||
@ -801,14 +791,14 @@ async def test_thermostat_get_temperature_range(hass, hk_driver, cls, driver):
|
|||||||
assert acc.get_temperature_range() == (15.5, 21.0)
|
assert acc.get_temperature_range() == (15.5, 21.0)
|
||||||
|
|
||||||
|
|
||||||
async def test_thermostat_temperature_step_whole(hass, hk_driver, cls, driver):
|
async def test_thermostat_temperature_step_whole(hass, hk_driver, cls):
|
||||||
"""Test climate device with single digit precision."""
|
"""Test climate device with single digit precision."""
|
||||||
entity_id = "climate.test"
|
entity_id = "climate.test"
|
||||||
|
|
||||||
hass.states.async_set(entity_id, HVAC_MODE_OFF, {ATTR_TARGET_TEMP_STEP: 1})
|
hass.states.async_set(entity_id, HVAC_MODE_OFF, {ATTR_TARGET_TEMP_STEP: 1})
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
acc = cls.thermostat(hass, hk_driver, "Climate", entity_id, 1, None)
|
acc = cls.thermostat(hass, hk_driver, "Climate", entity_id, 1, None)
|
||||||
driver.add_accessory(acc)
|
hk_driver.add_accessory(acc)
|
||||||
|
|
||||||
await acc.run_handler()
|
await acc.run_handler()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
@ -861,7 +851,7 @@ async def test_thermostat_restore(hass, hk_driver, cls, events):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async def test_thermostat_hvac_modes(hass, hk_driver, cls, driver):
|
async def test_thermostat_hvac_modes(hass, hk_driver, cls):
|
||||||
"""Test if unsupported HVAC modes are deactivated in HomeKit."""
|
"""Test if unsupported HVAC modes are deactivated in HomeKit."""
|
||||||
entity_id = "climate.test"
|
entity_id = "climate.test"
|
||||||
|
|
||||||
@ -871,7 +861,7 @@ async def test_thermostat_hvac_modes(hass, hk_driver, cls, driver):
|
|||||||
|
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
acc = cls.thermostat(hass, hk_driver, "Climate", entity_id, 1, None)
|
acc = cls.thermostat(hass, hk_driver, "Climate", entity_id, 1, None)
|
||||||
driver.add_accessory(acc)
|
hk_driver.add_accessory(acc)
|
||||||
|
|
||||||
await acc.run_handler()
|
await acc.run_handler()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
@ -894,7 +884,7 @@ async def test_thermostat_hvac_modes(hass, hk_driver, cls, driver):
|
|||||||
assert acc.char_target_heat_cool.value == 1
|
assert acc.char_target_heat_cool.value == 1
|
||||||
|
|
||||||
|
|
||||||
async def test_thermostat_hvac_modes_with_auto_heat_cool(hass, hk_driver, cls, driver):
|
async def test_thermostat_hvac_modes_with_auto_heat_cool(hass, hk_driver, cls):
|
||||||
"""Test we get heat cool over auto."""
|
"""Test we get heat cool over auto."""
|
||||||
entity_id = "climate.test"
|
entity_id = "climate.test"
|
||||||
|
|
||||||
@ -914,7 +904,7 @@ async def test_thermostat_hvac_modes_with_auto_heat_cool(hass, hk_driver, cls, d
|
|||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
acc = cls.thermostat(hass, hk_driver, "Climate", entity_id, 1, None)
|
acc = cls.thermostat(hass, hk_driver, "Climate", entity_id, 1, None)
|
||||||
driver.add_accessory(acc)
|
hk_driver.add_accessory(acc)
|
||||||
|
|
||||||
await acc.run_handler()
|
await acc.run_handler()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
@ -937,7 +927,7 @@ async def test_thermostat_hvac_modes_with_auto_heat_cool(hass, hk_driver, cls, d
|
|||||||
|
|
||||||
char_target_heat_cool_iid = acc.char_target_heat_cool.to_HAP()[HAP_REPR_IID]
|
char_target_heat_cool_iid = acc.char_target_heat_cool.to_HAP()[HAP_REPR_IID]
|
||||||
|
|
||||||
driver.set_characteristics(
|
hk_driver.set_characteristics(
|
||||||
{
|
{
|
||||||
HAP_REPR_CHARS: [
|
HAP_REPR_CHARS: [
|
||||||
{
|
{
|
||||||
@ -957,9 +947,7 @@ async def test_thermostat_hvac_modes_with_auto_heat_cool(hass, hk_driver, cls, d
|
|||||||
assert acc.char_target_heat_cool.value == 3
|
assert acc.char_target_heat_cool.value == 3
|
||||||
|
|
||||||
|
|
||||||
async def test_thermostat_hvac_modes_with_auto_no_heat_cool(
|
async def test_thermostat_hvac_modes_with_auto_no_heat_cool(hass, hk_driver, cls):
|
||||||
hass, hk_driver, cls, driver
|
|
||||||
):
|
|
||||||
"""Test we get auto when there is no heat cool."""
|
"""Test we get auto when there is no heat cool."""
|
||||||
entity_id = "climate.test"
|
entity_id = "climate.test"
|
||||||
|
|
||||||
@ -972,7 +960,7 @@ async def test_thermostat_hvac_modes_with_auto_no_heat_cool(
|
|||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
acc = cls.thermostat(hass, hk_driver, "Climate", entity_id, 1, None)
|
acc = cls.thermostat(hass, hk_driver, "Climate", entity_id, 1, None)
|
||||||
driver.add_accessory(acc)
|
hk_driver.add_accessory(acc)
|
||||||
|
|
||||||
await acc.run_handler()
|
await acc.run_handler()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
@ -995,7 +983,7 @@ async def test_thermostat_hvac_modes_with_auto_no_heat_cool(
|
|||||||
|
|
||||||
char_target_heat_cool_iid = acc.char_target_heat_cool.to_HAP()[HAP_REPR_IID]
|
char_target_heat_cool_iid = acc.char_target_heat_cool.to_HAP()[HAP_REPR_IID]
|
||||||
|
|
||||||
driver.set_characteristics(
|
hk_driver.set_characteristics(
|
||||||
{
|
{
|
||||||
HAP_REPR_CHARS: [
|
HAP_REPR_CHARS: [
|
||||||
{
|
{
|
||||||
@ -1015,7 +1003,7 @@ async def test_thermostat_hvac_modes_with_auto_no_heat_cool(
|
|||||||
assert acc.char_target_heat_cool.value == 3
|
assert acc.char_target_heat_cool.value == 3
|
||||||
|
|
||||||
|
|
||||||
async def test_thermostat_hvac_modes_with_auto_only(hass, hk_driver, cls, driver):
|
async def test_thermostat_hvac_modes_with_auto_only(hass, hk_driver, cls):
|
||||||
"""Test if unsupported HVAC modes are deactivated in HomeKit."""
|
"""Test if unsupported HVAC modes are deactivated in HomeKit."""
|
||||||
entity_id = "climate.test"
|
entity_id = "climate.test"
|
||||||
|
|
||||||
@ -1025,7 +1013,7 @@ async def test_thermostat_hvac_modes_with_auto_only(hass, hk_driver, cls, driver
|
|||||||
|
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
acc = cls.thermostat(hass, hk_driver, "Climate", entity_id, 1, None)
|
acc = cls.thermostat(hass, hk_driver, "Climate", entity_id, 1, None)
|
||||||
driver.add_accessory(acc)
|
hk_driver.add_accessory(acc)
|
||||||
|
|
||||||
await acc.run_handler()
|
await acc.run_handler()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
@ -1048,7 +1036,7 @@ async def test_thermostat_hvac_modes_with_auto_only(hass, hk_driver, cls, driver
|
|||||||
assert acc.char_target_heat_cool.value == 3
|
assert acc.char_target_heat_cool.value == 3
|
||||||
|
|
||||||
|
|
||||||
async def test_thermostat_hvac_modes_without_off(hass, hk_driver, cls, driver):
|
async def test_thermostat_hvac_modes_without_off(hass, hk_driver, cls):
|
||||||
"""Test a thermostat that has no off."""
|
"""Test a thermostat that has no off."""
|
||||||
entity_id = "climate.test"
|
entity_id = "climate.test"
|
||||||
|
|
||||||
@ -1058,7 +1046,7 @@ async def test_thermostat_hvac_modes_without_off(hass, hk_driver, cls, driver):
|
|||||||
|
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
acc = cls.thermostat(hass, hk_driver, "Climate", entity_id, 1, None)
|
acc = cls.thermostat(hass, hk_driver, "Climate", entity_id, 1, None)
|
||||||
driver.add_accessory(acc)
|
hk_driver.add_accessory(acc)
|
||||||
|
|
||||||
await acc.run_handler()
|
await acc.run_handler()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
@ -1085,9 +1073,7 @@ async def test_thermostat_hvac_modes_without_off(hass, hk_driver, cls, driver):
|
|||||||
assert acc.char_target_heat_cool.value == 1
|
assert acc.char_target_heat_cool.value == 1
|
||||||
|
|
||||||
|
|
||||||
async def test_thermostat_without_target_temp_only_range(
|
async def test_thermostat_without_target_temp_only_range(hass, hk_driver, cls, events):
|
||||||
hass, hk_driver, cls, events, driver
|
|
||||||
):
|
|
||||||
"""Test a thermostat that only supports a range."""
|
"""Test a thermostat that only supports a range."""
|
||||||
entity_id = "climate.test"
|
entity_id = "climate.test"
|
||||||
|
|
||||||
@ -1099,7 +1085,7 @@ async def test_thermostat_without_target_temp_only_range(
|
|||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
acc = cls.thermostat(hass, hk_driver, "Climate", entity_id, 1, None)
|
acc = cls.thermostat(hass, hk_driver, "Climate", entity_id, 1, None)
|
||||||
driver.add_accessory(acc)
|
hk_driver.add_accessory(acc)
|
||||||
|
|
||||||
await acc.run_handler()
|
await acc.run_handler()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
@ -1176,7 +1162,7 @@ async def test_thermostat_without_target_temp_only_range(
|
|||||||
|
|
||||||
char_target_temp_iid = acc.char_target_temp.to_HAP()[HAP_REPR_IID]
|
char_target_temp_iid = acc.char_target_temp.to_HAP()[HAP_REPR_IID]
|
||||||
|
|
||||||
driver.set_characteristics(
|
hk_driver.set_characteristics(
|
||||||
{
|
{
|
||||||
HAP_REPR_CHARS: [
|
HAP_REPR_CHARS: [
|
||||||
{
|
{
|
||||||
@ -1222,7 +1208,7 @@ async def test_thermostat_without_target_temp_only_range(
|
|||||||
|
|
||||||
char_target_temp_iid = acc.char_target_temp.to_HAP()[HAP_REPR_IID]
|
char_target_temp_iid = acc.char_target_temp.to_HAP()[HAP_REPR_IID]
|
||||||
|
|
||||||
driver.set_characteristics(
|
hk_driver.set_characteristics(
|
||||||
{
|
{
|
||||||
HAP_REPR_CHARS: [
|
HAP_REPR_CHARS: [
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user