Skip to content

Commit 7d4a998

Browse files
committed
Add support for button actions to ntfy
1 parent aea055b commit 7d4a998

File tree

4 files changed

+205
-4
lines changed

4 files changed

+205
-4
lines changed

homeassistant/components/ntfy/icons.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,10 @@
7575
},
7676
"services": {
7777
"publish": {
78-
"service": "mdi:send"
78+
"service": "mdi:send",
79+
"sections": {
80+
"actions": "mdi:gesture-tap-button"
81+
}
7982
}
8083
}
8184
}

homeassistant/components/ntfy/notify.py

Lines changed: 68 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from datetime import timedelta
66
from typing import Any
77

8-
from aiontfy import Message
8+
from aiontfy import BroadcastAction, HttpAction, Message, ViewAction
99
from aiontfy.exceptions import (
1010
NtfyException,
1111
NtfyHTTPError,
@@ -31,7 +31,7 @@
3131
from .entity import NtfyBaseEntity
3232

3333
PARALLEL_UPDATES = 0
34-
34+
MAX_ACTIONS_ALLOWED = 3
3535

3636
SERVICE_PUBLISH = "publish"
3737
ATTR_ATTACH = "attach"
@@ -43,7 +43,53 @@
4343
ATTR_MARKDOWN = "markdown"
4444
ATTR_PRIORITY = "priority"
4545
ATTR_TAGS = "tags"
46-
46+
ATTR_ACTION = "action"
47+
ATTR_VIEW = "view"
48+
ATTR_BROADCAST = "broadcast"
49+
ATTR_HTTP = "http"
50+
ATTR_LABEL = "label"
51+
ATTR_URL = "url"
52+
ATTR_CLEAR = "clear"
53+
ATTR_POSITION = "position"
54+
ATTR_INTENT = "intent"
55+
ATTR_EXTRAS = "extras"
56+
ATTR_METHOD = "method"
57+
ATTR_HEADERS = "headers"
58+
ATTR_BODY = "body"
59+
ACTIONS_MAP = {
60+
ATTR_VIEW: ViewAction,
61+
ATTR_BROADCAST: BroadcastAction,
62+
ATTR_HTTP: HttpAction,
63+
}
64+
65+
ACTION_SCHEMA = vol.Schema(
66+
{
67+
vol.Required(ATTR_LABEL): cv.string,
68+
vol.Optional(ATTR_CLEAR, default=False): cv.boolean,
69+
vol.Optional(ATTR_POSITION): vol.All(vol.Coerce(int), vol.Range(1, 3)),
70+
}
71+
)
72+
VIEW_SCHEMA = ACTION_SCHEMA.extend(
73+
{
74+
vol.Optional(ATTR_ACTION, default="view"): str,
75+
vol.Required(ATTR_URL): cv.url,
76+
}
77+
)
78+
BROADCAST_SCHEMA = ACTION_SCHEMA.extend(
79+
{
80+
vol.Optional(ATTR_ACTION, default="broadcast"): str,
81+
vol.Optional(ATTR_INTENT): cv.string,
82+
vol.Optional(ATTR_EXTRAS): dict[str, str],
83+
}
84+
)
85+
HTTP_SCHEMA = VIEW_SCHEMA.extend(
86+
{
87+
vol.Optional(ATTR_ACTION, default="http"): str,
88+
vol.Optional(ATTR_METHOD): cv.string,
89+
vol.Optional(ATTR_HEADERS): dict[str, str],
90+
vol.Optional(ATTR_BODY): cv.string,
91+
}
92+
)
4793
SERVICE_PUBLISH_SCHEMA = cv.make_entity_service_schema(
4894
{
4995
vol.Optional(ATTR_TITLE): cv.string,
@@ -60,6 +106,9 @@
60106
vol.Optional(ATTR_EMAIL): vol.Email(),
61107
vol.Optional(ATTR_CALL): cv.string,
62108
vol.Optional(ATTR_ICON): vol.All(vol.Url(), vol.Coerce(URL)),
109+
vol.Optional(ATTR_VIEW): vol.All(cv.ensure_list, [VIEW_SCHEMA]),
110+
vol.Optional(ATTR_BROADCAST): vol.All(cv.ensure_list, [BROADCAST_SCHEMA]),
111+
vol.Optional(ATTR_HTTP): vol.All(cv.ensure_list, [HTTP_SCHEMA]),
63112
}
64113
)
65114

@@ -115,6 +164,22 @@ async def publish(self, **kwargs: Any) -> None:
115164
translation_domain=DOMAIN,
116165
translation_key="delay_no_call",
117166
)
167+
actions: list[dict[str, Any]] = (
168+
params.pop(ATTR_VIEW, [])
169+
+ params.pop(ATTR_BROADCAST, [])
170+
+ params.pop(ATTR_HTTP, [])
171+
)
172+
actions.sort(key=lambda a: a.pop(ATTR_POSITION, float("inf")))
173+
174+
if actions:
175+
if len(actions) > MAX_ACTIONS_ALLOWED:
176+
raise ServiceValidationError(
177+
translation_domain=DOMAIN,
178+
translation_key="too_many_actions",
179+
)
180+
params["actions"] = [
181+
ACTIONS_MAP[action.pop(ATTR_ACTION)](**action) for action in actions
182+
]
118183

119184
msg = Message(topic=self.topic, **params)
120185
try:

homeassistant/components/ntfy/services.yaml

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,3 +88,115 @@ publish:
8888
type: url
8989
autocomplete: url
9090
example: https://example.org/logo.png
91+
actions:
92+
collapsed: true
93+
fields:
94+
view:
95+
selector:
96+
object:
97+
label_field: "label"
98+
description_field: "url"
99+
multiple: true
100+
fields:
101+
label:
102+
label: Label
103+
selector:
104+
text:
105+
url:
106+
label: URL
107+
selector:
108+
text:
109+
type: url
110+
clear:
111+
label: Clear
112+
selector:
113+
boolean:
114+
position:
115+
label: Position
116+
selector:
117+
select:
118+
options:
119+
- 1
120+
- 2
121+
- 3
122+
mode: dropdown
123+
broadcast:
124+
selector:
125+
object:
126+
label_field: "label"
127+
description_field: "intent"
128+
multiple: true
129+
fields:
130+
label:
131+
label: Label
132+
selector:
133+
text:
134+
intent:
135+
label: Android intent
136+
selector:
137+
text:
138+
extras:
139+
label: Intent extras
140+
selector:
141+
object:
142+
clear:
143+
label: Clear
144+
selector:
145+
boolean:
146+
position:
147+
label: Position
148+
selector:
149+
select:
150+
options:
151+
- 1
152+
- 2
153+
- 3
154+
mode: dropdown
155+
http:
156+
selector:
157+
object:
158+
label_field: "label"
159+
description_field: "url"
160+
multiple: true
161+
fields:
162+
label:
163+
label: Label
164+
selector:
165+
text:
166+
url:
167+
label: URL
168+
selector:
169+
text:
170+
type: url
171+
method:
172+
label: HTTP method
173+
selector:
174+
select:
175+
options:
176+
- GET
177+
- POST
178+
- PUT
179+
- DELETE
180+
custom_value: true
181+
headers:
182+
label: HTTP headers
183+
selector:
184+
object:
185+
body:
186+
label: HTTP body
187+
selector:
188+
text:
189+
multiline: true
190+
clear:
191+
label: Clear
192+
selector:
193+
boolean:
194+
position:
195+
label: Position
196+
selector:
197+
select:
198+
options:
199+
- 1
200+
- 2
201+
- 3
202+
mode: dropdown

homeassistant/components/ntfy/strings.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,9 @@
273273
},
274274
"delay_no_call": {
275275
"message": "Delayed call notifications are not supported"
276+
},
277+
"too_many_actions": {
278+
"message": "Too many actions defined. Only 3 allowed"
276279
}
277280
},
278281
"services": {
@@ -323,6 +326,24 @@
323326
"icon": {
324327
"name": "Icon URL",
325328
"description": "Include an icon that will appear next to the text of the notification. Only JPEG and PNG images are supported."
329+
},
330+
"view": {
331+
"name": "Open website/app",
332+
"description": "Adds a 'view' button action that opens a website or app when the action button is tapped. See the documentation for details: https://docs.ntfy.sh/publish/#open-websiteapp"
333+
},
334+
"broadcast": {
335+
"name": "Send Android broadcast",
336+
"description": "Adds a 'broadcast' button action that sends an Android broadcast intent when the action button is tapped. This action is only supported on Android. See the documentation for details: https://docs.ntfy.sh/publish/#send-android-broadcast"
337+
},
338+
"http": {
339+
"name": "Send HTTP request",
340+
"description": "Adds an 'http' button action that sends an HTTP request when the action button is tapped. See the documentation for details: https://docs.ntfy.sh/publish/#send-http-request"
341+
}
342+
},
343+
"sections": {
344+
"actions": {
345+
"name": "Action buttons",
346+
"description": "Up to three actions ('view', 'broadcast', or 'http') can be defined for a notification. These appear as buttons below the notification content. Actions are executed when the corresponding button is tapped or clicked."
326347
}
327348
}
328349
}

0 commit comments

Comments
 (0)