Help with automation input conditions and reuse

Hi

I am trying to make an automation that has three features for controlling my lights.

The first feature is to have some form of input flag for example if I have a toggle called “night_time” and if it is On, then motion triggers don’t turn the lights on.

The second feature is similar to the first but for example if I have a toggle called “ambient” if On it turns the room lamps on when motion is detected rather than the light.

I.e. if motion is detected and ambient is On then turn on light.{room}_lamp else turn on light.{room}

Finally I have named all my lights, motion sensors and lamps in the same pattern, so I wondered rather than having loads of duplicate automations, if I could use some template instead?

I.e.

if binary_sensor.{room}_motion is detected then turn on light.{room} and start timer.{room}

Everything you’ve described is possible. Post what you’ve created and we can help you refine it.

Hi @123

This is my lounge motion, which is the same as everywhere else in most ways.

- id: '1585417563603'
  alias: Turn On Lounge Light when motion detected
  description: ''
  trigger:
  - device_id: 0310800ab747484283cf6fb58715fb0d
    domain: binary_sensor
    entity_id: binary_sensor.lounge_motion
    platform: device
    type: motion
  condition:
  - condition: or
    conditions:
    - before: sunrise
      condition: sun
    - after: sunset
      condition: sun
  - condition: state
    entity_id: input_boolean.ambient_mode
    state: 'Off'
  action:
  - data: {}
    entity_id: light.lounge
    service: light.turn_on
  - data:
      entity_id: timer.lounge
    service: timer.cancel
  - data:
      duration: 00:02:00
      entity_id: timer.lounge
    service: timer.start
  mode: single

This is the off automation:

- id: '1585418369243'
  alias: Turn Off Lounge Light when there is no motion
  description: ''
  trigger:
  - event_data:
      entity_id: timer.lounge
    event_type: timer.finished
    platform: event
  action:
  - data: {}
    entity_id: light.lounge
    service: light.turn_off

I thought one way I could do the lamps and lights based on the toggle would be have two separate automations by inverting the toggle value on the condition.

But I wonder if I can do some kind of if toggle On then lamp else light.

Also very interested in trimming some of the repetition.

I’ve got every light and lamp controllable now, so the repetition is a little annoying and makes find and tweaking things a bit more difficult. Also I guess the feedback from my current setup is that I need to develop my light automations to be a little bit more sophisticated.

For example if you’re sat watching TV, it’s good to have the lamp on and you don’t want it turning off as you are probably sat still. You also don’t want the main light coming on every time you move. I guess I could tell alexa I’m watch TV and she set’s a toggle in home assistant, or maybe its possible to use some status from my fire stick.

The other scenario is when I’m in bed, so every room has motion sensors controlling the lights. I have some routines for “Alexa, I’m getting ready for bed” and “Alexa, good night”. But I think once the latter has been said then motion events shouldn’t turn on light, especially the bedroom light (the Mrs really wasn’t pleased).

But then like everything there are exceptions, whilst some can be dealt with by asking Alexa to turn something on which works for ad lib scenarios. The least manual intervention, the better really. But there are always those dilemmas such as going to the bathroom in the middle of the night. If I disable the motion sensor after saying “Alexa, good night”, then do I have to say “Alexa, turn on the light” or “Alexa, I’m going to the bathroom”, or is me talking to Alexa going to disturb other people. I don’t have the answer to some of these questions, not do I expect you to, but I would be interested to know how people have dealt with some of these common scenarios and how sophisticated or simple of a solution they have come up with.

What version of Home Assistant are you using?

also “Off” here should be lowercase:

  - condition: state
    entity_id: input_boolean.ambient_mode
    state: 'off'

all states in HA are generally all lowercase unless you’ve looked in the states page and verified otherwise.

But TBH, to do the things you want to try to minimize duplication of the code you’re going to have to learn to use templating. Which is more of an advanced concept.

And another thing that you’ll likely have to give up is the automation UI editors. They are OK (barely…) for basic stuff but they don’t lend themselves to more advanced stuff yet.

