Add set_hev_cycle_state service to LIFX integration (#77546)

Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
Avi Miller 2022-09-05 10:04:36 +10:00 committed by GitHub
parent 23a579d1c9
commit 168d122db4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 135 additions and 15 deletions

View file

@ -118,9 +118,6 @@ class LIFXUpdateCoordinator(DataUpdateCoordinator):
await self.async_update_color_zones()
if lifx_features(self.device)["hev"]:
if self.device.hev_cycle_configuration is None:
self.device.get_hev_configuration()
await self.async_get_hev_cycle()
async def async_update_color_zones(self) -> None:
@ -195,3 +192,10 @@ class LIFXUpdateCoordinator(DataUpdateCoordinator):
apply=apply,
)
)
async def async_set_hev_cycle_state(self, enable: bool, duration: int = 0) -> None:
"""Start or stop an HEV cycle on a LIFX Clean bulb."""
if lifx_features(self.device)["hev"]:
await async_execute_lifx(
partial(self.device.set_hev_cycle, enable=enable, duration=duration)
)

View file

@ -28,7 +28,14 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.event import async_track_point_in_utc_time
import homeassistant.util.color as color_util
from .const import ATTR_INFRARED, ATTR_POWER, ATTR_ZONES, DATA_LIFX_MANAGER, DOMAIN
from .const import (
ATTR_DURATION,
ATTR_INFRARED,
ATTR_POWER,
ATTR_ZONES,
DATA_LIFX_MANAGER,
DOMAIN,
)
from .coordinator import LIFXUpdateCoordinator
from .entity import LIFXEntity
from .manager import (
@ -43,14 +50,20 @@ LIFX_STATE_SETTLE_DELAY = 0.3
SERVICE_LIFX_SET_STATE = "set_state"
LIFX_SET_STATE_SCHEMA = cv.make_entity_service_schema(
{
**LIGHT_TURN_ON_SCHEMA,
ATTR_INFRARED: vol.All(vol.Coerce(int), vol.Clamp(min=0, max=255)),
ATTR_ZONES: vol.All(cv.ensure_list, [cv.positive_int]),
ATTR_POWER: cv.boolean,
}
)
LIFX_SET_STATE_SCHEMA = {
**LIGHT_TURN_ON_SCHEMA,
ATTR_INFRARED: vol.All(vol.Coerce(int), vol.Clamp(min=0, max=255)),
ATTR_ZONES: vol.All(cv.ensure_list, [cv.positive_int]),
ATTR_POWER: cv.boolean,
}
SERVICE_LIFX_SET_HEV_CYCLE_STATE = "set_hev_cycle_state"
LIFX_SET_HEV_CYCLE_STATE_SCHEMA = {
ATTR_POWER: vol.Required(cv.boolean),
ATTR_DURATION: vol.All(vol.Coerce(float), vol.Clamp(min=0, max=86400)),
}
HSBK_HUE = 0
HSBK_SATURATION = 1
@ -74,6 +87,11 @@ async def async_setup_entry(
LIFX_SET_STATE_SCHEMA,
"set_state",
)
platform.async_register_entity_service(
SERVICE_LIFX_SET_HEV_CYCLE_STATE,
LIFX_SET_HEV_CYCLE_STATE_SCHEMA,
"set_hev_cycle_state",
)
if lifx_features(device)["multizone"]:
entity: LIFXLight = LIFXStrip(coordinator, manager, entry)
elif lifx_features(device)["color"]:
@ -237,6 +255,18 @@ class LIFXLight(LIFXEntity, LightEntity):
# Update when the transition starts and ends
await self.update_during_transition(fade)
async def set_hev_cycle_state(
self, power: bool, duration: int | None = None
) -> None:
"""Set the state of the HEV LEDs on a LIFX Clean bulb."""
if lifx_features(self.bulb)["hev"] is False:
raise HomeAssistantError(
"This device does not support setting HEV cycle state"
)
await self.coordinator.async_set_hev_cycle_state(power, duration or 0)
await self.update_during_transition(duration or 0)
async def set_power(
self,
pwr: bool,

View file

@ -1,3 +1,29 @@
set_hev_cycle_state:
name: Set HEV cycle state
description: Control the HEV LEDs on a LIFX Clean bulb.
target:
entity:
integration: lifx
domain: light
fields:
power:
name: enable
description: Start or stop a Clean cycle.
required: true
example: true
selector:
boolean:
duration:
name: Duration
description: How long the HEV LEDs will remain on. Uses the configured default duration if not specified.
required: false
default: 7200
example: 3600
selector:
number:
min: 0
max: 86400
unit_of_measurement: seconds
set_state:
name: Set State
description: Set a color/brightness and possibly turn the light on/off.

View file

@ -118,9 +118,9 @@ def _mocked_brightness_bulb() -> Light:
def _mocked_clean_bulb() -> Light:
bulb = _mocked_bulb()
bulb.get_hev_cycle = MockLifxCommand(
bulb, duration=7200, remaining=0, last_power=False
)
bulb.get_hev_cycle = MockLifxCommand(bulb)
bulb.set_hev_cycle = MockLifxCommand(bulb)
bulb.hev_cycle_configuration = {"duration": 7200, "indication": False}
bulb.hev_cycle = {
"duration": 7200,
"remaining": 30,

View file

@ -8,6 +8,7 @@ import pytest
from homeassistant.components import lifx
from homeassistant.components.lifx import DOMAIN
from homeassistant.components.lifx.const import ATTR_POWER
from homeassistant.components.lifx.light import ATTR_INFRARED, ATTR_ZONES
from homeassistant.components.lifx.manager import SERVICE_EFFECT_COLORLOOP
from homeassistant.components.light import (
@ -40,6 +41,7 @@ from . import (
_mocked_brightness_bulb,
_mocked_bulb,
_mocked_bulb_new_firmware,
_mocked_clean_bulb,
_mocked_light_strip,
_mocked_white_bulb,
_patch_config_flow_try_connect,
@ -997,3 +999,61 @@ async def test_color_bulb_is_actually_off(hass: HomeAssistant) -> None:
)
assert bulb.set_color.calls[0][0][0] == [0, 0, 25700, 3500]
assert len(bulb.set_power.calls) == 1
async def test_clean_bulb(hass: HomeAssistant) -> None:
"""Test setting HEV cycle state on Clean bulbs."""
config_entry = MockConfigEntry(
domain=DOMAIN, data={CONF_HOST: "127.0.0.1"}, unique_id=SERIAL
)
config_entry.add_to_hass(hass)
bulb = _mocked_clean_bulb()
bulb.power_level = 0
bulb.hev_cycle = {"duration": 7200, "remaining": 0, "last_power": False}
with _patch_discovery(device=bulb), _patch_config_flow_try_connect(
device=bulb
), _patch_device(device=bulb):
await async_setup_component(hass, lifx.DOMAIN, {lifx.DOMAIN: {}})
await hass.async_block_till_done()
entity_id = "light.my_bulb"
state = hass.states.get(entity_id)
assert state.state == "off"
await hass.services.async_call(
DOMAIN,
"set_hev_cycle_state",
{ATTR_ENTITY_ID: entity_id, ATTR_POWER: True},
blocking=True,
)
call_dict = bulb.set_hev_cycle.calls[0][1]
call_dict.pop("callb")
assert call_dict == {"duration": 0, "enable": True}
bulb.set_hev_cycle.reset_mock()
async def test_set_hev_cycle_state_fails_for_color_bulb(hass: HomeAssistant) -> None:
"""Test that set_hev_cycle_state fails for a non-Clean bulb."""
config_entry = MockConfigEntry(
domain=DOMAIN, data={CONF_HOST: "127.0.0.1"}, unique_id=SERIAL
)
config_entry.add_to_hass(hass)
bulb = _mocked_bulb()
bulb.power_level = 0
with _patch_discovery(device=bulb), _patch_config_flow_try_connect(
device=bulb
), _patch_device(device=bulb):
await async_setup_component(hass, lifx.DOMAIN, {lifx.DOMAIN: {}})
await hass.async_block_till_done()
entity_id = "light.my_bulb"
state = hass.states.get(entity_id)
assert state.state == "off"
with pytest.raises(HomeAssistantError):
await hass.services.async_call(
DOMAIN,
"set_hev_cycle_state",
{ATTR_ENTITY_ID: entity_id, ATTR_POWER: True},
blocking=True,
)