Skip to content

Weather

The home’s outdoor conditions from one weather.* entity, with an air-quality sensor, sun.sun for day and night, and the hourly and daily forecasts. Read-only.

import { useHaWeather } from "@dashhaus/core";
/** The conditions now, with an air-quality sensor beside them and sun.sun for day and night. */
export function Outside() {
const { entity } = useHaWeather("weather.home", {
aqiEntityId: "sensor.home_aqi",
aqiScale: "US",
sunEntityId: "sun.sun",
loadForecasts: false,
});
if (entity.state === "unavailable") return <p>No weather right now.</p>;
return (
<p>
{entity.state}, {entity.temperature}
{entity.temperatureUnit}
{entity.isDay === false && " tonight"}
{entity.aqi != null && `, AQI ${entity.aqi}`}
</p>
);
}

aqi is only read with aqiScale: "US" and a sensor whose device_class is aqi: the hook won’t band a figure on a scale it can’t name. isDay comes from the sun entity you give; without one it stays unknown rather than guessing day.

<HaWeather> is useHaWeather 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: HaWeatherResult) => ReactNode
Draws the hook's result. The component itself draws nothing.
useHaWeather(entityId: string, options?: HaWeatherOptions): HaWeatherResult

One live weather entity for any UI: its conditions with AQI and sun companions, today's history and the forecasts.

It reads the weather entity, its companions, today’s temperature history, and the forecasts through weather.get_forecasts.

aqiEntityId?string
aqiScale?"US"
Explicit host-owned assertion that the companion uses the US AQI scale.
sunEntityId?string
name?string
Overrides Home Assistant's friendly name.
lastSeen?string
Overrides when the entity was last reachable, shown while it is unavailable.
temperatureUnit?"°C" | "°F"
windSpeedUnit?"km/h" | "mph" | "m/s"
pressureUnit?"hPa" | "kPa" | "inHg"
hourly?HourlyForecast[]
daily?DailyForecast[]
history?WeatherHistory
Host-owned history override; when omitted, today's history is read from Home Assistant.
loadHistory?boolean
Set false to skip the Home Assistant history read.
loadForecasts?boolean
Set false when forecasts are supplied by another application-owned query.
onForecastError?(error: unknown) => void
entityWeatherEntity
historyWeatherHistory
hourly?HourlyForecast[]
Undefined until the first forecast read settles.
daily?DailyForecast[]

hourly and daily are undefined until the first forecast read settles. They are read once an hour, and the previous hour’s forecast stays up while the next loads. Pass loadForecasts={false} when another part of your app reads them.

entityIdstring
The Home Assistant entity id.
namestring
Usually the home's name.
state"unavailable" | Condition
temperature?number
apparentTemperature?number
dewPoint?number
humidity?number
Relative humidity, percent.
pressure?number
windSpeed?number
windGustSpeed?number
windBearing?number
Degrees the wind comes from, 0 = north.
uvIndex?number
temperatureUnit"°C" | "°F"
windSpeedUnit"km/h" | "mph" | "m/s"
pressureUnit"hPa" | "kPa" | "inHg"
aqi?number
US AQI, 0-500, from an air-quality sensor.
isDay?boolean
From sun.sun; omitted or unavailable means daylight is unknown, not day.
lastUpdated?string
lastSeen?string
While it is unavailable, when it was last reachable: the `lastSeen` option, else what Home Assistant reports.

Today, from Home Assistant’s recorder, kept up to date by every change since. Pass history to supply your own, or loadHistory={false} to skip the read.

temperature(number | "unavailable" | null)[]
Today's hourly temperatures so far: a value, "unavailable", or null for hours not recorded.
currentHournumber

One hour of hourly.

hournumber
Hour of the day, 0-23 (today), 24+ for tomorrow.
temperaturenumber
conditionCondition
precipitationProbability?number
Percent.

One day of daily.

daystring
Short day label, e.g. "Sun".
conditionCondition
highnumber
lownumber
precipitationProbability?number

Hooks can’t be called in a loop, so a list renders one headless component per entity. The selector returns a string: useHaSelector re-renders only when its value changes, and a string of ids changes only when an entity comes or goes. Lists skip each item’s history read with loadHistory={false}.

import { HaWeather, useHaSelector } from "@dashhaus/core";
import type { HaSnapshot } from "@dashhaus/core";
const weatherIds = (snapshot: HaSnapshot) =>
Object.keys(snapshot.entities).filter((id) => id.startsWith("weather.")).sort().join(" ");
/** Every weather entity, conditions only: each one's forecast is a read of its own, so leave it out of a list. */
export function AllWeather() {
const ids = useHaSelector(weatherIds).split(" ").filter(Boolean);
return (
<ul>
{ids.map((id) => (
<li key={id}>
<HaWeather entityId={id} loadForecasts={false} loadHistory={false}>
{({ entity }) => (
<>
{entity.name}: {entity.state}, {entity.temperature ?? "—"}
{entity.temperatureUnit}
</>
)}
</HaWeather>
</li>
))}
</ul>
);
}
import { useHaWeather } from "@dashhaus/core";
/** The next days, read through weather.get_forecasts once an hour; undefined until the first read settles. */
export function Forecast({ entityId }: { entityId: string }) {
const { entity, daily } = useHaWeather(entityId, { loadHistory: false });
if (daily === undefined) return <p>Loading the forecast…</p>;
return (
<ol aria-label={`${entity.name} forecast`}>
{daily.slice(0, 5).map((day) => (
<li key={day.day}>
{day.day}: {day.condition}, {day.low}–{day.high}
{entity.temperatureUnit}
{day.precipitationProbability != null && `, ${day.precipitationProbability}% rain`}
</li>
))}
</ol>
);
}

A failed forecast read goes to onForecastError, never to the action errors: it’s a read, not something you did.

Orb’s HaWeatherTile and Field’s HaWeatherModule are useHaWeather above each skin’s card. They take the hook’s options as props, plus their own:

import { HaWeatherTile } from "@dashhaus/orb";
import { HaWeatherModule } from "@dashhaus/field";
export function OrbWeather() {
return <HaWeatherTile entityId="weather.home" aqiEntityId="sensor.home_aqi" aqiScale="US" sunEntityId="sun.sun" />;
}
export function FieldWeather() {
return <HaWeatherModule entityId="weather.home" sunEntityId="sun.sun" />;
}
entityIdstring
The Home Assistant entity id.
showControl?boolean
Compact only. false removes the inline reading, shows its value in its place, and makes the row open the detail sheet. 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.