Help with complex value template

Hello,

I am having trouble with a value template using multiple criteria. Have been staring at this too long. Any assistance would be appreciated. Sensor keeps coming up as being ‘unavailable’.

As context, I am trying to setup my complex tarrif system for electricity as being “Peak”, “Shoulder”, or “Off-Peak”. This includes time of year, day of week and hour of day.

Cheers

value_template: >-
          {% set m = now().month %}
          {% set d = now().strftime("%w") %}
          {% set h = now().hour %}
          {% if m >= 4 and m <= 5 and d <= 5 and h>=7 and h < 14 %} 'S'
          {% elif m >= 4 and m <= 5 and d <= 5 and h >= 14 and h < 20 %} 'P'
          {% elif m >= 4 and m <= 5 and d <= 5 and h >= 20 and h < 22 %} 'S'
          {% elif m >= 4 and m <= 5 and d <= 5 %} 'OP'
          {% elif m >= 4 and m <= 5 and h >= 7 and h < 17 %} 'S'
          {% elif m >= 4 and m <= 5 %} 'OP'
          {% elif m > 5 and m <= 8 and d <= 5 and h>=7 and h < 17 %} 'S'
          {% elif m > 5 and m <= 8 and d <= 5 and h >= 17 and h < 21 %} 'P'
          {% elif m > 5 and m <= 8 and d <= 5 and h >= 20 and h < 22 %} 'S'
          {% elif m > 5 and m <= 8 and d <= 5 %} 'OP'
          {% elif m > 5 and m <= 8 and h >= 7 and h < 22 %} 'S'
          {% elif m > 5 and m <= 8 %} 'OP'
          {% elif m > 8 and m <= 10 and d <= 5 and h>=7 and h < 14 %} 'S'
          {% elif m > 8 and m <= 10 and d <= 5 and h >= 14 and h < 20 %} 'P'
          {% elif m > 8 and m <= 10 and d <= 5 and h >= 20 and h < 22 %} 'S'
          {% elif m > 8 and m <= 10 and d <= 5 %} 'OP'
          {% elif m > 8 and m <= 10 and h >= 7 and h < 22 %} 'S'
          {% elif m > 8 and m <= 10 %} 'OP'
          {% elif d <= 5 and h>=7 and h < 14 %} 'S'
          {% elif d <= 5 and h >= 14 and h < 20 %} 'P'
          {% elif d <= 5 and h >= 20 and h < 22 %} 'S'
          {% elif d <= 5 %} 'OP'
          {% elif h >= 7 and h < 22 %} 'S'
          {% else %} 'OP'
          {% endif %}

It may be a copy/paste error, but it should be

value_template

not

Value template

Thanks, yes it is a copy paste error. code uses value_template: >-

Can you just describe what the values should be? Your code makes sense but it seems like it can be refactored to make it easier to read.

Right now, you can easily simplify some of it by swapping these statements:

to

