Do more with your Apple Watch with actionable notifications (eg: control covers)

Hi,

I just wanted to share an option to do more with your Apple Watch and home assistant. I got the idea from somewhere else but can’t remember where so I just wanted to share it here so it might inspire others as well. The possibilities with Apple Watch are quite limited but using actionable notifications, you can do a lot more.

The idea is you create an action in the companion app, which you can trigger from your Apple Watch. You then create an automation that triggers actionable notifications witch can act like a dropdown multiple choice menu.

In my case I have 3 covers that I want to control from my watch. So I press the action ‘control covers’ and I get a notification asking which cover? 1 2 or 3? After pressing any of them I get another notification asking: what action? up, stop or down? Once I press that the cover of my choice will open or close.
Screenshots:


Here is the automation: (it has some dutch words in it but I hope you can figure it out)

alias: "AW: Rolluiken"
description: ""
trigger:
  - platform: event
    event_type: ios.action_fired
    event_data:
      actionName: Rolluiken
    context: {}
condition: []
action:
  - service: notify.mobile_app_iphone_van_mij
    data:
      message: "AW: welk rolluik?"
      data:
        actions:
          - action: Rolluik_1
            title: Rolluik 1
          - action: Rolluik_2
            title: Rolluik 2
          - action: Rolluik_3
            title: Rolluik 3
  - wait_for_trigger:
      - platform: event
        event_type: mobile_app_notification_action
        event_data:
          action: Rolluik_1
      - platform: event
        event_type: mobile_app_notification_action
        event_data:
          action: Rolluik_2
      - platform: event
        event_type: mobile_app_notification_action
        event_data:
          action: Rolluik_3
    timeout:
      hours: 0
      minutes: 0
      seconds: 20
      milliseconds: 0
    continue_on_timeout: false
  - variables:
      rolluik: |
        {{
          {'Rolluik_1': 'cover.rolluik_1',
           'Rolluik_2': 'cover.rolluik_2',
           'Rolluik_3': 'cover.rolluik_3',
           }[wait.trigger.event.data.action] }}
  - service: notify.mobile_app_iphone_van_mij
    data:
      message: "AW: open of dicht?"
      data:
        actions:
          - action: r_open
            title: Open
          - action: r_stop
            title: Stop
          - action: r_dicht
            title: Dicht
  - wait_for_trigger:
      - platform: event
        event_type: mobile_app_notification_action
        event_data:
          action: r_open
      - platform: event
        event_type: mobile_app_notification_action
        event_data:
          action: r_stop
      - platform: event
        event_type: mobile_app_notification_action
        event_data:
          action: r_dicht
    timeout:
      hours: 0
      minutes: 0
      seconds: 20
      milliseconds: 0
    continue_on_timeout: false
  - variables:
      option: "{{ wait.trigger.event.data.action }}"
  - choose:
      - conditions:
          - condition: template
            value_template: "{{ option == 'r_open' }}"
        sequence:
          - service: cover.open_cover
            data: {}
            target:
              entity_id: "{{ rolluik }}"
      - conditions:
          - condition: template
            value_template: "{{ option == 'r_stop' }}"
        sequence:
          - service: cover.stop_cover
            data: {}
            target:
              entity_id: "{{ rolluik }}"
      - conditions:
          - condition: template
            value_template: "{{ option == 'r_dicht' }}"
        sequence:
          - service: cover.close_cover
            data: {}
            target:
              entity_id: "{{ rolluik }}"
mode: parallel
max: 10

To create an action in the companion app: go to settings, companion app, actions. Adding a new one is just adding a name an a nice icon and colors if you like. The name of the action will be the trigger in your automation. Mine is called ‘Rolluiken’.

So how it works is: it starts when the ios.action_fired is received. It then sends a notification with 3 options to click on. It then waits for any of the three options clicked. Then it stores the matching entity name in a variable called ‘Rolluik’ so I can use that variable later. Then it sends me another notification with 3 options to click on, and waits until one of the options is clicked. The button clicked is stored in the variable called ‘option’. Lastly I call the correct service (open, stop or close) based on last option clicked and use the entity from the variable ‘rolluik’ to determine which cover to control.

