Last active
December 3, 2025 19:46
-
-
Save Ltek/f6e517ac49d3e9ecd58714c2b9afe7d3 to your computer and use it in GitHub Desktop.
Home Assistant Blueprint: Auto-Lock by LTek
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: "🔐 Auto-Lock by LTek" | |
| description: ' | |
| Monitors for doors that just unlocked and Automatically Locks them after a period of time, when the door is closed. | |
| Features: | |
| * Door Sensor state monitoring to ensure door is closed before attempting to lock | |
| * Mobile and UI notifications | |
| * Configurable Delays, Timeouts and Retry Logic (in case lock jams) | |
| * Configurable Disable Schedules. These prevent auto-lock during specific days and time periods. -- just added! | |
| Author: LTek | |
| Version: 2025.12.01.2 | |
| source_url: https://gist.github.com/Ltek/f6e517ac49d3e9ecd58714c2b9afe7d3 | |
| ' | |
| domain: automation | |
| input: | |
| door_lock: | |
| name: "Door Lock" | |
| description: "Lock entity to control" | |
| selector: | |
| entity: | |
| domain: lock | |
| door_sensor: | |
| name: "Door Sensor" | |
| description: "Binary sensor that shows door open/closed state" | |
| selector: | |
| entity: | |
| domain: binary_sensor | |
| counter_variable: | |
| name: "Retry Counter" | |
| description: "Counter helper to track attempts - you must created this manually" | |
| default: "counter.door_lock_retries" | |
| selector: | |
| entity: | |
| domain: counter | |
| bypass_entity: | |
| name: "Bypass Entity" | |
| description: "When this Entity value is On, the automation will not run" | |
| default: "" | |
| selector: | |
| entity: | |
| multiple: false | |
| max_retries: | |
| name: "Maximum Retries" | |
| description: "Number of lock attempts after door is detected to be closed. Helps in case of jams or alignment issues." | |
| default: 3 | |
| selector: | |
| number: | |
| min: 1 | |
| max: 10 | |
| step: 1 | |
| door_close_timeout: | |
| name: "Wait for Door to Close (minutes)" | |
| description: "Automation Timesout (stops running) when this time passes, if door is not closed. Uses Door Sensor set above." | |
| default: 1 | |
| selector: | |
| number: | |
| min: 1 | |
| max: 15 | |
| step: 1 | |
| verification_timeout: | |
| name: "Delay after Closed (minutes)" | |
| description: "Wait to verify door remains closed. Helpful in case you quickly reopen and close the door again after the initial close." | |
| default: 1 | |
| selector: | |
| number: | |
| min: 1 | |
| max: 15 | |
| step: 1 | |
| notification_settings: | |
| name: "📢 Notification Settings" | |
| description: "Configure notification preferences" | |
| collapsed: true | |
| input: | |
| enable_mobile_notifications: | |
| name: "Enable Mobile Notifications" | |
| description: "Send notifications to mobile devices" | |
| default: true | |
| selector: | |
| boolean: {} | |
| notification_device: | |
| name: "Send Notification" | |
| description: "Notification service (e.g., notify.mobile_app_yourphone)" | |
| default: "notify.notify" | |
| selector: | |
| text: | |
| enable_persistent_notifications: | |
| name: "Enable UI Notifications" | |
| description: "Show notifications in Home Assistant" | |
| default: true | |
| selector: | |
| boolean: {} | |
| notify_monitoring_start: | |
| name: "Notify on Monitoring Start" | |
| description: "Send notification when monitoring begins" | |
| default: true | |
| selector: | |
| boolean: {} | |
| notify_timeout: | |
| name: "Notify on Lock Timeout" | |
| description: "Send notification when door fails to close" | |
| default: true | |
| selector: | |
| boolean: {} | |
| notify_max_retries: | |
| name: "Notify on Failure to Lock" | |
| description: "Send notification when max attempts reached and door did not lock" | |
| default: true | |
| selector: | |
| boolean: {} | |
| notify_lock_success: | |
| name: "Notify on Lock Success" | |
| description: "Send notification when door successfully locks" | |
| default: true | |
| selector: | |
| boolean: {} | |
| disable_schedules: | |
| name: "📅 Disable Schedules" | |
| description: "Configure time periods when auto-lock is disabled" | |
| collapsed: true | |
| input: | |
| # Disable Schedule 1 | |
| enable_schedule_1: | |
| name: "Schedule 1 - enable?" | |
| description: "Enable the first disable schedule" | |
| default: false | |
| selector: | |
| boolean: {} | |
| schedule_1_days: | |
| name: "Schedule 1 - Days" | |
| description: "Days when auto-lock is disabled" | |
| default: | |
| - mon | |
| - tue | |
| - wed | |
| - thu | |
| - fri | |
| selector: | |
| select: | |
| multiple: true | |
| options: | |
| - label: "Monday" | |
| value: "mon" | |
| - label: "Tuesday" | |
| value: "tue" | |
| - label: "Wednesday" | |
| value: "wed" | |
| - label: "Thursday" | |
| value: "thu" | |
| - label: "Friday" | |
| value: "fri" | |
| - label: "Saturday" | |
| value: "sat" | |
| - label: "Sunday" | |
| value: "sun" | |
| schedule_1_start_time: | |
| name: "Schedule 1 - Start Time" | |
| description: "Time when disable period begins" | |
| default: "07:00:00" | |
| selector: | |
| time: {} | |
| schedule_1_duration: | |
| name: "Schedule 1 - Duration (minutes)" | |
| description: "How long the disable period lasts" | |
| default: 60 | |
| selector: | |
| number: | |
| min: 1 | |
| max: 1440 | |
| step: 1 | |
| unit_of_measurement: "minutes" | |
| # Disable Schedule 2 | |
| enable_schedule_2: | |
| name: "Schedule 2 - enable?" | |
| description: "Enable the second disable schedule" | |
| default: false | |
| selector: | |
| boolean: {} | |
| schedule_2_days: | |
| name: "Schedule 2 - Days" | |
| description: "Days when auto-lock is disabled" | |
| default: | |
| - sat | |
| - sun | |
| selector: | |
| select: | |
| multiple: true | |
| options: | |
| - label: "Monday" | |
| value: "mon" | |
| - label: "Tuesday" | |
| value: "tue" | |
| - label: "Wednesday" | |
| value: "wed" | |
| - label: "Thursday" | |
| value: "thu" | |
| - label: "Friday" | |
| value: "fri" | |
| - label: "Saturday" | |
| value: "sat" | |
| - label: "Sunday" | |
| value: "sun" | |
| schedule_2_start_time: | |
| name: "Schedule 2 - Start Time" | |
| description: "Time when disable period begins" | |
| default: "09:00:00" | |
| selector: | |
| time: {} | |
| schedule_2_duration: | |
| name: "Schedule 2 - Duration (minutes)" | |
| description: "How long the disable period lasts" | |
| default: 120 | |
| selector: | |
| number: | |
| min: 1 | |
| max: 1440 | |
| step: 1 | |
| unit_of_measurement: "minutes" | |
| # Disable Schedule 3 | |
| enable_schedule_3: | |
| name: "Schedule 3 - enable?" | |
| description: "Enable the third disable schedule" | |
| default: false | |
| selector: | |
| boolean: {} | |
| schedule_3_days: | |
| name: "Schedule 3 - Days" | |
| description: "Days when auto-lock is disabled" | |
| default: | |
| - mon | |
| selector: | |
| select: | |
| multiple: true | |
| options: | |
| - label: "Monday" | |
| value: "mon" | |
| - label: "Tuesday" | |
| value: "tue" | |
| - label: "Wednesday" | |
| value: "wed" | |
| - label: "Thursday" | |
| value: "thu" | |
| - label: "Friday" | |
| value: "fri" | |
| - label: "Saturday" | |
| value: "sat" | |
| - label: "Sunday" | |
| value: "sun" | |
| schedule_3_start_time: | |
| name: "Schedule 3 - Start Time" | |
| description: "Time when disable period begins" | |
| default: "17:00:00" | |
| selector: | |
| time: {} | |
| schedule_3_duration: | |
| name: "Schedule 3 - Duration (minutes)" | |
| description: "How long the disable period lasts" | |
| default: 180 | |
| selector: | |
| number: | |
| min: 1 | |
| max: 1440 | |
| step: 1 | |
| unit_of_measurement: "minutes" | |
| variables: | |
| door_lock: !input door_lock | |
| door_sensor: !input door_sensor | |
| counter_variable: !input counter_variable | |
| max_retries: !input max_retries | |
| door_close_timeout: !input door_close_timeout | |
| verification_timeout: !input verification_timeout | |
| notify_monitoring_start: !input notify_monitoring_start | |
| notify_timeout: !input notify_timeout | |
| notify_max_retries: !input notify_max_retries | |
| notify_lock_success: !input notify_lock_success | |
| enable_mobile_notifications: !input enable_mobile_notifications | |
| enable_persistent_notifications: !input enable_persistent_notifications | |
| notification_device: !input notification_device | |
| bypass_entity: !input bypass_entity | |
| current_retry_count: > | |
| {% set count = states(counter_variable) | int(0) %} | |
| {{ 0 if count < 0 else count }} | |
| valid_notification_service: true | |
| safe_notification_service: "{{ notification_device }}" | |
| # Schedule variables | |
| enable_schedule_1: !input enable_schedule_1 | |
| schedule_1_days: !input schedule_1_days | |
| schedule_1_start_time: !input schedule_1_start_time | |
| schedule_1_duration: !input schedule_1_duration | |
| enable_schedule_2: !input enable_schedule_2 | |
| schedule_2_days: !input schedule_2_days | |
| schedule_2_start_time: !input schedule_2_start_time | |
| schedule_2_duration: !input schedule_2_duration | |
| enable_schedule_3: !input enable_schedule_3 | |
| schedule_3_days: !input schedule_3_days | |
| schedule_3_start_time: !input schedule_3_start_time | |
| schedule_3_duration: !input schedule_3_duration | |
| # Helper to check if current time is within a schedule | |
| in_schedule_1: > | |
| {% if not enable_schedule_1 %} | |
| false | |
| {% else %} | |
| {% set current_day = now().strftime('%a').lower() %} | |
| {% set current_time = now().strftime('%H:%M:%S') %} | |
| {% set start = schedule_1_start_time %} | |
| {% set end_timestamp = as_timestamp(now().replace(hour=start.split(':')[0]|int, minute=start.split(':')[1]|int, second=0)) + (schedule_1_duration * 60) %} | |
| {% set end = end_timestamp | timestamp_custom('%H:%M:%S') %} | |
| {{ current_day in schedule_1_days and current_time >= start and current_time < end }} | |
| {% endif %} | |
| in_schedule_2: > | |
| {% if not enable_schedule_2 %} | |
| false | |
| {% else %} | |
| {% set current_day = now().strftime('%a').lower() %} | |
| {% set current_time = now().strftime('%H:%M:%S') %} | |
| {% set start = schedule_2_start_time %} | |
| {% set end_timestamp = as_timestamp(now().replace(hour=start.split(':')[0]|int, minute=start.split(':')[1]|int, second=0)) + (schedule_2_duration * 60) %} | |
| {% set end = end_timestamp | timestamp_custom('%H:%M:%S') %} | |
| {{ current_day in schedule_2_days and current_time >= start and current_time < end }} | |
| {% endif %} | |
| in_schedule_3: > | |
| {% if not enable_schedule_3 %} | |
| false | |
| {% else %} | |
| {% set current_day = now().strftime('%a').lower() %} | |
| {% set current_time = now().strftime('%H:%M:%S') %} | |
| {% set start = schedule_3_start_time %} | |
| {% set end_timestamp = as_timestamp(now().replace(hour=start.split(':')[0]|int, minute=start.split(':')[1]|int, second=0)) + (schedule_3_duration * 60) %} | |
| {% set end = end_timestamp | timestamp_custom('%H:%M:%S') %} | |
| {{ current_day in schedule_3_days and current_time >= start and current_time < end }} | |
| {% endif %} | |
| trigger: | |
| - platform: state | |
| entity_id: !input door_lock | |
| to: "unlocked" | |
| - platform: state | |
| entity_id: !input door_sensor | |
| to: "on" | |
| condition: | |
| - condition: template | |
| value_template: >- | |
| {% if bypass_entity %} | |
| {{ not is_state(bypass_entity, 'on') }} | |
| {% else %} | |
| true | |
| {% endif %} | |
| # Check if we're NOT in any disable schedule | |
| - condition: template | |
| value_template: >- | |
| {{ not (in_schedule_1 | bool or in_schedule_2 | bool or in_schedule_3 | bool) }} | |
| action: | |
| # Monitoring Start Notification | |
| - if: | |
| - condition: template | |
| value_template: "{{ current_retry_count == 0 and notify_monitoring_start }}" | |
| then: | |
| - if: | |
| - condition: template | |
| value_template: "{{ enable_mobile_notifications }}" | |
| then: | |
| - service: "{{ safe_notification_service }}" | |
| data: | |
| message: "Auto-Lock monitoring {{ state_attr(door_lock, 'friendly_name') }}" | |
| - if: | |
| - condition: template | |
| value_template: "{{ enable_persistent_notifications }}" | |
| then: | |
| - service: persistent_notification.create | |
| data: | |
| title: "Auto-Lock monitoring {{ state_attr(door_lock, 'friendly_name') }}" | |
| message: "" | |
| notification_id: "lock_monitoring_{{ door_lock }}" | |
| # Max Retries Notification | |
| - if: | |
| - condition: template | |
| value_template: "{{ current_retry_count >= max_retries and notify_max_retries }}" | |
| then: | |
| - if: | |
| - condition: template | |
| value_template: "{{ enable_mobile_notifications }}" | |
| then: | |
| - service: "{{ safe_notification_service }}" | |
| data: | |
| message: "Auto-Lock Failed to lock {{ state_attr(door_lock, 'friendly_name') }} after {{ max_retries }} attempts" | |
| - if: | |
| - condition: template | |
| value_template: "{{ enable_persistent_notifications }}" | |
| then: | |
| - service: persistent_notification.create | |
| data: | |
| title: "Auto-Lock Failed to lock {{ state_attr(door_lock, 'friendly_name') }}" | |
| message: "after {{ max_retries }} attempts" | |
| notification_id: "lock_failed_{{ door_lock }}" | |
| - service: counter.reset | |
| target: | |
| entity_id: "{{ counter_variable }}" | |
| # Increment counter | |
| - service: counter.increment | |
| target: | |
| entity_id: "{{ counter_variable }}" | |
| # Wait for door to close | |
| - wait_template: "{{ is_state(door_sensor, 'off') }}" | |
| timeout: | |
| minutes: "{{ door_close_timeout }}" | |
| continue_on_timeout: true | |
| # Timeout Notification | |
| - if: | |
| - condition: state | |
| entity_id: !input door_sensor | |
| state: "on" | |
| - condition: template | |
| value_template: "{{ notify_timeout }}" | |
| then: | |
| - if: | |
| - condition: template | |
| value_template: "{{ enable_mobile_notifications }}" | |
| then: | |
| - service: "{{ safe_notification_service }}" | |
| data: | |
| message: "Auto-Lock Timeout waiting for {{ state_attr(door_sensor, 'friendly_name') }} to close" | |
| - if: | |
| - condition: template | |
| value_template: "{{ enable_persistent_notifications }}" | |
| then: | |
| - service: persistent_notification.create | |
| data: | |
| title: "Auto-Lock Timeout, {{ state_attr(door_sensor, 'friendly_name') }} didn't close in time" | |
| message: "" | |
| notification_id: "door_timeout_{{ door_sensor }}" | |
| - service: automation.trigger | |
| target: | |
| entity_id: "{{ this.entity_id }}" | |
| # Verification period | |
| - wait_for_trigger: | |
| - platform: state | |
| entity_id: !input door_sensor | |
| to: "off" | |
| timeout: | |
| minutes: "{{ verification_timeout }}" | |
| continue_on_timeout: true | |
| # Successful Lock | |
| - if: | |
| - condition: state | |
| entity_id: !input door_sensor | |
| state: "off" | |
| then: | |
| - service: lock.lock | |
| target: | |
| entity_id: !input door_lock | |
| - service: counter.reset | |
| target: | |
| entity_id: "{{ counter_variable }}" | |
| - if: | |
| - condition: template | |
| value_template: "{{ notify_lock_success and enable_mobile_notifications }}" | |
| then: | |
| - service: "{{ safe_notification_service }}" | |
| data: | |
| message: "Auto-Lock locked {{ state_attr(door_lock, 'friendly_name') }} successfully" | |
| - if: | |
| - condition: template | |
| value_template: "{{ notify_lock_success and enable_persistent_notifications }}" | |
| then: | |
| - service: persistent_notification.create | |
| data: | |
| title: "Auto-Lock locked {{ state_attr(door_lock, 'friendly_name') }}" | |
| message: "" | |
| notification_id: "lock_success_{{ door_lock }}" | |
| mode: restart |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment