Variables in 0.115 - can they be used like this?

Can variables refer to previous variables. i.e. does this work?

Can I reduce this:

      #=== Update last run time for this zone
      - service: input_text.set_value
        data_template:
          entity_id: >
            input_text.irrigation_{{ zone }}_previous_duration_in_seconds
          value: >
            {% set original_duration = states('sensor.irrigation_' ~ cycle ~ '_' ~ zone ~ '_actual_duration_in_seconds') | float %}
            {% set duration_remaining = state_attr('timer.irrigation_' ~ zone ~ '_timer', 'remaining') %}
            {% set duration_remaining_hrs = duration_remaining.split(':')[0] | float %}
            {% set duration_remaining_mins = duration_remaining.split(':')[1] | float %}
            {% set duration_remaining_secs = duration_remaining.split(':')[2] | float %}
            {% set duration_remaining_secs = duration_remaining_secs + (duration_remaining_mins * 60) + (duration_remaining_hrs * 3600) %}
            {{ (original_duration - duration_remaining_secs) | string }}

To this1:

      - variables:
          original_duration: "states('sensor.irrigation_' ~ cycle ~ '_' ~ zone ~ '_actual_duration_in_seconds') | float"
          duration_remaining: "state_attr('timer.irrigation_' ~ zone ~ '_timer', 'remaining')"
          duration_remaining_hrs: "duration_remaining.split(':')[0] | float"
          duration_remaining_mins: "duration_remaining.split(':')[1] | float"
          duration_remaining_secs: "duration_remaining.split(':')[2] | float + (duration_remaining_mins * 60) + (duration_remaining_hrs * 3600)"

      #=== Update last run time for this zone
      - service: input_text.set_value
        data_template:
          entity_id: "input_text.irrigation_{{ zone }}_previous_duration_in_seconds"
          value: "{{ (original_duration - duration_remaining_secs) | string }}"

1 This is a reduced example, the variables will be reused further down the script and I have a feeling that if the right people look at this then they will tell me there is a better way to have written those templates. But even if that is true, the general question still holds.

You’d have to see if they can reference eachother. Because it’s a dictionary (doesn’t start with -), I would assume they wouldn’t be able to.

At a minimum, this should work but they are all strings so you have to cast them as floats.

      - variables:
          original_duration: "{{ states('sensor.irrigation_' ~ cycle ~ '_' ~ zone ~ '_actual_duration_in_seconds') }}"
          duration_remaining: "{{ state_attr('timer.irrigation_' ~ zone ~ '_timer', 'remaining') }}"

      - service: input_text.set_value
        data_template:
          entity_id: "input_text.irrigation_{{ zone }}_previous_duration_in_seconds"
          value: "{{ (original_duration | float - duration_remaining_secs | float) | string }}"

This would probably work though

      - variables:
          original_duration: "{{ states('sensor.irrigation_' ~ cycle ~ '_' ~ zone ~ '_actual_duration_in_seconds') }}"
          duration_remaining: "{{ state_attr('timer.irrigation_' ~ zone ~ '_timer', 'remaining') }}"
      - variables:
          duration_remaining_hrs: "{{ duration_remaining.split(':')[0] }}"
          duration_remaining_mins: "{{ duration_remaining.split(':')[1] }}"
      - variables:
          duration_remaining_secs: "{{ duration_remaining.split(':')[2] | float + (duration_remaining_mins | float * 60) + (duration_remaining_hrs | float * 3600) }}"
      - service: input_text.set_value
        data_template:
          entity_id: "input_text.irrigation_{{ zone }}_previous_duration_in_seconds"
          value: "{{ (original_duration | float - duration_remaining_secs | float) | string }}"

I hadn’t thought of it like that.
I’ll have to experiment…
Thanks

So, I never read the docs on variables but it looks like your original thought should work

I did but I wasn’t sure if a templated variable could be referred to in a later variable within the same ‘block’. But I suppose there’d be no difference.

