core/homeassistant/components/fibaro/light.py

172 lines
5.7 KiB
Python

"""Support for Fibaro lights."""
from __future__ import annotations
from contextlib import suppress
from typing import Any
from pyfibaro.fibaro_device import DeviceModel
from homeassistant.components.light import (
ATTR_BRIGHTNESS,
ATTR_RGB_COLOR,
ATTR_RGBW_COLOR,
ENTITY_ID_FORMAT,
ColorMode,
LightEntity,
brightness_supported,
color_supported,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import FibaroController
from .const import DOMAIN
from .entity import FibaroEntity
PARALLEL_UPDATES = 2
def scaleto255(value: int | None) -> int:
"""Scale the input value from 0-100 to 0-255."""
if value is None:
return 0
# Fibaro has a funny way of storing brightness either 0-100 or 0-99
# depending on device type (e.g. dimmer vs led)
if value > 98:
value = 100
return round(value * 2.55)
def scaleto99(value: int | None) -> int:
"""Scale the input value from 0-255 to 0-99."""
if value is None:
return 0
# Make sure a low but non-zero value is not rounded down to zero
if 0 < value < 3:
return 1
return min(round(value / 2.55), 99)
async def async_setup_entry(
hass: HomeAssistant,
entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Perform the setup for Fibaro controller devices."""
controller: FibaroController = hass.data[DOMAIN][entry.entry_id]
async_add_entities(
[FibaroLight(device) for device in controller.fibaro_devices[Platform.LIGHT]],
True,
)
class FibaroLight(FibaroEntity, LightEntity):
"""Representation of a Fibaro Light, including dimmable."""
def __init__(self, fibaro_device: DeviceModel) -> None:
"""Initialize the light."""
supports_color = (
"color" in fibaro_device.properties
or "colorComponents" in fibaro_device.properties
or "RGB" in fibaro_device.type
or "rgb" in fibaro_device.type
or "color" in fibaro_device.base_type
) and (
"setColor" in fibaro_device.actions
or "setColorComponents" in fibaro_device.actions
)
supports_white_v = (
"setW" in fibaro_device.actions
or "RGBW" in fibaro_device.type
or "rgbw" in fibaro_device.type
)
supports_dimming = (
fibaro_device.has_interface("levelChange")
and "setValue" in fibaro_device.actions
)
if supports_color and supports_white_v:
self._attr_supported_color_modes = {ColorMode.RGBW}
self._attr_color_mode = ColorMode.RGBW
elif supports_color:
self._attr_supported_color_modes = {ColorMode.RGB}
self._attr_color_mode = ColorMode.RGB
elif supports_dimming:
self._attr_supported_color_modes = {ColorMode.BRIGHTNESS}
self._attr_color_mode = ColorMode.BRIGHTNESS
else:
self._attr_supported_color_modes = {ColorMode.ONOFF}
self._attr_color_mode = ColorMode.ONOFF
super().__init__(fibaro_device)
self.entity_id = ENTITY_ID_FORMAT.format(self.ha_id)
def turn_on(self, **kwargs: Any) -> None:
"""Turn the light on."""
if ATTR_BRIGHTNESS in kwargs:
self._attr_brightness = kwargs[ATTR_BRIGHTNESS]
self.set_level(scaleto99(self._attr_brightness))
return
if ATTR_RGB_COLOR in kwargs:
# Update based on parameters
rgb = kwargs[ATTR_RGB_COLOR]
self._attr_rgb_color = rgb
self.call_set_color(int(rgb[0]), int(rgb[1]), int(rgb[2]), 0)
return
if ATTR_RGBW_COLOR in kwargs:
# Update based on parameters
rgbw = kwargs[ATTR_RGBW_COLOR]
self._attr_rgbw_color = rgbw
self.call_set_color(int(rgbw[0]), int(rgbw[1]), int(rgbw[2]), int(rgbw[3]))
return
# The simplest case is left for last. No dimming, just switch on
self.call_turn_on()
def turn_off(self, **kwargs: Any) -> None:
"""Turn the light off."""
self.call_turn_off()
def update(self) -> None:
"""Update the state."""
super().update()
# Dimmable and RGB lights can be on based on different
# properties, so we need to check here several values
# to see if the light is on.
light_is_on = self.current_binary_state
with suppress(TypeError):
if self.fibaro_device.brightness != 0:
light_is_on = True
with suppress(TypeError):
if self.fibaro_device.current_program != 0:
light_is_on = True
with suppress(TypeError):
if self.fibaro_device.current_program_id != 0:
light_is_on = True
self._attr_is_on = light_is_on
# Brightness handling
if brightness_supported(self.supported_color_modes):
self._attr_brightness = scaleto255(self.fibaro_device.value.int_value())
# Color handling
if (
color_supported(self.supported_color_modes)
and self.fibaro_device.color.has_color
):
# Fibaro communicates the color as an 'R, G, B, W' string
rgbw = self.fibaro_device.color.rgbw_color
if rgbw == (0, 0, 0, 0) and self.fibaro_device.last_color_set.has_color:
rgbw = self.fibaro_device.last_color_set.rgbw_color
if self.color_mode == ColorMode.RGB:
self._attr_rgb_color = rgbw[:3]
else:
self._attr_rgbw_color = rgbw