Humidifier
One humidifier.* entity, a dehumidifier included: on and off, a target humidity and its modes.
Quick example
Section titled “Quick example”import { useHaHumidifier } from "@dashhaus/core";
/** The room's humidity, the target, and a slider for it when the device takes one. */export function Humidity({ entityId }: { entityId: string }) { const { entity, actions } = useHaHumidifier(entityId); const { onTargetChange } = actions; return ( <fieldset disabled={entity.state === "unavailable"}> <legend> {entity.name} ({entity.kind ?? "humidifier"}): {entity.currentHumidity ?? "—"}% now </legend> <button type="button" aria-pressed={entity.state === "on"} onClick={actions.onToggle}> {entity.state === "on" ? "On" : "Off"} </button> {onTargetChange && ( <label> Target {entity.targetHumidity}% <input type="range" min={entity.minHumidity} max={entity.maxHumidity} value={entity.targetHumidity ?? entity.minHumidity} onChange={(event) => onTargetChange(event.currentTarget.valueAsNumber)} /> </label> )} </fieldset> );}kind is dehumidifier when Home Assistant’s device_class says so: it dries to its target instead of adding moisture.
Component
Section titled “Component”<HaHumidifier> is useHaHumidifier 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: HaHumidifierResult) => ReactNode- Draws the hook's result. The component itself draws nothing.
useHaHumidifier(entityId: string, options?: HaHumidifierOptions): HaHumidifierResultOne live humidifier for any UI: the mapped entity, today's history and its service actions.
It reads the device, its area and today’s history.
Options
Section titled “Options”name?string- Overrides Home Assistant's friendly name.
area?string- Overrides the area Home Assistant's registries resolve for the entity.
lastSeen?string- Overrides when the entity was last reachable, shown while it is unavailable.
history?HumidifierHistory- 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.
onActionError?(error: HaActionError) => void- Called with an HaActionError when an action is refused or fails.
Returns
Section titled “Returns”entityHumidifierEntityhistoryHumidifierHistoryactionsHumidifierHandlers
entity: HumidifierEntity
Section titled “entity: HumidifierEntity”entityIdstring- The Home Assistant entity id.
namestring- Its name: the `name` option, else Home Assistant's friendly name, else its entity id.
area?string- Where it is: "Bedroom".
state"unavailable" | "off" | "on"kind?"humidifier" | "dehumidifier"- HA `device_class`: a dehumidifier dries to its target. Default humidifier.
action?HumidifierAction- Absent when the device doesn't report it.
currentHumidity?number- Relative humidity in the room, 0-100.
targetHumidity?number- Target relative humidity, 0-100. Absent when the device has no setpoint.
minHumiditynumbermaxHumiditynumbermode?stringmodes?string[]- HA `available_modes`: "normal", "eco", "sleep", "boost"…
lastChanged?stringlastSeen?string- While it is unavailable, when it was last reachable: the `lastSeen` option, else what Home Assistant reports.
history: HumidifierHistory
Section titled “history: HumidifierHistory”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.
samplesHourSample[]- 1 for hours it was on, 0 off, "unavailable", null for hours ahead. Fractions for part of an hour.
currentHournumberonMinutesnumber- Minutes on today, including the current hour.
actions: HumidifierHandlers
Section titled “actions: HumidifierHandlers”onToggle() => void- Calls `humidifier.toggle`.
onTargetChange?(humidity: number) => void- Only for a device that reports a target. Calls `humidifier.set_humidity`, rounded to a whole percent; outside `minHumidity` to `maxHumidity` reports `invalid_input`.
onModeChange?(mode: string) => void- Only with modes. Calls `humidifier.set_mode`; a mode the device doesn't list reports `unsupported`.
Every action on an unavailable entity is reported to onActionError as unsupported and never sent.
Every humidifier
Section titled “Every humidifier”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 { HaHumidifier, useHaSelector } from "@dashhaus/core";import type { HaSnapshot } from "@dashhaus/core";
const humidifierIds = (snapshot: HaSnapshot) => Object.keys(snapshot.entities).filter((id) => id.startsWith("humidifier.")).sort().join(" ");
export function AllHumidifiers() { const ids = useHaSelector(humidifierIds).split(" ").filter(Boolean); return ( <ul> {ids.map((id) => ( <li key={id}> <HaHumidifier entityId={id} loadHistory={false}> {({ entity }) => ( <> {entity.name}: {entity.action ?? entity.state}, {entity.currentHumidity ?? "—"}% </> )} </HaHumidifier> </li> ))} </ul> );}Pick a mode
Section titled “Pick a mode”import { useHaHumidifier } from "@dashhaus/core";
/** The device's own modes (normal, eco, sleep, boost…), one button each. */export function Modes({ entityId }: { entityId: string }) { const { entity, actions } = useHaHumidifier(entityId, { loadHistory: false }); const { onModeChange } = actions; if (!onModeChange || !entity.modes) return null; return ( <div role="group" aria-label={`${entity.name} mode`}> {entity.modes.map((mode) => ( <button key={mode} type="button" aria-pressed={entity.mode === mode} onClick={() => onModeChange(mode)}> {mode} </button> ))} </div> );}modes is Home Assistant’s available_modes: normal, eco, sleep, boost, whatever the device has.
In a skin
Section titled “In a skin”Orb’s HaHumidifierTile and Field’s HaHumidifierModule are useHaHumidifier above each skin’s card. They take the hook’s
options as props, plus their own:
import { HaHumidifierTile } from "@dashhaus/orb";import { HaHumidifierModule } from "@dashhaus/field";
export function OrbHumidifier() { return <HaHumidifierTile entityId="humidifier.nursery" />;}
export function FieldHumidifier() { return <HaHumidifierModule entityId="humidifier.nursery" footprint="compact" />;}entityIdstring- The Home Assistant entity id.
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?booleandefaultAction?undefined
entityIdstring- The Home Assistant entity id.
footprint?FieldFootprintdefaultOpen?boolean- Open the detail panel on first render (stories).