Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 35 additions & 2 deletions homeassistant/components/tplink/light.py
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ def _light_state_from_params(self, light_state_params) -> LightState:
def _get_light_state(self) -> LightState:
"""Get the light state."""
self._update_emeter()
return self._light_state_from_params(self.smartbulb.get_light_state())
return self._light_state_from_params(self._get_device_state())

def _update_emeter(self):
if not self.smartbulb.has_emeter:
Expand Down Expand Up @@ -427,7 +427,40 @@ def _set_light_state(
if not diff:
return

return self.smartbulb.set_light_state(diff)
return self._set_device_state(diff)

def _get_device_state(self):
"""State of the bulb or smart dimmer switch."""
if isinstance(self.smartbulb, SmartBulb):
return self.smartbulb.get_light_state()

# Its not really a bulb, its a dimmable SmartPlug (aka Wall Switch)
return {
LIGHT_STATE_ON_OFF: self.smartbulb.state,
LIGHT_STATE_BRIGHTNESS: self.smartbulb.brightness,
LIGHT_STATE_COLOR_TEMP: 0,
LIGHT_STATE_HUE: 0,
LIGHT_STATE_SATURATION: 0,
}

def _set_device_state(self, state):
"""Set state of the bulb or smart dimmer switch."""
if isinstance(self.smartbulb, SmartBulb):
return self.smartbulb.set_light_state(state)

# Its not really a bulb, its a dimmable SmartPlug (aka Wall Switch)
if LIGHT_STATE_BRIGHTNESS in state:
# Brightness of 0 is accepted by the
# device but the underlying library rejects it
# so we turn off instead.
if state[LIGHT_STATE_BRIGHTNESS]:
self.smartbulb.brightness = state[LIGHT_STATE_BRIGHTNESS]
else:
self.smartbulb.state = 0
elif LIGHT_STATE_ON_OFF in state:
self.smartbulb.state = state[LIGHT_STATE_ON_OFF]

return self._get_device_state()


def _light_state_diff(old_light_state: LightState, new_light_state: LightState):
Expand Down
177 changes: 175 additions & 2 deletions tests/components/tplink/test_light.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Tests for light platform."""
from typing import Callable, NamedTuple
from unittest.mock import Mock, patch
from unittest.mock import Mock, PropertyMock, patch

from pyHS100 import SmartDeviceException
import pytest
Expand All @@ -16,7 +16,11 @@
ATTR_HS_COLOR,
DOMAIN as LIGHT_DOMAIN,
)
from homeassistant.components.tplink.common import CONF_DISCOVERY, CONF_LIGHT
from homeassistant.components.tplink.common import (
CONF_DIMMER,
CONF_DISCOVERY,
CONF_LIGHT,
)
from homeassistant.const import (
ATTR_ENTITY_ID,
CONF_HOST,
Expand All @@ -41,6 +45,16 @@ class LightMockData(NamedTuple):
get_emeter_monthly_mock: Mock


class SmartSwitchMockData(NamedTuple):
"""Mock smart switch data."""

sys_info: dict
light_state: dict
state_mock: Mock
brightness_mock: Mock
get_sysinfo_mock: Mock


@pytest.fixture(name="light_mock_data")
def light_mock_data_fixture() -> None:
"""Create light mock data."""
Expand Down Expand Up @@ -152,6 +166,75 @@ def set_light_state(state) -> None:
)


@pytest.fixture(name="dimmer_switch_mock_data")
def dimmer_switch_mock_data_fixture() -> None:
"""Create dimmer switch mock data."""
sys_info = {
"sw_ver": "1.2.3",
"hw_ver": "2.3.4",
"mac": "aa:bb:cc:dd:ee:ff",
"mic_mac": "00:11:22:33:44",
"type": "switch",
"hwId": "1234",
"fwId": "4567",
"oemId": "891011",
"dev_name": "dimmer1",
"rssi": 11,
"latitude": "0",
"longitude": "0",
"is_color": False,
"is_dimmable": True,
"is_variable_color_temp": False,
"model": "HS220",
"alias": "dimmer1",
"feature": ":",
}

light_state = {
"on_off": 1,
"brightness": 13,
}

def state(*args, **kwargs):
nonlocal light_state
if len(args) == 0:
return light_state["on_off"]
light_state["on_off"] = args[0]

def brightness(*args, **kwargs):
nonlocal light_state
if len(args) == 0:
return light_state["brightness"]
if light_state["brightness"] == 0:
light_state["on_off"] = 0
else:
light_state["on_off"] = 1
light_state["brightness"] = args[0]

get_sysinfo_patch = patch(
"homeassistant.components.tplink.common.SmartDevice.get_sysinfo",
return_value=sys_info,
)
state_patch = patch(
"homeassistant.components.tplink.common.SmartPlug.state",
new_callable=PropertyMock,
side_effect=state,
)
brightness_patch = patch(
"homeassistant.components.tplink.common.SmartPlug.brightness",
new_callable=PropertyMock,
side_effect=brightness,
)
with brightness_patch as brightness_mock, state_patch as state_mock, get_sysinfo_patch as get_sysinfo_mock:
yield SmartSwitchMockData(
sys_info=sys_info,
light_state=light_state,
brightness_mock=brightness_mock,
state_mock=state_mock,
get_sysinfo_mock=get_sysinfo_mock,
)


async def update_entity(hass: HomeAssistant, entity_id: str) -> None:
"""Run an update action for an entity."""
await hass.services.async_call(
Expand All @@ -160,6 +243,96 @@ async def update_entity(hass: HomeAssistant, entity_id: str) -> None:
await hass.async_block_till_done()


async def test_smartswitch(
hass: HomeAssistant, dimmer_switch_mock_data: SmartSwitchMockData
) -> None:
"""Test function."""
light_state = dimmer_switch_mock_data.light_state

await async_setup_component(hass, HA_DOMAIN, {})
await hass.async_block_till_done()

await async_setup_component(
hass,
tplink.DOMAIN,
{
tplink.DOMAIN: {
CONF_DISCOVERY: False,
CONF_DIMMER: [{CONF_HOST: "123.123.123.123"}],
}
},
)
await hass.async_block_till_done()

assert hass.states.get("light.dimmer1")

await hass.services.async_call(
LIGHT_DOMAIN,
SERVICE_TURN_OFF,
{ATTR_ENTITY_ID: "light.dimmer1"},
blocking=True,
)
await hass.async_block_till_done()
await update_entity(hass, "light.dimmer1")

assert hass.states.get("light.dimmer1").state == "off"
assert light_state["on_off"] == 0

await hass.services.async_call(
LIGHT_DOMAIN,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: "light.dimmer1", ATTR_BRIGHTNESS: 50},
blocking=True,
)
await hass.async_block_till_done()
await update_entity(hass, "light.dimmer1")

state = hass.states.get("light.dimmer1")
assert state.state == "on"
assert state.attributes["brightness"] == 48.45
assert light_state["on_off"] == 1

await hass.services.async_call(
LIGHT_DOMAIN,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: "light.dimmer1", ATTR_BRIGHTNESS: 55},
blocking=True,
)
await hass.async_block_till_done()
await update_entity(hass, "light.dimmer1")

state = hass.states.get("light.dimmer1")
assert state.state == "on"
assert state.attributes["brightness"] == 53.55
assert light_state["brightness"] == 21

light_state["on_off"] = 0
light_state["brightness"] = 66

await hass.services.async_call(
LIGHT_DOMAIN,
SERVICE_TURN_OFF,
{ATTR_ENTITY_ID: "light.dimmer1"},
blocking=True,
)
await hass.async_block_till_done()
await update_entity(hass, "light.dimmer1")

state = hass.states.get("light.dimmer1")
assert state.state == "off"

await hass.services.async_call(
LIGHT_DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: "light.dimmer1"}, blocking=True,
)
await hass.async_block_till_done()
await update_entity(hass, "light.dimmer1")

state = hass.states.get("light.dimmer1")
assert state.state == "on"
assert state.attributes["brightness"] == 168.3
assert light_state["brightness"] == 66


async def test_light(hass: HomeAssistant, light_mock_data: LightMockData) -> None:
"""Test function."""
light_state = light_mock_data.light_state
Expand Down