Last active
August 25, 2024 22:40
-
-
Save benjivesterby/387503085bb63263aa78c2fa2c44ca20 to your computer and use it in GitHub Desktop.
UniFi Protect License Plate Notifications
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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