Turn on light, switch, scene, script or group based on motion, illuminance, sun (+ more conditions)

Github Gist: Home Assistant BluePrint to turn on light, switch, scene or script based on motion and illuminance · GitHub

Importing

Click the badge to import this Blueprint: (needs Home Assistant Core 2021.3 or higher)

Open your Home Assistant instance and show the blueprint import dialog with a specific blueprint pre-filled.

Or import this Blueprint by using the Gist URL.

Main features

Turn on a light, switch, scene or script based on motion detection, and (optionally) low illuminance level.
Also you are able to set a blocker entity, and time limits for the automation.
Only activating the automation on a certain sun state (below / above horizon is also possible.
Optionally, you can have the entity turn off after a certain amount of minutes of no motion detection.

Prerequisites

Some of the (optional) input values in this blueprint use helper entities you have to create yourself, to be able to dynamically set limits. It is not possible to set hardcoded limits for these inputs.

Optional features:

Is is also possible to define a blocking entity, which blocks the automation from running when this entity’s state is on. This could be for instance that sleep mode is enabled.

Time limits can also be defined to limit the time before and after the automation should trigger.
Outside of these limits the automation should not trigger.

If you do not configure the optional entities the automation will skip these conditions.

Optional entities:
- Illuminance sensor (sensor)
- Illuminance cutoff value (input_number)
- Blocking entity (any entity with state on/off)
- Time limit before (input_datetime)
- Time limit after (input_datetime)
- Wait time (input_number) [IN MINUTES!]

Defining optional entities in YAML: example code:

input_number:
  illumination_bedroom_low_cutoff:
    name: 'Illumination bedroom low cutoff value'
    min: 1
    max: 100
    step: 1
  bedroom_no_motion_turn_off_delay:
    name: 'Time in minutes automation waits to turn off bedroom lights after no motion'
    min: 1
    max: 120
input_boolean:
  sleepmode:
    name: 'Sleepmode'
input_datetime:
  bedroom_lights_turn_on_before_limit:
    name: 'Bedroom lights no longer turn on before this time'
    has_date: false
    has_time: true
  bedroom_lights_turn_on_after_limit:
    name: 'Bedroom lights no longer turn on after this time'
    has_date: false
    has_time: true

Defining optional entities in the UI

If you want to create the optional entities in the UI instead of in YAML, you van do so in the following way:

  • To to Configuration
  • Go to Helpers
  • Click the ‘Add helper’ button
  • Select the entity type (in this case, number, toggle or date/time)
  • Enter required fields
  • Click on create

Setting the values for the helper entities

To set a value for your newly created helper, find it in the helper list as described in the section above, press the settings icon on the top right of the screen and set the value there.

F.A.Q.

The blueprint is not (fully) working, what is wrong?

Something that often goes wrong when using this blueprint, is using hardcoded numbers instead of helper entities where required. For instance the no_motion_wait and the illuminance_cutoff parameters have to be an input_number helper entity, instead of a hardcoded number. Please read the full post again to see how to create the helper entities.
If it is still not working, please post your generated automation YAML code from the file automations.yaml.

How do I make sure my light sets set to a specific brightness, color etc?

Do do this, define a scene with your required settings. Then use that scene as the target entity for this script. If you want to trigger specific scenes at different times of the day, create multiple automations from this blueprint with different target entities (scenes) and with different time limits.

My target entity is triggered (light on) but it does not turn off after the wait time

You are probably using a scene or script as a target entity.
If you do, you must also define a target off entity.
This is because HA cannot ‘turn off’ a scene, it does now know how to return to the previous state.
The turn of entity could be either a light or a light group for instance.

Why do I need to create helper entities for some of the conditions instead of hardcoded number in the blueprint?

Requiring the helpers is indeed increasing the effort to get this blueprint to work. It was a design choice I made in the beginning of it’s development. I wanted to be able to dynamically change thresholds without having to change the automation itself. I do not want to change this right now because this would break the automations for updating users. I also thought about supporting both hardcoded numbers and helpers, but I think the blueprint is already complex enough to be maintainable.

Changelog

  • 2020-12-18: Initial version
  • 2020-12-18.1: Fix for hardcoded time limits
  • 2020-12-18.2: Refactored templates to be shorter, thanks to @123
  • 2020-12-19: Simplified action template
  • 2020-12-19.1: Added optional input to turn off entity after a certain amount of minutes of no motion
  • 2020-12-20: Added group support, fixed time condition bug
  • 2020-12-20.1: Made illumination sensor and cutoff value optional.
  • 2020-12-22: Removed entity state ‘on’ condition and set automation mode to restart to allow for entity off timer restart.
  • 2020-12-24: Added skip illuminance check if entity just turned on (when automation was restarted)
  • 2020-12-28: Added turn off blocking entity.
  • 2021-01-03: Fixed bug where time_limit_before did not work correctly when it was on the next day.
  • 2021-01-03.1: Added possibility to define turn-off entity other than target_entity.
  • 2021-01-08: Removed restriction of motion sensor needing to be binary_sensor in motion class. Now also possible to use groups of motion sensors. Also improved time condition.
  • 2021-01-21: Swapped input fields for time after and before to be more logical
  • 2021-09-02: Rewrote time condition to possibly fix time issue with blueprint not triggering when time window spans midnight.
  • 2021-12-14: Added default value to int casts.
  • 2022-03-20: Issues with scene as target entity not restarting automation on retrigger of motion sensor likely fixed.
  • 2022-03-24: Fixed issue in conditions pertaining to missing illuminance check when using scene as triggering entity
  • 2022-04-13: Added missing condition for non script/scene entities and no illuminance defined.
  • 2022-04-29: Refactored to use state object directly less often.
  • 2022-07-10: Fixed entity not turning off then no_motion_wait is undefined.
  • 2022-11-01: Added (backwards compatible) optional condition for triggering automation based on sunstate (below/above horizon).
  • 2022-11-08: Fixed turn off blocker entity state check being done before wait time.
  • 2022-11-21: Add support for skipping illuminance check on secondary motion detection, for scene target entities that control a single entity_id.

If you have any issues or questions, please let me know :slight_smile:

50 Likes

The time limits are inputs so why are they hard-coded in the template?

  - condition: template
    value_template: >
      {% set time_limit_after = '14:00'  %}
      {% set time_limit_before = '23:00'  %}

Is that a leftover from a previous version?

2 Likes

Very nice, this was exactly what i was starting to build and seen the new Blueprint option so I thought id look. Very nice!

Question though. I have DIY ESPHome ESP8266 sensors setup. For instance im doing my bathroom. For one it didnt detect my illuminance sensors, so i manually entered the id. I created a helper for the Bathroom Lux and selected it. Not sure how thats working though. My main question is for the blocker. I have a Humidity sensor that I want to use. Basically I want to to not shut the lights off if the humidity is high (Someone in the shower) but since its not boolean im not sure how your blueprint will handle it. Maybe a template of some form?

Good catch, that was some leftover testing template code indeed. I just fixed it in the gist and post itself.

As for your main question: I use the trend sensor to detect if humidity is increasing in my bathroom. This results in a binary_sensor, which is a boolean value. You could use this value as a blocker entity in this blueprint if you want :slight_smile:

I’m not sure if I undertstand the first part of your post correctly, but if you need any more help let me know.

Many of the templates aren’t taking full advantage of what Jinja2 offers.

For example, this:

  - condition: template
    value_template: >
      {% if entity_domain == "scene" %}
      true
      {% elif states[target_entity].state == 'off' %}
      true
      {% else %}
      false
      {% endif %}

can be reduced to this:

  - condition: template
    value_template: >
      {{ entity_domain == 'scene' or states[target_entity].state == 'off' }}

This:

  - condition: template
    value_template: >
      {% if blocker_entity == none %}
      true
      {% elif blocker_entity != none and states[blocker_entity].state == 'off' %}
      true
      {% elif blocker_entity != none and states[blocker_entity].state == 'on' %}
      false
      {% endif %}

can be expressed like this:

  - condition: template
    value_template: >
      {{ blocker_entity == none or states[blocker_entity].state == 'off' }}

I assume all of the following is to check if the current time is within the specified time range.

  - condition: template
    value_template: >
      {% set before_timestamp = '23:59'  %}
      {% set after_timestamp = '00:00'  %}

      {% if time_limit_before == none and time_limit_after == none %}
      true
      {% endif %}
      {% if time_limit_before != none %}
      {% set before_timestamp = time_limit_before %}
      {% endif %}

      {% if time_limit_after != none %}
      {% set after_timestamp = time_limit_after %}
      {% endif %}

      {% set current_time = now().strftime("%H:%M")  %}
      {% set current_time_before_limit = current_time < before_timestamp  %}
      {% set current_time_after_limit = current_time > after_timestamp  %}

      {% if current_time_before_limit and current_time_after_limit  %}
      true
      {% elif time_limit_before != none and current_time_before_limit and time_limit_after == none %}
      true
      {% elif time_limit_after != none and current_time_after_limit and time_limit_before == none %}
      true
      {% else %}
      false
      {% endif %}

It can be reduced to this:

  - condition: template
    value_template: >
      {{ (time_limit_before == none and time_limit_after == none) or 
         (time_limit_before != none and time_limit_after != none and  
          time_limit_after < now().strftime("%H:%M") < time_limit_before) }}

This:

  - service: >
        {% if entity_domain == "switch" %}
        switch.turn_on
        {% elif entity_domain == "light" %}
        light.turn_on
        {% elif entity_domain == "script" %}
        {{ target_entity }}
        {% elif entity_domain == "scene" %}
        scene.turn_on
        {% endif %}
    entity_id: !input target_entity

can be reduced to this:

  - service: "{{entity_domain}}.turn_on"
    entity_id: !input target_entity

If you wish, you can also take advantage of writing Template Conditions in shorthand notation.

12 Likes

Thanks for taking the effort to refactor some of my template code, I’ll incorporate it in a new version soon :slight_smile:

I just used your suggestions to refactor the templates.
I had to change some a bit to get them working, but the template code is much shorter now :wink: Thanks!

In the time limit one I have to handle the fact that there could be just a single time limit, before OR after. Also, in the first template I needed to add braces to each separate condition for it to work.
Your last suggestion was not entirely correct, because when a script is being called, there is no turn_on action, but the script is called by the name of the script itself.

Everything should still be working, I did some tests :slight_smile:

1 Like

Couldnt really get it working so i went ahead and created it manually. But i’ll redownload it again and test it out next time someone takes a shower and see if it does lux and humidity ok.

Also, I manually created my helper. I havent looked at your code yet but i may have that wrong which might be why. Thanks again man!!

How certain are you of this statement?

You may want to double-check.

Appears that motion sensor is required, even though it’s not specified as required in the docs.

Also, do you plan on adding any sort of ‘once a day’ condition? Or conditions on other things like a group being active?

1 Like

can you add an option to add a timer after which the light e.g. turns off…
btw many thanks for the blueprint!

You are correct. I guess I didn’t test properly that script.turn_on also works.
I was confused because calling script.scriptname also works, without any entity id.
Fixed it in the blueprint now.

I see that the docs were confusing there, I fixed that part now.
The motion sensor is indeed required, because that is the only trigger for this blueprint.

What is your usecase for a once a day condition? Since this blueprint is already quite complicated I want to know if it’s worth complicating it further.

I will look into group support later. Perhaps a group can also be a target entity (and also the condition to check whether the group is already on or not).

1 Like

I’ll look into that later as well. Im not sure whether to include a turn off action in this same blueprint or create a separate one for the turn off action. I’'ll post as soon as I have something.

1 Like

I have just updated the blueprint to have an optional input_number parameter which you can use to turn off the entity after x minutes of no more motion detected. Be aware that this only works for lights and switches, not for scenes or scripts.

Indeed it does because a script can be called two ways:

- service: script.turn_on
  entity_id: script.whatever

or

- service: script.whatever

The two methods are not 100% identical. The first method does not wait for the called script to finish; the caller continues to execute other actions while the script is executing. The second method waits for the called script to finish before proceeding to execute other actions.

For more information, see: Waiting for a script to complete

Where you added parentheses, such as the first template, was not needed. The statements were not ambiguous so the addition of parentheses doesn’t clarify anything. If you think they help you understand the template better, fine, but they’re not required for the Jinja2 interpreter.

In that case, the assumption I had made (both times are always use to define a range) was mistaken. The modification you made now handles it the desired way (and remains a fraction of the size of the original version). Good job!

1 Like

I just updated the blueprint again.
The time condidtion had a bug which I fixed.
Please update the blueprint if you are using it.
I also added groups as a possible target entity :slight_smile:

1 Like

Why does the action use a

condition: or

when there’s only one choice?

An oversight, fixed now.

1 Like