Repeat until Condition problem

Hi, hoping that someone might be able to help me with this.

I use an automation to control the lights in my bathroom.

PART 1 OF AUTOMATION
Turns on the lights in the bathroom when motion is detected. It then keeps the light on for a set time, if no motion has been detected during that time the lights turn off. Otherwise the set time repeats. This part works fine.

PART 2 OF AUTOMATION
The lights can also be turned on by a dimmer switch which is outside of the bathroom (so this part of the automation is triggered by the lights turning on rather than by motion). The automation should then keep the light on for a set time, if no motion has been detected during that time the lights should turn off. Otherwise the set time repeats.

The two separate parts of the automation basically use the same conditions but in the second part one of the conditions always reports as false so the automation just loops endlessly. When I test the condition in Developer Tools > Template I can see that it’s true. So I’m kind of stumped.

# Bathroom motion lights
- id: '7591950598'
  alias: bathroom_motion_lights
  mode: single
  trigger:
    - platform: homeassistant
      event: start
    - platform: state
      entity_id: binary_sensor.bathroom_multisensor_motion
      to: 'on'
    - platform: state
      entity_id: light.bathroom_pendant
      to: 'on'
  condition:
    - '{{ is_state("input_boolean.bath_time", "off") }}'
  action:
    - wait_template: >-
        {% set ignore = ["unknown", "unavailable"] %}
        {{ states("light.bathroom_pendant_zha") not in ignore
           and states("light.bathroom_pendant") not in ignore
           and states("binary_sensor.bathroom_multisensor_motion") not in ignore }}
    - variables:
        motion_clear_1: >
          {{ is_state("binary_sensor.bathroom_multisensor_motion", "off")
             and (as_timestamp(now()) - as_timestamp(states.binary_sensor.bathroom_multisensor_motion.last_changed) | default(0) | int > 1*60) }}        
        motion_clear_10: >
          {{ is_state("binary_sensor.bathroom_multisensor_motion", "off")
             and (as_timestamp(now()) - as_timestamp(states.binary_sensor.bathroom_multisensor_motion.last_changed) | default(0) | int >= 10*60) }}
        motion_clear_20: >
          {{ is_state("binary_sensor.bathroom_multisensor_motion", "off")
             and (as_timestamp(now()) - as_timestamp(states.binary_sensor.bathroom_multisensor_motion.last_changed) | default(0) | int >= 20*60) }}
        motion_clear_30: >
          {{ is_state("binary_sensor.bathroom_multisensor_motion", "off")
             and (as_timestamp(now()) - as_timestamp(states.binary_sensor.bathroom_multisensor_motion.last_changed) | default(0) | int >= 30*60) }}
    - choose:
      # IF trigger is motion detected
      - conditions:
          - '{{ trigger.entity_id == "binary_sensor.bathroom_multisensor_motion" }}'
          - '{{ is_state("light.bathroom_pendant", "off") }}'
        sequence:
          - choose:
            # IF sun is above horizon and bathroom pendant is off
            - conditions: '{{ is_state("sun.sun", "above_horizon") }}'
              sequence:
                - service: light.turn_on
                  target:
                    entity_id: light.bathroom_pendant
                  data:
                    transition: 2
                    brightness_pct: 100
                - repeat:
                    sequence:
                      - delay: '{{ "00:30:00" if is_state("binary_sensor.bathroom_humidity_bayesian", "on") else "00:20:00"}}'
                    until:
                      condition: or
                      conditions:
# PROBLEM: Condition works here.
                        - '{{ motion_clear_30 if is_state("binary_sensor.bathroom_humidity_bayesian", "on") else motion_clear_20 }}' 
                        - '{{ is_state("light.bathroom_pendant", "off") }}'
                - wait_for_trigger:
                  - platform: template
                    value_template: '{{ is_state("light.bathroom_pendant", "off") }}'
                  timeout: '00:00:10'
                  continue_on_timeout: true
                - choose:
                  - conditions: '{{ not wait.trigger }}'
                    sequence:
                      - service: light.turn_off
                        target:
                          entity_id: light.bathroom_pendant
                        data:
                          transition: 2
            # IF sun is below horizon and bathroom pendant is off
            # Bathroom nightlight                
            - conditions: '{{ is_state("sun.sun", "below_horizon") }}'
              sequence:    
                - service: light.turn_on
                  target:
                    entity_id: light.bathroom_led_strip
                  data:
                    transition: 2
                    brightness_pct: 10
                - repeat:
                    sequence:
                      - delay: '00:10:00'
                    until:
                      condition: or
                      conditions:
                        - '{{ motion_clear_10 }}'
                        - '{{ is_state("light.bathroom_pendant", "on") }}'
                - wait_for_trigger:
                  - platform: template
                    value_template: '{{ is_state("light.bathroom_pendant", "on") }}'
                  timeout: '00:00:10'
                  continue_on_timeout: true
                - choose:
                  - conditions: '{{ not wait.trigger }}'
                    sequence:
                      - service: light.turn_off
                        target:
                          entity_id: light.bathroom_led_strip
                        data:
                          transition: 2
      # IF trigger is light.bathroom_pendant and not motion
      - conditions:
          - '{{ is_state("light.bathroom_pendant", "on") if trigger.event == "start" else trigger.entity_id == "light.bathroom_pendant" }}'
          - '{{ is_state("binary_sensor.bathroom_multisensor_motion", "off") if trigger.event == "start" else motion_clear_1 }}'
        sequence:
          - choose:
            - conditions: '{{ is_state("sun.sun", "above_horizon") }}'
              sequence:
                - repeat:
                    sequence:
                      - delay: '{{ "00:30:00" if is_state("binary_sensor.bathroom_humidity_bayesian", "on") else "00:20:00"}}'
                    until:
                      condition: or
                      conditions:
