Condition: template in script - doesn't stop the script?

thanks to @petro who answered in this topic, I’ve built configurable/universal notification script. I have telegram bots for my users pjy & aga, with services: notify.ntf_bot_pjy and notify.ntf_bot_aga (right now one for each - but I guess I’ll make it configurabie via variables too, so I can have only one). then, every user can set his/her preference regarding the notifications, by choosing one of the input_select list options:

input_select.kfg_isl_notifytg_pjy and input_select.kfg_isl_notifytg_aga are:

  1. turned off
  2. turned off when at home
  3. show all
  4. show all, but only important when at home
  5. only important

(numbers are read from the input_select, they are not a part of the option). the aim of my notification script is, that wherever you want, you can call it by giving it the target user, importance flag (true/false) and the message. script will check the settings, user location and should take action based on message’s importance - so, if you want to tell user “pjy” that “kitchen lamp is turned on” and you think that it’s important, you call the script like:

- service: script.spt_event_notification
  data_template:
    temp_target: "pjy"
    temp_important: true
    temp_message: "kitchen lamp is turned on"

then, the script is executed:

spt_event_notification:
  sequence:
  - condition: template
    value_template: >
      {% if (temp_target == 'pjy') %}
        {% set temp_notifytg = state_attr('input_select.kfg_isl_notifytg_pjy','options').index(states('input_select.kfg_isl_notifytg_pjy')) %}
        {% if (states.device_tracker.pjxel.state == 'home') %}
          {% set temp_home = true %}
        {% else %}
          {% set temp_home = false %}
        {% endif %}
      {% elif (temp_target == 'aga') %}
        {% set temp_notifytg = state_attr('input_select.kfg_isl_notifytg_aga','options').index(states('input_select.kfg_isl_notifytg_aga')) %}
        {% if (states.device_tracker.agaxel.state == 'home') %}
          {% set temp_home = true %}
        {% else %}
          {% set temp_home = false %}
        {% endif %}
      {% endif %}
      {% if (temp_home) %}
        {% if ((temp_notifytg > 1) and (temp_important)) %}
          true
        {% elif ((temp_notifytg == 2) and not(temp_important)) %}
          true
        {% else %}
          false
        {% endif %}
      {% elif not(temp_home) %}
        {% if ((temp_notifytg > 0) and (temp_important)) %}
          true
        {% elif ((temp_notifytg > 0) and (temp_notifytg < 4) and not(temp_important)) %}
          true
        {% else -%}
          false
        {%- endif -%}
      {%- else -%}
        false
      {%- endif -%}
  - service_template: >
      {%- if (temp_target == 'pjy') -%}
        notify.ntf_bot_pjy
      {%- elif (temp_target == 'aga') -%}
        notify.ntf_bot_aga
      {%- endif -%}
    data_template:
      message: "{{ temp_message}}"

when I test this huge, nested if-elif-else-endif template in dev-template part of HA’s frontend, everything works fine. template shows true/false status like it should, but when used “in production”, it looks like it’s skipping some parts of the template.

example - I call the script with not important message:

- service: script.spt_event_notification
  data_template:
    temp_target: "pjy"
    temp_important: false
    temp_message: "something not important happened"

user pjy is home, so temp_home = true, my notification settings are only important, so temp_notifytg = 4. dev-template gives correct answer - it shows just false, but script is giving the notification anyway. can somebody tell me why? is it something I did wrong? or maybe the condition in script’s sequence isn’t giving a proper “false” answer, but just spits out “false” string and not logic value? what’s strange - if I choose to set my notifications as turned off it is indeed turned off and script works correctly.

FYI while checking the logs I can see that there are sometimes messages like:

2018-10-06 23:30:01 WARNING (MainThread) [homeassistant.components.script] Script script.spt_event_notification already running.

but don’t know if it’s related to script’s wrong behavior.

I see a hole in your template if your temp_target doesn’t equal pjy or aga. And if you get to that point, it won’t move forward at all but you should sees an error in your logs. Just a few pointers:

  • It seems like you’re coming from a verbose language. Python and Jinja are pretty forgiving, you don’t need all those parenthesis.
  • You could also cut your data_template names down to be more manageable. They won’t interfere with key names.
  • you can condense your if statements. Some of them don’t require you to return true or false, the statement itself can be returned as a boolean (t/f).
  • You gotta make your True’s and False’s capital. Lowercase treats it as a string.

Take a look at a code chuck that is pretty much the same, but covers all your bases:

call service:

- service: script.spt_event_notification
  data_template:
    target: "pjy"
    important: True #Make this capital.
    message: "kitchen lamp is turned on"

script

spt_event_notification:
  sequence:
  - condition: template
    value_template: >
      # this is a dictionary, it maps <left>:<right>  left is the key, right is the value.
      {% set targets = {'pjy':'pjxel','aga':'agaxel'} %}
      {% if target in targets.keys() %} #if the target is in the dictionary keys
        # make an entity_id example 'input_select.kfg_isl_notifytg_aga' if the target is 'aga'
        {% set entity_id = 'input_select.kfg_isl_notifytg_{}'.format(target) %}
        # get the index number of the option in options list.
        {% set idx = state_attr(entity_id ,'options').index(states(entity_id)) %}
        # get the value from the selections based on the selections[key]
        #   Example:  get 'agaxel' if the key is 'aga' using selections['aga']
        #             making string 'device_tracker.agaxel'
        # next check if it's home.\
        {% set home = is_state('device_tracker.{}'.format(targets[target]), 'home') %}
        # make a list, 0 is off, 1 is off when not home, 2 is on, 
        #              3 is on when important and home, 4 is on when important
        {% set selections = [ False, not home, True,  important and home, important ] %}
        {{ selections[idx] if 0 < idx < len(selections) else False }}
      {% else %}
         False # if the key isn't a valid target.  Don't message anything.
      {% endif %}

You only have 1 nested if statement now, it could be easier to follow if you take the time to learn all the types used in this. Read up on Python Dictionaries and Lists.

whoa! I should be going to sleep before tomorrow’s work, but hell, I’ll try to use all your hints!

oh, and I am a copy-paste programmer, so probably that’s the reason of my verbose sources haha :wink: I know very little of this, and a lot of less of that, so please don’t laugh too loud over my scripting outcome :wink:

I am really thankful for all the knowledge & tips I just read. looks totally useful and if I’ll comprehend this quickly, I guess that a lot of my configuration files will have a make-over :wink:

all right, tomorrow will be more hardcore testing, but for now - it works good!

one thing I had to change is len(selections) - exchanged it with (selections|length) [looks like length works like a filter, and len() just gave me an error while testing in dev-template].

one more time: thanks! I learned something again :slight_smile: btw, building of the entity_id, like:

{% set entity_id = 'input_select.kfg_isl_notifytg_{}'.format(target) %}

is a thing I was thinking few weeks ago - if it’s possible to use one thing to make up another’s name, forgot about that and here we are - you answered my lost question :wink:

yah, the len func is from python, I thought it would work here. Either way, the filter will def work