465 lines
15 KiB
Python
465 lines
15 KiB
Python
"""Test Z-Wave lights."""
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
from homeassistant.components import zwave
|
|
from homeassistant.components.light import (
|
|
ATTR_BRIGHTNESS,
|
|
ATTR_COLOR_TEMP,
|
|
ATTR_HS_COLOR,
|
|
ATTR_TRANSITION,
|
|
ATTR_WHITE_VALUE,
|
|
SUPPORT_BRIGHTNESS,
|
|
SUPPORT_COLOR,
|
|
SUPPORT_COLOR_TEMP,
|
|
SUPPORT_TRANSITION,
|
|
SUPPORT_WHITE_VALUE,
|
|
)
|
|
from homeassistant.components.zwave import const, light
|
|
|
|
from tests.mock.zwave import MockEntityValues, MockNode, MockValue, value_changed
|
|
|
|
|
|
class MockLightValues(MockEntityValues):
|
|
"""Mock Z-Wave light values."""
|
|
|
|
def __init__(self, **kwargs):
|
|
"""Initialize the mock zwave values."""
|
|
self.dimming_duration = None
|
|
self.color = None
|
|
self.color_channels = None
|
|
super().__init__(**kwargs)
|
|
|
|
|
|
def test_get_device_detects_dimmer(mock_openzwave):
|
|
"""Test get_device returns a normal dimmer."""
|
|
node = MockNode()
|
|
value = MockValue(data=0, node=node)
|
|
values = MockLightValues(primary=value)
|
|
|
|
device = light.get_device(node=node, values=values, node_config={})
|
|
assert isinstance(device, light.ZwaveDimmer)
|
|
assert device.supported_features == SUPPORT_BRIGHTNESS
|
|
|
|
|
|
def test_get_device_detects_colorlight(mock_openzwave):
|
|
"""Test get_device returns a color light."""
|
|
node = MockNode(command_classes=[const.COMMAND_CLASS_SWITCH_COLOR])
|
|
value = MockValue(data=0, node=node)
|
|
values = MockLightValues(primary=value)
|
|
|
|
device = light.get_device(node=node, values=values, node_config={})
|
|
assert isinstance(device, light.ZwaveColorLight)
|
|
assert device.supported_features == SUPPORT_BRIGHTNESS | SUPPORT_COLOR
|
|
|
|
|
|
def test_get_device_detects_zw098(mock_openzwave):
|
|
"""Test get_device returns a zw098 color light."""
|
|
node = MockNode(
|
|
manufacturer_id="0086",
|
|
product_id="0062",
|
|
command_classes=[const.COMMAND_CLASS_SWITCH_COLOR],
|
|
)
|
|
value = MockValue(data=0, node=node)
|
|
values = MockLightValues(primary=value)
|
|
device = light.get_device(node=node, values=values, node_config={})
|
|
assert isinstance(device, light.ZwaveColorLight)
|
|
assert device.supported_features == (
|
|
SUPPORT_BRIGHTNESS | SUPPORT_COLOR | SUPPORT_COLOR_TEMP
|
|
)
|
|
|
|
|
|
def test_get_device_detects_rgbw_light(mock_openzwave):
|
|
"""Test get_device returns a color light."""
|
|
node = MockNode(command_classes=[const.COMMAND_CLASS_SWITCH_COLOR])
|
|
value = MockValue(data=0, node=node)
|
|
color = MockValue(data="#0000000000", node=node)
|
|
color_channels = MockValue(data=0x1D, node=node)
|
|
values = MockLightValues(primary=value, color=color, color_channels=color_channels)
|
|
|
|
device = light.get_device(node=node, values=values, node_config={})
|
|
device.value_added()
|
|
assert isinstance(device, light.ZwaveColorLight)
|
|
assert device.supported_features == (
|
|
SUPPORT_BRIGHTNESS | SUPPORT_COLOR | SUPPORT_WHITE_VALUE
|
|
)
|
|
|
|
|
|
def test_dimmer_turn_on(mock_openzwave):
|
|
"""Test turning on a dimmable Z-Wave light."""
|
|
node = MockNode()
|
|
value = MockValue(data=0, node=node)
|
|
values = MockLightValues(primary=value)
|
|
device = light.get_device(node=node, values=values, node_config={})
|
|
|
|
device.turn_on()
|
|
|
|
assert node.set_dimmer.called
|
|
value_id, brightness = node.set_dimmer.mock_calls[0][1]
|
|
assert value_id == value.value_id
|
|
assert brightness == 255
|
|
|
|
node.reset_mock()
|
|
|
|
device.turn_on(**{ATTR_BRIGHTNESS: 224})
|
|
|
|
assert node.set_dimmer.called
|
|
value_id, brightness = node.set_dimmer.mock_calls[0][1]
|
|
|
|
assert value_id == value.value_id
|
|
assert brightness == 87 # round(224 / 255 * 99)
|
|
|
|
node.reset_mock()
|
|
|
|
device.turn_on(**{ATTR_BRIGHTNESS: 120})
|
|
|
|
assert node.set_dimmer.called
|
|
value_id, brightness = node.set_dimmer.mock_calls[0][1]
|
|
|
|
assert value_id == value.value_id
|
|
assert brightness == 47 # round(120 / 255 * 99)
|
|
|
|
with patch.object(light, "_LOGGER", MagicMock()) as mock_logger:
|
|
device.turn_on(**{ATTR_TRANSITION: 35})
|
|
assert mock_logger.debug.called
|
|
assert node.set_dimmer.called
|
|
msg, entity_id = mock_logger.debug.mock_calls[0][1]
|
|
assert entity_id == device.entity_id
|
|
|
|
|
|
def test_dimmer_min_brightness(mock_openzwave):
|
|
"""Test turning on a dimmable Z-Wave light to its minimum brightness."""
|
|
node = MockNode()
|
|
value = MockValue(data=0, node=node)
|
|
values = MockLightValues(primary=value)
|
|
device = light.get_device(node=node, values=values, node_config={})
|
|
|
|
assert not device.is_on
|
|
|
|
device.turn_on(**{ATTR_BRIGHTNESS: 1})
|
|
|
|
assert device.is_on
|
|
assert device.brightness == 1
|
|
|
|
device.turn_on(**{ATTR_BRIGHTNESS: 0})
|
|
|
|
assert device.is_on
|
|
assert device.brightness == 0
|
|
|
|
|
|
def test_dimmer_transitions(mock_openzwave):
|
|
"""Test dimming transition on a dimmable Z-Wave light."""
|
|
node = MockNode()
|
|
value = MockValue(data=0, node=node)
|
|
duration = MockValue(data=0, node=node)
|
|
values = MockLightValues(primary=value, dimming_duration=duration)
|
|
device = light.get_device(node=node, values=values, node_config={})
|
|
assert device.supported_features == SUPPORT_BRIGHTNESS | SUPPORT_TRANSITION
|
|
|
|
# Test turn_on
|
|
# Factory Default
|
|
device.turn_on()
|
|
assert duration.data == 0xFF
|
|
|
|
# Seconds transition
|
|
device.turn_on(**{ATTR_TRANSITION: 45})
|
|
assert duration.data == 45
|
|
|
|
# Minutes transition
|
|
device.turn_on(**{ATTR_TRANSITION: 245})
|
|
assert duration.data == 0x83
|
|
|
|
# Clipped transition
|
|
device.turn_on(**{ATTR_TRANSITION: 10000})
|
|
assert duration.data == 0xFE
|
|
|
|
# Test turn_off
|
|
# Factory Default
|
|
device.turn_off()
|
|
assert duration.data == 0xFF
|
|
|
|
# Seconds transition
|
|
device.turn_off(**{ATTR_TRANSITION: 45})
|
|
assert duration.data == 45
|
|
|
|
# Minutes transition
|
|
device.turn_off(**{ATTR_TRANSITION: 245})
|
|
assert duration.data == 0x83
|
|
|
|
# Clipped transition
|
|
device.turn_off(**{ATTR_TRANSITION: 10000})
|
|
assert duration.data == 0xFE
|
|
|
|
|
|
def test_dimmer_turn_off(mock_openzwave):
|
|
"""Test turning off a dimmable Z-Wave light."""
|
|
node = MockNode()
|
|
value = MockValue(data=46, node=node)
|
|
values = MockLightValues(primary=value)
|
|
device = light.get_device(node=node, values=values, node_config={})
|
|
|
|
device.turn_off()
|
|
|
|
assert node.set_dimmer.called
|
|
value_id, brightness = node.set_dimmer.mock_calls[0][1]
|
|
assert value_id == value.value_id
|
|
assert brightness == 0
|
|
|
|
|
|
def test_dimmer_value_changed(mock_openzwave):
|
|
"""Test value changed for dimmer lights."""
|
|
node = MockNode()
|
|
value = MockValue(data=0, node=node)
|
|
values = MockLightValues(primary=value)
|
|
device = light.get_device(node=node, values=values, node_config={})
|
|
|
|
assert not device.is_on
|
|
|
|
value.data = 46
|
|
value_changed(value)
|
|
|
|
assert device.is_on
|
|
assert device.brightness == 118
|
|
|
|
|
|
def test_dimmer_refresh_value(mock_openzwave):
|
|
"""Test value changed for dimmer lights."""
|
|
node = MockNode()
|
|
value = MockValue(data=0, node=node)
|
|
values = MockLightValues(primary=value)
|
|
device = light.get_device(
|
|
node=node,
|
|
values=values,
|
|
node_config={zwave.CONF_REFRESH_VALUE: True, zwave.CONF_REFRESH_DELAY: 5},
|
|
)
|
|
|
|
assert not device.is_on
|
|
|
|
with patch.object(light, "Timer") as mock_timer:
|
|
value.data = 46
|
|
value_changed(value)
|
|
|
|
assert not device.is_on
|
|
assert mock_timer.called
|
|
assert len(mock_timer.mock_calls) == 2
|
|
timeout, callback = mock_timer.mock_calls[0][1][:2]
|
|
assert timeout == 5
|
|
assert mock_timer().start.called
|
|
assert len(mock_timer().start.mock_calls) == 1
|
|
|
|
with patch.object(light, "Timer") as mock_timer_2:
|
|
value_changed(value)
|
|
assert not device.is_on
|
|
assert mock_timer().cancel.called
|
|
assert len(mock_timer_2.mock_calls) == 2
|
|
timeout, callback = mock_timer_2.mock_calls[0][1][:2]
|
|
assert timeout == 5
|
|
assert mock_timer_2().start.called
|
|
assert len(mock_timer_2().start.mock_calls) == 1
|
|
|
|
callback()
|
|
assert device.is_on
|
|
assert device.brightness == 118
|
|
|
|
|
|
def test_set_hs_color(mock_openzwave):
|
|
"""Test setting zwave light color."""
|
|
node = MockNode(command_classes=[const.COMMAND_CLASS_SWITCH_COLOR])
|
|
value = MockValue(data=0, node=node)
|
|
color = MockValue(data="#0000000000", node=node)
|
|
# Supports RGB only
|
|
color_channels = MockValue(data=0x1C, node=node)
|
|
values = MockLightValues(primary=value, color=color, color_channels=color_channels)
|
|
device = light.get_device(node=node, values=values, node_config={})
|
|
|
|
assert color.data == "#0000000000"
|
|
|
|
device.turn_on(**{ATTR_HS_COLOR: (30, 50)})
|
|
|
|
assert color.data == "#ffbf7f0000"
|
|
|
|
|
|
def test_set_white_value(mock_openzwave):
|
|
"""Test setting zwave light color."""
|
|
node = MockNode(command_classes=[const.COMMAND_CLASS_SWITCH_COLOR])
|
|
value = MockValue(data=0, node=node)
|
|
color = MockValue(data="#0000000000", node=node)
|
|
# Supports RGBW
|
|
color_channels = MockValue(data=0x1D, node=node)
|
|
values = MockLightValues(primary=value, color=color, color_channels=color_channels)
|
|
device = light.get_device(node=node, values=values, node_config={})
|
|
|
|
assert color.data == "#0000000000"
|
|
|
|
device.turn_on(**{ATTR_WHITE_VALUE: 200})
|
|
|
|
assert color.data == "#ffffffc800"
|
|
|
|
|
|
def test_disable_white_if_set_color(mock_openzwave):
|
|
"""
|
|
Test that _white is set to 0 if turn_on with ATTR_HS_COLOR.
|
|
|
|
See Issue #13930 - many RGBW ZWave bulbs will only activate the RGB LED to
|
|
produce color if _white is set to zero.
|
|
"""
|
|
node = MockNode(command_classes=[const.COMMAND_CLASS_SWITCH_COLOR])
|
|
value = MockValue(data=0, node=node)
|
|
color = MockValue(data="#0000000000", node=node)
|
|
# Supports RGB only
|
|
color_channels = MockValue(data=0x1C, node=node)
|
|
values = MockLightValues(primary=value, color=color, color_channels=color_channels)
|
|
device = light.get_device(node=node, values=values, node_config={})
|
|
device._white = 234
|
|
|
|
assert color.data == "#0000000000"
|
|
assert device.white_value == 234
|
|
|
|
device.turn_on(**{ATTR_HS_COLOR: (30, 50)})
|
|
|
|
assert device.white_value == 0
|
|
assert color.data == "#ffbf7f0000"
|
|
|
|
|
|
def test_zw098_set_color_temp(mock_openzwave):
|
|
"""Test setting zwave light color."""
|
|
node = MockNode(
|
|
manufacturer_id="0086",
|
|
product_id="0062",
|
|
command_classes=[const.COMMAND_CLASS_SWITCH_COLOR],
|
|
)
|
|
value = MockValue(data=0, node=node)
|
|
color = MockValue(data="#0000000000", node=node)
|
|
# Supports RGB, warm white, cold white
|
|
color_channels = MockValue(data=0x1F, node=node)
|
|
values = MockLightValues(primary=value, color=color, color_channels=color_channels)
|
|
device = light.get_device(node=node, values=values, node_config={})
|
|
|
|
assert color.data == "#0000000000"
|
|
|
|
device.turn_on(**{ATTR_COLOR_TEMP: 200})
|
|
|
|
assert color.data == "#00000000ff"
|
|
|
|
device.turn_on(**{ATTR_COLOR_TEMP: 400})
|
|
|
|
assert color.data == "#000000ff00"
|
|
|
|
|
|
def test_rgb_not_supported(mock_openzwave):
|
|
"""Test value changed for rgb lights."""
|
|
node = MockNode(command_classes=[const.COMMAND_CLASS_SWITCH_COLOR])
|
|
value = MockValue(data=0, node=node)
|
|
color = MockValue(data="#0000000000", node=node)
|
|
# Supports color temperature only
|
|
color_channels = MockValue(data=0x01, node=node)
|
|
values = MockLightValues(primary=value, color=color, color_channels=color_channels)
|
|
device = light.get_device(node=node, values=values, node_config={})
|
|
|
|
assert device.hs_color is None
|
|
|
|
|
|
def test_no_color_value(mock_openzwave):
|
|
"""Test value changed for rgb lights."""
|
|
node = MockNode(command_classes=[const.COMMAND_CLASS_SWITCH_COLOR])
|
|
value = MockValue(data=0, node=node)
|
|
values = MockLightValues(primary=value)
|
|
device = light.get_device(node=node, values=values, node_config={})
|
|
|
|
assert device.hs_color is None
|
|
|
|
|
|
def test_no_color_channels_value(mock_openzwave):
|
|
"""Test value changed for rgb lights."""
|
|
node = MockNode(command_classes=[const.COMMAND_CLASS_SWITCH_COLOR])
|
|
value = MockValue(data=0, node=node)
|
|
color = MockValue(data="#0000000000", node=node)
|
|
values = MockLightValues(primary=value, color=color)
|
|
device = light.get_device(node=node, values=values, node_config={})
|
|
|
|
assert device.hs_color is None
|
|
|
|
|
|
def test_rgb_value_changed(mock_openzwave):
|
|
"""Test value changed for rgb lights."""
|
|
node = MockNode(command_classes=[const.COMMAND_CLASS_SWITCH_COLOR])
|
|
value = MockValue(data=0, node=node)
|
|
color = MockValue(data="#0000000000", node=node)
|
|
# Supports RGB only
|
|
color_channels = MockValue(data=0x1C, node=node)
|
|
values = MockLightValues(primary=value, color=color, color_channels=color_channels)
|
|
device = light.get_device(node=node, values=values, node_config={})
|
|
|
|
assert device.hs_color == (0, 0)
|
|
|
|
color.data = "#ffbf800000"
|
|
value_changed(color)
|
|
|
|
assert device.hs_color == (29.764, 49.804)
|
|
|
|
|
|
def test_rgbww_value_changed(mock_openzwave):
|
|
"""Test value changed for rgb lights."""
|
|
node = MockNode(command_classes=[const.COMMAND_CLASS_SWITCH_COLOR])
|
|
value = MockValue(data=0, node=node)
|
|
color = MockValue(data="#0000000000", node=node)
|
|
# Supports RGB, Warm White
|
|
color_channels = MockValue(data=0x1D, node=node)
|
|
values = MockLightValues(primary=value, color=color, color_channels=color_channels)
|
|
device = light.get_device(node=node, values=values, node_config={})
|
|
|
|
assert device.hs_color == (0, 0)
|
|
assert device.white_value == 0
|
|
|
|
color.data = "#c86400c800"
|
|
value_changed(color)
|
|
|
|
assert device.hs_color == (30, 100)
|
|
assert device.white_value == 200
|
|
|
|
|
|
def test_rgbcw_value_changed(mock_openzwave):
|
|
"""Test value changed for rgb lights."""
|
|
node = MockNode(command_classes=[const.COMMAND_CLASS_SWITCH_COLOR])
|
|
value = MockValue(data=0, node=node)
|
|
color = MockValue(data="#0000000000", node=node)
|
|
# Supports RGB, Cold White
|
|
color_channels = MockValue(data=0x1E, node=node)
|
|
values = MockLightValues(primary=value, color=color, color_channels=color_channels)
|
|
device = light.get_device(node=node, values=values, node_config={})
|
|
|
|
assert device.hs_color == (0, 0)
|
|
assert device.white_value == 0
|
|
|
|
color.data = "#c86400c800"
|
|
value_changed(color)
|
|
|
|
assert device.hs_color == (30, 100)
|
|
assert device.white_value == 200
|
|
|
|
|
|
def test_ct_value_changed(mock_openzwave):
|
|
"""Test value changed for zw098 lights."""
|
|
node = MockNode(
|
|
manufacturer_id="0086",
|
|
product_id="0062",
|
|
command_classes=[const.COMMAND_CLASS_SWITCH_COLOR],
|
|
)
|
|
value = MockValue(data=0, node=node)
|
|
color = MockValue(data="#0000000000", node=node)
|
|
# Supports RGB, Cold White
|
|
color_channels = MockValue(data=0x1F, node=node)
|
|
values = MockLightValues(primary=value, color=color, color_channels=color_channels)
|
|
device = light.get_device(node=node, values=values, node_config={})
|
|
|
|
assert device.color_temp == light.TEMP_MID_HASS
|
|
|
|
color.data = "#000000ff00"
|
|
value_changed(color)
|
|
|
|
assert device.color_temp == light.TEMP_WARM_HASS
|
|
|
|
color.data = "#00000000ff"
|
|
value_changed(color)
|
|
|
|
assert device.color_temp == light.TEMP_COLD_HASS
|