"""Home Assistant entity for interacting with Afero Light.""" from functools import partial from aioafero import EventType from aioafero.v1 import AferoBridgeV1, LightController from aioafero.v1.models import Light from homeassistant.components.light import ( ATTR_BRIGHTNESS, ATTR_COLOR_TEMP_KELVIN, ATTR_EFFECT, ATTR_RGB_COLOR, ColorMode, LightEntity, LightEntityFeature, filter_supported_color_modes, ) from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.util.color import brightness_to_value, value_to_brightness from .bridge import HubspaceBridge from .const import DOMAIN from .entity import HubspaceBaseEntity class HubspaceLight(HubspaceBaseEntity, LightEntity): """Representation of an Afero light.""" def __init__( self, bridge: HubspaceBridge, controller: LightController, resource: Light, ) -> None: """Initialize an Afero light.""" super().__init__(bridge, controller, resource) self._supported_features: LightEntityFeature = LightEntityFeature(0) supported_color_modes = {ColorMode.ONOFF} if self.resource.supports_color: supported_color_modes.add(ColorMode.RGB) if self.resource.supports_color_temperature: supported_color_modes.add(ColorMode.COLOR_TEMP) if self.resource.supports_dimming: supported_color_modes.add(ColorMode.BRIGHTNESS) self._attr_supported_color_modes = filter_supported_color_modes( supported_color_modes ) @property def brightness(self) -> int | None: """The brightness of this light between 1..255.""" return ( value_to_brightness((1, 100), self.resource.brightness) if self.resource.dimming else None ) @property def color_mode(self) -> ColorMode: """Get the current color mode for the light.""" return get_color_mode(self.resource, self._attr_supported_color_modes) @property def color_temp_kelvin(self) -> int | None: """Get the current color temperature for the light.""" return ( self.resource.color_temperature.temperature if self.resource.color_temperature else None ) @property def effect(self) -> str | None: """Get the current effect for the light.""" return ( self.resource.effect.effect if (self.resource.effect and self.resource.color_mode.mode == "sequence") else None ) @property def effect_list(self) -> list[str] | None: """Get all available effects for the light.""" all_effects = [] for effects in self.resource.effect.effects.values() or []: all_effects.extend(effects) return all_effects or None @property def is_on(self) -> bool | None: """Determine if the light is currently on.""" return self.resource.is_on @property def max_color_temp_kelvin(self) -> int | None: """Get the lights maximum temperature color.""" return ( max(self.resource.color_temperature.supported) if self.resource.color_temperature else None ) @property def min_color_temp_kelvin(self) -> int | None: """Get the lights minimum temperature color.""" return ( min(self.resource.color_temperature.supported) if self.resource.color_temperature else None ) @property def rgb_color(self) -> tuple[int, int, int] | None: """Get the lights current RGB colors.""" return ( ( self.resource.color.red, self.resource.color.green, self.resource.color.blue, ) if self.resource.color else None ) @property def supported_color_modes(self) -> set[ColorMode]: """Get all supported color modes.""" return self._attr_supported_color_modes @property def supported_features(self) -> LightEntityFeature: """Get all supported light features.""" if self.resource.effect: return LightEntityFeature(0) | LightEntityFeature.EFFECT return LightEntityFeature(0) async def async_turn_on(self, **kwargs) -> None: """Turn device on.""" brightness: int | None = None if ATTR_BRIGHTNESS in kwargs: brightness = int(brightness_to_value((1, 100), kwargs[ATTR_BRIGHTNESS])) temperature: int | None = kwargs.get(ATTR_COLOR_TEMP_KELVIN) color: tuple[int, int, int] | None = kwargs.get(ATTR_RGB_COLOR) effect: str | None = kwargs.get(ATTR_EFFECT) color_mode: str | None = None if temperature: color_mode = "white" elif color: color_mode = "color" elif effect: color_mode = "sequence" await self.bridge.async_request_call( self.controller.set_state, device_id=self.resource.id, on=True, brightness=brightness, temperature=temperature, color=color, color_mode=color_mode, effect=effect, ) async def async_turn_off(self, **kwargs) -> None: """Turn device off.""" await self.bridge.async_request_call( self.controller.set_state, device_id=self.resource.id, on=False, ) def get_color_mode(resource: Light, supported_modes: set[ColorMode]) -> ColorMode: """Determine the correct mode. :param resource: Light from aioafero :param supported_modes: Supported color modes """ if not resource.color_mode: return list(supported_modes)[0] if len(supported_modes) else ColorMode.ONOFF if resource.color_mode.mode == "color": return ColorMode.RGB if resource.color_mode.mode == "white": if ColorMode.COLOR_TEMP in supported_modes: return ColorMode.COLOR_TEMP if ColorMode.BRIGHTNESS in supported_modes: return ColorMode.BRIGHTNESS return ColorMode.ONOFF return list(supported_modes)[-1] if len(supported_modes) else ColorMode.ONOFF async def async_setup_entry( hass: HomeAssistant, config_entry: ConfigEntry, async_add_entities: AddEntitiesCallback, ) -> None: """Set up entities.""" bridge: HubspaceBridge = hass.data[DOMAIN][config_entry.entry_id] api: AferoBridgeV1 = bridge.api controller: LightController = api.lights make_entity = partial(HubspaceLight, bridge, controller) @callback def async_add_entity(event_type: EventType, resource: Light) -> None: """Add an entity.""" async_add_entities([make_entity(resource)]) # add all current items in controller async_add_entities(make_entity(entity) for entity in controller) # register listener for new entities config_entry.async_on_unload( controller.subscribe(async_add_entity, event_filter=EventType.RESOURCE_ADDED) )