Round Hue transition to steps of 100ms (#62619)
* Adding round() to transition before firing turn_on, turn_off #62608pull/62436/head
parent
1bbeaa722c
commit
772428e70f
|
@ -8,6 +8,7 @@ from aiohue.v2.controllers.events import EventType
|
|||
from aiohue.v2.controllers.scenes import ScenesController
|
||||
from aiohue.v2.models.scene import Scene as HueScene
|
||||
|
||||
from homeassistant.components.light import ATTR_TRANSITION
|
||||
from homeassistant.components.scene import Scene as SceneEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
|
@ -16,6 +17,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
|||
from .bridge import HueBridge
|
||||
from .const import DOMAIN
|
||||
from .v2.entity import HueBaseEntity
|
||||
from .v2.helpers import normalize_hue_transition
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
|
@ -94,11 +96,9 @@ class HueSceneEntity(HueBaseEntity, SceneEntity):
|
|||
|
||||
async def async_activate(self, **kwargs: Any) -> None:
|
||||
"""Activate Hue scene."""
|
||||
transition = kwargs.get("transition")
|
||||
if transition is not None:
|
||||
# hue transition duration is in milliseconds
|
||||
transition = int(transition * 1000)
|
||||
transition = normalize_hue_transition(kwargs.get(ATTR_TRANSITION))
|
||||
dynamic = kwargs.get("dynamic", self.is_dynamic)
|
||||
|
||||
await self.bridge.async_request_call(
|
||||
self.controller.recall,
|
||||
self.resource.id,
|
||||
|
|
|
@ -29,6 +29,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
|||
from ..bridge import HueBridge
|
||||
from ..const import CONF_ALLOW_HUE_GROUPS, DOMAIN
|
||||
from .entity import HueBaseEntity
|
||||
from .helpers import normalize_hue_brightness, normalize_hue_transition
|
||||
|
||||
ALLOWED_ERRORS = [
|
||||
"device (groupedLight) has communication issues, command (on) may not have effect",
|
||||
|
@ -147,17 +148,11 @@ class GroupedHueLight(HueBaseEntity, LightEntity):
|
|||
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn the light on."""
|
||||
transition = kwargs.get(ATTR_TRANSITION)
|
||||
transition = normalize_hue_transition(kwargs.get(ATTR_TRANSITION))
|
||||
xy_color = kwargs.get(ATTR_XY_COLOR)
|
||||
color_temp = kwargs.get(ATTR_COLOR_TEMP)
|
||||
brightness = kwargs.get(ATTR_BRIGHTNESS)
|
||||
brightness = normalize_hue_brightness(kwargs.get(ATTR_BRIGHTNESS))
|
||||
flash = kwargs.get(ATTR_FLASH)
|
||||
if brightness is not None:
|
||||
# Hue uses a range of [0, 100] to control brightness.
|
||||
brightness = float((brightness / 255) * 100)
|
||||
if transition is not None:
|
||||
# hue transition duration is in milliseconds
|
||||
transition = int(transition * 1000)
|
||||
|
||||
# NOTE: a grouped_light can only handle turn on/off
|
||||
# To set other features, you'll have to control the attached lights
|
||||
|
@ -193,10 +188,7 @@ class GroupedHueLight(HueBaseEntity, LightEntity):
|
|||
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn the light off."""
|
||||
transition = kwargs.get(ATTR_TRANSITION)
|
||||
if transition is not None:
|
||||
# hue transition duration is in milliseconds
|
||||
transition = int(transition * 1000)
|
||||
transition = normalize_hue_transition(kwargs.get(ATTR_TRANSITION))
|
||||
|
||||
# NOTE: a grouped_light can only handle turn on/off
|
||||
# To set other features, you'll have to control the attached lights
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
"""Helper functions for Philips Hue v2."""
|
||||
|
||||
|
||||
def normalize_hue_brightness(brightness):
|
||||
"""Returns calculated brightness values"""
|
||||
|
||||
if brightness is not None:
|
||||
# Hue uses a range of [0, 100] to control brightness.
|
||||
brightness = float((brightness / 255) * 100)
|
||||
|
||||
return brightness
|
||||
|
||||
|
||||
def normalize_hue_transition(transition):
|
||||
"""Returns rounded transition values"""
|
||||
|
||||
if transition is not None:
|
||||
# hue transition duration is in milliseconds and round them to 100ms
|
||||
transition = int(round(transition, 1) * 1000)
|
||||
|
||||
return transition
|
|
@ -30,6 +30,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
|||
from ..bridge import HueBridge
|
||||
from ..const import DOMAIN
|
||||
from .entity import HueBaseEntity
|
||||
from .helpers import normalize_hue_brightness, normalize_hue_transition
|
||||
|
||||
ALLOWED_ERRORS = [
|
||||
"device (light) has communication issues, command (on) may not have effect",
|
||||
|
@ -155,17 +156,11 @@ class HueLight(HueBaseEntity, LightEntity):
|
|||
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn the device on."""
|
||||
transition = kwargs.get(ATTR_TRANSITION)
|
||||
transition = normalize_hue_transition(kwargs.get(ATTR_TRANSITION))
|
||||
xy_color = kwargs.get(ATTR_XY_COLOR)
|
||||
color_temp = kwargs.get(ATTR_COLOR_TEMP)
|
||||
brightness = kwargs.get(ATTR_BRIGHTNESS)
|
||||
brightness = normalize_hue_brightness(kwargs.get(ATTR_BRIGHTNESS))
|
||||
flash = kwargs.get(ATTR_FLASH)
|
||||
if brightness is not None:
|
||||
# Hue uses a range of [0, 100] to control brightness.
|
||||
brightness = float((brightness / 255) * 100)
|
||||
if transition is not None:
|
||||
# hue transition duration is in milliseconds
|
||||
transition = int(transition * 1000)
|
||||
|
||||
await self.bridge.async_request_call(
|
||||
self.controller.set_state,
|
||||
|
@ -181,11 +176,9 @@ class HueLight(HueBaseEntity, LightEntity):
|
|||
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn the light off."""
|
||||
transition = kwargs.get(ATTR_TRANSITION)
|
||||
transition = normalize_hue_transition(kwargs.get(ATTR_TRANSITION))
|
||||
flash = kwargs.get(ATTR_FLASH)
|
||||
if transition is not None:
|
||||
# hue transition duration is in milliseconds
|
||||
transition = int(transition * 1000)
|
||||
|
||||
await self.bridge.async_request_call(
|
||||
self.controller.set_state,
|
||||
id=self.resource.id,
|
||||
|
|
|
@ -110,16 +110,16 @@ async def test_light_turn_on_service(hass, mock_bridge_v2, v2_resources_test_dat
|
|||
assert test_light.attributes["color_mode"] == COLOR_MODE_COLOR_TEMP
|
||||
assert test_light.attributes["brightness"] == 255
|
||||
|
||||
# test again with sending transition
|
||||
# test again with sending transition with 250ms which should round up to 200ms
|
||||
await hass.services.async_call(
|
||||
"light",
|
||||
"turn_on",
|
||||
{"entity_id": test_light_id, "brightness_pct": 50, "transition": 6},
|
||||
{"entity_id": test_light_id, "brightness_pct": 50, "transition": 0.25},
|
||||
blocking=True,
|
||||
)
|
||||
assert len(mock_bridge_v2.mock_requests) == 2
|
||||
assert mock_bridge_v2.mock_requests[1]["json"]["on"]["on"] is True
|
||||
assert mock_bridge_v2.mock_requests[1]["json"]["dynamics"]["duration"] == 6000
|
||||
assert mock_bridge_v2.mock_requests[1]["json"]["dynamics"]["duration"] == 200
|
||||
|
||||
# test again with sending flash/alert
|
||||
await hass.services.async_call(
|
||||
|
@ -170,12 +170,12 @@ async def test_light_turn_off_service(hass, mock_bridge_v2, v2_resources_test_da
|
|||
await hass.services.async_call(
|
||||
"light",
|
||||
"turn_off",
|
||||
{"entity_id": test_light_id, "transition": 6},
|
||||
{"entity_id": test_light_id, "transition": 0.25},
|
||||
blocking=True,
|
||||
)
|
||||
assert len(mock_bridge_v2.mock_requests) == 2
|
||||
assert mock_bridge_v2.mock_requests[1]["json"]["on"]["on"] is False
|
||||
assert mock_bridge_v2.mock_requests[1]["json"]["dynamics"]["duration"] == 6000
|
||||
assert mock_bridge_v2.mock_requests[1]["json"]["dynamics"]["duration"] == 200
|
||||
|
||||
|
||||
async def test_light_added(hass, mock_bridge_v2):
|
||||
|
@ -310,7 +310,7 @@ async def test_grouped_lights(hass, mock_bridge_v2, v2_resources_test_data):
|
|||
"entity_id": test_light_id,
|
||||
"brightness_pct": 100,
|
||||
"xy_color": (0.123, 0.123),
|
||||
"transition": 6,
|
||||
"transition": 0.25,
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
|
@ -325,7 +325,7 @@ async def test_grouped_lights(hass, mock_bridge_v2, v2_resources_test_data):
|
|||
assert mock_bridge_v2.mock_requests[index]["json"]["color"]["xy"]["x"] == 0.123
|
||||
assert mock_bridge_v2.mock_requests[index]["json"]["color"]["xy"]["y"] == 0.123
|
||||
assert (
|
||||
mock_bridge_v2.mock_requests[index]["json"]["dynamics"]["duration"] == 6000
|
||||
mock_bridge_v2.mock_requests[index]["json"]["dynamics"]["duration"] == 200
|
||||
)
|
||||
|
||||
# Now generate update events by emitting the json we've sent as incoming events
|
||||
|
@ -374,7 +374,7 @@ async def test_grouped_lights(hass, mock_bridge_v2, v2_resources_test_data):
|
|||
"turn_off",
|
||||
{
|
||||
"entity_id": test_light_id,
|
||||
"transition": 6,
|
||||
"transition": 0.25,
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
|
@ -384,5 +384,5 @@ async def test_grouped_lights(hass, mock_bridge_v2, v2_resources_test_data):
|
|||
for index in range(0, 3):
|
||||
assert mock_bridge_v2.mock_requests[index]["json"]["on"]["on"] is False
|
||||
assert (
|
||||
mock_bridge_v2.mock_requests[index]["json"]["dynamics"]["duration"] == 6000
|
||||
mock_bridge_v2.mock_requests[index]["json"]["dynamics"]["duration"] == 200
|
||||
)
|
||||
|
|
|
@ -77,13 +77,13 @@ async def test_scene_turn_on_service(hass, mock_bridge_v2, v2_resources_test_dat
|
|||
await hass.services.async_call(
|
||||
"scene",
|
||||
"turn_on",
|
||||
{"entity_id": test_entity_id, "transition": 6},
|
||||
{"entity_id": test_entity_id, "transition": 0.25},
|
||||
blocking=True,
|
||||
)
|
||||
assert len(mock_bridge_v2.mock_requests) == 2
|
||||
assert mock_bridge_v2.mock_requests[1]["json"]["recall"] == {
|
||||
"action": "active",
|
||||
"duration": 6000,
|
||||
"duration": 200,
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue