Each blueprint now has its own folder containing: - blueprint.yaml: The automation code with a short header - README.md: Detailed documentation extracted from headers Updated CLAUDE.md with repository structure guidelines. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
422 lines
15 KiB
YAML
422 lines
15 KiB
YAML
# Home Presence Controller Blueprint
|
|
# Determines home presence/occupancy based on activity sensors, person entities,
|
|
# Wi-Fi connections, and Bluetooth devices. See README.md for detailed documentation.
|
|
#
|
|
# Author: Alexei Dolgolyov (dolgolyov.alexei@gmail.com)
|
|
|
|
blueprint:
|
|
name: "Custom: Home Presence Controller"
|
|
description: >
|
|
Determines home presence based on multiple signals including activity sensors,
|
|
person entities, Wi-Fi connections, and Bluetooth devices.
|
|
Outputs the result to an input_boolean helper for use by other automations.
|
|
domain: automation
|
|
|
|
input:
|
|
# -------------------------------------------------------------------------
|
|
# Output Configuration
|
|
# -------------------------------------------------------------------------
|
|
result_group:
|
|
name: Output
|
|
collapsed: false
|
|
input:
|
|
result_value_entity:
|
|
name: Result Value
|
|
description: Input boolean helper that will store the presence result (on = home, off = away)
|
|
selector:
|
|
entity:
|
|
domain: input_boolean
|
|
|
|
control_switch:
|
|
name: Control Switch
|
|
description: Master switch to enable/disable presence detection (gatekeeper)
|
|
selector:
|
|
entity:
|
|
domain:
|
|
- input_boolean
|
|
- binary_sensor
|
|
|
|
# -------------------------------------------------------------------------
|
|
# Activity Sensor Configuration
|
|
# -------------------------------------------------------------------------
|
|
activity_group:
|
|
name: Activity
|
|
collapsed: false
|
|
input:
|
|
activity_sensors:
|
|
name: Activity Sensor(s)
|
|
description: >
|
|
Entities that indicate activity (door, motion, occupancy, switches, etc.).
|
|
Presence is assumed if any entity's state changed within the threshold period.
|
|
Supports: binary_sensor, sensor, input_boolean, switch, light, and more.
|
|
default: []
|
|
selector:
|
|
entity:
|
|
multiple: true
|
|
|
|
activity_sensor_threshold:
|
|
name: Activity Sensor Threshold
|
|
description: >
|
|
Time window after any activity sensor state change to assume presence.
|
|
After this duration, presence will be re-evaluated based on other signals.
|
|
default: 60
|
|
selector:
|
|
number:
|
|
min: 0
|
|
max: 600
|
|
unit_of_measurement: seconds
|
|
mode: slider
|
|
|
|
# -------------------------------------------------------------------------
|
|
# Presence Detection Configuration
|
|
# -------------------------------------------------------------------------
|
|
presence_group:
|
|
name: Presence
|
|
collapsed: false
|
|
input:
|
|
presence_sensors:
|
|
name: Person Entities
|
|
description: Person entities to monitor for home/away status
|
|
default: []
|
|
selector:
|
|
entity:
|
|
domain: person
|
|
multiple: true
|
|
|
|
# -------------------------------------------------------------------------
|
|
# Wi-Fi Detection Configuration
|
|
# -------------------------------------------------------------------------
|
|
wifi_group:
|
|
name: Wi-Fi
|
|
collapsed: false
|
|
input:
|
|
wifi_id_sensors:
|
|
name: Wi-Fi ID Sensors
|
|
description: Sensors that report the current Wi-Fi network ID (SSID/BSSID)
|
|
default: []
|
|
selector:
|
|
entity:
|
|
domain: sensor
|
|
multiple: true
|
|
|
|
home_wifi_ids:
|
|
name: Home Wi-Fi ID(s)
|
|
description: List of Wi-Fi network IDs that indicate the device is at home
|
|
default: []
|
|
selector:
|
|
text:
|
|
multiple: true
|
|
|
|
# -------------------------------------------------------------------------
|
|
# Bluetooth Detection Configuration
|
|
# -------------------------------------------------------------------------
|
|
bluetooth_group:
|
|
name: Bluetooth
|
|
collapsed: true
|
|
input:
|
|
bluetooth_device_trackers:
|
|
name: Bluetooth Device Trackers
|
|
description: >
|
|
Device trackers that report home/away status via Bluetooth/BLE.
|
|
These are checked for 'home' state to indicate presence.
|
|
default: []
|
|
selector:
|
|
entity:
|
|
domain: device_tracker
|
|
multiple: true
|
|
|
|
# -------------------------------------------------------------------------
|
|
# Guest Mode Configuration
|
|
# -------------------------------------------------------------------------
|
|
guest_mode_group:
|
|
name: Guest Mode
|
|
collapsed: true
|
|
input:
|
|
guest_mode_switch:
|
|
name: Guest Mode Switch
|
|
description: >
|
|
Input boolean that forces presence ON when enabled.
|
|
Useful when guests are home without tracked devices.
|
|
Leave empty to disable guest mode feature.
|
|
selector:
|
|
entity:
|
|
domain: input_boolean
|
|
multiple: false
|
|
|
|
# -------------------------------------------------------------------------
|
|
# Debug Configuration
|
|
# -------------------------------------------------------------------------
|
|
debug_group:
|
|
name: Debug
|
|
collapsed: true
|
|
input:
|
|
enable_debug_notifications:
|
|
name: Enable Debug Notifications
|
|
description: >
|
|
Send persistent notifications for debugging automation behavior.
|
|
Shows trigger details, sensor states, and presence decisions.
|
|
default: false
|
|
selector:
|
|
boolean:
|
|
|
|
# Restart mode ensures that if a new trigger occurs while processing,
|
|
# the automation restarts with fresh sensor values
|
|
mode: restart
|
|
|
|
# =============================================================================
|
|
# Triggers - Events that cause presence to be re-evaluated
|
|
# =============================================================================
|
|
trigger:
|
|
# Home Assistant startup - evaluate presence on restart
|
|
- platform: homeassistant
|
|
event: start
|
|
id: 'startup_trigger'
|
|
|
|
# Activity sensor state changes - only real state changes
|
|
- platform: state
|
|
entity_id: !input activity_sensors
|
|
id: 'activity_trigger'
|
|
not_from:
|
|
- unknown
|
|
- unavailable
|
|
not_to:
|
|
- unknown
|
|
- unavailable
|
|
|
|
# Person entity state changes (home/away)
|
|
- platform: state
|
|
entity_id: !input presence_sensors
|
|
id: 'presence_trigger'
|
|
not_from:
|
|
- unknown
|
|
- unavailable
|
|
not_to:
|
|
- unknown
|
|
- unavailable
|
|
|
|
# Control switch toggled (enable/disable detection)
|
|
- platform: state
|
|
entity_id: !input control_switch
|
|
id: 'control_trigger'
|
|
|
|
# Wi-Fi sensor state changes (network ID changed)
|
|
- platform: state
|
|
entity_id: !input wifi_id_sensors
|
|
id: 'wifi_trigger'
|
|
not_from:
|
|
- unknown
|
|
- unavailable
|
|
not_to:
|
|
- unknown
|
|
- unavailable
|
|
|
|
# Bluetooth device tracker state changes (home/away)
|
|
- platform: state
|
|
entity_id: !input bluetooth_device_trackers
|
|
id: 'bluetooth_trigger'
|
|
not_from:
|
|
- unknown
|
|
- unavailable
|
|
not_to:
|
|
- unknown
|
|
- unavailable
|
|
|
|
# Guest mode switch toggled
|
|
- platform: state
|
|
entity_id: !input guest_mode_switch
|
|
id: 'guest_mode_trigger'
|
|
|
|
# =============================================================================
|
|
# Variables - Computed values for presence determination
|
|
# =============================================================================
|
|
variables:
|
|
# ---------------------------------------------------------------------------
|
|
# Input References
|
|
# ---------------------------------------------------------------------------
|
|
wifi_id_sensors: !input wifi_id_sensors
|
|
home_wifi_ids: !input home_wifi_ids
|
|
control_switch: !input control_switch
|
|
result_value_entity: !input result_value_entity
|
|
activity_sensors: !input activity_sensors
|
|
activity_sensor_threshold: !input activity_sensor_threshold
|
|
presence_sensors: !input presence_sensors
|
|
bluetooth_device_trackers: !input bluetooth_device_trackers
|
|
guest_mode_switch: !input guest_mode_switch
|
|
enable_debug_notifications: !input enable_debug_notifications
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Control Switch State (with unavailable handling)
|
|
# ---------------------------------------------------------------------------
|
|
# If control switch is unavailable/unknown, default to ON to prevent
|
|
# presence from being stuck in wrong state
|
|
control_switch_on: >
|
|
{% set state = states(control_switch) %}
|
|
{% if state in ['unknown', 'unavailable'] %}
|
|
{{ true }}
|
|
{% else %}
|
|
{{ is_state(control_switch, 'on') }}
|
|
{% endif %}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Guest Mode Check
|
|
# ---------------------------------------------------------------------------
|
|
# Guest mode forces presence ON regardless of other sensors
|
|
guest_mode_on: >
|
|
{% if guest_mode_switch is not none and guest_mode_switch | length > 0 %}
|
|
{{ is_state(guest_mode_switch, 'on') }}
|
|
{% else %}
|
|
{{ false }}
|
|
{% endif %}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Activity Sensors
|
|
# ---------------------------------------------------------------------------
|
|
# Check if any activity sensor's state changed within the threshold period
|
|
# This provides a temporary "presence assumed" window based on recent activity
|
|
activity_on: >
|
|
{% if activity_sensors | length > 0 %}
|
|
{% set ns = namespace(active=[]) %}
|
|
{% for s in activity_sensors %}
|
|
{% set state = states(s) %}
|
|
{% if state not in ['unknown', 'unavailable']
|
|
and (now() - states[s].last_changed).total_seconds() < activity_sensor_threshold %}
|
|
{% set ns.active = ns.active + [s] %}
|
|
{% endif %}
|
|
{% endfor %}
|
|
{{ ns.active | length > 0 }}
|
|
{% else %}
|
|
{{ false }}
|
|
{% endif %}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Person/Presence Sensors
|
|
# ---------------------------------------------------------------------------
|
|
# Check if any tracked person is currently home
|
|
presence_on: >
|
|
{% if presence_sensors | length > 0 %}
|
|
{% set home_persons = presence_sensors | select('is_state', 'home') | list %}
|
|
{{ home_persons | length > 0 }}
|
|
{% else %}
|
|
{{ false }}
|
|
{% endif %}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Wi-Fi Detection
|
|
# ---------------------------------------------------------------------------
|
|
# Check if any device is connected to a home Wi-Fi network
|
|
wifi_on: >
|
|
{% if wifi_id_sensors | length > 0 and home_wifi_ids | length > 0 %}
|
|
{{ expand(wifi_id_sensors)
|
|
| map(attribute='state')
|
|
| select('in', home_wifi_ids)
|
|
| list
|
|
| length > 0 }}
|
|
{% else %}
|
|
{{ false }}
|
|
{% endif %}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Bluetooth Detection
|
|
# ---------------------------------------------------------------------------
|
|
# Check if any Bluetooth device tracker is reporting 'home'
|
|
bluetooth_on: >
|
|
{% if bluetooth_device_trackers | length > 0 %}
|
|
{% set home_devices = bluetooth_device_trackers | select('is_state', 'home') | list %}
|
|
{{ home_devices | length > 0 }}
|
|
{% else %}
|
|
{{ false }}
|
|
{% endif %}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Combined Presence Determination
|
|
# ---------------------------------------------------------------------------
|
|
# Stable signal sources (excluding activity threshold which is temporary)
|
|
is_on_stable: >
|
|
{{ (presence_on or wifi_on or bluetooth_on) and control_switch_on }}
|
|
|
|
# Final presence determination:
|
|
# 1. Guest mode forces ON
|
|
# 2. Otherwise, stable signals OR activity threshold window
|
|
is_on: "{{ guest_mode_on or is_on_stable or activity_on }}"
|
|
|
|
# =============================================================================
|
|
# Actions - Update presence state based on computed values
|
|
# =============================================================================
|
|
action:
|
|
# -------------------------------------------------------------------------
|
|
# Debug Logging (enabled via Debug input section)
|
|
# -------------------------------------------------------------------------
|
|
- choose:
|
|
- conditions:
|
|
- condition: template
|
|
value_template: "{{ enable_debug_notifications }}"
|
|
sequence:
|
|
- service: persistent_notification.create
|
|
data:
|
|
title: "Home Presence Debug"
|
|
message: >
|
|
Trigger: {{ trigger.id | default('unknown') }}
|
|
Time: {{ now().strftime('%H:%M:%S') }}
|
|
|
|
Sensor States:
|
|
- activity_on: {{ activity_on }}
|
|
- presence_on: {{ presence_on }}
|
|
- wifi_on: {{ wifi_on }}
|
|
- bluetooth_on: {{ bluetooth_on }}
|
|
- guest_mode_on: {{ guest_mode_on }}
|
|
- control_switch_on: {{ control_switch_on }}
|
|
|
|
Combined:
|
|
- is_on_stable: {{ is_on_stable }}
|
|
- is_on: {{ is_on }}
|
|
|
|
Result: {{ 'HOME' if is_on else 'AWAY' }}
|
|
|
|
# -------------------------------------------------------------------------
|
|
# Update Result Entity
|
|
# -------------------------------------------------------------------------
|
|
- choose:
|
|
- conditions:
|
|
- condition: template
|
|
value_template: "{{ is_on }}"
|
|
sequence:
|
|
- service: input_boolean.turn_on
|
|
target:
|
|
entity_id: "{{ result_value_entity }}"
|
|
default:
|
|
- service: input_boolean.turn_off
|
|
target:
|
|
entity_id: "{{ result_value_entity }}"
|
|
|
|
# -------------------------------------------------------------------------
|
|
# Activity Sensor Delayed Re-evaluation
|
|
# -------------------------------------------------------------------------
|
|
# When triggered by activity and no stable presence indicators are active,
|
|
# wait for the threshold duration then turn off presence.
|
|
# If another trigger occurs during the delay, the automation restarts
|
|
# (mode: restart) and re-evaluates with fresh data.
|
|
- condition: template
|
|
value_template: "{{ (not is_on_stable) and (not guest_mode_on) and trigger.id == 'activity_trigger' }}"
|
|
|
|
- delay:
|
|
seconds: "{{ activity_sensor_threshold }}"
|
|
|
|
- service: input_boolean.turn_off
|
|
target:
|
|
entity_id: "{{ result_value_entity }}"
|
|
|
|
# Debug notification for delayed turn-off
|
|
- choose:
|
|
- conditions:
|
|
- condition: template
|
|
value_template: "{{ enable_debug_notifications }}"
|
|
sequence:
|
|
- service: persistent_notification.create
|
|
data:
|
|
title: "Home Presence Debug"
|
|
message: >
|
|
Action: DELAYED TURN OFF
|
|
Time: {{ now().strftime('%H:%M:%S') }}
|
|
Delay: {{ activity_sensor_threshold }}s
|
|
Result: AWAY
|