# PROBLEM: Condition always reports false
                        - '{{ motion_clear_30 if is_state("binary_sensor.bathroom_humidity_bayesian", "on") else motion_clear_20 }}'
                        - '{{ is_state("light.bathroom_pendant", "off") }}'
                - wait_for_trigger:
                  - platform: template
                    value_template: '{{ is_state("light.bathroom_pendant", "off") }}'
                  timeout: '00:00:10'
                  continue_on_timeout: true
                - choose:
                  - conditions: '{{ not wait.trigger }}'
                    sequence:
                      - service: light.turn_off
                        target:
                          entity_id: light.bathroom_pendant
                        data:
                          transition: 2
            - conditions: '{{ is_state("sun.sun", "below_horizon") }}'
              sequence:
                - repeat:
                    sequence:
                      - delay: '{{ "00:30:00" if is_state("binary_sensor.bathroom_humidity_bayesian", "on") else "00:10:00"}}'
                    until:
                      condition: or
                      conditions:
# PROBLEM: Condition always reports false
                        - '{{ motion_clear_30 if is_state("binary_sensor.bathroom_humidity_bayesian", "on") else motion_clear_10 }}'
                        - '{{ is_state("light.bathroom_pendant", "off") }}'
                - wait_for_trigger:
                  - platform: template
                    value_template: '{{ is_state("light.bathroom_pendant", "off") }}'
                  timeout: '00:00:10'
                  continue_on_timeout: true
                - choose:
                  - conditions: '{{ not wait.trigger }}'
                    sequence:
                      - service: light.turn_off
                        target:
                          entity_id: light.bathroom_pendant
                        data:
                          transition: 2

Here’s a trace:

