ControlTile

Molecule

Async controls: a frame (`ControlTile`) plus `ControlButton`, `ControlSwitch`, `ControlSlider` and `ControlSetpoint`. Each takes the bound `value` and an `onCommit` that returns a Promise, and shows idle -> pending -> confirmed / mismatch / failed with the previous value restored on failure. The slider writes once on release. State machine: `useAsyncControl` (libs/hooks). No transport knowledge; all text is overridable through `messages`.

Switch: pending then confirmed

Preview

Heater

Code
<ControlSwitch title="Heater" value={on} onCommit={write} />

Switch: failure rolls back (with Retry)

Preview

Heater

Code
<ControlSwitch title="Heater" value={on} onCommit={() => Promise.reject(new Error('Device offline'))} />

Switch: the device reports a different value (mismatch)

Preview

Heater

Code
<ControlSwitch title="Heater" value={on} reported={deviceState} timeoutMs={2500} onCommit={write} />

Slider: commit on release

Preview

Fan speed

0 %40 %100 %
Code
<ControlSlider title="Fan speed" value={speed} min={0} max={100} step={5} unit="%" onCommit={write} />

Set point: validated entry

Preview

Target temperature

°C

Current: 21.0 °C

Code
<ControlSetpoint title="Target temperature" value={t} min={5} max={30} step={0.5} unit="°C" decimals={1} onCommit={write} />

Button: none / confirm / typed confirmation

Preview

Gateway

Gateway

Gateway

Code
<ControlButton label="Reboot" confirm="typed" confirmText="reboot" onCommit={(c) => api.reboot(c)} />

Read-only (no permission)

Preview

Heater

Any control goes in the slot.

You do not have permission to use this control.
Code
<ControlSwitch title="Heater" value={on} readOnly onCommit={write} />
Sourcemodules/ui/ControlTile/index.ts