`wait_template` not behaving correctly

Hello again,
Still a noob to HA. Trying to get Athom’s human presence sensor automation honed in. But, am not quite there just yet. The idea is to eventually create a blueprint which:

  • allows user to input the area_id of interest
  • find all the lights, switches etc in that area
  • detect all presence sensors (and others in the future e.g. door sensor)
  • turn on lights as long as there is occupancy; in future, other services too.
  • wait for involved sensors to clear
  • turn off lights; and other services in future too.

I have seen other blueprints on github which are intended for a similar end result but via different means.
For now, following the KISS principle, i’m using a single athom sensor and hardcoding the area master_bedroom. I’d like for lights to turn on when lights turn a combination of binary_sensors parameters (e.g. occupancy OR no PIR but occupancy OR mmWave but no occupancy etc) occurs. Lights do turn on based on these conditions. But, its not getting past wait_template. Here’s the code. I’m sure its something stupidly simple but i’ve now several hours per day for 2 weeks trying to debug it using debug logs and developer tools with no luck.

alias: test-motion
description: test-motion
trigger:
  - platform: event
    event_data: {}
    event_type: state_changed
condition:
  - condition: template
    value_template: "{{ trigger.event.data.new_state is not none }}"
  - condition: template
    value_template: "{{ trigger.event.data.new_state.domain == 'binary_sensor'  }}"
  - condition: template
    value_template: "{{ area_id(trigger.event.data.entity_id) == 'master_bedroom' }}"
  - condition: template
    value_template: "{{ states('sensor.sensor_presence_mbr_light_sensor') | float() <35.0 }}"
  - condition: or
    conditions:
      - condition: and
        conditions:
          - condition: template
            value_template: "{{ trigger.event.data.entity_id.split('_')[-1] == 'occupancy' }}"
          - condition: template
            value_template: "{{ states(trigger.event.data.entity_id) == 'on' }}"
      - condition: and
        conditions:
          - condition: template
            value_template: "{{ trigger.event.data.entity_id.split('_')[-2] == 'mmwave' }}"
          - condition: template
            value_template: "{{ states(trigger.event.data.entity_id) == 'on' }}"
      - condition: and
        conditions:
          - condition: template
            value_template: "{{ trigger.event.data.entity_id.split('_')[-2] == 'pir' }}"
          - condition: template
            value_template: "{{ states(trigger.event.data.entity_id) == 'on' }}"
      - condition: and
        conditions:
          - condition: or
            conditions:
              - condition: template
                value_template: "{{ trigger.event.data.entity_id.split('_')[-2] == 'pir' }}"
              - condition: template
                value_template: "{{ trigger.event.data.entity_id.split('_')[-2] == 'mmwave' }}"
          - condition: and
            conditions:
              - condition: template
                value_template: >-
                  {{ trigger.event.data.entity_id.split('_')[-1] == 'occupancy'
                  }}
              - condition: template
                value_template: "{{ states(trigger.event.data.entity_id) == 'on' }}"
action:
  - alias: Set variables to be used later
    variables:
      pir_name: |
        "{% if trigger.event.data.entity_id.split('_')[-1] == 'occupancy' %}
          {{- trigger.event.data.entity_id[:-9] + 'pir_sensor' -}}
        {% elif trigger.event.data.entity_id.split('_')[-2] == 'mmwave' %}
          {{- trigger.event.data.entity_id[:-13] + 'pir_sensor' -}}
        {% else %}
          {{- trigger.event.data.entity_id -}}
        {% endif %}"
      mmwave_name: |
        "{% if trigger.event.data.entity_id.split('_')[-1] == 'occupancy' %}
          {{- trigger.event.data.entity_id[:-9] + 'mmwave_sensor' -}}
        {% elif trigger.event.data.entity_id.split('_')[-2] == 'pir' %}
          {{- trigger.event.data.entity_id[:-10] + 'mmwave_sensor' -}}
        {% else %}
          {{- trigger.event.data.entity_id }}
        {% endif %}"
      occ_name: |
        "{% if trigger.event.data.entity_id.split('_')[-2] == 'pir' %}
          {{- trigger.event.data.entity_id[:-10] + 'occupancy' -}}
        {% elif trigger.event.data.entity_id.split('_')[-2] == 'mmwave' %}
          {{- trigger.event.data.entity_id[:-13] + 'occupancy' -}}
        {% else %}
          {{- trigger.event.data.entity_id -}}
        {% endif %}"        
      area_name: "{{ area_id('light.master_bedroom_main') }}"
  - alias: Log variable values to see whether those are formulated correctly
    service: system_log.write
    data_template:
      message: >
        PIR entity = {{ pir_name }}, mmWave entity = {{ mmwave_name}}, 
        occupancy entity = {{ occ_name }}, area = {{area_name }}
      level: warning
  - alias: Turn on lights and switches
    service: light.turn_on
    data:
      area_id: "{{ area_name }}"
  - alias: Wait for all sensors to clear
    wait_template: |
      "{{ is_state('binary_sensor.sensor_presence_mbr_occupancy', 'off') and
          is_state('binary_sensor.sensor_presence_mbr_pir_sensor', 'off') and
          is_state('binary_sensor.sensor_presence_mbr_mmwave_sensor', 'off') 
      }}"
  - alias: Turn off lights and switches
    service: light.turn_off
    data:
      area_id: "{{ area_name }}"
mode: restart
max_exceeded: silent

syslog output shows variables being created correctly e.g.

2023-10-31 08:09:45.269 WARNING (MainThread) [homeassistant.components.system_log.external] PIR entity = "binary_sensor.sensor_presence_mbr_pir_sensor", mmWave entity = "binary_sensor.sensor_presence_mbr_mmwave_sensor",  occupancy entity = "binary_sensor.sensor_presence_mbr_occupancy", area = master_bedroom

After a certain time, sensor states change to off. But, wait_template doesn’t proceed to light.turn_off.
Help please.

This choice of Event Trigger:

  - platform: event
    event_data: {}
    event_type: state_changed

will cause the automation to trigger for every state-change that occurs in your system. Any entity that changes state will trigger the automation.

Is that really what you want? Because it’s a very inefficient use of system resources.

@123 you are indeed correct in regards to efficiency. In reading multiple posts, it seems trigger + bad conditions cause delay when event_type = state_changed. I was aiming to keep the triggers and conditions as generic (for blueprint) as possible; variables in templates didn’t seem to offer the same flexibility as available when using variables in condition. Hence, the present path. Open to suggestions.

upon further reflection (and more searching), i found a post by @tom_l which lists event filtering via area.

condition:
  - "{{ trigger.entity_id in area_entities('your_area_name_here') }}"

I wonder if going this route would address @123 observation and still give the required information of the correct triggered entities.

Not really. You posted a condition which is evaluated after the Event Trigger is processed (just like all the other conditions you have in your automation). Your Event Trigger will continue to monitor every state-change and then test it with the conditions.

Thank you, @123. I went back to the drawing board, thought a bit more and followed your advice. I’m able to achieve desirable outcome, using blueprint, with very good response times.

Adding code for brevity - perhaps others may benefit. It works for a single sensor per area. Any pointers on how to modify it were there more than 1 sensor operating lights/switches in a given area? A helper (template/boolean/number etc) would certainly help w/ the trigger aspects, but i’m unsure of whether / how to obtain entity.<xyz> events in such a case.

blueprint:
  name: Presence detection based behaviors
  description: Actions based on human presence detections e.g.
    - turn on lights
    - wait for conditions to be satisfied e.g. clearance of sensors
    - turn off lights
  domain: automation
  input:
    i_presence_entity:
      name: Presence Sensor
      selector:
        entity:
          filter:
            domain: binary_sensor
            device_class:
              - motion
              - occupancy
          multiple: true
    i_light_sensor:
      name: Light sensor to compare lux
      selector:
        entity:
          filter:
            domain: sensor
            device_class: illuminance
    i_light_sensor_value:
      name: Threshold lux
      description: Light sensor's lux threshold which triggers automation
      default: 35.0
      selector:
        number:
          min: 1
          max: 30000
          mode: slider
          unit_of_measurement: lux

trigger:
  - platform: state
    entity_id: !input i_presence_entity
    from: "off"
    to: "on"

variables:
  light_sensor: !input i_light_sensor
  light_sensor_value: !input i_light_sensor_value

condition:
  - condition: template
    value_template: "{{ is_state('binary_sensor.zzz_mode', 'off') }}"
  - condition: template
    value_template: "{{ (states(light_sensor) | float()) < (light_sensor_value | float()) }}"
  - condition: or
    conditions:
      - condition: and
        conditions:
          - condition: template
            value_template: "{{ trigger.to_state.entity_id.split('_')[-1] == 'occupancy' }}"
          - condition: template
            value_template: "{{ states(trigger.to_state.entity_id) == 'on' }}"
      - condition: and
        conditions:
          - condition: template
            value_template: "{{ trigger.to_state.entity_id.split('_')[-2] == 'pir' }}"
          - condition: template
            value_template: "{{ states(trigger.to_state.entity_id) == 'on' }}"
      - condition: and
        conditions:
          - condition: or
            conditions:
              - condition: template
                value_template: "{{ trigger.to_state.entity_id.split('_')[-2] == 'pir' }}"
              - condition: template
                value_template: "{{ trigger.to_state.entity_id.split('_')[-2] == 'mmwave' }}"
          - condition: and
            conditions:
              - condition: template
                value_template: "{{ trigger.to_state.entity_id.split('_')[-1] == 'occupancy' }}"
              - condition: template
                value_template: "{{ states(trigger.to_state.entity_id) == 'on' }}"

action:
  - alias: Set variables to be used later
    variables:
      pir_name: >-
        {% set x = device_attr(device_id(trigger.to_state.entity_id), 'name') |
        replace('-','_')  %} {% set y = 'binary_sensor.' + x + '_pir_sensor' %}
        {{ y }}
      mmwave_name: >-
        {% set a = device_attr(device_id(trigger.to_state.entity_id), 'name') |
        replace('-','_')  %} {% set b = 'binary_sensor.' + a + '_mmwave_sensor'
        %} {{ b }}
      occ_name: >-
        {% set c = device_attr(device_id(trigger.to_state.entity_id), 'name') |
        replace('-','_')  %} {% set d = 'binary_sensor.' + c + '_occupancy' %}
        {{ d }}
      area_name: "{{ area_id(trigger.to_state.entity_id) }}"
  - alias: Log variable values to see whether those are formulated correctly
    service: system_log.write
    data_template:
      message: >
        [PIR entity = {{ pir_name }}, {{ states(pir_name) }}],  [mmWave entity =
        {{ mmwave_name}}, {{ states(mmwave_name) }}],  [occupancy entity = {{
        occ_name }}, {{ states(occ_name) }}],  Area = {{area_name }}
      level: warning
  - alias: Turn on lights and switches
    service: light.turn_on
    data:
      area_id: "{{ area_name }}"
  - alias: Wait for all sensors to clear
    wait_template: "{{ is_state(occ_name, 'off') and is_state(pir_name, 'off') }}"
  - alias: Turn off lights and switches
    service: light.turn_off
    data:
      area_id: "{{ area_name }}"

mode: restart