Files
core/homeassistant/components/ntfy/notify.py
Manu eaf400f3b7 Add ntfy.publish action to ntfy integration (#143560)
Co-authored-by: Erik Montnemery <erik@montnemery.com>
Co-authored-by: Norbert Rittel <norbert@rittel.de>
2025-09-09 19:08:49 +02:00

139 lines
4.4 KiB
Python

"""ntfy notification entity."""
from __future__ import annotations
from datetime import timedelta
from typing import Any
from aiontfy import Message
from aiontfy.exceptions import (
NtfyException,
NtfyHTTPError,
NtfyUnauthorizedAuthenticationError,
)
import voluptuous as vol
from yarl import URL
from homeassistant.components.notify import (
ATTR_MESSAGE,
ATTR_TITLE,
NotifyEntity,
NotifyEntityDescription,
NotifyEntityFeature,
)
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
from homeassistant.helpers import config_validation as cv, entity_platform
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from .const import DOMAIN
from .coordinator import NtfyConfigEntry
from .entity import NtfyBaseEntity
PARALLEL_UPDATES = 0
SERVICE_PUBLISH = "publish"
ATTR_ATTACH = "attach"
ATTR_CALL = "call"
ATTR_CLICK = "click"
ATTR_DELAY = "delay"
ATTR_EMAIL = "email"
ATTR_ICON = "icon"
ATTR_MARKDOWN = "markdown"
ATTR_PRIORITY = "priority"
ATTR_TAGS = "tags"
SERVICE_PUBLISH_SCHEMA = cv.make_entity_service_schema(
{
vol.Optional(ATTR_TITLE): cv.string,
vol.Optional(ATTR_MESSAGE): cv.string,
vol.Optional(ATTR_MARKDOWN): cv.boolean,
vol.Optional(ATTR_TAGS): vol.All(cv.ensure_list, [str]),
vol.Optional(ATTR_PRIORITY): vol.All(vol.Coerce(int), vol.Range(1, 5)),
vol.Optional(ATTR_CLICK): vol.All(vol.Url(), vol.Coerce(URL)),
vol.Optional(ATTR_DELAY): vol.All(
cv.time_period,
vol.Range(min=timedelta(seconds=10), max=timedelta(days=3)),
),
vol.Optional(ATTR_ATTACH): vol.All(vol.Url(), vol.Coerce(URL)),
vol.Optional(ATTR_EMAIL): vol.Email(),
vol.Optional(ATTR_CALL): cv.string,
vol.Optional(ATTR_ICON): vol.All(vol.Url(), vol.Coerce(URL)),
}
)
async def async_setup_entry(
hass: HomeAssistant,
config_entry: NtfyConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up the ntfy notification entity platform."""
for subentry_id, subentry in config_entry.subentries.items():
async_add_entities(
[NtfyNotifyEntity(config_entry, subentry)], config_subentry_id=subentry_id
)
platform = entity_platform.async_get_current_platform()
platform.async_register_entity_service(
SERVICE_PUBLISH,
SERVICE_PUBLISH_SCHEMA,
"publish",
)
class NtfyNotifyEntity(NtfyBaseEntity, NotifyEntity):
"""Representation of a ntfy notification entity."""
entity_description = NotifyEntityDescription(
key="publish",
translation_key="publish",
name=None,
)
_attr_supported_features = NotifyEntityFeature.TITLE
async def async_send_message(self, message: str, title: str | None = None) -> None:
"""Publish a message to a topic."""
await self.publish(message=message, title=title)
async def publish(self, **kwargs: Any) -> None:
"""Publish a message to a topic."""
params: dict[str, Any] = kwargs
delay: timedelta | None = params.get("delay")
if delay:
params["delay"] = f"{delay.total_seconds()}s"
if params.get("email"):
raise ServiceValidationError(
translation_domain=DOMAIN,
translation_key="delay_no_email",
)
if params.get("call"):
raise ServiceValidationError(
translation_domain=DOMAIN,
translation_key="delay_no_call",
)
msg = Message(topic=self.topic, **params)
try:
await self.ntfy.publish(msg)
except NtfyUnauthorizedAuthenticationError as e:
self.config_entry.async_start_reauth(self.hass)
raise HomeAssistantError(
translation_domain=DOMAIN,
translation_key="authentication_error",
) from e
except NtfyHTTPError as e:
raise HomeAssistantError(
translation_key="publish_failed_request_error",
translation_domain=DOMAIN,
translation_placeholders={"error_msg": e.error},
) from e
except NtfyException as e:
raise HomeAssistantError(
translation_key="publish_failed_exception",
translation_domain=DOMAIN,
) from e