Use short texts in your notifications to make it more readable and user friendly so you don’t have to scroll a lot.

6 Likes

Hi, thanks a lot for this! Much appreciated!

I came to the same idea on the added value of iOS actions for Apple Watch and wanted to share these ideas in this forum but then I noticed you shared it already before me and with an even better automation!
So I upgraded my automations based on the script you shared ;).
Yet I also applied some “improvements” that might be interesting for other to consider maybe…

  • When the iOS actions are triggered from CarPlay or while driving, the notification would be shown in CarPlay only if the notification is marked as critical. So I added a variable to check this for all my notifications.

  • When using the wait_for_trigger with a timeout for follow up actions on the iOS events, I liked the possibility to remove the notification completely (using notification tag) once the wait timeout has passed, the follow up actions won’t work anymore anyway.

  • I also found some way to reuse the actions by defining these in variables first. This allows to define the notification actions based on some conditions, without having to re-define the same actions multiple times.

  • I also use some emoticons in the action names to make the actionlist even easier to use.

  • I defined some standard processing based on the selected action. Depending on the type of entity linked to the action, the correct toggle action will be selected (eg script.... entity will be launched with script turn on service call, light.... entity with a light toggle script, a selected climate.... entity will turn on the heating or return to auto hvac mode, etc).

alias: Media Selection iOS action event
description: Control media selection
trigger:
  - platform: event
    event_type: ios.action_fired
    event_data:
      actionName: MediaSelection
  - platform: event
    event_type: ios.notification_action_fired
    event_data:
      actionName: MediaSelection
