Home Assistant Unofficial Reference 2024.12.1
device_trigger.py
Go to the documentation of this file.
1 """Provides device triggers for binary sensors."""
2 
3 import voluptuous as vol
4 
6  CONF_TURNED_OFF,
7  CONF_TURNED_ON,
8  DEVICE_TRIGGER_BASE_SCHEMA,
9 )
10 from homeassistant.components.homeassistant.triggers import state as state_trigger
11 from homeassistant.const import CONF_ENTITY_ID, CONF_FOR, CONF_TYPE
12 from homeassistant.core import CALLBACK_TYPE, HomeAssistant
13 from homeassistant.helpers import config_validation as cv, entity_registry as er
14 from homeassistant.helpers.entity import get_device_class
15 from homeassistant.helpers.trigger import TriggerActionType, TriggerInfo
16 from homeassistant.helpers.typing import ConfigType
17 
18 from . import DOMAIN, BinarySensorDeviceClass
19 
20 DEVICE_CLASS_NONE = "none"
21 
22 CONF_BAT_LOW = "bat_low"
23 CONF_NOT_BAT_LOW = "not_bat_low"
24 CONF_CHARGING = "charging"
25 CONF_NOT_CHARGING = "not_charging"
26 CONF_CO = "co"
27 CONF_NO_CO = "no_co"
28 CONF_COLD = "cold"
29 CONF_NOT_COLD = "not_cold"
30 CONF_CONNECTED = "connected"
31 CONF_NOT_CONNECTED = "not_connected"
32 CONF_GAS = "gas"
33 CONF_NO_GAS = "no_gas"
34 CONF_HOT = "hot"
35 CONF_NOT_HOT = "not_hot"
36 CONF_LIGHT = "light"
37 CONF_NO_LIGHT = "no_light"
38 CONF_LOCKED = "locked"
39 CONF_NOT_LOCKED = "not_locked"
40 CONF_MOIST = "moist"
41 CONF_NOT_MOIST = "not_moist"
42 CONF_MOTION = "motion"
43 CONF_NO_MOTION = "no_motion"
44 CONF_MOVING = "moving"
45 CONF_NOT_MOVING = "not_moving"
46 CONF_OCCUPIED = "occupied"
47 CONF_NOT_OCCUPIED = "not_occupied"
48 CONF_PLUGGED_IN = "plugged_in"
49 CONF_NOT_PLUGGED_IN = "not_plugged_in"
50 CONF_POWERED = "powered"
51 CONF_NOT_POWERED = "not_powered"
52 CONF_PRESENT = "present"
53 CONF_NOT_PRESENT = "not_present"
54 CONF_PROBLEM = "problem"
55 CONF_NO_PROBLEM = "no_problem"
56 CONF_RUNNING = "running"
57 CONF_NOT_RUNNING = "not_running"
58 CONF_UNSAFE = "unsafe"
59 CONF_NOT_UNSAFE = "not_unsafe"
60 CONF_SMOKE = "smoke"
61 CONF_NO_SMOKE = "no_smoke"
62 CONF_SOUND = "sound"
63 CONF_NO_SOUND = "no_sound"
64 CONF_TAMPERED = "tampered"
65 CONF_NOT_TAMPERED = "not_tampered"
66 CONF_UPDATE = "update"
67 CONF_NO_UPDATE = "no_update"
68 CONF_VIBRATION = "vibration"
69 CONF_NO_VIBRATION = "no_vibration"
70 CONF_OPENED = "opened"
71 CONF_NOT_OPENED = "not_opened"
72 
73 
74 ENTITY_TRIGGERS = {
75  BinarySensorDeviceClass.BATTERY: [
76  {CONF_TYPE: CONF_BAT_LOW},
77  {CONF_TYPE: CONF_NOT_BAT_LOW},
78  ],
79  BinarySensorDeviceClass.BATTERY_CHARGING: [
80  {CONF_TYPE: CONF_CHARGING},
81  {CONF_TYPE: CONF_NOT_CHARGING},
82  ],
83  BinarySensorDeviceClass.CO: [
84  {CONF_TYPE: CONF_CO},
85  {CONF_TYPE: CONF_NO_CO},
86  ],
87  BinarySensorDeviceClass.COLD: [
88  {CONF_TYPE: CONF_COLD},
89  {CONF_TYPE: CONF_NOT_COLD},
90  ],
91  BinarySensorDeviceClass.CONNECTIVITY: [
92  {CONF_TYPE: CONF_CONNECTED},
93  {CONF_TYPE: CONF_NOT_CONNECTED},
94  ],
95  BinarySensorDeviceClass.DOOR: [
96  {CONF_TYPE: CONF_OPENED},
97  {CONF_TYPE: CONF_NOT_OPENED},
98  ],
99  BinarySensorDeviceClass.GARAGE_DOOR: [
100  {CONF_TYPE: CONF_OPENED},
101  {CONF_TYPE: CONF_NOT_OPENED},
102  ],
103  BinarySensorDeviceClass.GAS: [
104  {CONF_TYPE: CONF_GAS},
105  {CONF_TYPE: CONF_NO_GAS},
106  ],
107  BinarySensorDeviceClass.HEAT: [
108  {CONF_TYPE: CONF_HOT},
109  {CONF_TYPE: CONF_NOT_HOT},
110  ],
111  BinarySensorDeviceClass.LIGHT: [
112  {CONF_TYPE: CONF_LIGHT},
113  {CONF_TYPE: CONF_NO_LIGHT},
114  ],
115  BinarySensorDeviceClass.LOCK: [
116  {CONF_TYPE: CONF_NOT_LOCKED},
117  {CONF_TYPE: CONF_LOCKED},
118  ],
119  BinarySensorDeviceClass.MOISTURE: [
120  {CONF_TYPE: CONF_MOIST},
121  {CONF_TYPE: CONF_NOT_MOIST},
122  ],
123  BinarySensorDeviceClass.MOTION: [
124  {CONF_TYPE: CONF_MOTION},
125  {CONF_TYPE: CONF_NO_MOTION},
126  ],
127  BinarySensorDeviceClass.MOVING: [
128  {CONF_TYPE: CONF_MOVING},
129  {CONF_TYPE: CONF_NOT_MOVING},
130  ],
131  BinarySensorDeviceClass.OCCUPANCY: [
132  {CONF_TYPE: CONF_OCCUPIED},
133  {CONF_TYPE: CONF_NOT_OCCUPIED},
134  ],
135  BinarySensorDeviceClass.OPENING: [
136  {CONF_TYPE: CONF_OPENED},
137  {CONF_TYPE: CONF_NOT_OPENED},
138  ],
139  BinarySensorDeviceClass.PLUG: [
140  {CONF_TYPE: CONF_PLUGGED_IN},
141  {CONF_TYPE: CONF_NOT_PLUGGED_IN},
142  ],
143  BinarySensorDeviceClass.POWER: [
144  {CONF_TYPE: CONF_POWERED},
145  {CONF_TYPE: CONF_NOT_POWERED},
146  ],
147  BinarySensorDeviceClass.PRESENCE: [
148  {CONF_TYPE: CONF_PRESENT},
149  {CONF_TYPE: CONF_NOT_PRESENT},
150  ],
151  BinarySensorDeviceClass.PROBLEM: [
152  {CONF_TYPE: CONF_PROBLEM},
153  {CONF_TYPE: CONF_NO_PROBLEM},
154  ],
155  BinarySensorDeviceClass.RUNNING: [
156  {CONF_TYPE: CONF_RUNNING},
157  {CONF_TYPE: CONF_NOT_RUNNING},
158  ],
159  BinarySensorDeviceClass.SAFETY: [
160  {CONF_TYPE: CONF_UNSAFE},
161  {CONF_TYPE: CONF_NOT_UNSAFE},
162  ],
163  BinarySensorDeviceClass.SMOKE: [
164  {CONF_TYPE: CONF_SMOKE},
165  {CONF_TYPE: CONF_NO_SMOKE},
166  ],
167  BinarySensorDeviceClass.SOUND: [
168  {CONF_TYPE: CONF_SOUND},
169  {CONF_TYPE: CONF_NO_SOUND},
170  ],
171  BinarySensorDeviceClass.UPDATE: [
172  {CONF_TYPE: CONF_UPDATE},
173  {CONF_TYPE: CONF_NO_UPDATE},
174  ],
175  BinarySensorDeviceClass.TAMPER: [
176  {CONF_TYPE: CONF_TAMPERED},
177  {CONF_TYPE: CONF_NOT_TAMPERED},
178  ],
179  BinarySensorDeviceClass.VIBRATION: [
180  {CONF_TYPE: CONF_VIBRATION},
181  {CONF_TYPE: CONF_NO_VIBRATION},
182  ],
183  BinarySensorDeviceClass.WINDOW: [
184  {CONF_TYPE: CONF_OPENED},
185  {CONF_TYPE: CONF_NOT_OPENED},
186  ],
187  DEVICE_CLASS_NONE: [
188  {CONF_TYPE: CONF_TURNED_ON},
189  {CONF_TYPE: CONF_TURNED_OFF},
190  ],
191 }
192 
193 TURNED_ON = [trigger[0][CONF_TYPE] for trigger in ENTITY_TRIGGERS.values()]
194 TURNED_OFF = [trigger[1][CONF_TYPE] for trigger in ENTITY_TRIGGERS.values()]
195 
196 
197 TRIGGER_SCHEMA = DEVICE_TRIGGER_BASE_SCHEMA.extend(
198  {
199  vol.Required(CONF_ENTITY_ID): cv.entity_id_or_uuid,
200  vol.Required(CONF_TYPE): vol.In(TURNED_OFF + TURNED_ON),
201  vol.Optional(CONF_FOR): cv.positive_time_period_dict,
202  }
203 )
204 
205 
207  hass: HomeAssistant,
208  config: ConfigType,
209  action: TriggerActionType,
210  trigger_info: TriggerInfo,
211 ) -> CALLBACK_TYPE:
212  """Listen for state changes based on configuration."""
213  trigger_type = config[CONF_TYPE]
214  if trigger_type in TURNED_ON:
215  to_state = "on"
216  else:
217  to_state = "off"
218 
219  state_config = {
220  state_trigger.CONF_PLATFORM: "state",
221  state_trigger.CONF_ENTITY_ID: config[CONF_ENTITY_ID],
222  state_trigger.CONF_TO: to_state,
223  }
224  if CONF_FOR in config:
225  state_config[CONF_FOR] = config[CONF_FOR]
226 
227  state_config = await state_trigger.async_validate_trigger_config(hass, state_config)
228  return await state_trigger.async_attach_trigger(
229  hass, state_config, action, trigger_info, platform_type="device"
230  )
231 
232 
234  hass: HomeAssistant, device_id: str
235 ) -> list[dict[str, str]]:
236  """List device triggers."""
237  triggers: list[dict[str, str]] = []
238  entity_registry = er.async_get(hass)
239 
240  entries = [
241  entry
242  for entry in er.async_entries_for_device(entity_registry, device_id)
243  if entry.domain == DOMAIN
244  ]
245 
246  for entry in entries:
247  device_class = get_device_class(hass, entry.entity_id) or DEVICE_CLASS_NONE
248 
249  templates = ENTITY_TRIGGERS.get(
250  device_class, ENTITY_TRIGGERS[DEVICE_CLASS_NONE]
251  )
252 
253  triggers.extend(
254  {
255  **automation,
256  "platform": "device",
257  "device_id": device_id,
258  "entity_id": entry.id,
259  "domain": DOMAIN,
260  }
261  for automation in templates
262  )
263 
264  return triggers
265 
266 
268  hass: HomeAssistant, config: ConfigType
269 ) -> dict[str, vol.Schema]:
270  """List trigger capabilities."""
271  return {
272  "extra_fields": vol.Schema(
273  {vol.Optional(CONF_FOR): cv.positive_time_period_dict}
274  )
275  }
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)
str|None get_device_class(HomeAssistant hass, str entity_id)
Definition: entity.py:154