Wake-up light alarm with sunrise effect

Tags: #<Tag:0x00007f3262651828> #<Tag:0x00007f32626514e0>

GIthub Gist: https://gist.github.com/sbyx/96c43b13b90ae1c35b872313ba1d2d2d

This is a blueprint for a wake-up light / alarm clock using a dimmable and color-temperature controllable light entity. It takes its alarm time from an existing timestamp source (such as the _next_alarm sensor from the Android companion app) or from a manual input. It will generate a sunrise effect starting from a configurable amount of minutes before the alarm time with a dim and warm-colored light slowly transitioning to the fullest brightness and coldest light temperature supported by the lamp at the alarm time. The sunrise effect can be stopped by simply turning off the light during the automation run. User-defined actions can be run at the start of the sunrise.

Prerequisites

You need to enable the ‘date_time_iso’ and ‘date’ sensor in your configuration.yaml and restart HA before using this blueprint in an automation. Configuration can be found here: https://www.home-assistant.io/integrations/time_date/

Timestamp Sensor

You can provide a timestamp sensor containing the date and time of the next alarm. By default a compatible source is the _next_alarm sensor provided by the Android companion app that reads your next configured smart phone alarm. You can in principle use other sources as long as they contain a valid timestamp in text form with both date and time information that can be parsed by the as_timestamp function. However the source (like the next_alarm sensor) needs to have an attribute device_class set to timestamp before it appears in the dropdown. However you can still manually input the sensor by its name.

Using a manual alarm time

By setting the timestamp sensor to ‘none’ you can use a manual alarm time. The alarm will go off everyday at that time unless you turn off the automation manually or define additional conditions (see below). Note that alarm times at midnight or shortly after will not work as expected. Manual alarm time requires ‘sensor.date’ to be enabled.

Custom Pre-sunrise Actions

As noted you can define custom actions to be run before the sunrise effect. I’m using this e.g. to disable sleep mode in adaptive_lighting.

Additional conditions (e.g. workday, presence)

You can set an additional entity that is checked before the sunrise is triggered. If set the entity needs to have state ‘on’ or ‘home’ otherwise the alarm is not triggered. You can use for example a person entity or a device_tracker to check if a certain person is home before the sunrise is triggered. Other options would be to use a workday sensor to check the day if the day is a workday: https://www.home-assistant.io/integrations/workday/
Alternatively if you have a (bed) occupancy sensor you could use this as well.

Troubleshooting

  1. Please note that automations based on this blueprint can not be manually triggered. Either a timestamp sensor or a manual time needs to be defined. The automation will start the configured number of minutes (25 by default) BEFORE the alarm time.
  2. Make sure the machine running HA has the correct time set and you have the correct time zone configured in HA under Settings - General Settings.
  3. Check your HA logs for related problems, especially those referring to templates. Please post any potentially relevant errors along with your problem.
  4. If you are having issues please always include your blueprint configuration: use the three-dots menu and select Edit as YAML and include the contents of your configuration along with your post.

Using multiple lights for the sunrise

There are multiple ways to achieve this. If you have multiple lights of the same type you can just group them either using your native light integration (e.g. deconz) or you use HA’s high-level way of defining light groups documented here: https://www.home-assistant.io/integrations/light.group/
In any case the result will be a light entity that controls the whole group as if it was a single light.
You can just use this new light entity in the blueprint and be done. All lights of the group will be synchronized when using the group entity however they can still be individually controlled using their normal light entities.

If you have different kinds of lights with different absolute brightness and / or color temperature range you can simply create one automation for each such light from this blueprint and define e.g. different maximum brightness or even different sunrise durations individually to your liking. Just refer to the same timestamp sensor so that they will end at the same time.

Blueprint Code

blueprint:
  name: Wake-up light alarm with sunrise effect
  description: 'A wake-up light alarm with a brightness and color temperature sunrise
    effect. Note: Requires date_time_iso sensor in configuration, not manually executable!'
  domain: automation
  input:
    light_entity:
      name: Wake-up light entity
      description: The light to control. Turning it off during the sunrise will keep
        it off. Color temperature range is auto-detected.
      selector:
        entity:
          domain: light
    timestamp_sensor:
      name: Alarm timestamp sensor
      description: 'Sensor with timestamp of next alarm with device_class: timestamp
        (set to ''none'' for manual alarm time)'
      default: none
      selector:
        entity:
          device_class: timestamp
    manual_time:
      name: Manual alarm time
      description: Time to trigger alarm every day if timestamp sensor is not set.
        Settings at or shortly after midnight will not work as expected!
      default: '7:00:00'
      selector:
        time: {}
    check_entity:
      name: Additional entity to check before sunrise is triggered
      description: If set, checks if entity is 'on' or 'home' before triggering. Use
        e.g. a (workday) sensor, device_tracker or person entity.
      default: none
      selector:
        entity: {}
    sunrise_duration:
      name: Sunrise duration
      description: The sunrise will start the configured number of minutes before
        the timestamp.
      default: 25
      selector:
        number:
          min: 5.0
          max: 60.0
          step: 5.0
          unit_of_measurement: min
          mode: slider
    start_brightness:
      name: Minimum brightness
      description: The brightness to start with. Some lights ignore very low values
        and may turn on with full brightness instead!
      default: 1
      selector:
        number:
          min: 1.0
          max: 255.0
          step: 1.0
          mode: slider
    end_brightness:
      name: Maximum brightness
      description: The brightness will be transitioned from the minimum to the configured
        value.
      default: 254
      selector:
        number:
          min: 5.0
          max: 255.0
          step: 1.0
          mode: slider
    min_mired:
      name: Minimum color temperature
      description: 'The minimum color temperature to use. (0: lowest supported)'
      default: 0
      selector:
        number:
          min: 0.0
          max: 500.0
          step: 5.0
          mode: slider
          unit_of_measurement: mired
    pre_sunrise_actions:
      name: Pre-sunrise actions
      description: Optional actions to run before sunrise starts.
      default: []
      selector:
        action: {}
    post_sunrise_actions:
      name: Post-sunrise actions
      description: Optional actions to run after sunrise ends (around the alarm time).
      default: []
      selector:
        action: {}
  source_url: https://gist.github.com/sbyx/96c43b13b90ae1c35b872313ba1d2d2d
variables:
  light_entity: !input 'light_entity'
  sensor: !input 'timestamp_sensor'
  sunrise_duration: !input 'sunrise_duration'
  start_brightness: !input 'start_brightness'
  end_brightness: !input 'end_brightness'
  range_brightness: '{{float(end_brightness)-float(start_brightness)}}'
  manual_time: !input 'manual_time'
  seconds: '{{float(sunrise_duration) * 60}}'
  min_mired: !input 'min_mired'
  start_mired: '{{state_attr(light_entity, ''max_mireds'')}}'
  end_mired: '{{[state_attr(light_entity, ''min_mireds'')|int, min_mired|int]|max}}'
  tick_time: '{{float(seconds) / float(range_brightness)}}'
  check_entity: !input 'check_entity'
trigger:
- platform: time_pattern
  minutes: '*'
condition: []
action:
- wait_template: '{{sensor == ''none'' or as_timestamp(states(sensor)) != None}}'
- wait_template: '{{0 < as_timestamp(states(sensor) if sensor != ''none'' else states(''sensor.date'')
    ~ '' '' ~ manual_time) - as_timestamp(states(''sensor.date_time_iso'')) <= float(seconds)
    and states(check_entity) in [''unknown'', ''on'', ''home'']}}'
- choose: []
  default: !input 'pre_sunrise_actions'
- condition: template
  value_template: '{{sensor == ''none'' or as_timestamp(states(sensor)) != None}}'
- condition: template
  value_template: '{{0 < as_timestamp(states(sensor) if sensor != ''none'' else states(''sensor.date'')
    ~ '' '' ~ manual_time) - as_timestamp(now()) <= float(seconds) and states(check_entity)
    in [''unknown'', ''on'', ''home'']}}'
- choose:
  - conditions:
    - '{{state_attr(light_entity, ''min_mireds'') != None}}'
    sequence:
    - service: light.turn_on
      data:
        brightness: '{{start_brightness}}'
        color_temp: '{{start_mired}}'
      entity_id: !input 'light_entity'
  default:
  - service: light.turn_on
    data:
      brightness: '{{start_brightness}}'
    entity_id: !input 'light_entity'
- repeat:
    while:
    - '{{sensor == ''none'' or as_timestamp(states(sensor)) != None}}'
    - '{{0 < as_timestamp(states(sensor) if sensor != ''none'' else
        states(''sensor.date'') ~ '' '' ~ manual_time) - as_timestamp(now()) <= float(seconds)}}'
    sequence:
    - delay: '{{tick_time}}'
    - choose:
      - conditions:
        - '{{0 < state_attr(light_entity, ''brightness'') | int < end_brightness | int}}'
        - '{{sensor == ''none'' or as_timestamp(states(sensor)) != None}}'
        - '{{0 < as_timestamp(states(sensor) if sensor != ''none'' else
          states(''sensor.date'') ~ '' '' ~ manual_time) - as_timestamp(now()) <= float(seconds)}}'
        sequence:
        - choose:
          - conditions:
            - '{{state_attr(light_entity, ''min_mireds'') != None}}'
            sequence:
            - service: light.turn_on
              data:
                brightness: '{{(float(end_brightness) - (float(range_brightness) *
                  (as_timestamp(states(sensor) if sensor != ''none'' else states(''sensor.date'')
                  ~ '' '' ~ manual_time) - as_timestamp(now())) / float(seconds))) | int}}'
                color_temp: '{{(float(end_mired) + (float(start_mired) - float(end_mired))
                  * ((as_timestamp(states(sensor) if sensor != ''none'' else states(''sensor.date'')
                  ~ '' '' ~ manual_time) - as_timestamp(now())) / float(seconds))) | int}}'
              entity_id: !input 'light_entity'
          default:
          - service: light.turn_on
            data:
              brightness: '{{(float(end_brightness) - (float(range_brightness) * (as_timestamp(states(sensor)
                if sensor != ''none'' else states(''sensor.date'') ~ '' '' ~ manual_time)
                - as_timestamp(now())) / float(seconds))) | int}}'
            entity_id: !input 'light_entity'
