Skip to content

Instantly share code, notes, and snippets.

@FrankTub
Last active May 17, 2025 18:29
Show Gist options
  • Save FrankTub/ba9af2b147a8b6795d9b93299a82aab1 to your computer and use it in GitHub Desktop.
Save FrankTub/ba9af2b147a8b6795d9b93299a82aab1 to your computer and use it in GitHub Desktop.
Wasp principle for HA
blueprint:
name: Occupancy
description: |
This blueprint implements the 'Wasp in a Box' principle, a method for detecting room occupancy based on motion and door sensors. It was inspired by an AppDaemon app with a similar approach.
You can find more information about this blueprint on the Home Assistant Community: https://community.home-assistant.io/t/occupancy-blueprint/477772
domain: automation
source_url: https://gist.github.com/FrankTub/ba9af2b147a8b6795d9b93299a82aab1
input:
door_sensor:
name: Single Door Sensor or Door Sensor Group
selector:
entity:
filter:
- domain: binary_sensor
- domain: input_boolean
motion_sensor:
name: Single Motion Sensor or Motion Sensor Group
selector:
entity:
filter:
- domain: binary_sensor
- domain: input_boolean
motion_sensor_turn_off_delay:
name: Motion Sensor turn off delay
description: "Time after the motion sensor no longer detects motion to set the occupancy to clear. (Default = 5s)"
default: 5
selector:
number:
mode: box
min: 0
max: 3600
unit_of_measurement: seconds
step: 1.0
door_sensor_turn_off_delay:
name: Door Sensor turn off delay
description: "In order to automatically set the occupancy to clear when the door was opened and left open. This only clears the occupancy when there was no motion detected between opening the door and the period of this turn off delay period. (Default = 15s)"
default: 15
selector:
number:
mode: box
min: 0
max: 3600
unit_of_measurement: seconds
step: 1.0
motion_sensor_delay:
name: Motion Sensor Delay
description: |
The time the motion sensor takes before clearing its detected state. (Default=-1 [Disabled])
It is recommended to add a small buffer to prevent false positives. For example, if your motion sensor has a 10-second delay, set this to 12s.
default: -1
selector:
number:
mode: box
min: -1
max: 3600
unit_of_measurement: seconds
step: 1.0
occupancy_helper:
name: Occupancy Helper (Type input_boolean)
description: This helper tracks occupancy status and can be used as a trigger for automations, such as turning lights on or off.
selector:
entity:
domain: input_boolean
multiple: false
last_motion_helper:
name: Last Motion Helper (Type date and time)
description: This helper logs the last motion detection time to ensure occupancy clears correctly when the door is closed.
selector:
entity:
domain: input_datetime
multiple: false
reset_on_closing_door_after_delay_period:
name: Reset occupancy on closing door after delay period
description: |
Turn off occupancy when the door is closed after the greatest delay period (meaning Motion Sensor Delay + Motion Sensor turn off delay OR Door Sensor turn off delay) with a minimum of 20 seconds after the occupancy was turned on. This can be useful for doors that are not used frequently and prevent guests from doubting if they have to manually turn off a light, e.g. a toilet door. Other scenario where this could be usefull is a room where you don't necessarily close the door while using the room and when you leave the room you typically close the door, e.g. a laundry room.
default: false
selector:
boolean:
variables:
door_sensor: !input door_sensor
motion_sensor: !input motion_sensor
last_motion_helper: !input last_motion_helper
motion_sensor_delay: !input motion_sensor_delay
reset_on_closing_door_after_delay_period: !input reset_on_closing_door_after_delay_period
occupancy_helper: !input occupancy_helper
motion_sensor_turn_off_delay: !input motion_sensor_turn_off_delay
door_sensor_turn_off_delay: !input door_sensor_turn_off_delay
trigger:
- platform: state
entity_id: !input motion_sensor
from: "off"
to: "on"
id: motion
- platform: state
entity_id: !input door_sensor
id: door_opened
from: "off"
to: "on"
- platform: state
entity_id: !input door_sensor
id: door_closed
from: "on"
to: "off"
- platform: state
entity_id: !input motion_sensor
from: "on"
to: "off"
for: !input motion_sensor_turn_off_delay
id: clear
- platform: state
entity_id: !input door_sensor
to: "on"
for: !input door_sensor_turn_off_delay
id: door_left_open
condition: []
action:
- choose:
- conditions:
- condition: trigger
id: motion
sequence:
- service: input_datetime.set_datetime
data:
timestamp: "{{ as_timestamp(now()) }}"
target:
entity_id: !input last_motion_helper
- if:
- condition: state
entity_id: !input occupancy_helper
state: "off"
then:
- service: input_boolean.turn_on
data: {}
target:
entity_id: !input occupancy_helper
- conditions:
- condition: trigger
id: door_opened
sequence:
- if:
- condition: state
entity_id: !input occupancy_helper
state: "off"
then:
- service: input_boolean.turn_on
data: {}
target:
entity_id: !input occupancy_helper
- conditions:
- condition: state
entity_id: !input occupancy_helper
state: "on"
- condition: or
conditions:
- condition: and
conditions:
- condition: trigger
id: clear
- condition: or
conditions:
- condition: state
entity_id: !input door_sensor
state: "on"
- condition: state
entity_id: !input door_sensor
state: "unavailable"
- condition: state
entity_id: !input door_sensor
state: "unknown"
- condition: template
value_template: >-
{{
is_state(door_sensor, 'off')
and (
states[door_sensor].last_changed > as_local(as_datetime(states(last_motion_helper)))
and (
motion_sensor_delay == -1
or (
motion_sensor_delay > -1
and states[door_sensor].last_changed >= states[motion_sensor].last_changed - timedelta(seconds=motion_sensor_delay)
)
)
)
}}
alias: True, when the door is closed and last motion was detected before door was closed and no motion was detected in the timeout period
alias: Check if door is open or closed and no motion was detected afterwards
- condition: and
conditions:
- condition: trigger
id: door_closed
- condition: state
entity_id: !input motion_sensor
state: "off"
- condition: template
value_template: >-
{{
states[door_sensor].last_changed > as_local(as_datetime(states(last_motion_helper)))
}}
- condition: and
conditions:
- condition: trigger
id: door_left_open
- condition: state
entity_id: !input motion_sensor
state: "off"
- condition: template
value_template: >-
{{
states[door_sensor].last_changed > as_local(as_datetime(states(last_motion_helper)))
}}
alias: True, when the door was opened and no motion was detected since opening the door for the turn off delay
alias: If the door was left open and no motion was detected between when the door was openened and the turn off delay
- condition: and
conditions:
- condition: trigger
id: door_closed
- condition: template
value_template: "{{ reset_on_closing_door_after_delay_period }}"
alias: Boolean to reset occupancy on closing door second time was set to true
- condition: template
value_template: >-
{{
now().timestamp() - states[occupancy_helper].last_changed.timestamp() > max(door_sensor_turn_off_delay, max(0, motion_sensor_delay) + motion_sensor_turn_off_delay, 20)
}}
sequence:
- service: input_boolean.turn_off
data: {}
target:
entity_id: !input occupancy_helper
default: []
mode: queued
max: 10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment