Skip to content

Binary sensor

One binary_sensor.* entity, with the battery sensor on its device: a door or a window open or closed, a leak sensor wet or dry, a smoke, gas or carbon monoxide detector clear or not, and when it last changed. Read-only.

import { useHaBinarySensor } from "@dashhaus/core";
import { stateWord } from "@dashhaus/core/entities/binarySensor/words";
/** A door in its own words: Open or Closed, since when, and its battery. */
export function PatioDoor() {
const { entity } = useHaBinarySensor("binary_sensor.patio_door", { batteryEntityId: "sensor.patio_door_battery", loadHistory: false });
if (entity.state === "unavailable") return <p>{entity.name} is unavailable</p>;
return (
<p>
{entity.name}: {stateWord(entity)}
{entity.lastChanged ? ` since ${entity.lastChanged}` : ""}
{entity.battery != null ? ` · battery ${entity.battery}%` : ""}
</p>
);
}

Home Assistant reports every binary sensor as on or off; its device_class says what that means. stateWord says it in the class’s words: a door on is Open, a leak sensor’s Wet, a smoke detector’s Smoke. A sensor Home Assistant can’t reach is unavailable, never a safe-looking Closed or Clear.

<HaBinarySensor> is useHaBinarySensor 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: HaBinarySensorResult) => ReactNode
Draws the hook's result. The component itself draws nothing.
useHaBinarySensor(entityId: string, options?: HaBinarySensorOptions): HaBinarySensorResult

One live, read-only binary sensor for any UI (a door, a window, a leak, smoke): the mapped entity composed with its device's battery, and today's on/off history (how long it was open, wet or detecting). It sends no services.

It reads the sensor, its area, given batteryEntityId the battery sensor on the same device, and today’s history of when it was on.

batteryEntityId?string
Optional companion on the same device, `device_class: battery` (the automatic layout finds it).
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?BinarySensorHistory
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.
entityBinarySensorEntity
historyBinarySensorHistory
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: "Kitchen".
state"unavailable" | "on" | "off"
deviceClass?BinarySensorClass
What on and off mean (HA `device_class`); none is a plain on/off.
lastChanged?string
When it last changed state (HA `last_changed`), formatted.
changedAt?number
When the current state started, in ms since the epoch (HA `last_changed`): an alarm's start, for its timing.
battery?number
The same device's battery, 0–100, where it has one.
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: the share of each hour it was on, and the minutes that adds up to. Pass history to supply your own, or loadHistory={false} to skip the read.

samplesHourSample[]
1 for hours it was on (open, wet, detected), 0 off, "unavailable", null for hours ahead. Fractions for part of an hour.
currentHournumber
onMinutesnumber
Minutes on today, including the current hour.

binarySensorSeverity ranks what a sensor’s state may claim, the same in every skin: smoke, gas and carbon monoxide are an alarm, a leak urgent, a garage door left open and a low battery advisory. alertText says the warning in a few words (Smoke alarm, Open since 18:30), and alertSentence says it whole for a screen reader. An open door is a state, not a warning, however long it lasts.

import { HaBinarySensor, useHaSelector } from "@dashhaus/core";
import type { HaSnapshot } from "@dashhaus/core";
import { alertText } from "@dashhaus/core/entities/binarySensor/words";
import { binarySensorSeverity } from "@dashhaus/core/entities/binarySensor/severity";
const sensorIds = (snapshot: HaSnapshot) =>
Object.keys(snapshot.entities).filter((id) => id.startsWith("binary_sensor.")).sort().join(" ");
/**
* Every binary sensor that needs looking at, most urgent first in your own markup: smoke, gas and carbon monoxide are
* an alarm, a leak urgent, a garage door left open and a low battery advisory. An open door is a state, so it never lists.
*/
export function Warnings() {
const ids = useHaSelector(sensorIds).split(" ").filter(Boolean);
return (
<ul>
{ids.map((id) => (
<HaBinarySensor key={id} entityId={id} loadHistory={false}>
{({ entity }) => {
const severity = binarySensorSeverity(entity);
if (!severity) return null;
return <li data-severity={severity}>{entity.name}: {alertText(entity) ?? `battery ${entity.battery}%`}</li>;
}}
</HaBinarySensor>
))}
</ul>
);
}

Orb’s HaBinarySensorTile and Field’s HaBinarySensorModule are useHaBinarySensor above each skin’s card. Each draws the picture its device class names and says the state in its words. Smoke sounds the card’s alarm (Orb fills its slot, Field inverts its screen), and a leak or a garage door left open is marked as a warning, never a glow. They take the hook’s options as props, plus their own:

import { HaBinarySensorTile } from "@dashhaus/orb";
import { HaBinarySensorModule } from "@dashhaus/field";
/** The patio door, with the battery sensor on its device. */
export function OrbDoor() {
return <HaBinarySensorTile entityId="binary_sensor.patio_door" batteryEntityId="sensor.patio_door_battery" />;
}
/** A leak sensor under the sink as a compact row: Wet is urgent, an inverted block and the alert line. */
export function FieldLeak() {
return <HaBinarySensorModule entityId="binary_sensor.kitchen_leak" 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?boolean
defaultAction?undefined

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