✅ This opportunity has received architecture approval: home-assistant/architecture#1394.
Problem statement
Currently, the sun trigger in Home Assistant supports two events: sunrise and sunset. That's it. While a time-based offset can be applied to these, offsets are not a reliable substitute for proper sun elevation-based events. Events like civil dawn, nautical twilight, or the onset of night are defined by the sun's elevation angle and not by a fixed number of minutes before or after sunrise.
A "-30 minute offset on sunrise" may approximate civil dawn reasonably well on a spring morning at a mid-latitude location, but that same offset will be significantly off in winter or at a different latitude. For users at high latitudes this breaks down even further: in areas like Scandinavia, the offset needed to approximate a given elevation event shifts dramatically across seasons, requiring constant manual recalibration. For users inside the Arctic circle, sunrise and sunset may not occur at all for weeks at a time, making the trigger completely useless for large parts of the year.
Automating things like outdoor lights, roller blinds, or morning routines based on the state of the sun is one of the most common use cases in Home Assistant, particularly among users just getting started. The current trigger sets them up with automations that silently degrade as seasons change. We believe it's time to address the shortcomings of the sun trigger and condition in Home Assistant.
Community signals
Scope & Boundaries
In scope
- Expanding the offering for sun-based triggers and conditions in Home Assistant.
Not in scope
- Going beyond sun-based triggers and conditions (e.g., no moon).
Foreseen solution
We want to add a fuller set of sun triggers and conditions, all based on the sun's actual elevation rather than fixed time offsets, so automations behave correctly year-round and at any latitude.
A few principles guide the list:
- Triggers fire at a moment; conditions test a state. A trigger like sunrise or dawn fires the instant the sun crosses an elevation. A condition like "it is night" or "it is twilight" tests whether the sun is currently in a given state. Some things therefore appear only as a trigger or only as a condition, depending on whether they are a moment or a duration (see the note on phases and moments below).
- One target. There is only ever one sun, so these triggers and conditions do not need the target or behaviour options that other domains use.
- Elevation-based triggers support
for. The threshold triggers and the elevation condition support a for duration, so you can require a state to hold for a period before acting.
Phases vs. moments (dawn, dusk, and twilight)
These terms are easy to conflate, so to be clear about how they map here:
- Twilight is a phase, a period during which the sun sits in a band below the horizon. Each band has three types: civil (-0.833° to -6°), nautical (-6° to -12°), and astronomical (-12° to -18°). Because it has duration, twilight is a condition (
sun.is_morning_twilight / sun.is_evening_twilight, with a type option).
- Dawn and dusk are moments, the instants the sun crosses a band's boundary. Dawn is the morning (rising) crossing, dusk is the evening (descending) crossing. So civil dawn is the instant the sun reaches -6° while rising, and civil dusk is the instant it reaches -6° while descending. Because they have no duration, dawn and dusk are triggers (
sun.dawn / sun.dusk, with a type option). There is no phase called "civil dawn" or "civil dusk". The phase is civil twilight, and dawn and dusk are simply the names for its morning and evening edges. This is why dawn and dusk appear only as triggers and twilight only as a condition. For the same reason there are no sun.is_dawn / sun.is_dusk conditions (nothing to test as a sustained state), and no sun.is_solar_noon / sun.is_solar_midnight conditions (those are instantaneous moments too).
Higher priority
These cover the everyday cases: the position of the sun, and the named points around sunrise and sunset that most automations care about.
Triggers
| Key |
Title |
Description |
Spec |
Options |
sun.sunrise |
Sunrise |
Triggers when the sun rises. |
Elevation reaches -0.833° while rising. |
— |
sun.sunset |
Sunset |
Triggers when the sun sets. |
Elevation reaches -0.833° while descending. |
— |
sun.solar_noon |
Solar noon |
Triggers when the sun reaches its highest. |
Elevation reaches its peak. |
— |
sun.solar_midnight |
Solar midnight |
Triggers when the sun reaches its lowest point below the horizon. |
Elevation reaches its lowest point. |
— |
sun.elevation_crossed_threshold |
Sun elevation crossed threshold |
Triggers when the sun's elevation crosses a threshold you set. |
Fires once when the threshold or range set by the user is reached. |
Reuses the common threshold options for crossed_threshold triggers. |
sun.elevation_changed |
Sun elevation changed |
Triggers whenever the sun's elevation changes, optionally limited to a threshold or range you set. |
Fires on every elevation change, with an optional threshold or range. |
Reuses the common threshold options for crossed_threshold triggers. |
sun.dawn |
Dawn |
Triggers at dawn, when civil, nautical, or astronomical twilight begins. |
Elevation reaches a configurable threshold while rising. |
type: civil (-6°, default), nautical (-12°), astronomical (-18°). |
sun.dusk |
Dusk |
Triggers at dusk, when civil, nautical, or astronomical twilight ends. |
Elevation reaches a configurable threshold while descending. |
type: civil (-6°, default), nautical (-12°), astronomical (-18°). |
Conditions
| Key |
Title |
Description |
Spec |
Options |
sun.is_up |
Sun is up |
Tests if the sun is up. |
Elevation >= -0.833°. |
— |
sun.is_set |
Sun is set |
Tests if the sun is set. |
Elevation < -0.833°. |
— |
sun.is_rising |
Sun is rising |
Tests if the sun is rising. |
Elevation increasing (evaluated from trend, because reading the raw value could introduce noise around solar noon and solar midnight). |
— |
sun.is_descending |
Sun is descending |
Tests if the sun is descending. |
Elevation decreasing (evaluated from trend, because reading the raw value could introduce noise around solar noon and solar midnight). |
— |
sun.elevation |
Sun elevation |
Tests the sun's elevation against a threshold you set. |
Elevation compared against the user-set threshold. |
Reuses the common threshold selector (above/below and value). |
sun.is_night |
It is night |
Tests if it is night. |
Elevation <= -18°. |
— |
sun.is_morning_twilight |
It is morning twilight |
Tests if it is morning twilight, optionally of a specific type. |
Elevation within the band for the chosen type. |
type: any (-18° to -0.833°, default), civil (-6° to -0.833°), nautical (-12° to -6°), astronomical (-18° to -12°). |
sun.is_evening_twilight |
It is evening twilight |
Tests if it is evening twilight, optionally of a specific type. |
Elevation within the band for the chosen type. |
type: any (-18° to -0.833°, default), civil (-6° to -0.833°), nautical (-12° to -6°), astronomical (-18° to -12°). |
Lower priority (add later)
These are more specialist: the golden and blue hours that photographers care about, and the midnight sun and polar night that matter at high latitudes.
Triggers
| Key |
Title |
Description |
Spec |
Options |
sun.golden_hour_started |
Golden hour started |
Triggers when golden hour starts, in the morning, the evening, or either. |
Morning: elevation reaches -4° while rising. Evening: elevation reaches 6° while descending. With any, fires at both crossings. |
period: any (default), morning, evening |
sun.golden_hour_ended |
Golden hour ended |
Triggers when golden hour ends, in the morning, the evening, or either. |
Morning: elevation reaches 6° while rising. Evening: elevation reaches -4° while descending. With any, fires at both crossings. |
period: any (default), morning, evening |
sun.blue_hour_started |
Blue hour started |
Triggers when blue hour starts, in the morning, the evening, or either. |
Morning: elevation reaches -6° while rising. Evening: elevation reaches -4° while descending. With any, fires at both crossings. |
period: any (default), morning, evening |
sun.blue_hour_ended |
Blue hour ended |
Triggers when blue hour ends, in the morning, the evening, or either. |
Morning: elevation reaches -4° while rising. Evening: elevation reaches -6° while descending. With any, fires at both crossings. |
period: any (default), morning, evening |
sun.midnight_sun_started |
Midnight sun started |
Triggers when the midnight sun period starts and the sun stops setting. |
Sun stops setting; stays above the horizon for 24h. |
— |
sun.midnight_sun_ended |
Midnight sun ended |
Triggers when the midnight sun period ends and the sun sets again. |
Sun sets again after a midnight sun period. |
— |
sun.polar_night_started |
Polar night started |
Triggers when the polar night period starts and the sun stops rising. |
Sun stops rising; stays below the horizon for 24h. |
— |
sun.polar_night_ended |
Polar night ended |
Triggers when the polar night period ends and the sun rises again. |
Sun rises again after a polar night period. |
— |
Conditions
| Key |
Title |
Description |
Spec |
Options |
sun.is_golden_hour |
It is golden hour |
Tests if it is golden hour, optionally for a specific period. |
Elevation between -4° and 6°. |
period: any (default), morning, evening |
sun.is_blue_hour |
It is blue hour |
Tests if it is blue hour, optionally for a specific period. |
Elevation between -6° and -4°. |
period: any (default), morning, evening |
sun.is_midnight_sun |
It is midnight sun |
Tests if it is midnight sun. |
Sun stays above the horizon for 24h. |
— |
sun.is_polar_night |
It is polar night |
Tests if it is polar night. |
Sun stays below the horizon for 24h. |
— |
Risks & open questions
- Trigger/condition overlap. Some of the proposed triggers and conditions overlap. We've left them in because, semantically, they're different. For example, "golden hour ended" and "blue hour started" describe the same moment, but from different perspectives. We normally wouldn't want this, but in this case we've made the conscious decision to make an exception.
- No time-based offsets (yet?). Because of the high specificity of these triggers, we are assuming there is no longer a need for time-based offsets within them. We are open to feedback on this. For now, we have decided to leave them out.
- Naming convention deviation. A few titles deliberately depart from the standard trigger/condition naming convention (to be published as part of our developer documentation soon). Sun events are named moments ("Sunrise", "Dawn") rather than the usual "[entity] [past-tense event]" form, and some condition titles ("It is night", "It is twilight") read more naturally without the entity name. This is intentional. There is a risk involved in deviating from a standard, it is not a decision we should take too lightly, but in this case we think it's for the best.
- Double firing triggers. With the period set to "any", the golden and blue hour triggers fire at both the morning and the evening crossing (twice per day). This is intended, but the UI copy and docs should make it clear so it isn't surprising.
Appetite
Small - We should be able to complete this in several days to a week.
Execution issues
No response
✅ This opportunity has received architecture approval: home-assistant/architecture#1394.
Problem statement
Currently, the sun trigger in Home Assistant supports two events: sunrise and sunset. That's it. While a time-based offset can be applied to these, offsets are not a reliable substitute for proper sun elevation-based events. Events like civil dawn, nautical twilight, or the onset of night are defined by the sun's elevation angle and not by a fixed number of minutes before or after sunrise.
A "-30 minute offset on sunrise" may approximate civil dawn reasonably well on a spring morning at a mid-latitude location, but that same offset will be significantly off in winter or at a different latitude. For users at high latitudes this breaks down even further: in areas like Scandinavia, the offset needed to approximate a given elevation event shifts dramatically across seasons, requiring constant manual recalibration. For users inside the Arctic circle, sunrise and sunset may not occur at all for weeks at a time, making the trigger completely useless for large parts of the year.
Automating things like outdoor lights, roller blinds, or morning routines based on the state of the sun is one of the most common use cases in Home Assistant, particularly among users just getting started. The current trigger sets them up with automations that silently degrade as seasons change. We believe it's time to address the shortcomings of the sun trigger and condition in Home Assistant.
Community signals
Scope & Boundaries
In scope
Not in scope
Foreseen solution
We want to add a fuller set of sun triggers and conditions, all based on the sun's actual elevation rather than fixed time offsets, so automations behave correctly year-round and at any latitude.
A few principles guide the list:
for. The threshold triggers and the elevation condition support aforduration, so you can require a state to hold for a period before acting.Phases vs. moments (dawn, dusk, and twilight)
These terms are easy to conflate, so to be clear about how they map here:
sun.is_morning_twilight/sun.is_evening_twilight, with atypeoption).sun.dawn/sun.dusk, with atypeoption). There is no phase called "civil dawn" or "civil dusk". The phase is civil twilight, and dawn and dusk are simply the names for its morning and evening edges. This is why dawn and dusk appear only as triggers and twilight only as a condition. For the same reason there are nosun.is_dawn/sun.is_duskconditions (nothing to test as a sustained state), and nosun.is_solar_noon/sun.is_solar_midnightconditions (those are instantaneous moments too).Higher priority
These cover the everyday cases: the position of the sun, and the named points around sunrise and sunset that most automations care about.
Triggers
sun.sunrisesun.sunsetsun.solar_noonsun.solar_midnightsun.elevation_crossed_thresholdsun.elevation_changedsun.dawntype:civil(-6°, default),nautical(-12°),astronomical(-18°).sun.dusktype:civil(-6°, default),nautical(-12°),astronomical(-18°).Conditions
sun.is_upsun.is_setsun.is_risingsun.is_descendingsun.elevationsun.is_nightsun.is_morning_twilighttype:any(-18° to -0.833°, default),civil(-6° to -0.833°),nautical(-12° to -6°),astronomical(-18° to -12°).sun.is_evening_twilighttype:any(-18° to -0.833°, default),civil(-6° to -0.833°),nautical(-12° to -6°),astronomical(-18° to -12°).Lower priority (add later)
These are more specialist: the golden and blue hours that photographers care about, and the midnight sun and polar night that matter at high latitudes.
Triggers
sun.golden_hour_startedany, fires at both crossings.period:any(default),morning,eveningsun.golden_hour_endedany, fires at both crossings.period:any(default),morning,eveningsun.blue_hour_startedany, fires at both crossings.period:any(default),morning,eveningsun.blue_hour_endedany, fires at both crossings.period:any(default),morning,eveningsun.midnight_sun_startedsun.midnight_sun_endedsun.polar_night_startedsun.polar_night_endedConditions
sun.is_golden_hourperiod:any(default),morning,eveningsun.is_blue_hourperiod:any(default),morning,eveningsun.is_midnight_sunsun.is_polar_nightRisks & open questions
Appetite
Small - We should be able to complete this in several days to a week.
Execution issues
No response