core/homeassistant/components/homekit_controller/light.py

168 lines
5.4 KiB
Python

"""Support for Homekit lights."""
from __future__ import annotations
from typing import Any
from aiohomekit.model.characteristics import CharacteristicsTypes
from aiohomekit.model.services import Service, ServicesTypes
from homeassistant.components.light import (
ATTR_BRIGHTNESS,
ATTR_COLOR_TEMP,
ATTR_HS_COLOR,
ColorMode,
LightEntity,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import KNOWN_DEVICES
from .connection import HKDevice
from .entity import HomeKitEntity
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up Homekit lightbulb."""
hkid: str = config_entry.data["AccessoryPairingID"]
conn: HKDevice = hass.data[KNOWN_DEVICES][hkid]
@callback
def async_add_service(service: Service) -> bool:
if service.type != ServicesTypes.LIGHTBULB:
return False
info = {"aid": service.accessory.aid, "iid": service.iid}
entity = HomeKitLight(conn, info)
conn.async_migrate_unique_id(
entity.old_unique_id, entity.unique_id, Platform.LIGHT
)
async_add_entities([entity])
return True
conn.add_listener(async_add_service)
class HomeKitLight(HomeKitEntity, LightEntity):
"""Representation of a Homekit light."""
def get_characteristic_types(self) -> list[str]:
"""Define the homekit characteristics the entity cares about."""
return [
CharacteristicsTypes.ON,
CharacteristicsTypes.BRIGHTNESS,
CharacteristicsTypes.COLOR_TEMPERATURE,
CharacteristicsTypes.HUE,
CharacteristicsTypes.SATURATION,
]
@property
def is_on(self) -> bool:
"""Return true if device is on."""
return self.service.value(CharacteristicsTypes.ON)
@property
def brightness(self) -> int:
"""Return the brightness of this light between 0..255."""
return self.service.value(CharacteristicsTypes.BRIGHTNESS) * 255 / 100
@property
def hs_color(self) -> tuple[float, float]:
"""Return the color property."""
return (
self.service.value(CharacteristicsTypes.HUE),
self.service.value(CharacteristicsTypes.SATURATION),
)
@property
def min_mireds(self) -> int:
"""Return minimum supported color temperature."""
min_value = self.service[CharacteristicsTypes.COLOR_TEMPERATURE].minValue
return int(min_value) if min_value else super().min_mireds
@property
def max_mireds(self) -> int:
"""Return the maximum color temperature."""
max_value = self.service[CharacteristicsTypes.COLOR_TEMPERATURE].maxValue
return int(max_value) if max_value else super().max_mireds
@property
def color_temp(self) -> int:
"""Return the color temperature."""
return self.service.value(CharacteristicsTypes.COLOR_TEMPERATURE)
@property
def color_mode(self) -> str:
"""Return the color mode of the light."""
# aiohomekit does not keep track of the light's color mode, report
# hs for light supporting both hs and ct
if self.service.has(CharacteristicsTypes.HUE) or self.service.has(
CharacteristicsTypes.SATURATION
):
return ColorMode.HS
if self.service.has(CharacteristicsTypes.COLOR_TEMPERATURE):
return ColorMode.COLOR_TEMP
if self.service.has(CharacteristicsTypes.BRIGHTNESS):
return ColorMode.BRIGHTNESS
return ColorMode.ONOFF
@property
def supported_color_modes(self) -> set[ColorMode]:
"""Flag supported color modes."""
color_modes: set[ColorMode] = set()
if self.service.has(CharacteristicsTypes.HUE) or self.service.has(
CharacteristicsTypes.SATURATION
):
color_modes.add(ColorMode.HS)
if self.service.has(CharacteristicsTypes.COLOR_TEMPERATURE):
color_modes.add(ColorMode.COLOR_TEMP)
if not color_modes and self.service.has(CharacteristicsTypes.BRIGHTNESS):
color_modes.add(ColorMode.BRIGHTNESS)
if not color_modes:
color_modes.add(ColorMode.ONOFF)
return color_modes
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the specified light on."""
hs_color = kwargs.get(ATTR_HS_COLOR)
temperature = kwargs.get(ATTR_COLOR_TEMP)
brightness = kwargs.get(ATTR_BRIGHTNESS)
characteristics = {}
if hs_color is not None:
characteristics.update(
{
CharacteristicsTypes.HUE: hs_color[0],
CharacteristicsTypes.SATURATION: hs_color[1],
}
)
if brightness is not None:
characteristics[CharacteristicsTypes.BRIGHTNESS] = int(
brightness * 100 / 255
)
if temperature is not None:
characteristics[CharacteristicsTypes.COLOR_TEMPERATURE] = int(temperature)
characteristics[CharacteristicsTypes.ON] = True
await self.async_put_characteristics(characteristics)
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn the specified light off."""
await self.async_put_characteristics({CharacteristicsTypes.ON: False})