Home Assistant Automations: A Practical Guide (2026)

By LK Wood IV · 2026-05-31 · ~15 min read · St. Louis County, MO

Home Assistant automation flow diagram: a Trigger stage (sun, time, state, zone platforms) leads into a Condition gate (state, sun, numeric_state, template), then an Action stage calling services like light.turn_on, climate.set_temperature, scene.turn_on, notify and tts.speak; below are reusable building blocks (choose branches and scripts) and a debug strip covering Traces, the Template tool, and Logbook.

Home Assistant automations follow a consistent structure: something happens (trigger), check if conditions are met (conditions), then do things (actions). Once you understand that structure, you can write almost any automation. This guide is examples-first — real working YAML for the automations that actually matter.

If you haven’t set up Home Assistant yet, the Home Assistant on Proxmox guide covers the install. For Zigbee/Z-Wave devices, the integration guide covers pairing.

The automation structure

automation:
  - alias: "My Automation Name"
    trigger:
      - platform: <trigger_type>
        # trigger-specific fields
    condition:
      - condition: <condition_type>
        # condition-specific fields
    action:
      - service: <domain.service>
        target:
          entity_id: <entity_id>
        data:
          # service-specific data

Trigger: what initiates the automation (state change, time, zone entry, webhook, etc.) Condition: optional guards — the automation only proceeds if all conditions pass Action: what happens when the trigger fires and conditions pass

Lighting automations

Turn on lights at sunset

automation:
  - alias: "Living Room — Lights On at Sunset"
    trigger:
      - platform: sun
        event: sunset
        offset: "-00:30:00"   # 30 minutes before actual sunset
    action:
      - service: light.turn_on
        target:
          entity_id: light.living_room
        data:
          brightness_pct: 60
          color_temp: 400     # warm color temperature (mireds)

The offset field accepts positive or negative durations. -00:30:00 means 30 minutes before the event.

Adaptive lighting: dim at night

automation:
  - alias: "Bedroom — Dim Lights After 10 PM"
    trigger:
      - platform: time
        at: "22:00:00"
    condition:
      - condition: state
        entity_id: light.bedroom
        state: "on"
    action:
      - service: light.turn_on
        target:
          entity_id: light.bedroom
        data:
          brightness_pct: 20
          color_temp: 500     # very warm
          transition: 10      # 10-second transition

The condition here prevents the automation from triggering the bedroom lights if they’re already off — you don’t want the lights turning on at 10 PM just to dim them.

Motion-triggered lights with timeout

automation:
  - alias: "Hallway — Motion Light"
    trigger:
      - platform: state
        entity_id: binary_sensor.hallway_motion
        to: "on"
    action:
      - service: light.turn_on
        target:
          entity_id: light.hallway
      - delay: "00:05:00"   # wait 5 minutes
      - condition: state      # only turn off if still no motion
        entity_id: binary_sensor.hallway_motion
        state: "off"
      - service: light.turn_off
        target:
          entity_id: light.hallway

For more reliable motion timeout behavior, use the wait_for_trigger action instead of delay:

action:
  - service: light.turn_on
    target:
      entity_id: light.hallway
  - wait_for_trigger:
      - platform: state
        entity_id: binary_sensor.hallway_motion
        to: "off"
        for: "00:05:00"
  - service: light.turn_off
    target:
      entity_id: light.hallway

wait_for_trigger pauses the action sequence until the trigger fires, then continues. If the motion sensor never clears, the action sequence waits indefinitely (use timeout: to cap it).

Presence-based automations

Welcome home scene

automation:
  - alias: "Welcome Home — Set Living Room Scene"
    trigger:
      - platform: zone
        entity_id: person.lk
        zone: zone.home
        event: enter
    condition:
      - condition: sun
        after: sunset
        before: sunrise
    action:
      - service: scene.turn_on
        target:
          entity_id: scene.living_room_evening
      - service: climate.set_temperature
        target:
          entity_id: climate.main_thermostat
        data:
          temperature: 70

The sun condition ensures the welcome home lighting only triggers after dark. Arriving home at noon doesn’t need the lights on.

Everyone left — eco mode

