Best way to handle REPLY actions?

I am trying to use the ‘REPLY’ action in a actionable notification on android. From my poking around, there is no way to determine the context a reply came from. From example, If I have two scripts that send an action from a notification, I can’t differentiate between those two replies between the scripts. I noticed in the docs, there was an example using the context ID. That would be a nice way to handle that, but the REPLY keyword which opens a input box on android must not include any other characters/letters so it can’t be used here.

Is there a better way to do this? I really would rather not match on arbitrary ‘title’ or something that may change or is dynamic in nature.

Essentially, Is there a way for a REPLY action to be uniquely identified ?

Hm. I think I figured it out.

For someone else wanting to do this. Apparently, you can send really any data attribute to the android app and on a reply, it will reply also with that data. Example:

service: notify.phone_notifications
data:
  title: Human Detected @ Door
  message: Someones at the door.
  data:
    image: '{{ lasturl }}'
    tag: Doorbell-general
    group: General
    timeout: 180
    channel: General
    ttl: 0
    priority: high
    id: front-door-motion-snooze
    actions:
      - action: URI
        title: Live
        uri: '{{ linkurl }}'
      - action: URI
        title: All Cameras
        uri: /my-home/cams
      - action: REPLY
        title: Snooze

If I send the ‘id: front-door-motion-snooze’, I can then listen for that in the event data on the reply. Easy.

  - platform: event
    event_type: mobile_app_notification_action
    event_data:
      action: REPLY
      id: front-door-motion-snooze

and an example event:

Event 15 fired 12:40 PM:
{
    "event_type": "mobile_app_notification_action",
    "data": {
        "image": "",
        "tag": "Doorbell-general",
        "group": "General",
        "timeout": "180",
        "channel": "General",
        "ttl": "0",
        "priority": "high",
        "id": "front-door-motion-snooze",
        "action_1_key": "URI",
        "action_1_title": "Live",
        "action_1_uri": "",
        "action_2_key": "URI",
        "action_2_title": "All Cameras",
        "action_2_uri": "/my-home/cams",
        "action_3_key": "REPLY",
        "action_3_title": "Snooze",
        "action_3_uri": "null",
        "message": "Someones at the door.",
        "title": "Human Detected @ Door",
        "reply_text": "6",
        "action": "REPLY",
        "device_id": "xxx"
    },
    "origin": "REMOTE",
    "time_fired": "2022-05-26T16:40:38.508916+00:00",
    "context": {
        "id": "xxx",
        "parent_id": null,
        "user_id": "xxx"
    }
}
1 Like

This might be good information to include in the docs, especially for the REPLY. But really any time you want to generate a unique ID and there isn’t a ‘better’ way to do it.

Anyone knows how to handle two REPLY actions?

I also had a ton of trouble making my use case work, so wanted to share it now that I figured it out:

alias: Automation - Set Alarm for Before Morning Calendar Event
description: ""
trigger:
  - platform: calendar
    event: start
    offset: "-12:0:0"
    entity_id: calendar.family
condition:
  - condition: time
    before: "23:00:00"
    after: "12:01:00"
    enabled: true
action:
  - service: notify.mobile_app_pixel_5
    data:
      message: >-
        Set Alarm for {{trigger.calendar_event.summary}} at {{
        (strptime(trigger.calendar_event.start,
        '%Y-%m-%dT%H:%M:%S%z')).strftime('%H:%M') }} AM?
      data:
        tag: alarm_set
        actions:
          - action: REPLY
            title: Alarm Offset (enter minutes)
  - wait_for_trigger:
      - platform: event
        event_type: mobile_app_notification_action
        event_data:
          action: REPLY
          tag: alarm_set
    timeout: "60:00"
    continue_on_timeout: false
  - service: notify.mobile_app_pixel_5
    data:
      message: command_activity
      data:
        intent_extras: >-
          android.intent.extra.alarm.HOUR:{{(strptime(trigger.calendar_event.start,
          '%Y-%m-%dT%H:%M:%S%z') - timedelta(minutes=
          wait.trigger.event.data.reply_text | int(0) )).strftime('%H')
          }},android.intent.extra.alarm.MINUTES:{{(strptime(trigger.calendar_event.start,
          '%Y-%m-%dT%H:%M:%S%z') - timedelta(minutes=
          wait.trigger.event.data.reply_text | int(0) )).strftime('%M') }}
        intent_action: android.intent.action.SET_ALARM
mode: parallel
max: 10

Is this still working for you? I’m trying to add something similar (just an “id” attribute) and am having no luck in getting it returned upon interaction with the notification.

I am working on this right now, and got something working. What really helped me was first creating an automation that gets triggered by the ‘event_type: mobile_app_notification_action’ with ‘action: REPLY’ in data to catch all replies, then just send a test reply, go to ‘Traces’ in the automation and click the tab ‘Changed Variables’. This will show you everything there is to know about the trigger. My guess is that the best way to filter the reply events is by a combination of device id/user id (if there are multiple devices or users involved), message text, tag and/or action title. Filtering by tag has been working for me, but using a tag also means that your notification will be replaced by a new notification with the same tag (which works for my use case, but may not be desired behaviour). Action title is the text on the action/button in your notification. Below is an example of the output shown at ‘Changed Variables’:

this:
  entity_id: automation.notification_memo
  state: 'on'
  attributes:
    id: '1728942408707'
    last_triggered: '2024-10-16T10:30:50.729325+00:00'
    mode: single
    current: 0
    friendly_name: Notification Memo
  last_changed: '2024-10-16T10:34:31.764158+00:00'
  last_reported: '2024-10-16T10:34:31.764158+00:00'
  last_updated: '2024-10-16T10:34:31.764158+00:00'
  context:
    id: 01JAAE9FEMNEQQ806VF2JJ0M2T
    parent_id: null
    user_id: null
trigger:
  id: notification_memo_reply
  idx: '4'
  alias: Reply
  platform: event
  event:
    event_type: mobile_app_notification_action
    data:
      action_2_title: New Memo
      sticky: 'true'
      tag: notification_memo_persistent
      group: notification_memo_persistent
      webhook_id: 4a0e9fe17d489da847affd7c4f7c8d92919b3f8547fff304aadb8f22e01ffa6c
      persistent: 'true'
      channel: Memo_Persistent
      clickAction: noAction
      message: Note to self
      action_1_title: Disable
      action_1_key: notification_memo_disable
      action_2_key: REPLY
      importance: min
      server_id: '2'
      reply_text: Test reply 4
      action: REPLY
      device_id: fb35fa9a18221d4c
    origin: REMOTE
    time_fired: '2024-10-16T10:34:43.497736+00:00'
    context:
      id: 01JAAE9TX9MS0H30MG2HGPSS8R
      parent_id: null
      user_id: f24a8c7c46ea4e6ba34d1334a0920aa4
  description: event 'mobile_app_notification_action'

What you want is inside the event: data: section

This is what my automation trigger looks like:

alias: Reply
trigger: event
event_type: mobile_app_notification_action
event_data:
  action: REPLY
  action_2_title: New Memo
  message: Note to self
id: notification_memo_reply

Hope this helps. As I said, I am still figuring this out myself at the moment. I haven’t tested this with multiple automations with reply triggers, but I got a good feeling that this will do the trick.
I tried adding an ‘id’ to the notification like in post #2, but it didn’t show up in the event data. I’m guessing this has something to do with new android notification specifications.

If filtering this way isn’t specific enough, and you have another action besides the reply action, you could ‘hide’ a unique identifier in the other (not REPLY) action key (in my example:

action_1_key: notification_memo_disable_b8f22e01ffa6c

Then, in your automation actions, you could use a template as a condition for an ‘If/Then’ or ‘Choose’ block.

{{ (trigger.event.data.action_1_key) == 'notification_memo_disable_b8f22e01ffa6c' }}

It’s rather hacky, but it seems to work.