Another general tip if you want multiple (exclusive) modes is to use an input dropdown instead of a switch.
You will soon come to a stage where you need to differentiate between “modes” like “day”, “night”, “on holiday”, “weekend morning” etc etc. and keeping track of individual switches for all of these and giving priority to the right one (what if it is both night and you are also away on holiday?)

Hi I’m on 0.113.0b3

Yeah I think the templating is where I’m getting to now, just don’t have much experience which HA’s templating. TBH I don’t really use the UI editors for the automations I have so far, even some of the basic things I haven’t managed to achieve using the UI. Don’t worry about simplifying complexity for my benefit I’m a developer by day :slight_smile: I just want to get my head around the automations, so I can get them to a place where they become more responsive to real life rather than my current, turn light on when the sun is set and motion is detected. :slight_smile:

Yes that sounds more expandable for any future requirements I may come up with, good shout. I take it with the dropdowns you can have a multi-select option?

Really? it looks like the automation you posted was made by the device automation UI editor since it has all of the extraneous “id: ‘1585417563603’/device_id: 0310800ab747484283cf6fb58715fb0d/domain: binary_sensor/ entity_id: binary_sensor.lounge_motion/platform: device/type: motion” stuff. Those are usually only in there from the UI editor. I’ve never seen anyone hand code an automation with any of that included.

But since you have all of your lights named in a pattern it will be a bit easier to template things:

- alias: Turn On Lights when motion detected
  trigger:
    - platform: state
      entity_id: 
        - binary_sensor.lounge_motion
        - binary_sensor.other_motion
        - binary_sensor.someother_motion
        - binary_sensor.etc_motion
      to: 'on'
  condition:
    - condition: or
      conditions:
      - before: sunrise
        condition: sun
      - after: sunset
        condition: sun
    - condition: state
      entity_id: input_boolean.ambient_mode
      state: 'off'
  action:
    - service: light.turn_on
      data_template: 
        entity_id: >
          light.{{ trigger.entity_id.split('.')[1].split('_')[0] }}_light
    - data_template: 
        entity_id: >
          timer.{{ trigger.entity_id.split('.')[1].split('_')[0] }}
      service: timer.cancel
    - data_template:
        duration: 00:02:00
        entity_id: >
          timer.{{ trigger.entity_id.split('.')[1].split('_')[0] }}
      service: timer.start
  mode: single

that will work as long as the motion sensor has only one word before “_motion”.

So “binary_sensor.living_room_motion” won’t work but “binary_sensor.livingroom_motion” will. That’s because of the way the “.split()” function selects which piece of the split list to use (it’s 0 indexed)

as far as the different modes it will probably be easier to just use three different automations using the different conditions based on the input_select (which can only have one option selected at a time).

and you can template that too:

- alias: Turn On Lights when motion detected ambient mode
  trigger:
    - platform: state
      entity_id: 
        - binary_sensor.lounge_motion
        - binary_sensor.other_motion
        - binary_sensor.someother_motion
        - binary_sensor.etc_motion
      to: 'on'
  condition:
    - condition: or
      conditions:
      - before: sunrise
        condition: sun
      - after: sunset
        condition: sun
    - condition: template
      value_template: "{{ states('input_select.mode') == ambient }}"
  action:
    - service: light.turn_on
      data_template: 
        entity_id: >
          light.{{ trigger.entity_id.split('.')[1].split('_')[0] }}_light
    - data_template: 
        entity_id: >
          timer.{{ trigger.entity_id.split('.')[1].split('_')[0] }}
      service: timer.cancel
    - data_template:
        duration: 00:02:00
        entity_id: >
          timer.{{ trigger.entity_id.split('.')[1].split('_')[0] }}
      service: timer.start
  mode: single

then just create two more automations changing the word “ambient” in the value_template for whatever the other input_select options you have and creating the appropriately templated actions.

