UniFi Protect Blueprints

@petro i do have the blueprints in yaml still. Do I just upload the contents of the yaml files here?

Yep, that will do. If someone wants to maintain it, they can make a new repo for it. I’ll mark your post as the solution so people have a direct link to it.

So here are the blueprints (split into 3 seperate posts due to error with post size)

Ring Event Notification (notification_ring_event.yaml)

blueprint:
  name: UniFi Protect Doorbell Ring Notifications
  domain: automation
  source_url: https://raw.githubusercontent.com/AngellusMortis/unifiprotect_blueprints/main/blueprints/automation/unifiprotect/notification_ring_event.yaml
  description: "## UniFi Protect Doorbell Ring Notifications\n\nThis blueprint will
    send push notifications to a Home Assistant mobile app when a doorbell ring is
    detected.\n\n### Required Settings\n\n  - UniFi Protect Doorbell Sensor\n\n###
    Optional Settings\n\n  - Notification target for the [mobile app notification
    target][1].\n  - Cutoff time before ring event for video clips.\n  - Time formatting
    strings. Timestamp is injected into the notification in case the notification
    is delay.\n  - Cooldown before sending another notification\n  - Silence timer
    for muting notifications via Actionable Notification (docs: [Mobile][2])\n  -
    Configurable lovelace view from notification\n\n### Requirements\n\nTo take full
    effect of this automation blueprint, your Home Assistant instance needs some setup
    beforehand.\n\n- An UniFi Protect G4 Doorbell or G4 Doorbell Pro.\n- A valid HTTPS
    certificate and [properly configured external URL][3]\n  - If you are using Home
    Assistant Cloud, this is already set up for you.\n  - If this is not setup correctly,
    the actionable notifications and attachments will not appear in the notifications.\n
    \ - You do not need your _whole_ Home Assistant to be publicly accessible. Only
    the paths `/api/unifiprotect/*` and\n    `/api/webhook/*` need to be accessible
    outside of your network.\n\n[1]: https://companion.home-assistant.io/docs/notifications/notifications-basic#sending-notifications-to-multiple-devices\n[2]:
    https://companion.home-assistant.io/docs/notifications/actionable-notifications/\n[3]:
    https://www.home-assistant.io/docs/configuration/remote/\n"
  input:
    doorbell_sensor:
      name: Doorbell Sensor Entity
      description: 'The "Doorbell" sensor(s) to use.

        '
      selector:
        entity:
          integration: unifiprotect
          domain:
          - binary_sensor
          device_class:
          - occupancy
          multiple: true
    lock_entity:
      name: (Optional) Door Lock or Gate Entity
      description: 'The entity to provide an actionable notification to unlock on
        doorbell ring. The time interval you have to respond to the unlock action
        is controlled by "Cooldown". Short Cooldown timers may prevent you from unlocking
        the door.

        '
      default: ''
      selector:
        entity:
          domain:
          - lock
          - cover
          multiple: false
    tts_target:
      name: (Optional) TTS Service
      description: 'The TTS service you want to use to generate TTS messages https://www.home-assistant.io/integrations/tts/

        '
      default: ''
      selector:
        text: {}
    lock_tts:
      name: (Optional) Unlock TTS message
      description: 'TTS Message for play through doorbell when door is unlocked.

        '
      default: ''
      selector:
        text: {}
    wait_tts:
      name: (Optional) TTS message
      description: 'Adds actionable notification to play TTS message to respond to
        guest. The time interval you have to respond to the TTS action is controlled
        by "Cooldown". Short Cooldown timers may prevent you from sending a TTS message
        the door.

        '
      default: ''
      selector:
        text: {}
    notify_target_app:
      name: (Optional) Notification Target (Mobile App)
      description: 'The notification target for mobile apps notifications. Can be
        `notifiy.notify` or any Mobile app notify service (starts with `notify.mobile_app_`).
        https://companion.home-assistant.io/docs/notifications/notifications-basic#sending-notifications-to-multiple-devices

        '
      default: notify.notify
      selector:
        text: {}
    channel:
      name: (Optional) Notification Channel
      description: 'Notification channel/tag to use. Will automatically be prepended
        with "Manual " if action is triggered manually. https://companion.home-assistant.io/docs/notifications/notifications-basic#notification-channels

        '
      default: Doorbell
      selector:
        text: {}
    video_cutoff:
      name: (Optional) Video Cutoff
      description: 'Time before the doorbell ring to generate a video for to send.
        Setting to 0 will disable attaching a video clip.

        '
      default: 0
      selector:
        number:
          max: 30.0
          min: 0.0
          unit_of_measurement: seconds
          mode: slider
          step: 1.0
    time_format:
      name: (Optional) Time Format String
      description: 'Python datetime format code string for the event trigger time.
        This string is the actual time the doorbell event was triggered in case the
        automation or notification is delayed. Manual triggers will cause this to
        always be the time of the previous event. https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes

        '
      default: '%I:%M %p'
      selector:
        entity: {}
    cooldown:
      name: (Optional) Cooldown
      description: 'Delay before sending another notification for this camera after
        the last event. Is also the interval you have to respond to actions in notification.

        '
      default: 120
      selector:
        number:
          max: 300.0
          min: 0.0
          unit_of_measurement: seconds
          mode: slider
          step: 1.0
    silence_timer:
      name: (Optional) Silence Notifications
      description: 'How long to silence notifications for this camera when requested
        as part of the actionable notification. The time interval you have to respond
        to the slient action is controlled by "Cooldown". Short Cooldown timers may
        prevent you from silencing.

        '
      default: 30
      selector:
        number:
          max: 300.0
          min: 0.0
          unit_of_measurement: minutes
          mode: slider
          step: 1.0
    lovelace_view:
      name: (Optional) Lovelace View
      description: 'Home Assistant Lovelace view to open when clicking notification.

        If left blank, URI Notification actions will not be generated.

        '
      default: ''
      selector:
        text: {}
    debug_event_id:
      name: (Optional) Debug Event ID
      description: 'Debug Event ID for UniFi Protect to use for when manually triggering
        automation. Will be used to generate a thumbnail for testing notifications.

        '
      default: ''
      selector:
        text: {}
mode: single
max_exceeded: silent
variables:
  input_doorbell: !input doorbell_sensor
  input_lock_entity: !input lock_entity
  input_lock_tts: !input lock_tts
  input_wait_tts: !input wait_tts
  input_tts_target: !input tts_target
  input_channel: !input channel
  input_lovelace_view: !input lovelace_view
  input_notify_target_app: !input notify_target_app
  input_silence_timer: !input silence_timer
  input_time_format: !input time_format
  input_debug_event_id: !input debug_event_id
  input_cooldown: !input cooldown
  input_video_cutoff: !input video_cutoff
  lovelace_view: '{{ input_lovelace_view | trim }}'
  is_manual: '{{ ''from_state'' not in trigger }}'
  notification_channel: "{% if is_manual %}\n  Manual {{ input_channel }}\n{% else
    %}\n  {{ input_channel }}\n{% endif %}\n"
  entity_id: '{% if is_manual %}{{ input_doorbell[0] }}{% else %}{{ trigger.entity_id
    }}{% endif %}'
  device_id: '{{ device_id(entity_id) }}'
  device_name: '{{ device_attr(device_id, ''name'') }}'
  camera_entities: '[{% for eid in device_entities(device_id) %}{%if eid.startswith(''camera'')
    and not ''package'' in eid and not is_state(eid, ''unavailable'') %}"{{ eid }}",{%
    endif %}{% endfor %}]'
  camera_entity_id: '{{ camera_entities | default([None]) | first }}'
  lock_entity_id: '{{ input_lock_entity or '''' }}'
  media_entities: '[{% for eid in device_entities(device_id) %}{%if eid.startswith(''media_player'')
    and not is_state(eid, ''unavailable'') %}"{{ eid }}",{% endif %}{% endfor %}]'
  media_entity_id: '{{ media_entities | default([None]) | first }}'
  event_id: '{% if is_manual %}{{ input_debug_event_id }}{% else %}{{ state_attr(entity_id,
    ''event_id'') }}{% endif %}'
  video_end: '{{ states[entity_id].last_changed.isoformat() }}'
  trigger_time: "{% if states[entity_id] == None %}\n  None\n{% else %}\n  {{ as_local(states[entity_id].last_changed).strftime(input_time_format)
    }}\n{% endif %}\n"
  notification_title: '{{ device_name }}: Doorbell Ring'
  notification_tag: '{{ notification_channel.lower().replace('' '', ''-'') }}'
  notification_message: '{{ device_name }} was rung{% if trigger_time != None %} at
    {{ trigger_time }}{% endif %}.'
  notification_image: /api/unifiprotect/thumbnail/{{ config_entry_id(entity_id) }}/{{
    event_id }}
  notification_url: "{% if lovelace_view == \"\" %}\n  None\n{% else %}\n  {{ lovelace_view
    }}\n{% endif %}\n"
  unlock_text: '{% if lock_entity_id.startswith(''cover'') %}Open Gate{% else %}Unlock
    Door{% endif %}'
  unlock_service: '{% if lock_entity_id.startswith(''cover'') %}cover.open_cover{%
    else %}lock.unlock{% endif %}'
  unlock_action: unlock-ring-{{ lock_entity_id }}
  silence_action: silence-ring-{{ entity_id }}
  tts_action: tts-ring-{{ input_doorbell }}
  lock_tts_enabled: '{{ input_tts_target != '''' and input_lock_tts != '''' and media_entity_id
    != None }}'
  wait_tts_enabled: '{{ input_tts_target != '''' and input_wait_tts != '''' and media_entity_id
    != None }}'
trigger:
- platform: state
  entity_id: !input doorbell_sensor
  from: 'off'
  to: 'on'
action:
- service: '{{ input_notify_target_app }}'
  data:
    message: '{{ notification_message }}'
    title: '{{ notification_title }}'
    data:
      tag: '{{ notification_tag }}'
      channel: '{{ notification_channel }}'
      ttl: 0
      priority: high
      alert_once: "{% if tag != \"\" %}\n  true\n{% else %}\n  false\n{% endif %}\n"
      time-sensitive: 1
      image: '{{ notification_image }}'
      entity_id: '{{ camera_entity_id }}'
      actions: '[{% if notification_url != None %} { "action": "URI", "title": "Open
        Camera", "uri": "{{ notification_url }}" }, {% endif %} {% if lock_entity_id
        != "" %} { "action": "{{ unlock_action }}", "title": "{{ unlock_text }}" },
        {% endif %} {% if wait_tts_enabled %} { "action": "{{ tts_action }}", "title":
        "Respond" }, {% endif %} {% if input_silence_timer > 0 %} { "action": "{{
        silence_action }}", "title": "Silence", "destructive": True }, {% endif %}]

        '
- choose:
  - conditions:
    - condition: template
      value_template: '{{ input_video_cutoff > 0 }}'
    sequence:
    - service: '{{ input_notify_target_app }}'
      data:
        message: '{{ notification_message }}'
        title: '{{ notification_title }}'
        data:
          tag: '{{ notification_tag }}'
          channel: '{{ notification_channel }}'
          ttl: 0
          priority: high
          alert_once: "{% if tag != \"\" %}\n  true\n{% else %}\n  false\n{% endif
            %}\n"
          time-sensitive: 1
          image: '{{ notification_image }}'
          video: /api/unifiprotect/video/{{ config_entry_id(entity_id) }}/{{ entity_id
            }}/{{ (as_datetime(video_end) - timedelta(seconds=input_video_cutoff)).isoformat()
            }}/{{ video_end }}
          entity_id: '{{ camera_entity_id }}'
          actions: '[{% if notification_url != None %} { "action": "URI", "title":
            "Open Camera", "uri": "{{ notification_url }}" }, {% endif %} {% if lock_entity_id
            != "" %} { "action": "{{ unlock_action }}", "title": "{{ unlock_text }}"
            }, {% endif %} {% if wait_tts_enabled %} { "action": "{{ tts_action }}",
            "title": "Respond" }, {% endif %} {% if input_silence_timer > 0 %} { "action":
            "{{ silence_action }}", "title": "Silence", "destructive": True }, {%
            endif %}]

            '
- wait_for_trigger:
  - platform: event
    event_type: mobile_app_notification_action
    event_data:
      action: '{{ silence_action }}'
  - platform: event
    event_type: mobile_app_notification_action
    event_data:
      action: '{{ unlock_action }}'
  - platform: event
    event_type: mobile_app_notification_action
    event_data:
      action: '{{ tts_action }}'
  - platform: event
    event_type: mobile_app_notification_cleared
    event_data:
      message: '{{ notification_message }}'
  timeout:
    seconds: '{{ input_cooldown }}'
  continue_on_timeout: false
- choose:
  - conditions:
    - condition: template
      value_template: '{{ wait.trigger.platform == ''event'' and wait.trigger.event.event_type
        == ''mobile_app_notification_action'' and wait.trigger.event.data.action ==
        silence_action }}'
    sequence:
    - delay:
        minutes: '{{ input_silence_timer }}'
  - conditions:
    - condition: template
      value_template: '{{ wait.trigger.platform == ''event'' and wait.trigger.event.event_type
        == ''mobile_app_notification_action'' and wait.trigger.event.data.action ==
        unlock_action }}'
    sequence:
    - service: '{{ unlock_service }}'
      data:
        entity_id: '{{ lock_entity_id }}'
    - choose:
      - conditions: '{{ lock_tts_enabled }}'
        sequence:
        - service: '{{ input_tts_target }}'
          data:
            entity_id: '{{ media_entity_id }}'
            message: '{{ input_lock_tts }}'
  - conditions:
    - condition: template
      value_template: '{{ wait.trigger.platform == ''event'' and wait.trigger.event.event_type
        == ''mobile_app_notification_action'' and wait.trigger.event.data.action ==
        tts_action }}'
    sequence:
    - service: '{{ input_tts_target }}'
      data:
        entity_id: '{{ media_entity_id }}'
        message: '{{ input_wait_tts }}'
  - conditions:
    - condition: template
      value_template: '{{ wait.trigger.platform == ''event'' and wait.trigger.event.event_type
        == ''mobile_app_notification_cleared'' }}'
    sequence:
    - delay:
        seconds: '{{ max([input_cooldown - (wait.trigger.event.time_fired - as_datetime(video_end)).total_seconds(),
          5]) }}'

2 Likes

Smart Motion Notification Events (notification_smart_motion_event.yaml):

blueprint:
  name: UniFi Protect Motion / Smart Detection Notifications
  domain: automation
  source_url: https://raw.githubusercontent.com/AngellusMortis/unifiprotect_blueprints/main/blueprints/automation/unifiprotect/notification_smart_motion_event.yaml
  description: "## UniFi Protect Motion / Smart Detection Notifications\n\nThis blueprint
    will send push notifications to a Home Assistant mobile app when a camera detections
    motion or a\nsmart detection.\n\n### Required Settings\n\n  - UniFi Protect Detection
    Sensor\n\n### Optional Settings\n\n  - Notification target for the [mobile app
    notification target][1].\n  - Presence filter - list of mobile phones or other
    entities that should be within the \"home\" zone\n  - Alarm entity to check arm
    states.\n  - Alarm arm states when the notifications should work. Required if
    alarm entity is selected.\n  - Time formatting strings. Timestamp is injected
    into the notification in case the notification is delay.\n  - Cooldown before
    sending another notification\n  - Silence timer for muting notifications via Actionable
    Notification (docs: [Mobile][2])\n  - Configurable lovelace view from notification\n\n
    \ The presence filter works together with the alarm entity (you can choose presence
    filter or alarm entity, you can choose both or nothing at all).\n\n### Requirements\n\nTo
    take full effect of this automation blueprint, your Home Assistant instance needs
    some setup beforehand.\n\n- An UniFi Protect camera. Only cameras that are capable
    of smart detections (G4, AI or G5 Series cameras) will have objection detection
    sensors.\n- A valid HTTPS certificate and [properly configured external URL][3]\n
    \ - If you are using Home Assistant Cloud, this is already set up for you.\n  -
    If this is not setup correctly, the actionable notifications and attachments will
    not appear in the notifications.\n  - You do not need your _whole_ Home Assistant
    to be publicly accessible. Only the paths `/api/unifiprotect/*` and\n    `/api/webhook/*`
    need to be accessible outside of your network.\n\n[1]: https://companion.home-assistant.io/docs/notifications/notifications-basic#sending-notifications-to-multiple-devices\n[2]:
    https://companion.home-assistant.io/docs/notifications/actionable-notifications/\n[3]:
    https://www.home-assistant.io/docs/configuration/remote/\n"
  input:
    obj_sensor:
      name: Detection Sensor
      description: 'The "Motion/Person/etc. Detected" sensor(s) to use.

        '
      selector:
        entity:
          integration: unifiprotect
          domain:
          - binary_sensor
          multiple: true
    presence_filter:
      name: (Optional) Presence Filter
      description: Only notify if selected presence entity is not "home".
      default: ''
      selector:
        entity:
          domain:
          - device_tracker
          multiple: true
    alarm_entity:
      name: (Optional) Alarm Entity
      default: ''
      description: The alarm entity to monitor for state changes.
      selector:
        entity:
          domain:
          - alarm_control_panel
          multiple: false
    alarm_arm_states:
      name: Alarm Arm States
      description: Select the alarm arm states for which you want to receive notifications.
        Required if an Alarm Entity is set.
      default:
      - armed_away
      - armed_home
      - armed_night
      - armed_vacation
      - armed_custom_bypass
      selector:
        select:
          options:
          - armed_away
          - armed_home
          - armed_night
          - armed_vacation
          - armed_custom_bypass
          multiple: true
          sort: false
          custom_value: false
    notify_target_app:
      name: (Optional) Notification Target (Mobile App)
      description: 'The notification target for mobile apps notifications. Can be
        `notifiy.notify` or any Mobile app notify service (starts with `notify.mobile_app_`).
        https://companion.home-assistant.io/docs/notifications/notifications-basic#sending-notifications-to-multiple-devices

        '
      default: notify.notify
      selector:
        text: {}
    channel:
      name: (Optional) Notification Channel
      description: 'Notification channel/tag to use. Will automatically be prepended
        with "Manual " if action is triggered manually. https://companion.home-assistant.io/docs/notifications/notifications-basic#notification-channels

        '
      default: Smart Detection
      selector:
        text: {}
    time_format:
      name: (Optional) Time Format String
      description: 'Python datetime format code string for the event trigger time.
        This string is the actual time the doorbell event was triggered in case the
        automation or notification is delayed. Manual triggers will cause this to
        always be the time of the previous event. https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes

        '
      default: '%I:%M %p'
      selector:
        entity: {}
    cooldown:
      name: (Optional) Cooldown
      description: 'Delay before sending another notification for this camera after
        the last event. Is also the interval you have to respond to actions in notification.

        '
      default: 120
      selector:
        number:
          max: 300.0
          min: 0.0
          unit_of_measurement: seconds
          mode: slider
          step: 1.0
    silence_timer:
      name: (Optional) Silence Notifications
      description: 'How long to silence notifications for this camera when requested
        as part of the actionable notification. The time interval you have to respond
        to the slient action is controlled by "Cooldown". Short Cooldown timers may
        prevent you from silencing.

        '
      default: 30
      selector:
        number:
          max: 300.0
          min: 0.0
          unit_of_measurement: minutes
          mode: slider
          step: 1.0
    lovelace_view:
      name: (Optional) Lovelace View
      description: 'Home Assistant Lovelace view to open when clicking notification.

        If left blank, URI Notification actions will not be generated.

        '
      default: ''
      selector:
        text: {}
    debug_event_id:
      name: (Optional) Debug Event ID
      description: 'Debug Event ID for UniFi Protect to use for when manually triggering
        automation. Will be used to generate a thumbnail for testing notifications.

        '
      default: ''
      selector:
        text: {}
mode: single
max_exceeded: silent
variables:
  input_obj: !input obj_sensor
  input_channel: !input channel
  input_lovelace_view: !input lovelace_view
  input_notify_target_app: !input notify_target_app
  input_silence_timer: !input silence_timer
  input_time_format: !input time_format
  input_presence_filter: !input presence_filter
  input_alarm_entity: !input alarm_entity
  input_alarm_arm_states: !input alarm_arm_states
  input_debug_event_id: !input debug_event_id
  input_cooldown: !input cooldown
  lovelace_view: '{{ input_lovelace_view | trim }}'
  is_manual: '{{ ''from_state'' not in trigger }}'
  entity_id: '{% if is_manual %}{{ input_obj[0] }}{% else %}{{ trigger.entity_id }}{%
    endif %}'
  entity_name: '{{ state_attr(entity_id, ''friendly_name'') }}'
  device_id: '{{ device_id(entity_id) }}'
  camera_entities: '[{% for eid in device_entities(device_id) %}{%if eid.startswith(''camera'')
    and not ''package'' in eid and not is_state(eid, ''unavailable'') %}"{{ eid }}",{%
    endif %}{% endfor %}]'
  camera_entity_id: '{{ camera_entities | default([None]) | first }}'
  event_id: '{% if is_manual %}{{ input_debug_event_id }}{% else %}{{ state_attr(entity_id,
    ''event_id'') }}{% endif %}'
  video_start: '{{ states[entity_id].last_changed.isoformat() }}'
  trigger_time: "{% if states[entity_id] == None %}\n  None\n{% else %}\n  {{ as_local(states[entity_id].last_changed).strftime(input_time_format)
    }}\n{% endif %}\n"
  notification_channel: "{% if is_manual %}\n  Manual {{ input_channel }}\n{% else
    %}\n  {{ input_channel }}\n{% endif %}\n"
  notification_title: '{{ entity_name }}'
  notification_tag: '{{ notification_channel.lower().replace('' '', ''-'') }}'
  notification_message: '{{ entity_name }}{% if trigger_time != None %} at {{ trigger_time
    }}{% endif %}.'
  notification_image: /api/unifiprotect/thumbnail/{{ config_entry_id(entity_id) }}/{{
    event_id }}
  notification_url: "{% if lovelace_view == \"\" %}\n  None\n{% else %}\n  {{ lovelace_view
    }}\n{% endif %}\n"
  silence_action: silence-smart-{{ entity_id }}
trigger:
- platform: state
  entity_id: !input obj_sensor
  from: 'off'
  to: 'on'
condition:
  condition: and
  conditions:
  - condition: or
    conditions:
    - condition: template
      value_template: '{{ input_alarm_entity is not defined or input_alarm_entity
        == '''' }}'
    - condition: and
      conditions:
      - condition: template
        value_template: '{{ input_alarm_entity is defined and input_alarm_entity !=
          '''' }}'
      - condition: template
        value_template: '{{ input_alarm_arm_states is defined and input_alarm_arm_states
          | length > 0 }}'
      - condition: template
        value_template: '{{ states(input_alarm_entity) in input_alarm_arm_states }}'
  - condition: or
    conditions:
    - condition: template
      value_template: '{{ input_presence_filter is not defined or input_presence_filter
        == '''' }}'
    - condition: template
      value_template: '{{ (input_presence_filter | select(''is_state'', ''home'')
        | list | count) == 0 }}'
action:
- service: '{{ input_notify_target_app }}'
  data:
    message: '{{ notification_message }}'
    title: '{{ notification_title }}'
    data:
      tag: '{{ notification_tag }}'
      channel: '{{ notification_channel }}'
      ttl: 0
      priority: high
      alert_once: "{% if tag != \"\" %}\n  true\n{% else %}\n  false\n{% endif %}\n"
      time-sensitive: 1
      image: '{{ notification_image }}'
      entity_id: '{{ camera_entity_id }}'
      actions: '[{% if notification_url != None %} { "action": "URI", "title": "Open
        Camera", "uri": "{{ notification_url }}" }, {% endif %} {% if input_silence_timer
        > 0 %} { "action": "{{ silence_action }}", "title": "Silence", "destructive":
        True }, {% endif %}]

        '
- wait_for_trigger:
  - platform: event
    event_type: mobile_app_notification_action
    event_data:
      action: '{{ silence_action }}'
  - platform: event
    event_type: mobile_app_notification_cleared
    event_data:
      message: '{{ notification_message }}'
  - platform: state
    entity_id: !input obj_sensor
    to: 'off'
  timeout:
    seconds: '{{ input_cooldown }}'
  continue_on_timeout: false
- choose:
  - conditions:
    - condition: template
      value_template: '{{ wait.trigger.platform == ''state'' }}'
    sequence:
    - service: '{{ input_notify_target_app }}'
      data:
        message: '{{ notification_message }}'
        title: '{{ notification_title }}'
        data:
          tag: '{{ notification_tag }}'
          channel: '{{ notification_channel }}'
          ttl: 0
          priority: high
          alert_once: "{% if tag != \"\" %}\n  true\n{% else %}\n  false\n{% endif
            %}\n"
          time-sensitive: 1
          image: '{{ notification_image }}'
          video: /api/unifiprotect/video/{{ config_entry_id(entity_id) }}/{{ entity_id
            }}/{{ video_start }}/{{ states[entity_id].last_changed.isoformat() }}
          actions: '[{% if notification_url != None %} { "action": "URI", "title":
            "Open Camera", "uri": "{{ notification_url }}" }, {% endif %} {% if input_silence_timer
            > 0 %} { "action": "{{ silence_action }}", "title": "Silence", "destructive":
            True }, {% endif %}]

            '
    - wait_for_trigger:
      - platform: event
        event_type: mobile_app_notification_action
        event_data:
          action: '{{ silence_action }}'
      timeout:
        seconds: '{{ max([input_cooldown - (states[entity_id].last_changed - as_datetime(video_start)).total_seconds(),
          5]) }}'
      continue_on_timeout: false
  - conditions:
    - condition: template
      value_template: '{{ wait.trigger.platform == ''event'' and wait.trigger.event.event_type
        == ''mobile_app_notification_action'' }}'
    sequence:
    - delay:
        minutes: '{{ input_silence_timer }}'
  - conditions:
    - condition: template
      value_template: '{{ wait.trigger.platform == ''event'' and wait.trigger.event.event_type
        == ''mobile_app_notification_cleared'' }}'
    sequence:
    - delay:
        seconds: '{{ max([input_cooldown - (wait.trigger.event.time_fired - as_datetime(video_start)).total_seconds(),
          5]) }}'

3 Likes

License plate smart notifications (notification_smart_licenseplate_event.yaml)

