Areas, history and requests
These reads go through Home Assistant’s websocket commands, not the entity subscription. Each is shared by every
component asking for the same thing, run again after a reconnect, and never answered with a result from an older
connection. A transport without generic commands (sendMessage), such as a minimal test transport, makes them read
as undefined rather than fail.
useHaAreas returns every area with the entity ids that belong to it: an entity’s own area, or else its device’s.
Areas come in the registry’s order, and an area with no entities is still there, with an empty list. It is
undefined while the registries load.
import { HaLight, useHaAreas } from "@dashhaus/core";
/** The house by area, from Home Assistant's registries: each area's lights, under its name. */export function LightsByArea() { const areas = useHaAreas(); if (!areas) return <p>Reading the areas…</p>; return ( <> {areas.map(({ area, entityIds }) => { const lights = entityIds.filter((id) => id.startsWith("light.")); if (lights.length === 0) return null; return ( <section key={area.id} aria-label={area.name}> <h2>{area.name}</h2> {lights.map((id) => ( <HaLight key={id} entityId={id} loadHistory={false}> {({ entity, actions }) => ( <button type="button" aria-pressed={entity.state === "on"} onClick={actions.onToggle}> {entity.name} </button> )} </HaLight> ))} </section> ); })} </> );}areaHaAreaRegistryEntry- The area, as Home Assistant's area registry has it.
entityIdsreadonly string[]- The entities in it: their own area, else their device's.
useHaArea(entityId) is one entity’s area name, which every entity hook already reads for its area.
useHaRegistry() is all of it, typed: areas, floors, devices, entities and the membership map.
areasreadonly HaAreaRegistryEntry[]floorsreadonly HaFloorRegistryEntry[]devicesreadonly HaDeviceRegistryEntry[]entitiesReadonlyMap<string, HaEntityRegistryEntry>membershipReadonlyMap<string, string>- Every entity's area id: its own, else its device's. Unknown areas remain, by id.
The registries are read once per connection and shared by every caller; an entity changing state never reads them again.
Today’s history, raw
Section titled “Today’s history, raw”The entity hooks parse their history into hourly samples. For anything else, useHaHistory returns today’s raw state
changes: what the recorder holds since midnight, then every change seen live since that read. It is read again on a
new day and after a reconnect. Pass the page’s clock (useNow), so the day turns over with it.
import { useHaHistory } from "@dashhaus/core";import { useNow } from "@dashhaus/core/hooks";
/** Today's raw state changes for any entity: the recorder's day, extended by every live change since. */export function DoorLog({ entityId }: { entityId: string }) { const now = useNow(); const records = useHaHistory([entityId], true, now); if (!records) return null; const openings = records.filter((record) => record.state === "on"); return ( <ol aria-label="Opened today"> {openings.map((record) => ( <li key={record.changed.getTime()}>{record.changed.toLocaleTimeString([], { timeStyle: "short" })}</li> ))} </ol> );}entityIdstring- The Home Assistant entity id the change is for.
statestringchangedDateattributesRecord<string, unknown>
Any other read
Section titled “Any other read”useHaRequest(key, fetch, options) runs one read through the store while connected. Callers with the same key share
it; a new connection runs it again; undefined as the key skips it. cache: true keeps a successful answer for the
rest of the connection; keepPrevious: true keeps showing the last key’s value while a new key loads.
import { useHaRequest } from "@dashhaus/core";
interface CoreConfig { location_name: string; version: string;}
/** * Any other read: one websocket command, shared by every caller with the same key, run again on each reconnect * and never left over from an older connection. `cache` keeps the answer for the rest of the connection. */export function AboutHome() { const { value, error } = useHaRequest( "core-config", (store) => store.callApi("get_config") as Promise<CoreConfig>, { cache: true }, ); if (error) return <p>Couldn't read Home Assistant's configuration.</p>; if (!value) return null; return ( <p> {value.location_name}, Home Assistant {value.version} </p> );}value?Terror?unknown
cache?boolean- Keep a successful result for the rest of the connection generation (registries). Default: share in-flight requests only.
keepPrevious?boolean- Keep showing the previous key's value while the next key loads (an hourly forecast refresh).
A failed read sets error and never touches the store’s lastActionError: that is for things you did.