Skip to content

Sun

Home Assistant’s sun.sun, from its Sun integration: whether the sun is up, and when it next sets, rises, dawns, dusks and peaks. With your home’s location, today’s path of the sun too. Read-only.

import { useHaSun } from "@dashhaus/core";
import { useHourCycle } from "@dashhaus/core/hooks";
import { sunAllDay, sunNext, sunTime, sunWhen } from "@dashhaus/core/entities/sun/words";
/** When the sun next sets or rises, on the page's clock, and how long until it. */
export function NextSunEvent() {
const { entity } = useHaSun("sun.sun");
const hourCycle = useHourCycle();
if (entity.state === "unavailable") return <p>{entity.name} is unavailable</p>;
const next = sunNext(entity);
if (!next) return <p>{sunAllDay(entity) ?? "Waiting…"}</p>;
return <p>{sunTime(next, hourCycle)}: {sunWhen(next, entity.now)}</p>;
}

sunNext is what a card leads with: the sunset while the sun is up, the sunrise while it is down. sunWhen counts down to it from the entity’s own minute: Sets in 4h 35m, Rises in 9m, or its day when it is more than a day off (Rises Thu). Where neither comes within two days, as in a polar summer or winter, sunAllDay says Up all day or Down all day. Times are on the page’s clock: 20:30, or on a 12-hour page 8:30 PM (pass sunTime the page’s useHourCycle()). Every skin says it in these words.

<HaSun> is useHaSun as a component that draws nothing of its own. It takes every option of the hook as a prop, and hands the hook’s result to its child function. Use it where hooks can’t go, such as one per item of a list.

entityIdstring
The Home Assistant entity id.
children(live: HaSunResult) => ReactNode
Draws the hook's result. The component itself draws nothing.
useHaSun(entityId: string, options?: HaSunOptions): HaSunResult

The sun for any UI: the mapped `sun.*` entity, counted from the minute clock, and today's path, worked out from the home's latitude and longitude (Home Assistant's `get_config`, read once per connection, or the options). It sends no services.

It reads the sun and counts from a clock that turns each minute. Today’s path is worked out from your home’s latitude and longitude, read once from Home Assistant’s configuration; pass latitude and longitude to draw it for another place, or loadHistory: false to leave it out.

name?string
Overrides Home Assistant's friendly name.
area?string
Overrides the area Home Assistant's registries resolve.
lastSeen?string
Overrides when the entity was last reachable, shown while it is unavailable.
latitude?number
Where today's path is drawn from, in degrees; by default Home Assistant's own location (`get_config`).
longitude?number
loadHistory?boolean
Set false to leave out today's path (YAML `history: false`): `history` is then undefined.
entitySunEntity
historySunHistory | undefined
Today's path of the sun, worked out from the location: no recorder read. Undefined without a location, or with `loadHistory: false`.
entityIdstring
namestring
The entity's name: "Sun".
area?string
Its area: the `area` option, else the one Home Assistant's registries resolve; the sun usually has none.
state"unavailable" | "ok"
"unavailable" while it can't be read (`unknown`, `unavailable`, missing); "ok" otherwise.
up?boolean
Above the horizon (`above_horizon`); omitted while it isn't known. Its active set (`isActive`).
nextRising?number
When it next rises and sets (`next_rising`, `next_setting`); omitted until Home Assistant reports them.
nextSetting?number
nextDawn?number
When civil twilight next begins and ends (`next_dawn`, `next_dusk`), and the sun next peaks (`next_noon`).
nextDusk?number
nextNoon?number
elevation?number
Its height above the horizon, in degrees (`elevation`): below zero at night.
azimuth?number
Its compass bearing, in degrees from north (`azimuth`).
nownumber
The minute the card counts from, in ms since the epoch: the hook's minute clock, or a seed's fixed minute. "Sets in 4h 35m" and where the sun is drawn on today's path are counted from it.
lastUpdated?string
When Home Assistant last updated it ("11:54").
lastSeen?string
While it is unavailable, when it was last reachable.

Today’s path of the sun from midnight to midnight, worked out from the location rather than read from Home Assistant’s recorder: its elevation through the day, each hour’s height against the day’s peak, where now, sunrise and sunset fall, and how long it is up.

pathnumber[]
The sun's elevation in degrees, `SUN_PATH_STEPS + 1` points evenly spaced over the local day.
samplesHourSample[]
Per hour, 0 to 1: the sun's highest elevation in that hour against the day's peak; 0 while it is down.
currentHournumber
nowAtnumber
Where now falls in the day, 0 to 1.
riseAt?number
Where today's sunrise and sunset fall in the day, 0 to 1; omitted on a day it doesn't rise or set.
setAt?number
rise?number
When today's sunrise and sunset are, in ms since the epoch, from the path; omitted with `riseAt` and `setAt`.
set?number
peaknumber
Today's highest elevation, in degrees.
daylightMinutesnumber
Minutes the sun is up today.

sunPathDrawing turns the path into pieces of line for any drawing: the day so far, the day still to come and the night, the horizon and where the sun is now, all as fractions of the drawing.

import { useHaSun } from "@dashhaus/core";
import { sunPathDrawing } from "@dashhaus/core/entities/sun/drawing";
import { daylightSummary } from "@dashhaus/core/entities/sun/words";
/** Today's path of the sun as a line, the day so far solid and the rest dotted, with the sun on it. */
export function SunPath() {
const { history } = useHaSun("sun.sun");
if (!history) return null;
const drawing = sunPathDrawing(history);
const [x, y] = drawing.sun;
return (
<figure>
<svg viewBox="0 0 1 1" preserveAspectRatio="none" width={240} height={80}>
{drawing.pieces.map((piece, i) => (
<polyline
key={i}
points={piece.points.map(([px, py]) => `${px},${py}`).join(" ")}
fill="none"
stroke="currentColor"
strokeWidth={piece.part === "past" ? 2 : 1}
strokeDasharray={piece.part === "past" ? undefined : "2 3"}
vectorEffect="non-scaling-stroke"
/>
))}
<circle cx={x} cy={y} r={0.02} fill="currentColor" />
</svg>
<figcaption>{daylightSummary(history)}</figcaption>
</figure>
);
}

Orb’s HaSunTile and Field’s HaSunModule are useHaSun above each skin’s card. Each leads with what comes next and counts down to it, draws today’s path (Orb’s as a line with the sun on it, Field’s as the sun’s height by hour), and opens on every time to come. They take the hook’s options as props, plus their own:

import { HaSunTile } from "@dashhaus/orb";
import { HaSunModule } from "@dashhaus/field";
/** The sun with today's path, from Home Assistant's own location. */
export function OrbSun() {
return <HaSunTile entityId="sun.sun" footprint="featured" />;
}
/** The same as a compact row: the countdown on the row's line, the time on the screen. */
export function FieldSun() {
return <HaSunModule entityId="sun.sun" footprint="compact" />;
}
entityIdstring
showControl?boolean
Compact only. false removes the inline control, shows the value in its place, and makes the row open the details. Default true.
footprint?CardFootprint
Card footprint. The skin's stylesheet sets the heights; the three names are the shared vocabulary.
defaultOpen?boolean
defaultAction?undefined

Every state of both is in Storybook: Orb and Field.