Last active
November 8, 2025 16:26
-
-
Save fmartingr/da951662beef27d08efd15abe02bc708 to your computer and use it in GitHub Desktop.
This file contains hidden or 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: "Repeating Alert Notifications" | |
| description: > | |
| Repeating Alert Notifications ideal for doors, windows, locks, etc | |
| 🚀 Version 2025.11.08.1 | |
| Author : fmartingr | |
| Forked from: https://gist.github.com/Ltek/0d88ed720f635a7579849aac93b9ff93 | |
| 📖 Features: | |
| - Repeat notifications with several user confurible options : max count limit, time delay between alerts, etc | |
| - Bypass entities to suppress notifications | |
| - Customizable alerts with rich notifications | |
| - Automatic notification clearing | |
| 📝 Changes: | |
| - 2025.11.08.1: | |
| - Changed: Selector for notification targets instead of a comma separated text input | |
| - Fixed: Trimmed APNS notification tag to 64 characters | |
| - Fixed: Multiple trigger entity handling | |
| domain: automation | |
| source_url: https://fmartingr.com/homeassistant/blueprints/persistent-notifications.yaml | |
| input: | |
| trigger_entity: | |
| name: "\U0001F916 Triggering Entity" | |
| description: "binary_sensor or input_boolean" | |
| selector: | |
| entity: | |
| domain: | |
| - binary_sensor | |
| - input_boolean | |
| multiple: true | |
| issue_state: | |
| name: "⚠️ Triggering State" | |
| description: "Entity state to trigger the Notification" | |
| default: "on" | |
| selector: | |
| select: | |
| options: | |
| - "on" | |
| - "off" | |
| duration_issue_state: | |
| name: "⏰ Time Delay before Alert is Sent" | |
| description: "How long (in minutes) entity must be in the triggering state before alerting starts. This delay can be used to only notify about sustained issues (e.g., a door left open for 10 minutes)." | |
| default: | |
| minutes: 0 | |
| selector: | |
| duration: | |
| enable_day: true | |
| condition_send_notification: | |
| name: "\U0001F50D Secondary Trigger Condition" | |
| description: "Condition is checked after the Triggering Entity. Useful for custom triggers." | |
| default: [] | |
| selector: | |
| condition: {} | |
| delete_notification: | |
| name: "\U0001F5D1️ Clear Alert when Trigger ends?" | |
| description: "Delete notification when state changes from issue state" | |
| default: true | |
| selector: | |
| boolean: {} | |
| duration_from_issue_state: | |
| name: "⏳ Time Delay before Clearing Alert" | |
| description: "How long the entity must be out of the trigger state before clearing / deleting the notification. This delay can add stability when the issue resolves (e.g., ignoring momentary door closings before clearing the alert)." | |
| default: | |
| seconds: 0 | |
| selector: | |
| duration: | |
| enable_day: true | |
| friendly_name: | |
| name: "\U0001F3F7️ Custom Friendly Name" | |
| description: "Override the Friendly Name variable (Fridge, Snickerdoodle, etc)" | |
| default: "" | |
| selector: | |
| text: {} | |
| notify_services: | |
| name: "📱 Notify devices (mobile_app)" | |
| description: "Choose one or more phones/tablets that use the Companion App." | |
| selector: | |
| device: | |
| filter: | |
| - integration: mobile_app | |
| multiple: true | |
| notification_click_url: | |
| name: "\U0001F517 Open URL with tap" | |
| description: "URL opens when tapping the notification." | |
| default: "/dashboard-ROOM" | |
| selector: | |
| text: {} | |
| notification_title: | |
| name: "\U0001F4E2 Notification Title" | |
| description: "Allows variables. Default is {{ friendly_name }}" | |
| default: "{{ friendly_name }} is Open" | |
| selector: | |
| text: {} | |
| notification_message: | |
| name: "\U0001F4EC Notification Message" | |
| description: 'Allows variables like... {{ as_timestamp(states[trigger.entity_id].last_updated) | timestamp_custom("%I:%M:%S %p") }}' | |
| default: 'Last Change was {{ as_timestamp(states[trigger.entity_id].last_updated) | timestamp_custom("%I:%M:%S %p") }}' | |
| selector: | |
| text: {} | |
| repeat_notification: | |
| name: "\U0001F501 Repeat Alerts" | |
| description: "Repeat at specific time intervals" | |
| default: false | |
| selector: | |
| boolean: {} | |
| max_repeat_count: | |
| name: "🕔 Maximum Repeat Count" | |
| description: "Maximum number repeats for a single notification (0 for unlimited)" | |
| default: 0 | |
| selector: | |
| number: | |
| min: 0 | |
| max: 100 | |
| step: 1 | |
| mode: box | |
| time_between_repeat_notification: | |
| name: "⏳ Delay Between Repeats" | |
| description: "Time between repeat notifications." | |
| default: | |
| minutes: 1 | |
| selector: | |
| duration: | |
| enable_day: true | |
| bypass_entities: | |
| name: "🛡️ Bypass Entities" | |
| description: 'When these Entities are "On" notifications will not be sent' | |
| default: [] | |
| selector: | |
| entity: | |
| domain: | |
| - binary_sensor | |
| - input_boolean | |
| multiple: true | |
| notification_icon_warning: | |
| name: "\U0001F6A8 Notification Icon (Android Only)" | |
| description: "The icon that is shown when the issue is reported." | |
| default: "alert" | |
| selector: | |
| select: | |
| options: | |
| - alert | |
| - alert-circle | |
| - door | |
| - door-open | |
| - motion-sensor | |
| - fridge | |
| - fridge-alert | |
| - home | |
| - home-alert | |
| - home-assistant | |
| - window-closed | |
| - window-open | |
| - window-open-variant | |
| notification_color: | |
| name: "\U0001F308 Notification Color (Android Only)" | |
| description: "The color of the notification." | |
| default: "red" | |
| selector: | |
| select: | |
| options: | |
| - red | |
| - orange | |
| - yellow | |
| - green | |
| - blue | |
| - purple | |
| notification_persistent: | |
| name: "\U0001F4CC Persistent Notification (Android Only)" | |
| description: "Notification cannot be closed manually, stays until the trigger clears. Can be used with Repeats Alerts." | |
| default: false | |
| selector: | |
| boolean: {} | |
| notification_interruption_level: | |
| name: "\U0001F514 Interruption Level (iOS Only)" | |
| description: "Intrusiveness of the notification received." | |
| default: "active" | |
| selector: | |
| select: | |
| options: | |
| - passive | |
| - active | |
| - time-sensitive | |
| - critical | |
| custom_action_issue_state: | |
| name: "⚙️ Custom Action - Entering Trigger State" | |
| description: "Custom actions when trigger occurs" | |
| default: [] | |
| selector: | |
| action: {} | |
| custom_action_from_issue_state: | |
| name: "⚙️ Custom Action - Exiting Trigger State" | |
| description: "Custom actions when trigger ends" | |
| default: [] | |
| selector: | |
| action: {} | |
| mode: restart | |
| max_exceeded: silent | |
| variables: | |
| custom_friendly_name: !input friendly_name | |
| trigger_entity: !input trigger_entity | |
| issue_state: !input issue_state | |
| duration_issue_state: !input duration_issue_state | |
| condition_send_notification: !input condition_send_notification | |
| delete_notification: !input delete_notification | |
| duration_from_issue_state: !input duration_from_issue_state | |
| notify_services: !input notify_services | |
| notification_click_url: !input notification_click_url | |
| notification_title: !input notification_title | |
| notification_message: !input notification_message | |
| repeat_notification: !input repeat_notification | |
| max_repeat_count: !input max_repeat_count | |
| time_between_repeat_notification: !input time_between_repeat_notification | |
| bypass_entities: !input bypass_entities | |
| notification_icon_warning: !input notification_icon_warning | |
| notification_color: !input notification_color | |
| notification_persistent: !input notification_persistent | |
| notification_interruption_level: !input notification_interruption_level | |
| custom_action_issue_state: !input custom_action_issue_state | |
| custom_action_from_issue_state: !input custom_action_from_issue_state | |
| repeat_count: 0 | |
| trigger: | |
| - platform: state | |
| entity_id: !input trigger_entity | |
| to: !input issue_state | |
| for: !input duration_issue_state | |
| id: send_notification | |
| - platform: state | |
| entity_id: !input trigger_entity | |
| from: !input issue_state | |
| for: !input duration_from_issue_state | |
| id: delete_notification | |
| action: | |
| - variables: | |
| # Derive notify.mobile_app_<slugified_device_name> for each selected device | |
| notify_services: !input notify_services | |
| notify_services_list: > | |
| {% set ns = namespace(services=[]) %} | |
| {% for dev in notify_services %} | |
| {% set name = device_attr(dev, 'name') | slugify %} | |
| {% set ns.services = ns.services + ['notify.mobile_app_' ~ name] %} | |
| {% endfor %} | |
| {{ ns.services }} | |
| number_of_notify_services: "{{ notify_services_list | count }}" | |
| base_tag: "{{ trigger.entity_id ~ ':' ~ issue_state }}" | |
| # ASCII-only + <=64 bytes for APNs collapse-id | |
| notification_tag: > | |
| {{ base_tag | slugify | replace('-', '') | truncate(64, True, '') }} | |
| initially_triggered_at: "{{ now() }}" | |
| - choose: | |
| - conditions: | |
| - condition: trigger | |
| id: send_notification | |
| - condition: template | |
| value_template: >- | |
| {% if bypass_entities | length > 0 %} | |
| {{ not (bypass_entities | selectattr('state', 'eq', 'on') | list | count > 0) }} | |
| {% else %} | |
| true | |
| {% endif %} | |
| - condition: !input condition_send_notification | |
| sequence: | |
| - variables: | |
| friendly_name: >- | |
| {% if custom_friendly_name != '' %} | |
| {{ custom_friendly_name }} | |
| {% else %} | |
| {% set expanded_trigger_entity_list = expand(trigger_entity) | |
| | selectattr('state', 'eq', issue_state) | |
| | map(attribute='name') | join(', ') %} | |
| {{ ' & '.join(expanded_trigger_entity_list.rsplit(', ', 1)) }} | |
| {% endif %} | |
| - parallel: | |
| - repeat: | |
| count: "{{ number_of_notify_services }}" | |
| sequence: | |
| - service: "{{ notify_services_list[repeat.index-1] }}" | |
| data: | |
| message: !input notification_message | |
| title: !input notification_title | |
| data: | |
| clickAction: !input notification_click_url | |
| url: !input notification_click_url | |
| tag: "{{ notification_tag }}" | |
| color: !input notification_color | |
| notification_icon: mdi:{{ notification_icon_warning }} | |
| push: | |
| interruption-level: !input notification_interruption_level | |
| persistent: !input notification_persistent | |
| sticky: !input notification_persistent | |
| - choose: [] | |
| default: !input custom_action_issue_state | |
| - if: | |
| - condition: template | |
| value_template: "{{ repeat_notification and (max_repeat_count == 0 or repeat_count < max_repeat_count) and is_state(trigger.entity_id, issue_state) }}" | |
| then: | |
| - variables: | |
| repeat_count: "{{ repeat_count + 1 }}" | |
| - delay: !input time_between_repeat_notification | |
| - repeat: | |
| while: | |
| - "{{ repeat_notification and (max_repeat_count == 0 or repeat_count < max_repeat_count) and is_state(trigger.entity_id, issue_state) }}" | |
| sequence: | |
| - parallel: | |
| - repeat: | |
| count: "{{ number_of_notify_services }}" | |
| sequence: | |
| - service: "{{ notify_services_list[repeat.index-1] }}" | |
| data: | |
| message: !input notification_message | |
| title: !input notification_title | |
| data: | |
| clickAction: !input notification_click_url | |
| url: !input notification_click_url | |
| tag: "{{ notification_tag }}" | |
| color: !input notification_color | |
| notification_icon: mdi:{{ notification_icon_warning }} | |
| push: | |
| interruption-level: !input notification_interruption_level | |
| persistent: !input notification_persistent | |
| sticky: !input notification_persistent | |
| - choose: [] | |
| default: !input custom_action_issue_state | |
| - variables: | |
| repeat_count: "{{ repeat_count + 1 }}" | |
| - delay: !input time_between_repeat_notification | |
| - conditions: | |
| - condition: trigger | |
| id: delete_notification | |
| - condition: template | |
| value_template: "{{ delete_notification }}" | |
| sequence: | |
| - variables: | |
| repeat_count: 0 | |
| - parallel: | |
| - repeat: | |
| count: "{{ number_of_notify_services }}" | |
| sequence: | |
| - service: "{{ notify_services_list[repeat.index-1] }}" | |
| data: | |
| message: clear_notification | |
| data: | |
| tag: "{{ notification_tag }}" | |
| - choose: [] | |
| default: !input custom_action_from_issue_state |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment