Calculating time left untill next alarm

Hi there,

I’m expanding my alarm and having some trouble comparing two timestamps. Perhaps the long post is a little bit of an overkill but I figured maybe someone would like to see the code for their own setup.

Current setup: wakeup light with radio alarm which is adjustable by a slider. Also I implemented an On/Off switch and a selector for various radio streams. Currently the whole sequence takes 20 minutes which is perfect (easy to make a slider for that as well but I have no need for that).

Frontend view:

Configuration for switch, sliders and selector:

input_boolean:
  alarm_clock:
    name: On/Off
    initial: on
    icon: mdi:alarm

input_slider: 
  alarm_hour:
    name: Hour
    icon: mdi:timer
    initial: 6
    min: 0
    max: 23
    step: 1
  alarm_minutes:
    name: Minutes
    icon: mdi:timer
    initial: 35
    min: 0
    max: 55
    step: 5
    
input_select:
  radio_station:
    name: Radio Station
    options:
      - Radio 538
      - Q-Music
      - 3FM
      - 100% NL
      - Veronica
      - Sky Radio
#      - Arrow Classic Rock
    initial: Radio 538
    icon: mdi:radio

Automation (perhaps not so fancy but it works):

- alias: 'Rule 9 - Wakeup Light with Radio'
  trigger:
    platform: time
    minutes: '/5'
    seconds: '0'
  condition:
    condition: and
    conditions:
      - condition: template
        value_template: '{{ ((now().strftime("%s") | int + 1200) | timestamp_custom("%H:%M")) == states.sensor.alarmtime.state  }}'
      - condition: state
        entity_id: input_boolean.alarm_clock
        state: 'on'
  action:
    - service: light.turn_on
      data:
        entity_id: light.bed_room
        brightness: 255
        rgb_color: [255,255,255]
        transition: 1200   
    - service: media_player.play_media
      data_template:
        entity_id: media_player.bed_room
        media_content_id: >
          {% if is_state("input_select.radio_station", "Radio 538") %} http://vip-icecast.538.lw.triple-it.nl:80/RADIO538_MP3
          {% elif is_state("input_select.radio_station", "Q-Music") %} http://icecast-qmusic.cdp.triple-it.nl/Qmusic_nl_live_96.mp3
          {% elif is_state("input_select.radio_station", "3FM") %} http://icecast.omroep.nl/3fm-bb-mp3
          {% elif is_state("input_select.radio_station", "100% NL") %} http://stream.100p.nl/100pctnl.mp3
          {% elif is_state("input_select.radio_station", "Veronica") %} http://8543.live.streamtheworld.com/VERONICACMP3
          {% elif is_state("input_select.radio_station", "Sky Radio") %} http://8623.live.streamtheworld.com:80/SKYRADIOAAC_SC
          {% endif %}
        media_content_type: 'audio/mp4' 
    - service: media_player.volume_set
      data:
        entity_id: media_player.bed_room
        volume_level: '0.01'
    - delay: '00:02:00'
    - service: media_player.volume_set
      data:
        entity_id: media_player.bed_room
        volume_level: '0.05'
    - delay: '00:02:00'
    - service: media_player.volume_set
      data:
        entity_id: media_player.bed_room
        volume_level: '0.10'
    - delay: '00:01:30'
    - service: media_player.volume_set
      data:
        entity_id: media_player.bed_room
        volume_level: '0.15'
    - delay: '00:01:30'
    - service: media_player.volume_set
      data:
        entity_id: media_player.bed_room
        volume_level: '0.20'
    - delay: '00:01:30' 
    - service: media_player.volume_set
      data:
        entity_id: media_player.bed_room
        volume_level: '0.25'
    - delay: '00:01:00'
    - service: media_player.volume_set
      data:
        entity_id: media_player.bed_room
        volume_level: '0.30'
    - delay: '00:01:00'
    - service: media_player.volume_set
      data:
        entity_id: media_player.bed_room
        volume_level: '0.35'
    - delay: '00:01:00'     
    - service: media_player.volume_set
      data:
        entity_id: media_player.bed_room
        volume_level: '0.40'
    - delay: '00:01:00' 
    - service: media_player.volume_set
      data:
        entity_id: media_player.bed_room
        volume_level: '0.45'
    - delay: '00:01:00'
    - service: media_player.volume_set
      data:
        entity_id: media_player.bed_room
        volume_level: '0.50'
    - delay: '00:01:00'
    - service: media_player.volume_set
      data:
        entity_id: media_player.bed_room
        volume_level: '0.55'
    - delay: '00:00:45'
    - service: media_player.volume_set
      data:
        entity_id: media_player.bed_room
        volume_level: '0.60'
    - delay: '00:00:45'
    - service: media_player.volume_set
      data:
        entity_id: media_player.bed_room
        volume_level: '0.65'
    - delay: '00:00:45'
    - service: media_player.volume_set
      data:
        entity_id: media_player.bed_room
        volume_level: '0.70'
    - delay: '00:02:00'   
    - service: light.turn_on
      data:
        entity_id: light.hall_way
        brightness: 125
    - service: light.turn_on
      data:
        entity_id: light.diner_table
        brightness: 125
    - service: light.turn_on
      data:
        entity_id: light.living_room
        brightness: 140