If you want to get really fancy you could probably use scripts to actually perform the actions based on which input_select option you choose. But I think I’ve given you enough to play with for now. :wink:

Building on what’s been suggested so far (and I’m just going to deal with your original request, you can refine as you go)…

- trigger:
  - platform: state
    entity_id:
    - binary_sensor.lounge_motion
    - binary_sensor.X_motion
    - binary_sensor.Y_Z_motion
    to: 'on'
  condition:
  - condition: or
    conditions:
    - before: sunrise
      condition: sun
    - after: sunset
      condition: sun
  - condition: state
    entity_id: input_boolean.night_time
    state: 'off'
  mode: parallel
  action:
  - service: light.turn_on
    data_template:
      entity_id: >
        light.{{ trigger.entity_id.split('.', 1)[1].replace(
          '_motion',
          '_lamp' if is_state('input_boolean.ambient_mode', 'on') else ''
        ) }}
  - service: timer.start
    data_template:
      entity_id: >
        timer.{{ trigger.entity_id.split('.', 1)[1].replace('_motion', '') }}
      duration: "00:02:00"

Ask if you have any questions about the templates, etc.

A couple things I want to point out.

First, you should use parallel mode instead of single so that it properly handles multiple motion sensors going on at approximately the same time. Not likely, but still…

Second, you don’t need to cancel and start a timer to restart it. Just start it, and if it’s already running, that will restart it.

And for handling the timers finishing…

- trigger:
  - platform: event
    event_type: timer.finish
  mode: parallel
  condition:
  - condition: template
    value_template: >
      {% set room = trigger.event.data.entity_id.split('.', 1)[1] %}
      {% set rooms = ['lounge', 'X', 'Y_Z'] %}
      {{ room in rooms }}
  action:
  - service: light.turn_off
    data_template:
      entity_id: >
        {% set room = trigger.event.data.entity_id.split('.', 1)[1] %}
        light.{{ room }}{{ '_lamp' if is_state('input_boolean.ambient_mode', 'on') else '' }}

This depends on input_boolean.ambient_mode not changing between the on & off automations triggering. Or you could do this instead:

  action:
  - service: light.turn_off
    data_template:
      entity_id: >
        {% set room = trigger.event.data.entity_id.split('.', 1)[1] %}
        light.{{ room }}, light.{{ room }}_lamp

I believe you can reduce that to this:

  light.{{ trigger.to_state.object_id[:-6] }}light

It just slices off the last 6 characters (motion) and then tacks on light.

__
EDIT
Correction. Don’t know why I wrote trigget.object_id because I’ve created several examples that use trigger.to_state.object_id :man_shrugging: Anyway, now it’s fixed.

1 Like

Thanks for all the awesome ideas, let me try a few and I’ll get back to you shortly :slight_smile:

Hi

So I’m starting to piece together something incorporating the ideas above, it’s still a work in progress and I may change directions and separate things either in to groups on some feature or area but I’ll come back to that. I was also very interested in the new chooser as that kind of opens a ton of new possibilities, so this is me so far:

- alias: Turn On Lights
  trigger:
    - platform: state
      entity_id: 
        - binary_sensor.patio_motion
        - binary_sensor.basement_stairs_motion
        - binary_sensor.basement_hall_motion
        - binary_sensor.snug_motion
        - binary_sensor.dining_room_motion
        - binary_sensor.utility_room_motion
        - binary_sensor.toilet_motion
        - binary_sensor.hall_motion
        - binary_sensor.lounge_motion
        - binary_sensor.drawing_room_motion
        - binary_sensor.kitchen_motion
        - binary_sensor.landing_motion
        - binary_sensor.studio_motion
        - binary_sensor.bathroom_motion6
        - binary_sensor.middle_bedroom_motion
        - binary_sensor.front_bedroom_motion
        - binary_sensor.dressing_room_motion
      to: 'on'
  action:
    - choose:
      - conditions:
          - condition: template
            value_template: "{{ states('input_select.mode') == bright }}"
        sequence:
          - service: light.turn_on
            data_template: 
              entity_id: >
                light.{{ trigger.object_id[:-7] }}
      - conditions:
          - condition: template
            value_template: "{{ states('input_select.mode') == ambient }}"
        sequence:
          - service: light.turn_on
            data_template: 
              entity_id: >
                light.{{ trigger.object_id[:-6] }}lamp
    - data_template:
        duration: 00:02:00
        entity_id: >
          timer.{{ trigger.entity_id.split('.')[1].split('_')[0] }}
      service: timer.start
  mode: parallel

My thought was to remove the sun conditions as there are situations where that doesn’t apply, which I’ll explain…

So as I’ve said all lights (more or less are called) light.{room} and lamps are called light.{room}_lamp, motion is binary_sensor.{room}_motion, etc.

So the automation above was very much if its bright mode turn the light on, if it’s ambient turn the lamp on. However not every room has a lamp, so I need some way of determining which rooms do have lamps and I’m not sure how to achieve this? It’s like there could do with being some form of metadata I can query using the room name that I’ve extracted from the entityid.

Another scenario which is perhaps a little easier to deal with, although again could be seen as one of these grouping issues again, is some rooms, such as those in the basement, I would always turn the light regardless of the sun attribute.

Another thought it when I include my night profile i.e. don’t trigger lights to come on (especially in the bedrooms) there will be certain lights you would want to come on. I.e. patio lights and bathroom lights.

I guess one final thing, is that some areas I set 1 minute for the timer, like hallways and utility rooms. Again it’s one of them grouping issues either I need to separate thing, have hard code conditions, perhaps you can use arrays? or some metadata I can lookup?

Well, you must like a lot of code, because you managed to turn a single entity_id template into another dozen or so lines of code. :stuck_out_tongue_winking_eye:

Also, for a state trigger the trigger variable does not have an object_id attribute. See here. To get the object_id you can do:

trigger.entity_id.split('.', 1)[1]

or:

trigger.to_state.object_id
1 Like

There’s an example on Reddit where someone used choose to create a long-winded script that, upon closer examination, can be easily replaced with a templated service and entity_id (just two lines instead of a dozen).

@mcinnes01
You also need to delimit the words bright and ambient with quotes so that they are understood to be strings. Without them, they are assumed to be variables.

1 Like

Yeah. Although “choose” is kind of bizarre, it at least allows more traditional coding constructs. Also it’s new and “shiny” right now. So I can see where people might tend to gravitate towards it instead of service & data templates which in many circumstances lend themselves to a simpler, better solution. But there are definitely many cases where an if-elif-else is useful (which is basically what “choose” is), so I think it was worth adding.

Are you saying this part can be templated away too?

      entity_id: 
        - binary_sensor.patio_motion
        - binary_sensor.basement_stairs_motion
        - binary_sensor.basement_hall_motion
        - binary_sensor.snug_motion
        - binary_sensor.dining_room_motion
        - binary_sensor.utility_room_motion
        - binary_sensor.toilet_motion
        - binary_sensor.hall_motion
        - binary_sensor.lounge_motion
        - binary_sensor.drawing_room_motion
        - binary_sensor.kitchen_motion
        - binary_sensor.landing_motion
        - binary_sensor.studio_motion
        - binary_sensor.bathroom_motion6
        - binary_sensor.middle_bedroom_motion
        - binary_sensor.front_bedroom_motion
        - binary_sensor.dressing_room_motion

No, I was referring to this part:

  - service: light.turn_on
    data_template:
      entity_id: >
        light.{{ trigger.entity_id.split('.', 1)[1].replace(
          '_motion',
          '_lamp' if is_state('input_boolean.ambient_mode', 'on') else ''
        ) }}

But, yes, it probably could, using an event trigger looking for a state_changed event, and then a condition that looks for:

{{ trigger.event.data.entity_id|regex_match('binary_sensor\..+_motion6*') }}