Add EntityFeature enum to Light (#69103)

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
pull/69165/head
Franck Nijhof 2022-04-03 05:57:01 +02:00 committed by GitHub
parent 2d37066ce5
commit ea148a1b8e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 37 additions and 24 deletions

View File

@ -16,8 +16,8 @@ from homeassistant.components.light import (
COLOR_MODE_RGBW, COLOR_MODE_RGBW,
COLOR_MODE_RGBWW, COLOR_MODE_RGBWW,
COLOR_MODE_WHITE, COLOR_MODE_WHITE,
SUPPORT_EFFECT,
LightEntity, LightEntity,
LightEntityFeature,
) )
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -149,7 +149,7 @@ class DemoLight(LightEntity):
supported_color_modes = SUPPORT_DEMO supported_color_modes = SUPPORT_DEMO
self._color_modes = supported_color_modes self._color_modes = supported_color_modes
if self._effect_list is not None: if self._effect_list is not None:
self._features |= SUPPORT_EFFECT self._features |= LightEntityFeature.EFFECT
@property @property
def device_info(self) -> DeviceInfo: def device_info(self) -> DeviceInfo:

View File

@ -5,6 +5,7 @@ from collections.abc import Iterable
import csv import csv
import dataclasses import dataclasses
from datetime import timedelta from datetime import timedelta
from enum import IntEnum
import logging import logging
import os import os
from typing import cast, final from typing import cast, final
@ -40,7 +41,17 @@ DATA_PROFILES = "light_profiles"
ENTITY_ID_FORMAT = DOMAIN + ".{}" ENTITY_ID_FORMAT = DOMAIN + ".{}"
# Bitfield of features supported by the light entity
class LightEntityFeature(IntEnum):
"""Supported features of the light entity."""
EFFECT = 4
FLASH = 8
TRANSITION = 32
# These SUPPORT_* constants are deprecated as of Home Assistant 2022.5.
# Please use the LightEntityFeature enum instead.
SUPPORT_BRIGHTNESS = 1 # Deprecated, replaced by color modes SUPPORT_BRIGHTNESS = 1 # Deprecated, replaced by color modes
SUPPORT_COLOR_TEMP = 2 # Deprecated, replaced by color modes SUPPORT_COLOR_TEMP = 2 # Deprecated, replaced by color modes
SUPPORT_EFFECT = 4 SUPPORT_EFFECT = 4
@ -274,9 +285,9 @@ def filter_turn_off_params(light, params):
"""Filter out params not used in turn off or not supported by the light.""" """Filter out params not used in turn off or not supported by the light."""
supported_features = light.supported_features supported_features = light.supported_features
if not supported_features & SUPPORT_FLASH: if not supported_features & LightEntityFeature.FLASH:
params.pop(ATTR_FLASH, None) params.pop(ATTR_FLASH, None)
if not supported_features & SUPPORT_TRANSITION: if not supported_features & LightEntityFeature.TRANSITION:
params.pop(ATTR_TRANSITION, None) params.pop(ATTR_TRANSITION, None)
return {k: v for k, v in params.items() if k in (ATTR_TRANSITION, ATTR_FLASH)} return {k: v for k, v in params.items() if k in (ATTR_TRANSITION, ATTR_FLASH)}
@ -286,11 +297,11 @@ def filter_turn_on_params(light, params):
"""Filter out params not supported by the light.""" """Filter out params not supported by the light."""
supported_features = light.supported_features supported_features = light.supported_features
if not supported_features & SUPPORT_EFFECT: if not supported_features & LightEntityFeature.EFFECT:
params.pop(ATTR_EFFECT, None) params.pop(ATTR_EFFECT, None)
if not supported_features & SUPPORT_FLASH: if not supported_features & LightEntityFeature.FLASH:
params.pop(ATTR_FLASH, None) params.pop(ATTR_FLASH, None)
if not supported_features & SUPPORT_TRANSITION: if not supported_features & LightEntityFeature.TRANSITION:
params.pop(ATTR_TRANSITION, None) params.pop(ATTR_TRANSITION, None)
if not supported_features & SUPPORT_WHITE_VALUE: if not supported_features & SUPPORT_WHITE_VALUE:
params.pop(ATTR_WHITE_VALUE, None) params.pop(ATTR_WHITE_VALUE, None)
@ -831,7 +842,7 @@ class LightEntity(ToggleEntity):
data[ATTR_MIN_MIREDS] = self.min_mireds data[ATTR_MIN_MIREDS] = self.min_mireds
data[ATTR_MAX_MIREDS] = self.max_mireds data[ATTR_MAX_MIREDS] = self.max_mireds
if supported_features & SUPPORT_EFFECT: if supported_features & LightEntityFeature.EFFECT:
data[ATTR_EFFECT_LIST] = self.effect_list data[ATTR_EFFECT_LIST] = self.effect_list
data[ATTR_SUPPORTED_COLOR_MODES] = sorted(supported_color_modes) data[ATTR_SUPPORTED_COLOR_MODES] = sorted(supported_color_modes)
@ -927,7 +938,7 @@ class LightEntity(ToggleEntity):
if self.hs_color is not None: if self.hs_color is not None:
data.update(self._light_internal_convert_color(COLOR_MODE_HS)) data.update(self._light_internal_convert_color(COLOR_MODE_HS))
if supported_features & SUPPORT_EFFECT: if supported_features & LightEntityFeature.EFFECT:
data[ATTR_EFFECT] = self.effect data[ATTR_EFFECT] = self.effect
return {key: val for key, val in data.items() if val is not None} return {key: val for key, val in data.items() if val is not None}

