Home Assistant Unofficial Reference 2024.12.1
notify.py
Go to the documentation of this file.
1 """Support for iOS push notifications."""
2 
3 from __future__ import annotations
4 
5 from http import HTTPStatus
6 import logging
7 from typing import Any
8 
9 import requests
10 
12  ATTR_DATA,
13  ATTR_MESSAGE,
14  ATTR_TARGET,
15  ATTR_TITLE,
16  ATTR_TITLE_DEFAULT,
17  BaseNotificationService,
18 )
19 from homeassistant.core import HomeAssistant
20 from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
21 import homeassistant.util.dt as dt_util
22 
23 from . import device_name_for_push_id, devices_with_push, enabled_push_ids
24 
25 _LOGGER = logging.getLogger(__name__)
26 
27 PUSH_URL = "https://ios-push.home-assistant.io/push"
28 
29 
31  hass: HomeAssistant, target: str, resp: dict[str, Any], level: int = 20
32 ) -> None:
33  """Output rate limit log line at given level."""
34  rate_limits = resp["rateLimits"]
35  resetsAt = dt_util.parse_datetime(rate_limits["resetsAt"])
36  resetsAtTime = resetsAt - dt_util.utcnow() if resetsAt is not None else "---"
37  rate_limit_msg = (
38  "iOS push notification rate limits for %s: "
39  "%d sent, %d allowed, %d errors, "
40  "resets in %s"
41  )
42  _LOGGER.log(
43  level,
44  rate_limit_msg,
45  device_name_for_push_id(hass, target),
46  rate_limits["successful"],
47  rate_limits["maximum"],
48  rate_limits["errors"],
49  str(resetsAtTime).split(".", maxsplit=1)[0],
50  )
51 
52 
54  hass: HomeAssistant,
55  config: ConfigType,
56  discovery_info: DiscoveryInfoType | None = None,
57 ) -> iOSNotificationService | None:
58  """Get the iOS notification service."""
59  if "ios.notify" not in hass.config.components:
60  # Need this to enable requirements checking in the app.
61  hass.config.components.add("ios.notify")
62 
63  if not devices_with_push(hass):
64  return None
65 
66  return iOSNotificationService()
67 
68 
69 class iOSNotificationService(BaseNotificationService):
70  """Implement the notification service for iOS."""
71 
72  def __init__(self) -> None:
73  """Initialize the service."""
74 
75  @property
76  def targets(self) -> dict[str, str]:
77  """Return a dictionary of registered targets."""
78  return devices_with_push(self.hass)
79 
80  def send_message(self, message: str = "", **kwargs: Any) -> None:
81  """Send a message to the Lambda APNS gateway."""
82  data: dict[str, Any] = {ATTR_MESSAGE: message}
83 
84  # Remove default title from notifications.
85  if (
86  kwargs.get(ATTR_TITLE) is not None
87  and kwargs.get(ATTR_TITLE) != ATTR_TITLE_DEFAULT
88  ):
89  data[ATTR_TITLE] = kwargs.get(ATTR_TITLE)
90 
91  if not (targets := kwargs.get(ATTR_TARGET)):
92  targets = enabled_push_ids(self.hass)
93 
94  if kwargs.get(ATTR_DATA) is not None:
95  data[ATTR_DATA] = kwargs.get(ATTR_DATA)
96 
97  for target in targets:
98  if target not in enabled_push_ids(self.hass):
99  _LOGGER.error("The target (%s) does not exist in .ios.conf", targets)
100  return
101 
102  data[ATTR_TARGET] = target
103 
104  req = requests.post(PUSH_URL, json=data, timeout=10)
105 
106  if req.status_code != HTTPStatus.CREATED:
107  fallback_error = req.json().get("errorMessage", "Unknown error")
108  fallback_message = (
109  f"Internal server error, please try again later: {fallback_error}"
110  )
111  message = req.json().get("message", fallback_message)
112  if req.status_code == HTTPStatus.TOO_MANY_REQUESTS:
113  _LOGGER.warning(message)
114  log_rate_limits(self.hass, target, req.json(), 30)
115  else:
116  _LOGGER.error(message)
117  else:
118  log_rate_limits(self.hass, target, req.json())
None send_message(self, str message="", **Any kwargs)
Definition: notify.py:80
web.Response get(self, web.Request request, str config_key)
Definition: view.py:88
None log_rate_limits(HomeAssistant hass, str target, dict[str, Any] resp, int level=20)
Definition: notify.py:32
iOSNotificationService|None get_service(HomeAssistant hass, ConfigType config, DiscoveryInfoType|None discovery_info=None)
Definition: notify.py:57
str|None device_name_for_push_id(HomeAssistant hass, str push_id)
Definition: __init__.py:242
list[str] enabled_push_ids(HomeAssistant hass)
Definition: __init__.py:228
dict[str, str] devices_with_push(HomeAssistant hass)
Definition: __init__.py:219