# 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