{
  "trace": {
    "last_step": "action/2/choose/1/sequence/0/choose/0/sequence/0/repeat/until/0/conditions/1",
    "run_id": "7",
    "state": "running",
    "script_execution": null,
    "timestamp": {
      "start": "2021-06-19T16:35:28.346641+00:00",
      "finish": null
    },
    "domain": "automation",
    "item_id": "7591950598",
    "trigger": "Home Assistant starting",
    "trace": {
      "trigger/0": [
        {
          "path": "trigger/0",
          "timestamp": "2021-06-19T16:35:28.346752+00:00",
          "changed_variables": {
            "trigger": {
              "platform": "homeassistant",
              "event": "start",
              "description": "Home Assistant starting",
              "id": "0"
            }
          }
        }
      ],
      "condition/0": [
        {
          "path": "condition/0",
          "timestamp": "2021-06-19T16:35:28.346899+00:00",
          "result": {
            "result": true,
            "entities": [
              "input_boolean.bath_time"
            ]
          }
        }
      ],
      "action/0": [
        {
          "path": "action/0",
          "timestamp": "2021-06-19T16:35:28.436101+00:00",
          "changed_variables": {
            "context": {
              "id": "270567fad461901e551e7a0742810b21",
              "parent_id": null,
              "user_id": null
            }
          },
          "result": {
            "wait": {
              "remaining": null,
              "completed": true
            }
          }
        }
      ],
      "action/1": [
        {
          "path": "action/1",
          "timestamp": "2021-06-19T16:35:43.287406+00:00",
          "changed_variables": {
            "wait": {
              "remaining": null,
              "completed": true
            }
          }
        }
      ],
      "action/2": [
        {
          "path": "action/2",
          "timestamp": "2021-06-19T16:35:43.292839+00:00",
          "changed_variables": {
            "motion_clear_1": false,
            "motion_clear_10": false,
            "motion_clear_20": false,
            "motion_clear_30": false
          },
          "result": {
            "choice": 1
          }
        }
      ],
      "action/2/choose/0": [
        {
          "path": "action/2/choose/0",
          "timestamp": "2021-06-19T16:35:43.295317+00:00",
          "result": {
            "result": false
          }
        }
      ],
      "action/2/choose/0/conditions/0": [
        {
          "path": "action/2/choose/0/conditions/0",
          "timestamp": "2021-06-19T16:35:43.295668+00:00",
          "result": {
            "result": false,
            "entities": []
          }
        }
      ],
      "action/2/choose/1": [
        {
          "path": "action/2/choose/1",
          "timestamp": "2021-06-19T16:35:43.296274+00:00",
          "result": {
            "result": true
          }
        }
      ],
      "action/2/choose/1/conditions/0": [
        {
          "path": "action/2/choose/1/conditions/0",
          "timestamp": "2021-06-19T16:35:43.296380+00:00",
          "result": {
            "result": true,
            "entities": [
              "light.bathroom_pendant"
            ]
          }
        }
      ],
      "action/2/choose/1/conditions/1": [
        {
          "path": "action/2/choose/1/conditions/1",
          "timestamp": "2021-06-19T16:35:43.297149+00:00",
          "result": {
            "result": true,
            "entities": [
              "binary_sensor.bathroom_multisensor_motion"
            ]
          }
        }
      ],
      "action/2/choose/1/sequence/0": [
        {
          "path": "action/2/choose/1/sequence/0",
          "timestamp": "2021-06-19T16:35:43.345308+00:00",
          "result": {
            "choice": 0
          }
        }
      ],
      "action/2/choose/1/sequence/0/choose/0": [
        {
          "path": "action/2/choose/1/sequence/0/choose/0",
          "timestamp": "2021-06-19T16:35:43.346675+00:00",
          "result": {
            "result": true
          }
        }
      ],
      "action/2/choose/1/sequence/0/choose/0/conditions/0": [
        {
          "path": "action/2/choose/1/sequence/0/choose/0/conditions/0",
          "timestamp": "2021-06-19T16:35:43.346809+00:00",
          "result": {
            "result": true,
            "entities": [
              "sun.sun"
            ]
          }
        }
      ],
      "action/2/choose/1/sequence/0/choose/0/sequence/0": [
        {
          "path": "action/2/choose/1/sequence/0/choose/0/sequence/0",
          "timestamp": "2021-06-19T16:35:43.363886+00:00"
        }
      ],
      "action/2/choose/1/sequence/0/choose/0/sequence/0/repeat/sequence/0": [
        {
          "path": "action/2/choose/1/sequence/0/choose/0/sequence/0/repeat/sequence/0",
          "timestamp": "2021-06-19T16:35:43.377740+00:00",
          "changed_variables": {
            "repeat": {
              "first": true,
              "index": 1
            }
          },
          "result": {
            "delay": 1200,
            "done": true
          }
        },
        {
          "path": "action/2/choose/1/sequence/0/choose/0/sequence/0/repeat/sequence/0",
          "timestamp": "2021-06-19T16:55:43.388633+00:00",
          "changed_variables": {
            "repeat": {
              "first": false,
              "index": 2
            }
          },
          "result": {
            "delay": 1200,
            "done": false
          }
        }
      ],
      "action/2/choose/1/sequence/0/choose/0/sequence/0/repeat": [
        {
          "path": "action/2/choose/1/sequence/0/choose/0/sequence/0/repeat",
          "timestamp": "2021-06-19T16:55:43.383277+00:00",
          "changed_variables": {
            "repeat": {
              "first": true,
              "index": 1
            }
          },
          "result": {
            "result": false
          }
        }
      ],
      "action/2/choose/1/sequence/0/choose/0/sequence/0/repeat/until/0": [
        {
          "path": "action/2/choose/1/sequence/0/choose/0/sequence/0/repeat/until/0",
          "timestamp": "2021-06-19T16:55:43.383685+00:00",
          "result": {
            "result": false
          }
        }
      ],
      "action/2/choose/1/sequence/0/choose/0/sequence/0/repeat/until/0/conditions/0": [
        {
          "path": "action/2/choose/1/sequence/0/choose/0/sequence/0/repeat/until/0/conditions/0",
          "timestamp": "2021-06-19T16:55:43.383869+00:00",
          "result": {
            "result": false,
            "entities": [
              "binary_sensor.bathroom_humidity_bayesian"
            ]
          }
        }
      ],
      "action/2/choose/1/sequence/0/choose/0/sequence/0/repeat/until/0/conditions/1": [
        {
          "path": "action/2/choose/1/sequence/0/choose/0/sequence/0/repeat/until/0/conditions/1",
          "timestamp": "2021-06-19T16:55:43.385220+00:00",
          "result": {
            "result": false,
            "entities": [
              "light.bathroom_pendant"
            ]
          }
        }
      ]
    },
    "config": {
      "id": "7591950598",
      "alias": "bathroom_motion_lights",
      "mode": "single",
      "trigger": [
        {
          "platform": "homeassistant",
          "event": "start"
        },
        {
          "platform": "state",
          "entity_id": "binary_sensor.bathroom_multisensor_motion",
          "to": "on"
        },
        {
          "platform": "state",
          "entity_id": "light.bathroom_pendant",
          "to": "on"
        }
      ],
      "condition": [
        "{{ is_state(\"input_boolean.bath_time\", \"off\") }}"
      ],
      "action": [
        {
          "wait_template": "{% set ignore = [\"unknown\", \"unavailable\"] %} {{ states(\"light.bathroom_pendant_zha\") not in ignore\n   and states(\"light.bathroom_pendant\") not in ignore\n   and states(\"binary_sensor.bathroom_multisensor_motion\") not in ignore }}"
        },
        {
          "variables": {
            "motion_clear_1": "{{ is_state(\"binary_sensor.bathroom_multisensor_motion\", \"off\")\n   and (as_timestamp(now()) - as_timestamp(states.binary_sensor.bathroom_multisensor_motion.last_changed) | default(0) | int > 1*60) }}        \n",
            "motion_clear_10": "{{ is_state(\"binary_sensor.bathroom_multisensor_motion\", \"off\")\n   and (as_timestamp(now()) - as_timestamp(states.binary_sensor.bathroom_multisensor_motion.last_changed) | default(0) | int >= 10*60) }}\n",
            "motion_clear_20": "{{ is_state(\"binary_sensor.bathroom_multisensor_motion\", \"off\")\n   and (as_timestamp(now()) - as_timestamp(states.binary_sensor.bathroom_multisensor_motion.last_changed) | default(0) | int >= 20*60) }}\n",
            "motion_clear_30": "{{ is_state(\"binary_sensor.bathroom_multisensor_motion\", \"off\")\n   and (as_timestamp(now()) - as_timestamp(states.binary_sensor.bathroom_multisensor_motion.last_changed) | default(0) | int >= 30*60) }}\n"
          }
        },
        {
          "choose": [
            {
              "conditions": [
                "{{ trigger.entity_id == \"binary_sensor.bathroom_multisensor_motion\" }}",
                "{{ is_state(\"light.bathroom_pendant\", \"off\") }}"
              ],
              "sequence": [
                {
                  "choose": [
                    {
                      "conditions": "{{ is_state(\"sun.sun\", \"above_horizon\") }}",
                      "sequence": [
                        {
                          "service": "light.turn_on",
                          "target": {
                            "entity_id": "light.bathroom_pendant"
                          },
                          "data": {
                            "transition": 2,
                            "brightness_pct": 100
                          }
                        },
                        {
                          "repeat": {
                            "sequence": [
                              {
                                "delay": "{{ \"00:30:00\" if is_state(\"binary_sensor.bathroom_humidity_bayesian\", \"on\") else \"00:20:00\"}}"
                              }
                            ],
                            "until": {
                              "condition": "or",
                              "conditions": [
                                "{{ motion_clear_30 if is_state(\"binary_sensor.bathroom_humidity_bayesian\", \"on\") else motion_clear_20 }}",
                                "{{ is_state(\"light.bathroom_pendant\", \"off\") }}"
                              ]
                            }
                          }
                        },
                        {
                          "wait_for_trigger": [
                            {
                              "platform": "template",
                              "value_template": "{{ is_state(\"light.bathroom_pendant\", \"off\") }}"
                            }
                          ],
                          "timeout": "00:00:10",
                          "continue_on_timeout": true
                        },
                        {
                          "choose": [
                            {
                              "conditions": "{{ not wait.trigger }}",
                              "sequence": [
                                {
                                  "service": "light.turn_off",
                                  "target": {
                                    "entity_id": "light.bathroom_pendant"
                                  },
                                  "data": {
                                    "transition": 2
                                  }
                                }
                              ]
                            }
                          ]
                        }
                      ]
                    },
                    {
                      "conditions": "{{ is_state(\"sun.sun\", \"below_horizon\") }}",
                      "sequence": [
                        {
                          "service": "light.turn_on",
                          "target": {
                            "entity_id": "light.bathroom_led_strip"
                          },
                          "data": {
                            "transition": 2,
                            "brightness_pct": 10
                          }
                        },
                        {
                          "repeat": {
                            "sequence": [
                              {
                                "delay": "00:10:00"
                              }
                            ],
                            "until": {
                              "condition": "or",
                              "conditions": [
                                "{{ motion_clear_10 }}",
                                "{{ is_state(\"light.bathroom_pendant\", \"on\") }}"
                              ]
                            }
                          }
                        },
                        {
                          "wait_for_trigger": [
                            {
                              "platform": "template",
                              "value_template": "{{ is_state(\"light.bathroom_pendant\", \"on\") }}"
                            }
                          ],
                          "timeout": "00:00:10",
                          "continue_on_timeout": true
                        },
                        {
                          "choose": [
                            {
                              "conditions": "{{ not wait.trigger }}",
                              "sequence": [
                                {
                                  "service": "light.turn_off",
                                  "target": {
                                    "entity_id": "light.bathroom_led_strip"
                                  },
                                  "data": {
                                    "transition": 2
                                  }
                                }
                              ]
                            }
                          ]
                        }
                      ]
                    }
                  ]
                }
              ]
            },
            {
              "conditions": [
                "{{ is_state(\"light.bathroom_pendant\", \"on\") if trigger.event == \"start\" else trigger.entity_id == \"light.bathroom_pendant\" }}",
                "{{ is_state(\"binary_sensor.bathroom_multisensor_motion\", \"off\") if trigger.event == \"start\" else motion_clear_1 }}"
              ],
              "sequence": [
                {
                  "choose": [
                    {
                      "conditions": "{{ is_state(\"sun.sun\", \"above_horizon\") }}",
                      "sequence": [
                        {
                          "repeat": {
                            "sequence": [
                              {
                                "delay": "{{ \"00:30:00\" if is_state(\"binary_sensor.bathroom_humidity_bayesian\", \"on\") else \"00:20:00\"}}"
                              }
                            ],
                            "until": {
                              "condition": "or",
                              "conditions": [
                                "{{ motion_clear_30 if is_state(\"binary_sensor.bathroom_humidity_bayesian\", \"on\") else motion_clear_20 }}",
                                "{{ is_state(\"light.bathroom_pendant\", \"off\") }}"
                              ]
                            }
                          }
                        },
                        {
                          "wait_for_trigger": [
                            {
                              "platform": "template",
                              "value_template": "{{ is_state(\"light.bathroom_pendant\", \"off\") }}"
                            }
                          ],
                          "timeout": "00:00:10",
                          "continue_on_timeout": true
                        },
                        {
                          "choose": [
                            {
                              "conditions": "{{ not wait.trigger }}",
                              "sequence": [
                                {
                                  "service": "light.turn_off",
                                  "target": {
                                    "entity_id": "light.bathroom_pendant"
                                  },
                                  "data": {
                                    "transition": 2
                                  }
                                }
                              ]
                            }
                          ]
                        }
                      ]
                    },
                    {
                      "conditions": "{{ is_state(\"sun.sun\", \"below_horizon\") }}",
                      "sequence": [
                        {
                          "repeat": {
                            "sequence": [
                              {
                                "delay": "{{ \"00:30:00\" if is_state(\"binary_sensor.bathroom_humidity_bayesian\", \"on\") else \"00:10:00\"}}"
                              }
                            ],
                            "until": {
                              "condition": "or",
                              "conditions": [
                                "{{ motion_clear_30 if is_state(\"binary_sensor.bathroom_humidity_bayesian\", \"on\") else motion_clear_10 }}",
                                "{{ is_state(\"light.bathroom_pendant\", \"off\") }}"
                              ]
                            }
                          }
                        },
                        {
                          "wait_for_trigger": [
                            {
                              "platform": "template",
                              "value_template": "{{ is_state(\"light.bathroom_pendant\", \"off\") }}"
                            }
                          ],
                          "timeout": "00:00:10",
                          "continue_on_timeout": true
                        },
                        {
                          "choose": [
                            {
                              "conditions": "{{ not wait.trigger }}",
                              "sequence": [
                                {
                                  "service": "light.turn_off",
                                  "target": {
                                    "entity_id": "light.bathroom_pendant"
                                  },
                                  "data": {
                                    "transition": 2
                                  }
                                }
                              ]
                            }
                          ]
                        }
                      ]
                    }
                  ]
                }
              ]
            }
          ]
        }
      ]
    },
    "blueprint_inputs": null,
    "context": {
      "id": "270567fad461901e551e7a0742810b21",
      "parent_id": null,
      "user_id": null
    }
  },
  "logbookEntries": [
    {
      "name": "bathroom_motion_lights",
      "message": "has been triggered by Home Assistant starting",
      "source": "Home Assistant starting",
      "entity_id": "automation.bathroom_motion_lights",
      "context_id": "270567fad461901e551e7a0742810b21",
      "when": "2021-06-19T16:35:28.347697+00:00",
      "domain": "automation"
    }
  ]
}