condition: []
action:
  - variables:
      critical_desired: >-
        {% if states('sensor.iphone_activity') == 'Automotive' or 
        (trigger is defined and trigger.event is defined and
        trigger.event.data.triggerSource == 'carPlay') %}1{% else %}0{% endif %}
      media_player_title: >-
        Media 🎶 
      media_player_message: >-
        {{state_attr('media_player.hub','media_artist')|replace('Various
        Artists','')}}: {{state_attr('media_player.hub','media_title')|replace('None','')|
        regex_replace('\\[.*?\\]', '')}}

        {% if states('binary_sensor.media_playing_plex') == 'on' %}Plex
        playlist: {{states('input_select.plexplaylist')}}{% endif %}
      actions_stop:
        - action: Stop all cast
          title: 🔇 Stop all media casting
          activationMode: background
          authenticationRequired: true
          destructive: false
          behavior: default
      actions_switch:
        - action: Switch selection
          title: Switch selection
          activationMode: background
          authenticationRequired: true
          destructive: false
          behavior: default
      actions_play:
        - action: Plex
          title: Plex ({{states('input_select.plexplaylist')}})
          activationMode: background
          authenticationRequired: true
          destructive: false
          behavior: default
        - action: Play
          title: ▶ Play
          activationMode: background
          authenticationRequired: true
          destructive: false
          behavior: default
        - action: Pause
          title: ⏸ Pause
          activationMode: background
          authenticationRequired: true
          destructive: false
          behavior: default
        - action: Next
          title: ⏩ Next
          activationMode: background
          authenticationRequired: true
          destructive: false
          behavior: default
        - action: Back
          title: ⏪ Back
          activationMode: background
          authenticationRequired: true
          destructive: false
          behavior: default
        - action: Volume Up
          title: 🔊 Volume up
          activationMode: background
          authenticationRequired: true
          destructive: false
          behavior: default
        - action: Volume Down
          title: 🔈 Volume down
          activationMode: background
          authenticationRequired: true
          destructive: false
          behavior: default
      actions_plex:
        - action: PlexRate1
          title: "        ⭐"
          activationMode: background
          authenticationRequired: true
          destructive: false
          behavior: default
        - action: PlexRate2
          title: "     ⭐⭐"
          activationMode: background
          authenticationRequired: true
          destructive: false
          behavior: default
        - action: PlexRate3
          title: "    ⭐⭐⭐"
          activationMode: background
          authenticationRequired: true
          destructive: false
          behavior: default
        - action: PlexRate4
          title: "  ⭐⭐⭐⭐"
          activationMode: background
          authenticationRequired: true
          destructive: false
          behavior: default
        - action: PlexRate5
          title: ⭐⭐⭐⭐⭐
          activationMode: background
          authenticationRequired: true
          destructive: false
          behavior: default
      actions_playlist:
        - action: Select playlist
          title: Change playlist ({{states('input_select.plexplaylist')}})
          activationMode: background
          authenticationRequired: true
          destructive: false
          behavior: default
      actions_desired: >-
        {% if state_attr('media_player.hub','app_name') == 'Plex'
        %}{{actions_stop + actions_switch + actions_play + actions_plex +
        actions_playlist}}{% else %}{{actions_stop + actions_switch +
        actions_play + actions_playlist}}{% endif %}
  - choose: []
    default:
      - service: notify.iphone_notification_group
        continue_on_error: true
        data:
          title: "{{media_player_title}}"
          message: "{{media_player_message}}"
          data:
            push:
              sound:
                name: default
                critical: "{{critical_desired}}"
            url: /lovelace-media/remote
            group: media
            tag: media
            actions: "{{actions_desired}}"
      - wait_for_trigger:
          - platform: event
            event_type: mobile_app_notification_action
        timeout:
          hours: 0
          minutes: 0
          seconds: 30
          milliseconds: 0
        continue_on_timeout: true
        enabled: true
      - choose:
          - conditions:
              - condition: template
                value_template: "{{wait.trigger == None}}"
            sequence:
              - service: notify.iphone_notification_group
                metadata: {}
                data:
                  message: clear_notification
                  data:
                    tag: media
              - stop: timeout
      - variables:
          option: "{{ wait.trigger.event.data.action }}"
          selected_entity: |
            {{
              {'Stop all cast': 'script.stop_all_cast',
               'Switch selection': 'automation.switch_selection_ios_action_event',
               'Plex': 'script.play_plex_media_selection',
               'Play': 'script.cast_pause_selection',
               'Pause': 'script.cast_pause_selection',
               'Next': 'script.cast_next_selection',
               'Back': 'script.cast_previous_selection',
               'Volume Up': 'script.volume_up_selection',
               'Volume Down': 'script.volume_down_selection',
               'Select playlist': 'automation.select_playlist_ios_action_event'
               }[wait.trigger.event.data.action] }}
          entity_type: "{{selected_entity.split('.')[0] }}"
      - service: notify.iphone_notification_group
        continue_on_error: true
        data:
          title: Debug
          message: >-
            option: {{option}}, selected_entity: {{selected_entity}},
            entity_type: {{entity_type}}
        enabled: false
      - choose:
          - conditions:
              - condition: template
                value_template: "{{ entity_type == 'climate' }}"
            sequence:
              - choose:
                  - conditions:
                      - condition: template
                        value_template: "{{state_attr(selected_entity,'temperature') >= 19}}"
                    sequence:
                      - service: climate.set_hvac_mode
                        data:
                          hvac_mode: auto
                        target:
                          entity_id: "{{selected_entity}}"
                default:
                  - service: climate.set_temperature
                    data:
                      temperature: 20
                      hvac_mode: heat
                    target:
                      entity_id: "{{selected_entity}}"
          - conditions:
              - condition: template
                value_template: "{{ entity_type == 'light' }}"
            sequence:
              - service: light.toggle
                data: {}
                target:
                  entity_id: "{{selected_entity}}"
          - conditions:
              - condition: template
                value_template: "{{ entity_type == 'switch' }}"
            sequence:
              - service: switch.toggle
                data: {}
                target:
                  entity_id: "{{selected_entity}}"
          - conditions:
              - condition: template
                value_template: "{{ entity_type == 'script' }}"
            sequence:
              - service: script.turn_on
                data: {}
                target:
                  entity_id: "{{selected_entity}}"
          - conditions:
              - condition: template
                value_template: "{{ entity_type == 'automation' }}"
            sequence:
              - service: automation.trigger
                data:
                  skip_condition: true
                target:
                  entity_id: "{{selected_entity}}"
mode: single

(Some events of my (plex related) actions in the example above are handled by separate automations and some are handled by the inline wait_for_trigger event handler)

06/03/2024: updated code: most of the time no need to specify all different actions in the wait_for_trigger