Spot the error... nested template

Ah ok, minor issue then.

    {%- 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 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 %}
    
    {% if offset != None %}
      {% set today_alarm = getalarm() | float %}
      {% set next_alarm = getalarm(offset) | float %}
      {% set alarm = next_alarm if today_alarm < 0 else today_alarm %}
      {% if offset > 1 %}
        {{ next_alarm // 86400 }}:{{ next_alarm | timestamp_custom('%-H:%-M', False) }}
      {% else %}
        {{ alarm | timestamp_custom('%-H:%-M', False) }}
      {% endif %}
    {% else %}
      None 
    {% endif %}

yes, that works now… tY! Cool.
Minor issues can be nasty… :wink:

hope it gets around the full weekend also.

btw @petro please allow me this final question:

why do we need to do
{% if days %} {{(next_alarm // 86400) |int }}:{{ next_alarm | timestamp_custom('%-H:%-M', False) }}
and can’t we use
{% if days %} {{ next_alarm | timestamp_custom('%-d:%-H:%-M', False) }}

the %d is always +1

because %d is the day of the month, not the day of the week or a count.

yes, realize that, but it is what you had in your first iteration, counting the days if days exist. I changed it then, because I knew no other way to get the days counted using the days as a separate template.
Still doesn’t really explain why it is always one up, to put more precisely, I still don’t grasp that …

if % H and %M are valid options, isn’t there an option for days that could be used, other than specifying it as an extra template like now?

the only option is %d, you claimed it wasn’t working for you and always outputting one. Which is fine, no big deal. So I changed it to this new method which is int division.

I do not know why it was always one for you, it should actually work and increment the days. This way is a work-around and it will work 100% of the time.

right now it is indeed. tried the original again, but it is off, so won’t look back at it again, no use when having this at hand!

have another request though.

I am still using this bit of python in my system monitor (summary):

##########################################################################################
# Alarm clock
# /config/packages/package_alarmclock.yaml
##########################################################################################

alarms_prefix = ['alarmclock_wd', 'alarmclock_we']
alarms_wfilter = [range(1,6), range(6,8)]
alarms_desc = ''
mydict = {'hidden':hidden}

for entity_id, filter in zip(alarms_prefix, alarms_wfilter):
    state = hass.states.get('input_boolean.{}_enabled'.format(entity_id))
    if state:
        if state.state is 'on' and datetime.datetime.now().isoweekday() in filter:
            state = hass.states.get('sensor.{}_time'.format(entity_id))
            alarms_desc = '{}{}, '.format(alarms_desc, state.state)

if (alarms_desc == ''):
    mydict['entity_picture'] = '/local/badges/alarm_off.png'
    mydict['friendly_name'] =  'Relax'
    mydict['unit_of_measurement'] = 'Off'
    mydict['theme'] = 'grey_badge'
    mydict['love'] = 'Alarm clock is not set, relax'
    alarms_desc = '%- Alarm clock is not set, relax'

else:
    mydict['entity_picture'] = '/local/badges/alarm.png'
    mydict['friendly_name'] = alarms_desc[:-2]
    mydict['unit_of_measurement'] = 'On'
    mydict['theme'] = 'orange_badge'
    mydict['love'] = 'Alarm clock set at ' + alarms_desc[:-2]
    alarms_desc = '/- Alarm clock set at ' + alarms_desc[:-2]

hass.states.set('sensor.alarms_badge', '', mydict)

this only sets the alarm to be ‘on’ and displays the state, when on weekday and weekday alarm is on, or on weekend day and weekend alarm is on.

Would it be possible to have it behave like the sensor.time_until_next_alarm: have it show a weekend alarm on a weekday too (and vice versa), preferably with the alarm day in the alarms_desc?

and, just to give full feedback and thanks, this is what I am using now and things seem to be working perfectly.
Did have to create an automation to update all sensors, immediately and not await sensor.time. I had the commented entity_ids in first, but they wouldn’t make a difference for the updating of the sensors. Automation does it better. Now only have the entities listed which are used in the template, and even they might not be necessary , safe the sensor.time.

      number_of_days_next_alarm:
        friendly_name: Days to next alarm
        entity_id:
          - sensor.time
          - sensor.alarmclock_wd_time
          - sensor.alarmclock_we_time
#          - 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: >
          {% 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 %}

      next_alarm_day:
#        icon_template: >
#          {% if not is_state('sensor.next_alarm_day','Not set') %} mdi:calendar-clock
#          {% else %} mdi:alarm-off
#          {% endif %}
        friendly_name: Next alarm day
        entity_id:
          - sensor.time
          - sensor.number_of_days_next_alarm
          - sensor.next_alarm_daytype
#          - sensor.time_until_next_alarm
#          - 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 offset = states('sensor.number_of_days_next_alarm')|int %}

          {% if is_state('sensor.next_alarm_daytype','Today,')%}
            {{states('sensor.next_alarm_daytype')}} {{ as_timestamp(now().replace(day=now().day)) | timestamp_custom('%A') }}
          {% elif states('sensor.next_alarm_daytype') in ['Tomorrow,', 'The day after tomorrow,'] %}
            {{states('sensor.next_alarm_daytype')}} {{ as_timestamp(now().replace(day=now().day + offset)) | timestamp_custom('%A')}}

          {% elif is_state('sensor.number_of_days_next_alarm','Not set') and is_state('sensor.next_alarm_daytype','Not set') %}
            Not set
          {% else %}
            {{ as_timestamp(now().replace(day=now().day + offset)) | timestamp_custom('%A')}}
          {% endif %}

      next_alarm_daytype:
        friendly_name: Next alarm daytype
        entity_id:
          - sensor.time
          - sensor.time_until_next_alarm
          - 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' %} The day after tomorrow,
          {% else %} More than 2: ({{days}}) days
          {% endif %}

      time_until_next_alarm:
        friendly_name: 'Time until next alarm'
        entity_id:
          - sensor.time
          - 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: >
          {%- 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 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 %}

          {% if offset != None %}
            {% set today_alarm = getalarm() | float %}
            {% set next_alarm = getalarm(offset) | float %}
            {% set alarm = next_alarm if today_alarm < 0 else today_alarm %}
            {% if offset > 1 %}
              {{ (next_alarm // 86400) |int }}:{{ next_alarm | timestamp_custom('%-H:%-M', False) }}
            {% else %}
              {{ alarm | timestamp_custom('%-H:%-M', False) }}
            {% endif %}
          {% else %}
            Not set, relax
          {% endif %}

      next_alarm_text:
        friendly_name: Next alarm text
        entity_id:
          - sensor.time_until_next_alarm
          - sensor.next_alarm_day
#          - sensor.number_of_days_next_alarm
#          - sensor.next_alarm_daytype

        value_template: >
          {% set time = states('sensor.time_until_next_alarm') %}
          {% set next_alarm = states('sensor.next_alarm_day')|lower %}
          {% set pickup = 'Next alarm will be ' + next_alarm + ' in ' %}
          {% if time == 'Not set, relax' %} Alarm is {{time|lower}}
          {% elif (time.split(':')|length - 1) > 1 %} 
            {{pickup}}
            {% set day = 'day' if time.split(':')[0]== '1' else 'days' %}
            {% set hour = 'hour' if time.split(':')[1]== '1' else 'hours' %}
            {% set minute = 'minute' if time.split(':')[2]== '1' else 'minutes' %}

            {% if time.split(':')[1] == '0' %} {{time.split(':')[0] }} {{day}} {{time.split(':')[2] }} {{minute}}
            {% elif time.split(':')[2] == '0' %} {{time.split(':')[0] }} {{day}} and {{time.split(':')[1] }} {{hour}} exactly
            {% else %} {{time.split(':')[0] }} {{day}}, {{ time.split(':')[1] }} {{hour}} and {{time.split(':')[2] }} {{minute}}
            {% endif%}

          {% else %}
            {{pickup}}
            {% set hour = 'hour' if time.split(':')[0]== '1' else 'hours' %}
            {% set minute = 'minute' if time.split(':')[1]== '1' else 'minutes' %}

            {% if time.split(':')[0] == '0' %} {{time.split(':')[1] }} {{minute}}
            {% elif time.split(':')[1] == '0' %} {{time.split(':')[0] }} {{hour}} exactly
            {% else %} {{time.split(':')[0] }} {{hour}} and {{time.split(':')[1] }} {{minute}}
            {% endif%}
          {% endif %}

and automation:

  - alias: 'Update next alarm'
    id: 'Update next alarm'
    initial_state: 'on'
    trigger:
      platform: state
      entity_id:
        - sensor.time_until_next_alarm
        - 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
    action:
      service: homeassistant.update_entity
      entity_id:
        - sensor.next_alarm_day
        - sensor.next_alarm_daytype
        - sensor.number_of_days_next_alarm

you made me twist my mind here. After having reread this many times, I must conclude I did not…?
I had only added the states('input_boolean.alarmclock_wd_enabled') == 'on' condition outside the macro.

Its gone there now too, and the latest ‘minor issue’ then out makes it behave as it should. Very nice!

I have btw changed/compressed the separate day counter (I need for showing the days in a separate sensor, and for calculating some wordings for TTS) to this now:

      number_of_days_next_alarm_alt:
        friendly_name: Days to next alarm alt
        entity_id: sensor.time
        value_template: >
          {% set end_on = is_state('input_boolean.alarmclock_we_enabled','on') %}
          {% set week_on = is_state('input_boolean.alarmclock_wd_enabled','on') %}
          {% set week_time = now().time().strftime('%H:%M') < states('sensor.alarmclock_wd_time') %}
          
          {% set end_time = now().time().strftime('%H:%M') < states('sensor.alarmclock_we_time') %}
          {% set now = now().weekday() %}

          {% if not end_on and not week_on %} Not set 

          {% elif now in [0,1,2,3] %}
            {% if week_on %} {{'0' if week_time else '1' }}
            {% elif end_on %} {{5 - now}}
            {% endif %}

          {% elif now == 4 %}
            {% if week_on %}
              {% if week_time %} 0
              {% else %} {{ '1' if end_on else '3'}}
              {% endif %}
            {% else %} {{ '1' if end_on}}
            {% endif %}

          {% elif now == 5 %}
            {% if end_on %} {{'0' if end_time else '1'}}
            {% else %} 
              {% if week_on %}2
              {% endif %}
            {% endif %} 

          {% elif now == 6 %}
            {% if end_on %} {{'0' if end_time else '6'}}
            {% else %} 
              {% if week_on %}1
              {% endif %}
            {% endif %}

          {% endif %}

Ive tried to use the bit in the bigger template sensor

          {% 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 %}

but that won’t account for today, or 0, since it needs the extra alarmtime to current time comparison.

You must have added it accidentally? Everytime you posted the macro in this post and the other post you had the check inside it

I’m not sure what you are trying to do, that doesn’t account for today ever. That will only account for tomorrow (or whenever the next alarm is). The remaing portion of the if statement in the template accounted for today, but for some reason you keep omitting pieces of the templates! Why aren’t you using the one that has proven to work? The all in one template that just tells you the next alarm?

    {%- 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 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 %}
    
    {% if offset != None %}
      {% set today_alarm = getalarm() | float %}
      {% set next_alarm = getalarm(offset) | float %}
      {% set alarm = next_alarm if today_alarm < 0 else today_alarm %}
      {% if offset > 1 %}
        {{ next_alarm // 86400 }}:{{ next_alarm | timestamp_custom('%-H:%-M', False) }}
      {% else %}
        {{ alarm | timestamp_custom('%-H:%-M', False) }}
      {% endif %}
    {% else %}
      None 
    {% endif %}

Ah yes! you’re right. I completely missed that… my apologies…
not using it anymore, that was a c&p from my temporary testing package… so sorry for the confusion.

I must be explaining myself completely unclear here.
I am not looking to change or modify the all in 1 template at all. That is working fine now, and showing the time until next alarm correctly.

I am trying to create an extra template sensor, for only showing the number if days until next alarm. 0 is today, 1 of tomorrow etc etc.

That number of days sensor is then used to do this:

       value_template: >
          {% set offset = 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') %} {% set offset = 'Not set' %}
          {% elif offset == '0' %} {% set daytype = 'Today,'%}
          {% elif offset == '1' %} {% set daytype = 'Tomorrow,' %}
          {% elif offset == '2' %} {% set daytype = 'The day after tomorrow,' %}
          {% endif %}

          {% if daytype == 'Today,'%}
            {{daytype}} {{ as_timestamp(now().replace(day=now().day)) | timestamp_custom('%A') }}
          {% elif daytype in ['Tomorrow,', 'The day after tomorrow,'] %}
            {{daytype}} {{ as_timestamp(now().replace(day=now().day + offset|int)) | timestamp_custom('%A')}}

          {% elif offset == 'Not set' %}
            Not set
          {% else %}
            {{ as_timestamp(now().replace(day=now().day + offset|int)) | timestamp_custom('%A')}}
          {% endif %}

which in its place is then used to create the text I want the TTS to be announcing:

        value_template: >
          {% set time = states('sensor.time_until_next_alarm') %}
          {% set next_alarm = states('sensor.next_alarm_day')|lower %}
          {% set pickup = 'Next alarm will be ' + next_alarm + ' in ' %}
          {% if time == 'Not set, relax' %} Alarm is {{time|lower}}
          {% elif (time.split(':')|length - 1) > 1 %} 
            {{pickup}}
            {% set day = 'day' if time.split(':')[0]== '1' else 'days' %}
            {% set hour = 'hour' if time.split(':')[1]== '1' else 'hours' %}
            {% set minute = 'minute' if time.split(':')[2]== '1' else 'minutes' %}

            {% if time.split(':')[1] == '0' %} {{time.split(':')[0] }} {{day}} {{time.split(':')[2] }} {{minute}}
            {% elif time.split(':')[2] == '0' %} {{time.split(':')[0] }} {{day}} and {{time.split(':')[1] }} {{hour}} exactly
            {% else %} {{time.split(':')[0] }} {{day}}, {{ time.split(':')[1] }} {{hour}} and {{time.split(':')[2] }} {{minute}}
            {% endif%}

          {% else %}
            {{pickup}}
            {% set hour = 'hour' if time.split(':')[0]== '1' else 'hours' %}
            {% set minute = 'minute' if time.split(':')[1]== '1' else 'minutes' %}

            {% if time.split(':')[0] == '0' %} {{time.split(':')[1] }} {{minute}}
            {% elif time.split(':')[1] == '0' %} {{time.split(':')[0] }} {{hour}} exactly
            {% else %} {{time.split(':')[0] }} {{hour}} and {{time.split(':')[1] }} {{minute}}
            {% endif%}
          {% endif %}

visualized:

54

the green sensor being my _alt sensor for testing purposes…

Ah ok, unfortunately you still need the macro and the template will be very similar. This is because the macro is used to determine if the alarm is today or tomorrow.

    {%- 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 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 %}
    
    {% if offset != None %}
      {% set today_alarm = getalarm() | float %}
      {% set next_alarm = getalarm(offset) | float %}
      {% set alarm = offset if today_alarm < 0 else 0 %}
      {% if offset > 1 %}
        {{ offset }}
      {% else %}
        {{ alarm }}
      {% endif %}
    {% else %}
      None 
    {% endif %}

yes, i had thought of the too, thanks!

but see what is happening. Your macro template is (are) off somehow in the situation of Today (being friday) having an alarmtime > current time and weekend aalarm is Off:

01

if I turn of weekend alarm, and don’t change the weekday alarm, it changes to the correct situation:


24

so the macro must have a bug still

if I use alarm instead of next_alarm in

          {% if offset != None %}
            {% set today_alarm = getalarm() | float %}
            {% set next_alarm = getalarm(offset) | float %}
            {% set alarm = next_alarm if today_alarm < 0 else today_alarm %}
            {% if offset > 1 %}
              {{ (next_alarm // 86400) |int }}:{{ next_alarm | timestamp_custom('%-H:%-M', False) }}
            {% else %}
              {{ alarm | timestamp_custom('%-H:%-M', False) }}
            {% endif %}
          {% else %}
            Not set, relax
          {% endif %}

it handles it correctly, but the introduce the other error again of course…

when only weekend alarm is on, the macro templates make errors too:

if the weekend time is set, the macro calculates correctly for times before current time. if the alarm time is set after current time, it only calculates minutes, and leaves out the hours…
if the alarm is to be tomorrow (seen from friday to saturday that is), on the same time as now this is what happens:

33

I can’t debug it here but try this

    {%- 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 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 %}
    
    {% if offset != None %}
      {% set today_alarm = getalarm() | float %}
      {% set next_alarm = getalarm(offset) | float %}
      {% set alarm = today_alarm if today_alarm > 0 else next_alarm %}
      {% if offset > 1 %}
        {{ alarm // 86400 }}:{{ alarm | timestamp_custom('%-H:%-M', False) }}
      {% else %}
        {{ alarm | timestamp_custom('%-H:%-M', False) }}
      {% endif %}
    {% else %}
      None 
    {% endif %}

that doesn’t change the output in any way. other than the |float which is now left out in {{alarm//86400}}

I just tested it and it just adds the zero but the time is correct but it adds the zero day.

This removes the zero day.

    {%- 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 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 %}
    
    {% if offset != None %}
      {% set today_alarm = getalarm() | float %}
      {% set next_alarm = getalarm(offset) | float %}
      {% if today_alarm > 0 %}
        {{ today_alarm | timestamp_custom('%-H:%-M', False) }}
      {% elif offset == 1 %}
        {{ next_alarm | timestamp_custom('%-H:%-M', False) }}
      {% else %}
        {{ next_alarm // 86400 }}:{{ next_alarm | timestamp_custom('%-H:%-M', False) }}
      {% endif %}
    {% else %}
      None 
    {% endif %}

this is correct for the current day (being friday now) and showing the correct time until next alarm, when set both after now() and before now() calculating over the weekend.

so progress!

it is still incorrect however for the alarm being tomorrow after the current time. It truncates the day, and displays the same time the current macro template does:

your new macro:

current macro:

03

it is correct for times set before current time:

as was the current macro:

think this outputs correctly, though it might be a horror to your eyes…had to add an extra condition (see marker):

          {%- 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 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 %}
    
          {% if offset != None %}
            {% set today_alarm = getalarm() | float %}
            {% set next_alarm = getalarm(offset) | float %}
            {% if today_alarm > 0 %}
              {{ today_alarm | timestamp_custom('%-H:%-M', False) }}
            
            {% else %} 
               {% if (next_alarm // 86400)|int == 0 %} # <------- added condition here
                 {{ next_alarm | timestamp_custom('%-H:%-M', False) }}
              {% else %}
                {{ (next_alarm // 86400 )|int }}:{{ next_alarm | timestamp_custom('%-H:%-M', False) }} {% endif %}
              {% endif %}
            {% else %}
              Not set, relax
          {% endif %}

now how to make this into the count the days template…

maybe this:

          {% if offset != None %}
            {% set today_alarm = getalarm() | float %}
            {% set next_alarm = getalarm(offset) | float %}
            {% if today_alarm > 0 %} 0
            {% else %} 
              {% if (next_alarm // 86400)|int == 0 %} {{offset}}
              {% else %} {{ offset }}
              {% endif %}
            {% endif %}
          {% else %}
            Not set, relax
          {% endif %}

or even:

          {% if offset != None %}
            {% set today_alarm = getalarm() | float %}
            {% set next_alarm = getalarm(offset) | float %}
            {% if today_alarm > 0 %} 0
            {% else %} {{ offset }}
            {% endif %}
          {% else %}
            Not set, relax
          {% endif %}

update

above seems to operate well now. Will see how it holds up over the weekend. Simulation went fine. always check irl…

update 2
it doesn’t… grrr. it doesn’t count the time and days to monday…if weekend alarm is off. Counts the time and day to the weekend alarm (while that is turned off) (and weekend alarm is > current time…)

Why is this so horribly difficult?

Got the feeling we are getting close here, but there’s still a few issues… Would really appreciate if you could check again for me please @petro , I am a bit lost where to start changing. Is it only the final template, or should the macro or weekday part be checked again.

Main problem lies in the time until next alarm sensor, Ill tackle the days sensor after that…

could this be it:


          {% if offset != None %}
            {% set today_alarm = getalarm() | float %}
            {% set next_alarm = getalarm(offset) | float %}
            {% if today_alarm > 0 and offset == 1 %}  ## <<------ added offset ==1 check
              {{ today_alarm | timestamp_custom('%-H:%-M', False) }}
            {% else %} 
               {% if (next_alarm // 86400)|int == 0 %}
                 {{ next_alarm | timestamp_custom('%-H:%-M', False) }}
               {% else %}
                 {{ (next_alarm // 86400 )|int }}:{{ next_alarm | timestamp_custom('%-H:%-M', False) }}
               {% endif %}
            {% endif %}
          {% else %}
            Not set, relax
          {% endif %}

or:

          {% if offset != None %}

            {% set today_alarm = getalarm() | float %}
            {% set next_alarm = getalarm(offset) | float %}

            {% if offset > 1 %} {{ (next_alarm // 86400 )|int }}:{{ next_alarm | timestamp_custom('%-H:%-M', False) }}
            {% else %}
              {% if today_alarm > 0 and offset == 1 %}
                {{ today_alarm | timestamp_custom('%-H:%-M', False) }}
              {% else %}
                 {{ next_alarm | timestamp_custom('%-H:%-M', False) }}
              {% endif %}
            {% endif %}
          {% else %}
            Not set, relax
          {% endif %}

both working for now at least…

so it just turned sunday, nd the template is off again. This is really nagging me now.

ok. so had to resort to below template again, since I couldn’t get the full all-in-one to work correctly. Think is was the template calculating the offset, because it never got to being 0.

below I can calculate
0= today_alarm
else always next_alarm, with a check comparing the current time to relevant alarm time.

        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 week_on = is_state('input_boolean.alarmclock_wd_enabled','on') %}
          {% set end_on = is_state('input_boolean.alarmclock_we_enabled','on') %}
          {% set in_days = states('sensor.number_of_days_next_alarm_alt')|int %}
          {% set today_alarm = getalarm() | float %}
          {% set next_alarm = getalarm(in_days) | float %}

          {% if week_on or end_on %}
            {% if in_days == 0 %}
              {{ today_alarm | timestamp_custom('%-H:%-M', False) }}
            {% else %}
              {% if (next_alarm // 86400 )|int == 0 %}
                {{ next_alarm | timestamp_custom('%-H:%-M', False) }}
              {% else %}
                {{ (next_alarm // 86400 )|int }}:{{ next_alarm | timestamp_custom('%-H:%-M', False) }}
              {% endif %}
            {% endif %}
          {% else %} Not set, relax
          {% endif %}

or even shorter:

      time_until_next_alarm_alt:
        friendly_name: 'Time until next alarm alt'
        entity_id:
          - sensor.time
          - 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: >
          {%- 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 week_on = is_state('input_boolean.alarmclock_wd_enabled','on') %}
          {% set end_on = is_state('input_boolean.alarmclock_we_enabled','on') %}
          {% set in_days = states('sensor.number_of_days_next_alarm_alt')|int %}
         
          {% set alarm = getalarm(in_days) | float %}

          {% if week_on or end_on %}

              {% if (alarm // 86400 )|int  == 0 %}
                {{ alarm | timestamp_custom('%-H:%-M', False) }}
              {% else %}
                {{ (alarm // 86400 )|int }}:{{ alarm | timestamp_custom('%-H:%-M', False) }}
              {% endif %}
          
          {% else %} Not set, relax
          {% endif %}

using the intermediary template again to calculate the number of days:

      number_of_days_next_alarm_alt:
        friendly_name: Days to next alarm alt
        entity_id: sensor.time
        value_template: >
          {% set end_on = is_state('input_boolean.alarmclock_we_enabled','on') %}
          {% set week_on = is_state('input_boolean.alarmclock_wd_enabled','on') %}
          {% set week_time = now().time().strftime('%H:%M') < states('sensor.alarmclock_wd_time') %}
          
          {% set end_time = now().time().strftime('%H:%M') < states('sensor.alarmclock_we_time') %}
          {% set now = now().weekday() %}

          {% if not end_on and not week_on %} Not set 

          {% elif now in [0,1,2,3] %}
            {% if week_on %} {{'0' if week_time else '1' }}
            {% elif end_on %} {{5 - now}}
            {% endif %}

          {% elif now == 4 %}
            {% if week_on %}
              {% if week_time %} 0
              {% else %} {{ '1' if end_on else '3'}}
              {% endif %}
            {% else %} {{ '1' if end_on}}
            {% endif %}

          {% elif now == 5 %}
            {% if end_on %} {{'0' if end_time else '1'}}
            {% else %} {{'2' if week_on }}
            {% endif %}

          {% elif now == 6 %}
            {% if end_on and not week_on %}
              {{ '0' if end_time else '6' }}
            {% elif end_on and week_on %} 
              {{ '0' if end_time else '1' }}
            {% else %} {{ '1' if week_on }}
            {% endif %}

          {% endif %}

and this template to calculate the ‘daytype’:

      next_alarm_day:
        friendly_name: Next alarm day
        entity_id:
          - sensor.time
          - sensor.number_of_days_next_alarm
          - input_boolean.alarmclock_wd_enabled
          - input_boolean.alarmclock_we_enabled
        value_template: >
          {% set offset = states('sensor.number_of_days_next_alarm') %}
          {% set day_number = now().strftime('%-d') %}
          {% if is_state('input_boolean.alarmclock_wd_enabled','off') and
                is_state('input_boolean.alarmclock_we_enabled','off') %} {% set daytype = 'Not set' %}
          {% elif offset == '0' %} {% set daytype = 'Today,'%}
          {% elif offset == '1' %} {% set daytype = 'Tomorrow,' %}
          {% elif offset == '2' %} {% set daytype = 'The day after tomorrow,' %}
          {% elif offset > '2' %} {% set daytype = 'Next' %}
          {% endif %}

          {% if offset == 'Not set' %} Not set
          {% elif offset == '0'%}
            {{daytype}} {{ as_timestamp(now().replace(day=now().day)) | timestamp_custom('%A') }}
          {% else %}
            {% if now().day + offset|int > states('days_current_month')|int %}
             {{daytype}} {{ as_timestamp(now().replace(month= +1).replace(day=(now().day + 
                                                offset|int - day_number|int))) | timestamp_custom('%A')}}
            {% else %}
             {{daytype}} {{ as_timestamp(now().replace(day=(now().day + offset|int )))| timestamp_custom('%A') }}
            {% endif %}
          {% endif %}

which has set another challenge for me, because simply replacing the day, caused it to surpass the allowed days of the current month. S0 again the need for an extra sensor was born… sensor.days_current_month:

      days_current_month:
        friendly_name: Days current month
        entity_id: sensor.date
        value_template: >
          {% set month = now().strftime('%-m') %}
          {% if month in ['1','3','5','7','8','10','12'] %} 31
          {% elif month in ['4','6','9','11'] %} 30
          {% else %} {{'29' if (now().strftime('%-y'))|int//4 == 0 else '28'}}
          {% endif %}

hope this rather complex set does it now, for such a simple task as showing the next alarm :-))