- choose: []
  default: !input 'post_sunrise_actions'
mode: single
max_exceeded: silent

Explanation

In the variables section we are first reading the max_mireds and min_mireds from the light entity to define the color temperature range we can use for the sunrise effect.

The trigger is actually not the real trigger as you may guess. It will simply start the automation every minute in case it is not running and will waiting for the real trigger in the wait_template of the first action. This seems necessary since the computed blueprint variables are not available in the actual trigger section already. Note that we are using the date_time_iso sensor here instead of the now() function to cause reevaluation of the template at least every minute.

We are running pre-sunrise actions inside a choose block with an always-true condition since I haven’t found a better way to include them in the flow yet. If you have one, please let me know!
Thanks to swiftlyfalling for providing a better solution!

We turn on the light unconditionally only the first time with minmum brightness and warmest color temperature. Afterwards we always check if someone didn’t turn off the light in the meantime and in that case we just skip updating the light. We are however not leaving the automation since that would cause it to restart turning the light on again.

Now in the main loop every 5 seconds we recalculate what should be the current brightness and temperature of the light based on how close we are to the alarm time and simply update the lamp.

Changelog

  • 2021-01-13: Test whether light was manually set above end brightness.
  • 2021-01-12: Add custom post-sunrise actions
  • 2021-01-10: Add additional sensor to check before sunrise
  • 2021-01-08: Fix minimum color temperature detection
  • 2021-01-06: Add optional minimum brightness and color temperature.
  • 2021-01-01: Work-around template issue in HA to fix manual time.
  • 2020-12-19: Use absolute brightness steps instead of percent and remove transitions again.
  • 2020-12-18: Fix custom-conditions triggering light at random times.
  • 2020-12-17: Added support for manual alarm time
  • 2020-12-16: Added support for non-color-temperature lights. Added default for pre-sunrise-actions (thanks to swiftlyfalling).
  • 2020-12-15 (15.00 UTC): Added default values. Dynamically determine tick intervals based on duration and maximum brightness instead of using fixed 5 second interval. Added transitions between intervals for lights that support it.
  • 2020-12-15: Added maximum brightness input.
  • 2020-12-14: Avoid logging errors when template sensor is not available or does not contain a valid timestamp temporarily.
  • 2020-12-13: Initial version

My blueprints

25 Likes

tnx alot i never got this to work before blueprints.

But i have a small request,

  • Wake-up light entit, can you make these multiple devices ?
  • is there a way to play music over google cast devices ?

