"""Group platform for notify component.""" from __future__ import annotations import asyncio from collections.abc import Coroutine, Mapping from copy import deepcopy from typing import Any import voluptuous as vol from homeassistant.components.notify import ( ATTR_DATA, ATTR_MESSAGE, DOMAIN, PLATFORM_SCHEMA, BaseNotificationService, ) from homeassistant.const import ATTR_SERVICE from homeassistant.core import HomeAssistant import homeassistant.helpers.config_validation as cv from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType CONF_SERVICES = "services" PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( { vol.Required(CONF_SERVICES): vol.All( cv.ensure_list, [{vol.Required(ATTR_SERVICE): cv.slug, vol.Optional(ATTR_DATA): dict}], ) } ) def update(input_dict: dict[str, Any], update_source: dict[str, Any]) -> dict[str, Any]: """Deep update a dictionary. Async friendly. """ for key, val in update_source.items(): if isinstance(val, Mapping): recurse = update(input_dict.get(key, {}), val) # type: ignore[arg-type] input_dict[key] = recurse else: input_dict[key] = update_source[key] return input_dict async def async_get_service( hass: HomeAssistant, config: ConfigType, discovery_info: DiscoveryInfoType | None = None, ) -> GroupNotifyPlatform: """Get the Group notification service.""" return GroupNotifyPlatform(hass, config[CONF_SERVICES]) class GroupNotifyPlatform(BaseNotificationService): """Implement the notification service for the group notify platform.""" def __init__(self, hass: HomeAssistant, entities: list[dict[str, Any]]) -> None: """Initialize the service.""" self.hass = hass self.entities = entities async def async_send_message(self, message: str = "", **kwargs: Any) -> None: """Send message to all entities in the group.""" payload: dict[str, Any] = {ATTR_MESSAGE: message} payload.update({key: val for key, val in kwargs.items() if val}) tasks: list[Coroutine[Any, Any, bool | None]] = [] for entity in self.entities: sending_payload = deepcopy(payload.copy()) if (data := entity.get(ATTR_DATA)) is not None: update(sending_payload, data) tasks.append( self.hass.services.async_call( DOMAIN, entity[ATTR_SERVICE], sending_payload ) ) if tasks: await asyncio.wait(tasks)