Confirmed…Just tried @pnbruckner’s sun component, and it was exactly what was called for.
Hi everyone.
Like others have said, I also wanted to have a light turn on at dusk rather than sunset.
Currently for me the difference is about 28 minutes between the two attributes of sun.sun being next_setting and next_dusk.
I did get some inspiration from the trigger that @will presented but I did not want the 180 second offset he used and I wanted it to occur at the exact moment that the next_dusk attribute of the sun.sun entity reports.
After removing the 180 second offset, i discovered the trigger never occurs because of the following statement at
https://www.home-assistant.io/docs/configuration/templating/#time
- Using
now()
will cause templates to be refreshed at the start of every new minute.
I understood that to mean if I used a value lower than 60 seconds in the offset, now() will never get a chance to be greater than or equal to next_dusk.
Due to this discovery, I had to find another way to have my light turn on exactly at dusk.
Here is what I found worked for me.
trigger:
- platform: state
entity_id: sun.sun
attribute: next_dusk
This simple trigger does exactly what I want.
When the value for now() catches up to the next_dusk value for today, the next_dusk attribute will immediately roll over to the next day.
This trigger just waits for that attribute to change and then my light turns on.
As I am rather new to Home Assistant, I only recently found the developer tools to be handy for troubleshooting. This might be handy for newbies.
States Tab
as well as the template tab
Hope this helps anyone else.
If anyone still wants to use the offset, then I would suggest using this updated code. Apparantly using states.sun.sun.attributes.next_dusk is a frowned upon even though it appears to do the job.
Avoid using
states.sensor.temperature.state
, instead usestates('sensor.temperature')
. It is strongly advised to use thestates()
,is_state()
,state_attr()
andis_state_attr()
as much as possible, to avoid errors and error message when the entity isn’t ready yet (e.g., during Home Assistant startup).
Source: https://www.home-assistant.io/docs/configuration/templating/#home-assistant-template-extensions
Updated code
trigger:
- platform: template
value_template: >-
{{ ((as_timestamp(state_attr('sun.sun', 'next_dusk')) | int ) - 180 ) <
(as_timestamp(utcnow()) | int ) }}
This is slightly off topic but I have also added a notify action to show me when next dusk will occur when the trigger in my automation occurs
alias: Light on dusk
description: ''
trigger:
- platform: state
entity_id: sun.sun
attribute: next_dusk
condition: []
action:
- type: turn_on
device_id: xxx
entity_id: xxx
domain: light
- service: notify.notify
data_template:
message: >
Dusk tomorrow will be at {{ as_timestamp(state_attr("sun.sun",
"next_dusk")) | timestamp_custom('%I:%M:%S %p') }}
mode: single
This will turn the light on at dusk as well as show the time for dusk tomorrow when the time for dusk today is reached
Thought I’d share my take on this classic automation of turning on the porch lights. This was my first ever automation, and my version of it has evolved over the past four years. Here are my latest set of requirements:
- Be ‘on’ between 30 minutes before sunset and 30 minutes after sunrise
- EXCEPT if it’s after 23:30h or before 07:00h (so ‘off’ in this case)
- EXCEPT if (so, ‘on’ in these cases):
- An exterior door is open
- It is within 30 minutes of an exterior door being closed
- it is within 30 minutes of somebody arriving home
So, first, I have a binary sensor that will be ‘on’ if these conditions are met, and ‘off’ otherwise. I found it frustrating that sun.sun
always shows the next sunrise and not the last sunrise. I approximated by just forcing today’s date onto the setting and rising times; I’m not sure if I’ll run into a “1-hour-off” bug during daylight savings time changes.
template:
- binary_sensor:
- name: outside_lights_on
state: >
{%- set current_time = states('sensor.date_time') | as_timestamp -%}
{%- set today_date = states('sensor.date') -%}
{%- set today_sunset = (today_date + 'T' + state_attr('sun.sun', 'next_setting').split('T')[1]) | as_timestamp - (60 * 30) -%}
{%- set today_sunrise = (today_date + 'T' + state_attr('sun.sun', 'next_rising').split('T')[1]) | as_timestamp + (60 * 30) -%}
{%- set morning_time = (today_date + "T07:00:00") | as_timestamp -%}
{%- set evening_time = (today_date + "T23:30:00") | as_timestamp -%}
{%- set exterior_doors = ['binary_sensor.frontdoor', 'binary_sensor.backdoor'] -%}
{# returns a JSON array of entities that have a state in the *states_to_match* array #}
{%- macro filter_by_state (entities, states_to_match) -%}
{{ "[" }}
{%- for e in entities if (states(e) in states_to_match) -%}
"{{ e }}"{{ "," if (not loop.last) else "" }}
{%- endfor -%}
{{ "]" }}
{% endmacro %}
{# returns a JSON array of entities whose states have changed within *delta* time of *ct* (current_time) #}
{%- macro changed_in_last (entities, ct, delta) -%}
{{ "[" }}
{%- for e in entities if ((ct - (states[e].last_changed | as_timestamp)) < delta.total_seconds()) -%}
"{{ e }}"{{ "," if (not loop.last) else "" }}
{%- endfor -%}
{{ "]" }}
{% endmacro %}
{%- if (current_time > today_sunset) or (current_time < today_sunrise) -%}
{%- if (current_time >= evening_time) or (current_time <= morning_time) -%}
{%- set people_home = states.person | selectattr('state', 'eq', 'home') | map(attribute='entity_id') | list -%}
{%- set people_home_in_range = changed_in_last (people_home, current_time, timedelta(minutes=30)) | from_json -%}
{%- set doors_open = filter_by_state(exterior_doors, ['on']) | from_json -%}
{%- set doors_closed = filter_by_state(exterior_doors, ['off']) | from_json -%}
{%- set doors_closed_in_range = changed_in_last (doors_closed, current_time, timedelta(minutes=30)) | from_json -%}
{%- if (people_home_in_range | count > 0) -%} true
{%- elif (doors_open | count > 0) -%} true
{%- elif (doors_closed_in_range | count > 0) -%} true
{%- else -%} false
{%- endif -%}
{%- else -%}
true
{%- endif -%}
{%- else -%}
false
{%- endif -%}
Next, I have an automation to set the state of the outside lights to whatever the sensor says they should be. Ignore the condition
for now, I’ll get back to that.
automation:
- alias: outside_lights_on_off
mode: queued
max: 10
max_exceeded: silent
initial_state: 'on'
trigger:
- platform: state
entity_id: binary_sensor.outside_lights_on
action:
- condition: template
value_template: "{{ not is_state('timer.porchlights', 'active') }}"
- service: "light.turn_{{ states('binary_sensor.outside_lights_on') }}"
data:
entity_id:
- light.front_porch_lights
- light.garage_outside_light
- light.deck_light
After trying this out for a night, I realized that there was a problem: if somebody manually changed the state of any of those lights, it would never come back in-line with the rest until the binary sensor changed state again. This is where that timer comes in. I introduced it along with two other automations to allow people to manually turn the lights on or off outside of their scheduled time ranges. When the lights are manually switched, start a 20 minute timer, after which another automation will set the lights back to the state the binary sensor says they should be:
timer:
porchlights:
duration: '00:20:00'
automation:
- alias: outside_lights_manually_switched
mode: restart
trigger:
- platform: state
entity_id:
- light.front_porch_lights
- light.garage_outside_light
- light.deck_light
condition:
condition: template
value_template: >
{# Be careful not to trigger this automation when the lights are turned on or off via the actual schedule. #}
{%- set two_seconds_ago = (now() - timedelta(seconds=2)) | as_timestamp -%}
{%- set last_automation_run = state_attr('automation.outside_lights_on_off', 'last_triggered') | as_timestamp -%}
{{ last_automation_run < two_seconds_ago }}
action:
- service: timer.cancel
target:
entity_id: timer.porchlights
- service: timer.start
target:
entity_id: timer.porchlights
data:
duration: "00:20:00"
- alias: outside_lights_timer_finished
trigger:
- platform: event
event_type: timer.finished
event_data:
entity_id: timer.porchlights
action:
- service: automation.trigger
target:
entity_id: automation.outside_lights_on_off
I’m pretty happy with this version; it covers all the cases I could think of.
Hey Will,
Did you fix the turn on lights at dusk? I would really like to be able to automate that.
Thanks!
I’ve fixed it.
Here’s how I did it
alias: Front Stairs on dusk
description: ''
trigger:
- platform: state
entity_id: sun.sun
attribute: next_dusk
condition: []
action:
- type: turn_on
device_id: 9b90ebd0a6d1fe1021f792e438d913c3
entity_id: light.front_stairs
domain: light
mode: single
Alright,
Actually I tried that today. The lights went on just about 2 hours later than dusk. Do you have any ideas?
Have you set your house coordinates correctly in home assistant / configuration / general?
Also check the Timezone just below that setting on the same page … and possibly elevation might play a part in the calculation too
Yes,
Checked everything there. All set correctly…
This is what it said today:
next_dusk: ‘2021-09-10T18:19:56.880598+00:00’
Light automation triggered 8:22:54 PM
What do you see when you go here in dev tools?
Ok, Those times are in utc, to convert the time stamp, instead try pasting this in dev tools / template
Next Dusk will be at
{{ as_timestamp(state_attr("sun.sun","next_dusk")) | timestamp_custom('%I:%M:%S %p') }}
I’ve updated the code.
Try
Next setting will be at
{{ as_timestamp(state_attr("sun.sun","next_setting")) | timestamp_custom('%I:%M:%S %p') }}
Next Dusk will be at
{{ as_timestamp(state_attr("sun.sun","next_dusk")) | timestamp_custom('%I:%M:%S %p') }}
trigger:
- platform: state
entity_id: sun.sun
attribute: next_dusk
The trigger you have will trigger when the ‘next_dusk’ attribute changes, not at the time the attribute refers to. You need to look at a time trigger or a template trigger.
I disagree. This trigger works perfectly for me everyday.
I guess it would change when the current ‘next_dusk’ time passes. Fair enough
Thats what I figured.
Then I should wait and see what happens tomorrow?
Well, is the time of 8:19pm what you expected for dusk or not? I don’t live where you live so I don’t know what is normal where you live.
Did you try the updated template that shows setting and dusk times?
I have double checked now.
Dusk where I live is at 20:19.
However. This is what the su.sun attributes says: next_dusk: ‘2021-09-10T18:19:56.880598+00:00’