blueprint:
  name: UniFi Protect License Plate Notifications
  domain: automation
  source_url: https://raw.githubusercontent.com/AngellusMortis/unifiprotect_blueprints/main/blueprints/automation/unifiprotect/notification_smart_licenseplate_event.yaml
  description:
    "## UniFi Protect License Plate Notifications\n\nThis blueprint will
    send push notifications to a Home Assistant mobile app when an AI series series
    camera detects\na License Plate.\n\n### Required Settings\n\n  - UniFi Protect
    License Plate Sensor\n\n### Optional Settings\n\n  - Notification target for the
    [mobile app notification target][1].\n  - Time formatting strings. Timestamp is
    injected into the notification in case the notification is delay.\n  - Cooldown
    before sending another notification\n  - Silence timer for muting notifications
    via Actionable Notification (docs: [Mobile][2])\n  - Configurable lovelace view
    from notification\n\n### Requirements\n\nTo take full effect of this automation
    blueprint, your Home Assistant instance needs some setup beforehand.\n\n- An AI
    series UniFi Protect camera capable of detecting license plates (AI Bullet, AI
    Theta and AI DSLR).\n- A valid HTTPS certificate and [properly configured external
    URL][3]\n  - If you are using Home Assistant Cloud, this is already set up for
    you.\n  - If this is not setup correctly, the actionable notifications and attachments
    will not appear in the notifications.\n  - You do not need your _whole_ Home Assistant
    to be publicly accessible. Only the paths `/api/unifiprotect/*` and\n    `/api/webhook/*`
    need to be accessible outside of your network.\n\n[1]: https://companion.home-assistant.io/docs/notifications/notifications-basic#sending-notifications-to-multiple-devices\n[2]:
    https://companion.home-assistant.io/docs/notifications/actionable-notifications/\n[3]:
    https://www.home-assistant.io/docs/configuration/remote/\n"
  input:
    licenseplate_sensor:
      name: License Plate Sensor Entity
      description: 'The "License Plate Detected" sensor(s) to use.

        '
      selector:
        entity:
          integration: unifiprotect
          domain: sensor
          multiple: true
    presence_filter:
      name: (Optional) Presence Filter
      description: Only notify if selected presence entity is not "home".
      default: ""
      selector:
        entity:
          domain: device_tracker
          multiple: true
    notify_target_app:
      name: (Optional) Notification Target (Mobile App)
      description:
        "The notification target for mobile apps notifications. Can be
        `notifiy.notify` or any Mobile app notify service (starts with `notify.mobile_app_`).
        https://companion.home-assistant.io/docs/notifications/notifications-basic#sending-notifications-to-multiple-devices

        "
      default: notify.notify
      selector:
        text: {}
    channel:
      name: (Optional) Notification Channel
      description:
        'Notification channel/tag to use. Will automatically be prepended
        with "Manual " if action is triggered manually. https://companion.home-assistant.io/docs/notifications/notifications-basic#notification-channels

        '
      default: License Plate
      selector:
        text: {}
    time_format:
      name: (Optional) Time Format String
      description:
        "Python datetime format code string for the event trigger time.
        This string is the actual time the doorbell event was triggered in case the
        automation or notification is delayed. Manual triggers will cause this to
        always be the time of the previous event. https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes

        "
      default: "%I:%M %p"
      selector:
        entity: {}
    cooldown:
      name: (Optional) Cooldown
      description:
        "Delay before sending another notification for this camera after
        the last event. Is also the interval you have to respond to actions in notification.

        "
      default: 120
      selector:
        number:
          max: 300.0
          min: 0.0
          unit_of_measurement: seconds
          step: 1.0
          mode: slider
    silence_timer:
      name: (Optional) Silence Notifications
      description:
        'How long to silence notifications for this camera when requested
        as part of the actionable notification. The time interval you have to respond
        to the slient action is controlled by "Cooldown". Short Cooldown timers may
        prevent you from silencing.

        '
      default: 30
      selector:
        number:
          max: 300.0
          min: 0.0
          unit_of_measurement: minutes
          step: 1.0
          mode: slider
    lovelace_view:
      name: (Optional) Lovelace View
      description:
        "Home Assistant Lovelace view to open when clicking notification.

        If left blank, URI Notification actions will not be generated.

        "
      default: ""
      selector:
        text: {}
    debug_license_plate:
      name: (Optional) Debug License Plate
      description: "License Plate to use when manually triggering automation.

        "
      default: ABCD1234
      selector:
        text: {}
    debug_event_id:
      name: (Optional) Debug Event ID
      description:
        "Debug Event ID for UniFi Protect to use for when manually triggering
        automation. Will be used to generate a thumbnail for testing notifications.

        "
      default: ""
      selector:
        text: {}
mode: single
max_exceeded: silent
variables:
  input_licenseplate: !input licenseplate_sensor
  input_channel: !input channel
  input_lovelace_view: !input lovelace_view
  input_notify_target_app: !input notify_target_app
  input_silence_timer: !input silence_timer
  input_time_format: !input time_format
  input_presence_filter: !input presence_filter
  input_debug_license_plate: !input debug_license_plate
  input_debug_event_id: !input debug_event_id
  input_cooldown: !input cooldown
  lovelace_view: "{{ input_lovelace_view | trim }}"
  is_manual: "{{ 'from_state' not in trigger }}"
  entity_id:
    "{% if is_manual %}{{ input_licenseplate[0] }}{% else %}{{ trigger.entity_id
    }}{% endif %}"
  device_id: "{{ device_id(entity_id) }}"
  device_name: "{{ device_attr(device_id, 'name') }}"
  camera_entities:
    '[{% for eid in device_entities(device_id) %}{%if eid.startswith(''camera'')
    and not ''package'' in eid and not is_state(eid, ''unavailable'') %}"{{ eid }}",{%
    endif %}{% endfor %}]'
  camera_entity_id: "{{ camera_entities | default([None]) | first }}"
  license_plate:
    "{% if is_manual %}{{ input_debug_license_plate }}{% else %}{{ states(entity_id)
    }}{% endif %}"
  event_id:
    "{% if is_manual %}{{ input_debug_event_id }}{% else %}{{ state_attr(entity_id,
    'event_id') }}{% endif %}"
  video_start: "{{ states[entity_id].last_changed.isoformat() }}"
  trigger_time:
    "{% if states[entity_id] == None %}\n  None\n{% else %}\n  {{ as_local(states[entity_id].last_changed).strftime(input_time_format)
    }}\n{% endif %}\n"
  notification_channel:
    "{% if is_manual %}\n  Manual {{ input_channel }}\n{% else
    %}\n  {{ input_channel }}\n{% endif %}\n"
  notification_title: "{{ device_name }}: License Plate Detected"
  notification_tag: "{{ notification_channel.lower().replace(' ', '-') }}"
  notification_message:
    License Plate {{ license_plate }} detected by {{ device_name
    }}{% if trigger_time != None %} at {{ trigger_time }}{% endif %}.
  notification_image:
    /api/unifiprotect/thumbnail/{{ config_entry_id(entity_id) }}/{{
    event_id }}
  notification_url:
    "{% if lovelace_view == \"\" %}\n  None\n{% else %}\n  {{ lovelace_view
    }}\n{% endif %}\n"
  silence_action: silence-smart-licenseplate-{{ entity_id }}
trigger:
  - platform: state
    entity_id: !input licenseplate_sensor
    from: none
    not_to: unavailable
condition:
  - "{{ not input_presence_filter or (input_presence_filter | select('is_state', 'home')
    | list | count) == 0 }}"
action:
  - service: "{{ input_notify_target_app }}"
    data:
      message: "{{ notification_message }}"
      title: "{{ notification_title }}"
      data:
        tag: "{{ notification_tag }}"
        channel: "{{ notification_channel }}"
        ttl: 0
        priority: high
        time-sensitive: 1
        image: "{{ notification_image }}"
        entity_id: "{{ camera_entity_id }}"
        actions:
          '[{% if notification_url != None %} { "action": "URI", "title": "Open
          Camera", "uri": "{{ notification_url }}" }, {% endif %} {% if input_silence_timer
          > 0 %} { "action": "{{ silence_action }}", "title": "Silence", "destructive":
          True }, {% endif %}]

          '
  - wait_for_trigger:
      - platform: event
        event_type: mobile_app_notification_action
        event_data:
          action: "{{ silence_action }}"
      - platform: event
        event_type: mobile_app_notification_cleared
        event_data:
          message: "{{ notification_message }}"
      - platform: state
        entity_id: !input licenseplate_sensor
        to: none
    timeout:
      seconds: "{{ input_cooldown }}"
    continue_on_timeout: false
  - choose:
      - conditions:
          - condition: template
            value_template: "{{ wait.trigger.platform == 'state' }}"
        sequence:
          - service: "{{ input_notify_target_app }}"
            data:
              message: "{{ notification_message }}"
              title: "{{ notification_title }}"
              data:
                tag: "{{ notification_tag }}"
                channel: "{{ notification_channel }}"
                ttl: 0
                priority: high
                time-sensitive: 1
                image: "{{ notification_image }}"
                video:
                  /api/unifiprotect/video/{{ config_entry_id(entity_id) }}/{{ entity_id
                  }}/{{ video_start }}/{{ states[entity_id].last_changed.isoformat() }}
                actions:
                  '[{% if notification_url != None %} { "action": "URI", "title":
                  "Open Camera", "uri": "{{ notification_url }}" }, {% endif %} {% if input_silence_timer
                  > 0 %} { "action": "{{ silence_action }}", "title": "Silence", "destructive":
                  True }, {% endif %}]

                  '
          - wait_for_trigger:
              - platform: event
                event_type: mobile_app_notification_action
                event_data:
                  action: "{{ silence_action }}"
            timeout:
              seconds:
                "{{ max([input_cooldown - (states[entity_id].last_changed - as_datetime(video_start)).total_seconds(),
                5]) }}"
            continue_on_timeout: false
      - conditions:
          - condition: template
            value_template:
              "{{ wait.trigger.platform == 'event' and wait.trigger.event.event_type
              == 'mobile_app_notification_action' }}"
        sequence:
          - delay:
              minutes: "{{ input_silence_timer }}"
      - conditions:
          - condition: template
            value_template:
              "{{ wait.trigger.platform == 'event' and wait.trigger.event.event_type
              == 'mobile_app_notification_cleared' }}"
        sequence:
          - delay:
              seconds:
                "{{ max([input_cooldown - (wait.trigger.event.time_fired - as_datetime(video_start)).total_seconds(),
                5]) }}"
2 Likes

Thanks for posting these. So would I just put them as a .ymal file?

Yes, I would suggest putting the individual files into the following location:
/blueprints/automation/AngellusMortis/

I’m not sure the editorialization here is helpful…even with all the public information available on what happened here the high road is always a better choice.

Has anyone been able to get the UniFi Protect Motion / Smart Detection Notifications to send the notification via Telegram? Or have an automation I can re-use?

Hello everyone,

I’ve been getting the following error message for a few days now:

Client error (404): Event thumbnail not found

At first it only happened with the following automation:

blueprint:
  name: UniFi Protect Motion / Smart Detection Notifications by Rockhound
  domain: automation
  source_url: https://raw.githubusercontent.com/AngellusMortis/unifiprotect_blueprints/main/blueprints/automation/unifiprotect/notification_smart_motion_event.yaml
  description: "## UniFi Protect Motion / Smart Detection Notifications\n\nThis blueprint
    will send push notifications to a Home Assistant mobile app when a camera detections
    motion or a\nsmart detection.\n\n### Required Settings\n\n  - UniFi Protect Detection
    Sensor\n\n### Optional Settings\n\n  - Notification target for the [mobile app
    notification target][1].\n  - Presence filter - list of mobile phones or other
    entities that should be within the \"home\" zone\n  - Alarm entity to check arm
    states.\n  - Alarm arm states when the notifications should work. Required if
    alarm entity is selected.\n  - Time formatting strings. Timestamp is injected
    into the notification in case the notification is delay.\n  - Cooldown before
    sending another notification\n  - Silence timer for muting notifications via Actionable
    Notification (docs: [Mobile][2])\n  - Configurable lovelace view from notification\n\n
    \ The presence filter works together with the alarm entity (you can choose presence
    filter or alarm entity, you can choose both or nothing at all).\n\n### Requirements\n\nTo
    take full effect of this automation blueprint, your Home Assistant instance needs
    some setup beforehand.\n\n- An UniFi Protect camera. Only cameras that are capable
    of smart detections (G4, AI or G5 Series cameras) will have objection detection
    sensors.\n- A valid HTTPS certificate and [properly configured external URL][3]\n
    \ - If you are using Home Assistant Cloud, this is already set up for you.\n  -
    If this is not setup correctly, the actionable notifications and attachments will
    not appear in the notifications.\n  - You do not need your _whole_ Home Assistant
    to be publicly accessible. Only the paths `/api/unifiprotect/*` and\n    `/api/webhook/*`
    need to be accessible outside of your network.\n\n[1]: https://companion.home-assistant.io/docs/notifications/notifications-basic#sending-notifications-to-multiple-devices\n[2]:
    https://companion.home-assistant.io/docs/notifications/actionable-notifications/\n[3]:
    https://www.home-assistant.io/docs/configuration/remote/\n"
  input:
    obj_sensor:
      name: Detection Sensor
      description: 'The "Motion/Person/etc. Detected" sensor(s) to use.

        '
      selector:
        entity:
          integration: unifiprotect
          domain:
          - binary_sensor
          multiple: true
    presence_filter:
      name: (Optional) Presence Filter
      description: Only notify if selected presence entity is not "home".
      default: ''
      selector:
        entity:
          domain:
          - device_tracker
          multiple: true
    alarm_entity:
      name: (Optional) Alarm Entity
      default: ''
      description: The alarm entity to monitor for state changes.
      selector:
        entity:
          domain:
          - alarm_control_panel
          multiple: false
    alarm_arm_states:
      name: Alarm Arm States
      description: Select the alarm arm states for which you want to receive notifications.
        Required if an Alarm Entity is set.
      default:
      - armed_away
      - armed_home
      - armed_night
      - armed_vacation
      - armed_custom_bypass
      selector:
        select:
          options:
          - armed_away
          - armed_home
          - armed_night
          - armed_vacation
          - armed_custom_bypass
          multiple: true
          sort: false
          custom_value: false
    notify_target_app:
      name: (Optional) Notification Target (Mobile App)
      description: 'The notification target for mobile apps notifications. Can be
        `notifiy.notify` or any Mobile app notify service (starts with `notify.mobile_app_`).
        https://companion.home-assistant.io/docs/notifications/notifications-basic#sending-notifications-to-multiple-devices

        '
      default: notify.notify
      selector:
        text: {}
    color:
      name: Notification Color (Optional)
      description:
        "Set the color of the notification on your mobile device or TV.

        "
      default: steelblue
      selector:
            select:
              options:
                - steelblue
                - grey
                - black
                - indigo
                - green
                - red
                - cyan
                - teal
                - amber
                - pink
              multiple: false
              custom_value: false
              sort: false
    icon:
      name: Notification Icon (Optional)
      description:
        "Change the icon that displays on the notification. You can enter
        a single icon or create a template like the example given in the dropdown.
        You must include 'mdi:' in the icon name.

        "
      default: mdi:home-assistant
      selector:
        icon: {}
    channel:
      name: (Optional) Notification Channel
      description: 'Notification channel/tag to use. Will automatically be prepended
        with "Manual " if action is triggered manually. https://companion.home-assistant.io/docs/notifications/notifications-basic#notification-channels

        '
      default: Smart Detection
      selector:
        text: {}
    time_format:
      name: (Optional) Time Format String
      description: 'Python datetime format code string for the event trigger time.
        This string is the actual time the doorbell event was triggered in case the
        automation or notification is delayed. Manual triggers will cause this to
        always be the time of the previous event. https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes

        '
      default: "%H:%M"
      selector:
        entity: {}
    cooldown:
      name: (Optional) Cooldown
      description: 'Delay before sending another notification for this camera after
        the last event. Is also the interval you have to respond to actions in notification.

        '
      default: 120
      selector:
        number:
          max: 300.0
          min: 0.0
          unit_of_measurement: seconds
          mode: slider
          step: 1.0
    silence_timer:
      name: (Optional) Silence Notifications
      description: 'How long to silence notifications for this camera when requested
        as part of the actionable notification. The time interval you have to respond
        to the slient action is controlled by "Cooldown". Short Cooldown timers may
        prevent you from silencing.

        '
      default: 60
      selector:
        number:
          max: 300.0
          min: 0.0
          unit_of_measurement: minutes
          mode: slider
          step: 1.0
    lovelace_view:
      name: (Optional) Lovelace View
      description: 'Home Assistant Lovelace view to open when clicking notification.

        If left blank, URI Notification actions will not be generated.

        '
      default: ''
      selector:
        text: {}
    debug_event_id:
      name: (Optional) Debug Event ID
      description: 'Debug Event ID for UniFi Protect to use for when manually triggering
        automation. Will be used to generate a thumbnail for testing notifications.

        '
      default: ''
      selector:
        text: {}
