Automations · Home Assistant

Automation Fundamentals.

Reading time
~20 min · 4,159 words
FAQ
0 questions
Status
Draft 1 · under review
Section
All Home Assistant pages

An automation in Home Assistant is a rule that watches for something to happen, checks that conditions are right, and takes action. A greenhouse temperature crossing 85°F during the day, a soil moisture reading dropping below 22%, the sun rising thirty minutes ago — each can trigger an automation. For agricultural operations, automations turn the sensor and integration work of the prior pages into actual operational value: alerts that arrive before a crop is damaged, controls that respond to conditions rather than schedules, sequences that run correctly whether the grower is watching or not. This page covers the automation mental model (triggers, conditions, actions, modes), the UI-editor-versus-YAML choice, the specific trigger types that matter in agriculture, the conditions that keep automations from firing at the wrong time, the actions available, and the debugging patterns that save hours when something does not work. The first automation a grower builds takes an hour; the hundredth takes a few minutes. This page is the foundation for everything in the Automations sub-section that follows.

Before building automations.

Prerequisites from earlier pages:

Home Assistant installed and integrations added. Per the Getting Started pages. The automations on this page assume sensors and actuators already exist as entities in Home Assistant.

Areas and naming conventions established. Per [Organizing Home Assistant for a Farm](/home-assistant/agriculture/organizing). Automation aliases, entity references, and organization all depend on a consistent naming scheme. An operation without naming discipline ends up with automations referencing `sensor.temp_3` and nobody remembering which zone that is six months later.

Hardware safety in place. Home Assistant automations handle operational control; hardware handles catastrophic cases. Thermal cutoffs on heaters, mechanical float switches in reservoirs, contactors with local override — these are not replaced by automations. They are the layer that keeps the crop safe when the automation, the Home Assistant host, the network, or the grower's attention fails.

A place for the configuration to live. Ideally a Git repository. Automations are configuration, and configuration belongs under version control. The setup is small; the payoff when an update breaks something is large.

The automation model.

Three parts: trigger, condition, action.

Trigger. The event that starts the automation running. When this thing happens, consider running.

Condition. Optional checks that must be true when the trigger fires. If these are not all true, do not run.

Action. What to do. Call a service, wait, branch on logic, start another automation, send a notification.

The pattern in plain terms:

- Trigger: Greenhouse Zone 1 temperature rises above 85°F. Condition: it is daytime and the ventilation is not already in full cooling mode. Action: send a high-priority alert to the grower's phone. - Trigger: a soil moisture sensor drops below 22%. Condition: the current time is within the irrigation window, and the zone has not been watered in the last 30 minutes. Action: start a five-minute irrigation cycle on that zone's valve. - Trigger: the sun rose thirty minutes ago. Condition: propagation zone is in seedling stage. Action: ramp the supplemental lights up over fifteen minutes.

A useful automation has all three parts. Some have only trigger and action, which is fine when no conditions are needed. The mental model is always: when this happens, if these are true, do that.

The UI editor and YAML.

Home Assistant offers two ways to build automations: the visual editor in the UI, and YAML configuration files.

The UI editor. A form-based interface for building automations without writing code. Dropdowns for trigger types, entity pickers, templates for common patterns. Good for first automations. Good when the automation is straightforward. Produces underlying YAML that can be inspected and edited later. Most agricultural automations can be built entirely in the UI editor and run reliably.

YAML. The native configuration format. Every automation is ultimately YAML — the UI editor is a friendlier face on top of it. YAML allows advanced patterns the UI does not fully surface: complex template triggers, multi-step sequences with conditional branches and variables, fine-grained mode control, extended timeouts with error handling. YAML is also more exact for version control and more portable between Home Assistant instances.

The middle ground. Build in the UI to get something working quickly, then switch to YAML view to refine, add comments, put it under version control, and hand-tune. The UI editor remains useful for prototyping even when most of an operation's automations are YAML-managed.

Version control. For any operation with more than a handful of automations, Git or similar source control is worth the setup. When an automation change breaks something — and over a long enough period, one will — reverting is trivial with Git and painful without it. Version history also documents why automations evolved the way they did, which matters when a grower returns to an automation a year later wondering what their earlier self was thinking.

Triggers.

Triggers are what start an automation running. Home Assistant supports many trigger types. The ones that matter most for agricultural operations:

State triggers. Fire when an entity changes state. "When the irrigation pump turns on." "When a door sensor goes to open." State triggers can restrict to specific transitions (`from: off`, `to: on`) or require the state to hold for a duration (`for: "00:05:00"`) before triggering. The duration variant is useful for ignoring brief excursions — a door that opened for two seconds while someone checked on the crop should not necessarily trigger an alert; one that has been open for five minutes should.

Numeric state triggers. Fire when a numeric value crosses a threshold. "When Zone 1 temperature rises above 85°F." "When soil moisture drops below 22%." The `above` and `below` options specify the threshold direction, and `for:` requires the threshold to hold for a duration. A common pattern for agricultural automations pairs a higher threshold for triggering with a lower threshold for resetting, which is discussed further under hysteresis below.

Time triggers. Fire at a specific time of day. "At 06:00:00." "At 18:00:00." Time triggers handle daylight saving transitions correctly when local time is used, which matters for photoperiod-sensitive crops. Time pattern triggers can fire on intervals — "every fifteen minutes," "every hour at the top of the hour" — useful for scheduled checks.

Template triggers. Fire when a Jinja2 template evaluates to true. The most flexible trigger type. "When the rolling ten-minute average of CO2 is above 1500 ppm." "When the difference between two temperature sensors exceeds 2°C." Template triggers cover patterns that other trigger types cannot express. They can be less efficient than a simpler equivalent where one exists — a numeric state trigger on a single sensor beats a template trigger evaluating the same condition.

Sun triggers. Fire relative to sunrise or sunset. "At sunrise minus thirty minutes." "At sunset." Useful for natural-light-based lighting automations and for time-of-day behaviors that should follow the actual sun rather than a fixed clock time. Sun triggers adjust automatically through the year; fixed time triggers do not.

Platform-specific triggers. Some integrations provide their own trigger types — MQTT message arrival, webhook calls, Zigbee device events, Zigbee2MQTT actions, calendar events, geolocation. Each integration's documentation covers its specific triggers. For growers, MQTT-message-arrival triggers are common (ESPHome devices publishing to MQTT), and calendar-event triggers are useful for integrating a planting schedule with the automation system.

Event triggers. Fire on Home Assistant events. Less commonly used for agricultural operations directly but available when an integration produces events rather than entity state changes.

Multiple triggers in one automation. Any automation can have multiple triggers, and any one of them firing starts the automation. This is useful when the same action should happen for several conditions. A "high temperature alert" automation might trigger on Zone 1, Zone 2, or Zone 3 crossing threshold, with the action identifying which zone fired through `trigger.entity_id`. One automation, many sources.

Trigger IDs. When multiple triggers live in the same automation, giving each a unique `id:` lets the action branch on which trigger fired. The trigger ID becomes available as `trigger.id` in the actions, which is cleaner than parsing entity IDs to figure out which zone raised the alert.

Conditions.

Conditions are optional filters between the trigger and the action. If the condition is not met when the trigger fires, the automation does not run even though the trigger fired.

State conditions. "Only if the irrigation system is in auto mode." "Only if the grower is not on-site."

Numeric state conditions. "Only if outdoor temperature is below 40°F." "Only if the reservoir level is above 20%."

Time conditions. "Only between 06:00 and 18:00." "Only on weekdays." "Only during daylight hours." Time conditions are essential for automations that should only operate during certain hours. A ventilation cooling automation that fires at 3 AM because a sensor briefly spiked is not usually useful; a time condition restricting it to daylight hours prevents that.

Template conditions. Arbitrary Jinja2 expressions. "Only if no zone has been watered in the last hour." "Only if today's DLI target has not already been met." Template conditions cover logic that does not fit the simpler condition types.

AND and OR logic. Multiple conditions default to AND — all must be true. An `or` block explicitly groups conditions so that any one of them being true satisfies the group. `not` inverts a condition. Conditions nest, so fairly complex logic is expressible.

Conditions versus triggers. A common early-stage mistake is using conditions where a trigger would be more efficient, or vice versa. Triggers are cheap to check — Home Assistant is watching for them as a matter of course. Conditions are evaluated only when a trigger fires. A rule like "alert when temperature rises above 85°F, but only during daylight" is cleanest as a numeric state trigger plus a time condition. A rule like "alert every fifteen minutes while temperature is above 85°F" is cleanest as a time pattern trigger with a numeric state condition. The shape of the rule usually suggests the right structure.

Actions.

Actions are what the automation does when it runs. Home Assistant provides many action types.

Service calls. The most common action. Call a service on a target — `switch.turnon` on a greenhouse fan switch, `notify.mobileappgrowerphone` with a message, `script.cooling_sequence` to run a named script. Services cover nearly every controllable thing in Home Assistant.

Delays. Pause the automation for a specified time. "Wait thirty minutes before checking again." "Run for fifteen minutes, then stop." Delays inside a running automation are common in irrigation cycles, ventilation sequences, and any operation where timing matters.

Wait for trigger. Pause until a specific condition is met or a timeout expires. "Wait until temperature drops below 75°F, or thirty minutes, whichever comes first." More flexible than a fixed delay when the wait should end when a real condition is satisfied rather than on a clock.

Wait for template. Similar but uses a Jinja2 template as the condition. Useful when the wait-until logic is more complex than a single entity state.

Conditional branches (`choose`). Run different actions depending on what is true. "If moisture is below 15%, run a long cycle; if below 22%, run a short cycle; otherwise, do nothing." Conditional branches let one automation handle multiple cases cleanly.

Parallel actions. Run several actions at once rather than sequentially. "Start ventilation, send alert, and log the event — all simultaneously." Useful when the actions are independent and none should wait on another.

Repeating actions. Loop over a list of items or while a condition is true. "For each greenhouse zone, check the temperature and build a summary message." "While the moisture is below target, run another irrigation cycle." Repeats should always have a safety cap (a count limit, a time limit, or both) to prevent runaway loops.

Variables. Capture values at the start of an automation and reference them throughout. Useful when trigger data needs to be referenced multiple times in the actions. Variables can be set from templates, which lets an automation compute a value once and use it many times.

Calling other automations or scripts. An automation can trigger another automation with the `automation.trigger` service, or run a script. Scripts are the usual choice for shared reusable logic — a "send alert with standard formatting" script called from many automations reduces duplication and makes changes in one place affect all callers. [Scripts and Scenes](/home-assistant/automations/scripts-scenes) covers this pattern in depth.

Actions chain. An automation can call a service, wait, check a condition, branch, call another service, wait again, and summarize. Long sequences work; they are usually better factored into scripts once they grow past a certain complexity.

Automation modes.

Home Assistant supports four automation modes. The mode determines what happens when the automation is triggered again while a previous run is still executing. Choosing the right mode matters because the wrong mode produces subtle bugs that are painful to diagnose.

Single (the default). The automation runs once. If the trigger fires again while the first run is executing, the second firing is ignored. Best for automations that should produce one output per triggering event and where the output's work is finished before the next firing would matter — most alerts, most simple on-off controls.

Restart. If the trigger fires while the automation is running, the current run is canceled and the automation restarts from the beginning. Useful for debouncing — "only run the most recent trigger." Common for automations that set a long timer that should restart when the trigger refires. A "lights off after no motion for ten minutes" pattern, adapted to agriculture as "pump off after no flow for five minutes," uses `mode: restart`.

Queued. If the trigger fires while the automation is running, the new firing is queued to run after the current one finishes. Each trigger eventually produces exactly one complete run. Useful when each trigger must produce exactly one action but triggers may arrive faster than the automation can complete. An irrigation cycle that must run to completion for each moisture-below-threshold reading is a `mode: queued` automation.

Parallel. Each trigger firing starts a new concurrent execution. The automation may have many runs executing simultaneously. Useful for independent operations on different targets — "send an alert" automations that may fire many times in quick succession, each for a different entity, and all should produce their notifications. Parallel mode has no interference between runs because each run is independent.

Choosing the wrong mode produces real operational problems. A "start irrigation" automation in single mode can miss triggers — a moisture reading that drops below threshold twice in quick succession produces irrigation only once. In queued mode the same conditions produce two cycles back-to-back, which may be more water than the crop needs. In parallel mode two valves might open simultaneously when the operation cannot supply the flow. The mode should match the real-world behavior the grower wants.

Organizing automations.

As the count grows, organization matters.

