Create your own flexible wake up light with time calculation

Hi everyone,

after getting much input from this community I really would like to share some of my solutions and thoughts. Having some Hue bulbs in my bedroom and being hardly to motivate to wake up in the morning, I was looking for a solution to create a wake up light.
Basically you just can create an automation with a fixed start time and using the “light.turn_on” service, but this was to static for me and I wanted to have a more flexible solution. So I came up with the idea to use some “date_time-helpers” for setting the wake up time and the duration for transition. All information are adjustable through the UI.

settings

As you can see, I do have two lights, I can set up the wake up time, the duration and choose which bulbs are used in the morning.

Starting with the code for the shown card. The code is pretty straight forward and just a collection of some entities:

type: vertical-stack
title: Licht Aufstehen
cards:
  - type: entities
    entities:
      - entity: input_datetime.aufstehen
        name: Weckzeit
      - entity: input_datetime.aufstehen_offset
        name: Überblendzeit (vor Wecker)
      - entity: input_boolean.aufstehen_bulb1
        name: Lampe 1
      - entity: input_boolean.aufstehen_bulb2
        name: Lampe 2

Moreover we do need the mentioned helpers. In my case three date_time-helpers and two boolean.
Names are: “input_datetime.aufstehen”, “input_datetime.aufstehen_offset”, “input_datetime.aufstehen_start”, “input_boolean.aufstehen_bulb1” and “input_boolean.aufstehen_bulb2”. The two lights are furthermore summarized in a group called “light.alles_schlafzimmer”.


For the less experienced users: You might have to add the lines:
input_boolean:
input_boolean:

in your configuration.yaml to activate the helpers.
Afterwards you can add the helpers under “settings->automatisation & scenes->helper”


Next step is an automatisation for calculating the time, when the transition should start (wake up time minus duration). Sounds simple, but this was quiet challenging to me, because calculation of date_time-helpers isn’t that easy.

Triggers for this automatisation is the change of either “input_datetime.aufstehen” or “input_datetime.aufstehen_offset” and the aim is to calculate the end time minus the offset and save this new time inside the helper “input_datetime.aufstehen_start”

Complete automation looks like this:

alias: 'Automatisierung: Setze Startzeit Licht Aufstehen'
description: ''
trigger:
  - platform: state
    entity_id: input_datetime.aufstehen
  - platform: state
    entity_id: input_datetime.aufstehen_offset
condition: []
action:
  - service: input_datetime.set_datetime
    data:
      time: >
        {% set offset_hour = state_attr('input_datetime.aufstehen_offset', 'hour') %} 
        {% set offset_minute = state_attr('input_datetime.aufstehen_offset', 'minute') %} 
        {% set end_hour = state_attr('input_datetime.aufstehen', 'hour') %} 
        {% set end_minute = state_attr('input_datetime.aufstehen', 'minute') %}

        {% if offset_hour==0 %} 
        {% set offset_hour_calc = 0 %} 
        {% else %} 
        {% set offset_hour_calc = offset_hour * 60 %} 
        {%endif%}

        {% if end_hour==0 %} 
        {% set end_hour_calc = 0 %} 
        {% else %} 
        {% set end_hour_calc = end_hour * 60 %} 
        {%endif%}

        {% set minute_offset = offset_minute + offset_hour_calc %} 
        {% set minute_end = end_minute + end_hour_calc %}

        {% set minute_start = minute_end - minute_offset %} 
        {% if minute_start<=0 %} 
        {% set start_hour = 0 %} 
        {% set start_minute = 0 %}
        {% else %} 
        {% set start_hour = (minute_start / 60) | int %} 
        {% set start_minute = (((minute_start / 60) - start_hour) * 60) | round(0) %}
        {%endif%}

        {% set time_string = (start_hour | string) + ":" + (start_minute | string) + ":" + "00" %} 
        {{time_string}}
    target:
      entity_id: input_datetime.aufstehen_start
mode: single

For interested readers some explanations:

First block, saving the the set hours and minutes of the helpers in some variables.
Second block, recalculate the hours of offset into minutes.
Third block, recalculate the hours of end time into minutes.
Forth block, convert the input times into a value in minutes by adding.
Fifth block, calculate the start time by subtracting the end time minus offset. Afterwards check, if this value is getting negative. If yes, it would mean to start the light the day before. I think this won’t happen in a real case, but just to be sure, I will set the start time to “00:00” in this case. Otherwise calculate the start time and recalculate it in hours and minutes.
Last block, create a string containing our start time and giving the value as output.


Now, our start time will be calculated every time we change one of our helpers.

A second automatisation will turn on the lights in the morning, starting at the calculated start time and using the set duration for transition (just weekdays):

alias: 'Automatisierung: Licht Aufstehen Woche'
description: ''
trigger:
  - platform: time
    at: input_datetime.aufstehen_start
condition:
  - condition: time
    weekday:
      - mon
      - tue
      - wed
      - thu
      - fri
action:
  - service: light.turn_on
    data:
      brightness: 255
      kelvin: 4000
      transition: >
        {% set offset_hour = state_attr('input_datetime.aufstehen_offset', 'hour') %} 
        {% set offset_minute = state_attr('input_datetime.aufstehen_offset', 'minute') %} 
        {% if offset_hour==0 %} 
        {% set offset_hour_calc = 0 %} 
        {% else %} 
        {% set offset_hour_calc = offset_hour * 60 %} 
        {%endif%} 
        {% set minute_offset = offset_minute + offset_hour_calc %} 
        {% set seconds_offset = minute_offset * 60 %} 
        {{seconds_offset}}
    target:
      entity_id: >
        {% if is_state('input_boolean.aufstehen_bulb1', 'on') %} 
        {% if is_state('input_boolean.aufstehen_bulb2', 'on') %}
          light.alles_schlafzimmer
        {%else%}
          light.schlafzimmer_bulb1
        {%endif%} 
        {%else%} 
        {% if is_state('input_boolean.aufstehen_bulb2', 'on') %}
          light.schlafzimmer_bulb2
        {%else%} 
        {%endif%} 
        {%endif%}
mode: single

Here again some calculation for getting the transition time in seconds.
The used lights are selected through the booleans by some if-then-else inside an if-then-else. This isn’t the best solution, but I haven’t found a better way for this so far.



I hope this code might help someone.

And for sure… If you do have any suggestion for improving, I likely would hear them.

Kind regards and have fun,
Lars

Heya,

nice idea. Based on it I made the following changes:

  1. create an additional input_number to hold the warmup duration in seconds, the first automation will set its value.
  2. Use this as a value for the light transition in the automation:
              transition: |
                {{ states('input_number.timewakeupwarmupinsecs') }}
  1. The wake up automation uses Choices instead of if clauses for selecting which lights to turn on.
action:
  - choose:
      - conditions:
          - condition: state
            entity_id: input_boolean.wakeuplightskids
            state: "on"
        sequence:
          - service: light.turn_on
            data:
              transition: |
                {{ states('input_number.timewakeupwarmupinsecs') }}
            target:
              entity_id:
                - light.hue_gu10_ellie
                - light.hue_gu10_flo
            enabled: true
      - conditions:
          - condition: state
            entity_id: input_boolean.wakeuplightsparents
            state: "on"
        sequence:
          - service: light.turn_on
            data:
              transition: |
                {{ states('input_number.timewakeupwarmupinsecs') }}
            target:
              entity_id:
                - light.hue_bulb_white_05
                - light.hue_bulb_lux_02
            enabled: true

I tested it just now with one lamp, testing in Prod will happen tomorrow morning with the bedroom lights:)

Next step is to use the bank holiday check to make sure it only occurs on non-bank holidays or allow an override button on the dashboard.

Schöne Grüsse aus England,

Norberto

Hi Norberto,

Especially using the choose-condition is much smarter that my construction with multiple if-then-else. I will change that in my setup. Thanks for this idea.

But about one detail I am not sure about your code.

What will happen if both input booleans are turned on. I would guess that only the lights in your children’s bedroom will turn on and not the lights in parent’s bedroom.
I am not sure, but I would guess that the condition will only pass the first case, if both inputs are turned on.

But with adding “and” and “or” conditions to your choose-condition it should work.

https://www.home-assistant.io/docs/scripts/conditions/

Under “Logical conditions” there are some examples for this.

Hope this helps.

Regards
Lars