mode: single
max_exceeded: silent
variables:
  input_obj: !input obj_sensor
  input_channel: !input channel
  input_lovelace_view: !input lovelace_view
  input_notify_target_app: !input notify_target_app
  color: !input color
  icon: !input icon
  input_silence_timer: !input silence_timer
  input_time_format: !input time_format
  input_presence_filter: !input presence_filter
  input_alarm_entity: !input alarm_entity
  input_alarm_arm_states: !input alarm_arm_states
  input_debug_event_id: !input debug_event_id
  input_cooldown: !input cooldown
  lovelace_view: '{{ input_lovelace_view | trim }}'
  is_manual: '{{ ''from_state'' not in trigger }}'
  entity_id: '{% if is_manual %}{{ input_obj[0] }}{% else %}{{ trigger.entity_id }}{%
    endif %}'
  entity_name: '{{ state_attr(entity_id, ''friendly_name'') }}'
  device_id: '{{ device_id(entity_id) }}'
  camera_entities: '[{% for eid in device_entities(device_id) %}{%if eid.startswith(''camera'')
    and not ''package'' in eid and not is_state(eid, ''unavailable'') %}"{{ eid }}",{%
    endif %}{% endfor %}]'
  camera_entity_id: '{{ camera_entities | default([None]) | first }}'
  event_id: '{% if is_manual %}{{ input_debug_event_id }}{% else %}{{ state_attr(entity_id,
    ''event_id'') }}{% endif %}'
  video_start: '{{ states[entity_id].last_changed.isoformat() }}'
  trigger_time: "{% if states[entity_id] == None %}\n  None\n{% else %}\n  {{ as_local(states[entity_id].last_changed).strftime(input_time_format)
    }}\n{% endif %}\n"
  notification_channel: "{% if is_manual %}\n  Manual {{ input_channel }}\n{% else
    %}\n  {{ input_channel }}\n{% endif %}\n"
  notification_title: '{{ entity_name }}'
  notification_tag: '{{ notification_channel.lower().replace('' '', ''-'') }}'
  notification_message: '{{ entity_name }}{% if trigger_time != None %} at {{ trigger_time
    }}{% endif %}.'
  notification_image: /api/unifiprotect/thumbnail/{{ config_entry_id(entity_id) }}/{{
    event_id }}
  notification_url: "{% if lovelace_view == \"\" %}\n  None\n{% else %}\n  {{ lovelace_view
    }}\n{% endif %}\n"
  silence_action: silence-smart-{{ entity_id }}
trigger:
- platform: state
  entity_id: !input obj_sensor
  from: 'off'
  to: 'on'
condition:
  condition: and
  conditions:
  - condition: or
    conditions:
    - condition: template
      value_template: '{{ input_alarm_entity is not defined or input_alarm_entity
        == '''' }}'
    - condition: and
      conditions:
      - condition: template
        value_template: '{{ input_alarm_entity is defined and input_alarm_entity !=
          '''' }}'
      - condition: template
        value_template: '{{ input_alarm_arm_states is defined and input_alarm_arm_states
          | length > 0 }}'
      - condition: template
        value_template: '{{ states(input_alarm_entity) in input_alarm_arm_states }}'
  - condition: or
    conditions:
    - condition: template
      value_template: '{{ input_presence_filter is not defined or input_presence_filter
        == '''' }}'
    - condition: template
      value_template: '{{ (input_presence_filter | select(''is_state'', ''home'')
        | list | count) == 0 }}'
action:
- service: '{{ input_notify_target_app }}'
  data:
    message: '{{ notification_message }}'
    title: '{{ notification_title }}'
    data:
      tag: '{{ notification_tag }}'
      channel: '{{ notification_channel }}'
      color: '{{color}}'
      notification_icon: '{{icon}}'
      ttl: 0
      priority: high
      alert_once: "{% if tag != \"\" %}\n  true\n{% else %}\n  false\n{% endif %}\n"
      time-sensitive: 1
      image: '{{ notification_image }}'
      entity_id: '{{ camera_entity_id }}'
      actions: '[{% if notification_url != None %} { "action": "URI", "title": "Open
        Camera", "uri": "{{ notification_url }}" }, {% endif %} {% if input_silence_timer
        > 0 %} { "action": "{{ silence_action }}", "title": "Silence", "destructive":
        True }, {% endif %}]

        '
- wait_for_trigger:
  - platform: event
    event_type: mobile_app_notification_action
    event_data:
      action: '{{ silence_action }}'
  - platform: event
    event_type: mobile_app_notification_cleared
    event_data:
      message: '{{ notification_message }}'
  - platform: state
    entity_id: !input obj_sensor
    to: 'off'
  timeout:
    seconds: '{{ input_cooldown }}'
  continue_on_timeout: false
- choose:
  - conditions:
    - condition: template
      value_template: '{{ wait.trigger.platform == ''state'' }}'
    sequence:
    - service: '{{ input_notify_target_app }}'
      data:
        message: '{{ notification_message }}'
        title: '{{ notification_title }}'
        data:
          tag: '{{ notification_tag }}'
          channel: '{{ notification_channel }}'
          color: '{{color}}'
          notification_icon: '{{icon}}'
          ttl: 0
          priority: high
          alert_once: "{% if tag != \"\" %}\n  true\n{% else %}\n  false\n{% endif
            %}\n"
          time-sensitive: 1
          image: '{{ notification_image }}'
          video: /api/unifiprotect/video/{{ config_entry_id(entity_id) }}/{{ entity_id
            }}/{{ video_start }}/{{ states[entity_id].last_changed.isoformat() }}
          actions: '[{% if notification_url != None %} { "action": "URI", "title":
            "Open Camera", "uri": "{{ notification_url }}" }, {% endif %} {% if input_silence_timer
            > 0 %} { "action": "{{ silence_action }}", "title": "Silence", "destructive":
            True }, {% endif %}]

            '
    - wait_for_trigger:
      - platform: event
        event_type: mobile_app_notification_action
        event_data:
          action: '{{ silence_action }}'
      timeout:
        seconds: '{{ max([input_cooldown - (states[entity_id].last_changed - as_datetime(video_start)).total_seconds(),
          5]) }}'
      continue_on_timeout: false
  - conditions:
    - condition: template
      value_template: '{{ wait.trigger.platform == ''event'' and wait.trigger.event.event_type
        == ''mobile_app_notification_action'' }}'
    sequence:
    - delay:
        minutes: '{{ input_silence_timer }}'
  - conditions:
    - condition: template
      value_template: '{{ wait.trigger.platform == ''event'' and wait.trigger.event.event_type
        == ''mobile_app_notification_cleared'' }}'
    sequence:
    - delay:
        seconds: '{{ max([input_cooldown - (wait.trigger.event.time_fired - as_datetime(video_start)).total_seconds(),
          5]) }}'

After yesterday’s update of Unifi Protect, I no longer have any thumbnail images. The event video still appears with the following automation for the doorbell, but with the first one, neither the thumbnail nor the event video appears:

blueprint:
  name: UniFi Protect Doorbell Ring Notifications by Rockhound
  domain: automation
  source_url: https://raw.githubusercontent.com/AngellusMortis/unifiprotect_blueprints/main/blueprints/automation/unifiprotect/notification_ring_event.yaml
  description: "## UniFi Protect Doorbell Ring Notifications\n\nThis blueprint will
    send push notifications to a Home Assistant mobile app when a doorbell ring is
    detected.\n\n### Required Settings\n\n  - UniFi Protect Doorbell Sensor\n\n###
    Optional Settings\n\n  - Notification target for the [mobile app notification
    target][1].\n  - Cutoff time before ring event for video clips.\n  - Time formatting
    strings. Timestamp is injected into the notification in case the notification
    is delay.\n  - Cooldown before sending another notification\n  - Silence timer
    for muting notifications via Actionable Notification (docs: [Mobile][2])\n  -
    Configurable lovelace view from notification\n\n### Requirements\n\nTo take full
    effect of this automation blueprint, your Home Assistant instance needs some setup
    beforehand.\n\n- An UniFi Protect G4 Doorbell or G4 Doorbell Pro.\n- A valid HTTPS
    certificate and [properly configured external URL][3]\n  - If you are using Home
    Assistant Cloud, this is already set up for you.\n  - If this is not setup correctly,
    the actionable notifications and attachments will not appear in the notifications.\n
    \ - You do not need your _whole_ Home Assistant to be publicly accessible. Only
    the paths `/api/unifiprotect/*` and\n    `/api/webhook/*` need to be accessible
    outside of your network.\n\n[1]: https://companion.home-assistant.io/docs/notifications/notifications-basic#sending-notifications-to-multiple-devices\n[2]:
    https://companion.home-assistant.io/docs/notifications/actionable-notifications/\n[3]:
    https://www.home-assistant.io/docs/configuration/remote/\n"
  input:
    doorbell_sensor:
      name: Doorbell Sensor Entity
      description: 'The "Doorbell" sensor(s) to use.

        '
      selector:
        entity:
          integration: unifiprotect
          domain:
          - binary_sensor
          device_class:
          - occupancy
          multiple: true
    lock_entity:
      name: (Optional) Door Lock or Gate Entity
      description: 'The entity to provide an actionable notification to unlock on
        doorbell ring. The time interval you have to respond to the unlock action
        is controlled by "Cooldown". Short Cooldown timers may prevent you from unlocking
        the door.

        '
      default: ''
      selector:
        entity:
          domain:
          - lock
          - cover
          multiple: false
    tts_target:
      name: (Optional) TTS Service
      description: 'The TTS service you want to use to generate TTS messages https://www.home-assistant.io/integrations/tts/

        '
      default: ''
      selector:
        text: {}
    lock_tts:
      name: (Optional) Unlock TTS message
      description: 'TTS Message for play through doorbell when door is unlocked.

        '
      default: ''
      selector:
        text: {}
    wait_tts:
      name: (Optional) TTS message
      description: 'Adds actionable notification to play TTS message to respond to
        guest. The time interval you have to respond to the TTS action is controlled
        by "Cooldown". Short Cooldown timers may prevent you from sending a TTS message
        the door.

        '
      default: ''
      selector:
        text: {}
    notify_target_app:
      name: (Optional) Notification Target (Mobile App)
      description: 'The notification target for mobile apps notifications. Can be
        `notifiy.notify` or any Mobile app notify service (starts with `notify.mobile_app_`).
        https://companion.home-assistant.io/docs/notifications/notifications-basic#sending-notifications-to-multiple-devices

        '
      default: notify.notify
      selector:
        text: {}
    color:
      name: Notification Color (Optional)
      description:
        "Set the color of the notification on your mobile device or TV.

        "
      default: steelblue
      selector:
            select:
              options:
                - steelblue
                - grey
                - black
                - indigo
                - green
                - red
                - cyan
                - teal
                - amber
                - pink
              multiple: false
              custom_value: false
              sort: false
    icon:
      name: Notification Icon (Optional)
      description:
        "Change the icon that displays on the notification. You can enter
        a single icon or create a template like the example given in the dropdown.
        You must include 'mdi:' in the icon name.

        "
      default: mdi:home-assistant
      selector:
        icon: {}
    channel:
      name: (Optional) Notification Channel
      description: 'Notification channel/tag to use. Will automatically be prepended
        with "Manual " if action is triggered manually. https://companion.home-assistant.io/docs/notifications/notifications-basic#notification-channels

        '
      default: Doorbell
      selector:
        text: {}
    video_cutoff:
      name: (Optional) Video Cutoff
      description: 'Time before the doorbell ring to generate a video for to send.
        Setting to 0 will disable attaching a video clip.

        '
      default: 0
      selector:
        number:
          max: 30.0
          min: 0.0
          unit_of_measurement: seconds
          mode: slider
          step: 1.0
    time_format:
      name: (Optional) Time Format String
      description: 'Python datetime format code string for the event trigger time.
        This string is the actual time the doorbell event was triggered in case the
        automation or notification is delayed. Manual triggers will cause this to
        always be the time of the previous event. https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes

        '
      default: "%H:%M"
      selector:
        entity: {}
    cooldown:
      name: (Optional) Cooldown
      description: 'Delay before sending another notification for this camera after
        the last event. Is also the interval you have to respond to actions in notification.

        '
      default: 120
      selector:
        number:
          max: 300.0
          min: 0.0
          unit_of_measurement: seconds
          mode: slider
          step: 1.0
    silence_timer:
      name: (Optional) Silence Notifications
      description: 'How long to silence notifications for this camera when requested
        as part of the actionable notification. The time interval you have to respond
        to the slient action is controlled by "Cooldown". Short Cooldown timers may
        prevent you from silencing.

        '
      default: 30
      selector:
        number:
          max: 300.0
          min: 0.0
          unit_of_measurement: minutes
          mode: slider
          step: 1.0
    lovelace_view:
      name: (Optional) Lovelace View
      description: 'Home Assistant Lovelace view to open when clicking notification.

        If left blank, URI Notification actions will not be generated.

        '
      default: ''
      selector:
        text: {}
    debug_event_id:
      name: (Optional) Debug Event ID
      description: 'Debug Event ID for UniFi Protect to use for when manually triggering
        automation. Will be used to generate a thumbnail for testing notifications.

        '
      default: ''
      selector:
        text: {}
mode: single
max_exceeded: silent
variables:
  input_doorbell: !input doorbell_sensor
  input_lock_entity: !input lock_entity
  input_lock_tts: !input lock_tts
  input_wait_tts: !input wait_tts
  input_tts_target: !input tts_target
  input_channel: !input channel
  input_lovelace_view: !input lovelace_view
  input_notify_target_app: !input notify_target_app
  color: !input color
  icon: !input icon
  input_silence_timer: !input silence_timer
  input_time_format: !input time_format
  input_debug_event_id: !input debug_event_id
  input_cooldown: !input cooldown
  input_video_cutoff: !input video_cutoff
  lovelace_view: '{{ input_lovelace_view | trim }}'
  is_manual: '{{ ''from_state'' not in trigger }}'
  notification_channel: "{% if is_manual %}\n  Manual {{ input_channel }}\n{% else
    %}\n  {{ input_channel }}\n{% endif %}\n"
  entity_id: '{% if is_manual %}{{ input_doorbell[0] }}{% else %}{{ trigger.entity_id
    }}{% endif %}'
  device_id: '{{ device_id(entity_id) }}'
  device_name: '{{ device_attr(device_id, ''name'') }}'
  camera_entities: '[{% for eid in device_entities(device_id) %}{%if eid.startswith(''camera'')
    and not ''package'' in eid and not is_state(eid, ''unavailable'') %}"{{ eid }}",{%
    endif %}{% endfor %}]'
  camera_entity_id: '{{ camera_entities | default([None]) | first }}'
  lock_entity_id: '{{ input_lock_entity or '''' }}'
  media_entities: '[{% for eid in device_entities(device_id) %}{%if eid.startswith(''media_player'')
    and not is_state(eid, ''unavailable'') %}"{{ eid }}",{% endif %}{% endfor %}]'
  media_entity_id: '{{ media_entities | default([None]) | first }}'
  event_id: '{% if is_manual %}{{ input_debug_event_id }}{% else %}{{ state_attr(entity_id,
    ''event_id'') }}{% endif %}'
  video_end: '{{ states[entity_id].last_changed.isoformat() }}'
  trigger_time: "{% if states[entity_id] == None %}\n  None\n{% else %}\n  {{ as_local(states[entity_id].last_changed).strftime(input_time_format)
    }}\n{% endif %}\n"
  notification_title: '{{ device_name }}: Doorbell Ring'
  notification_tag: '{{ notification_channel.lower().replace('' '', ''-'') }}'
  notification_message: '{{ device_name }} was rung{% if trigger_time != None %} at
    {{ trigger_time }}{% endif %}.'
  notification_image: /api/unifiprotect/thumbnail/{{ config_entry_id(entity_id) }}/{{
    event_id }}
  notification_url: "{% if lovelace_view == \"\" %}\n  None\n{% else %}\n  {{ lovelace_view
    }}\n{% endif %}\n"
  unlock_text: '{% if lock_entity_id.startswith(''cover'') %}Open Gate{% else %}Unlock
    Door{% endif %}'
  unlock_service: '{% if lock_entity_id.startswith(''cover'') %}cover.open_cover{%
    else %}lock.unlock{% endif %}'
  unlock_action: unlock-ring-{{ lock_entity_id }}
  silence_action: silence-ring-{{ entity_id }}
  tts_action: tts-ring-{{ input_doorbell }}
  lock_tts_enabled: '{{ input_tts_target != '''' and input_lock_tts != '''' and media_entity_id
    != None }}'
  wait_tts_enabled: '{{ input_tts_target != '''' and input_wait_tts != '''' and media_entity_id
    != None }}'
trigger:
- platform: state
  entity_id: !input doorbell_sensor
  from: 'off'
  to: 'on'
action:
- service: '{{ input_notify_target_app }}'
  data:
    message: '{{ notification_message }}'
    title: '{{ notification_title }}'
    data:
      tag: '{{ notification_tag }}'
      channel: '{{ notification_channel }}'
      color: "{{color}}"
      notification_icon: "{{icon}}"
      ttl: 0
      priority: high
      alert_once: "{% if tag != \"\" %}\n  true\n{% else %}\n  false\n{% endif %}\n"
      time-sensitive: 1
      image: '{{ notification_image }}'
      entity_id: '{{ camera_entity_id }}'
      actions: '[{% if notification_url != None %} { "action": "URI", "title": "Open
        Camera", "uri": "{{ notification_url }}" }, {% endif %} {% if lock_entity_id
        != "" %} { "action": "{{ unlock_action }}", "title": "{{ unlock_text }}" },
        {% endif %} {% if wait_tts_enabled %} { "action": "{{ tts_action }}", "title":
        "Respond" }, {% endif %} {% if input_silence_timer > 0 %} { "action": "{{
        silence_action }}", "title": "Silence", "destructive": True }, {% endif %}]

        '
- choose:
  - conditions:
    - condition: template
      value_template: '{{ input_video_cutoff > 0 }}'
    sequence:
    - service: '{{ input_notify_target_app }}'
      data:
        message: '{{ notification_message }}'
        title: '{{ notification_title }}'
        data:
          tag: '{{ notification_tag }}'
          channel: '{{ notification_channel }}'
          color: "{{color}}"
          notification_icon: "{{icon}}"
          ttl: 0
          priority: high
          alert_once: "{% if tag != \"\" %}\n  true\n{% else %}\n  false\n{% endif
            %}\n"
          time-sensitive: 1
          image: '{{ notification_image }}'
          video: /api/unifiprotect/video/{{ config_entry_id(entity_id) }}/{{ entity_id
            }}/{{ (as_datetime(video_end) - timedelta(seconds=input_video_cutoff)).isoformat()
            }}/{{ video_end }}
          entity_id: '{{ camera_entity_id }}'
          actions: '[{% if notification_url != None %} { "action": "URI", "title":
            "Open Camera", "uri": "{{ notification_url }}" }, {% endif %} {% if lock_entity_id
            != "" %} { "action": "{{ unlock_action }}", "title": "{{ unlock_text }}"
            }, {% endif %} {% if wait_tts_enabled %} { "action": "{{ tts_action }}",
            "title": "Respond" }, {% endif %} {% if input_silence_timer > 0 %} { "action":
            "{{ silence_action }}", "title": "Silence", "destructive": True }, {%
            endif %}]

            '
- wait_for_trigger:
  - platform: event
    event_type: mobile_app_notification_action
    event_data:
      action: '{{ silence_action }}'
  - platform: event
    event_type: mobile_app_notification_action
    event_data:
      action: '{{ unlock_action }}'
  - platform: event
    event_type: mobile_app_notification_action
    event_data:
      action: '{{ tts_action }}'
  - platform: event
    event_type: mobile_app_notification_cleared
    event_data:
      message: '{{ notification_message }}'
  timeout:
    seconds: '{{ input_cooldown }}'
  continue_on_timeout: false
- choose:
  - conditions:
    - condition: template
      value_template: '{{ wait.trigger.platform == ''event'' and wait.trigger.event.event_type
        == ''mobile_app_notification_action'' and wait.trigger.event.data.action ==
        silence_action }}'
    sequence:
    - delay:
        minutes: '{{ input_silence_timer }}'
  - conditions:
    - condition: template
      value_template: '{{ wait.trigger.platform == ''event'' and wait.trigger.event.event_type
        == ''mobile_app_notification_action'' and wait.trigger.event.data.action ==
        unlock_action }}'
    sequence:
    - service: '{{ unlock_service }}'
      data:
        entity_id: '{{ lock_entity_id }}'
    - choose:
      - conditions: '{{ lock_tts_enabled }}'
        sequence:
        - service: '{{ input_tts_target }}'
          data:
            entity_id: '{{ media_entity_id }}'
            message: '{{ input_lock_tts }}'
  - conditions:
    - condition: template
      value_template: '{{ wait.trigger.platform == ''event'' and wait.trigger.event.event_type
        == ''mobile_app_notification_action'' and wait.trigger.event.data.action ==
        tts_action }}'
    sequence:
    - service: '{{ input_tts_target }}'
      data:
        entity_id: '{{ media_entity_id }}'
        message: '{{ input_wait_tts }}'
  - conditions:
    - condition: template
      value_template: '{{ wait.trigger.platform == ''event'' and wait.trigger.event.event_type
        == ''mobile_app_notification_cleared'' }}'
    sequence:
    - delay:
        seconds: '{{ max([input_cooldown - (wait.trigger.event.time_fired - as_datetime(video_end)).total_seconds(),
          5]) }}'

Does anyone else have this problem?

can anyone help?

Many thanks and greetings

@Rockhound53 I have had similar. The only thing that worked for me was downgrading Unif Protect back to 4.0.33 by SSHing into Unifi, apt-get update and then apt-get install --reinstall --allow-downgrades unifi-protect=4.0.33 -y

@Rockhound53 @Townsmcp I haven’t had much time to dig into this myself but I’m also experiencing this issue. The main source of the issue seems to be changes in how the Person detection is working.
The object detection sensor is working like the how the person detection worked before the upgrade i.e. it turns on as soon as an object is detected and turns off shortly after the object is no longer detected.
The person detect sensor no longer turns on when a person is decked…instead…it quickly toggles on and off once the detection STOPS. This might explain why the video notification never works…it’s trying to send a video of 0 length.
I’ll play around once I have more time but hopefully this is enough for @bdraco to start preliminary investigations into why the changes are occurring with the latest Protect update.

There are at least 2 open issues related to this in GitHub.

Edit: I see what I mentioned above was already being discussed in one of the threads. Should have read them both before testing/posting…lol.

1 Like

This is all working again with Version 5 of Protect.

This blueprint has the people home filter, but what would be great is if there was an alarm filter as an alternative. That would mean you could only get notified if the alarm was “armed away” or something like that. Maybe i should have a go at editing the yaml… its been a while.

There’s already an option for that in the blueprint.

Apologies, I must have an older version. I’ll update with the yaml above

Edit: yep, the versions above were newer than what i already had, updated to those versions

1 Like

Are the snapshot notifications on iOS working for others still using these Blueprints?

I had this “Failed to load attachment” issue last year with one of my cameras as reported above in this thread, but I have yet to find a fix. It seems to have spread to others, making the push notifications from these Blueprints not nearly as useful. I’m wondering if one of the recent UniFi Protect updates changed something (currently on Protect 5.0.51).

I’ve started this new thread on the topic to see if I can find a fix before reverting to dumb-down automations for push alerts from UniFi cameras.

@ziptbm I do get this a few times a day but sometimes the image does come through. I put it down to using Frigate/Double Take and sharing the stream from Scrypted - the blueprint grabs the image direct from the camera and my thinking is concurrent requests for snapshot is why I get the error

1 Like

I am having the same issue, and I can’t understand why sometimes the image (and the video of the detection) shows up and other times it doesn’t.

I also have another automation that doesn’t use the blueprint, and recently stop showing the picture.

description: Uses the API from Unify Protect Integration
triggers:
  - type: turned_on
    device_id: 347fc630b5ff31a1e35b775f1ff0ae80
    entity_id: dfdc3219da63c47152e97426c215c026
    domain: binary_sensor
    for:
      hours: 0
      minutes: 0
      seconds: 0
    trigger: device
