The current solar phase logic in src/utils.ts only works with sunrise and sunset, and getTimeOfDayWithSunData() derives sunrise / day / sunset / night from fixed windows around those values.
This has two problems:
- it throws away richer solar event data available from
sun.sun
- it can incorrectly switch to
night because of the current > 12h adjustment heuristic when the next sunrise is tomorrow but less than 12 hours away
Current behavior
The current source priority should stay as-is:
- configured sunrise/sunset override entities
- weather entity attributes
sun.sun
- static fallback
The problem is that the data model only preserves sunrise and sunset, so even if sun.sun provides richer fields like:
next_dawn
next_noon
next_dusk
elevation
azimuth
that information is lost before phase calculation.
Proposed change
Extend SunMoonData
Add support for richer solar fields, for example:
dawn?: Date | null
noon?: Date | null
dusk?: Date | null
elevation?: number | null
azimuth?: number | null
while keeping:
sunrise: Date | null
sunset: Date | null
Keep current fallback order
Do not change the existing retrieval precedence. Only improve what happens once sun.sun is used as fallback.
Use richer sun.sun data when available
If sun.sun provides enough data, derive phases from a linear solar timeline instead of hardcoded sunrise ± 1h / sunset ± 1h windows.
Suggested mapping:
sunrise: dawn -> sunrise
day: sunrise -> sunset
sunset: sunset -> dusk
night: otherwise
If only partial data exists, fall back gracefully to sunrise/sunset logic, and finally to the static fallback.
Why
This would:
- preserve existing compatibility
- improve the
sun.sun fallback path
- avoid the current incorrect
night classification caused by the 12-hour heuristic
- make the phase calculation better match Home Assistant’s available solar state without requiring complex calculations
Relevant code
The current heuristic is here:
export function getTimeOfDayWithSunData(sunData: SunMoonData & { hasSunData: boolean }): TimeOfDay {
const now = new Date();
// If we have real sun data, use it
if (sunData.hasSunData && sunData.sunrise && sunData.sunset) {
const currentTime = now.getTime();
let sunriseTime = sunData.sunrise.getTime();
let sunsetTime = sunData.sunset.getTime();
// Check if sunrise/sunset are for tomorrow (common with Yandex Weather and similar integrations)
// If sunrise is more than 12 hours in the future, subtract 24 hours to get today's time
if (sunriseTime - currentTime > 12 * 60 * 60 * 1000) {
sunriseTime -= 24 * 60 * 60 * 1000;
}
if (sunsetTime - currentTime > 12 * 60 * 60 * 1000) {
sunsetTime -= 24 * 60 * 60 * 1000;
}
The current solar phase logic in
src/utils.tsonly works withsunriseandsunset, andgetTimeOfDayWithSunData()derivessunrise/day/sunset/nightfrom fixed windows around those values.This has two problems:
sun.sunnightbecause of the current> 12hadjustment heuristic when the next sunrise is tomorrow but less than 12 hours awayCurrent behavior
The current source priority should stay as-is:
sun.sunThe problem is that the data model only preserves
sunriseandsunset, so even ifsun.sunprovides richer fields like:next_dawnnext_noonnext_duskelevationazimuththat information is lost before phase calculation.
Proposed change
Extend
SunMoonDataAdd support for richer solar fields, for example:
dawn?: Date | nullnoon?: Date | nulldusk?: Date | nullelevation?: number | nullazimuth?: number | nullwhile keeping:
sunrise: Date | nullsunset: Date | nullKeep current fallback order
Do not change the existing retrieval precedence. Only improve what happens once
sun.sunis used as fallback.Use richer
sun.sundata when availableIf
sun.sunprovides enough data, derive phases from a linear solar timeline instead of hardcodedsunrise ± 1h/sunset ± 1hwindows.Suggested mapping:
sunrise:dawn -> sunriseday:sunrise -> sunsetsunset:sunset -> dusknight: otherwiseIf only partial data exists, fall back gracefully to sunrise/sunset logic, and finally to the static fallback.
Why
This would:
sun.sunfallback pathnightclassification caused by the 12-hour heuristicRelevant code
The current heuristic is here: