mirror of
https://github.com/home-assistant/core.git
synced 2026-04-02 08:26:41 +01:00
154 lines
5.1 KiB
Python
154 lines
5.1 KiB
Python
"""Light platform for SLZB-Ultima Ambilight."""
|
|
|
|
from dataclasses import dataclass
|
|
import logging
|
|
from typing import Any
|
|
|
|
from pysmlight.const import AMBI_EFFECT_LIST, AmbiEffect, Pages
|
|
from pysmlight.models import AmbilightPayload
|
|
|
|
from homeassistant.components.light import (
|
|
ATTR_BRIGHTNESS,
|
|
ATTR_EFFECT,
|
|
ATTR_RGB_COLOR,
|
|
ColorMode,
|
|
LightEntity,
|
|
LightEntityDescription,
|
|
LightEntityFeature,
|
|
)
|
|
from homeassistant.core import HomeAssistant, callback
|
|
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
|
|
|
from .coordinator import SmConfigEntry, SmDataUpdateCoordinator
|
|
from .entity import SmEntity
|
|
|
|
PARALLEL_UPDATES = 1
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
|
|
@dataclass(kw_only=True, frozen=True)
|
|
class SmLightEntityDescription(LightEntityDescription):
|
|
"""Class describing Smlight light entities."""
|
|
|
|
effect_list: list[str]
|
|
|
|
|
|
AMBILIGHT = SmLightEntityDescription(
|
|
key="ambilight",
|
|
translation_key="ambilight",
|
|
icon="mdi:led-strip",
|
|
effect_list=AMBI_EFFECT_LIST,
|
|
)
|
|
|
|
|
|
async def async_setup_entry(
|
|
hass: HomeAssistant,
|
|
entry: SmConfigEntry,
|
|
async_add_entities: AddConfigEntryEntitiesCallback,
|
|
) -> None:
|
|
"""Initialize light for SLZB-Ultima device."""
|
|
coordinator = entry.runtime_data.data
|
|
|
|
if coordinator.data.info.has_peripherals:
|
|
async_add_entities([SmLightEntity(coordinator, AMBILIGHT)])
|
|
|
|
|
|
class SmLightEntity(SmEntity, LightEntity):
|
|
"""Representation of light entity for SLZB-Ultima Ambilight."""
|
|
|
|
coordinator: SmDataUpdateCoordinator
|
|
entity_description: SmLightEntityDescription
|
|
_attr_color_mode = ColorMode.RGB
|
|
_attr_supported_color_modes = {ColorMode.RGB}
|
|
_attr_supported_features = LightEntityFeature.EFFECT
|
|
|
|
def __init__(
|
|
self,
|
|
coordinator: SmDataUpdateCoordinator,
|
|
description: SmLightEntityDescription,
|
|
) -> None:
|
|
"""Initialize light entity."""
|
|
super().__init__(coordinator)
|
|
|
|
self.entity_description = description
|
|
self._attr_unique_id = f"{coordinator.unique_id}-{description.key}"
|
|
self._attr_effect_list = description.effect_list
|
|
|
|
@callback
|
|
def _handle_coordinator_update(self) -> None:
|
|
"""Handle updated data from the coordinator."""
|
|
if ambi := self.coordinator.data.sensors.ambilight:
|
|
self._attr_is_on = ambi.ultLedMode not in (None, AmbiEffect.WSULT_OFF)
|
|
self._attr_brightness = ambi.ultLedBri
|
|
self._attr_effect = self._effect_from_mode(ambi.ultLedMode)
|
|
self._attr_rgb_color = self._parse_rgb_color(ambi.ultLedColor)
|
|
super()._handle_coordinator_update()
|
|
|
|
async def async_added_to_hass(self) -> None:
|
|
"""Register SSE page callback when entity is added to hass."""
|
|
await super().async_added_to_hass()
|
|
self.async_on_remove(
|
|
self.coordinator.client.sse.register_page_cb(
|
|
Pages.API2_PAGE_AMBILIGHT, self._handle_ambilight_changes
|
|
)
|
|
)
|
|
|
|
@callback
|
|
def _handle_ambilight_changes(self, changes: dict) -> None:
|
|
"""Handle ambilight SSE event."""
|
|
self.coordinator.update_ambilight(changes)
|
|
|
|
def _effect_from_mode(self, mode: AmbiEffect | None) -> str | None:
|
|
"""Return the effect name for a given AmbiEffect mode."""
|
|
if mode is None:
|
|
return None
|
|
try:
|
|
return self.entity_description.effect_list[int(mode)]
|
|
except IndexError, ValueError:
|
|
return None
|
|
|
|
def _parse_rgb_color(self, color: str | None) -> tuple[int, int, int] | None:
|
|
"""Parse a hex color string into an RGB tuple."""
|
|
try:
|
|
if color and color.startswith("#"):
|
|
return (int(color[1:3], 16), int(color[3:5], 16), int(color[5:7], 16))
|
|
except ValueError:
|
|
pass
|
|
return None
|
|
|
|
async def async_turn_on(self, **kwargs: Any) -> None:
|
|
"""Format kwargs into the specific schema for SLZB-OS and set."""
|
|
payload = AmbilightPayload()
|
|
|
|
if ATTR_EFFECT in kwargs:
|
|
effect_name: str = kwargs[ATTR_EFFECT]
|
|
try:
|
|
idx = self.entity_description.effect_list.index(effect_name)
|
|
except ValueError:
|
|
_LOGGER.warning("Unknown effect: %s", effect_name)
|
|
return
|
|
payload.ultLedMode = AmbiEffect(idx)
|
|
elif not self.is_on:
|
|
payload.ultLedMode = AmbiEffect.WSULT_SOLID
|
|
|
|
if ATTR_BRIGHTNESS in kwargs:
|
|
payload.ultLedBri = kwargs[ATTR_BRIGHTNESS]
|
|
if ATTR_RGB_COLOR in kwargs:
|
|
r, g, b = kwargs[ATTR_RGB_COLOR]
|
|
payload.ultLedColor = f"#{r:02x}{g:02x}{b:02x}"
|
|
|
|
if payload == AmbilightPayload():
|
|
return
|
|
|
|
await self.coordinator.async_execute_command(
|
|
self.coordinator.client.actions.ambilight, payload
|
|
)
|
|
|
|
async def async_turn_off(self, **kwargs: Any) -> None:
|
|
"""Turn the Ambilight off using effect OFF."""
|
|
await self.coordinator.async_execute_command(
|
|
self.coordinator.client.actions.ambilight,
|
|
AmbilightPayload(ultLedMode=AmbiEffect.WSULT_OFF),
|
|
)
|