Home Assistant Unofficial Reference 2024.12.1
notify.py
Go to the documentation of this file.
1 """Support for BMW notifications."""
2 
3 from __future__ import annotations
4 
5 import logging
6 from typing import Any, cast
7 
8 from bimmer_connected.models import MyBMWAPIError, PointOfInterest
9 from bimmer_connected.vehicle import MyBMWVehicle
10 import voluptuous as vol
11 
13  ATTR_DATA,
14  ATTR_TARGET,
15  BaseNotificationService,
16 )
17 from homeassistant.const import ATTR_LATITUDE, ATTR_LONGITUDE, CONF_ENTITY_ID
18 from homeassistant.core import HomeAssistant
19 from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
20 from homeassistant.helpers import config_validation as cv
21 from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
22 
23 from . import DOMAIN, BMWConfigEntry
24 
25 ATTR_LOCATION_ATTRIBUTES = ["street", "city", "postal_code", "country"]
26 
27 POI_SCHEMA = vol.Schema(
28  {
29  vol.Required(ATTR_LATITUDE): cv.latitude,
30  vol.Required(ATTR_LONGITUDE): cv.longitude,
31  vol.Optional("street"): cv.string,
32  vol.Optional("city"): cv.string,
33  vol.Optional("postal_code"): cv.string,
34  vol.Optional("country"): cv.string,
35  }
36 )
37 
38 _LOGGER = logging.getLogger(__name__)
39 
40 
42  hass: HomeAssistant,
43  config: ConfigType,
44  discovery_info: DiscoveryInfoType | None = None,
45 ) -> BMWNotificationService:
46  """Get the BMW notification service."""
47  config_entry: BMWConfigEntry | None = hass.config_entries.async_get_entry(
48  (discovery_info or {})[CONF_ENTITY_ID]
49  )
50 
51  targets = {}
52  if (
53  config_entry
54  and (coordinator := config_entry.runtime_data.coordinator)
55  and not coordinator.read_only
56  ):
57  targets.update({v.name: v for v in coordinator.account.vehicles})
58  return BMWNotificationService(targets)
59 
60 
61 class BMWNotificationService(BaseNotificationService):
62  """Send Notifications to BMW."""
63 
64  vehicle_targets: dict[str, MyBMWVehicle]
65 
66  def __init__(self, targets: dict[str, MyBMWVehicle]) -> None:
67  """Set up the notification service."""
68  self.vehicle_targetsvehicle_targets = targets
69 
70  @property
71  def targets(self) -> dict[str, Any] | None:
72  """Return a dictionary of registered targets."""
73  return self.vehicle_targetsvehicle_targets
74 
75  async def async_send_message(self, message: str = "", **kwargs: Any) -> None:
76  """Send a message or POI to the car."""
77 
78  try:
79  # Verify data schema
80  poi_data = kwargs.get(ATTR_DATA) or {}
81  POI_SCHEMA(poi_data)
82 
83  # Create the POI object
84  poi = PointOfInterest(
85  lat=poi_data.pop(ATTR_LATITUDE),
86  lon=poi_data.pop(ATTR_LONGITUDE),
87  name=(message or None),
88  **poi_data,
89  )
90 
91  except (vol.Invalid, TypeError, ValueError) as ex:
93  translation_domain=DOMAIN,
94  translation_key="invalid_poi",
95  translation_placeholders={
96  "poi_exception": str(ex),
97  },
98  ) from ex
99 
100  for vehicle in kwargs[ATTR_TARGET]:
101  vehicle = cast(MyBMWVehicle, vehicle)
102  _LOGGER.debug("Sending message to %s", vehicle.name)
103 
104  try:
105  await vehicle.remote_services.trigger_send_poi(poi)
106  except MyBMWAPIError as ex:
107  raise HomeAssistantError(ex) from ex
None __init__(self, dict[str, MyBMWVehicle] targets)
Definition: notify.py:66
None async_send_message(self, str message="", **Any kwargs)
Definition: notify.py:75
BMWNotificationService get_service(HomeAssistant hass, ConfigType config, DiscoveryInfoType|None discovery_info=None)
Definition: notify.py:45