Multiple notifications - device tracker

For my washing machine I’d like to only get notifications when I’m at home.
This is my example in automations.yaml

- alias: notification
  trigger:
    ... 
  action:
    - service: notify.user_one
      data:
        message: "my message"
    - condition: state
      entity_id: 'device_tracker.user_two'
      state: 'home'
    - service: notify.user_two
      data:
        message: "my message"
    - service: notify.user_three
      data:
        message: "my message"   

The problem with this is that the third user won’t get the message, when the second one isn’t at home. So the condition will block everything below.
Do you know a nice way to avoid this? I have two ideas, but I don’t know if there is a better way.

  1. One script for each user. But I also don’t know if the conditon of one script will block the others below?
  2. Turn on an input_boolean and trigger three automations with that boolean. Each with its own condiotn and message. I don’t like this idea, because it would mean much unneccesary code.

Taken from https://www.home-assistant.io/docs/automation/action/. I’ve highlighted the bit that I think is causing this to fail for you.

Conditions can also be part of an action. You can combine multiple service calls and conditions in a single action, and they will be processed in the order you put them in. If the result of a condition is false, the action will stop there so any service calls after that condition will not be executed.

If it’s only user two that has to be conditional it’s easy as @cjsimmons pointed out.

  action:
    - service: notify.user_one
      data:
        message: "my message"
    - service: notify.user_three
      data:
        message: "my message" 
    - condition: state
      entity_id: 'device_tracker.user_two'
      state: 'home'
    - service: notify.user_two
      data:
        message: "my message"

If you want them all to be conditional it could be possible with a template.

@cjsimmons
Thanks, but this is what I said here.

I want it for other users too. Do you have an example for that template?

What about scripts? Will the condition of the script stop the actions below?

automation.yaml

- alias: notification
  trigger:
    ... 
  action:
    - service: script.turn_on
      entity_id: script.user_one
    - service: notify.user_two
      data:
        message: "my message"

script.yaml

user_one:
  sequence:
    - condition: state
      entity_id: device_tracker.user_one
      state: 'home'
    - service: notify.user_one
      data:
        message: "my message"

I hope you understand what I mean. Without knowing it there could be two ways.

  1. The action in Automation does not “listen” to the condition in scripts, or
  2. The script is just a placeholder, and all commands are filled in in that action list.

They will in my example above. Users 1 and 3 get messaged (unconditionally), then user 2 might if the home test passes.

I edited my message above, you were to fast :wink:

No worries. It can be done. I’m just trying to work out how to do it. give me a minute (or ten!).

EDIT: Actually this is trickier than I thought.

  1. Before the action, you will need a set of ‘or’ conditions to make sure at least one person is home. Otherwise there is no one to notify. That’s not so hard.
  2. There are 7 possible combinations of people to notify. (1+2+3 or 1+2 or 1+3 or 2+3 or just 1 or 2 or 3). This would seem to be best done with a for loop (for each user that is home -> notify). We’ve checked that at least one person is home in the conditions. This is do-able but I’m not sure how. Someone else may be able to help, @petro, @pnbruckner, or @mf_social perhaps.
1 Like

@h4nc

You can make a basic script that does an if check, then execute that 3 times.

script:
  is_home_notify:
    - condition: template
      value_template: "{{ is_state(device_tracker, 'home') }}"
    - service_template: "{{ notify }}"
      data_template:
        message: "{{ message }}"

then in the automation:

- alias: notification
  trigger:
    ... 
  action:
    - service: script.is_home_notify
      data:
        device_tracker: device_tracker.user_1
        nofity: notify.user_1
        message: "my message"
    - service: script.is_home_notify
      data:
        device_tracker: device_tracker.user_2
        nofity: notify.user_2
        message: "my message"
    - service: script.is_home_notify
      data:
        device_tracker: device_tracker.user_3
        nofity: notify.user_3
        message: "my message"

All the data is passed as a vairable to the is_home_notify script through the variables inside data.

data:
  variable: value

transfers into the script as variable and when you access it, it will return value.

3 Likes

Thanks I will try this. This seems like a really elegant way to afford this. I like it.

I think this also answers my other question. If there is a script in the automation with a condition, this condioton will NOT affect the scripts afterwards, as this is what you use in your code. Am I right?

Yep, it should just fire the scripts and move on, not caring about the outcome.

1 Like

Coming through with the goods again petro. Nice solution.

2 Likes

This kind of code makes me worry about my whole configuration. Because this shows how compact and elegant it all could be.

Thanks to all! What a great community!

Not sure this will work. A script cannot be called when it’s still running from being called previously. Depending on timing it might work, or it might work sometimes. I think it would be easiest to have three separate scripts. Actually, it’d be easiest with three automations, each using the same trigger, but each using a condition and action for the particular person.

EDIT: I’ve toyed with the idea of enhancing the scripting to allow a condition to optionally only affect the next step. I’ve also toyed with the idea of adding if/then/else options to scripting. Just haven’t had enough time to work it all out. But if that puts ideas into someone else’s head who does have the time… :wink:

I was hoping it would be fast enough. Could always just add a wait between each one.

wait_template: "{{ is_state('script.is_home_notify', 'off') }}"

I tried something like that when I first started using HA. But unfortunately you can’t count on that working either. Again, depending on timing, if the script’s state hasn’t changed fast enough before the automation gets to the wait_template, it will blow right past it, and you’ll end up with the same problem.

So much for compartmentalizing things. An easy solution would be to create new instances of scripts when executed. But that would probably break other peoples stuff. Maybe a new script type attribute that says ‘allow copy’ or something.

Yeah, it would make sense for the system to have separate contexts for each script execution. It might even already. I really haven’t dug into it that much. But I do know that it will abort with an error if a particular script is started while it’s still running. And, I probably actually do have some scripts using the wait_template technique you suggested that I wrote a long time ago that might only be working by the grace of god. Actually, from time to time I do get the “script already running” error, so… I do need to go back over everything I’ve written at some point, but… :wink:

Regarding the script enhancements, I was thinking of starting small. E.g., add if and endif options. The if would look and work exactly the same as a condition (it would even use the same code), but its effect would be to only conditionally run all the steps up until the endif step. Later elif could be added, and maybe deal with nesting if that didn’t “just work.” But, like I said, haven’t really had time to work though it. FWIW, it would look something like this:

- if: # same options as for condition
- service: ...
- service: ...
- endif
- service: ...

Might even make sense to indent the steps inside the if. Then the endif wouldn’t even be necessary:

- if: # same options as for condition
    - service: ...
    - service: ...
- service: ...

I like the second indentation option. More like yaml, less like jinja. I feel people would get more confused with if endif with that and jinja.

I think we talked about this in a previous thread too. About adding a loop that acted like ‘sequence’.

Personally I’m totally fine using one separate script for each user. However I don’t want to use three different automations for this because I have for notifcations I’d like to trigger (washing machine, dryer, windows open, …).
This way I can use the scripts for other automations too.

So would be the code I use (untill maybe there is even a better solution^^)

script.yaml

is_home_notify_user1:
  sequence:
    - condition: template
      value_template: "{{ is_state('device_tracker.user1', 'home') }}"
    - service_template: notify.user1
      data_template:
        message: "{{ message }}"

is_home_notify_user2:
  sequence:
    - condition: template
      value_template: "{{ is_state('device_tracker.user2', 'home') }}"
    - service_template: notify.user2
      data_template:
        message: "{{ message }}"

is_home_notify_user3:
  sequence:
    - condition: template
      value_template: "{{ is_state('device_tracker.user3', 'home') }}"
    - service_template: notify.user3
      data_template:
        message: "{{ message }}"

automation looks like this:

- alias: MESSAGE
  trigger: ...
  action:
    - service: script.is_home_notify_user1
      data:
        message: "MESSAGE"
    - service: script.is_home_notify_user2
      data:
        message: "MESSAGE"
    - service: script.is_home_notify_user3
      data:
        message: "MESSAGE"

How can I reuse the massage value. Would be nicer to have “MESSAGE” only one time in the code.

Yes, that would work, but you should use service instead of service_template, and I’d probably use a state condition instead of a template condition. E.g.:

is_home_notify_user1:
  sequence:
    - condition: state
      entity_id: device_tracker.user1
      state: 'home'
    - service: notify.user1
      data_template:
        message: "{{ message }}"