UniFi Protect Blueprints

Forgive me if this has been already asked, but I’m looking to:

  1. Use the license plate data as cars come up the driveway (I have a long one) to automatically open the correct garage door based on the vehicle that has the plate.

  2. If it isn’t one of my plates, then send a notification but only then.

  3. Do facial recognition and link that to persons in home assistant to know if the person is home, and to not notify me if it’s one of my family.

Is any of this possible?

1 Like

As I (also) prefer not opening remote access for anything unless really needed, I came up with the idea of handling motion & doorbell notifications through Home Assistant. Very happy to see others already solved this and the blueprints are great!

I do however have a an issue which I cannot really explain nor properly consistently reproduce: I sometimes simply do not get an image preview in the motion trigger notification.

This seems to happen more often when not connected to my local network, but I have setup the correct access to /api/unifiprotect/* and /api/webhook/* via Nginx Proxy Manager and can confirm it works, it just sometimes doesn’t.

If I trigger the automation manually after receiving a notification without a thumbnail, using the ID of that event in the Debug Event ID field… it does show the thumbnail!

Could if be the notification is send/received before the image was actually created and therefor not shown? Any other ideas? Would love to have this working consistently.

Thanks for the quick answer. I have done some more (mostly manual) testing and it seems that even the manual events with a static Debug Event ID will eventually trigger a notification where the image doesn’t appear (anymore):

  • Triggering a manual run with Debug Event ID while my Android phone is connected to local WiFi / VPN always results in showing the image (so far),

  • Disconnecting phone from WiFi / VPN and triggering it again (same setup) 5 minutes after also shows the image.

  • Waiting another 15 min (phone still only on 4G) to trigger once more and the image is not shown…

I now think my assumption of “my firewall/routing works” might be wrong, and the remote notifications only display the image since it is somehow still cached on the device. Only after xx minutes it tries to fetch it again and fails (maybe)?

I will look into my routing setup: I am confident I have outside access to the /api/unifiprotect/ endpoints because when accessing an image directly (remote) it returns a 401: Unauthorized (same when accessing locally) instead of a 403 Forbidden. I assumed this was correct, since I am accessing the url directly without being signed. This also triggers a Login attempt or request with invalid authentication from unifi.localdomain (192.168.0.1). See the log for details. while this doesn’t appear for any of the notification requests.

I realise this might be offtopic because it might be a remote access issue. Am I missing something in the Home Assistant configuration? For instance, do I need to add certain trusted_networks or trusted_proxies (besides my Nginx iProxy)?


EDIT:
Testing if caching might somehow be involved was of course easy to test:

  • Phone on 4G (~10 min after last connected to WiFi) only I triggered motion by standing in front of my G4 Doorbell. Resulted in a fresh notification with corresponding image.
  • 40 minutes later I did the same thing (phone still on 4G only): Resulted in a fresh notification without an image.
  • Triggering manually with hardcoded Device Event ID: no image (this image worked before when on WiFi)
  • Connect Phone to WiFi and triggering manually again with same Device Event ID: image.

It’s either random with a pattern I just think is there, or it really just stops working ~30 minutes after the phone is disconnected from local network. Hard to say.

If it is indeed a timeout issue, is there a way to debug this? Is there a way to set a higher timeout (I assume this is managed by the receiving device, my Android phone).

Figured checking my Nginx Proxy Manager logs might clear things up:

First manual notification the image worked (just after switching from WifI to 4G, also just had Home Assistant App open).

[05/Jan/2024:20:12:37 +0100] - 200 200 - GET https REMOTE_URL"/api/unifiprotect/thumbnail/11696ee...a6f8b9/659551e...e4004c93" [Client REMOTE_IP] [Length 16532] [Gzip -] [Sent-to 192.168.0.20] "Home Assistant/2023.12.4-11898 (Android 14; Pixel 7)" "-"

An hour later, triggered another manual one, and image doesn’t work. I did not try to open the Home Assistant App at all:

[05/Jan/2024:21:13:01 +0100] - - 403 - POST REMOTE_URL "/api/webhook/c4828043d...ce3f2320fb93e" [Client REMOTE_IP] [Length 107] [Gzip 1.36] [Sent-to 192.168.0.20] "Home Assistant/2023.12.4-11898 (Android 14; Pixel 7)" "-"
2024/01/05 21:13:18 [error] 505#505: *16988 access forbidden by rule, client: REMOTE_IP, server: REMOTE_URL, request: "POST /auth/token HTTP/2.0", host: "REMOTE_URL"
[05/Jan/2024:21:13:18 +0100] - - 403 - POST REMOTE_URL "/auth/token" [Client REMOTE_IP] [Length 107] [Gzip 1.36] [Sent-to 192.168.0.20] "Home Assistant/2023.12.4-11898 (Android 14; Pixel 7)" "-"

The /api/unifiprotect/thumbnail/ path is never called (and image doesn’t show up).

So it looks like it needs the /auth/token endpoint after a certain amount of time to refresh authentication (which is still blocked, since I only opened /api/unifiprotect/ and /api/webhook/).

If I allow full remote access to / it immediately starts working again:

[05/Jan/2024:21:32:25 +0100] - - 403 - POST https REMOTE_URL "/api/webhook/c4828043d142a...ce3f2320fb93e" [Client REMOTE_IP] [Length 107] [Gzip 1.36] [Sent-to 192.168.0.20] "Home Assistant/2023.12.4-11898 (Android 14; Pixel 7)" "-"
[05/Jan/2024:21:32:59 +0100] - 200 200 - POST https REMOTE_URL "/auth/token" [Client REMOTE_IP] [Length 233] [Gzip -] [Sent-to 192.168.0.20] "Home Assistant/2023.12.4-11898 (Android 14; Pixel 7)" "-"
[05/Jan/2024:21:33:00 +0100] - 200 200 - GET https REMOTE_URL "/api/unifiprotect/thumbnail/11696eec...a6f8b9/659551e...e4004c93" [Client REMOTE_IP] [Length 16532] [Gzip -] [Sent-to 192.168.0.20] "Home Assistant/2023.12.4-11898 (Android 14; Pixel 7)" "-"

Is this expected?

Yeah I understand this issue is unrelated to these blueprints or how the Unifi Protect Integration works. Glad I got some steps closer to a solution and will look in other places for more information. Thanks!

Hi Angellus. I’ve been using your integration and blueprints since briiis was the origin author. Appreciate your hard work on maintaining this. I was originally on android and the Smart Detections bp has always worked like a charm with the initial picture and then video clips notification updates. I switched to IOS a couple of months ago and my notifications have never been as reliable. A lot of times the initial message does not include the the image. I would usually get the video clip shortly after but even that would occasionally just show a black box. I never had the time to start troubleshooting till this weekend.

I did a reimport of your bp to ensure I had the latest version and started to test manually with the debug event id (didn’t even know that was an option till I updated the bp). Coincidentally I did my testing using the MacBook instead of my iPhone and noticed there was an “error” in the thumbnail for the image notification (never noticed this on my iPhone). When expanded it gave a “Failed to load attachment” error. While searching the forum I saw that another bp as having similar issues and they seemed to found a fix or workaround. I’m not sure if this is the exact same thing I’m experiencing (as well as others who have mentioned similar issues with this bp).

Please see link to forum post below that hopefully is helpful. A few post down they post a potential fix with an update. I also added a pic of the error as seen in MacOs.

1 Like

I think this is similar to the sporadic issues I’ve seen and reported as well. While the camera feed is nice when it works, it often either takes too long to load or fails to load.

Does anyone know what in the BP would specifically need to change to grab the snapshot instead of the video for iOS? It seems like if I really want to see the video, I’ll click through to launch the actual camera.

What are you using as the trigger for this automation to ensure that the eventID is availble when you need it ? I get NONE as the eventID somtimes ?

So, to make sure I’m not missing something, expected behavior with having multiple cameras setup like this would mean that any one triggering will prevent notifications from the others during the cooldown, yeah?

Also, for anyone else looking, you can having the “open camera” action take you directly to the stream. After struggling a bit with figuring this out, I decided to RTFM and found you can just set the URL to the entity ID.

The More Info panel of an entity using entityId:<entity_ID> where <entity_id> is replaced with the entity ID you wish to view. Ex: entityId:sun.sun.

For example, if you set it to

camera.doorbell_high_resolution_channel

It’ll open the app and redirect you to the stream.

I’m now seeing this “failed to load attachment Response could not be serialized, input data was nil or zero length” error in the image/video in the push notifications from my G5 Pro fairly consistently.

Has anyone figured out what this is and how to resolve it?

Thanks for creating this and I’m brand new to home assistant.

I got the blueprint working to send me a push notification of the license plate data and timestamp to my phone.

Now, I’d like to send that data to a zapier webhook

I found instructions on using the restful integration. If I manually test the restful service, the webhook is triggered. But how do I get HA to pass the message from the blue print to restful everytime the blueprint runs?

Sorry for missing something obvious

Thanks.

Hey,

Links are down, can you reupload the Blueprint for License Plate detection.

I believe the dev is taking a hiatus and likely switched the repo to private or took it down.

so because the devs account is suspended until later this year the blueprint cant be installed? is there no work around for this?

The DEV owns the code so no. It’s not because they were suspended, it’s because they opted to either make the GitHub repo private or took it down altogether.

The dev is having a temper tantrum and nuking all their content. If anyone has the blueprint stored locally, please post it here. Otherwise this thread will be deleted.

2 Likes

@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