169 lines
6.1 KiB
Python
169 lines
6.1 KiB
Python
"""The Twinkly light component."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
from typing import Any
|
|
|
|
from homeassistant.components.light import (
|
|
ATTR_BRIGHTNESS,
|
|
ATTR_EFFECT,
|
|
ATTR_RGB_COLOR,
|
|
ATTR_RGBW_COLOR,
|
|
ColorMode,
|
|
LightEntity,
|
|
LightEntityFeature,
|
|
)
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
|
|
|
from . import TwinklyConfigEntry, TwinklyCoordinator
|
|
from .const import DEV_LED_PROFILE, DEV_PROFILE_RGB, DEV_PROFILE_RGBW
|
|
from .entity import TwinklyEntity
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
|
|
async def async_setup_entry(
|
|
hass: HomeAssistant,
|
|
config_entry: TwinklyConfigEntry,
|
|
async_add_entities: AddEntitiesCallback,
|
|
) -> None:
|
|
"""Setups an entity from a config entry (UI config flow)."""
|
|
entity = TwinklyLight(config_entry.runtime_data)
|
|
|
|
async_add_entities([entity], update_before_add=True)
|
|
|
|
|
|
class TwinklyLight(TwinklyEntity, LightEntity):
|
|
"""Implementation of the light for the Twinkly service."""
|
|
|
|
_attr_name = None
|
|
_attr_translation_key = "light"
|
|
|
|
def __init__(self, coordinator: TwinklyCoordinator) -> None:
|
|
"""Initialize a TwinklyLight entity."""
|
|
super().__init__(coordinator)
|
|
device_info = coordinator.data.device_info
|
|
self._attr_unique_id = device_info["mac"]
|
|
|
|
if device_info.get(DEV_LED_PROFILE) == DEV_PROFILE_RGBW:
|
|
self._attr_supported_color_modes = {ColorMode.RGBW}
|
|
self._attr_color_mode = ColorMode.RGBW
|
|
self._attr_rgbw_color = (255, 255, 255, 0)
|
|
elif device_info.get(DEV_LED_PROFILE) == DEV_PROFILE_RGB:
|
|
self._attr_supported_color_modes = {ColorMode.RGB}
|
|
self._attr_color_mode = ColorMode.RGB
|
|
self._attr_rgb_color = (255, 255, 255)
|
|
else:
|
|
self._attr_supported_color_modes = {ColorMode.BRIGHTNESS}
|
|
self._attr_color_mode = ColorMode.BRIGHTNESS
|
|
self.client = coordinator.client
|
|
if coordinator.supports_effects:
|
|
self._attr_supported_features = LightEntityFeature.EFFECT
|
|
self._update_attr()
|
|
|
|
@property
|
|
def effect(self) -> str | None:
|
|
"""Return the current effect."""
|
|
if (current_movie_id := self.coordinator.data.current_movie) is not None:
|
|
return (
|
|
f"{current_movie_id} {self.coordinator.data.movies[current_movie_id]}"
|
|
)
|
|
return None
|
|
|
|
@property
|
|
def effect_list(self) -> list[str]:
|
|
"""Return the list of saved effects."""
|
|
return [
|
|
f"{identifier} {name}"
|
|
for identifier, name in self.coordinator.data.movies.items()
|
|
]
|
|
|
|
async def async_turn_on(self, **kwargs: Any) -> None:
|
|
"""Turn device on."""
|
|
if ATTR_BRIGHTNESS in kwargs:
|
|
brightness = int(int(kwargs[ATTR_BRIGHTNESS]) / 2.55)
|
|
|
|
# If brightness is 0, the twinkly will only "disable" the brightness,
|
|
# which means that it will be 100%.
|
|
if brightness == 0:
|
|
await self.client.turn_off()
|
|
return
|
|
|
|
await self.client.set_brightness(brightness)
|
|
|
|
if (
|
|
ATTR_RGBW_COLOR in kwargs
|
|
and kwargs[ATTR_RGBW_COLOR] != self._attr_rgbw_color
|
|
):
|
|
await self.client.interview()
|
|
if LightEntityFeature.EFFECT & self.supported_features:
|
|
# Static color only supports rgb
|
|
await self.client.set_static_colour(
|
|
(
|
|
kwargs[ATTR_RGBW_COLOR][0],
|
|
kwargs[ATTR_RGBW_COLOR][1],
|
|
kwargs[ATTR_RGBW_COLOR][2],
|
|
)
|
|
)
|
|
await self.client.set_mode("color")
|
|
self.client.default_mode = "color"
|
|
else:
|
|
await self.client.set_cycle_colours(
|
|
(
|
|
kwargs[ATTR_RGBW_COLOR][3],
|
|
kwargs[ATTR_RGBW_COLOR][0],
|
|
kwargs[ATTR_RGBW_COLOR][1],
|
|
kwargs[ATTR_RGBW_COLOR][2],
|
|
)
|
|
)
|
|
await self.client.set_mode("movie")
|
|
self.client.default_mode = "movie"
|
|
self._attr_rgbw_color = kwargs[ATTR_RGBW_COLOR]
|
|
|
|
if ATTR_RGB_COLOR in kwargs and kwargs[ATTR_RGB_COLOR] != self._attr_rgb_color:
|
|
await self.client.interview()
|
|
if LightEntityFeature.EFFECT & self.supported_features:
|
|
await self.client.set_static_colour(kwargs[ATTR_RGB_COLOR])
|
|
await self.client.set_mode("color")
|
|
self.client.default_mode = "color"
|
|
else:
|
|
await self.client.set_cycle_colours(kwargs[ATTR_RGB_COLOR])
|
|
await self.client.set_mode("movie")
|
|
self.client.default_mode = "movie"
|
|
|
|
self._attr_rgb_color = kwargs[ATTR_RGB_COLOR]
|
|
|
|
if (
|
|
ATTR_EFFECT in kwargs
|
|
and LightEntityFeature.EFFECT & self.supported_features
|
|
):
|
|
movie_id = kwargs[ATTR_EFFECT].split(" ")[0]
|
|
if (
|
|
self.coordinator.data.current_movie is None
|
|
or int(movie_id) != self.coordinator.data.current_movie
|
|
):
|
|
await self.client.interview()
|
|
await self.client.set_current_movie(int(movie_id))
|
|
await self.client.set_mode("movie")
|
|
self.client.default_mode = "movie"
|
|
if not self._attr_is_on:
|
|
await self.client.turn_on()
|
|
await self.coordinator.async_refresh()
|
|
|
|
async def async_turn_off(self, **kwargs: Any) -> None:
|
|
"""Turn device off."""
|
|
await self.client.turn_off()
|
|
await self.coordinator.async_refresh()
|
|
|
|
def _update_attr(self) -> None:
|
|
"""Update the entity attributes."""
|
|
self._attr_is_on = self.coordinator.data.is_on
|
|
self._attr_brightness = self.coordinator.data.brightness
|
|
|
|
def _handle_coordinator_update(self) -> None:
|
|
"""Handle updated data from the coordinator."""
|
|
self._update_attr()
|
|
super()._handle_coordinator_update()
|