Home Assistant Unofficial Reference 2024.12.1
device_trigger.py
Go to the documentation of this file.
1 """Provides device triggers for Shelly."""
2 
3 from __future__ import annotations
4 
5 from typing import Final
6 
7 import voluptuous as vol
8 
10  DEVICE_TRIGGER_BASE_SCHEMA,
11  InvalidDeviceAutomationConfig,
12 )
13 from homeassistant.components.homeassistant.triggers import event as event_trigger
14 from homeassistant.const import (
15  ATTR_DEVICE_ID,
16  CONF_DEVICE_ID,
17  CONF_DOMAIN,
18  CONF_EVENT,
19  CONF_PLATFORM,
20  CONF_TYPE,
21 )
22 from homeassistant.core import CALLBACK_TYPE, HomeAssistant
23 from homeassistant.helpers.trigger import TriggerActionType, TriggerInfo
24 from homeassistant.helpers.typing import ConfigType
25 
26 from .const import (
27  ATTR_CHANNEL,
28  ATTR_CLICK_TYPE,
29  BLOCK_INPUTS_EVENTS_TYPES,
30  CONF_SUBTYPE,
31  DOMAIN,
32  EVENT_SHELLY_CLICK,
33  INPUTS_EVENTS_SUBTYPES,
34  RPC_INPUTS_EVENTS_TYPES,
35  SHBTN_MODELS,
36 )
37 from .coordinator import (
38  get_block_coordinator_by_device_id,
39  get_rpc_coordinator_by_device_id,
40 )
41 from .utils import (
42  get_block_input_triggers,
43  get_rpc_input_triggers,
44  get_shbtn_input_triggers,
45 )
46 
47 TRIGGER_SCHEMA: Final = DEVICE_TRIGGER_BASE_SCHEMA.extend(
48  {
49  vol.Required(CONF_TYPE): vol.In(
50  RPC_INPUTS_EVENTS_TYPES | BLOCK_INPUTS_EVENTS_TYPES
51  ),
52  vol.Required(CONF_SUBTYPE): vol.In(INPUTS_EVENTS_SUBTYPES),
53  }
54 )
55 
56 
58  triggers: list[dict[str, str]],
59  input_triggers: list[tuple[str, str]],
60  device_id: str,
61 ) -> None:
62  """Add trigger to triggers list."""
63  for trigger, subtype in input_triggers:
64  triggers.append(
65  {
66  CONF_PLATFORM: "device",
67  CONF_DEVICE_ID: device_id,
68  CONF_DOMAIN: DOMAIN,
69  CONF_TYPE: trigger,
70  CONF_SUBTYPE: subtype,
71  }
72  )
73 
74 
76  hass: HomeAssistant, config: ConfigType
77 ) -> ConfigType:
78  """Validate config."""
79  config = TRIGGER_SCHEMA(config)
80 
81  # if device is available verify parameters against device capabilities
82  trigger = (config[CONF_TYPE], config[CONF_SUBTYPE])
83 
84  if config[CONF_TYPE] in RPC_INPUTS_EVENTS_TYPES:
85  rpc_coordinator = get_rpc_coordinator_by_device_id(hass, config[CONF_DEVICE_ID])
86  if not rpc_coordinator or not rpc_coordinator.device.initialized:
87  return config
88 
89  input_triggers = get_rpc_input_triggers(rpc_coordinator.device)
90  if trigger in input_triggers:
91  return config
92 
93  elif config[CONF_TYPE] in BLOCK_INPUTS_EVENTS_TYPES:
94  block_coordinator = get_block_coordinator_by_device_id(
95  hass, config[CONF_DEVICE_ID]
96  )
97  if not block_coordinator or not block_coordinator.device.initialized:
98  return config
99 
100  assert block_coordinator.device.blocks
101 
102  for block in block_coordinator.device.blocks:
103  input_triggers = get_block_input_triggers(block_coordinator.device, block)
104  if trigger in input_triggers:
105  return config
106 
108  f"Invalid ({CONF_TYPE},{CONF_SUBTYPE}): {trigger}"
109  )
110 
111 
113  hass: HomeAssistant, device_id: str
114 ) -> list[dict[str, str]]:
115  """List device triggers for Shelly devices."""
116  triggers: list[dict[str, str]] = []
117 
118  if rpc_coordinator := get_rpc_coordinator_by_device_id(hass, device_id):
119  input_triggers = get_rpc_input_triggers(rpc_coordinator.device)
120  append_input_triggers(triggers, input_triggers, device_id)
121  return triggers
122 
123  if block_coordinator := get_block_coordinator_by_device_id(hass, device_id):
124  if block_coordinator.model in SHBTN_MODELS:
125  input_triggers = get_shbtn_input_triggers()
126  append_input_triggers(triggers, input_triggers, device_id)
127  return triggers
128 
129  if not block_coordinator.device.initialized:
130  return triggers
131 
132  assert block_coordinator.device.blocks
133 
134  for block in block_coordinator.device.blocks:
135  input_triggers = get_block_input_triggers(block_coordinator.device, block)
136  append_input_triggers(triggers, input_triggers, device_id)
137 
138  return triggers
139 
140  raise InvalidDeviceAutomationConfig(f"Device not found: {device_id}")
141 
142 
144  hass: HomeAssistant,
145  config: ConfigType,
146  action: TriggerActionType,
147  trigger_info: TriggerInfo,
148 ) -> CALLBACK_TYPE:
149  """Attach a trigger."""
150  event_config = {
151  event_trigger.CONF_PLATFORM: CONF_EVENT,
152  event_trigger.CONF_EVENT_TYPE: EVENT_SHELLY_CLICK,
153  event_trigger.CONF_EVENT_DATA: {
154  ATTR_DEVICE_ID: config[CONF_DEVICE_ID],
155  ATTR_CHANNEL: INPUTS_EVENTS_SUBTYPES[config[CONF_SUBTYPE]],
156  ATTR_CLICK_TYPE: config[CONF_TYPE],
157  },
158  }
159 
160  event_config = event_trigger.TRIGGER_SCHEMA(event_config)
161  return await event_trigger.async_attach_trigger(
162  hass, event_config, action, trigger_info, platform_type="device"
163  )
ShellyRpcCoordinator|None get_rpc_coordinator_by_device_id(HomeAssistant hass, str device_id)
Definition: coordinator.py:830
ShellyBlockCoordinator|None get_block_coordinator_by_device_id(HomeAssistant hass, str device_id)
Definition: coordinator.py:810
list[dict[str, str]] async_get_triggers(HomeAssistant hass, str device_id)
ConfigType async_validate_trigger_config(HomeAssistant hass, ConfigType config)
None append_input_triggers(list[dict[str, str]] triggers, list[tuple[str, str]] input_triggers, str device_id)
CALLBACK_TYPE async_attach_trigger(HomeAssistant hass, ConfigType config, TriggerActionType action, TriggerInfo trigger_info)
list[tuple[str, str]] get_shbtn_input_triggers()
Definition: utils.py:215
list[tuple[str, str]] get_rpc_input_triggers(RpcDevice device)
Definition: utils.py:400
list[tuple[str, str]] get_block_input_triggers(BlockDevice device, Block block)
Definition: utils.py:191