Skip to content

Instantly share code, notes, and snippets.

@AlexanderBabel
Last active March 18, 2025 16:26
Show Gist options
  • Save AlexanderBabel/487f054b289b61f90afdc837d23cb85e to your computer and use it in GitHub Desktop.
Save AlexanderBabel/487f054b289b61f90afdc837d23cb85e to your computer and use it in GitHub Desktop.
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/AlexanderBabel/487f054b289b61f90afdc837d23cb85e
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
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
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
sequence:
- service: input_boolean.turn_off
data: {}
target:
entity_id: !input occupancy_helper
default: []
mode: queued
max: 10
@harphere
Copy link

harphere commented Feb 7, 2023

Good day, I'm trying to use this but every time the motion sensor clears, the boolean turns off which turns the lights off all while the door is closed which indicates occupancy. I thought door closed = lights on always?

@AlexanderBabel
Copy link
Author

The motion sensor has to detect motion once while the door is closed. When the Motion is detected beforehand it will not count.

@mprzekop-equinix
Copy link

mprzekop-equinix commented Mar 21, 2023

The problem is if you use z2m or a motion sensor that does not send each detection data then this script might not get into the "wasp in box" state.
I have Aqara P1 set for 5sec detection intervals and 30sec timeout in the blueprint

For example my wife "Always triggers"
0min 00sec - Someone opens the door motion is detected Occupancy Helper is set to on, Last Motion set to 0:00
0:03 - Door closed
0:05 - P1 detects motion -> it is not sent to z2m as it does not change the Sensor State, Last Motion is still 0:00
0:10 - P1 detects another motion -> it is not sent to z2m as it does not change the Sensor State, Last Motion is still 0:00
0:15 - Toilet sitting started P1 detects no motion this is sent to z2m.
0:20 - P1 detects no motion -> it is not sent to z2m as it does not change the Sensor State, Last Motion is still 0:00
0:25 - P1 detects no motion -> it is not sent to z2m as it does not change the Sensor State, Last Motion is still 0:00
0:30 - 30s timeout triggered - Wife complaints on lights switching off ;)

@karteekiitg
Copy link

karteekiitg commented Oct 19, 2024

@AlexanderBabel Thanks for the blueprint, very useful. Can you allow adding input_boolean as an input for door_sensor and motion_sensor from ui. This would allow for more complex automations. I would have created a pull request, but unfortunately I cant create PRs for gists (stupid github). Code change below for your convenience:

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

@AlexanderBabel
Copy link
Author

Thank you for your suggestion. I added the improvement to the original gist :)

@karteekiitg
Copy link

Thank you :)

@FrankTub
Copy link

@AlexanderBabel I've used your code and adjusted some parts to match a situation where my required output would be that the occupancy is set immediately when the door was opened. In order to do so I added a new turn of delay: door_sensor_turn_off_delay. In order to keep things neat I changed the existing delay to motion_sensor_turn_off_delay. Also asked ChatGPT to enhance some parts of the descriptions and refactored the template code parts a bit so I could understand what was going on. I've played around for it for some time now and it seems to work perfect for my use case.

Would you be open to updating your version to this? Probably best to test it in your house first before doing so 😄 .

@AlexanderBabel
Copy link
Author

Hey @FrankTub,

Thank you for your patience. I will check out your blueprint and report back about the change. I recently moved and had to re-setup numerous automations.

@AlexanderBabel
Copy link
Author

Hi @FrankTub again,

I tested the script for a month and everything looks good to me. Thank you for the improvement! I adjusted the original script to your version.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment