Home Assistant Unofficial Reference 2024.12.1
device_trigger.py
Go to the documentation of this file.
1 """Provides device automations for Climate."""
2 
3 from __future__ import annotations
4 
5 import voluptuous as vol
6 
7 from homeassistant.components.device_automation import DEVICE_TRIGGER_BASE_SCHEMA
9  numeric_state as numeric_state_trigger,
10  state as state_trigger,
11 )
12 from homeassistant.const import (
13  CONF_ABOVE,
14  CONF_BELOW,
15  CONF_DEVICE_ID,
16  CONF_DOMAIN,
17  CONF_ENTITY_ID,
18  CONF_FOR,
19  CONF_PLATFORM,
20  CONF_TYPE,
21  PERCENTAGE,
22 )
23 from homeassistant.core import CALLBACK_TYPE, HomeAssistant
24 from homeassistant.helpers import config_validation as cv, entity_registry as er
25 from homeassistant.helpers.trigger import TriggerActionType, TriggerInfo
26 from homeassistant.helpers.typing import ConfigType
27 
28 from . import DOMAIN, const
29 
30 TRIGGER_TYPES = {
31  "current_temperature_changed",
32  "current_humidity_changed",
33  "hvac_mode_changed",
34 }
35 
36 HVAC_MODE_TRIGGER_SCHEMA = DEVICE_TRIGGER_BASE_SCHEMA.extend(
37  {
38  vol.Required(CONF_ENTITY_ID): cv.entity_id_or_uuid,
39  vol.Required(CONF_TYPE): "hvac_mode_changed",
40  vol.Required(state_trigger.CONF_TO): vol.In(const.HVAC_MODES),
41  vol.Optional(CONF_FOR): cv.positive_time_period_dict,
42  }
43 )
44 
45 CURRENT_TRIGGER_SCHEMA = vol.All(
46  DEVICE_TRIGGER_BASE_SCHEMA.extend(
47  {
48  vol.Required(CONF_ENTITY_ID): cv.entity_id_or_uuid,
49  vol.Required(CONF_TYPE): vol.In(
50  ["current_temperature_changed", "current_humidity_changed"]
51  ),
52  vol.Optional(CONF_BELOW): vol.Any(vol.Coerce(float)),
53  vol.Optional(CONF_ABOVE): vol.Any(vol.Coerce(float)),
54  vol.Optional(CONF_FOR): cv.positive_time_period_dict,
55  }
56  ),
57  cv.has_at_least_one_key(CONF_BELOW, CONF_ABOVE),
58 )
59 
60 TRIGGER_SCHEMA = vol.Any(HVAC_MODE_TRIGGER_SCHEMA, CURRENT_TRIGGER_SCHEMA)
61 
62 
64  hass: HomeAssistant, device_id: str
65 ) -> list[dict[str, str]]:
66  """List device triggers for Climate devices."""
67  registry = er.async_get(hass)
68  triggers = []
69 
70  # Get all the integrations entities for this device
71  for entry in er.async_entries_for_device(registry, device_id):
72  if entry.domain != DOMAIN:
73  continue
74 
75  state = hass.states.get(entry.entity_id)
76 
77  # Add triggers for each entity that belongs to this integration
78  base_trigger = {
79  CONF_PLATFORM: "device",
80  CONF_DEVICE_ID: device_id,
81  CONF_DOMAIN: DOMAIN,
82  CONF_ENTITY_ID: entry.id,
83  }
84 
85  triggers.append(
86  {
87  **base_trigger,
88  CONF_TYPE: "hvac_mode_changed",
89  }
90  )
91 
92  if state and const.ATTR_CURRENT_TEMPERATURE in state.attributes:
93  triggers.append(
94  {
95  **base_trigger,
96  CONF_TYPE: "current_temperature_changed",
97  }
98  )
99 
100  if state and const.ATTR_CURRENT_HUMIDITY in state.attributes:
101  triggers.append(
102  {
103  **base_trigger,
104  CONF_TYPE: "current_humidity_changed",
105  }
106  )
107 
108  return triggers
109 
110 
112  hass: HomeAssistant,
113  config: ConfigType,
114  action: TriggerActionType,
115  trigger_info: TriggerInfo,
116 ) -> CALLBACK_TYPE:
117  """Attach a trigger."""
118  if (trigger_type := config[CONF_TYPE]) == "hvac_mode_changed":
119  state_config = {
120  state_trigger.CONF_PLATFORM: "state",
121  state_trigger.CONF_ENTITY_ID: config[CONF_ENTITY_ID],
122  state_trigger.CONF_TO: config[state_trigger.CONF_TO],
123  state_trigger.CONF_FROM: [
124  mode
125  for mode in const.HVAC_MODES
126  if mode != config[state_trigger.CONF_TO]
127  ],
128  }
129  if CONF_FOR in config:
130  state_config[CONF_FOR] = config[CONF_FOR]
131  state_config = await state_trigger.async_validate_trigger_config(
132  hass, state_config
133  )
134  return await state_trigger.async_attach_trigger(
135  hass, state_config, action, trigger_info, platform_type="device"
136  )
137 
138  numeric_state_config = {
139  numeric_state_trigger.CONF_PLATFORM: "numeric_state",
140  numeric_state_trigger.CONF_ENTITY_ID: config[CONF_ENTITY_ID],
141  }
142 
143  if trigger_type == "current_temperature_changed":
144  numeric_state_config[numeric_state_trigger.CONF_VALUE_TEMPLATE] = (
145  "{{ state.attributes.current_temperature }}"
146  )
147  else: # trigger_type == "current_humidity_changed"
148  numeric_state_config[numeric_state_trigger.CONF_VALUE_TEMPLATE] = (
149  "{{ state.attributes.current_humidity }}"
150  )
151 
152  if CONF_ABOVE in config:
153  numeric_state_config[CONF_ABOVE] = config[CONF_ABOVE]
154  if CONF_BELOW in config:
155  numeric_state_config[CONF_BELOW] = config[CONF_BELOW]
156  if CONF_FOR in config:
157  numeric_state_config[CONF_FOR] = config[CONF_FOR]
158 
159  numeric_state_config = await numeric_state_trigger.async_validate_trigger_config(
160  hass, numeric_state_config
161  )
162  return await numeric_state_trigger.async_attach_trigger(
163  hass, numeric_state_config, action, trigger_info, platform_type="device"
164  )
165 
166 
168  hass: HomeAssistant, config: ConfigType
169 ) -> dict[str, vol.Schema]:
170  """List trigger capabilities."""
171  trigger_type = config[CONF_TYPE]
172 
173  if trigger_type == "hvac_action_changed":
174  return {}
175 
176  if trigger_type == "hvac_mode_changed":
177  return {
178  "extra_fields": vol.Schema(
179  {
180  vol.Required(state_trigger.CONF_TO): vol.In(const.HVAC_MODES),
181  vol.Optional(CONF_FOR): cv.positive_time_period_dict,
182  }
183  )
184  }
185 
186  if trigger_type == "current_temperature_changed":
187  unit_of_measurement: str = hass.config.units.temperature_unit
188  else:
189  unit_of_measurement = PERCENTAGE
190 
191  return {
192  "extra_fields": vol.Schema(
193  {
194  vol.Optional(
195  CONF_ABOVE, description={"suffix": unit_of_measurement}
196  ): vol.Coerce(float),
197  vol.Optional(
198  CONF_BELOW, description={"suffix": unit_of_measurement}
199  ): vol.Coerce(float),
200  vol.Optional(CONF_FOR): cv.positive_time_period_dict,
201  }
202  )
203  }
dict[str, vol.Schema] async_get_trigger_capabilities(HomeAssistant hass, ConfigType config)
CALLBACK_TYPE async_attach_trigger(HomeAssistant hass, ConfigType config, TriggerActionType action, TriggerInfo trigger_info)
list[dict[str, str]] async_get_triggers(HomeAssistant hass, str device_id)