Help with template sensor icon please

After a long time trying I’ve made a nice template sensor that calculates the current height of our local tide. It’s not elegant, but it works. My next challenge is to make its icon show whether the tide is rising or falling. I’m using two local variables from the tidal height calculation, but it looks like they are not available to the icon: statement. Can anyone help me resolve this?

template:
  - sensor:
    - name: height now
      unique_id: height_now
      state_class: measurement
      unit_of_measurement: m
      state: >
        {% set last_tide = states.sensor.tide1.state %}
        {% set last_ht = states.sensor.tide1h.state %} 
        {% set next_tide = states.sensor.tide1.state %}
        {% set next_ht = states.sensor.tide1h.state %} 
        {%- if as_timestamp(states.sensor.tide1.state) >= as_timestamp(now()) %} 
          {% set next_tide = states.sensor.tide1.state %}
          {% set next_ht = states.sensor.tide1h.state %} 
        {%- elif as_timestamp(states.sensor.tide2.state) >= as_timestamp(now()) %} 
          {% set last_tide = states.sensor.tide1.state %}
          {% set last_ht = states.sensor.tide1h.state %} 
          {% set next_tide = states.sensor.tide2.state %}
          {% set next_ht = states.sensor.tide2h.state %} 
        {%- elif as_timestamp(states.sensor.tide3.state) >= as_timestamp(now()) %}  
          {% set last_tide = states.sensor.tide2.state %}
          {% set last_ht = states.sensor.tide2h.state %} 
          {% set next_tide = states.sensor.tide3.state %}
          {% set next_ht = states.sensor.tide3h.state %} 
        {%- elif as_timestamp(states.sensor.tide4.state) >= as_timestamp(now()) %}  
          {% set last_tide = states.sensor.tide3.state %}
          {% set last_ht = states.sensor.tide3h.state %} 
          {% set next_tide = states.sensor.tide4.state %}
          {% set next_ht = states.sensor.tide4h.state %} 
        {%- elif as_timestamp(states.sensor.tide5.state) >= as_timestamp(now()) %}  
          {% set last_tide = states.sensor.tide4.state %}
          {% set last_ht = states.sensor.tide4h.state %} 
          {% set next_tide = states.sensor.tide5.state %}
          {% set next_ht = states.sensor.tide5h.state %} 
        {% endif -%}
        {{last_ht | float + 0.5*(next_ht | float - last_ht | float) * (1-cos(3.1415926|float * (as_timestamp(now())-as_timestamp(last_tide))/(as_timestamp(next_tide)-as_timestamp(last_tide)))) }}
      icon: >
        {% if next_ht | float < last_ht | float %} 
          mdi:arrow-down 
        {% else %} 
          mdi:arrow-up 
        {% endif %}

The Jinja2 variables defined in one YAML option like, next_ht in state, are undefined if referenced in any other YAML option, like next_ht in icon.

A Jinja2 variable’s scope is limited to the YAML option where it’s defined.

I can see that. Is there a work around that does not make me repeat the whole block of code do you know?

It has to be repeated.

You may wish to consider voting for the following Feature Request:

Note: this is not a solution to the actual question posed and will still need repeating.

Slightly shorter block of code, which I think should work. Try it out in the Template Editor first, of course:

{% set tl = [states('sensor.tide1'), states('sensor.tide2'), states('sensor.tide3'), states('sensor.tide4'), states('sensor.tide5')] %}
{% set hl = [states('sensor.tide1h'), states('sensor.tide2h'), states('sensor.tide3h'), states('sensor.tide4h'), states('sensor.tide5h')] %}
{% set tsl = tl|map('as_timestamp', default=0)|list %}
{% set idx = tsl.index(tsl|select('>=',as_timestamp(now()))|first) %}
{% set last_tide, last_ht = tl[idx-1], hl[idx-1] %}
{% set next_tide, next_ht = tl[idx], hl[idx] %}

{{ last_tide }} {{ last_ht }}
{{ next_tide }} {{ next_ht }}

Thanks Troon, that’s very clever & worked perfectly. I wish I knew enough to do that!
It makes me wonder whether I can simplify the multiscrape that generated all those tide times & heights. I’ve also got a list sensor.tide0 which contains 4 sets of 3 [state/time/height]:

['Low', '06:20', '1.67m', 'High', '11:49', '5.70m', 'Low', '18:56', '1.88m', 'Low', '05:20', '1.67m', 'High', '10:49', '5.70m', 'Low', '17:56', '1.88m', 'High', '23:22', '5.86m']

Can this be used to make it even simpler?

Potentially. Try this:

{% set a = ['Low', '06:20', '1.67m', 'High', '11:49', '5.70m', 'Low', '18:56', '1.88m', 'Low', '05:20', '1.67m', 'High', '10:49', '5.70m', 'Low', '17:56', '1.88m', 'High', '23:22', '5.86m'] %}
Tides: {{ a[0::3] }}
Times: {{ a[1::3] }}
Heights: {{ a[2::3] }}

How does Troon’s example fullfil your request?

Long or short(er), you still have to duplicate it.

Sorry, have I made a faux pas? Having accepted the limitation you pointed out, Troon has provided a more elegant & efficient block of code to repeat. FWIW I voted for your feature request, which I can see being useful in other areas I’m working on.

The purpose of the Solution tag is to answer/resolve the original question/problem. It helps lead other users to the post that helps them answer/resolve the original question/problem. For more information, see guideline 21 in the FAQ.

You asked:

Is there a work around that does not make me repeat the whole block of code

The answer is no; you must repeat it.

That’s the answer other users, seeking to solve the same problem, ought to be directed to. There’s no workaround; you have to repeat the code block.

Troon’s template is an elegant reduction of your original template but it isn’t a workaround for duplication. Whether you copy-paste 30 lines of template or just 8, you still have to make a complete duplicate.

1 Like