Skip to content

Instantly share code, notes, and snippets.

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