View File

@ -24,9 +24,9 @@ from . import (
ATTR_FLASH, ATTR_FLASH,
DOMAIN, DOMAIN,
FLASH_SHORT, FLASH_SHORT,
SUPPORT_FLASH,
VALID_BRIGHTNESS_PCT, VALID_BRIGHTNESS_PCT,
VALID_FLASH, VALID_FLASH,
LightEntityFeature,
brightness_supported, brightness_supported,
get_supported_color_modes, get_supported_color_modes,
) )
@ -116,7 +116,7 @@ async def async_get_actions(
) )
) )
if supported_features & SUPPORT_FLASH: if supported_features & LightEntityFeature.FLASH:
actions.append({**base_action, CONF_TYPE: TYPE_FLASH}) actions.append({**base_action, CONF_TYPE: TYPE_FLASH})
return actions return actions
@ -144,7 +144,7 @@ async def async_get_action_capabilities(
if brightness_supported(supported_color_modes): if brightness_supported(supported_color_modes):
extra_fields[vol.Optional(ATTR_BRIGHTNESS_PCT)] = VALID_BRIGHTNESS_PCT extra_fields[vol.Optional(ATTR_BRIGHTNESS_PCT)] = VALID_BRIGHTNESS_PCT
if supported_features & SUPPORT_FLASH: if supported_features & LightEntityFeature.FLASH:
extra_fields[vol.Optional(ATTR_FLASH)] = VALID_FLASH extra_fields[vol.Optional(ATTR_FLASH)] = VALID_FLASH
return {"extra_fields": vol.Schema(extra_fields)} if extra_fields else {} return {"extra_fields": vol.Schema(extra_fields)} if extra_fields else {}

View File

@ -9,7 +9,7 @@ from homeassistant.components.light import (
DOMAIN, DOMAIN,
FLASH_LONG, FLASH_LONG,
FLASH_SHORT, FLASH_SHORT,
SUPPORT_FLASH, LightEntityFeature,
) )
from homeassistant.const import CONF_PLATFORM, STATE_OFF, STATE_ON from homeassistant.const import CONF_PLATFORM, STATE_OFF, STATE_ON
from homeassistant.helpers import device_registry from homeassistant.helpers import device_registry
@ -57,7 +57,7 @@ async def test_get_actions(hass, device_reg, entity_reg):
"test", "test",
"5678", "5678",
device_id=device_entry.id, device_id=device_entry.id,
supported_features=SUPPORT_FLASH, supported_features=LightEntityFeature.FLASH,
capabilities={"supported_color_modes": ["brightness"]}, capabilities={"supported_color_modes": ["brightness"]},
) )
expected_actions = [ expected_actions = [
@ -196,7 +196,7 @@ async def test_get_action_capabilities(hass, device_reg, entity_reg):
( (
False, False,
{"turn_on", "toggle", "turn_off", "flash"}, {"turn_on", "toggle", "turn_off", "flash"},
SUPPORT_FLASH, LightEntityFeature.FLASH,
0, 0,
None, None,
{}, {},
@ -215,7 +215,7 @@ async def test_get_action_capabilities(hass, device_reg, entity_reg):
True, True,
{"turn_on", "toggle", "turn_off", "flash"}, {"turn_on", "toggle", "turn_off", "flash"},
0, 0,
SUPPORT_FLASH, LightEntityFeature.FLASH,
None, None,
{}, {},
{ {

View File

@ -120,14 +120,16 @@ async def test_services(hass, mock_light_profiles, enable_custom_integrations):
ent1, ent2, ent3 = platform.ENTITIES ent1, ent2, ent3 = platform.ENTITIES
ent1.supported_color_modes = [light.COLOR_MODE_HS] ent1.supported_color_modes = [light.COLOR_MODE_HS]
ent3.supported_color_modes = [light.COLOR_MODE_HS] ent3.supported_color_modes = [light.COLOR_MODE_HS]
ent1.supported_features = light.SUPPORT_TRANSITION ent1.supported_features = light.LightEntityFeature.TRANSITION
ent2.supported_features = ( ent2.supported_features = (
light.SUPPORT_COLOR light.SUPPORT_COLOR
| light.SUPPORT_EFFECT | light.LightEntityFeature.EFFECT
| light.SUPPORT_TRANSITION | light.LightEntityFeature.TRANSITION
| light.SUPPORT_WHITE_VALUE | light.SUPPORT_WHITE_VALUE
) )
ent3.supported_features = light.SUPPORT_FLASH | light.SUPPORT_TRANSITION ent3.supported_features = (
light.LightEntityFeature.FLASH | light.LightEntityFeature.TRANSITION
)
# Test init # Test init
assert light.is_on(hass, ent1.entity_id) assert light.is_on(hass, ent1.entity_id)
@ -539,7 +541,7 @@ async def test_light_profiles(
ent1, _, _ = platform.ENTITIES ent1, _, _ = platform.ENTITIES
ent1.supported_color_modes = [light.COLOR_MODE_HS] ent1.supported_color_modes = [light.COLOR_MODE_HS]
ent1.supported_features = light.SUPPORT_TRANSITION ent1.supported_features = light.LightEntityFeature.TRANSITION
await hass.services.async_call( await hass.services.async_call(
light.DOMAIN, light.DOMAIN,
@ -576,7 +578,7 @@ async def test_default_profiles_group(
ent, _, _ = platform.ENTITIES ent, _, _ = platform.ENTITIES
ent.supported_color_modes = [light.COLOR_MODE_HS] ent.supported_color_modes = [light.COLOR_MODE_HS]
ent.supported_features = light.SUPPORT_TRANSITION ent.supported_features = light.LightEntityFeature.TRANSITION
await hass.services.async_call( await hass.services.async_call(
light.DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: ent.entity_id}, blocking=True light.DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: ent.entity_id}, blocking=True
) )
@ -683,7 +685,7 @@ async def test_default_profiles_light(
dev = next(filter(lambda x: x.entity_id == "light.ceiling_2", platform.ENTITIES)) dev = next(filter(lambda x: x.entity_id == "light.ceiling_2", platform.ENTITIES))
dev.supported_color_modes = [light.COLOR_MODE_HS] dev.supported_color_modes = [light.COLOR_MODE_HS]
dev.supported_features = light.SUPPORT_TRANSITION dev.supported_features = light.LightEntityFeature.TRANSITION
await hass.services.async_call( await hass.services.async_call(
light.DOMAIN, light.DOMAIN,
SERVICE_TURN_ON, SERVICE_TURN_ON,