{% if 4 <= m <= 5

Then I recommend nesting your if statements instead of using flat if - elif’s

Thanks, I assume you mean having if statements within if statements. I started with that but have been debugging to try and get it to work.

As an example: currently we are in month 12 (december) and the day of the week is 4 (thursday). It is 1:36pm where i am, so it should return a value of ‘S’ being shoulder period. The line which should bring this is {% elif d <= 5 and h>=7 and h < 14 %} 'S'

I’m having trouble returning any value. The structure seem to be tripping up and returning unavailable. I would think if the conditions themselves weren’t structured properly, it would at least be returning ‘OP’ via {% else %} 'OP'

now().strftime("%w") returns a string not an integer, so you can’t do mathematical comparisons without converting it first or you can just use now().isoweekday()

{% set m = now().month %}
{% set d = now().isoweekday() %}
{% set h = now().hour %}
  
{% if  4 <= m <= 5  %}       
  {% if d <= 5 %}
     {% if 14 > h >=7 %} S
     {% elif  20 > h >= 14 %} P
     {% elif 22 > h >= 20 %} S
     {% else %} OP
     {% endif %}
  {% elif  17 > h >= 7 %} S
  {% else %} OP
  {% endif %}     

{% elif 8 >= m > 5 %}
  {% if d <= 5 %}
    {% if 17 > h >= 7 %} S
    {% elif 21 > h >= 17 %} P
    {% elif 22 > h >= 20 %} S
    {% else %} OP
    {% endif %}
  {% elif h >= 7 and h < 22 %} S
  {% else %} OP
  {% endif %}

... 

{% endif %}

1 Like

Cheers @Didgeridrew that solved it. Here was the final code:

        value_template: >-
          {% set m = now().month %}
          {% set d = now().isoweekday() %}
          {% set h = now().hour %}
          
          {% if 4 <= m <= 8 and d <= 5 and 0 <= h < 7 %} OP
          {% elif 4 <= m <= 8 and d <= 5 and 7 <= h < 14 %} S
          {% elif 4 <= m <= 5 and d <= 5 and 14 <= h < 20 %} P
          {% elif 4 <= m <= 5 and d <= 5 and 20 <= h < 22 %} S
          {% elif 4 <= m <= 8 and d <= 5 and 22 <= h < 24 %} OP
          
          {% elif 4 <= m <= 5 and d >= 6 and 0 <= h < 7 %} OP
          {% elif 4 <= m <= 5 and d >= 6 and 7 <= h < 17 %} S
          {% elif 4 <= m <= 5 and d >= 6 and 17 <= h < 24 %} OP
          
          {% elif 5 < m <= 8 and d <= 5 and 0 <= h < 7 %} OP
          {% elif 5 < m <= 8 and d <= 5 and 7 <= h < 17 %} S
          {% elif 5 < m <= 8 and d <= 5 and 17 <= h < 21 %} P
          {% elif 5 < m <= 8 and d <= 5 and 21 <= h < 22 %} S
          {% elif 5 < m <= 8 and d <= 5 and 22 <= h < 24 %} OP
          
          {% elif 5 < m <= 8 and d >= 6 and 0 <= h < 7 %} OP
          {% elif 5 < m <= 8 and d >= 6 and 7 <= h < 22 %} S
          {% elif 5 < m <= 8 and d >= 6 and 22 <= h < 24 %} OP
          
          {% elif 8 < m <= 10 and d <= 5 and 0 <= h < 7 %} OP
          {% elif 8 < m <= 10 and d <= 5 and 7 <= h < 14 %} S
          {% elif 8 < m <= 10 and d <= 5 and 14 <= h < 20 %} P
          {% elif 8 < m <= 10 and d <= 5 and 20 <= h < 22 %} S
          {% elif 8 < m <= 10 and d <= 5 and 22 <= h < 24 %} OP
          
          {% elif 8 < m <= 10 and d >= 6 and 0 <= h < 7 %} OP
          {% elif 8 < m <= 10 and d >= 6 and 7 <= h < 22 %} S
          {% elif 8 < m <= 10 and d >= 6 and 22 <= h < 24 %} OP
          
          
          {% elif m < 4 or m >= 11 and d <= 5 and 0 <= h <= 7 %} OP
          {% elif m < 4 or m >= 11 and d <= 5 and 7 <= h < 14 %} S
          {% elif m < 4 or m >= 11 and d <= 5 and 14 <= h < 20 %} P
          {% elif m < 4 or m >= 11 and d <= 5 and 20 <= h < 22 %} S
          {% elif m < 4 or m >= 11 and d <= 5 and 22 <= h <= 24 %} OP
          
          {% elif m < 4 or m >= 11 and d >= 6 and 0 <= h < 7 %} OP
          {% elif m < 4 or m >= 11 and d >= 6 and 7 <= h < 22 %} S
          {% elif m < 4 or m >= 11 and d >= 6 and 22 <= h < 24 %} OP
          
          {% endif %}

Why doesn’t the “final code” look like what is in the post you marked as the Solution?

Because the issue and solution was related to using now().isoweekday() rather than now().strftime("%w"). The code looks different as i prefer to not use nested if statements, whereas Didgeridrew’s code did use nested if statements.

The only difference between the two is that one indexes weekdays from 0 to 6 and the other from 1 to 7. Both are equally effective at reporting the day of the week. However, I suspect you didn’t know that when you created the template and so everywhere you used d <= 5 you assumed it meant Monday (1) to Friday (5) when it actually meant Sunday (0) to Friday (5).

What you referred to as a “complex template” isn’t actually complex, just needlessly bloated. Didgeridrew simplified it by removing all the duplicated and unnecessary logic.

Anyway, it’s the featured Solution post so, hopefully, it will steer other users in the right direction.


EDIT

Correction. Fixed and enhanced day ranges.

2 Likes

Thanks. I tested now().isoweekday() and now().strftime("%w") and found they both report a value of 4 for Thursday.

Yes but @Didgeridrew pointed out…

What I was saying was to nest it, but nest it intelligently. Right now your doing elif and covering every possibility when you can reorganize and have proper fallbacks with nesting. For example, always check peak first. Then shoulder next. Then everything else falls outside that and you don’t need to provide the timerange. If you check peak first, you don’t have to define 2 time ranges for shoulder. Just check the whole thing because peak would have already been hit.

and reduce it to something readable, then copy/paste and adjust numbers.

{% if 4 <= m <= 5 %}
  {% if d <= 5 %}
    {% if 14 <= h < 20 %}P
    {% elif 7 <= h < 22 %}S
    {% else %}OP
    {% endif %}
  {% else %}
    {% if 17 <= h < 21 %}P
    {% elif 7 <= h < 22 %}S
    {% else %}OP
    {% endif %}
  {% endif %}
... add elifs here...

You can even make a macro because shoulder looks like it’s always between 7 and 22 for all months, you simply just need to define peak.

{% macro terriff(hour, peak_start, peak_end) %}
{% if peak_start <= hour <= peak_end %}P
{% elif 7 <= hour < 22 %}S
{% else %}OP
{% endif %}
{% endmacro %}

{% if 4 <= m <= 5 %}
  {% if d <= 5 %}
    {{ terriff(h, 14, 20) }}
  {% else %}
    {{ terriff(h, 17, 21) }}
  {% endif %}
... add elifs here...

Thanks, I have switched over to nested conditions now. I had no idea you could do macros like this - will come in handy!

1 Like