Home Assistant Community

Dynamic brightness based on time of the day - setup with Lovelace sliders

#1

You are reading a how to for ‘triggered dynamic brightness based on time of the day’ or call it ‘time to brightness.’
This is very easy to implement, it’s just a somewhat big post to explain the ins and outs.

Here is how it looks in Lovelace:
Lovelace

The following setup will be useful when you want to illuminate an area with different brightness levels at different times. For example: brightness 16 at night, brightness 192 during the day, fade in from night to day 6:00-9:00, and fade out from day to night 22:00-23:30.

These brightness levels will be set when the automation is triggered, so the light does not have to be on all day. This setup also does not interfere with other automations that set specific brightness levels because you can obviously use conditions. For example use this setup with a motion sensor, and override it with a manual button that maybe temporarily disables the automation we will set up now.

To get a better understanding of dynamic brightness, have a look at the graph I made at Desmos.

The graph describes the brightness of the light during the day (only when triggered). It has the minutes of the day (0-1439) on the x-axis and the brightness (0-255) on the y-axis. Now in Desmos, open the “3c. Formulas components (dynamic)” folder in the left pane. What appears are the sliders just as how they will work in HA via Lovelace after setup.

  1. The lower level brightness (m / y1)
  2. The upper level brightness (l / y2)
  3. The fade in start time (a / x1)
  4. The fade in finish time (b / x2)
  5. The fade out start time (c / x3)
  6. The fade out finish time (d / x4)

Play with the sliders to get an understanding.

To the code then…
In the code below, the example of hallway_light is used. It is easy to change this but make sure you do change everything systematically then.

We need 6 input_numbers in the configuration.yaml per light:

input_number:
  hallway_light_x1:
    name: Hallway light x1
    min: 0
    max: 12
    step: 0.25
  hallway_light_x2:
    name: Hallway light x2
    min: 0
    max: 12
    step: 0.25
  hallway_light_x3:
    name: Hallway light x3
    min: 12
    max: 24
    step: 0.25
  hallway_light_x4:
    name: Hallway light x4
    min: 12
    max: 24
    step: 0.25
  hallway_light_y1:
    name: Hallway light y1
    min: 0
    max: 255
    step: 5
  hallway_light_y2:
    name: Hallway light y2
    min: 0
    max: 255
    step: 5

This is the automation for HA:

automation:
- id: '001'
  alias: Hallway light dynamic brightness < Motion
  trigger:
  - platform: state
    entity_id: binary_sensor.motion_sensor
    to: 'on'
  condition:
  - condition: state
    entity_id: light.hallway
    state: 'off'
  action:
  - service: light.turn_on
    data_template:
      entity_id: light.hallway
      color_temp: 250
      brightness: >-
        {% if ( ( states('input_number.hallway_light_x1') | float ) *60 ) > ( ( ( now().hour ) *60 ) + ( now().minute ) ) >= ( 0 ) %}
        {{ states('input_number.hallway_light_y1') | int }}
        {% elif ( ( states('input_number.hallway_light_x1') | float ) *60 ) <= ( ( ( now().hour ) *60 ) + ( now().minute ) ) < ( ( states('input_number.hallway_light_x2') | float ) *60 ) %}
        {{ ( (now().hour*60 + now().minute) * (states('input_number.hallway_light_y2' ) | int - states('input_number.hallway_light_y1') | int ) / (states('input_number.hallway_light_x2') | int *60 - states('input_number.hallway_light_x1') | int *60 ) + (states('input_number.hallway_light_y2' ) | int - states('input_number.hallway_light_y1') | int ) / (states('input_number.hallway_light_x2') | int *60 - states('input_number.hallway_light_x1') | int *60 ) * -1 *states('input_number.hallway_light_x1') | int *60 + states('input_number.hallway_light_y1') | int ) | int }}
        {% elif ( ( states('input_number.hallway_light_x2') | float ) *60 ) <= ( ( ( now().hour ) *60 ) + ( now().minute ) ) < ( ( states('input_number.hallway_light_x3') | float ) *60 ) %}
        {{ states('input_number.hallway_light_y2') | int }}
        {% elif ( ( states('input_number.hallway_light_x3') | float ) *60 ) <= ( ( ( now().hour ) *60 ) + ( now().minute ) ) < ( ( states('input_number.hallway_light_x4') | float ) *60 ) %}
        {{ ( (now().hour*60 + now().minute) * (states('input_number.hallway_light_y1' ) | int - states('input_number.hallway_light_y2') | int ) / (states('input_number.hallway_light_x4') | int *60 - states('input_number.hallway_light_x3') | int *60 ) + (states('input_number.hallway_light_y1' ) | int - states('input_number.hallway_light_y2') | int ) / (states('input_number.hallway_light_x4') | int *60 - states('input_number.hallway_light_x3') | int *60 ) * -1 *states('input_number.hallway_light_x3') | int *60 + states('input_number.hallway_light_y2') | int ) | int }}
        {% elif ( ( states('input_number.hallway_light_x4') | float ) *60 ) <= ( ( ( now().hour ) *60 ) + ( now().minute ) ) < ( 1440 ) %}
        {{ states('input_number.hallway_light_y1') | int }}
        {% else %}
        {{ ( 3 ) | int }}
        {% endif %}

The if state is selected based on which minute of the day it currently is, and according to that the brightness will be calculated.

Here the UI Lovelace YAML code to get the sliders:

views:
  - title: Preferences
    icon: mdi:tune-vertical
    cards:
    - type: vertical-stack
      cards:
      - type: entities
        title: Hallway
        show_header_toggle: false
        entities:
        - entity: input_number.hallway_light_y1
          name: Brightness night
          icon: mdi:brightness-3
        - entity: input_number.hallway_light_y2
          name: Brightness day
          icon: mdi:white-balance-sunny
        - entity: input_number.hallway_light_x1
          name: Fade in start
          icon: mdi:arrow-expand-up
        - entity: input_number.hallway_light_x2
          name: Fade in done
          icon: mdi:check
        - entity: input_number.hallway_light_x3
          name: Fade out start
          icon: mdi:arrow-expand-down
        - entity: input_number.hallway_light_x4
          name: Fade out done
          icon: mdi:check

If you used Desmos to generate your preferences, then note that [a-d] / x[1-4] are in minutes in Desmos, but in ‘mathematical hours’ in Lovelace. Thus 540 equals 09:00 and thus 9 in Lovelace. 570 equals 09:30 and thus 9,5 in Lovelace. 585 equals 09:45 and thus 9,75 in Lovelace.

Notes that shouldn’t matter but provide more detail in case you are going to customize:
This setup has been working without problems for 6 weeks now, except what seems to be an unrelated 1-2x per week minor issue with my Hue colour bulb. Wrong brightness from time in template if statement

Any minute of the day equal or greater than 1440 and smaller than 0 will result in brightness=3. This should not happen because ‘minute 1440’ does not exist; it will be 0 again. Let alone anything >1440 and <0. This is added for debugging/closing the if statement.

All the if states are exclusive. Even though the first one that is valid will be executed, there still is only one valid each time.

You can change the input_number details (min, max, step) of the sliders, but do note that weird things will happen when you: 1) Change the order of the x/y-points in the graph; e.g. have x1 after x3. 2) Use numbers outside the interval of 0-24 for min and max. These will not be converted to corresponding next cycle hours; e.g. 25 -> 1 is not happening. This also means that there is a limitation for the fade out finish time (d / x4); 24 is the maximum in this setup. My suggestions is to keep this general shape when trying out via Desmos: low, increasing and reaching max before 12:00, going steady for a while, then decreasing.

Why input_number and not input_datetime? Because the latter one is ridiculous to adjust in Lovelace.

Brightness is set on minute precision. Minute 1440 however will never occur (because 24:00 does not exist, it will be 0:00 instead) and thus the corresponding brightness will never be set. This might result in brightness at 00:00 being off, but only in extremely weird unlogical use cases.

Currently brightness is only updated when the automation is triggered, although it is very easy to cause ‘retriggers’ for as long as something (motion maybe) is detected.

Future improvements?

  • I will try to covert it to a script ‘soon’ that uses the entity_id as variable, so that one instance can be easily used for multiple lights. Script version being tested right now.

Problems?
Let me know. In this topic I had to generalize some of my personal data, maybe I did something wrong so feedback is welcome.

8 Likes
Wrong brightness from time in template if statement
#2

Thank you very much! Just implemented it, and it seems to work! I will play with it in the next couple days to implement it everywhere :slight_smile:
Because I wanted the same brightness for every bulb with motion detection, I changed the input_number name from hallway to just brightness. Seems more suitable for my config.

#3

Perhaps I missed the explanation but how is this different from https://www.home-assistant.io/components/flux/ ?
Does it do something the flux component can’t?

#4

Didn’t try Flux myself but from reading the page my understanding was that it doesn’t do brightness how I am doing that now. It does have a brightness option, but what does it mean? That’s the max and it will fade to 0? Seems like you can’t set a lower bound to get a night light. Also, fade in and fade out durations are equal, while I for example want slow fade in, quick fade out. On the fly adjustments in Lovelace and ability to disable it by simply disabling an automation also seems not possible with Flux. Flux is not flexible enough for me.

Someone on another forum pointed me at Circadian Lighting [Custom Component]. That one seems much more flexible, it does include night light options and also complete brightness control. But I guess it will be synced with the sun always. Offsets for that are available, but if someone always goes to bed 23:00 despite which of the 365 days it is… Ja, I am not sure how that will work then. It will all depend on use case.

The thing I am running can very easily be converted to also do colour temperature, if that would be a miss for someone. Or maybe it runs fine next to other tools. Let me know what you all make of it. :ok_hand:

#5

FWIW, You can specify sunrise and sunset times in Circadian Lighting, so it will always be the same. That’s not recommended because our bodies are accustomed to the sun changing with the season, but it doesn’t have to be synced with the sun if you don’t want.

#6

Alright, so there are some options available. :ok_hand:

With some coding help the script version is running now, I will test it for a few days before updating the topic start.

1 Like