Totally open to suggestions of how this could be simplified, if I’ve over complicated it.

Thanks for reading :+1:

/me thinks there should be a badge for the most complicated automation posted on this forum :slight_smile:

Typo in bayesian, or have you set them up mis-spelled?

:sweat_smile: just a typo, corrected now.

So probably no-one cares, but maybe this can help someone out who enjoys creating “the most complicated automations” here’s how I fixed this:

One automation became 3:

# Bathroom lights helper
- alias: bathroom_lights_helper
  mode: single
  trigger:
    - platform: event
      event_type: timer.finished
      event_data:
        entity_id: timer.bathroom_lights
  action:
    - service: input_boolean.turn_on
      target:
        entity_id: input_boolean.bathroom_lights_helper
    - delay: '00:00:01'
    - service: input_boolean.turn_off
      target:
        entity_id: input_boolean.bathroom_lights_helper  
# Bathroom lights motion turn on
- alias: bathroom_lights_motion
  mode: single
  trigger:
    - platform: state
      entity_id: binary_sensor.bathroom_multisensor_motion
      to: 'on'
  condition:
    - '{{ is_state("input_boolean.bath_time", "off") }}'
    - '{{ is_state("light.bathroom_pendant", "off") }}'
    - '{{ not is_state("timer.bathroom_lights", "active") }}'
  action:
    - wait_template: >-
        {% set ignore = ["unknown", "unavailable"] %}
        {{ states("light.bathroom_pendant_zha") not in ignore
           and states("light.bathroom_pendant") not in ignore
           and states("light.bathroom_led_strip") not in ignore
           and states("binary_sensor.bathroom_multisensor_motion") not in ignore
           and states("timer.bathroom_lights") not in ignore }}
    - choose:
      # IF sun is above horizon and bathroom pendant is off
      - conditions: '{{ is_state("sun.sun", "above_horizon") }}'
        sequence:
          - service: light.turn_on
            target:
              entity_id: light.bathroom_pendant
            data:
              transition: 2
              brightness_pct: 100
          - service: timer.start
            target:
              entity_id: timer.bathroom_lights
            data:
              duration: '{{ "00:30:00" if is_state("binary_sensor.bathroom_humidity_bayesian", "on") else "00:20:00"}}'
          - repeat:
              sequence:
                - wait_for_trigger:
                  - platform: state
                    entity_id: binary_sensor.bathroom_multisensor_motion
                    to: 'on'
                  timeout: '{{ state_attr("timer.bathroom_lights", "duration") }}'
                  continue_on_timeout: true
                - choose:
                  - conditions: '{{ wait.trigger }}'
                    sequence:
                      - service: timer.start
                        target:
                          entity_id: timer.bathroom_lights
                        data:
                          duration: '{{ "00:30:00" if is_state("binary_sensor.bathroom_humidity_bayesian", "on") else "00:20:00"}}'
              until:
                condition: or
                conditions:
                  - '{{ is_state("input_boolean.bathroom_lights_helper", "on") }}'
                  - '{{ is_state("light.bathroom_pendant", "off") }}'
          - service: timer.finish
            target:
              entity_id: '{{timer.bathroom_lights if not is_state("timer.bathroom_lights", "idle") else "none"}}' 
          - wait_for_trigger:
            - platform: template
              value_template: '{{ is_state("light.bathroom_pendant", "off") }}'
            timeout: '00:00:10'
            continue_on_timeout: true
          - choose:
            - conditions: '{{ not wait.trigger }}'
              sequence:
                - service: light.turn_off
                  target:
                    entity_id: light.bathroom_pendant
                  data:
                    transition: 2
      # IF sun is below horizon and bathroom pendant is off (nightlight)              
      - conditions: '{{ is_state("sun.sun", "below_horizon") }}'
        sequence:    
          - service: light.turn_on
            target:
              entity_id: light.bathroom_led_strip
            data:
              transition: 2
              brightness_pct: 10
          - service: timer.start
            target:
              entity_id: timer.bathroom_lights
            data:
              duration: '00:10:00'
          - repeat:
              sequence:
                - wait_for_trigger:
                  - platform: state
                    entity_id: binary_sensor.bathroom_multisensor_motion
                    to: 'on'
                  timeout: '{{ state_attr("timer.bathroom_lights", "duration") }}'
                  continue_on_timeout: true
                - choose:
                  - conditions: '{{ wait.trigger }}'
                    sequence:
                      - service: timer.start
                        target:
                          entity_id: timer.bathroom_lights
                        data:
                          duration: '00:10:00'
              until:
                condition: or
                conditions:
                  - '{{ is_state("input_boolean.bathroom_lights_helper", "on") }}'
                  - '{{ is_state("light.bathroom_pendant", "on") }}'
          - service: timer.finish
            target:
              entity_id: '{{timer.bathroom_lights if not is_state("timer.bathroom_lights", "idle") else "none"}}'
          - wait_for_trigger:
            - platform: template
              value_template: '{{ is_state("light.bathroom_pendant", "on") }}'
            timeout: '00:00:10'
            continue_on_timeout: true
          - choose:
            - conditions: '{{ not wait.trigger }}'
              sequence:
                - service: light.turn_off
                  target:
                    entity_id: light.bathroom_led_strip
                  data:
                    transition: 2
# Bathroom lights manual turn on
- alias: bathroom_lights_manual
  mode: single
  trigger:
    - platform: homeassistant
      event: start
    - platform: state
      entity_id: light.bathroom_pendant
      to: 'on'
  condition:
    - '{{ is_state("input_boolean.bath_time", "off") }}'
    - '{{ is_state("light.bathroom_pendant", "on") }}'
    - '{{ not is_state("timer.bathroom_lights", "active") }}'
    - condition: template
      value_template: >-
        {{ (as_timestamp(states.automation.bathroom_lights_motion.attributes.last_triggered) - as_timestamp(states.light.bathroom_pendant.last_changed) | float ) | abs | timestamp_custom("%H:%M:%S") > "00:00:05"
           if states.automation.bathroom_lights_motion.attributes.last_triggered != "none" and states.light.bathroom_pendant.last_changed != "none" 
           else "True" }}
  action:
    - wait_template: >-
        {% set ignore = ["unknown", "unavailable"] %}
        {{ states("light.bathroom_pendant_zha") not in ignore
           and states("light.bathroom_pendant") not in ignore
           and states("light.bathroom_led_strip") not in ignore
           and states("binary_sensor.bathroom_multisensor_motion") not in ignore
           and states("timer.bathroom_lights") not in ignore }}
    - choose:
      # IF sun is above horizon and bathroom pendant is off
      - conditions: '{{ is_state("sun.sun", "above_horizon") }}'
        sequence:
          - service: timer.start
            target:
              entity_id: timer.bathroom_lights
            data:
              duration: '{{ "00:30:00" if is_state("binary_sensor.bathroom_humidity_bayesian", "on") else "00:20:00"}}'
          - repeat:
              sequence:
                - wait_for_trigger:
                  - platform: state
                    entity_id: binary_sensor.bathroom_multisensor_motion
                    to: 'on'
                  timeout: '{{ state_attr("timer.bathroom_lights", "duration") }}'
                  continue_on_timeout: true
                - choose:
                  - conditions: '{{ wait.trigger }}'
                    sequence:
                      - service: timer.start
                        target:
                          entity_id: timer.bathroom_lights
                        data:
                          duration: '{{ "00:30:00" if is_state("binary_sensor.bathroom_humidity_bayesian", "on") else "00:20:00"}}'
              until:
                condition: or
                conditions:
                  - '{{ is_state("input_boolean.bathroom_lights_helper", "on") }}'
                  - '{{ is_state("light.bathroom_pendant", "off") }}'
          - service: timer.finish
            target:
              entity_id: '{{timer.bathroom_lights if not is_state("timer.bathroom_lights", "idle") else "none"}}'
          - wait_for_trigger:
            - platform: template
              value_template: '{{ is_state("light.bathroom_pendant", "off") }}'
            timeout: '00:00:10'
            continue_on_timeout: true
          - choose:
            - conditions: '{{ not wait.trigger }}'
              sequence:
                - service: light.turn_off
                  target:
                    entity_id: light.bathroom_pendant
                  data:
                    transition: 2
      # IF sun is below horizon and bathroom pendant is off (nightlight)              
      - conditions: '{{ is_state("sun.sun", "below_horizon") }}'
        sequence:    
          - service: timer.start
            target:
              entity_id: timer.bathroom_lights
            data:
              duration: '{{ "00:30:00" if is_state("binary_sensor.bathroom_humidity_bayesian", "on") else "00:10:00"}}'
          - repeat:
              sequence:
                - wait_for_trigger:
                  - platform: state
                    entity_id: binary_sensor.bathroom_multisensor_motion
                    to: 'on'
                  timeout: '{{ state_attr("timer.bathroom_lights", "duration") }}'
                  continue_on_timeout: true
                - choose:
                  - conditions: '{{ wait.trigger }}'
                    sequence:
                      - service: timer.start
                        target:
                          entity_id: timer.bathroom_lights
                        data:
                          duration: '{{ "00:30:00" if is_state("binary_sensor.bathroom_humidity_bayesian", "on") else "00:10:00"}}'
              until:
                condition: or
                conditions:
                  - '{{ is_state("input_boolean.bathroom_lights_helper", "on") }}'
                  - '{{ is_state("light.bathroom_pendant", "off") }}'
          - service: timer.finish
            target:
              entity_id: '{{timer.bathroom_lights if not is_state("timer.bathroom_lights", "idle") else "none"}}'
          - wait_for_trigger:
            - platform: template
              value_template: '{{ is_state("light.bathroom_pendant", "off") }}'
            timeout: '00:00:10'
            continue_on_timeout: true
          - choose:
            - conditions: '{{ not wait.trigger }}'
              sequence:
                - service: light.turn_off
                  target:
                    entity_id: light.bathroom_pendant
                  data:
                    transition: 2
