Home Assistant Unofficial Reference 2024.12.1
device_action.py
Go to the documentation of this file.
1 """Provides device actions for lights."""
2 
3 from __future__ import annotations
4 
5 import voluptuous as vol
6 
8  async_get_entity_registry_entry_or_raise,
9  async_validate_entity_schema,
10  toggle_entity,
11 )
12 from homeassistant.const import (
13  ATTR_ENTITY_ID,
14  CONF_DEVICE_ID,
15  CONF_DOMAIN,
16  CONF_ENTITY_ID,
17  CONF_TYPE,
18  SERVICE_TURN_ON,
19 )
20 from homeassistant.core import Context, HomeAssistant
21 from homeassistant.exceptions import HomeAssistantError
22 from homeassistant.helpers import config_validation as cv, entity_registry as er
23 from homeassistant.helpers.entity import get_supported_features
24 from homeassistant.helpers.typing import ConfigType, TemplateVarsType, VolDictType
25 
26 from . import (
27  ATTR_BRIGHTNESS_PCT,
28  ATTR_BRIGHTNESS_STEP_PCT,
29  ATTR_FLASH,
30  DOMAIN,
31  FLASH_SHORT,
32  VALID_BRIGHTNESS_PCT,
33  VALID_FLASH,
34  LightEntityFeature,
35  brightness_supported,
36  get_supported_color_modes,
37 )
38 
39 # mypy: disallow-any-generics
40 
41 TYPE_BRIGHTNESS_INCREASE = "brightness_increase"
42 TYPE_BRIGHTNESS_DECREASE = "brightness_decrease"
43 TYPE_FLASH = "flash"
44 
45 _ACTION_SCHEMA = cv.DEVICE_ACTION_BASE_SCHEMA.extend(
46  {
47  vol.Required(ATTR_ENTITY_ID): cv.entity_id_or_uuid,
48  vol.Required(CONF_DOMAIN): DOMAIN,
49  vol.Required(CONF_TYPE): vol.In(
50  [
51  *toggle_entity.DEVICE_ACTION_TYPES,
52  TYPE_BRIGHTNESS_INCREASE,
53  TYPE_BRIGHTNESS_DECREASE,
54  TYPE_FLASH,
55  ]
56  ),
57  vol.Optional(ATTR_BRIGHTNESS_PCT): VALID_BRIGHTNESS_PCT,
58  vol.Optional(ATTR_FLASH): VALID_FLASH,
59  }
60 )
61 
62 
64  hass: HomeAssistant, config: ConfigType
65 ) -> ConfigType:
66  """Validate config."""
67  return async_validate_entity_schema(hass, config, _ACTION_SCHEMA)
68 
69 
71  hass: HomeAssistant,
72  config: ConfigType,
73  variables: TemplateVarsType,
74  context: Context | None,
75 ) -> None:
76  """Change state based on configuration."""
77  if (
78  config[CONF_TYPE] in toggle_entity.DEVICE_ACTION_TYPES
79  and config[CONF_TYPE] != toggle_entity.CONF_TURN_ON
80  ):
81  await toggle_entity.async_call_action_from_config(
82  hass, config, variables, context, DOMAIN
83  )
84  return
85 
86  data = {ATTR_ENTITY_ID: config[ATTR_ENTITY_ID]}
87 
88  if config[CONF_TYPE] == TYPE_BRIGHTNESS_INCREASE:
89  data[ATTR_BRIGHTNESS_STEP_PCT] = 10
90  elif config[CONF_TYPE] == TYPE_BRIGHTNESS_DECREASE:
91  data[ATTR_BRIGHTNESS_STEP_PCT] = -10
92  elif ATTR_BRIGHTNESS_PCT in config:
93  data[ATTR_BRIGHTNESS_PCT] = config[ATTR_BRIGHTNESS_PCT]
94 
95  if config[CONF_TYPE] == TYPE_FLASH:
96  data[ATTR_FLASH] = config.get(ATTR_FLASH, FLASH_SHORT)
97 
98  await hass.services.async_call(
99  DOMAIN, SERVICE_TURN_ON, data, blocking=True, context=context
100  )
101 
102 
104  hass: HomeAssistant, device_id: str
105 ) -> list[dict[str, str]]:
106  """List device actions."""
107  actions = await toggle_entity.async_get_actions(hass, device_id, DOMAIN)
108 
109  entity_registry = er.async_get(hass)
110 
111  for entry in er.async_entries_for_device(entity_registry, device_id):
112  if entry.domain != DOMAIN:
113  continue
114 
115  supported_color_modes = get_supported_color_modes(hass, entry.entity_id)
116  supported_features = get_supported_features(hass, entry.entity_id)
117 
118  base_action = {
119  CONF_DEVICE_ID: device_id,
120  CONF_DOMAIN: DOMAIN,
121  CONF_ENTITY_ID: entry.id,
122  }
123 
124  if brightness_supported(supported_color_modes):
125  actions.extend(
126  (
127  {**base_action, CONF_TYPE: TYPE_BRIGHTNESS_INCREASE},
128  {**base_action, CONF_TYPE: TYPE_BRIGHTNESS_DECREASE},
129  )
130  )
131 
132  if supported_features & LightEntityFeature.FLASH:
133  actions.append({**base_action, CONF_TYPE: TYPE_FLASH})
134 
135  return actions
136 
137 
139  hass: HomeAssistant, config: ConfigType
140 ) -> dict[str, vol.Schema]:
141  """List action capabilities."""
142  if config[CONF_TYPE] != toggle_entity.CONF_TURN_ON:
143  return {}
144 
145  try:
146  entry = async_get_entity_registry_entry_or_raise(hass, config[CONF_ENTITY_ID])
147  supported_color_modes = get_supported_color_modes(hass, entry.entity_id)
148  supported_features = get_supported_features(hass, entry.entity_id)
149  except HomeAssistantError:
150  supported_color_modes = None
151  supported_features = 0
152 
153  extra_fields: VolDictType = {}
154 
155  if brightness_supported(supported_color_modes):
156  extra_fields[vol.Optional(ATTR_BRIGHTNESS_PCT)] = VALID_BRIGHTNESS_PCT
157 
158  if supported_features & LightEntityFeature.FLASH:
159  extra_fields[vol.Optional(ATTR_FLASH)] = VALID_FLASH
160 
161  return {"extra_fields": vol.Schema(extra_fields)} if extra_fields else {}
er.RegistryEntry async_get_entity_registry_entry_or_raise(HomeAssistant hass, str entity_registry_id)
Definition: __init__.py:332
ConfigType async_validate_entity_schema(HomeAssistant hass, ConfigType config, VolSchemaType schema)
Definition: __init__.py:344
dict[str, vol.Schema] async_get_action_capabilities(HomeAssistant hass, ConfigType config)
None async_call_action_from_config(HomeAssistant hass, ConfigType config, TemplateVarsType variables, Context|None context)
list[dict[str, str]] async_get_actions(HomeAssistant hass, str device_id)
ConfigType async_validate_action_config(HomeAssistant hass, ConfigType config)
set[str]|None get_supported_color_modes(HomeAssistant hass, str entity_id)
Definition: __init__.py:176
bool brightness_supported(Iterable[ColorMode|str]|None color_modes)
Definition: __init__.py:155
int get_supported_features(HomeAssistant hass, str entity_id)
Definition: entity.py:169