core/homeassistant/components/wilight/light.py

171 lines
6.1 KiB
Python

"""Support for WiLight lights."""
from __future__ import annotations
from typing import Any
from pywilight.const import ITEM_LIGHT, LIGHT_COLOR, LIGHT_DIMMER, LIGHT_ON_OFF
from pywilight.wilight_device import PyWiLightDevice
from homeassistant.components.light import (
ATTR_BRIGHTNESS,
ATTR_HS_COLOR,
ColorMode,
LightEntity,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import DOMAIN, WiLightDevice
from .parent_device import WiLightParent
def entities_from_discovered_wilight(api_device: PyWiLightDevice) -> list[LightEntity]:
"""Parse configuration and add WiLight light entities."""
entities: list[LightEntity] = []
for item in api_device.items:
if item["type"] != ITEM_LIGHT:
continue
index = item["index"]
item_name = item["name"]
if item["sub_type"] == LIGHT_ON_OFF:
entities.append(WiLightLightOnOff(api_device, index, item_name))
elif item["sub_type"] == LIGHT_DIMMER:
entities.append(WiLightLightDimmer(api_device, index, item_name))
elif item["sub_type"] == LIGHT_COLOR:
entities.append(WiLightLightColor(api_device, index, item_name))
return entities
async def async_setup_entry(
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
"""Set up WiLight lights from a config entry."""
parent: WiLightParent = hass.data[DOMAIN][entry.entry_id]
# Handle a discovered WiLight device.
assert parent.api
entities = entities_from_discovered_wilight(parent.api)
async_add_entities(entities)
class WiLightLightOnOff(WiLightDevice, LightEntity):
"""Representation of a WiLights light on-off."""
_attr_color_mode = ColorMode.ONOFF
_attr_supported_color_modes = {ColorMode.ONOFF}
@property
def is_on(self) -> bool | None:
"""Return true if device is on."""
return self._status.get("on")
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the device on."""
await self._client.turn_on(self._index)
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn the device off."""
await self._client.turn_off(self._index)
class WiLightLightDimmer(WiLightDevice, LightEntity):
"""Representation of a WiLights light dimmer."""
_attr_color_mode = ColorMode.BRIGHTNESS
_attr_supported_color_modes = {ColorMode.BRIGHTNESS}
@property
def brightness(self) -> int:
"""Return the brightness of this light between 0..255."""
return int(self._status.get("brightness", 0))
@property
def is_on(self) -> bool | None:
"""Return true if device is on."""
return self._status.get("on")
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the device on,set brightness if needed."""
# Dimmer switches use a range of [0, 255] to control
# brightness. Level 255 might mean to set it to previous value
if ATTR_BRIGHTNESS in kwargs:
brightness = kwargs[ATTR_BRIGHTNESS]
await self._client.set_brightness(self._index, brightness)
else:
await self._client.turn_on(self._index)
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn the device off."""
await self._client.turn_off(self._index)
def wilight_to_hass_hue(value: int) -> float:
"""Convert wilight hue 1..255 to hass 0..360 scale."""
return min(360, round((value * 360) / 255, 3))
def hass_to_wilight_hue(value: float) -> int:
"""Convert hass hue 0..360 to wilight 1..255 scale."""
return min(255, round((value * 255) / 360))
def wilight_to_hass_saturation(value: int) -> float:
"""Convert wilight saturation 1..255 to hass 0..100 scale."""
return min(100, round((value * 100) / 255, 3))
def hass_to_wilight_saturation(value: float) -> int:
"""Convert hass saturation 0..100 to wilight 1..255 scale."""
return min(255, round((value * 255) / 100))
class WiLightLightColor(WiLightDevice, LightEntity):
"""Representation of a WiLights light rgb."""
_attr_color_mode = ColorMode.HS
_attr_supported_color_modes = {ColorMode.HS}
@property
def brightness(self) -> int:
"""Return the brightness of this light between 0..255."""
return int(self._status.get("brightness", 0))
@property
def hs_color(self) -> tuple[float, float]:
"""Return the hue and saturation color value [float, float]."""
return (
wilight_to_hass_hue(int(self._status.get("hue", 0))),
wilight_to_hass_saturation(int(self._status.get("saturation", 0))),
)
@property
def is_on(self) -> bool | None:
"""Return true if device is on."""
return self._status.get("on")
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the device on,set brightness if needed."""
# Brightness use a range of [0, 255] to control
# Hue use a range of [0, 360] to control
# Saturation use a range of [0, 100] to control
if ATTR_BRIGHTNESS in kwargs and ATTR_HS_COLOR in kwargs:
brightness = kwargs[ATTR_BRIGHTNESS]
hue = hass_to_wilight_hue(kwargs[ATTR_HS_COLOR][0])
saturation = hass_to_wilight_saturation(kwargs[ATTR_HS_COLOR][1])
await self._client.set_hsb_color(self._index, hue, saturation, brightness)
elif ATTR_BRIGHTNESS in kwargs and ATTR_HS_COLOR not in kwargs:
brightness = kwargs[ATTR_BRIGHTNESS]
await self._client.set_brightness(self._index, brightness)
elif ATTR_BRIGHTNESS not in kwargs and ATTR_HS_COLOR in kwargs:
hue = hass_to_wilight_hue(kwargs[ATTR_HS_COLOR][0])
saturation = hass_to_wilight_saturation(kwargs[ATTR_HS_COLOR][1])
await self._client.set_hs_color(self._index, hue, saturation)
else:
await self._client.turn_on(self._index)
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn the device off."""
await self._client.turn_off(self._index)