mirror of
https://github.com/home-assistant/core.git
synced 2026-02-15 07:36:16 +00:00
Add dimming functionality to the Lunatone light entity (#154508)
Co-authored-by: Dave T <17680170+davet2001@users.noreply.github.com>
This commit is contained in:
@@ -5,11 +5,17 @@ from __future__ import annotations
|
||||
import asyncio
|
||||
from typing import Any
|
||||
|
||||
from homeassistant.components.light import ColorMode, LightEntity
|
||||
from homeassistant.components.light import (
|
||||
ATTR_BRIGHTNESS,
|
||||
ColorMode,
|
||||
LightEntity,
|
||||
brightness_supported,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||
from homeassistant.util.color import brightness_to_value, value_to_brightness
|
||||
|
||||
from .const import DOMAIN
|
||||
from .coordinator import LunatoneConfigEntry, LunatoneDevicesDataUpdateCoordinator
|
||||
@@ -42,8 +48,10 @@ class LunatoneLight(
|
||||
):
|
||||
"""Representation of a Lunatone light."""
|
||||
|
||||
_attr_color_mode = ColorMode.ONOFF
|
||||
_attr_supported_color_modes = {ColorMode.ONOFF}
|
||||
BRIGHTNESS_SCALE = (1, 100)
|
||||
|
||||
_last_brightness = 255
|
||||
|
||||
_attr_has_entity_name = True
|
||||
_attr_name = None
|
||||
_attr_should_poll = False
|
||||
@@ -82,6 +90,25 @@ class LunatoneLight(
|
||||
"""Return True if light is on."""
|
||||
return self._device is not None and self._device.is_on
|
||||
|
||||
@property
|
||||
def brightness(self) -> int:
|
||||
"""Return the brightness of this light between 0..255."""
|
||||
if self._device is None:
|
||||
return 0
|
||||
return value_to_brightness(self.BRIGHTNESS_SCALE, self._device.brightness)
|
||||
|
||||
@property
|
||||
def color_mode(self) -> ColorMode:
|
||||
"""Return the color mode of the light."""
|
||||
if self._device is not None and self._device.is_dimmable:
|
||||
return ColorMode.BRIGHTNESS
|
||||
return ColorMode.ONOFF
|
||||
|
||||
@property
|
||||
def supported_color_modes(self) -> set[ColorMode]:
|
||||
"""Return the supported color modes."""
|
||||
return {self.color_mode}
|
||||
|
||||
@callback
|
||||
def _handle_coordinator_update(self) -> None:
|
||||
"""Handle updated data from the coordinator."""
|
||||
@@ -91,13 +118,27 @@ class LunatoneLight(
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Instruct the light to turn on."""
|
||||
assert self._device
|
||||
await self._device.switch_on()
|
||||
|
||||
if brightness_supported(self.supported_color_modes):
|
||||
brightness = kwargs.get(ATTR_BRIGHTNESS, self._last_brightness)
|
||||
await self._device.fade_to_brightness(
|
||||
brightness_to_value(self.BRIGHTNESS_SCALE, brightness)
|
||||
)
|
||||
else:
|
||||
await self._device.switch_on()
|
||||
|
||||
await asyncio.sleep(STATUS_UPDATE_DELAY)
|
||||
await self.coordinator.async_refresh()
|
||||
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
"""Instruct the light to turn off."""
|
||||
assert self._device
|
||||
await self._device.switch_off()
|
||||
|
||||
if brightness_supported(self.supported_color_modes):
|
||||
self._last_brightness = self.brightness
|
||||
await self._device.fade_to_brightness(0)
|
||||
else:
|
||||
await self._device.switch_off()
|
||||
|
||||
await asyncio.sleep(STATUS_UPDATE_DELAY)
|
||||
await self.coordinator.async_refresh()
|
||||
|
||||
@@ -27,6 +27,7 @@ def mock_setup_entry() -> Generator[AsyncMock]:
|
||||
@pytest.fixture
|
||||
def mock_lunatone_devices() -> Generator[AsyncMock]:
|
||||
"""Mock a Lunatone devices object."""
|
||||
state = {"is_dimmable": False}
|
||||
|
||||
def build_devices_mock(devices: Devices):
|
||||
device_list = []
|
||||
@@ -36,6 +37,10 @@ def mock_lunatone_devices() -> Generator[AsyncMock]:
|
||||
device.id = device.data.id
|
||||
device.name = device.data.name
|
||||
device.is_on = device.data.features.switchable.status
|
||||
device.brightness = device.data.features.dimmable.status
|
||||
type(device).is_dimmable = PropertyMock(
|
||||
side_effect=lambda s=state: s["is_dimmable"]
|
||||
)
|
||||
device_list.append(device)
|
||||
return device_list
|
||||
|
||||
@@ -47,6 +52,7 @@ def mock_lunatone_devices() -> Generator[AsyncMock]:
|
||||
type(devices).devices = PropertyMock(
|
||||
side_effect=lambda d=devices: build_devices_mock(d)
|
||||
)
|
||||
devices.set_is_dimmable = lambda value, s=state: s.update(is_dimmable=value)
|
||||
yield devices
|
||||
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ from unittest.mock import AsyncMock
|
||||
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
|
||||
from homeassistant.components.light import DOMAIN as LIGHT_DOMAIN
|
||||
from homeassistant.components.light import ATTR_BRIGHTNESS, DOMAIN as LIGHT_DOMAIN
|
||||
from homeassistant.const import (
|
||||
ATTR_ENTITY_ID,
|
||||
SERVICE_TURN_OFF,
|
||||
@@ -47,7 +47,6 @@ async def test_turn_on_off(
|
||||
mock_lunatone_devices: AsyncMock,
|
||||
mock_lunatone_info: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
entity_registry: er.EntityRegistry,
|
||||
) -> None:
|
||||
"""Test the light can be turned on and off."""
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
@@ -77,3 +76,59 @@ async def test_turn_on_off(
|
||||
|
||||
state = hass.states.get(TEST_ENTITY_ID)
|
||||
assert state.state == STATE_OFF
|
||||
|
||||
|
||||
async def test_turn_on_off_with_brightness(
|
||||
hass: HomeAssistant,
|
||||
mock_lunatone_devices: AsyncMock,
|
||||
mock_lunatone_info: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test the light can be turned on with brightness."""
|
||||
expected_brightness = 128
|
||||
brightness_percentages = iter([50.0, 0.0, 50.0])
|
||||
|
||||
mock_lunatone_devices.set_is_dimmable(True)
|
||||
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
|
||||
async def fake_update():
|
||||
brightness = next(brightness_percentages)
|
||||
device = mock_lunatone_devices.data.devices[0]
|
||||
device.features.switchable.status = brightness > 0
|
||||
device.features.dimmable.status = brightness
|
||||
|
||||
mock_lunatone_devices.async_update.side_effect = fake_update
|
||||
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
{ATTR_ENTITY_ID: TEST_ENTITY_ID, ATTR_BRIGHTNESS: expected_brightness},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
state = hass.states.get(TEST_ENTITY_ID)
|
||||
assert state.state == STATE_ON
|
||||
assert state.attributes["brightness"] == expected_brightness
|
||||
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
SERVICE_TURN_OFF,
|
||||
{ATTR_ENTITY_ID: TEST_ENTITY_ID},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
state = hass.states.get(TEST_ENTITY_ID)
|
||||
assert state.state == STATE_OFF
|
||||
assert not state.attributes["brightness"]
|
||||
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
{ATTR_ENTITY_ID: TEST_ENTITY_ID},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
state = hass.states.get(TEST_ENTITY_ID)
|
||||
assert state.state == STATE_ON
|
||||
assert state.attributes["brightness"] == expected_brightness
|
||||
|
||||
Reference in New Issue
Block a user