Yet another question on blueprints + motion activated lights

There are plenty of discussions on motion activated lights, but I have not seen a solution for my case. In addition to usual ‘turn on the light if a motion is detected’ statement, I would like to add 2 more requirements that make the task more complicated, comparing with usual examples on the internet:

  • Keep the lights on while someone is still in the room
  • Even if the lights were turned on using alternate ways (automations, wall switch, or via HA dashboard) it should be turned off eventually if there is no more motion.

Well, about a year ago I actually solved this using regular timers and 3 automations:

  • If the light is turned on -> start (restart) the timer
  • If a motion detected -> turn the lights on and start (restart) the timer
  • If the timer is due -> turn off the lights

The only tricky point here is that HA motion sensor object triggers only on ‘off’->‘on’ switch, but does not trigger automations if it already in ‘on’ state. This means automation will switch lights off even if you are still in the room. The solution in this case was to use mqtt trigger, parse the payload, and fire the trigger when ‘occupied’ field is ‘true’ regardless of its previous state.

As I said, everything is working fine (I can share the config if someone needs it). The only problem I have is that I have to copy/paste these automations every time I need motion activated lights (I have 4 rooms with this config, and I would like to set up one more).

From the preamble to actual question. I am looking towards blueprints, so that I create only one record per room, and pass only switch name, sensor name, and a timeout. I would like to use a motion_light.yaml that comes out of the box, and make a few adjustments.

I already tried to google for ‘multiple automations in a blueprint’ so that I could reuse my 3 automations. Unfortunately it looks like the only single automation is possible. Moreover timers are not supported in blueprints, but fortunately it can be overcome with wait_for_trigger action.

Here is what I have so far:

blueprint:
  name: Motion-activated Light (Improved)
  description: Turn on a light when motion is detected.
  domain: automation
  source_url: https://github.com/home-assistant/core/blob/067f2d0098d13134284e442d75ae5f1015ae044c/homeassistant/components/automation/blueprints/motion_light.yaml
  input:
    motion_entity:
      name: Motion Sensor
      selector:
        entity:
          domain: binary_sensor
          device_class: motion
    light_target:
      name: Light
      selector:
        target:
          entity:
            domain: light
    no_motion_wait:
      name: Wait time
      description: Time to leave the light on after last motion is detected.
      default: 120
      selector:
        number:
          min: 0
          max: 3600
          unit_of_measurement: seconds

# If motion is detected within the delay,
# we restart the script.
mode: restart
max_exceeded: silent

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

action:
  - service: light.turn_on
    target:
      entity_id: !input light_target
  - condition: template
    value_template: '{{ trigger.payload_json.occupancy == true  }}'
  - wait_for_trigger:
      platform: state
      entity_id: !input motion_entity
      from: "on"
      to: "off"
    timeout: !input no_motion_wait
  - service: light.turn_off
    target:
      entity_id: !input light_target

This code can turn off the light if it was turned on by a motion, or with a switch, or somehow else. But this code does not keep lights on while someone is in the room.

Question:
Can I somehow specify a trigger that will fire in one of these cases?

  • mqtt message with trigger.payload_json.occupancy == true
  • light state is turned on

Simplifying a long description above, I can rephrase my question as follows:

  • Can I somehow specify a condition right in the mqtt trigger block? Something like this
trigger:
  - platform: mqtt
    topic: zigbee2mqtt/vestibule_motion_sensor
    value_template: '{{ trigger.payload_json.occupancy }}'
    to: "true"

No. You are limited to specifying the topic and an optional (hard-coded) payload.

MQTT Trigger

An MQTT Sensor provides a value_template allowing you to extract a portion of the payload. You could create an MQTT Sensor (or MQTT Binary Sensor) and use it to trigger the automation.

You are not making full use of the motion sensor and its attributes (ie the off bit)
I have several such automations depending on usage
The most likely to match your case is as follows : -
Create template binary sensor based on the motion sensor with a templated delay off (so you can adjust the time.
Then switch the lights on when the template binary comes on (it stays on with short ‘cleared’ readings
Then in your automation have a wait in the action for binary sensor off and then turn off the light
This is easier to code

@123, MQTT binary sensor may indeed work. I created one that triggers my automation. However I hit the same issue - even after I specified “force_update: true” in the sensor settings, it does not trigger automation on subsequent motion sensor events. My trigger currently looks like this

trigger:
  - platform: state
    entity_id: !input motion_entity
    #from: "off" # This is commented out intentionally, otherwise it will not trigger on subsequent motions
    to: "on"

Binary sensor settings:

- platform: mqtt
  name: "Storeroom Motion Sensor"
  unique_id: storeroom_motion_sensor_improved
  state_topic: "zigbee2mqtt/storeroom_motion_sensor"
  value_template: '{{ value_json.occupancy }}'
  payload_on: "True"
  payload_off: "False"
  device_class: motion
  force_update: true
  expire_after: 300

Do I need to use some other platform type to catch all events from the sensor?

@Mutt, Interesting idea. I am going to try to rely on binary sensor’s timeout. Could you please share the code, so that I do not have to reintent the wheel?

My code is a bit complex as I have two different time factors for the lights in question depending on how they are being used.
I’ll dig through and prune it down … Give me an hour

Here’s the Binary Sensor : -

binary_sensor:
  - platform: template
    sensors:
      ## kitchen motion (with delay)
      bs_light_kitchen_motion:
        value_template: "{{ is_state('binary_sensor.fib_mosen_kit_motion_sensor', 'on') }}"
        friendly_name: Kitchen Motion With Delay
        delay_on: "00:00:00"
        delay_off: "00:00:{{ (states('input_number.in_light_kitchenled_mosen_timer') | float) * 60 - 30 }}"
        device_class: motion

Note that the actual sensor has a minimum dead time of 30 seconds and the timer ‘adjustment’ is an input number 0.5 to 10 with 0.5 steps to give a delay into the above.
I left the delay on in there incase I ever needed it. haven’t yet. just too lazy to remove it as it’s doing nothing
Here is the Automation : -

automation:
  #name: Light Kitchen LED Mosen On
  - alias: au_light_kitchenled_mosen_on
    mode: single
    max_exceeded: silent
    trigger:
      - platform: state
        entity_id: binary_sensor.bs_light_kitchen_motion
        to: 'on'
    condition:
      - condition: state
        entity_id: binary_sensor.bs_aalight_mosen_nightslot
        state:  'on'
      - condition: state
        entity_id: light.fibrgbw441_kitn_level_wte
        state:  'off'
      - condition: state
        entity_id: light.fibdim2_kitf_level
        state:  'off'
      - condition: state
        entity_id: light.fibdim2_kitr_level
        state:  'off'
    action:
      - service: input_boolean.turn_on
        entity_id: input_boolean.ib_light_kitchenled_mosen_triggered
      - service: light.turn_on
        entity_id: light.fibrgbw441_kitn_level_wte
      - delay: '00:00:01'
      - wait_template: "{{ is_state('binary_sensor.bs_light_kitchen_motion', 'off') }}"
      - service: input_boolean.turn_off
        entity_id: input_boolean.ib_light_kitchenled_mosen_triggered
      - service: light.turn_off
        entity_id: light.fibrgbw441_kitn_level_wte

The extra binary sensor is to distinguish if the light was turned on due to motion or was separately activated
The light check that the sun is in my nightslot (below a given elevation)
AND that NO OTHER Kitchen lights are on
The one second delay is to be sure, to be sure
:rofl:

It won’t until the sensor changes state. It must change from on to off to on again to trigger.

Thanks to Muttley’s code snippet I managed to finish my blueprint.

Actually additional template binary sensor or mqtt sensors are not required - they produce an object that does not report subsequent ‘occupied’ events, so original trigger did not catch this. I also tried leveraging event trigger (which is able to catch update events), but it was too complicated to write a condition, taking into account that lights can be turned on with a switch.

The trick was to using wait_template to monitor light’s and sensor’s states. Here is a resulting blueprint code:

blueprint:
  name: Motion-activated Light (Improved)
  description: Turn on a light when motion is detected.
  domain: automation
  source_url: https://github.com/home-assistant/core/blob/1fc4284a29602168708036c69d8d9fdea25bbc65/homeassistant/components/automation/blueprints/motion_light.yaml
  input:
    motion_entity:
      name: Motion Sensor
      selector:
        entity:
          domain: binary_sensor
          device_class: motion
    light_target:
      name: Light
      selector:
        target:
          entity:
            domain: light
    no_motion_wait:
      name: Wait time
      description: Time to leave the light on after last motion is detected.
      default: 120
      selector:
        number:
          min: 0
          max: 3600
          unit_of_measurement: seconds

# If motion is detected within the delay,
# we restart the script.
mode: restart
max_exceeded: silent

variables:
  motion_entity: !input motion_entity
  light_target: !input light_target

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

action:
  - service: light.turn_on
    target:
      entity_id: !input light_target
  - wait_template: "{{ is_state(motion_entity, 'off') or is_state(light_target, 'off')}}"
  - delay: !input no_motion_wait
  - service: light.turn_off
    target:
      entity_id: !input light_target

Usage in automations.yaml

- id: storeroom_motion_light
  alias: storeroom light
  description: Turn on store room lights for 2 min on motion detector
  use_blueprint:
    path: homeassistant/motion_light_adv.yaml
    input:
      no_motion_wait: '120'
      motion_entity: binary_sensor.storeroom_motion_sensor_occupancy
      light_target: light.storeroom_light

The only thing I have to declare separately is defining a light object

light:
  - platform: switch
    name: Storeroom light
    entity_id: switch.storeroom_light_left

I’d love this to be a part of a blueprint code as well. I’ll try to modify blueprint code so that it accepts switch object instead of a light one.

Please let me know if you see any issues with the code above.

I think if you look in the docs you can template a switch to a light.
But that can’t go in a blueprint either so it doesn’t help you.

So why have you done this as a blueprint or is it just because it’s flavour of the month ?
(seeing as you can’t blueprint the whole requirement)

Edit: Ah yes, but you can if your target was a light in the first place ! :+1:

Well,
In software engineering it looks very natual when a common piece of functionality is extracted into a function or a library. And I am happy that someone invented the same for Home Assistant configs. I have 4 rooms with motion sensors, and duplicating configs for 3 automations and a timer for each room is quite time consuming and error prone. Although setting this up is a one-time job and I could just be satisfied with 4 copies of automations, I would prefer to understand better the tool of blueprints.