automation:
  - alias: "All Away — Energy Saving Mode"
    trigger:
      - platform: state
        entity_id:
          - person.lk
          - person.partner   # list multiple people
        to: "not_home"
    condition:
      - condition: state
        entity_id: person.lk
        state: "not_home"
      - condition: state
        entity_id: person.partner
        state: "not_home"
    action:
      - service: climate.set_temperature
        target:
          entity_id: climate.main_thermostat
        data:
          temperature: 65    # setback temperature
      - service: light.turn_off
        target:
          area_id: living_room
      - service: notify.mobile_app_phone
        data:
          message: "Away mode activated."

The trigger fires when any person changes to not_home. The conditions verify that ALL tracked people are away before applying eco mode — so the trigger fires but conditions gate it until the last person leaves.

Notification automations

Dishwasher done

This works with a smart plug that measures wattage (Zigbee or Z-Wave smart outlet):

automation:
  - alias: "Dishwasher — Done Notification"
    trigger:
      - platform: numeric_state
        entity_id: sensor.dishwasher_power
        below: 5     # watts — below this = cycle complete
        for: "00:02:00"
    condition:
      - condition: numeric_state
        entity_id: sensor.dishwasher_power
        above: 0.1   # was actually running (not just idle/off)
    action:
      - service: notify.mobile_app_phone
        data:
          title: "Dishwasher Done"
          message: "Cycle complete."

The for: "00:02:00" on the trigger prevents false positives from mid-cycle power dips — the wattage has to stay below 5W for two minutes before triggering.

Low battery alert

automation:
  - alias: "Low Battery — All Devices"
    trigger:
      - platform: numeric_state
        entity_id:
          - sensor.front_door_lock_battery
          - sensor.bedroom_motion_battery
          - sensor.thermostat_battery
          - sensor.smoke_detector_battery
        below: 20
    action:
      - service: notify.mobile_app_phone
        data:
          title: "Low Battery"
          message: "{{ trigger.to_state.name }} is at {{ trigger.to_state.state }}%"

The template {{ trigger.to_state.name }} and {{ trigger.to_state.state }} pull the entity’s display name and current value from the trigger context — so one automation handles multiple devices and tells you specifically which one is low.

Template-based automations

Door left open warning

automation:
  - alias: "Front Door — Left Open Alert"
    trigger:
      - platform: state
        entity_id: binary_sensor.front_door
        to: "on"
        for: "00:10:00"   # open for 10 minutes
    condition:
      - condition: template
        value_template: "{{ states('person.lk') == 'home' }}"
    action:
      - service: notify.mobile_app_phone
        data:
          message: "Front door has been open for 10 minutes."
      - service: tts.speak
        target:
          entity_id: media_player.kitchen_speaker
        data:
          message: "The front door is still open."

The template condition checks that someone is home before sending the alert — no point in notifying if no one is there to close it.

Thermostat override protection

automation:
  - alias: "Thermostat — Override Detection"
    trigger:
      - platform: state
        entity_id: climate.main_thermostat
        attribute: temperature
    condition:
      - condition: template
        value_template: >
          {{ trigger.to_state.attributes.temperature | float > 78 and
             now().hour >= 1 and now().hour < 6 }}
    action:
      - service: climate.set_temperature
        target:
          entity_id: climate.main_thermostat
        data:
          temperature: 70
      - service: notify.mobile_app_phone
        data:
          message: "Thermostat was set above 78°F at night — reset to 70°F."

Choose blocks: conditional action branching

When you need the automation to do different things based on a condition, use choose:

automation:
  - alias: "Motion — Lighting by Time of Day"
    trigger:
      - platform: state
        entity_id: binary_sensor.living_room_motion
        to: "on"
    action:
      - choose:
          - conditions:
              - condition: time
                after: "06:00:00"
                before: "20:00:00"
            sequence:
              - service: light.turn_on
                target:
                  entity_id: light.living_room
                data:
                  brightness_pct: 90
                  color_temp: 250   # cooler, daytime
          - conditions:
              - condition: time
                after: "20:00:00"
                before: "23:00:00"
            sequence:
              - service: light.turn_on
                target:
                  entity_id: light.living_room
                data:
                  brightness_pct: 40
                  color_temp: 500   # warm, evening
        default:
          - service: light.turn_on
            target:
              entity_id: light.living_room
            data:
              brightness_pct: 10
              color_temp: 600   # very warm, late night

Scripts: reusable action sequences

Put repeated action sequences in scripts:

# configuration.yaml
script:
  good_morning:
    alias: "Good Morning Routine"
    sequence:
      - service: light.turn_on
        target:
          area_id: bedroom
        data:
          brightness_pct: 30
          color_temp: 200    # cool/bright
          transition: 120    # 2-minute sunrise
      - service: climate.set_temperature
        target:
          entity_id: climate.main_thermostat
        data:
          temperature: 70
      - delay: "00:02:00"
      - service: light.turn_on
        target:
          entity_id: light.kitchen
        data:
          brightness_pct: 80

Call this script from any automation or button press:

action:
  - service: script.good_morning

Debugging automations

Trace view: Settings → Automations → open automation → Traces. Shows every firing with the trigger value, each condition result (pass/fail with values), and each action outcome.

Template testing: Developer Tools → Template. Paste any Jinja2 expression and see it evaluate against current state in real time. Use this to test conditions before putting them in an automation.

Entity history: Developer Tools → States. See the current value and last-changed time for any entity. Useful when an automation isn’t triggering — check if the entity state is actually what you think it is.

Logbook: Settings → Logbook. Shows state changes and automation fires in chronological order. Filter by entity to see exactly when something changed.

Best practices

Use for: on state triggers to avoid automations firing on momentary state changes (a sensor flickering, a button double-press).

Avoid complex logic in a single automation — break it into an automation that calls a script, with multiple scripts for different conditions. Simpler automations are easier to debug.

Version control your config — store your configuration.yaml and automation files in a Gitea repository. The Docker Compose starter stack includes Gitea for exactly this.

Use areas and labels — Home Assistant’s area grouping lets you target all lights in a room without listing entity IDs. area_id: living_room in a target covers everything in that area, including devices added later.


This guide extends the setup work from the Home Assistant on Proxmox guide and the Zigbee/Z-Wave integration guide. The automations here assume your devices are already paired and showing correct state in HA.

Frequently asked questions

Should I use the Home Assistant automation UI or YAML?
Both write to the same underlying YAML file. The UI is useful for simple automations and for discovering what fields are available. YAML is necessary for anything complex — multiple conditions with AND/OR logic, choose blocks, repeat loops, or automations you want to version control. Learning YAML early pays off. Write it in configuration.yaml or use the UI’s ‘Edit in YAML’ button; both work.
What is the difference between an automation and a script in Home Assistant?
Automations run automatically when a trigger fires (without you doing anything). Scripts are manual action sequences you call explicitly — from a button press, a service call, or from within an automation. Scripts are reusable: if three automations all need to ’turn on the good morning lighting scene and set the thermostat to 70’, put that in a script and call it from each automation rather than repeating the action list. Scripts don’t have triggers.
How do I debug an automation that isn't firing?
Settings → Automations → open the automation → trace. The automation trace shows every recent run attempt, whether the trigger fired, which conditions passed or failed, and which actions ran. If the automation didn’t fire at all, the trigger didn’t activate — check the entity state, the trigger value_template, or the time specification. If it fired but did nothing visible, check the condition section — a condition that evaluates false silently stops the automation.
What is a template in Home Assistant?
Templates are Jinja2 expressions inside Home Assistant YAML that evaluate dynamically at runtime. They let you calculate values, compare states, and make conditional decisions inside automations. For example: {{ states('sensor.temperature') | float > 75 }} evaluates to true or false based on the current temperature sensor reading. Templates are used in condition value_templates, in action data (to compute a brightness value from a sensor), and in trigger value_templates (to trigger on computed conditions).
How do I trigger an automation when someone arrives home?
The most reliable approach is zone-based presence detection with the official companion app (iOS or Android). The app reports when a device enters or leaves a defined Home Assistant zone (like ‘Home’). In the automation: trigger type ‘Zone’, entity = person.your_name, zone = zone.home, event = enter. Companion apps handle battery-efficient geofencing. Alternative: Bluetooth proxy detection (device comes in range of a Bluetooth proxy), or router-based tracking (device connects to the home WiFi network).