conditions: []
actions:
  - action: notify.mobile_app_iphone
    data:
      title: Frontdoor Detection
      message: Person Detected at {{ now().strftime('%H:%M:%S') }}
      data:
        image: >-
          /api/unifiprotect/thumbnail/{{config_entry_id(trigger.entity_id) }}/{{
          state_attr(trigger.entity_id, 'event_id') }}
type or paste code here

I think @Townsmcp is on to something regarding a situation where UniFi Protect is getting hounded for the same image/video multiple times. And it seems like the update of the iOS notification with the video clip might be part of the problem.

So, I modified this UniFi Blueprint by removing the video parts. Now, it seems like I’m getting push notifications with the image clip only and it seems like it’s working more reliably…I’m still testing through to confirm. UPDATE - it seems like every other push alert, the image works. TL;DR - this modified version of the blueprint did not fix it.

blueprint:
  name: UniFi Protect Motion / Smart Detection Notifications - Thumbnail Only
  domain: automation
  source_url: https://raw.githubusercontent.com/AngellusMortis/unifiprotect_blueprints/main/blueprints/automation/unifiprotect/notification_smart_motion_event.yaml
  description: "## UniFi Protect Motion / Smart Detection Notifications\n\nThis blueprint
    will send push notifications to a Home Assistant mobile app when a camera detections
    motion or a\nsmart detection.\n\n### Required Settings\n\n  - UniFi Protect Detection
    Sensor\n\n### Optional Settings\n\n  - Notification target for the [mobile app
    notification target][1].\n  - Presence filter - list of mobile phones or other
    entities that should be within the \"home\" zone\n  - Alarm entity to check arm
    states.\n  - Alarm arm states when the notifications should work. Required if
    alarm entity is selected.\n  - Time formatting strings. Timestamp is injected
    into the notification in case the notification is delay.\n  - Cooldown before
    sending another notification\n  - Silence timer for muting notifications via Actionable
    Notification (docs: [Mobile][2])\n  - Configurable lovelace view from notification\n\n
    \ The presence filter works together with the alarm entity (you can choose presence
    filter or alarm entity, you can choose both or nothing at all).\n\n### Requirements\n\nTo
    take full effect of this automation blueprint, your Home Assistant instance needs
    some setup beforehand.\n\n- An UniFi Protect camera. Only cameras that are capable
    of smart detections (G4, AI or G5 Series cameras) will have objection detection
    sensors.\n- A valid HTTPS certificate and [properly configured external URL][3]\n
    \ - If you are using Home Assistant Cloud, this is already set up for you.\n  -
    If this is not setup correctly, the actionable notifications and attachments will
    not appear in the notifications.\n  - You do not need your _whole_ Home Assistant
    to be publicly accessible. Only the paths `/api/unifiprotect/*` and\n    `/api/webhook/*`
    need to be accessible outside of your network.\n\n[1]: https://companion.home-assistant.io/docs/notifications/notifications-basic#sending-notifications-to-multiple-devices\n[2]:
    https://companion.home-assistant.io/docs/notifications/actionable-notifications/\n[3]:
    https://www.home-assistant.io/docs/configuration/remote/\n"
  input:
    obj_sensor:
      name: Detection Sensor
      description: 'The "Motion/Person/etc. Detected" sensor(s) to use.

        '
      selector:
        entity:
          integration: unifiprotect
          domain:
          - binary_sensor
          multiple: true
    presence_filter:
      name: (Optional) Presence Filter
      description: Only notify if selected presence entity is not "home".
      default: ''
      selector:
        entity:
          domain:
          - device_tracker
          multiple: true
    alarm_entity:
      name: (Optional) Alarm Entity
      default: ''
      description: The alarm entity to monitor for state changes.
      selector:
        entity:
          domain:
          - alarm_control_panel
          multiple: false
    alarm_arm_states:
      name: Alarm Arm States
      description: Select the alarm arm states for which you want to receive notifications.
        Required if an Alarm Entity is set.
      default:
      - armed_away
      - armed_home
      - armed_night
      - armed_vacation
      - armed_custom_bypass
      selector:
        select:
          options:
          - armed_away
          - armed_home
          - armed_night
          - armed_vacation
          - armed_custom_bypass
          multiple: true
          custom_value: false
          sort: false
    notify_target_app:
      name: (Optional) Notification Target (Mobile App)
      description: 'The notification target for mobile apps notifications. Can be
        `notifiy.notify` or any Mobile app notify service (starts with `notify.mobile_app_`).
        https://companion.home-assistant.io/docs/notifications/notifications-basic#sending-notifications-to-multiple-devices

        '
      default: notify.notify
      selector:
        text: {}
    channel:
      name: (Optional) Notification Channel
      description: 'Notification channel/tag to use. Will automatically be prepended
        with "Manual " if action is triggered manually. https://companion.home-assistant.io/docs/notifications/notifications-basic#notification-channels

        '
      default: Smart Detection
      selector:
        text: {}
    time_format:
      name: (Optional) Time Format String
      description: 'Python datetime format code string for the event trigger time.
        This string is the actual time the doorbell event was triggered in case the
        automation or notification is delayed. Manual triggers will cause this to
        always be the time of the previous event. https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes

        '
      default: '%I:%M %p'
      selector:
        entity: {}
    cooldown:
      name: (Optional) Cooldown
      description: 'Delay before sending another notification for this camera after
        the last event. Is also the interval you have to respond to actions in notification.

        '
      default: 120
      selector:
        number:
          max: 300.0
          min: 0.0
          unit_of_measurement: seconds
          step: 1.0
          mode: slider
    silence_timer:
      name: (Optional) Silence Notifications
      description: 'How long to silence notifications for this camera when requested
        as part of the actionable notification. The time interval you have to respond
        to the slient action is controlled by "Cooldown". Short Cooldown timers may
        prevent you from silencing.

        '
      default: 30
      selector:
        number:
          max: 300.0
          min: 0.0
          unit_of_measurement: minutes
          step: 1.0
          mode: slider
    lovelace_view:
      name: (Optional) Lovelace View
      description: 'Home Assistant Lovelace view to open when clicking notification.

        If left blank, URI Notification actions will not be generated.

        '
      default: ''
      selector:
        text: {}
    debug_event_id:
      name: (Optional) Debug Event ID
      description: 'Debug Event ID for UniFi Protect to use for when manually triggering
        automation. Will be used to generate a thumbnail for testing notifications.

        '
      default: ''
      selector:
        text: {}
mode: single
max_exceeded: silent
variables:
  input_obj: !input obj_sensor
  input_channel: !input channel
  input_lovelace_view: !input lovelace_view
  input_notify_target_app: !input notify_target_app
  input_silence_timer: !input silence_timer
  input_time_format: !input time_format
  input_presence_filter: !input presence_filter
  input_alarm_entity: !input alarm_entity
  input_alarm_arm_states: !input alarm_arm_states
  input_debug_event_id: !input debug_event_id
  input_cooldown: !input cooldown
  lovelace_view: '{{ input_lovelace_view | trim }}'
  is_manual: '{{ ''from_state'' not in trigger }}'
  entity_id: '{% if is_manual %}{{ input_obj[0] }}{% else %}{{ trigger.entity_id }}{%
    endif %}'
  entity_name: '{{ state_attr(entity_id, ''friendly_name'') }}'
  device_id: '{{ device_id(entity_id) }}'
  camera_entities: '[{% for eid in device_entities(device_id) %}{%if eid.startswith(''camera'')
    and not ''package'' in eid and not is_state(eid, ''unavailable'') %}"{{ eid }}",{%
    endif %}{% endfor %}]'
  camera_entity_id: '{{ camera_entities | default([None]) | first }}'
  event_id: '{% if is_manual %}{{ input_debug_event_id }}{% else %}{{ state_attr(entity_id,
    ''event_id'') }}{% endif %}'
#  video_start: '{{ states[entity_id].last_changed.isoformat() }}'
  trigger_time: "{% if states[entity_id] == None %}\n  None\n{% else %}\n  {{ as_local(states[entity_id].last_changed).strftime(input_time_format)
    }}\n{% endif %}\n"
  notification_channel: "{% if is_manual %}\n  Manual {{ input_channel }}\n{% else
    %}\n  {{ input_channel }}\n{% endif %}\n"
  notification_title: '{{ entity_name }}'
  notification_tag: '{{ notification_channel.lower().replace('' '', ''-'') }}'
  notification_message: '{{ entity_name }}{% if trigger_time != None %} at {{ trigger_time
    }}{% endif %}.'
  notification_image: /api/unifiprotect/thumbnail/{{ config_entry_id(entity_id) }}/{{
    event_id }}
  notification_url: "{% if lovelace_view == \"\" %}\n  None\n{% else %}\n  {{ lovelace_view
    }}\n{% endif %}\n"
  silence_action: silence-smart-{{ entity_id }}
trigger:
- platform: state
  entity_id: !input obj_sensor
  from: 'off'
  to: 'on'
