State
The one piece of memory that survives between handler calls.
state is a plain object the hub injects before every handler and saves back after it returns. It
is the only memory an instance has between calls: top-level variables reset on every run.
function onMotion() {
state.motionCount = (state.motionCount ?? 0) + 1;
state.lastMotionAt = new Date().toISOString();
}
function onDailyReport() {
sendPushNotification(`${state.motionCount ?? 0} motion events today`);
state.motionCount = 0;
}Rules
- JSON only. Strings, numbers, booleans, arrays and plain objects. An
EntityWrapperstored in state serialises to{ entityId, type: 'EntityWrapper' }; store the id and rebuild the wrapper withnew EntityWrapper(id)when you need it. - Start empty. A new instance begins with
{}. Write code that tolerates missing keys (state.count ?? 0) rather than seeding defaults ininstalledonly. - Whole-object save. The hub persists the object after the handler returns; there is no partial update and no versioning. Keep it small (kilobytes, not megabytes).
- Per instance. Two installs of the same definition have separate state. To share between apps,
use location events or an
input_*helper entity. - Survives reboots, settings changes and code updates. Cleared on uninstall.
Reading state outside a handler
Only handlers run inside the isolate, so there is no way to read state from a dynamic
preferences(values) function or from another app. Surface anything a person should see through
console.log, a notification, or by writing it to an input_text / input_number helper entity
that dashboards can show.
Patterns
Debounce / inactivity timers do not need state: runIn replaces its own pending timer.
Per-entity bookkeeping keyed by entity id:
function onAnyDoor(evt) {
state.openSince ??= {};
if (evt.newState.state === 'on') state.openSince[evt.entityId] = Date.now();
else delete state.openSince[evt.entityId];
}Idempotent handlers: timers that came due while the hub was off fire once on boot, and a re-delivered event is possible after a crash. Make handlers safe to run twice.