Also I just saw the discussion on anchors. If I read that right it seems that whole block of jinja where I set the variables could also just be an anchor if I can get the indentation right…?

Although using variables: is infinitely more readable IMO.

Well no, you’d need a field to put it in (at least I think).

Oh yeah, anchors are nice but they are hard to follow when they are everywhere.

yep.I just tested that, a complete condition and action block in anchors, including the new variable with a template :wink:
how’s that for a Thursday evening.

1 Like

not quite what he was asking. I believe he wanted to put the jinja block in an anchor like this:

          value: > &something
            {% set original_duration = states('sensor.irrigation_' ~ cycle ~ '_' ~ zone ~ '_actual_duration_in_seconds') | float %}
            {% set duration_remaining = state_attr('timer.irrigation_' ~ zone ~ '_timer', 'remaining') %}
            {% set duration_remaining_hrs = duration_remaining.split(':')[0] | float %}
            {% set duration_remaining_mins = duration_remaining.split(':')[1] | float %}
            {% set duration_remaining_secs = duration_remaining.split(':')[2] | float %}
            {% set duration_remaining_secs = duration_remaining_secs + (duration_remaining_mins * 60) + (duration_remaining_hrs * 3600) %}
            {{ (original_duration - duration_remaining_secs) | string }}

which I’m 95% sure won’t work.

Actually I’ve just realised, a huge downside to using variables: is that it requires more effort to test in the template editor.

You have to {% set %} all the variables there anyway.

