Introduction
Hello everyone. Hope you are all well.
This template sensor attempts to detect the direction you’re moving (upstairs/downstairs, inside/outside) based on other sensors around a main sensor. It’s a single, self-contained solution. Great for doors and gates and can be used on stairs with a well positioned PIR sensor at the center of your stair way.
It solved an issue I was having with my previous implementations where the off state of sensors were captured and compared making the direction sensors think you’d walked back the other way after the sensors stopped detecting you. I found this more robust than just using the last_changed/last_updated states within home assistant.
It also requires less sensors overall as you can just use existing area sensors and another in the middle of those area’s which is perfect for doors.
Trigger Based Template - Direction Motion Sensor
This is a trigger based template sensor and should be placed in “/blueprints/template” path in your configuration. I’m not sure if the below link works or not properly as it opens the standard blueprint screen in home assistant for me. The blueprint code is at the bottom of the post.
Requirements
-
Main Sensor Placement: Place your main binary sensors (PIR, contact sensors) strategically – e.g., halfway up stairs for tracking upstairs movement, on doors for in/out detection.
-
Entry Entities: These are the initial sensors that trigger. (e.g. PIR sensors upstairs/downstairs, inside/outside sensors for doors)
-
Exit Entities: These are the final sensors that trigger. (e.g. PIR sensors upstairs/downstairs, inside/outside sensors for doors)
Important Notes:
-
Low Traffic: This system is best suited for low-traffic areas although shouldn’t matter too much in the case of doors and I’ve never noticed it cause an issue on my stairs as I use it for an early trigger on for my occupancy in the landing/hallway area’s.
-
Single Active State: The sensor will only be active when the primary movement sensor triggers on and the entry entities we’re the last triggered on. My PIR’s have a cool down of 10 seconds so they won’t detect me running up and down the stairs multiple times for example but it will capture that initial travel up/down the stairs.
How it Works:
This sensor leverages your existing binary sensors (contact, PIR, etc.) to track movement direction. It captures the last triggered on time of the entry and exit binary sensors. When the main sensor triggers, it compares the latest entry and exit times. If the entry sensor’s last triggered on time was most recent, the sensor turns on. The sensor will turn off if the entry/exit sensors update in the background, this prevents the sensor from being falsely triggered by background updates of the entry/exit sensors.
Example
Below is an example of how I’m using it on my stairs. The main sensors is on the banister of the stairs and my landing sensors are upstairs and my hallway sensors are downstairs. Just swap the entry/exit sensors to create the alternative sensor for up and downstairs. This makes my lighting in those area’s feel predictive rather than reactive.
template:
- name: PIR Going Downstairs
unique_id: pir_going_downstairs
use_blueprint:
path: personal/direction_motion_sensor.yaml # relative to config/blueprints/template/
input:
main_binary_sensor: binary_sensor.pir_stairs_wall_behind_banister_occupancy
entry_entities:
- binary_sensor.pir_landing_stairwell_occupancy
exit_entities:
- binary_sensor.pir_hallway_ceiling_entrance_occupancy
- binary_sensor.contact_hallway_back_door_contact
- binary_sensor.pir_hallway_shoe_stand_occupancy
- name: PIR Going Upstairs
unique_id: pir_going_upstairs
use_blueprint:
path: personal/direction_motion_sensor.yaml # relative to config/blueprints/template/
input:
main_binary_sensor: binary_sensor.pir_stairs_wall_behind_banister_occupancy
entry_entities:
- binary_sensor.pir_hallway_ceiling_entrance_occupancy
- binary_sensor.contact_hallway_back_door_contact
- binary_sensor.pir_hallway_shoe_stand_occupancy
exit_entities:
- binary_sensor.pir_landing_stairwell_occupancy```
Below is another example of my back door. The hallway is the last area before the back garden and I only have frigate detection outside. This has been great for disabling my security alerts as we go outside as it only triggers as we leave, and again the lights in the garden and hallway feel predictive rather than reactive. Frigate isn’t very fast at starting detection, and my hallway PIR’s don’t detect me until the door is open and I’m visible so it’s a nice additional trigger of occupancy without just relying on the door open trigger.
template:
- name: PIR Back Door Going Outside
unique_id: pir_back_door_going_outside
use_blueprint:
path: personal/direction_motion_sensor.yaml # relative to config/blueprints/template/
input:
main_binary_sensor: binary_sensor.contact_hallway_back_door_contact
entry_entities:
- binary_sensor.pir_hallway_ceiling_entrance_occupancy
- binary_sensor.pir_hallway_shoe_stand_occupancy
exit_entities:
- binary_sensor.camera_back_garden_door_person_occupancy
- binary_sensor.contact_back_garden_back_gate_contact
- binary_sensor.zone_camera_back_garden_patio_person_occupancy
- binary_sensor.zone_camera_back_garden_nook_person_occupancy
- binary_sensor.zone_camera_back_garden_nook_person_occupancy
- binary_sensor.zone_camera_back_garden_grass_area_person_occupancy
- binary_sensor.camera_back_garden_gate_person_occupancy
- binary_sensor.camera_back_garden_door_person_occupancy
- binary_sensor.camera_side_garden_person_occupancy
- name: PIR Back Door Coming Inside
unique_id: pir_back_door_coming_inside
use_blueprint:
path: personal/direction_motion_sensor.yaml # relative to config/blueprints/template/
input:
main_binary_sensor: binary_sensor.contact_hallway_back_door_contact
entry_entities:
- binary_sensor.camera_back_garden_door_person_occupancy
- binary_sensor.contact_back_garden_back_gate_contact
- binary_sensor.zone_camera_back_garden_patio_person_occupancy
- binary_sensor.zone_camera_back_garden_nook_person_occupancy
- binary_sensor.zone_camera_back_garden_nook_person_occupancy
- binary_sensor.zone_camera_back_garden_grass_area_person_occupancy
- binary_sensor.camera_back_garden_gate_person_occupancy
- binary_sensor.camera_back_garden_door_person_occupancy
- binary_sensor.camera_side_garden_person_occupancy
exit_entities:
- binary_sensor.pir_hallway_ceiling_entrance_occupancy
- binary_sensor.pir_hallway_shoe_stand_occupancy
Blueprint
blueprint:
name: Direction Motion Sensor
description: Creates a motion sensor that only triggers from a specific direction
domain: template
source_url: https://gist.notexpectedyet.com/notexpectedyet/041f0f0ed78b4489b824e2326e81e498/raw/HEAD/direction_motion_sensor.yaml
input:
main_binary_sensor:
name: Main Binary Sensor
description: The binary_sensor that you want to detect a direction when triggered. Should be inbetween the entry and exit sensors.
selector:
entity:
domain: binary_sensor
entry_entities:
name: Entry entities
description: The first set of entities that should trigger "on" before the main binary_sensor triggers.
#multiple: true
selector:
entity:
domain: binary_sensor
exit_entities:
name: Exit entities
description: The last set of entities that should trigger "on" after the main binary_sensor triggers.
#multiple: true
selector:
entity:
domain: binary_sensor
variables:
main_binary_sensor_input: !input main_binary_sensor
entry_entities_input: !input entry_entities
exit_entities_input: !input exit_entities
triggers:
- trigger: state
id: Main Binary Sensor
entity_id: !input main_binary_sensor
from: "off"
to: "on"
- trigger: state
id: Main Binary Sensor
entity_id: !input main_binary_sensor
from: "on"
to: "off"
- trigger: state
id: Entry Entities
entity_id: !input entry_entities
from: "off"
to: "on"
- trigger: state
id: Exit Entities
entity_id: !input exit_entities
from: "off"
to: "on"
conditions:
- condition: template
value_template: >-
{{ states(main_binary_sensor_input) not in ['unavailable', 'unknown'] }}
binary_sensor:
state: >
{% if trigger.id == "Main Binary Sensor" %}
{{ is_state(main_binary_sensor_input, 'on') and this.attributes.last_detected_entry|float(0) > this.attributes.last_detected_exit|float(0) }}
{% else %}
{{ false }}
{% endif %}
device_class: motion
attributes:
last_detected_entry: >-
{% if trigger.id == "Entry Entities" %}
{{ as_timestamp(now()) }}
{% else %}
{{ this.attributes.last_detected_entry if "last_detected_entry" in this.attributes else "0" }}
{% endif %}
last_detected_exit: >-
{% if trigger.id == "Exit Entities" %}
{{ as_timestamp(now()) }}
{% else %}
{{ this.attributes.last_detected_exit if "last_detected_exit" in this.attributes else "0" }}
{% endif %}