[SOLVED] Service_template in breaks rule

Hi there,

I’m new to Home Assistant, coming from openHAB, but I am really impressed how smooth and easy some things are working. But there are also some problems I encountered; most of them I can solve by myself, but regarding the following, I actually have no clue, what to do.

(I think it’s similar to this posting: Rule broken)

I have a lock, which I want do get locked within the action part of a rule. But this should happen only, if it’s unlocked. So my rule looks like this:

  ## Tür abschließen
  - service_template: >
      {% if is_state('lock.hm_sec_key', 'unlocked') %}
        lock.lock
      {%- else -%}
        # Do nothing
      {% endif %}
    entity_id: lock.hm_sec_key

The rules breaks at this point.
This on the other hand works:

## Tür abschließen
  - service_template: >
      {% if is_state('lock.hm_sec_key', 'unlocked') %}
        lock.lock
      {%- else -%}
        lock.unlock
      {% endif %}
    entity_id: lock.hm_sec_key

So, I understand, that I seem to always have to put a service call inside the “else” block, right? But what if I don’t want anything to happen “else”? If I just delete the else-part like this, the rule also breaks:

  ## Tür abschließen
  - service_template: >
      {% if is_state('lock.hm_sec_key', 'unlocked') %}
        lock.lock
      {% endif %}
    entity_id: lock.hm_sec_key

How can I achieve to lock the door in my rule, when it is unlocked without doing anything else?

Thank you very much for your ideas, help or insights! :slight_smile:

Cheers
Norman

Instead of using a service template use a condition to check

{% if is_state('lock.hm_sec_key', 'unlocked') %}

If it’s true your action (lock.lock) can be executed.

This I can’t do. I forget to mention, that there are more actions in that rule. All actions above the lock-part work, the ones below don’t (because of the “breaking” of the rule). The rule must execute regardless of the state of the lock.

Move the lock action to the end of your actions and put the condition above it (you can put conditions in actions).

easiest solution for that, and you can use it anywhere in HA after this, is to use a dummy script (doing nothing), which you create in your scripts configuration:

script:
  dummy:
    alias: 'Dummy script'
    sequence:
      delay: 00:00:00

and call that in the else clause.

You have to care a bit for the if cause, because this dummy script doesnt use an entity_id.
What I do most of the time, and this makes it even more customizable, is to create a script in the if clause also, which than can use the entity_id just fine

  - service_template: >
      {% if is_state('lock.hm_sec_key', 'unlocked') %}
        script.lock
      {%- else -%}
        script.dummy
      {% endif %}

or shorter:

     script.{{'lock' if is_state('lock.hm_sec_key', 'unlocked') else 'dummy'}}
 

and script lock would then be:

script:
  lock:
    alias: 'Dummy lock'
    sequence:
      service: lock.lock
      entity_id: lock.hm_sec_key
2 Likes

I think you refer to something like this: Multiple Actions, but skip some based on conditions. Possible?

This will work, thank you! But I think it’s a limited way to achieve such a goal as mine, because you have to put the action at the end of the rule and you can’t add another different condition after that.

Thank you very much for this! Works like a charm!

Here’s an alternative solution. It leverages the fact that Home Assistant won’t complain if you specify a non-existent entity.

## Tür abschließen
  - service_template: >
      {{ 'lock.lock' if is_state('lock.hm_sec_key', 'unlocked') else 'lock.unlock' }}
    data_template:
      entity_id: >
        {{ 'lock.hm_sec_key' if is_state('lock.hm_sec_key', 'unlocked') else 'lock.nothing' }}
  • The service_template calls lock.lock service if hm_sec_key is unlocked otherwise it calls lock.unlock.
  • The data_template sets the entity to hm_sec_key if it is unlocked otherwise it sets it to a non-existent entity (lock.nothing).

Hey Taras, ive seen you suggest this before, and it strikes me as so unlike you tbh (please dont take offense). You are one of the most precise coders in the community, and a creative one at that.

It is clearly an oversight of HA to not complain on referencing a non-existing entity, if not a bug. Would think this to be a matter of time for the dev-team to correct it.

Why would you advise on using this ‘hack’, when valid ways of doing this are available at no effort at all? Just because it is not erring out doesnt mean it’s sound programming?

A hack is a hack is a hack: specifying a non-existent entity or calling a do-nothing script.

If the devs wish to correct something, they can implement one of the following (or both):

  1. Allow Home Assistant to ignore a service_template that returns nothing
  2. Allow for the use of a do-nothing service (call it homeassistant.none)

The first would allow for this:

  - service_template: >
      {% if is_state('lock.hm_sec_key', 'unlocked') %}
        lock.lock
      {% endif %}
    entity_id: lock.hm_sec_key

The second would allow for this:

  - service_template: >
      {% if is_state('lock.hm_sec_key', 'unlocked') %}
        lock.lock
      {%- else -%}
        homeassistant.none
      {% endif %}
    entity_id: lock.hm_sec_key

In both cases, if the lock is already locked, nothing happens (no warnings or errors and no actual service is called).

well, you know this is incorrect.
a do nothing script is nowhere near a non-existing entity. It might work, but it isn’t clean.

and what the dev’s could/should do might be a fine subject for an architecture discussion :wink:
creating an error on acting on a non-existing entity should be listed as first option…

I’ll borrow your phrase:

well, you know this is incorrect.

I’ve read the full thread and I’m really torn.
And although everything Taras has said is true and defendable, I feel that my preference would be to follow Marius’s position.
Ultimately I do think the dummy script is a hack (one that works and breaks no rules) but I REALLY like the idea of making proper provision for a null operation, and something along the lines of Taras’s homeassistant.none would fit that bill nicely

The dummy script is one of the shortest ways of telling Ha to do nothing. There are moments in life one has to formulate a to do action to do nothing… they tend to be life savers . These are no hacks, they’re simply another way of formulating things.
And yes, that’s clean, and always works. No exception.

Imagine being in an icey curve driving your car. people tend to react to push the brake and steer in the opposite direction to stay on track.

My script would be the analogy of: don’t let go of your steering wheel, don’t brake, and simply steer along with the car. No hack, a simple instruction to keep going, instead of not instructing to do anything.
Or even worse:
Imagine being told to push a button that isn’t there :wink:

haha, of course this is a bit over the top. And there is always more than 1 way to reach the same goal. Appreciate that.
Always appreciate Taras contributions for that matter. And yes, we could do with a none action.
Then again, we already have that…

Two sides of the same coin:

  • Call a script that achieves nothing.
  • Use an entity that achieves nothing.

Two ways of achieving nothing … all because the YAML automation demands we give it something to do … even if it’s to do nothing. :slight_smile:

as a final question/remark, and not to be nitpicking, but it’s not about Yaml is is? Isn’t about building a safeguard in our templates? Always have an else clause, to prevent trouble from happening when none of the if’s are met. In that, it is more fundamental than simple Yaml syntax.

Either way, let’s call it a night :wink: Cheers!

1 Like

No, not specifically YAML but the way it’s used to define automations. Effectively, it is used to create placeholders and our obligation is to populate them.

So, in a manner of speaking, YAML is used to create a form with fields and we must fill in the fields … and you can’t leave a field blank. So if your ‘form’ contains the service_template ‘field’, it can’t be left blank therefore its template must generate something … even if that something is to do nothing. :slight_smile:

I still say this is an incorrect use of a service template.

Service templates are for choosing between different types of services depending on some variable. If you only have only have one service you want to run conditionally then use a condition.

I agree. That’s the cleanest solution. You phrased it best:

Except, some (including me) want the automation/script to continue after the decision.