Vacuum
One vacuum.* entity, a robot vacuum: whether it is cleaning, docked, on its way back, paused, idle or stopped with an
error; its battery and fan speed, which it reports itself; and what it can do, from what it declares to Home
Assistant.
Quick example
Section titled “Quick example”import { useHaVacuum } from "@dashhaus/core";import { pressWord, vacuumPress, vacuumWord } from "@dashhaus/core/entities/vacuum/words";
/** * One button that does what the vacuum can do now: pause it while it moves, start or resume it while it stands. What it * can do comes from what it declares to Home Assistant, so a vacuum that can't pause is sent home instead. */export function RobotVacuum({ entityId }: { entityId: string }) { const { entity, actions } = useHaVacuum(entityId, { loadHistory: false }); const press = vacuumPress(entity); const run = { start: actions.onStart, pause: actions.onPause, return: actions.onReturnToBase };
return ( <p> {entity.name}: {vacuumWord(entity)} {entity.battery != null && `, battery ${entity.battery}%`} {press && <button type="button" onClick={run[press]}>{pressWord(press, entity)}</button>} </p> );}Integrations name the same activity differently: one says charging where Home Assistant says docked, another
returning_home or stopped. They are mapped onto Home Assistant’s own, a kind of cleaning named its own way
(spot_cleaning, mopping) is cleaning, and any other state is said in its own words, Emptying the bin, never
guessed. An error is a warning; so is a low battery while it stands away from its dock, not cleaning, not on its way home and not charging.
Component
Section titled “Component”<HaVacuum> is useHaVacuum 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: HaVacuumResult) => ReactNode- Draws the hook's result. The component itself draws nothing.
useHaVacuum(entityId: string, options?: HaVacuumOptions): HaVacuumResultOne live robot vacuum for any UI: the mapped entity (its battery is its own attribute, not a companion), today's cleaning, and its service actions.
It reads the vacuum, its area and today’s cleaning. The battery is the vacuum’s own, so there is no companion to pass.
Options
Section titled “Options”name?stringarea?string- Overrides the area Home Assistant's registries resolve.
lastSeen?stringhistory?VacuumHistory- 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
Returns
Section titled “Returns”entityVacuumEntityhistoryVacuumHistoryactionsVacuumHandlers
entity: VacuumEntity
Section titled “entity: VacuumEntity”Each supports… flag comes from what the vacuum declares to Home Assistant. Its battery, status and fan speed are known
only while it is available.
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 lives: "Hall".
stateVacuumStatestateText?string- An `other` state in words, as the integration names it: `zone_cleaning` → "Zone cleaning".
status?string- HA `status`: the integration's own words for what it is doing ("Charging", "Cleaning the kitchen"), where it says.
error?string- While it is in error, why, where the integration says (HA `error`): "Brush jammed".
battery?number- Its battery, 0–100 (HA `battery_level`, an attribute of the vacuum itself).
charging?boolean- It is charging, where HA's state, `battery_icon` or `status` says so. A charging or docked vacuum never warns of its battery.
supportsStart?boolean- It starts or resumes cleaning (`VacuumEntityFeature.START`).
supportsPause?boolean- It pauses (`VacuumEntityFeature.PAUSE`).
supportsReturn?boolean- It goes back to its dock on request (`VacuumEntityFeature.RETURN_HOME`).
supportsLocate?boolean- It plays a sound to be found (`VacuumEntityFeature.LOCATE`).
supportsFanSpeed?boolean- It takes a fan speed (`VacuumEntityFeature.FAN_SPEED`) and lists at least one.
fanSpeeds?string[]- Its fan speeds, as Home Assistant names them ("quiet", "turbo").
fanSpeed?string- The fan speed it runs at.
lastChanged?string- When it last changed state (HA `last_changed`), formatted.
changedAt?number- The same, in ms since the epoch.
lastSeen?string- While it is unavailable, when it was last reachable: the `lastSeen` option, else what Home Assistant reports.
history: VacuumHistory
Section titled “history: VacuumHistory”Today, from Home Assistant’s recorder, kept up to date by every change since: the hours it was cleaning. Pass history
to supply your own, or loadHistory={false} to skip the read.
samplesHourSample[]- 1 for hours it was cleaning, 0 for hours it wasn't, "unavailable", null for hours ahead. Fractions for part of an hour.
currentHournumbercleaningMinutesnumber- Minutes cleaning today, including the current hour.
actions: VacuumHandlers
Section titled “actions: VacuumHandlers”onStart() => void- Calls `vacuum.start`: it starts cleaning, or resumes after a pause. A vacuum without `START` reports `unsupported`.
onPause() => void- Calls `vacuum.pause`, where it stops in place. A vacuum without `PAUSE` reports `unsupported`.
onReturnToBase() => void- Calls `vacuum.return_to_base`. A vacuum without `RETURN_HOME` reports `unsupported`.
onLocate() => void- Calls `vacuum.locate`: it plays a sound to be found. A vacuum without `LOCATE` reports `unsupported`.
onFanSpeedChange(speed: string) => void- Calls `vacuum.set_fan_speed`. A vacuum without fan speeds reports `unsupported`; a speed it doesn't list reports `invalid_input`.
An action the vacuum doesn’t declare, or any action while it is unavailable, is reported to onActionError as
unsupported and never sent; a fan speed it doesn’t list is reported as invalid_input.
Every vacuum
Section titled “Every vacuum”Hooks can’t be called in a loop, so a list renders one headless component per entity. Lists skip each item’s history
read with loadHistory={false}.
import { HaVacuum, useHaSelector } from "@dashhaus/core";import type { HaSnapshot } from "@dashhaus/core";import { vacuumWarning, vacuumWord } from "@dashhaus/core/entities/vacuum/words";
const vacuumIds = (snapshot: HaSnapshot) => Object.keys(snapshot.entities).filter((id) => id.startsWith("vacuum.")).sort().join(" ");
/** Every robot vacuum in the house, what it is doing, and its warning: an error, or a low battery away from its dock. */export function AllVacuums() { const ids = useHaSelector(vacuumIds).split(" ").filter(Boolean); return ( <ul> {ids.map((id) => ( <li key={id}> <HaVacuum entityId={id} loadHistory={false}> {({ entity }) => ( <> {entity.name}: {vacuumWord(entity)} {vacuumWarning(entity) ? ` (${vacuumWarning(entity)})` : ""} </> )} </HaVacuum> </li> ))} </ul> );}Its fan speed
Section titled “Its fan speed”import { useHaVacuum } from "@dashhaus/core";import { fanSpeedLabel } from "@dashhaus/core/entities/vacuum/words";
/** Its fan speeds, the running one pressed: only where the vacuum declares them, in their own words. */export function VacuumFanSpeed({ entityId }: { entityId: string }) { const { entity, actions } = useHaVacuum(entityId, { loadHistory: false }); if (!entity.supportsFanSpeed || !entity.fanSpeeds) return null; return ( <div role="group" aria-label={`${entity.name} fan speed`}> {entity.fanSpeeds.map((speed) => ( <button key={speed} type="button" aria-pressed={speed === entity.fanSpeed} onClick={() => actions.onFanSpeedChange(speed)}> {fanSpeedLabel(speed)} </button> ))} </div> );}fanSpeeds is Home Assistant’s fan_speed_list, in the integration’s own words: quiet, standard, turbo, max_plus.
In a skin
Section titled “In a skin”Orb’s HaVacuumTile and Field’s HaVacuumModule are useHaVacuum above each skin’s card. One press pauses it while it
moves and starts it while it stands; returning to its dock, locating it and its fan speeds are in its details. An error
is marked as a warning, never a glow. They take the hook’s options as props, plus their own:
import { HaVacuumTile } from "@dashhaus/orb";import { HaVacuumModule } from "@dashhaus/field";
export function OrbVacuum() { return <HaVacuumTile entityId="vacuum.robot_vacuum" />;}
/** A row for a phone's column: the first key, the name, and the screen. */export function FieldVacuum() { return <HaVacuumModule entityId="vacuum.upstairs_vacuum" footprint="compact" />;}entityIdstringshowControl?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
entityIdstringfootprint?FieldFootprintdefaultOpen?boolean- Open the detail panel on first render (stories).