Add support for dimmable bond lights (#38203)

* Add support for dimmable lights

* Fix formatting

* Add supported features test on Bond Light

* Add more tests to bond light and fixes comments

* Fix rebase conflict resolution

* Apply suggestions from code review

Co-authored-by: Chris Talkington <chris@talkingtontech.com>
This commit is contained in:
Marcio Granzotto Rodrigues 2020-07-29 22:01:59 -03:00 committed by GitHub
parent fa9866db96
commit 8ab1b41974
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 106 additions and 9 deletions

View File

@ -47,20 +47,45 @@ class BondLight(BondEntity, LightEntity):
def __init__(self, hub: BondHub, device: BondDevice):
"""Create HA entity representing Bond fan."""
super().__init__(hub, device)
self._brightness: Optional[int] = None
self._light: Optional[int] = None
def _apply_state(self, state: dict):
self._light = state.get("light")
self._brightness = state.get("brightness")
@property
def supported_features(self) -> Optional[int]:
"""Flag supported features."""
features = 0
if self._device.supports_set_brightness():
features |= SUPPORT_BRIGHTNESS
return features
@property
def is_on(self) -> bool:
"""Return if light is currently on."""
return self._light == 1
@property
def brightness(self) -> int:
"""Return the brightness of this light between 1..255."""
brightness_value = (
round(self._brightness * 255 / 100) if self._brightness else None
)
return brightness_value
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn on the light."""
await self._hub.bond.action(self._device.device_id, Action.turn_light_on())
brightness = kwargs.get(ATTR_BRIGHTNESS)
if brightness:
await self._hub.bond.action(
self._device.device_id,
Action(Action.SET_BRIGHTNESS, round((brightness * 100) / 255)),
)
else:
await self._hub.bond.action(self._device.device_id, Action.turn_light_on())
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn off the light."""

View File

@ -3,10 +3,6 @@
"name": "Bond",
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/bond",
"requirements": [
"bond-api==0.1.7"
],
"codeowners": [
"@prystupa"
]
"requirements": ["bond-api==0.1.7"],
"codeowners": ["@prystupa"]
}

View File

@ -60,6 +60,11 @@ class BondDevice:
]
)
def supports_set_brightness(self) -> bool:
"""Return True if this device supports setting a light brightness."""
actions: List[str] = self._attrs["actions"]
return bool([action for action in actions if action in [Action.SET_BRIGHTNESS]])
class BondHub:
"""Hub device representing Bond Bridge."""

View File

@ -5,10 +5,15 @@ import logging
from bond_api import Action, DeviceType
from homeassistant import core
from homeassistant.components.light import ATTR_BRIGHTNESS, DOMAIN as LIGHT_DOMAIN
from homeassistant.components.light import (
ATTR_BRIGHTNESS,
DOMAIN as LIGHT_DOMAIN,
SUPPORT_BRIGHTNESS,
)
from homeassistant.const import (
ATTR_ASSUMED_STATE,
ATTR_ENTITY_ID,
ATTR_SUPPORTED_FEATURES,
SERVICE_TURN_OFF,
SERVICE_TURN_ON,
)
@ -36,6 +41,15 @@ def ceiling_fan(name: str):
}
def dimmable_ceiling_fan(name: str):
"""Create a ceiling fan (that has built-in light) with given name."""
return {
"name": name,
"type": DeviceType.CEILING_FAN,
"actions": [Action.TURN_LIGHT_ON, Action.TURN_LIGHT_OFF, Action.SET_BRIGHTNESS],
}
def fireplace(name: str):
"""Create a fireplace with given name."""
return {"name": name, "type": DeviceType.FIREPLACE}
@ -128,6 +142,52 @@ async def test_turn_off_light(hass: core.HomeAssistant):
)
async def test_brightness_support(hass: core.HomeAssistant):
"""Tests that a dimmable light should support the brightness feature."""
await setup_platform(
hass,
LIGHT_DOMAIN,
dimmable_ceiling_fan("name-1"),
bond_device_id="test-device-id",
)
state = hass.states.get("light.name_1")
assert state.attributes[ATTR_SUPPORTED_FEATURES] & SUPPORT_BRIGHTNESS
async def test_brightness_not_supported(hass: core.HomeAssistant):
"""Tests that a non-dimmable light should not support the brightness feature."""
await setup_platform(
hass, LIGHT_DOMAIN, ceiling_fan("name-1"), bond_device_id="test-device-id",
)
state = hass.states.get("light.name_1")
assert not state.attributes[ATTR_SUPPORTED_FEATURES] & SUPPORT_BRIGHTNESS
async def test_turn_on_light_with_brightness(hass: core.HomeAssistant):
"""Tests that turn on command, on a dimmable light, delegates to API and parses brightness."""
await setup_platform(
hass,
LIGHT_DOMAIN,
dimmable_ceiling_fan("name-1"),
bond_device_id="test-device-id",
)
with patch_bond_action() as mock_set_brightness, patch_bond_device_state():
await hass.services.async_call(
LIGHT_DOMAIN,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: "light.name_1", ATTR_BRIGHTNESS: 128},
blocking=True,
)
await hass.async_block_till_done()
mock_set_brightness.assert_called_once_with(
"test-device-id", Action(Action.SET_BRIGHTNESS, 50)
)
async def test_update_reports_light_is_on(hass: core.HomeAssistant):
"""Tests that update command sets correct state when Bond API reports the light is on."""
await setup_platform(hass, LIGHT_DOMAIN, ceiling_fan("name-1"))
@ -220,3 +280,14 @@ async def test_light_available(hass: core.HomeAssistant):
await help_test_entity_available(
hass, LIGHT_DOMAIN, ceiling_fan("name-1"), "light.name_1"
)
async def test_parse_brightness(hass: core.HomeAssistant):
"""Tests that reported brightness level (0..100) converted to HA brightness (0...255)."""
await setup_platform(hass, LIGHT_DOMAIN, dimmable_ceiling_fan("name-1"))
with patch_bond_device_state(return_value={"light": 1, "brightness": 50}):
async_fire_time_changed(hass, utcnow() + timedelta(seconds=30))
await hass.async_block_till_done()
assert hass.states.get("light.name_1").attributes[ATTR_BRIGHTNESS] == 128