Skip to content

Instantly share code, notes, and snippets.

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