Skip to content

Improve sun-based triggers and conditions #96

Description

@nielsrowinbik

✅ 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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions