Skip to content

Instantly share code, notes, and snippets.

@benjivesterby
Last active August 25, 2024 22:39
Show Gist options
  • Save benjivesterby/9921632ad3e964523307280af05c1eeb to your computer and use it in GitHub Desktop.
Save benjivesterby/9921632ad3e964523307280af05c1eeb to your computer and use it in GitHub Desktop.
UniFi Protect Doorbell Ring Notifications
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]) }}'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment