Main

The Wall Switch Beats the Automation: Designing Override Precedence So a Human Always Wins

Most smart-home failures are not broken devices. They are precedence failures. A motion automation turns a light off while someone is reading. A schedule overrides a manual dim. A guest flips a wall switch and the hub flips it back. The system is working as designed; the design just never decided who wins.

This article is about making that decision explicit. The goal is not to remove automation. It is to make the human the highest-priority input in every room, and to make that priority survive a hub reboot, a network outage, or a cloud service going dark.

What “override” actually means in a local-first stack

In Home Assistant, a light or switch entity has a state: on, off, unavailable, or unknown. The state is the current value; attributes carry brightness, color, and other detail. The Light integration documentation and the Switch integration documentation both describe this model. An override is not a new state. It is a separate piece of information that says: the last intentional change came from a human, and automations should not fight it until something clears that flag.

Home Assistant’s input_boolean helper is the simplest place to store that flag. The Input boolean documentation describes it as a virtual entity that stores an on/off state, is not tied to a physical device, and can be used as a condition in automations. It also restores its previous value after a restart if one is available. That last property matters: an override should not evaporate because the hub rebooted.

So the pattern is:

  • A physical wall switch or remote changes the load.
  • An automation detects that change and turns on input_boolean.office_manual_override.
  • Every automation that would otherwise control that load includes a condition that the override is off.
  • A human action, a timer, or a defined event clears the override.

That is the whole mechanism. The hard part is choosing where the override lives and what clears it.

Where the override should live

There are three layers, and they are not equivalent.

Layer 1: The device itself

If the wall switch is physically wired to the load, it already wins. No automation can turn a light on if the switch has cut power to the fixture. This is the most reliable override because it does not depend on software, radio, or the hub. It is also the least flexible: the load is simply unavailable to the smart system.

For Zigbee devices, binding is the next best thing. The Zigbee2MQTT binding documentation states that binding allows devices to directly control each other without the intervention of Zigbee2MQTT or any home automation software. It lists two advantages: smoother dimming feedback because commands do not round-trip through MQTT and the hub, and reliability because it works even when the home automation software, Zigbee2MQTT, or the coordinator is down. That is a real precedence decision made at the radio layer.

The same documentation notes that not all devices support binding, and that state reporting after a bound change depends on the target device’s reporting support. Some older bulbs may need to be polled. So binding is not universal, but where it works it removes the hub from the critical path.

Layer 2: The hub’s automation logic

This is where most people start, and it is where most precedence bugs live. A Home Assistant automation has a trigger and optional conditions. The automation condition documentation explains that conditions are checked after a trigger fires, and if any condition is false the automation does not run. It also warns about race conditions: a switch can turn on and then off in quick succession, and by the time the automation checks conditions the state may already have changed again.

That race condition is exactly how an automation overrides a human. The human presses the wall switch. The state changes. The automation triggers on that change, checks a condition that is still evaluating the old context, and issues a command that reverses the human action.

The fix is not a more clever condition. It is a separate override flag that is set before the automation can act, and a condition that reads that flag. The flag is not the light state; it is the human’s intent.

Layer 3: The physical switch as a sensor

If the wall switch is not directly wired to the load, it can still be read as an input. An ESPHome device with a GPIO binary sensor can detect the switch position. The ESPHome GPIO binary sensor documentation describes interrupt mode as the default for most platforms, with polling mode available for compatibility. It also documents debouncing with filters such as delayed_on: 10ms and delayed_off: 10ms, and notes that floating pins can produce rapid on/off events unless pull-up or pull-down resistors are enabled.

That last point is a common source of false overrides. A floating GPIO pin can generate a stream of state changes that look like human input. If your override flag is set by every state change, it will be set constantly. Debouncing and a defined pull-up or pull-down are not optional if you want the override to mean something.

Designing the override lifecycle

An override that never clears is just a broken automation. An override that clears too quickly is just a race condition with extra steps. The lifecycle needs three decisions: what sets it, what clears it, and what happens when the hub restarts.

What sets the override

The cleanest trigger is a change that could only have come from a human. That is easier to define on some devices than others.

  • Physical wall switch wired to the load: the load loses power. The smart device reports unavailable or off depending on the hardware. This is unambiguous but also means the smart system cannot control the load until the switch is restored.
  • Smart switch with a physical button: the device reports a state change. The problem is that the hub also causes state changes when it sends commands. You need to distinguish the two. One common approach is to compare the command the hub sent with the state that came back. If the hub did not send a command, the change is human. That comparison is not built into Home Assistant; it requires a template or a script that tracks the last command.
  • Remote or scene controller bound directly to the load: the load changes without the hub seeing a command. The hub sees the resulting state change. If the hub did not initiate it, it is human. Again, the hub needs to know what it initiated.

There is no reliable way to distinguish human from automated changes on every device without some form of command tracking. The tradeoff is complexity. If you skip command tracking, you will get false overrides. If you add it, you have another piece of state to maintain.

What clears the override

There are four common choices, and they have different failure modes.

  1. A timer. The override clears after a fixed period, such as 30 minutes or 2 hours. This is simple and predictable. It also means a human who wants the light off for the rest of the evening will have it turned back on by the automation when the timer expires. That is a real tradeoff, not a bug.
  2. A manual clear action. A dashboard button, a voice command, or a physical button press clears the override. This respects human intent indefinitely. It also means the override can be forgotten, and the automation stays disabled until someone notices.
  3. A state change that indicates the human is done. For example, the room becomes vacant for 15 minutes, or the door closes, or the media player turns off. This is context-dependent and can be wrong. It is best used as a secondary clear condition, not the only one.
  4. A scheduled reset. The override clears at a fixed time, such as 6:00 AM. This is useful for guest rooms and offices where the override should not persist across days. It is not useful for a living room where someone might want the light off all evening.

A timer plus a manual clear is a common recommendation. The timer prevents the override from being forgotten forever. The manual clear lets a human extend it. If the space is a guest room or a rental, a scheduled reset is worth adding.

What happens when the hub restarts

The Input boolean documentation states that if you set a valid value for initial, the helper starts with that value. Otherwise it restores the state it had before Home Assistant stopped, and if there is no state to restore it defaults to off. That means an override stored in an input_boolean will survive a normal restart if the state was saved. It will not survive a fresh install or a database reset.

If the override must survive a full rebuild, it needs to live somewhere else: a file, a script, or a device that reports its own state. That is a tradeoff between simplicity and durability. For most homes, the input_boolean restore behavior is enough.

Graceful degradation when the hub is gone

The strongest override is the one that does not need the hub. That is the argument for binding and for physical wiring. The Zigbee2MQTT binding documentation explicitly lists reliability as an advantage: binding works even when the home automation software, Zigbee2MQTT, or the coordinator is down. That is not a theoretical benefit. It is the difference between a light that works during a hub outage and a light that does not.

For ESPHome devices, the local control loop runs on the device. If the hub is down, the device can still read its GPIO input and control its output if the configuration is written to do so. The GPIO binary sensor documentation describes the input side, but the output side depends on the specific output component and the automation logic on the device. ESPHome supports on-device automations, so a local override can be implemented without the hub. That is a design choice, not a default.

For Z-Wave, the equivalent of binding is association. The Z-Wave JS documentation for associations is not covered here, so the exact configuration is not described. The principle is the same: if the device supports direct association, the wall switch can control the load without the hub.

A diagnostic path for “the automation keeps overriding my switch”

When someone reports that a light will not stay off, the first question is not “what is wrong with the automation.” It is “what is the last command, and who sent it.”

  1. Check the entity history. In Home Assistant, open the entity and look at the history. You are looking for a pattern: a state change, followed within a second or two by a command that reverses it. That pattern is the signature of an automation fighting a human.
  2. Check the automation traces. Home Assistant records traces for automations. Open the automation and look at the most recent trace. You want to see which trigger fired, which conditions were evaluated, and which action ran. If the action ran immediately after a human state change, the automation is the culprit.
  3. Check for race conditions. The condition documentation warns that a switch can turn on and then off in quick succession, and the automation may see the current state rather than the state at trigger time. If the automation triggers on a state change and then checks a condition that reads the same state, it can act on stale information. The fix is to use a separate override flag that is set by the human action before the automation evaluates its conditions.
  4. Check for multiple automations. It is common to have a motion automation, a schedule automation, and a scene automation all targeting the same light. Each one may have its own conditions. If only one of them checks the override flag, the others will still fight the human. Every automation that controls the load needs the override condition.
  5. Check the device’s local behavior. Some smart switches have their own local automation or “smart bulb mode” that can conflict with the hub. If the device is configured to always restore power to the load, a physical switch press may be interpreted as a command rather than a power cut. The device documentation is the primary source here.

Once you have identified the automation, the fix is not to delete it. It is to add the override condition and to make sure the override is set by the human action. Then test it: press the wall switch, confirm the override flag turns on, confirm the automation does not run, and confirm the light stays where the human put it.

A repeatable procedure

This is a procedure for a room where a human needs to win.

  1. Decide the override scope. Is it per-light, per-room, or per-house? Per-light is the most precise and the most work. Per-room is usually the right balance. Per-house is rarely useful because it disables too much.
  2. Create the override helper. In Home Assistant, create an input_boolean for the scope. Name it something explicit, such as input_boolean.office_manual_override. The Input boolean documentation describes how to create it from Settings > Devices & services > Helpers, and how to configure it in configuration.yaml if you prefer.
  3. Identify the human input. Is it a wired wall switch, a smart switch button, a bound remote, or an ESPHome GPIO input? If it is a smart switch, you need a way to distinguish human from automated changes. If you cannot distinguish them, consider whether the override should be set by a different signal, such as a physical button that is not also controlled by the hub.
  4. Set the override on human input. Create an automation that triggers on the human input and turns on the override helper. If the human input is a state change that the hub also causes, add a condition that the hub did not just send a command. That condition requires tracking the last command, which is extra work but prevents false overrides.
  5. Add the override condition to every automation that controls the load. The condition is input_boolean.office_manual_override is off. The condition documentation shows how conditions are structured. If you have multiple automations, add the condition to each one. There is no central place to enforce this in Home Assistant; it is a per-automation change.
  6. Define the clear behavior. Add a timer, a manual clear action, or both. If you use a timer, document the duration. If you use a manual clear, make it accessible: a dashboard button, a voice command, or a physical button.
  7. Test the failure modes. Press the wall switch. Confirm the override turns on. Confirm the automation does not run. Restart Home Assistant. Confirm the override survives if that is what you want. Disconnect the hub from the network. Confirm the wall switch still controls the load if the device supports local control or binding.
  8. Document the precedence. Write down which input wins in which situation. If the wall switch wins over the motion sensor, say so. If the dashboard button wins over the schedule, say so. The documentation is for the next person who has to debug it, including you.

When a plain switch is the smarter choice

Not every load needs an override. Some loads should not be automated at all. A bathroom fan that runs on a mechanical timer is a better solution than a smart fan with a humidity sensor and a schedule if the goal is simply “run for 20 minutes after a shower.” A plain switch on a closet light is better than a motion sensor if the closet is used infrequently and the motion sensor would trigger every time someone walks past.

The tradeoff is control versus reliability. A plain switch has no firmware, no radio, no hub, and no cloud dependency. It also cannot be scheduled, dimmed remotely, or included in a scene. If the automation value is low and the reliability value is high, the plain switch wins. That is not a failure of the smart-home design; it is a correct precedence decision.

The same logic applies to mechanical timers. A mechanical timer is a local, deterministic override that does not need a hub. If the requirement is “this load runs on a schedule and a human can override it by turning the dial,” a mechanical timer may be more reliable than a smart plug with a schedule and an override flag. The smart plug adds remote control and logging; the mechanical timer adds simplicity. Choose based on which failure mode you can tolerate.

What this article does not cover

This article does not cover every device’s behavior at low temperatures, after a firmware update, or after a factory reset. It does not cover every Zigbee binding combination, and the Zigbee2MQTT documentation itself notes that not all devices support binding and that state reporting depends on the device. Z-Wave associations are not covered because that documentation was not retrieved. Where a procedure is described, it is based on the documented behavior of the platforms, not on a controlled experiment. Treat the numbers and timings as starting points, not as measured results.

FAQ

Does an input_boolean survive a Home Assistant restart?

Yes, if a previous state is available. The Input boolean documentation states that if you set a valid value for initial, the helper starts with that value; otherwise it restores the state it had before Home Assistant stopped, and if there is no state to restore it defaults to off.

Can I use the light’s own state as the override?

You can, but it is fragile. The light state changes for many reasons, including automated commands. If you use the light state as the override, the automation that changes the light will also set the override, which defeats the purpose. A separate helper is clearer because it represents human intent, not device state.

What if the wall switch cuts power to the smart device?

Then the smart device is unavailable until power is restored. That is the strongest override because no automation can control the load. It also means the smart system cannot report the device’s state or include it in scenes while the switch is off. If that tradeoff is acceptable, a wired wall switch is the most reliable override available.

How do I know if a state change came from a human or an automation?

You need to track the commands the hub sends. If the hub did not send a command and the state changed, the change came from somewhere else, which is usually a human or a bound device. Home Assistant does not do this tracking automatically for every integration. It requires a template, a script, or an integration-specific feature. If you cannot track commands, you cannot reliably distinguish human from automated changes on that device.

Should the override clear when the room becomes vacant?

It can, but vacancy is not the same as “the human is done.” A person may leave the room and want the light to stay off. A vacancy clear will turn the light back on when the automation resumes. If you use vacancy as a clear condition, make it a long vacancy, such as 30 minutes, and make sure the automation that turns the light back on is the one you want to run.

Does binding work with all Zigbee devices?

No. The Zigbee2MQTT binding documentation states that not all devices support binding and that it depends on the Zigbee implementation of the device. It also notes that state reporting after a bound change depends on the target device’s reporting support, and that some older bulbs may need to be polled. Check the device-specific page before relying on binding.

What is the simplest override that still works?

A wired wall switch that cuts power to the load. It requires no hub, no radio, and no configuration. It also removes the load from smart control while it is off. If that tradeoff is acceptable, it is the simplest and most reliable override. If you need the load to remain smart-controllable, a bound remote or a smart switch with a separate override helper is the next step up in complexity.

For a broader look at how to audit the small systems that quietly run your week, including the automations that are easy to forget, see How to Audit the Small Systems That Quietly Run Your Week. The audit process is a useful companion to this article because it helps you find the automations that need an override condition in the first place.