it will come one step closer to the endgoal :smiley:
(endgoal : https://www.youtube.com/watch?v=mccJNHih7a8&ab_channel=CraigMidwinter)

2 Likes

Hahaha that’s really crazy. But in principle you can already achieve a bit less sophisticated version of this with the blueprint. In the pre-sunrise actions you can call media_player.play_media service on a google home to play an audio of your choice. You can create a light group in HA and use that as light entity but they will be synchronized then and not turn on one after the other. However I guess you could use two automations made from this same blueprint with two different lights to have that delay somehow. Though youtube videos aside I suppose this would get old pretty fast if it wakes you up like this every morning :wink:

2 Likes

My plan is to use the song BFG division. It wont get old. It will also physically chase me out of bed!

Thanks for providing the Blueprint, this is going to be my first attempt at using it.

Out of interest, how does it handle the ‘Next Alarm’ being unavailable?
I haven’t reconfigured NabuCasa yet, so if I’m not at home for any reason HA wont be able to pull my latest alarm. Would it just not fire and write an error to the logs?
(that’s my hope)

Yeah it will actually write some error in the log since the template will fail in some way but not trigger the sunrise or anything. I guess error handling should be improved at some point so that the log is not written to if there is no alarm. Right now it will just error and restart trying to evaluate the next alarm one minute later. So other than some entries in your log nothing bad should actually happen.

1 Like

Great stuff! Didn’t want my logs getting spammed/lights going mad while I’m away.
Maybe there would be a way to add a condition as a first step? (“If ‘bed occupancy sensor’ is true” or “IF ‘phone is home’”)

2 Likes

This combination is interesting and not something I’ve seen before.

I also like the way you use the current time to determine brightness/color of the lights at each interval instead of using some incrementing value like many other similar automations I’ve seen.

In my case, the “wake up light” is also the “okay I’m up and need to see in this room because it’s dark out” light. So, my “sunrise” should end when I set the light to the color/brightness that I generally use. If you’re like me, you can add to the repeat sequence conditions to check for those values and also not perform the light.turn_on calls if those values are seen.

1 Like

Before blueprints I had this automation with hardcoded entity and sensor etc. and I actually used what I have now in the wait_template as a template trigger directly. But yeah with blueprints that doesn’t seem to work or at least I didn’t find a way to access the blueprint inputs in a trigger template. So I had to improvise a bit.

Have you seen this before? A one-choice choose hard-coded to True.

  - choose:
    - conditions:
      - condition: template
        value_template: '{{ true }}'
      sequence: !input pre_sunrise_actions

Blueprints. The new way to distribute unoptimized automations. :man_shrugging:

4 Likes

hehe. I can’t say that I have.

I assumed the OP looked into ways to perform a sequence of events specified by selector: action: and found that this was the cleanest way. I don’t use choose statements often because they are cumbersome so I just move those automations to something better suited to expressing logic (like pyscript).

What can be used in an “action:” list to indicate a sequence of actions to perform?

action:
  - delay: 1
  - something_here: !input pre_sunrise_actions

Perhaps a default with no choices?

action:
  - choose: []
    default: !input pre_sunrise_actions

Or maybe sequence can be used in a sequence?

action:
  - sequence: !input pre_sunrise_actions

I honestly don’t know.

Well I think it’s interesting.

It’s a bit unoptimized since, every minute, something in Home Assistant will wake up, see that this automation is still running, and then go back to sleep. But, it certainly is a way to work around issues and features that are currently missing.

1 Like

I now changed my other blueprint to the choose with just a default-approach. Seems to work as well. Thanks for the hint. Gonna do this here too when I am addressing the logging issue.

However turning the choose with true-condition into an outright optimization issue is a bit nitpicking.

Your posting history in this forum indicates you have never shared an automation before. If you had, I can assure you it would have been scrutized and any unoptimized code identified. This forum is filled with examples of automations undergoing a process of refinement.

The advent of blueprints doesn’t change that. In fact, it may be even more necessary because now it’s easier than ever to distribute unoptimized code, especially to new users who have little or no understanding of YAML automations.

3 Likes

I pointed out that I didn’t like this part and was looking or a better solution for it together with the blueprint in the very start of the thread already. Yet instead of proposing a better solution you just told me what I knew already.

Never mind the discussions I updated the original post and added an additional check that makes sure the log is not polluted when the timestamp sensor is not set / available. And I removed that true condition from the choose-block containg the custom actions. Thanks again to swiftlyfalling for providing the solution with the empty choose-block.

1 Like

Why don’t you go for

action:
  - service: light.turn_on
    data:
      brightness: 1
      kelvin: 2700
      transition: 0
    entity_id: light.licht_schlafzimmer
  - service: light.turn_on
    data:
      transition: 1800
      brightness: 255
      kelvin: 6000
    entity_id: light.licht_schlafzimmer
3 Likes

Great blueprint, and one I fully intend to try.
One improvement for me (and mentioned by someone in this thread) would be to set a max brightness for the light. A simple number input (max 100) should do it, and then change the formula in the light setting to use that percentage instead of 100 as the max.

Eg from:

brightness_pct: >-
 {{ (100 - (100 *
 (as_timestamp(states(timestamp_sensor)) -
  as_timestamp(now())) /
  (float(sunrise_duration) * 60))) | int }}

To:

brightness_pct: >-
  {{ (100 - (float(max brightness) i
  (as_timestamp(states(timestamp_sensor)) -
   as_timestamp(now())) /
  (float(sunrise_duration) * 60))) | int }}
1 Like

Would it be possible to get a github link for the code?

Hi,
Is it possible to use something else than time timestamp?
I’m not using alarm on my phone for wake up so for example input_datetime would be usefull.
How can I use it with you blueprint?

I pushed a couple changes:

  • There is now a Github Gist at the very top with the code.
  • I added the max brightness as an additional input, if you update and already have an automation based on this blueprint, make sure you are setting that value in your automation otherwise it won’t work. To get the existing behavior just set the maximum brightness to 100.
  • I added an additional paragraph in the original post to describe steps how to setup using an input_datetime.

As for why I am not simply using transition: 1800 or some thing. Not sure this is widely supported among light integrations with these high numbers but I might be wrong here. If it works for you this way then sure would be a much cleaner solution.

2 Likes