174 lines
5.9 KiB
Python
174 lines
5.9 KiB
Python
"""Matter light."""
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
from functools import partial
|
|
from typing import Any
|
|
|
|
from chip.clusters import Objects as clusters
|
|
from matter_server.common.models import device_types
|
|
|
|
from homeassistant.components.light import (
|
|
ATTR_BRIGHTNESS,
|
|
ColorMode,
|
|
LightEntity,
|
|
LightEntityDescription,
|
|
)
|
|
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 .entity import MatterEntity, MatterEntityDescriptionBaseClass
|
|
from .helpers import get_matter
|
|
from .util import renormalize
|
|
|
|
|
|
async def async_setup_entry(
|
|
hass: HomeAssistant,
|
|
config_entry: ConfigEntry,
|
|
async_add_entities: AddEntitiesCallback,
|
|
) -> None:
|
|
"""Set up Matter Light from Config Entry."""
|
|
matter = get_matter(hass)
|
|
matter.register_platform_handler(Platform.LIGHT, async_add_entities)
|
|
|
|
|
|
class MatterLight(MatterEntity, LightEntity):
|
|
"""Representation of a Matter light."""
|
|
|
|
entity_description: MatterLightEntityDescription
|
|
|
|
def _supports_brightness(self) -> bool:
|
|
"""Return if device supports brightness."""
|
|
return (
|
|
clusters.LevelControl.Attributes.CurrentLevel
|
|
in self.entity_description.subscribe_attributes
|
|
)
|
|
|
|
async def async_turn_on(self, **kwargs: Any) -> None:
|
|
"""Turn light on."""
|
|
if ATTR_BRIGHTNESS not in kwargs or not self._supports_brightness():
|
|
await self.matter_client.send_device_command(
|
|
node_id=self._device_type_instance.node.node_id,
|
|
endpoint=self._device_type_instance.endpoint,
|
|
command=clusters.OnOff.Commands.On(),
|
|
)
|
|
return
|
|
|
|
level_control = self._device_type_instance.get_cluster(clusters.LevelControl)
|
|
# We check above that the device supports brightness, ie level control.
|
|
assert level_control is not None
|
|
|
|
level = round(
|
|
renormalize(
|
|
kwargs[ATTR_BRIGHTNESS],
|
|
(0, 255),
|
|
(level_control.minLevel, level_control.maxLevel),
|
|
)
|
|
)
|
|
|
|
await self.matter_client.send_device_command(
|
|
node_id=self._device_type_instance.node.node_id,
|
|
endpoint=self._device_type_instance.endpoint,
|
|
command=clusters.LevelControl.Commands.MoveToLevelWithOnOff(
|
|
level=level,
|
|
# It's required in TLV. We don't implement transition time yet.
|
|
transitionTime=0,
|
|
),
|
|
)
|
|
|
|
async def async_turn_off(self, **kwargs: Any) -> None:
|
|
"""Turn light off."""
|
|
await self.matter_client.send_device_command(
|
|
node_id=self._device_type_instance.node.node_id,
|
|
endpoint=self._device_type_instance.endpoint,
|
|
command=clusters.OnOff.Commands.Off(),
|
|
)
|
|
|
|
@callback
|
|
def _update_from_device(self) -> None:
|
|
"""Update from device."""
|
|
supports_brigthness = self._supports_brightness()
|
|
|
|
if self._attr_supported_color_modes is None and supports_brigthness:
|
|
self._attr_supported_color_modes = {ColorMode.BRIGHTNESS}
|
|
|
|
if attr := self.get_matter_attribute(clusters.OnOff.Attributes.OnOff):
|
|
self._attr_is_on = attr.value
|
|
|
|
if supports_brigthness:
|
|
level_control = self._device_type_instance.get_cluster(
|
|
clusters.LevelControl
|
|
)
|
|
# We check above that the device supports brightness, ie level control.
|
|
assert level_control is not None
|
|
|
|
# Convert brightness to Home Assistant = 0..255
|
|
self._attr_brightness = round(
|
|
renormalize(
|
|
level_control.currentLevel,
|
|
(level_control.minLevel, level_control.maxLevel),
|
|
(0, 255),
|
|
)
|
|
)
|
|
|
|
|
|
@dataclass
|
|
class MatterLightEntityDescription(
|
|
LightEntityDescription,
|
|
MatterEntityDescriptionBaseClass,
|
|
):
|
|
"""Matter light entity description."""
|
|
|
|
|
|
# You can't set default values on inherited data classes
|
|
MatterLightEntityDescriptionFactory = partial(
|
|
MatterLightEntityDescription, entity_cls=MatterLight
|
|
)
|
|
|
|
# Mapping of a Matter Device type to Light Entity Description.
|
|
# A Matter device type (instance) can consist of multiple attributes.
|
|
# For example a Color Light which has an attribute to control brightness
|
|
# but also for color.
|
|
|
|
DEVICE_ENTITY: dict[
|
|
type[device_types.DeviceType],
|
|
MatterEntityDescriptionBaseClass | list[MatterEntityDescriptionBaseClass],
|
|
] = {
|
|
device_types.OnOffLight: MatterLightEntityDescriptionFactory(
|
|
key=device_types.OnOffLight,
|
|
subscribe_attributes=(clusters.OnOff.Attributes.OnOff,),
|
|
),
|
|
device_types.DimmableLight: MatterLightEntityDescriptionFactory(
|
|
key=device_types.DimmableLight,
|
|
subscribe_attributes=(
|
|
clusters.OnOff.Attributes.OnOff,
|
|
clusters.LevelControl.Attributes.CurrentLevel,
|
|
),
|
|
),
|
|
device_types.DimmablePlugInUnit: MatterLightEntityDescriptionFactory(
|
|
key=device_types.DimmablePlugInUnit,
|
|
subscribe_attributes=(
|
|
clusters.OnOff.Attributes.OnOff,
|
|
clusters.LevelControl.Attributes.CurrentLevel,
|
|
),
|
|
),
|
|
device_types.ColorTemperatureLight: MatterLightEntityDescriptionFactory(
|
|
key=device_types.ColorTemperatureLight,
|
|
subscribe_attributes=(
|
|
clusters.OnOff.Attributes.OnOff,
|
|
clusters.LevelControl.Attributes.CurrentLevel,
|
|
clusters.ColorControl,
|
|
),
|
|
),
|
|
device_types.ExtendedColorLight: MatterLightEntityDescriptionFactory(
|
|
key=device_types.ExtendedColorLight,
|
|
subscribe_attributes=(
|
|
clusters.OnOff.Attributes.OnOff,
|
|
clusters.LevelControl.Attributes.CurrentLevel,
|
|
clusters.ColorControl,
|
|
),
|
|
),
|
|
}
|