Descriptive aliases. "Alert when Greenhouse Zone 1 temperature exceeds 85°F during daylight hours" beats "Automation 37." The alias is what appears in logs, in the UI, in error messages, and in notifications when they reference their source automation. Clarity pays off every time the automation comes up in a debugging session.

Automation IDs. Each automation has an `id:` field that functions as its stable identifier. IDs are how automations are referenced from scripts, services, and other automations. Descriptive IDs like `ghzone1hightemp_alert` beat autogenerated IDs like `1703845782191` — readable IDs are searchable and self-documenting.

Areas. Associate each automation with an area (a greenhouse zone, a propagation room, an outdoor field). Dashboards and filtered views become useful when automations are area-assigned. A "show me every automation for Zone 1" filter is trivial when areas are set consistently.

Labels and categories. Home Assistant supports labels and categories for automations. "Alerts," "Irrigation," "Climate," "Safety" as labels help filter long lists. For operations with dozens or hundreds of automations, labels make the list navigable.

File organization. YAML automations can be split across multiple files by topic — one file for climate automations, one for irrigation, one for alerts. The single `automations.yaml` file works for small setups; larger setups benefit from `!includedirmergelist` or `!includedir_list` patterns that combine multiple files. Per-topic files are easier to navigate and reduce the risk that an unrelated change introduces a merge conflict.

Documentation in the YAML. Comments explaining why an automation does what it does are worth the effort. Six months later, the grower asking "why is this set this way?" will thank their earlier self for leaving a comment. The best comments explain intent, not mechanics — "we set this to twenty minutes because the last-mile valves need that long to equalize pressure" is more useful than "wait twenty minutes."

Testing and debugging.

A production automation that fires at the wrong time, or fails to fire when it should, can cost a crop. Testing discipline is not optional for anything that matters.

Manual triggering. Home Assistant lets the grower run any automation manually, bypassing the trigger. Useful for verifying that the action side of the automation works — the service calls succeed, the notifications arrive, the valves operate as expected. Manual triggering does not verify the trigger logic, only the actions.

The trace viewer. Home Assistant records each run of an automation as a trace — the trigger that fired, the condition checks and their results, each action and its outcome. Traces are the primary debugging tool. When an automation did not do what was expected, the trace shows exactly what happened: whether the trigger fired, which condition blocked execution, which action produced an error. Every substantive automation deserves a trace review on its first few production runs.

The automation editor's test features. The UI editor can test numeric-state and template trigger logic without waiting for the real condition. Enter a trial state value or render a template against current data to verify the trigger evaluates correctly.

Developer Tools → Template. Jinja2 templates can be tested directly in Developer Tools before they go into a production automation. Useful for verifying that a template produces the expected output given current entity states.

Log review. Home Assistant's system log records automation runs and errors. When an automation is not firing or is firing at the wrong time, the logs often explain why. Startup errors, referenced entities that do not exist, and service call failures all show up in the log.

Staging on a test system. For critical automations, a second Home Assistant instance on spare hardware or in a VM lets the grower test changes without risking production. Not every operation needs staging, but for photoperiod-sensitive crops, cold chain monitoring, fertigation, and any other domain where a bug costs a crop, the extra safety is worth the setup.

Start simple, add complexity. Build an automation with the simplest trigger and action. Verify it works. Add one condition, verify it still works. Add the second condition, verify. Incremental construction is faster than building everything at once and then unwinding a tangle.

Common failure modes.

Specific automation problems that come up in real production.

The automation that never fired. The trigger condition was never actually met because a typo in an entity name referenced a sensor that did not exist. Home Assistant fails quietly in many cases — no trigger, no action, no obvious error. Fix: verify entity names through Developer Tools → States; use the trace viewer to check whether triggers are registering; enable the entity unavailable state in automations that depend on specific entities so their unavailability is noticed.

The automation that fired too often. A numeric state trigger with no hysteresis fired repeatedly as a sensor value bounced around the threshold. Irrigation ran eight times in ten minutes. Fix: add hysteresis (separate above and below thresholds, with a meaningful gap), add a `for:` duration requirement so brief excursions do not trigger, or use `mode: single` with a sustained execution to suppress repeat firings.

The automation that fired at 3 AM. A template trigger with complex logic produced an unexpected true evaluation at a time the grower had not anticipated — some sensor reported an unusual value overnight, the template evaluated true, the alert went out. Fix: test template triggers against the full range of real-world conditions before deploying; log trigger firings during a validation period to confirm timing matches expectations; add time conditions that limit the automation to hours when the grower actually wants it active.

The automation that did the wrong thing. A `choose` block had its conditions ordered such that the wrong branch matched. The logic looked right but ran wrong. Fix: test each branch explicitly; add logging or notifications in each branch during validation so it is clear which ran; remember that `choose` evaluates branches in order and runs the first match.

The automation that stopped working after an update. A Home Assistant version update changed the syntax of a particular trigger type or service call. The automation still parsed but no longer behaved as before. Fix: read the release notes for breaking changes; run a post-update trace review on critical automations; subscribe to the Home Assistant release notes for advance notice of deprecations.

The automation that was disabled. Someone — perhaps the grower, perhaps the grower six weeks ago — disabled the automation and forgot. The thing it was supposed to do stopped happening. Weeks later the crop showed stress. Fix: periodic review of disabled automations; a "critical automations disabled" monitor that alerts when a flagged-as-critical automation is disabled or removed.

The automation that raced another automation. Two automations triggered by related conditions both fired near-simultaneously and their actions conflicted — one turned the fan on, the other turned it off. Fix: factor shared logic into a single script that both automations call; design overlapping automations to complement rather than compete; use `mode` carefully to avoid unintended concurrency.

The automation that got stuck. A `waitfortrigger` with no timeout waited indefinitely for a condition that never occurred. The automation appeared to be running (it was) but was doing nothing. Fix: always set a `timeout:` on wait actions; review the trace viewer periodically for runs that never completed.

The automation broken by an entity rename. A smart plug or sensor changed its entity ID after a firmware update or integration reconfiguration. The automation referenced the old ID. Fix: prefer entity selectors (which bind to entities by identity rather than name) over string entity IDs; monitor for referenced entities becoming unavailable; use the entity registry's stable unique IDs where possible.

The automation that fired on restart. A state trigger on "when the freezer door opens" fired spuriously when Home Assistant restarted and the sensor's state was re-evaluated as a transition. Fix: use `from:` and `to:` together to specify a real transition (`from: closed, to: open`) rather than just `to: open`; filter out the startup period with a time condition or a startup-recovery script.

What not to do.

Patterns to avoid.

Don't build critical automations without testing. An irrigation automation that has never been manually triggered should not be trusted with production. The first time it runs should not be the first time it does anything.

Don't rely on Home Assistant for life-safety. Temperature protection, electrical protection, water control — all need hardware backup. Home Assistant makes operations smarter; it should not be the only layer between the crop and catastrophe. A greenhouse with a heater controlled only by a Home Assistant automation, with no thermal cutoff on the heater itself, is one misconfigured YAML file away from a fire.

Don't make one automation do too many things. One automation, one purpose is clearer than one automation doing five things. Smaller, focused automations are easier to debug, easier to modify, and easier to understand when returning to them months later.

Don't skip hysteresis on numeric state triggers. A sensor hovering near a threshold triggers endlessly without it. A meaningful gap between the trigger threshold and the recovery threshold prevents thrashing. For temperature, 2–5°F is usually enough; for humidity, 5–10 percentage points; for soil moisture, 3–5 percentage points.

Don't use `mode: single` for automations that should respond to every trigger. Notifications, alerts, and per-event logging often need `mode: parallel` or `mode: queued` — otherwise some firings are silently dropped and the grower never learns about events that mattered.

Don't leave automations undocumented. Six months from now, the grower will read an automation and wonder why it exists. A comment explaining the intent saves the wondering and reduces the risk that someone changes the automation without understanding why it was the way it was.

Don't hardcode entity IDs that will change. An ESPHome device that might get replaced, a smart plug that might get upgraded — referencing these by name in many automations creates a brittle web. A single input helper (inputboolean, inputnumber) or template sensor that other automations reference is easier to update than editing twenty automation YAML files.

Don't disable an automation without a note. A disabled automation still exists in the UI. Without a note in the alias or a comment explaining why, the grower later cannot remember whether to re-enable it or delete it.

Don't ignore trace warnings. Home Assistant's trace viewer sometimes flags slow actions, timeouts, or degraded behavior before the automation actually fails. Paying attention to the warnings is cheaper than waiting for the failure.