Spot the error... nested template

What am I missing… been staring at this for hours now, and the individual bits are correct, the complete template simply doesn’t output:

          {% set alarm = states('sensor.alarmclock_wd_time') if now().weekday() in [0,1,2,3,4]
                    else states('sensor.alarmclock_we_time') %}
          {% set now = now().time().strftime('%H:%M')%}

          {% if alarm < now %}
             {% if (now().weekday() in [0,1,2,3,6] and is_state('input_boolean.alarmclock_wd_enabled','on')) or 
                (now().weekday() in [4,5] and is_state('input_boolean.alarmclock_we_enabled','on')) %} Tomorrow
             {% else %} Not tomorrow
             {% endif %}

          {% elif alarm == 'Not set' %} Not set
          {% else %} Today
          {% endif %}

the sub If…else works fine:

 {% if (now().weekday() in [0,1,2,3,6] and is_state('input_boolean.alarmclock_wd_enabled','on')) or 
                (now().weekday() in [4,5] and is_state('input_boolean.alarmclock_we_enabled','on')) %} Tomorrow
             {% else %} Not tomorrow
             {% endif %}

and the structure template also:

          {% set alarm = states('sensor.alarmclock_wd_time') if now().weekday() in [0,1,2,3,4]
                    else states('sensor.alarmclock_we_time') %}
          {% set now = now().time().strftime('%H:%M')%}

          {% if alarm < now %} Without sub template
             
          {% elif alarm == 'Not set' %} Not set
          {% else %} Today
          {% endif %}

