Home Assistant Unofficial Reference 2024.12.1
type_triggers.py
Go to the documentation of this file.
1 """Class to hold all sensor accessories."""
2 
3 from __future__ import annotations
4 
5 import logging
6 from typing import Any
7 
8 from pyhap.const import CATEGORY_SENSOR
9 from pyhap.util import callback as pyhap_callback
10 
11 from homeassistant.core import CALLBACK_TYPE, Context, callback
12 from homeassistant.helpers import entity_registry as er
13 from homeassistant.helpers.trigger import async_initialize_triggers
14 
15 from .accessories import TYPES, HomeAccessory
16 from .aidmanager import get_system_unique_id
17 from .const import (
18  CHAR_NAME,
19  CHAR_PROGRAMMABLE_SWITCH_EVENT,
20  CHAR_SERVICE_LABEL_INDEX,
21  CHAR_SERVICE_LABEL_NAMESPACE,
22  SERV_SERVICE_LABEL,
23  SERV_STATELESS_PROGRAMMABLE_SWITCH,
24 )
25 from .util import cleanup_name_for_homekit
26 
27 _LOGGER = logging.getLogger(__name__)
28 
29 
30 @TYPES.register("DeviceTriggerAccessory")
32  """Generate a Programmable switch."""
33 
34  def __init__(
35  self,
36  *args: Any,
37  device_triggers: list[dict[str, Any]] | None = None,
38  device_id: str | None = None,
39  ) -> None:
40  """Initialize a Programmable switch accessory object."""
41  super().__init__(*args, category=CATEGORY_SENSOR, device_id=device_id)
42  assert device_triggers is not None
43  self._device_triggers_device_triggers = device_triggers
44  self._remove_triggers_remove_triggers: CALLBACK_TYPE | None = None
45  self.triggerstriggers = []
46  assert device_triggers is not None
47  ent_reg = er.async_get(self.hasshass)
48  for idx, trigger in enumerate(device_triggers):
49  type_: str = trigger["type"]
50  subtype: str | None = trigger.get("subtype")
51  unique_id = f'{type_}-{subtype or ""}'
52  entity_id: str | None = None
53  if (entity_id_or_uuid := trigger.get("entity_id")) and (
54  entry := ent_reg.async_get(entity_id_or_uuid)
55  ):
56  unique_id += (
57  f"-entity_unique_id:{get_system_unique_id(entry, entry.unique_id)}"
58  )
59  entity_id = entry.entity_id
60  trigger_name_parts = []
61  if entity_id and (state := self.hasshass.states.get(entity_id)):
62  trigger_name_parts.append(state.name)
63  trigger_name_parts.append(type_.replace("_", " ").title())
64  if subtype:
65  trigger_name_parts.append(subtype.replace("_", " ").title())
66  trigger_name = cleanup_name_for_homekit(" ".join(trigger_name_parts))
67  serv_stateless_switch = self.add_preload_service(
68  SERV_STATELESS_PROGRAMMABLE_SWITCH,
69  [CHAR_NAME, CHAR_SERVICE_LABEL_INDEX],
70  unique_id=unique_id,
71  )
72  self.triggerstriggers.append(
73  serv_stateless_switch.configure_char(
74  CHAR_PROGRAMMABLE_SWITCH_EVENT,
75  value=0,
76  valid_values={"Trigger": 0},
77  )
78  )
79  serv_stateless_switch.configure_char(CHAR_NAME, value=trigger_name)
80  serv_stateless_switch.configure_char(
81  CHAR_SERVICE_LABEL_INDEX, value=idx + 1
82  )
83  serv_service_label = self.add_preload_service(
84  SERV_SERVICE_LABEL, unique_id=unique_id
85  )
86  serv_service_label.configure_char(CHAR_SERVICE_LABEL_NAMESPACE, value=1)
87  serv_stateless_switch.add_linked_service(serv_service_label)
88 
89  @callback
90  def _remove_triggers_if_configured(self) -> None:
91  if self._remove_triggers_remove_triggers:
92  self._remove_triggers_remove_triggers()
93  self._remove_triggers_remove_triggers = None
94 
95  async def async_attach(self) -> None:
96  """Start the accessory."""
97  self._remove_triggers_if_configured_remove_triggers_if_configured()
98  self._remove_triggers_remove_triggers = await async_initialize_triggers(
99  self.hasshass,
100  self._device_triggers_device_triggers,
101  self.async_triggerasync_trigger,
102  "homekit",
103  self.display_name,
104  _LOGGER.log,
105  )
106 
107  @pyhap_callback # type: ignore[misc]
108  @callback
109  def run(self) -> None:
110  """Run the accessory."""
111  # Triggers have not entities so we do not call super().run()
112 
113  async def async_trigger(
114  self,
115  run_variables: dict[str, Any],
116  context: Context | None = None,
117  skip_condition: bool = False,
118  ) -> None:
119  """Trigger button press.
120 
121  This method is a coroutine.
122  """
123  reason = ""
124  if "trigger" in run_variables and "description" in run_variables["trigger"]:
125  reason = f' by {run_variables["trigger"]["description"]}'
126  _LOGGER.debug("Button triggered%s - %s", reason, run_variables)
127  idx = int(run_variables["trigger"]["idx"])
128  self.triggers[idx].set_value(0)
129 
130  @callback
131  def async_stop(self) -> None:
132  """Handle accessory driver stop event."""
133  self._remove_triggers_if_configured_remove_triggers_if_configured()
134  super().async_stop()
135 
136  @property
137  def available(self) -> bool:
138  """Return available."""
139  return True
None async_trigger(self, dict[str, Any] run_variables, Context|None context=None, bool skip_condition=False)
None __init__(self, *Any args, list[dict[str, Any]]|None device_triggers=None, str|None device_id=None)
CALLBACK_TYPE|None async_initialize_triggers(HomeAssistant hass, list[ConfigType] trigger_config, Callable action, str domain, str name, Callable log_cb, bool home_assistant_start=False, TemplateVarsType variables=None)
Definition: trigger.py:311