Home Assistant Unofficial Reference 2024.12.1
time_pattern.py
Go to the documentation of this file.
1 """Offer time listening automation rules."""
2 
3 from __future__ import annotations
4 
5 from datetime import datetime
6 from typing import Any
7 
8 import voluptuous as vol
9 
10 from homeassistant.const import CONF_PLATFORM
11 from homeassistant.core import CALLBACK_TYPE, HassJob, HomeAssistant, callback
12 from homeassistant.helpers import config_validation as cv
13 from homeassistant.helpers.event import async_track_time_change
14 from homeassistant.helpers.trigger import TriggerActionType, TriggerInfo
15 from homeassistant.helpers.typing import ConfigType
16 
17 CONF_HOURS = "hours"
18 CONF_MINUTES = "minutes"
19 CONF_SECONDS = "seconds"
20 
21 
23  """Validate a time pattern value.
24 
25  :raises Invalid: If the value has a wrong format or is outside the range.
26  """
27 
28  def __init__(self, maximum: int) -> None:
29  """Initialize time pattern."""
30  self.maximummaximum = maximum
31 
32  def __call__(self, value: Any) -> str | int:
33  """Validate input."""
34  try:
35  if value == "*":
36  return value # type: ignore[no-any-return]
37 
38  if isinstance(value, str) and value.startswith("/"):
39  number = int(value[1:])
40  else:
41  value = number = int(value)
42 
43  if not (0 <= number <= self.maximummaximum):
44  raise vol.Invalid(f"must be a value between 0 and {self.maximum}")
45  except ValueError as err:
46  raise vol.Invalid("invalid time_pattern value") from err
47 
48  return value # type: ignore[no-any-return]
49 
50 
51 TRIGGER_SCHEMA = vol.All(
52  cv.TRIGGER_BASE_SCHEMA.extend(
53  {
54  vol.Required(CONF_PLATFORM): "time_pattern",
55  CONF_HOURS: TimePattern(maximum=23),
56  CONF_MINUTES: TimePattern(maximum=59),
57  CONF_SECONDS: TimePattern(maximum=59),
58  }
59  ),
60  cv.has_at_least_one_key(CONF_HOURS, CONF_MINUTES, CONF_SECONDS),
61 )
62 
63 
65  hass: HomeAssistant,
66  config: ConfigType,
67  action: TriggerActionType,
68  trigger_info: TriggerInfo,
69 ) -> CALLBACK_TYPE:
70  """Listen for state changes based on configuration."""
71  trigger_data = trigger_info["trigger_data"]
72  hours = config.get(CONF_HOURS)
73  minutes = config.get(CONF_MINUTES)
74  seconds = config.get(CONF_SECONDS)
75  job = HassJob(action, f"time pattern trigger {trigger_info}")
76 
77  # If larger units are specified, default the smaller units to zero
78  if minutes is None and hours is not None:
79  minutes = 0
80  if seconds is None and minutes is not None:
81  seconds = 0
82 
83  @callback
84  def time_automation_listener(now: datetime) -> None:
85  """Listen for time changes and calls action."""
86  hass.async_run_hass_job(
87  job,
88  {
89  "trigger": {
90  **trigger_data,
91  "platform": "time_pattern",
92  "now": now,
93  "description": "time pattern",
94  }
95  },
96  )
97 
99  hass, time_automation_listener, hour=hours, minute=minutes, second=seconds
100  )
CALLBACK_TYPE async_attach_trigger(HomeAssistant hass, ConfigType config, TriggerActionType action, TriggerInfo trigger_info)
Definition: time_pattern.py:69
CALLBACK_TYPE async_track_time_change(HomeAssistant hass, Callable[[datetime], Coroutine[Any, Any, None]|None] action, Any|None hour=None, Any|None minute=None, Any|None second=None)
Definition: event.py:1904