Docs

Best practices

The rules the platform enforces, and the habits that keep an app reliable.

Enforced by the platform

The hub validates code on registration and again at run time. In short:

  • Source at most 128 KiB; no import / export.
  • No setTimeout / setInterval / clearTimeout / clearInterval.
  • No local-time Date getters (getHours, getDay, toLocaleString, …) in AI-generated automations.
  • Subscription filters may only contain from, to, state, attribute.
  • Only the listed state values per domain in filters.
  • httpRequest may not reach loopback, link-local or multicast addresses.
  • 8 MB heap, 30 s to evaluate the file, 10 s of synchronous time per handler.

The generated Validation rules page lists every rule set with its exact names.

Habits that pay off

Teardown before setup. updated calls unsubscribe() and unschedule() before initialize().

Guard every input. Inputs can be undefined; multi-selects can be one wrapper or many.

Treat state as the only memory. Anything else resets per handler. Make handlers idempotent; a timer can fire once on boot after a reboot.

Use the home's clock. formatDateParts(new Date(), getHomeTimeZone()) for any wall-clock decision; epoch maths for durations.

Re-arm sun timers. scheduleAtSunrise / scheduleAtSunset fire once.

Debounce with runIn. Re-arming replaces the pending timer; no bookkeeping needed.

Prefer transitions to levels. Subscribe with { to } / { from, to } for actions, {} for monitoring; never trigger on unavailable / unknown for user-facing behaviour.

Remember presence is a binary_sensor. on = home, label Present.

Compare with is() or labels, not === on raw tokens. door.is('Open') and { to: 'Open' } read like the app and survive casing differences; getState() === 'on' is strict.

Don't read state back immediately after a service call. Wait for the entity change.

Log for the person reading it later. Short lines, no secrets, gated by a logging preference.

Name things for the install picker. definition.name and input labels are what people see; descriptions on inputs save support questions.

Let people choose recipients and devices. Inputs, not hard-coded ids or addresses.

Checklist before registering

  1. definition has name and namespace; no version.
  2. preferences.pages[] with inputs keyed as camelCase identifiers.
  3. installed and updated exist; updated tears down first.
  4. Every handler is a top-level named function.
  5. Every subscribe filter uses only allowed keys, and each state is a raw token or the label the app shows for that device.
  6. No timers, no fetch, no local-time Date getters.
  7. Multi-select and optional inputs are guarded.
  8. Anything that must persist lives in state.

On this page