condition:
  condition: and
  conditions:
  - condition: or
    conditions:
    - condition: template
      value_template: '{{ input_alarm_entity is not defined or input_alarm_entity
        == '''' }}'
    - condition: and
      conditions:
      - condition: template
        value_template: '{{ input_alarm_entity is defined and input_alarm_entity !=
          '''' }}'
      - condition: template
        value_template: '{{ input_alarm_arm_states is defined and input_alarm_arm_states
          | length > 0 }}'
      - condition: template
        value_template: '{{ states(input_alarm_entity) in input_alarm_arm_states }}'
  - condition: or
    conditions:
    - condition: template
      value_template: '{{ input_presence_filter is not defined or input_presence_filter
        == '''' }}'
    - condition: template
      value_template: '{{ (input_presence_filter | select(''is_state'', ''home'')
        | list | count) == 0 }}'
action:
- service: '{{ input_notify_target_app }}'
  data:
    message: '{{ notification_message }}'
    title: '{{ notification_title }}'
    data:
      tag: '{{ notification_tag }}'
      channel: '{{ notification_channel }}'
      ttl: 0
      priority: high
      alert_once: "{% if tag != \"\" %}\n  true\n{% else %}\n  false\n{% endif %}\n"
      time-sensitive: 1
      image: '{{ notification_image }}'
      entity_id: '{{ camera_entity_id }}'
      actions: '[{% if notification_url != None %} { "action": "URI", "title": "Open
        Camera", "uri": "{{ notification_url }}" }, {% endif %} {% if input_silence_timer
        > 0 %} { "action": "{{ silence_action }}", "title": "Silence", "destructive":
        True }, {% endif %}]

        '
- wait_for_trigger:
  - platform: event
    event_type: mobile_app_notification_action
    event_data:
      action: '{{ silence_action }}'
  - platform: event
    event_type: mobile_app_notification_cleared
    event_data:
      message: '{{ notification_message }}'
  - platform: state
    entity_id: !input obj_sensor
    to: 'off'
  timeout:
    seconds: '{{ input_cooldown }}'
  continue_on_timeout: false
- choose:
  - conditions:
    - condition: template
      value_template: '{{ wait.trigger.platform == ''state'' }}'
    sequence:
    - service: '{{ input_notify_target_app }}'
      data:
        message: '{{ notification_message }}'
        title: '{{ notification_title }}'
        data:
          tag: '{{ notification_tag }}'
          channel: '{{ notification_channel }}'
          ttl: 0
          priority: high
          alert_once: "{% if tag != \"\" %}\n  true\n{% else %}\n  false\n{% endif
            %}\n"
          time-sensitive: 1
          image: '{{ notification_image }}'
#          video: /api/unifiprotect/video/{{ config_entry_id(entity_id) }}/{{ entity_id
#            }}/{{ video_start }}/{{ states[entity_id].last_changed.isoformat() }}
          actions: '[{% if notification_url != None %} { "action": "URI", "title":
            "Open Camera", "uri": "{{ notification_url }}" }, {% endif %} {% if input_silence_timer
            > 0 %} { "action": "{{ silence_action }}", "title": "Silence", "destructive":
            True }, {% endif %}]

            '
    - wait_for_trigger:
      - platform: event
        event_type: mobile_app_notification_action
        event_data:
          action: '{{ silence_action }}'
      timeout:
        seconds: '{{ max([input_cooldown - (states[entity_id].last_changed - as_datetime(video_start)).total_seconds(),
          5]) }}'
      continue_on_timeout: false
  - conditions:
    - condition: template
      value_template: '{{ wait.trigger.platform == ''event'' and wait.trigger.event.event_type
        == ''mobile_app_notification_action'' }}'
    sequence:
    - delay:
        minutes: '{{ input_silence_timer }}'
  - conditions:
    - condition: template
      value_template: '{{ wait.trigger.platform == ''event'' and wait.trigger.event.event_type
        == ''mobile_app_notification_cleared'' }}'
    sequence:
    - delay:
        seconds: '{{ max([input_cooldown - (wait.trigger.event.time_fired - as_datetime(video_start)).total_seconds(),
          5]) }}'

And I’ve got a manual automation where it takes a snapshot of the camera as a jpg at the time and sends that…this one seems to have no issues. The only downside is it’s not pulling the exact detection moment from UniFi Protect.

I’m also wondering if there’s a way to leverage the UniFi Protect detections directly from the media-browser. And it’d be awesome if pushing the notification could take me directly to that detection video in the Media Browser of HA…haven’t found anything definitive here yet.

1 Like

Hello everyone,

I’m not really getting anywhere and I hope you can help me:

I customized the blueprint for myself and added a few points (icon, color, group, etc.).

Now I wanted to expand the blueprint so that I could insert the LLM Vision analysis as text. I’ve already added the inputs, but I don’t know exactly when and where I should add the actions:

My blueprint:

blueprint:
  name: UniFi Protect Motion / Smart Detection / LLM Notifications by Rockhound
  domain: automation
  source_url: https://raw.githubusercontent.com/AngellusMortis/unifiprotect_blueprints/main/blueprints/automation/unifiprotect/notification_smart_motion_event.yaml
  description: "## UniFi Protect Motion / Smart Detection Notifications\n\nThis blueprint
    will send push notifications to a Home Assistant mobile app"
  input:
    obj_sensor:
      name: Detection Sensor
      description: 'The "Motion/Person/etc. Detected" sensor(s) to use.

        '
      selector:
        entity:
          integration: unifiprotect
          domain:
          - binary_sensor
          multiple: true
    presence_filter:
      name: (Optional) Presence Filter
      description: Only notify if selected presence entity is not "home".
      default: ''
      selector:
        entity:
          domain:
          - device_tracker
          multiple: true
    alarm_entity:
      name: (Optional) Alarm Entity
      default: ''
      description: The alarm entity to monitor for state changes.
      selector:
        entity:
          domain:
          - alarm_control_panel
          multiple: false
    alarm_arm_states:
      name: Alarm Arm States
      description: Select the alarm arm states for which you want to receive notifications.
        Required if an Alarm Entity is set.
      default:
      - armed_away
      - armed_home
      - armed_night
      - armed_vacation
      - armed_custom_bypass
      selector:
        select:
          options:
          - armed_away
          - armed_home
          - armed_night
          - armed_vacation
          - armed_custom_bypass
          multiple: true
          sort: false
          custom_value: false
    notify_target_app:
      name: (Optional) Notification Target (Mobile App)
      description: 'The notification target for mobile apps notifications. Can be
        `notifiy.notify` or any Mobile app notify service (starts with `notify.mobile_app_`).
        https://companion.home-assistant.io/docs/notifications/notifications-basic#sending-notifications-to-multiple-devices

        '
      default: notify.notify
      selector:
        text: {}
    color:
      name: Notification Color (Optional)
      description:
        "Set the color of the notification on your mobile device or TV.

        "
      default: steelblue
      selector:
            select:
              options:
                - steelblue
                - grey
                - black
                - indigo
                - green
                - red
                - cyan
                - teal
                - amber
                - pink
              multiple: false
              custom_value: false
              sort: false
    icon:
      name: Notification Icon (Optional)
      description:
        "Change the icon that displays on the notification. You can enter
        a single icon or create a template like the example given in the dropdown.
        You must include 'mdi:' in the icon name.

        "
      default: mdi:home-assistant
      selector:
        icon: {}
    tag:
      name: tag
      description: "Used to uniquely identify the notification."
      default: ''
      selector:
        text: {}
    group:
      name: group
      description: "Used for grouping different notifications together visually."
      default: ''
      selector:
        text: {}
    channel:
      name: (Optional) Notification Channel
      description: 'Notification channel/tag to use. Will automatically be prepended
        with "Manual " if action is triggered manually. https://companion.home-assistant.io/docs/notifications/notifications-basic#notification-channels

        '
      default: Smart Detection
      selector:
        text: {}
    time_format:
      name: (Optional) Time Format String
      description: 'Python datetime format code string for the event trigger time.
        This string is the actual time the doorbell event was triggered in case the
        automation or notification is delayed. Manual triggers will cause this to
        always be the time of the previous event. https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes

        '
      default: "%H:%M"
      selector:
        entity: {}
    cooldown:
      name: (Optional) Cooldown
      description: 'Delay before sending another notification for this camera after
        the last event. Is also the interval you have to respond to actions in notification.

        '
      default: 120
      selector:
        number:
          max: 300.0
          min: 0.0
          unit_of_measurement: seconds
          mode: slider
          step: 1.0
    silence_timer:
      name: (Optional) Silence Notifications
      description: 'How long to silence notifications for this camera when requested
        as part of the actionable notification. The time interval you have to respond
        to the slient action is controlled by "Cooldown". Short Cooldown timers may
        prevent you from silencing.

        '
      default: 60
      selector:
        number:
          max: 300.0
          min: 0.0
          unit_of_measurement: minutes
          mode: slider
          step: 1.0
    lovelace_view:
      name: (Optional) Lovelace View
      description: 'Home Assistant Lovelace view to open when clicking notification.

        If left blank, URI Notification actions will not be generated.

        '
      default: ''
      selector:
        text: {}
    debug_event_id:
      name: (Optional) Debug Event ID
      description: 'Debug Event ID for UniFi Protect to use for when manually triggering
        automation. Will be used to generate a thumbnail for testing notifications.

        '
      default: ''
      selector:
        text: {}
# Ab hier beginnt die LLM Vision sektion:
    mode:
      name: Mode
      description: Select the mode to use
      selector:
        select:
          options:
          - Frigate
          - Camera
          sort: false
          custom_value: false
          multiple: false
    remember:
      name: Remember
      description: Remember this event so you can ask about it later. Event Calendar
        needs to be configured. If 'important' is set to true, only events classified
        as 'normal' or higher will be remembered.
      default: false
      selector:
        boolean: {}
    camera_entities:
      name: Camera Entities
      description: (Camera and Frigate mode) List of camera entities to monitor
      default: []
      selector:
        entity:
          multiple: true
          filter:
          - domain:
            - camera
    trigger_state:
      name: Trigger State
      description: (Camera mode only) Trigger the automation when your cameras change
        to this state.
      default: recording
      selector:
        text:
          multiline: false
          multiple: false
    motion_sensors:
      name: Motion Sensor
      description: (Camera mode only) Set if your cameras don't change state. Use
        the same order used for camera entities.
      default: []
      selector:
        entity:
          multiple: true
          filter:
          - domain:
            - binary_sensor
    duration:
      name: Duration
      description: (Camera mode only) How long to record before analyzing (in seconds)
      default: 5
      selector:
        number:
          min: 1.0
          max: 60.0
          mode: slider
          step: 1.0
    max_frames:
      name: Max Frames
      description: (Camera and Frigate mode) How many frames to analyze. Picks frames
        with the most movement.
      default: 3
      selector:
        number:
          min: 1.0
          max: 60.0
          mode: slider
          step: 1.0
    provider:
      name: Provider
      description: Provider to use for analysis. See docs for additional information.
      selector:
        config_entry:
          integration: llmvision
    model:
      name: Model
      description: Model to use for the video_analyzer action. Leave blank to automatically
        detect the best model.
      default: gpt-4o-mini
      selector:
        text:
          multiline: false
          multiple: false
    message:
      name: Prompt
      description: Model prompt for the video_analyzer action
      default: Fassen Sie zusammen, was im Kamera-Feed passiert (maximal ein Satz). 
        Beschreiben Sie nicht die Szene! Wenn es eine Person gibt, beschreiben Sie, was sie tut und wie sie aussieht. 
        Wenn sie wie ein Kurier aussehen, erwähnen Sie das! Wenn Autos in der Einfahrt stehen, beschreiben sie diese und nennen die Kennzeichen. 
        Wenn nichts passiert, sagen Sie es.
      selector:
        text:
          multiline: true
          multiple: false
    target_width:
      name: Target Width
      description: Downscale images (uses less tokens and speeds up processing)
      default: 1280
      selector:
        number:
          min: 512.0
          max: 3840.0
          mode: slider
          step: 1.0
    max_tokens:
      name: Maximum Tokens
      description: Maximum number of tokens to generate. Use this to control the length
        of the summaries.
      default: 20
      selector:
        number:
          min: 1.0
          max: 100.0
          mode: slider
          step: 1.0
    detail:
      name: Detail
      description: Detail parameter (OpenAI only)
      default: low
      selector:
        select:
          options:
          - high
          - low
          sort: false
          custom_value: false
          multiple: false
    temperature:
      name: Temperature
      description: Randomness. Lower is more accurate, higher is more creative.
      default: 0.1
      selector:
        number:
          min: 0.1
          max: 1.0
          step: 0.1
          mode: slider
mode: single
max_exceeded: silent
variables:
  input_obj: !input obj_sensor
  input_tag: !input tag
  input_group: !input group
  input_channel: !input channel
  input_lovelace_view: !input lovelace_view
  input_notify_target_app: !input notify_target_app
  color: !input color
  icon: !input icon
  input_silence_timer: !input silence_timer
  input_time_format: !input time_format
  input_presence_filter: !input presence_filter
  input_alarm_entity: !input alarm_entity
  input_alarm_arm_states: !input alarm_arm_states
  input_debug_event_id: !input debug_event_id
  input_cooldown: !input cooldown
  mode: !input mode
  lovelace_view: '{{ input_lovelace_view | trim }}'
  is_manual: '{{ ''from_state'' not in trigger }}'
  entity_id: '{% if is_manual %}{{ input_obj[0] }}{% else %}{{ trigger.entity_id }}{%
    endif %}'
  entity_name: '{{ state_attr(entity_id, ''friendly_name'') }}'
  device_id: '{{ device_id(entity_id) }}'
  camera_entities: '[{% for eid in device_entities(device_id) %}{%if eid.startswith(''camera'')
    and not ''package'' in eid and not is_state(eid, ''unavailable'') %}"{{ eid }}",{%
    endif %}{% endfor %}]'
  camera_entity_id: '{{ camera_entities | default([None]) | first }}'
  event_id: '{% if is_manual %}{{ input_debug_event_id }}{% else %}{{ state_attr(entity_id,
    ''event_id'') }}{% endif %}'
  video_start: '{{ states[entity_id].last_changed.isoformat() }}'
  trigger_time: "{% if states[entity_id] == None %}\n  None\n{% else %}\n  {{ as_local(states[entity_id].last_changed).strftime(input_time_format)
    }}\n{% endif %}\n"
#  notification_channel: "{% if is_manual %}\n  Manual {{ input_channel }}\n{% else
#    %}\n  {{ input_channel }}\n{% endif %}\n"
  notification_title: '{{ entity_name }}'
#  notification_tag: '{{ notification_channel.lower().replace('' '', ''-'') }}'
#  notification_message: '{{ entity_name }}{% if trigger_time != None %} um {{ trigger_time
#    }}{% endif %}.'
  notification_message: 'um {{ trigger_time}} Uhr'
  notification_image: /api/unifiprotect/thumbnail/{{ config_entry_id(entity_id) }}/{{
    event_id }}
  notification_url: "{% if lovelace_view == \"\" %}\n  None\n{% else %}\n  {{ lovelace_view
    }}\n{% endif %}\n"
  silence_action: silence-smart-{{ entity_id }}
trigger:
- platform: state
  entity_id: !input obj_sensor
  from: 'off'
  to: 'on'
condition:
  condition: and
  conditions:
  - condition: or
    conditions:
    - condition: template
      value_template: '{{ input_alarm_entity is not defined or input_alarm_entity
        == '''' }}'
    - condition: and
      conditions:
      - condition: template
        value_template: '{{ input_alarm_entity is defined and input_alarm_entity !=
          '''' }}'
      - condition: template
        value_template: '{{ input_alarm_arm_states is defined and input_alarm_arm_states
          | length > 0 }}'
      - condition: template
        value_template: '{{ states(input_alarm_entity) in input_alarm_arm_states }}'
  - condition: or
    conditions:
    - condition: template
      value_template: '{{ input_presence_filter is not defined or input_presence_filter
        == '''' }}'
    - condition: template
      value_template: '{{ (input_presence_filter | select(''is_state'', ''home'')
        | list | count) == 0 }}'
action:
- service: '{{ input_notify_target_app }}'
  data:
    message: '{{ notification_message }}'
    title: '{{ notification_title }}'
    data:
      tag: '{{ input_tag }}'
      group: '{{ input_group }}'
      channel: '{{ input_channel }}'
      color: '{{color}}'
      notification_icon: '{{icon}}'
      ttl: 0
      priority: high
      alert_once: "{% if tag != \"\" %}\n  true\n{% else %}\n  false\n{% endif %}\n"
      time-sensitive: 1
      image: '{{ notification_image }}'
      entity_id: '{{ camera_entity_id }}'
      actions: '[{% if notification_url != None %} { "action": "URI", "title": "Open
        Camera", "uri": "{{ notification_url }}" }, {% endif %} {% if input_silence_timer
        > 0 %} { "action": "{{ silence_action }}", "title": "Silence", "destructive":
        True }, {% endif %}]

        '
- wait_for_trigger:
  - platform: event
    event_type: mobile_app_notification_action
    event_data:
      action: '{{ silence_action }}'
  - platform: event
    event_type: mobile_app_notification_cleared
    event_data:
      message: '{{ notification_message }}'
  - platform: state
    entity_id: !input obj_sensor
    to: 'off'
  timeout:
    seconds: '{{ input_cooldown }}'
  continue_on_timeout: false
- choose:
  - conditions:
    - condition: template
      value_template: '{{ wait.trigger.platform == ''state'' }}'
    sequence:
    - service: '{{ input_notify_target_app }}'
      data:
        message: '{{ notification_message }}'
        title: '{{ notification_title }}'
        data:
          tag: '{{ input_tag }}'
          group: '{{ input_group }}'
          channel: '{{ input_channel }}'
          color: '{{color}}'
          notification_icon: '{{icon}}'
          ttl: 0
          priority: high
          alert_once: "{% if tag != \"\" %}\n  true\n{% else %}\n  false\n{% endif
            %}\n"
          time-sensitive: 1
          image: '{{ notification_image }}'
          video: /api/unifiprotect/video/{{ config_entry_id(entity_id) }}/{{ entity_id
            }}/{{ video_start }}/{{ states[entity_id].last_changed.isoformat() }}
          actions: '[{% if notification_url != None %} { "action": "URI", "title":
            "Open Camera", "uri": "{{ notification_url }}" }, {% endif %} {% if input_silence_timer
            > 0 %} { "action": "{{ silence_action }}", "title": "Silence", "destructive":
            True }, {% endif %}]

            '
    - wait_for_trigger:
      - platform: event
        event_type: mobile_app_notification_action
        event_data:
          action: '{{ silence_action }}'
      timeout:
        seconds: '{{ max([input_cooldown - (states[entity_id].last_changed - as_datetime(video_start)).total_seconds(),
          5]) }}'
      continue_on_timeout: false
  - conditions:
    - condition: template
      value_template: '{{ wait.trigger.platform == ''event'' and wait.trigger.event.event_type
        == ''mobile_app_notification_action'' }}'
    sequence:
    - delay:
        minutes: '{{ input_silence_timer }}'
  - conditions:
    - condition: template
      value_template: '{{ wait.trigger.platform == ''event'' and wait.trigger.event.event_type
        == ''mobile_app_notification_cleared'' }}'
    sequence:
    - delay:
        seconds: '{{ max([input_cooldown - (wait.trigger.event.time_fired - as_datetime(video_start)).total_seconds(),
          5]) }}'

