Sensor
A room’s reading: a temperature or humidity sensor.*, read with the humidity and battery sensors on the same device. Read-only.
Quick example
Section titled “Quick example”import { useHaSensor } from "@dashhaus/core";import { fmt1 } from "@dashhaus/core/entities";
/** A room's temperature, with the humidity and battery sensors on the same device. */export function RoomReading() { const { entity } = useHaSensor("sensor.bedroom_temperature", { humidityEntityId: "sensor.bedroom_humidity", batteryEntityId: "sensor.bedroom_battery", }); if (entity.state === "unavailable") return <p>{entity.name}: no reading</p>; return ( <p> {entity.name}: {entity.temperature == null ? "—" : `${fmt1(entity.temperature)}${entity.unit}`} {entity.humidity != null && `, ${fmt1(entity.humidity)}% humidity`} {entity.battery != null && entity.battery < 20 && " (battery low)"} </p> );}Home Assistant gives each measurement its own entity. The hook reads the companions you name and puts them on one SensorEntity, so a card shows the room, not three sensors.
Component
Section titled “Component”<HaSensor> is useHaSensor 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: HaSensorResult) => ReactNode- Draws the hook's result. The component itself draws nothing.
useHaSensor(entityId: string, options?: HaSensorOptions): HaSensorResultOne live, read-only sensor for any UI: the primary sensor composed with its humidity and battery companions.
It reads the sensor and its companions, its area, and today’s history of the temperature and the humidity companion. outdoor marks a sensor outside, where indoor comfort words don’t apply.
Options
Section titled “Options”humidityEntityId?string- Optional companion entity with `device_class: humidity`.
batteryEntityId?string- Optional companion entity with `device_class: battery`.
name?string- Overrides Home Assistant's friendly name.
area?string- Overrides the area Home Assistant's registries resolve for the entity.
outdoor?booleanlastSeen?string- Overrides when the entity was last reachable, shown while it is unavailable.
unit?"°C" | "°F"history?SensorHistory- 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.
Returns
Section titled “Returns”entitySensorEntityhistorySensorHistory
entity: SensorEntity
Section titled “entity: SensorEntity”entityIdstring- The Home Assistant entity id.
namestring- Usually the room it measures.
area?string- Its area: the `area` option, else the one Home Assistant's registries resolve; none when neither has one.
state"unavailable" | "ok"temperature?numberhumidity?number- Relative humidity in percent. Omit for temperature-only sensors.
unit"°C" | "°F"outdoor?boolean- Outdoor sensors skip the indoor comfort reading.
battery?number- Battery level in percent, for battery-powered sensors.
lastUpdated?stringlastSeen?string- While it is unavailable, when it was last reachable: the `lastSeen` option, else what Home Assistant reports.
history: SensorHistory
Section titled “history: SensorHistory”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.
temperatureReading[]- Hourly readings for today: a value, "unavailable", or null for hours still ahead.
humidity?Reading[]currentHournumber
Every temperature
Section titled “Every temperature”A sensor’s domain doesn’t say what it measures, so the selector reads each one’s device_class.
import { HaSensor, useHaSelector } from "@dashhaus/core";import type { HaSnapshot } from "@dashhaus/core";import { fmt1 } from "@dashhaus/core/entities";
/** Every temperature sensor: a sensor's domain says nothing of what it measures, so read its device class. */const temperatureIds = (snapshot: HaSnapshot) => Object.values(snapshot.entities) .filter((entity) => entity.entity_id.startsWith("sensor.") && entity.attributes.device_class === "temperature") .map((entity) => entity.entity_id) .sort() .join(" ");
export function AllTemperatures() { const ids = useHaSelector(temperatureIds).split(" ").filter(Boolean); return ( <ul> {ids.map((id) => ( <li key={id}> <HaSensor entityId={id} loadHistory={false}> {({ entity }) => ( <> {entity.name}: {entity.temperature == null ? "—" : `${fmt1(entity.temperature)}${entity.unit}`} </> )} </HaSensor> </li> ))} </ul> );}Today’s high and low
Section titled “Today’s high and low”import { useHaSensor } from "@dashhaus/core";import { fmt1 } from "@dashhaus/core/entities";
/** Today's high and low so far, from the hourly readings the hook reads from Home Assistant's recorder. */export function HighLow({ entityId }: { entityId: string }) { const { entity, history } = useHaSensor(entityId); const readings = history.temperature.filter((reading): reading is number => typeof reading === "number"); if (readings.length === 0) return <p>{entity.name}: no readings yet today</p>; return ( <p> {entity.name} today: {fmt1(Math.min(...readings))} to {fmt1(Math.max(...readings))} {entity.unit} </p> );}history.temperature has one reading per hour: a number, "unavailable", or null for hours ahead and before the first reading.
In a skin
Section titled “In a skin”Orb’s HaSensorTile and Field’s HaSensorModule are useHaSensor above each skin’s card. They take the hook’s
options as props, plus their own:
import { HaSensorTile } from "@dashhaus/orb";import { HaSensorModule } from "@dashhaus/field";
export function OrbRoom() { return <HaSensorTile entityId="sensor.living_room_temperature" humidityEntityId="sensor.living_room_humidity" />;}
export function FieldOutside() { return <HaSensorModule entityId="sensor.outside_temperature" outdoor footprint="compact" />;}entityIdstring- Primary sensor, normally the temperature entity for this device.
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?booleandefaultAction?undefined
entityIdstring- Primary sensor, normally the temperature entity for this device.
footprint?FieldFootprintdefaultOpen?boolean- Open the detail panel on first render (stories).