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.

2 Likes

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