(flipped a boolean, so the first template changed output…

If I reverse turn both templates around in dev-template, nothing is displayed, so something must be wrong, can’t spot it though…

if I only test the {{alarm < now}} the outcome is correct:
47

But it won’t render that part of the If correctly.
it does run when alarm > now, using the else of the structure template…
Please have a look?

Might even want to do:

          {% set alarm = states('sensor.alarmclock_wd_time') if now().weekday() in [0,1,2,3,4]
                    else states('sensor.alarmclock_we_time') %}
          {% set now = now().time().strftime('%H:%M')%}

          {% if alarm < now and
             (now().weekday() in [0,1,2,3,6] and is_state('input_boolean.alarmclock_wd_enabled','on')) or 
             (now().weekday() in [4,5] and is_state('input_boolean.alarmclock_we_enabled','on')) %} Tomorrow

          {% elif alarm == 'Not set' %} Not set
          {% else %} Today
          {% endif %}

to make it simpler…:wink:

this works also, so it must the sub template:

          {% set alarm = states('sensor.alarmclock_wd_time') if now().weekday() in [0,1,2,3,4]
                    else states('sensor.alarmclock_we_time') %}
          {% set now = now().time().strftime('%H:%M')%}

          {% if alarm < now %}
             {% if 1==1 %} Tomorrow
             {% else %} Not tomorrow
             {% endif %}

          {% elif alarm == 'Not set' %} Not set
          {% else %} Today

made an intermediary sensor:

      test_tomorrow_alarm:
        friendly_name: Test tomorrow alarm
        value_template: >
          {{(now().weekday() in [0,1,2,3,6] and is_state('input_boolean.alarmclock_wd_enabled','on')) or 
            (now().weekday() in [4,5] and is_state('input_boolean.alarmclock_we_enabled','on'))}}

which makes this possible:

      next_alarm_today_full:
        friendly_name: Next alarm today full
        value_template: >
          {% set alarm = states('sensor.alarmclock_wd_time') if now().weekday() in [0,1,2,3,4]
                    else states('sensor.alarmclock_we_time') %}
          {% set now = now().time().strftime('%H:%M')%}

          {% if alarm < now %}
             {% if is_state('sensor.test_tomorrow_alarm','True') %} Tomorrow
             {% else %} Not tomorrow
             {% endif %}

          {% elif alarm == 'Not set' %} Not set
          {% else %} Today
          {% endif %}

which gets me the desired result finally.

Really can’t see why the original setup doesn’t work though… How can that be?

I’m not sure why your original template wouldn’t output anything at all.

I pasted it into my template editor (edited for my ease of reading) and I got the following (noting that I also don’t have your sensor entities):

I haven’t looked at anything you posted past that original template but the original template does produce an output for me.

thanks for having a look. Yes, sometimes it is a bit of a search. Havent found the answer in this particular case though, and have change set up. It was too simple an algorithm after all, and I am using this now:

      next_alarm_daytype:
        friendly_name: Next alarm daytype
        entity_id:
          - sensor.time
          - sensor.date
          - input_boolean.alarmclock_wd_enabled
          - input_boolean.alarmclock_we_enabled
          - input_number.alarmclock_wd_hour
          - input_number.alarmclock_wd_minute
          - input_number.alarmclock_we_hour
          - input_number.alarmclock_we_minute
        value_template: >
          {% set days = states('sensor.number_of_days_next_alarm') %}
          {% if is_state('input_boolean.alarmclock_wd_enabled','off') and
                is_state('input_boolean.alarmclock_we_enabled','off') %} Not set
          {% elif days == '0' %} Today,
          {% elif days == '1' %} Tomorrow,
          {% elif days == '2' %} Day after tomorrow,
          {% else %} More than 2
          {% endif %}

which uses the main day calculator:

        value_template: >
          {% if is_state('input_boolean.alarmclock_wd_enabled','on') %}
            {% if now().weekday() in [0,1,2,3] %}
              {% if now().time().strftime('%H:%M') < states('sensor.alarmclock_wd_time') %} 0
              {% else %} 1
              {% endif %}

            {% elif now().weekday() == 4 %}
              {% if is_state('input_boolean.alarmclock_we_enabled','on') %} 
                {% if now().time().strftime('%H:%M') < states('sensor.alarmclock_wd_time') %} 0
                {% else %} 1
                {% endif %}
              {% else %} 3
              {% endif %}

            {% elif now().weekday() == 5 %}
              {% if is_state('input_boolean.alarmclock_we_enabled','on') %}
                {% if now().time().strftime('%H:%M') < states('sensor.alarmclock_we_time') %} 0
                {% else %} 1
                {% endif %}
              {% else %} 2
              {% endif %}

            {% elif now().weekday() == 6 %}
              {% if is_state('input_boolean.alarmclock_we_enabled','on') %}
                {% if now().time().strftime('%H:%M') < states('sensor.alarmclock_we_time') %} 0
                {% else %} 1
                {% endif %}
              {% else %} 1
              {% endif %}
            {% endif %}

          {% elif is_state('input_boolean.alarmclock_we_enabled','on') %}
              {% if now().weekday() in [0,1,2,3] %} {{5 - now().weekday()}}
              {% elif now().weekday() in [4] %} 1

              {% elif now().weekday() in [5] %}
                {% if now().time().strftime('%H:%M') < states('sensor.alarmclock_we_time') %} 0
                {% else %} 1
                {% endif %}

              {% elif now().weekday() == 6 %}
                {% if now().time().strftime('%H:%M') < states('sensor.alarmclock_we_time') %} 0
                {% else %} 6
                {% endif %}
              {% endif %}

          {% else %} Not set
          {% endif %}

It is completely verbose at the moment, and I might change it soon to be shorter like this:

        value_template: >
         {% set day = now().weekday() %}
         {% set now = now().time().strftime('%H:%M') %}
         {% set weekday = is_state('input_boolean.alarmclock_wd_enabled','on') %}
         {% set weekend = is_state('input_boolean.alarmclock_we_enabled','on') %}
         {% set day_alarm = states('sensor.alarmclock_wd_time') %}
         {% set end_alarm = states('sensor.alarmclock_we_time') %}

          {% if weekday %}
            {% if day in [0,1,2,3] %}
              {% if now < day_alarm %} 0
              {% else %} 1
              {% endif %}

            {% elif day == 4 %}
              {% if weekend %} 
                {% if now < day_alarm %} 0
                {% else %} 1
                {% endif %}
              {% else %} 3
              {% endif %}

            {% elif day == 5 %}
              {% if weekend %}
                {% if now < end_alarm %} 0
                {% else %} 1
                {% endif %}
              {% else %} 2
              {% endif %}

            {% elif day == 6 %}
              {% if weekend %}
                {% if now < end_alarm %} 0
                {% else %} 1
                {% endif %}
              {% else %} 1
              {% endif %}
            {% endif %}

          {% elif weekend %}
              {% if day in [0,1,2,3] %} {{5 - day}}
              {% elif day in [4] %} 1

              {% elif day in [5] %}
                {% if now < end_alarm %} 0
                {% else %} 1
                {% endif %}

              {% elif day == 6 %}
                {% if now < end_alarm %} 0
                {% else %} 6
                {% endif %}
              {% endif %}

          {% else %} Not set
          {% endif %}

and hope to make a bit more intelligent en compress the if’s and else’s…
Need it to be as easy to check and change if necessary for this moment…

HI @petro,

all is working perfectly now, and I am using your macro template, with my own sensor for counting the days now. It needed refining with calculating whether or not the alarm would be on current day or not.

I have made it to this so far:

          {% set weekday = is_state('input_boolean.alarmclock_wd_enabled','on') %}
          {% set weekend = is_state('input_boolean.alarmclock_we_enabled','on') %}
          {% set current_day = now().weekday() %}
          {% set now_wd = now().time().strftime('%H:%M') < states('sensor.alarmclock_wd_time') %}

          {% set now_we = now().time().strftime('%H:%M') < states('sensor.alarmclock_we_time') %}

          {% if weekday %}
            {% if current_day in [0,1,2,3] %}
              {% if now_wd %} 0
              {% else %} 1
              {% endif %}

            {% elif current_day == 4 %}
              {% if weekend %} 
                {% if now_wd %} 0
                {% else %} 1
                {% endif %}
              {% else %} 3
              {% endif %}

            {% elif current_day == 5 %}
              {% if weekend %}
                {% if now_we %} 0
                {% else %} 1
                {% endif %}
              {% else %} 2
              {% endif %}

            {% elif current_day == 6 %}
              {% if weekend %}
                {% if now_we %} 0
                {% else %} 1
                {% endif %}
              {% else %} 1
              {% endif %}
            {% endif %}

          {% elif weekend %}
              {% if current_day in [0,1,2,3] %} {{5 - current_day}}
              {% elif current_day in [4] %} 1

              {% elif current_day in [5] %}
                {% if now_we %} 0
                {% else %} 1
                {% endif %}

              {% elif current_day == 6 %}
                {% if now_we %} 0
                {% else %} 6
                {% endif %}
              {% endif %}

          {% else %} Not set
          {% endif %}

And am trying to see if something more compressed like what you had before would be possible:


          {% set weekday = is_state('input_boolean.alarmclock_wd_enabled','on') %}
          {% set weekend = is_state('input_boolean.alarmclock_we_enabled','on') %}
          {% set current_day = now().weekday() %}

          {% if weekday and not weekend %}
            {% set offset = 7-current_day if current_day in range(4,7) else 1 %}
          {% elif not weekday and weekend %}
            {% if current_day in range(4) %}
              {% set offset = 5 - current_day %}
            {% else %}
              {% set offset = 6 if current_day == 6 else 1 %}
            {% endif %}
          {% elif weekday and weekend %}
             {% set offset = 1 %}
          {% else %}
             {% set offset = None %}
          {% endif %}

would you know how to fit in the now<alarm test in to that and make it as short as possible?
thanks for having another look if you would…

I have no clue what you are trying to do? I thought this was already solved as the total template I provided would give you the time til the next alarm.

It almost did that… It didn’t make a difference on current day, between times before or after current time. And hence there where no 0 days (alarm today)

I had to write it out completely, and at this moment that template is as it should. It is rather verbose… so would have hoped to be able to compress it like you did before?

The macro was designed to handle that. If it’s not doing that, then it has a bug. I don’t have any of these devices, so I simulate them. It was working on my end.

appreciate that of course, that’s why I took a while to sort things…

The macro didn’t work 100% so I changed template to:

            {% set in_days = states('sensor.number_of_days_next_alarm') %}
            {% set today_alarm = getalarm() | float %}
            {% set next_alarm = getalarm(in_days|int) | float %}
            {% set alarm = next_alarm if in_days|int > 0 else today_alarm %}
            {% set days = alarm // 86400 %}

using the in_days calculation of my own sensor. There was this strange behavior of the % d too, so changed that also, to:

              {% if days %} {{days|int}}:{{ next_alarm | timestamp_custom('%-H:%-M', False) }}
              {% else %} {{ alarm | timestamp_custom('%-H:%-M', False) }}
              {% endif %}

with these 2 adaptations, the sensor works perfectly now…
Must admit I didn’t yet grasp the workings of the macro completely, so wouldn’t really be able to pin the error down. Must be this line:

            {{ (offset - time) + alarm if offsetday else alarm - time }}

where is it comparing the current time to the alarm time on the same day?

is eqivalent to:

{% if offsetday %}
{{ (offset - time) + alarm }}
{% else %}
{{ alarm - time }}
{% endif %}

the {% if offsetday %} checks if the offset is non-zero. I.e. set to 1 or above. I.E 0 = today, 1 or above is days past today.

yes, that’s how it works now. But only using my own days calculation. Somehow it wouldn’t set to 0 when alarmtime > current time.

That doesn’t make sense unless your clock on your system is set wrong. Can you post the macro again?

clock seems alright…

        {% macro getalarm(offsetday=0) %}
        {% set day = (now().weekday() + offsetday) % 7 %}
        {% set offset = offsetday * 86400 %}
        {% set fmat = 'd' if day in [0,1,2,3,4] and states('input_boolean.alarmclock_wd_enabled') == 'on' 
                 else 'e' %}

        {% set hour = 'input_number.alarmclock_w{}_hour'.format(fmat) %}
        {% set minute = 'input_number.alarmclock_w{}_minute'.format(fmat) %}
        {% set alarm = states(hour) | float | multiply(3600) + states(minute) | float | multiply(60) %}
        {% set time = now().hour * 3600 + now().minute * 60 %}
        {{ (offset - time) + alarm if offsetday else alarm - time }}
        {% endmacro %}

        {% if is_state('input_boolean.alarmclock_wd_enabled','on') or
              is_state('input_boolean.alarmclock_we_enabled','on') %}
        {% set in_days = states('sensor.number_of_days_next_alarm') %}
        {% set today_alarm = getalarm() | float %}
        {% set next_alarm = getalarm(in_days|int) | float %}
        {% set alarm = next_alarm if in_days|int > 0 else today_alarm %}
        {% set days = alarm // 86400 %}

          {% if days %} {{days|int}}:{{ next_alarm | timestamp_custom('%-H:%-M', False) }}
          {% else %} {{ alarm | timestamp_custom('%-H:%-M', False) }}
          {% endif %}

        {% elif is_state('input_boolean.alarmclock_wd_enabled','off') and 
                is_state('input_boolean.alarmclock_we_enabled','off') %} Not set, relax
        {% endif %}

this was your original:

        value_template: >
          {%- macro getalarm(offsetday=0) %}
          {%- set day = (now().weekday() + offsetday) % 7 %}
          {%- set offset = offsetday * 86400 %}
          {%- set fmat = 'd' if day in range(5) else 'e' %}
          {%- set hour = 'input_number.alarmclock_w{}_hour'.format(fmat) %}
          {%- set minute = 'input_number.alarmclock_w{}_minute'.format(fmat) %}
          {%- set alarm = states(hour) | float | multiply(3600) + states(minute) | float | multiply(60) %}
          {%- set time = now().hour * 3600 + now().minute * 60 %}
          {{ (offset - time) + alarm if offsetday else alarm - time }}
          {%- endmacro %}
          {% set today_alarm = getalarm() | float %}
          {% set tomorrow_alarm = getalarm(1) | float %}
          {% set alarm = tomorrow_alarm if today_alarm < 0 else today_alarm %}
          {% set days = alarm // 86400 %}
          {% if days %}
            {{ alarm | timestamp_custom('%-d day %H:%M', False) }}
          {% else %}
            {{ alarm | timestamp_custom('%H:%M', False) }}
          {% endif %}

it wouldn’t go over to the next weekend either if weekend alarm was set, and current day being a weekday:

how it should be:

macro original:

reading the weekday alarm, while it isn’t set…

Why did you add states('input_boolean.alarmclock_wd_enabled') == 'on' into the macro again? That cannot be there. I removed it in every post reply to you… Keep it out. The macro is agnostic to your on off flags, as it should be. The on off flags should be handled outside the macro.

paste this into your template editor

{%- macro getalarm(offsetday=0) %}
{%- set day = (now().weekday() + offsetday) % 7 %}
{%- set offset = offsetday * 86400 %}
{%- set fmat = 'd' if day in [0,1,2,3,4] else 'e' %}
{%- set hour = 'input_number.alarmclock_w{}_hour'.format(fmat) %}
{%- set minute = 'input_number.alarmclock_w{}_minute'.format(fmat) %}
{%- set alarm = states(hour) | float | multiply(3600) + states(minute) | float | multiply(60) %}
{%- set time = now().hour * 3600 + now().minute * 60 %}
{{- (offset - time) + alarm if offsetday else alarm - time }}
{%- endmacro %}
{{ getalarm() | int }}
{{ getalarm(1) | int }}

Tell me what your input_numbers are set to and show me the results.

I did that because it otherwise sets the alarm to weekday alarm, even if that is not enabled.

01

whats your time right now?

01

my utc offset:

33

According to those timestamps returned from the macro. Everything is correct. Use that macro in the post with all that logic and you’ll get the correct time.

literally copy and paste this:

ok i will do so, and see what happens in a week (have to meet the weekend again to see if it checks all options correctly).

this did happen with the original:

wonder why that would have been.

but please see this:

and your macro:


exact copy. showing time to next alarm on a weekday, while weekday is off.
thanks again for reassuring, and your explanation.

Both on using 9:30 for weekday and 10 for weekend:

your weekday alarm is set to earlier than current time. If I do so, the template checks alright. Setting it to later today, makes it behave incorrectly. While it shouldn’t be used at all, since weekday alarm is set off