1 Like

For the record, I care but even though I have spent over 2.5 years helping people debug their automations, this one made my eyes glaze over (no offense intended).

Your description of how it works was straightforward and comprehensible. However, matching the description to the labyrinth of code was too much of a chore for me (my fault, not yours).

FWIW, I use a single automation to provide motion-activated lighting in a bathroom (two bathrooms actually). I believe it provides all the functionality you mentioned and possibly a bit more.

  • Automatically turns on light when motion is detected but only if it’s after dark and the bathroom’s light level is below a threshold value (and the light is currently off).

  • The light’s brightness depends on the current time. It is set to a much lower value after 23:30.

  • Automatically turns off the light after detecting 2 consecutive minutes of “no occupancy” (where “no occupancy” is defined as a solid minute of no motion).

  • The auto-off function can be temporarily suspended by changing the light’s brightness using the wall switch. Any change from the default brightness value will suspend auto-off for 20 minutes.

  • Turning on the ceiling fan will also suspend the auto-off feature.

  • After 20 minutes, the auto-off feature is re-enabled. If no occupancy is detected, the light is also immediately turned off.

  • Manually turning off the light immediately re-enables the auto-off feature (if it was suspended).

The automation references the following entities:

  1. Light
  2. Motion Sensor
  3. Occupancy Sensor
  4. Light Level Sensor
  5. Input Boolean (tracks auto-off function)
  6. Switch (ceiling fan)
  7. Sun (if below_horizon)

It used to be two automations but I recently consolidated it into one.

Hi @123, yes you’ve actually helped me a out a number of times :+1:

I’m still very much learning and my automations do tend to bloat pretty quickly - your version sounds great - would be delighted if you can share and I’ll see if I can implement something similar :grin:

Can you share yours I’m just starting and this will help me a lot

The following automaton performs all of the functions described in my previous post. If you’re just starting out, this automation might prove to be challenging to understand. I’ve added a few blank lines to help make it a bit easier to read.

The reason why its mode is set to queued is because it performs a few actions that cause it to trigger itself (this is intentional). I’ve been using it for over a year and it works very reliably.

- alias: 'Automatic Bathroom Light'
  id: automatic_bathroom_light
  mode: queued
  trigger:
  - id: 'motion'
    platform: state
    entity_id: binary_sensor.bathroom_fan
    from: 'off'
    to: 'on'

  - id: 'unoccupied'
    platform: state
    entity_id: binary_sensor.bathroom_occupancy
    to: 'off'
    for: '00:02:00'

  - id: 'brightness'
    platform: state
    entity_id: light.bathroom_light
    attribute: brightness

  - id: 'timeout'
    platform: state
    entity_id: input_boolean.bathroom_auto_off
    to: 'off'
    for: '00:20:00'

  - id: 'light_off'
    platform: state
    entity_id: light.bathroom_light
    from: 'on'
    to: 'off'

  - id: 'fan'
    platform: state
    entity_id: switch.bathroom_fan
    from:
    - 'on'
    - 'off'
    to:
    - 'on'
    - 'off'

  condition: "{{ is_state('sun.sun', 'below_horizon') }}"

  action:
  - variables:
      light: light.bathroom_light
      fan: switch.bathroom_fan
      auto_off: input_boolean.bathroom_auto_off
      occupancy: binary_sensor.bathroom_occupancy
      luminance: sensor.bathroom_light_level
      lo: 26
      mid: 125
      brightness: >
        {{ lo if now() > today_at('23:30') or
            now().time() < (state_attr('sun.sun', 'next_rising') | as_datetime | as_local).time() else mid }}
  - choose:
    - conditions:
      - "{{ trigger.id == 'motion' }}"
      - "{{ is_state(light, 'off') }}"
      - "{{ states(luminance) | int(0) < 15 or is_state(fan, 'on') }}"
      sequence:
      - service: light.turn_on
        target:
          entity_id: '{{ light }}'
        data:
          brightness: '{{ brightness }}'

    - conditions:
      - "{{ trigger.id == 'unoccupied' }}"
      - "{{ is_state(light, 'on') }}"
      - "{{ is_state(auto_off, 'on') }}"
      sequence:
      - service: light.turn_off
        target:
          entity_id: '{{ light }}'
        data:
          transition: 5

    - conditions:
      - "{{ trigger.id == 'brightness' }}"
      - "{{ is_state(auto_off, 'on') }}"
      - "{{ trigger.from_state.state == trigger.to_state.state }}"
      - "{{ trigger.to_state.attributes.brightness > brightness + 2 or trigger.to_state.attributes.brightness < brightness - 2 }}"
      sequence:
      - service: input_boolean.turn_off
        target:
          entity_id: '{{ auto_off }}'

    - conditions:
      - "{{ trigger.id == 'timeout' or (trigger.id == 'light_off' and is_state(auto_off, 'off')) }}"
      sequence:
      - service: input_boolean.turn_on
        target:
          entity_id: '{{ auto_off }}'
      - condition: "{{ is_state(occupancy, 'off') and is_state(light, 'on') }}"
      - service: light.turn_off
        target:
          entity_id: '{{ light }}'

    - conditions:
      - "{{ trigger.id == 'light_off' }}"
      sequence: []

    - conditions:
      - "{{ trigger.id == 'fan' }}"
      sequence:
      - service: "input_boolean.turn_{{ 'off' if trigger.to_state.state == 'on' else 'on' }}"
        target:
          entity_id: '{{ auto_off }}'

    default: []


####EDIT
Correction. Incorrect service call. Change light_on to turn_on.

6 Likes

Little mistake in here. Should be:

      sequence:
      - service: light.turn_on
1 Like

Thank you! I have corrected the mistake in the posted example.

Im one of those just starting out with writing YAML automations and Im finding your posts very helpful! But before trying this one out I wonder if this code is all thats necessary (+changing entity IDs…) to make it work, or do I need to create other scripts or stuff like those input_boolean thingamabobs somewhere?

Read my previous post where it explains the automation references seven entities. They must exist in order for the automation to work properly.