Skip to the content.

Automations

If scripts are the verbs — the sequences you run — automations decide when to run them. The danger is unique to automations: they react to state, and state includes the state they themselves change. Get that wrong and an automation chases its own tail, or leaves the house in two contradictory states at once.

Enforce a single active source

In a whole-home system, two sources playing at once is almost never what anyone wants. Make it structurally impossible: selecting a new whole-home source stops the others first.

# Illustrative — choosing a whole-home source stops the others first (single active source).
automation:
  - alias: "Single active source"
    trigger:
      - trigger: state
        entity_id: input_select.house_source
    action:
      - action: script.stop_all_sources           # stop current before starting new
      - action: script.turn_on
        target:
          entity_id: "script.source_"

Stop-then-start is the safe order. The new source never has to coexist with the old one, so you never get the “why is the patio still playing?” call.

Design triggers and conditions to be idempotent

Assume every automation can fire more than once — because in a real house, it will. Guard it so a second firing does no harm: condition on current state before acting, so an automation that runs twice doesn’t undo itself or stack up commands.

Why it holds: this is idempotency at the automation layer. Events get duplicated, triggers get noisy, and you press buttons while automations run. An automation that’s only correct when it fires exactly once is a bug waiting for a busy evening.

Avoid feedback loops

The classic trap: an automation that triggers on a state its own action changes. It fires, changes the state, which fires it again. Break the loop with a condition that stops the re-fire, or by triggering on something the action doesn’t touch. If an automation ever seems to “run forever,” look here first.

Avoid double-toggling

Before flipping a device, check whether it’s already in the target state. Don’t turn off a TV that’s already off — especially where “off” is destructive (some devices disable their own network control on a naive power-off; see the gotchas). Condition on current state, then act only if needed.

Keep your state truthful, however playback starts

People start audio in ways your scripts never see — a native media browser, a phone casting directly to a player. If your source-of-truth helpers only get written by your own scripts, they go stale the moment someone bypasses them, and your dashboard starts lying.

The fix is a reactive automation that watches the player and writes the source helper by inspecting the player’s attributes — so the UI stays honest no matter how playback began. Two details make it robust:

Re-apply the group after out-of-band playback

When someone starts playback directly on the streaming player — a native browse, a cast handoff — your room group never got applied, so the audio reaches only that one player. Catch it: trigger on the player entering “playing” and on its media_content_id changing (so successive browse picks, which don’t re-transition the state, still fire), then re-apply the active group by calling your idempotent room_add scripts, each gated on its room boolean.

Make this automation self-sufficient — have it apply the group itself rather than depending on another automation whose gate might be false in the cast case. And hold each trigger with a short for: to de-dupe it against the source-detection automation watching the same entity.

Reconcile state instead of trusting it

Helper booleans and device “on” states drift from reality: a room shows active but plays nothing; a display reports “on” in two different modes. Don’t build a toggle on a single state you haven’t confirmed (see avoid double-toggling). Where a device’s own state is unreliable, use a companion signal as a proxy — a downstream device that’s only on when the thing really is — and consider a periodic reconcile that clears “phantom active” rooms. This is automate against reality, not labels at the automation layer.

Pitfalls

See also