Home Assistant Unofficial Reference 2024.12.1
device_trigger.py
Go to the documentation of this file.
1 """Provides device automations for Netatmo."""
2 
3 from __future__ import annotations
4 
5 import voluptuous as vol
6 
8  DEVICE_TRIGGER_BASE_SCHEMA,
9  InvalidDeviceAutomationConfig,
10 )
11 from homeassistant.components.homeassistant.triggers import event as event_trigger
12 from homeassistant.const import (
13  ATTR_DEVICE_ID,
14  CONF_DEVICE_ID,
15  CONF_DOMAIN,
16  CONF_ENTITY_ID,
17  CONF_PLATFORM,
18  CONF_TYPE,
19 )
20 from homeassistant.core import CALLBACK_TYPE, HomeAssistant
21 from homeassistant.helpers import (
22  config_validation as cv,
23  device_registry as dr,
24  entity_registry as er,
25 )
26 from homeassistant.helpers.trigger import TriggerActionType, TriggerInfo
27 from homeassistant.helpers.typing import ConfigType
28 
29 from .climate import STATE_NETATMO_AWAY, STATE_NETATMO_HG, STATE_NETATMO_SCHEDULE
30 from .const import (
31  CLIMATE_TRIGGERS,
32  DOMAIN,
33  EVENT_TYPE_THERM_MODE,
34  INDOOR_CAMERA_TRIGGERS,
35  NETATMO_EVENT,
36  OUTDOOR_CAMERA_TRIGGERS,
37 )
38 
39 CONF_SUBTYPE = "subtype"
40 
41 DEVICES = {
42  "Smart Indoor Camera": INDOOR_CAMERA_TRIGGERS,
43  "Smart Outdoor Camera": OUTDOOR_CAMERA_TRIGGERS,
44  "Smart Thermostat": CLIMATE_TRIGGERS,
45  "Smart Valve": CLIMATE_TRIGGERS,
46 }
47 
48 SUBTYPES = {
49  EVENT_TYPE_THERM_MODE: [
50  STATE_NETATMO_SCHEDULE,
51  STATE_NETATMO_HG,
52  STATE_NETATMO_AWAY,
53  ]
54 }
55 
56 TRIGGER_TYPES = OUTDOOR_CAMERA_TRIGGERS + INDOOR_CAMERA_TRIGGERS + CLIMATE_TRIGGERS
57 
58 TRIGGER_SCHEMA = DEVICE_TRIGGER_BASE_SCHEMA.extend(
59  {
60  vol.Required(CONF_ENTITY_ID): cv.entity_id_or_uuid,
61  vol.Required(CONF_TYPE): vol.In(TRIGGER_TYPES),
62  vol.Optional(CONF_SUBTYPE): str,
63  }
64 )
65 
66 
68  hass: HomeAssistant, config: ConfigType
69 ) -> ConfigType:
70  """Validate config."""
71  config = TRIGGER_SCHEMA(config)
72 
73  device_registry = dr.async_get(hass)
74  device = device_registry.async_get(config[CONF_DEVICE_ID])
75 
76  if not device or device.model is None:
78  f"Trigger invalid, device with ID {config[CONF_DEVICE_ID]} not found"
79  )
80 
81  trigger = config[CONF_TYPE]
82 
83  if (
84  not device
85  or device.model not in DEVICES
86  or trigger not in DEVICES[device.model]
87  ):
88  raise InvalidDeviceAutomationConfig(f"Unsupported model {device.model}")
89 
90  return config
91 
92 
94  hass: HomeAssistant, device_id: str
95 ) -> list[dict[str, str]]:
96  """List device triggers for Netatmo devices."""
97  registry = er.async_get(hass)
98  device_registry = dr.async_get(hass)
99  triggers: list[dict[str, str]] = []
100 
101  for entry in er.async_entries_for_device(registry, device_id):
102  if (
103  device := device_registry.async_get(device_id)
104  ) is None or device.model is None:
105  continue
106 
107  for trigger in DEVICES.get(device.model, []):
108  if trigger in SUBTYPES:
109  triggers.extend(
110  {
111  CONF_PLATFORM: "device",
112  CONF_DEVICE_ID: device_id,
113  CONF_DOMAIN: DOMAIN,
114  CONF_ENTITY_ID: entry.id,
115  CONF_TYPE: trigger,
116  CONF_SUBTYPE: subtype,
117  }
118  for subtype in SUBTYPES[trigger]
119  )
120  else:
121  triggers.append(
122  {
123  CONF_PLATFORM: "device",
124  CONF_DEVICE_ID: device_id,
125  CONF_DOMAIN: DOMAIN,
126  CONF_ENTITY_ID: entry.id,
127  CONF_TYPE: trigger,
128  }
129  )
130 
131  return triggers
132 
133 
135  hass: HomeAssistant,
136  config: ConfigType,
137  action: TriggerActionType,
138  trigger_info: TriggerInfo,
139 ) -> CALLBACK_TYPE:
140  """Attach a trigger."""
141  device_registry = dr.async_get(hass)
142  device = device_registry.async_get(config[CONF_DEVICE_ID])
143 
144  if not device:
145  return lambda: None
146 
147  if device.model not in DEVICES:
148  return lambda: None
149 
150  event_config = {
151  event_trigger.CONF_PLATFORM: "event",
152  event_trigger.CONF_EVENT_TYPE: NETATMO_EVENT,
153  event_trigger.CONF_EVENT_DATA: {
154  "type": config[CONF_TYPE],
155  ATTR_DEVICE_ID: config[ATTR_DEVICE_ID],
156  },
157  }
158 
159  if config[CONF_TYPE] in SUBTYPES:
160  event_config.update(
161  {event_trigger.CONF_EVENT_DATA: {"data": {"mode": config[CONF_SUBTYPE]}}}
162  )
163 
164  event_config = event_trigger.TRIGGER_SCHEMA(event_config)
165  return await event_trigger.async_attach_trigger(
166  hass, event_config, action, trigger_info, platform_type="device"
167  )
list[dict[str, str]] async_get_triggers(HomeAssistant hass, str device_id)
ConfigType async_validate_trigger_config(HomeAssistant hass, ConfigType config)
CALLBACK_TYPE async_attach_trigger(HomeAssistant hass, ConfigType config, TriggerActionType action, TriggerInfo trigger_info)