This is the blueprint I wanted to include in my:

blueprint:
  name: AI Event Summary (LLM Vision v1.3.1)
  author: valentinfrlch
  description: 'AI-powered security event summaries for frigate or camera entities.  Sends
    a notification with a preview to your phone that is updated dynamically when the
    AI summary is available.

    '
  domain: automation
  source_url: https://raw.githubusercontent.com/valentinfrlch/ha-llmvision/refs/heads/main/blueprints/event_summary.yaml
  input:
    mode:
      name: Mode
      description: Select the mode to use
      selector:
        select:
          options:
          - Frigate
          - Camera
          sort: false
          custom_value: false
          multiple: false
    important:
      name: Important (Beta)
      description: 'Use AI to classify events into ''critical'', ''normal'' and ''low''.
        Notifications will only be sent when an event is classified as at least ''normal''.
        For critical events, the notification will be delivered even if ''Do not disturb''
        is on. Use with caution: AI can make mistakes.

        '
      default: false
      selector:
        boolean: {}
    remember:
      name: Remember
      description: Remember this event so you can ask about it later. Event Calendar
        needs to be configured. If 'important' is set to true, only events classified
        as 'normal' or higher will be remembered.
      default: false
      selector:
        boolean: {}
    notify_device:
      name: Notify Device
      description: The devices to send the notification to. Multiple devices may be
        used. Only works with Home Assistant mobile app.
      default: []
      selector:
        device:
          multiple: true
          filter:
          - integration: mobile_app
    camera_entities:
      name: Camera Entities
      description: (Camera and Frigate mode) List of camera entities to monitor
      default: []
      selector:
        entity:
          multiple: true
          filter:
          - domain:
            - camera
    trigger_state:
      name: Trigger State
      description: (Camera mode only) Trigger the automation when your cameras change
        to this state.
      default: recording
      selector:
        text:
          multiline: false
          multiple: false
    motion_sensors:
      name: Motion Sensor
      description: (Camera mode only) Set if your cameras don't change state. Use
        the same order used for camera entities.
      default: []
      selector:
        entity:
          multiple: true
          filter:
          - domain:
            - binary_sensor
    preview_mode:
      name: Preview Mode
      description: (Camera mode only) Choose between a live preview or a snapshot
        of the event
      default: Live Preview
      selector:
        select:
          options:
          - Live Preview
          - Snapshot
          sort: false
          custom_value: false
          multiple: false
    cooldown:
      name: Cooldown
      description: Time in minutes to wait before running again. Recommended for busy
        areas.
      default: 10
      selector:
        number:
          min: 0.0
          max: 60.0
          mode: slider
          step: 1.0
    tap_navigate:
      name: Tap Navigate
      description: Path to navigate to when notification is opened (e.g. /lovelace/cameras)
      default: /lovelace/0
      selector:
        text:
          multiline: false
          multiple: false
    duration:
      name: Duration
      description: (Camera mode only) How long to record before analyzing (in seconds)
      default: 5
      selector:
        number:
          min: 1.0
          max: 60.0
          mode: slider
          step: 1.0
    max_frames:
      name: Max Frames
      description: (Camera and Frigate mode) How many frames to analyze. Picks frames
        with the most movement.
      default: 3
      selector:
        number:
          min: 1.0
          max: 60.0
          mode: slider
          step: 1.0
    provider:
      name: Provider
      description: Provider to use for analysis. See docs for additional information.
      selector:
        config_entry:
          integration: llmvision
    model:
      name: Model
      description: Model to use for the video_analyzer action. Leave blank to automatically
        detect the best model.
      default: gpt-4o-mini
      selector:
        text:
          multiline: false
          multiple: false
    message:
      name: Prompt
      description: Model prompt for the video_analyzer action
      default: Summarize what's happening in the camera feed (one sentence max). Don't
        describe the scene! If there is a person, describe what they're doing and
        what they look like. If they look like a courier mention that! If nothing
        is happening, say so.
      selector:
        text:
          multiline: true
          multiple: false
    target_width:
      name: Target Width
      description: Downscale images (uses less tokens and speeds up processing)
      default: 1280
      selector:
        number:
          min: 512.0
          max: 3840.0
          mode: slider
          step: 1.0
    max_tokens:
      name: Maximum Tokens
      description: Maximum number of tokens to generate. Use this to control the length
        of the summaries.
      default: 20
      selector:
        number:
          min: 1.0
          max: 100.0
          mode: slider
          step: 1.0
    detail:
      name: Detail
      description: Detail parameter (OpenAI only)
      default: low
      selector:
        select:
          options:
          - high
          - low
          sort: false
          custom_value: false
          multiple: false
    temperature:
      name: Temperature
      description: Randomness. Lower is more accurate, higher is more creative.
      default: 0.1
      selector:
        number:
          min: 0.1
          max: 1.0
          step: 0.1
          mode: slider
variables:
  important: !input important
  cooldown: !input cooldown
  mode: !input mode
  preview_mode: !input preview_mode
  notify_devices: !input notify_device
  device_name_map: "{% set ns = namespace(device_names=[]) %} {% for device_id in
    notify_devices %}\n  {% set device_name = device_attr(device_id, \"name\") %}\n
    \ {% set sanitized_name = \"mobile_app_\" + device_name | lower | regex_replace(\"[^a-z0-9_\\-
    ]\", \"\") | replace(\" \", \"_\") | replace(\"-\", \"_\") %}\n  {% set ns.device_names
    = ns.device_names + [sanitized_name] %}\n{% endfor %} {{ ns.device_names }}\n"
  camera_entities_list: !input camera_entities
  motion_sensors_list: !input motion_sensors
  camera_entity: "{% if mode == 'Camera' %}\n  {% if motion_sensors_list and not \"camera\"
    in trigger.entity_id %}\n    {% set index = motion_sensors_list.index(trigger.entity_id)
    %}\n    {{ camera_entities_list[index] }}\n  {% else %}\n    {{ trigger.entity_id
    }}\n  {% endif %}\n{% else %}\n  {{ trigger.payload_json['after']['camera'] }}\n{%
    endif %}\n"
  tag: "{% if mode == 'Frigate' %}\n  {{ trigger.payload_json['after']['camera'] +
    int(as_timestamp(now()))|string }}\n{% else %}\n  {{ camera_entity + int(as_timestamp(now()))|string
    }}\n{% endif %}\n"
  group: "{% if mode == 'Frigate' %}\n  {{ trigger.payload_json['after']['camera']
    }}\n{% else %}\n  {{ camera_entity }}\n{% endif %}\n"
  label: "{% if mode == 'Frigate' %}\n  {{ trigger.payload_json['after']['label']|capitalize
    }} seen\n{% else %}\n  Motion detected\n{% endif %}\n"
  camera: "{% if mode == 'Frigate' %}\n  {{ trigger.payload_json['after']['camera'].replace('_',
    ' ')|capitalize }}\n{% else %}\n  {{ camera_entity.replace(\"camera.\", \"\").replace(\"_\",
    \" \")|capitalize }}\n{% endif %}\n"
  video: "{% if mode == 'Frigate' %}\n  /api/frigate/notifications/{{ trigger.payload_json['after']['id']
    }}/clip.mp4\n{% else %} {% endif %}\n"
  image: "{% if mode == 'Frigate' %}\n  ''\n{% else %}\n  {% if preview_mode == 'Live
    Preview' %}\n    {{ '/api/camera_proxy/' + camera_entity }}\n  {% else %}\n    /local/llmvision/{{camera_entity.replace(\"camera.\",
    \"\")}}_0.jpg\n  {% endif %}\n{% endif %}\n"
  importance_prompt: 'Your job is to classify security events based on cctv footage.
    Your options: "passive" if an event seems unimportant, "time-sensitive" if important
    and "critical" for suspicious events. Use "critical" only for possible burglaries
    and similar events. "time-sensitive" could be a courier at the front door or an
    event of similar importance. Reply with these replies exactly.

    '
trigger:
- platform: mqtt
  topic: frigate/events
  id: frigate_trigger
- platform: state
  entity_id: !input camera_entities
  to: !input trigger_state
  id: camera_trigger
- platform: state
  entity_id: !input motion_sensors
  to: 'on'
  id: motion_sensor_trigger
condition:
- condition: template
  value_template: "{% if mode == 'Frigate' %}\n  {{ trigger.payload_json[\"type\"]
    == \"end\" and (state_attr(this.entity_id, 'last_triggered') is none or (now()
    - state_attr(this.entity_id, 'last_triggered')).total_seconds() / 60 > cooldown)
    and ('camera.' + trigger.payload_json['after']['camera']|lower) in camera_entities_list
    }}\n{% else %}\n  {{ state_attr(this.entity_id, 'last_triggered') is none or (now()
    - state_attr(this.entity_id, 'last_triggered')).total_seconds() / 60 > cooldown
    }}\n{% endif %}\n"
action:
- choose:
  - conditions:
    - condition: template
      value_template: '{{ important }}'
    sequence:
    - alias: Decide Important
      choose:
      - conditions:
        - condition: template
          value_template: '{{ mode == ''Frigate''}}'
        sequence:
        - action: llmvision.image_analyzer
          data:
            image_entity: '{{ [''camera.'' + trigger.payload_json[''after''][''camera'']|lower]
              }}'
            provider: !input provider
            model: !input model
            message: '{{importance_prompt}}'
            include_filename: true
            target_width: 1280
            detail: low
            max_tokens: 3
            temperature: 0.1
          response_variable: importance
      - conditions:
        - condition: template
          value_template: '{{ mode == ''Camera'' }}'
        sequence:
        - action: llmvision.image_analyzer
          data:
            image_entity: '{{[camera_entity]}}'
            provider: !input provider
            model: !input model
            message: '{{importance_prompt}}'
            include_filename: true
            target_width: 1280
            detail: low
            max_tokens: 3
            temperature: 0.1
          response_variable: importance
- choose:
  - conditions:
    - condition: template
      value_template: '{{ importance is defined and importance.response_text|lower
        == ''passive'' }}'
    sequence:
    - stop: Event is not important
- choose:
  - conditions:
    - condition: template
      value_template: '{{ image != '''' or video != '''' }}'
    sequence:
    - alias: Send instant notification to notify devices
      repeat:
        for_each: '{{device_name_map}}'
        sequence:
        - action: notify.{{ repeat.item }}
          data:
            title: '{{ label }}'
            message: '{{camera}}'
            data:
              video: '{{video if video != '''' else None}}'
              image: '{{image if image != '''' else None}}'
              entity_id: '{{camera_entity if mode==''Camera'' and preview_mode==''Live
                Preview''}}'
              url: !input tap_navigate
              clickAction: !input tap_navigate
              tag: '{{tag}}'
              group: '{{group}}'
              interruption-level: '{{importance.response_text|lower if importance
                is defined else ''active''}}'
- alias: Analyze event
  choose:
  - conditions:
    - condition: template
      value_template: '{{ mode == ''Frigate'' }}'
    sequence:
    - action: llmvision.video_analyzer
      data:
        event_id: '{{ trigger.payload_json[''after''][''id''] }}'
        provider: !input provider
        model: !input model
        message: !input message
        remember: !input remember
        include_filename: true
        max_frames: !input max_frames
        target_width: !input target_width
        detail: !input detail
        max_tokens: !input max_tokens
        temperature: !input temperature
      response_variable: response
  - conditions:
    - condition: template
      value_template: '{{ mode == ''Camera'' }}'
    sequence:
    - action: llmvision.stream_analyzer
      data:
        image_entity: '{{[camera_entity]}}'
        duration: !input duration
        provider: !input provider
        model: !input model
        message: !input message
        remember: !input remember
        include_filename: true
        max_frames: !input max_frames
        target_width: !input target_width
        detail: !input detail
        max_tokens: !input max_tokens
        temperature: !input temperature
        expose_images: '{{true if preview_mode == ''Snapshot''}}'
      response_variable: response
- choose:
  - conditions:
    - condition: template
      value_template: '{{ image != '''' or video != '''' }}'
    sequence:
    - alias: Send instant notification to notify devices
      repeat:
        for_each: '{{device_name_map}}'
        sequence:
        - action: notify.{{ repeat.item }}
          data:
            title: '{{ label }}'
            message: '{{response.response_text}}'
            data:
              video: '{{video if video != '''' else None}}'
              image: '{{image if image != '''' else None}}'
              entity_id: '{{camera_entity if mode==''Camera'' and preview_mode==''Live
                Preview''}}'
              url: !input tap_navigate
              clickAction: !input tap_navigate
              tag: '{{tag}}'
              group: '{{group}}'
              interruption-level: passive

I hope someone can help me here!

Best regards