And as this is my thread I can digress and refer back to that other thread and ask, what is @Mariusthvdb doing with {% set mode is ...?

Ooooh, you’re all testing me today.

- service: input_text.set_value
  data_template:
    entity_id: >
      input_text.irrigation_{{ zone }}_previous_duration_in_seconds
    <<: &something
      value: >
        {% set original_duration = states('sensor.irrigation_' ~ cycle ~ '_' ~ zone ~ '_actual_duration_in_seconds') | float %}
        {% set duration_remaining = state_attr('timer.irrigation_' ~ zone ~ '_timer', 'remaining') %}
        {% set duration_remaining_hrs = duration_remaining.split(':')[0] | float %}
        {% set duration_remaining_mins = duration_remaining.split(':')[1] | float %}
        {% set duration_remaining_secs = duration_remaining.split(':')[2] | float %}
        {% set duration_remaining_secs = duration_remaining_secs + (duration_remaining_mins * 60) + (duration_remaining_hrs * 3600) %}
        {{ (original_duration - duration_remaining_secs) | string }}

Then in the next one

- service: input_text.set_value
  data_template:
    entity_id: >
      input_text.irrigation_{{ zone }}_previous_duration_in_seconds
    <<: *something

really?

title: >
  {% set mode is trigger.to_state.state|replace('_',' ')|capitalize %}
  ALARM: {{mode}}

this is creating a variable ‘mode’ the ‘old’ way, per block, so you can re-use that in that block with the {{mode}}

Ive now created that the ‘modern way’ which enables us to use it globally in that automation throughout the action block.

Yeah but I’ve never seen ‘is’.

I’ve always used and only ever seen {% set mode = 'blah-blah' %}

:blush:
me neither… Dont know where that came from, using this myself now:

      action:
        - variables:
            mode: >
              {{trigger.to_state.state|replace('_',' ')|capitalize}}
        - service: notify.notify
          data:
            title: >
              ALARM: {{mode}}
            message: >
              {{as_timestamp(now())|timestamp_custom('%X')}}: The alarm is in '{{mode}}' mode

and yes, it used to be:

    action:
      service: notify.notify
      data:
        message: >
          {% set mode = trigger.to_state.state|replace('_',' ')|capitalize %}
          {{as_timestamp(now())|timestamp_custom('%X')}}: Alarm panel set to '{{mode}}' mode.

sorry for that confusion, and will check and correct the other thread…

1 Like

and this:

        entity_picture_template: >
          {% set person = states.device_tracker.life360_marijn %}
          <<: &location_picture
            {% set zones = states.zone|map(attribute='name')|list %}
            {% if person.attributes.country_code and person.attributes.country_code != 'nl' and
                  person.state not in zones and
                  person.state not in ['moving','driving'] %}
             /local/flags/{{person.attributes.country_code}}.png
            {% elif person.state in ['home','not_home'] %} {{person.attributes.entity_picture}}
            {% else %}
            /local/zones/{{person.state|lower|replace(' ','_')}}.png
            {% endif %}

and

        entity_picture_template: >
          {% set person = states.device_tracker.life360_w %}
          <<: *location_picture

doesnt work unfortunately.

No, you have to anchor either a series of key/value pairs or a value. You can’t do a partial value (or certainly I haven’t found any way to do so).

Would be great to have the possibility to add a YAML file to configuration file that store all variables. So you can use them everywhere in automations, scrips… Something like a global_data.yaml

Otherwise you have in different locations variables and thats not easy to manage when you use a lot of them

Just use the custom hass-variables component by rogro82.

It works exactly as you want it to. You create the variables and put them wherever you want (all in one file or in packages) and you can use them wherever you want as often as you want.

1 Like

but can we use it here, where the value_template is identical to the icon_template:

      hour_icon:
        friendly_name: Hour icon
        value_template: >
          {% set t = states('sensor.time') %}
          {% set word = ['skipthis','one','two','three','four','five','six','seven',
                         'eight','nine','ten','eleven','twelve','one'] %}
          {%- set hour = now().strftime('%-I')|int %}
          {%- set minute = now().strftime('%-M')|int %}
          {%- set index = hour if minute <= 30 else hour + 1 %}mdi:clock-time-{{word[index]}}
            {{- '-outline' if states('sun.sun') != 'above_horizon' }}
        icon_template: >
          {% set t = states('sensor.time') %}
          {% set word = ['skipthis','one','two','three','four','five','six','seven',
                         'eight','nine','ten','eleven','twelve','one'] %}
          {%- set hour = now().strftime('%-I')|int %}
          {%- set minute = now().strftime('%-M')|int %}
          {%- set index = hour if minute <= 30 else hour + 1 %}mdi:clock-time-{{word[index]}}
            {{- '-outline' if states('sun.sun') != 'above_horizon' }}
        attribute_templates:
          Hour: >
            {% set t = states('sensor.time') %}
            {{now().strftime('%-I')}}
          Minutes: >
            {% set t = states('sensor.time') %}
            {{now().strftime('%-M')}}
          Addition: >
            {% set t = states('sensor.time') %}
            {{0 if now().strftime('%-M')|int <= 30 else 1}}

this would be another example we could use the global variable in a template sensor…

Probably. Does this work?

      hour_icon:
        friendly_name: Hour icon
        value_template: &test
          >
            {% set t = states('sensor.time') %}
            {% set word = ['skipthis','one','two','three','four','five','six','seven',
                         'eight','nine','ten','eleven','twelve','one'] %}
            {%- set hour = now().strftime('%-I')|int %}
            {%- set minute = now().strftime('%-M')|int %}
            {%- set index = hour if minute <= 30 else hour + 1 %}mdi:clock-time-{{word[index]}}
              {{- '-outline' if states('sun.sun') != 'above_horizon' }}
        icon_template: *test
        attribute_templates:
          Hour: >
            {% set t = states('sensor.time') %}
            {{now().strftime('%-I')}}
          Minutes: >
            {% set t = states('sensor.time') %}
            {{now().strftime('%-M')}}
          Addition: >
            {% set t = states('sensor.time') %}
            {{0 if now().strftime('%-M')|int <= 30 else 1}}

(I can’t test it right now)

1 Like

guess it does!

cool.

1 Like