Now I want to add 2 things:

  1. TTS notification on my Chromecast that tells me how much time I have left untill my next alarm (by sending a http post command to trigger a script using Tasker using my wireless charger next to my bed as trigger);
  2. Calculate the time I have slept and make that part of my “Morning briefing”.

I can’t figure out how to calculate the time untill my next alarm.

Values that must be compared are:

Current time:

(now().strftime("%s") | int | timestamp_custom(" %H:%M"))

Wakeup time:

(states.sensor.alarmtime.state) | timestamp_custom(" %H:%M")

If I want to calculate, I first have to figure out a way to convert both “timestamps” (which are currently not seen as timestamps by HA) to a complete timestamp (year, month, day, hour, minute, second). I don’t know how to do that (rather new to HA, just installed it 3 weeks ago).

Help is much appreciated!

Here is how I calculate reaming time unitl next alarm:

1 Like
'{{ states.input_slider.alarm_hour.state|float|multiply(60) + states.input_slider.alarm_minutes.state|float - (now().hour|float|multiply(60) + now().minute)}}

Gives me -894, 894 is exactly the time that has passed since my previous alarm.

{{ (now().hour|float|multiply(60) + now().minute) - states.input_slider.alarm_hour.state|float|multiply(60) + states.input_slider.alarm_minutes.state|float  }}

Gives me 966, which is 16 hours from now so allso not right.

Ideal would be the have the following output in the end: “HH:MM”

After some trial and error, I succeeded in calculation the time between now and my next alarm in hours:

{{  (states.input_slider.alarm_hour.state|float|multiply(60) + states.input_slider.alarm_minutes.state|float  +  ( 1440 - (now().hour|float|multiply(60) + now().minute)))/60  }}

Now I have to find a way to convert the part after the comma in minutes.
Output is 10.25 in the example code which must be converted to 10:15.

Do I have to split the output to make the conversion?

After rethinking the whole thing this doesn’t seem to be the proper way. The script calculates the time until midnight plus the time from midnight to the alarmhour state. This way it will never work if the calculation is made after 00:00.

Can someone help me out here?

Try this:

{% set relative_time =  (states.input_slider.alarmhour.state|float|multiply(60) + states.input_slider.alarmminutes.state|float) - (now().hour|float|multiply(60) + now().minute) %}
{%- if relative_time < 0 -%}
         {{24*60+relative_time}}
 {%- else -%}
          {{ relative_time}}
{%- endif %}

That does give me the correct time :slight_smile: Thanks!

It’s in seconds so I only have to convert it to “HH:MM” now

Feels like I’m really close but doesn’t work:

Sensor:

          {% set relative_time =  (states.input_slider.alarm_hour.state|float|multiply(60) + states.input_slider.alarm_minutes.state|float) - (now().hour|float|multiply(60) + now().minute) %}
          {%- if relative_time < 0 -%}
                   {{(24*60+relative_time | timestamp_custom("%H:%M"))}}
          {%- else -%}
                   {{(relative_time | timestamp_custom("%H:%M"))}}
          {%- endif %}

Output is blanc.

What am I missing here?

The output for the sensor also won’t convert to the desired format:

{{ states.sensor.nextalarm.state | timestamp_custom("%H:%M") }} gives 648.0

And:

{{  (as_timestamp(states.sensor.nextalarm.state) | timestamp_custom("%H:%M")) }}

gives Error rendering template: not a valid date/time.

Almost got it!

 {{  (states.sensor.nextalarm.state.split(" ")[0] | int *60 ) | timestamp_custom("%H:%M") }}

Allmost gives me the correct time (for some reason it adds 1 hour). Do I have to add the timezone somehow?

Got it working by cheating with the sensor template but it isn’y how it should be:

{% set relative_time = (states.input_slider.alarmhour.state|float|multiply(60) + states.input_slider.alarmminutes.state|float) - (now().hour|float|multiply(60) + now().minute) %}
{%- if relative_time < 0 -%}
{{23*60+relative_time}}
{%- else -%}
{{ relative_time-60}}
{%- endif %}

Hey Bob. Got your reply and came here to check, indeed a macro the good tip. You’re not far now, I think timestamps are UTC and so did you try with utcnow?
I have done something similar for alarm clocks (week/weekend) and showing me only the next active one depending on day&time :wink:

So did you win on this one? Can you share the code?

Not yet, still using the workaround. To be honest I didn’t spend much time on it after this seems to work (for now) :blush:

What would be the correct layout to add also days to it? Usually on the weekend, i do not have an Alarm turned on. I would like to see something like this:

Time to next Alarm: 02 d 05h 04m

have you figured out how to calculate the time you’ve been asleep? I was thinking about using an input_boolean set to true when I am asleep (automated through Tasker + Sleep as Android) and the history_stats component.