Skip to content

Instantly share code, notes, and snippets.

@Ltek
Last active December 3, 2025 19:46
Show Gist options
  • Select an option

  • Save Ltek/f6e517ac49d3e9ecd58714c2b9afe7d3 to your computer and use it in GitHub Desktop.

Select an option

Save Ltek/f6e517ac49d3e9ecd58714c2b9afe7d3 to your computer and use it in GitHub Desktop.
Home Assistant Blueprint: Auto-Lock by LTek
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