Home Assistant Presence Detection: Combining Multiple Sensors for Reliability
Presence detection is the foundation of useful home automation. Lights that turn on when you arrive, thermostats that adjust when you leave, security that arms automatically—all depend on reliably knowing who’s home.
Single-source presence detection fails. Phones lose connectivity, motion sensors miss still people, GPS drifts. The solution is sensor fusion: combining multiple imperfect signals into reliable presence.
The Sensor Stack
Each sensor type has strengths and weaknesses:
Phone-Based Detection
Home Assistant Companion App
- GPS geofencing
- WiFi BSSID connection
- Bluetooth beacons
Strengths: Accurate location, works away from home Weaknesses: Battery drain, forgetful users, guests without app
Network-Based Detection
Router Integration (UniFi, etc.)
- Device connection status
- DHCP tracking
Strengths: Works with any device, no app needed Weaknesses: Doesn’t detect room, slow to register departure
Motion Sensors
PIR and mmWave
- Immediate room-level detection
- No app or phone needed
Strengths: Catches everyone, instant response Weaknesses: Can’t identify individuals, misses still people (PIR)
Door Sensors
Contact Sensors
- Entry/exit events
- Definitive state changes
Strengths: Unambiguous events Weaknesses: Doesn’t know who or direction
Sensor Fusion Architecture
The goal is a single binary_sensor.someone_home that’s reliably true when anyone is home and false when empty.
Individual Sensors
# configuration.yaml
# Phone tracking
device_tracker:
- platform: mobile_app
# Router tracking (UniFi example)
device_tracker:
- platform: unifi
host: 10.0.1.1
# Motion sensors are already binary_sensors from integration
Person Entity
Group multiple trackers per person:
person:
- name: Charles
id: charles
device_trackers:
- device_tracker.charles_phone_app
- device_tracker.charles_phone_wifi
- device_tracker.charles_watch
Bayesian Sensor
Combine signals probabilistically:
binary_sensor:
- platform: bayesian
name: "Someone Home"
prior: 0.6 # 60% prior probability someone is home
probability_threshold: 0.9
observations:
# Person entities
- entity_id: person.charles
prob_given_true: 0.99
prob_given_false: 0.05
platform: state
to_state: "home"
- entity_id: person.spouse
prob_given_true: 0.99
prob_given_false: 0.05
platform: state
to_state: "home"
# Recent motion
- entity_id: binary_sensor.living_room_motion
prob_given_true: 0.7
prob_given_false: 0.1
platform: state
to_state: "on"
# Front door opened recently (template sensor)
- entity_id: binary_sensor.front_door_recent
prob_given_true: 0.8
prob_given_false: 0.3
platform: state
to_state: "on"
Supporting Templates
template:
- binary_sensor:
- name: "Front Door Recent"
state: >
{{ (now() - states.binary_sensor.front_door.last_changed).seconds < 600 }}
- name: "Any Motion Recent"
state: >
{% set sensors = [
'binary_sensor.living_room_motion',
'binary_sensor.kitchen_motion',
'binary_sensor.bedroom_motion'
] %}
{% set ns = namespace(recent=false) %}
{% for sensor in sensors %}
{% if (now() - states[sensor].last_changed).seconds < 1800 %}
{% set ns.recent = true %}
{% endif %}
{% endfor %}
{{ ns.recent }}
Room-Level Presence
For per-room presence, mmWave sensors outperform PIR:
# ESPHome mmWave sensor config
binary_sensor:
- platform: ld2410
has_target:
name: "Office Presence"
has_moving_target:
name: "Office Motion"
has_still_target:
name: "Office Stationary"
Room Occupancy Entity
template:
- binary_sensor:
- name: "Office Occupied"
state: >
{{ is_state('binary_sensor.office_presence', 'on')
or is_state('binary_sensor.office_motion', 'on')
or (is_state('binary_sensor.office_door', 'off')
and was_state('binary_sensor.office_presence', 'on', 300)) }}
delay_off: "00:05:00"
The logic:
- Sensor detects presence → occupied
- Motion detected → occupied
- Door closed AND was recently occupied → probably still occupied
- 5-minute delay before marking unoccupied
Arrival and Departure Automations
Smart Arrival
automation:
- alias: "Welcome Home"
trigger:
- platform: state
entity_id: binary_sensor.someone_home
from: "off"
to: "on"
condition:
- condition: time
after: "06:00:00"
before: "22:00:00"
action:
- service: light.turn_on
target:
area_id: entryway
data:
brightness_pct: 80
- service: climate.set_temperature
target:
entity_id: climate.main_floor
data:
temperature: 72
- service: media_player.play_media
target:
entity_id: media_player.kitchen_speaker
data:
media_content_id: "media-source://tts/welcome_home"
media_content_type: "provider"
Confident Departure
The tricky part—you don’t want lights turning off while you’re in the shower.
automation:
- alias: "House Empty - Away Mode"
trigger:
- platform: state
entity_id: binary_sensor.someone_home
from: "on"
to: "off"
for: "00:10:00" # 10 minute buffer
condition:
# Double-check with motion sensors
- condition: state
entity_id: binary_sensor.any_motion_recent
state: "off"
action:
- service: climate.set_preset_mode
target:
entity_id: climate.main_floor
data:
preset_mode: "away"
- service: light.turn_off
target:
entity_id: all
- service: lock.lock
target:
entity_id: lock.front_door
Guest Handling
Guests don’t have the app. Handle them with motion-based overrides:
input_boolean:
guest_mode:
name: "Guest Mode"
icon: mdi:account-group
automation:
- alias: "Detect Guests"
trigger:
- platform: state
entity_id: binary_sensor.any_motion_recent
to: "on"
condition:
- condition: state
entity_id: binary_sensor.someone_home
state: "off"
- condition: state
entity_id: input_boolean.guest_mode
state: "off"
action:
- service: notify.mobile_app_charles_phone
data:
title: "Motion Detected"
message: "Motion detected but no one marked home. Guest?"
data:
actions:
- action: "ENABLE_GUEST_MODE"
title: "Enable Guest Mode"
- action: "FALSE_ALARM"
title: "False Alarm"
Debugging Presence Issues
When presence detection misbehaves:
Check Sensor States
# Add to dashboard
type: entities
title: Presence Debug
entities:
- entity: person.charles
- entity: device_tracker.charles_phone_app
- entity: device_tracker.charles_phone_wifi
- entity: binary_sensor.someone_home
- entity: binary_sensor.any_motion_recent
Trace Bayesian Sensor
# Enable debug logging temporarily
logger:
default: warning
logs:
homeassistant.components.bayesian: debug
Common Issues
- Phone tracker shows “unknown” — App background refresh disabled
- Slow departure detection — Router integration has long timeout
- False arrivals — GPS drift near home zone boundary
- Motion sensor stuck — PIR sensitivity too high
Performance Results
After implementing sensor fusion:
| Metric | Single Sensor | Sensor Fusion |
|---|---|---|
| False departures/week | 5-10 | 0-1 |
| False arrivals/week | 3-5 | 0 |
| Detection latency | 30-120s | 5-15s |
| Guest handling | Manual | Semi-automatic |
The difference is dramatic. Automations that were frustrating (lights turning off mid-movie) became invisible and reliable.
Key Takeaways
- Never trust a single sensor — All sensors fail, fuse multiple sources
- Bayesian beats boolean — Probability handles uncertainty gracefully
- Room presence needs mmWave — PIR misses stationary occupants
- Add buffers to departure — Fast departure detection causes pain
- Plan for guests — Not everyone will have your app
Reliable presence detection transforms home automation from gimmick to genuine quality-of-life improvement. The setup takes effort, but the result is a home that actually understands when you’re there.
Enjoyed this post?
Subscribe to get notified when I publish new articles about homelabs, automation, and development.
No spam, unsubscribe anytime. Typically 2-4 emails per month.