Skip to content

Automations

Home Assistant automations, ready to copy

Short versions of the automations from the blog. The entity IDs are placeholders, so swap in your own. The full story, including what broke along the way, is in the linked post.

Pause the TV when a phone rings

Pauses the TV the moment a phone rings and resumes two seconds after the call ends, but only if the automation was the one that paused it.

Trigger
The phone state sensor from the Companion app changes to ringing, in_call or offhook.
Conditions
The TV is on, and the helper input_boolean.tv_was_playing is off.
Actions
Set the helper, send pause, wait for idle (two hours at most), wait two seconds, send play, clear the helper.
Requires
Home Assistant Companion app on the phone, the Android TV integration and one input_boolean helper.

Automation

alias: TV — Pause on phone call
trigger:
  - platform: state
    entity_id: sensor.your_phone_phone_state
    to: [ringing, in_call, offhook]
condition:
  - condition: state
    entity_id: remote.living_room_tv
    state: "on"
  - condition: state
    entity_id: input_boolean.tv_was_playing
    state: "off"
action:
  - action: input_boolean.turn_on
    target:
      entity_id: input_boolean.tv_was_playing
  - action: remote.send_command
    target:
      entity_id: remote.living_room_tv
    data:
      command: MEDIA_PAUSE
  - wait_for_trigger:
      - platform: state
        entity_id: sensor.your_phone_phone_state
        to: idle
    timeout: "02:00:00"
    continue_on_timeout: true
  - delay:
      seconds: 2
  - condition: state
    entity_id: input_boolean.tv_was_playing
    state: "on"
  - action: remote.send_command
    target:
      entity_id: remote.living_room_tv
    data:
      command: MEDIA_PLAY
  - action: input_boolean.turn_off
    target:
      entity_id: input_boolean.tv_was_playing

The full story: Pausing the TV Automatically for Regular Calls and Messenger

Heating off when a window opens (blueprint)

Turns a radiator off once a window has been open for a minute, and puts back its exact previous state when the window closes. Built as a blueprint, so the next room takes about 30 seconds.

Trigger
The window has been open for the chosen number of minutes, or the window closes.
Conditions
None. A quick airing never fires, because the open trigger waits for the delay.
Actions
On open: snapshot the radiator into a scene, then set it to off. On close: restore the scene.
Requires
A window sensor with device_class window and a climate entity. Tested with first-generation Mill radiators.

Blueprint: /config/blueprints/automation/homeassistant/window_heating_control.yaml

blueprint:
  name: "Window → Heating off"
  domain: automation
  input:
    window_sensor:
      selector:
        entity:
          domain: binary_sensor
          device_class: window
    climate_entity:
      selector:
        entity:
          domain: climate
    delay_minutes:
      default: 1
      selector:
        number:
          min: 0
          max: 10
          unit_of_measurement: min

mode: restart

trigger:
  - platform: state
    entity_id: !input window_sensor
    to: "on"
    for:
      minutes: !input delay_minutes
    id: opened
  - platform: state
    entity_id: !input window_sensor
    to: "off"
    id: closed

action:
  - choose:
      - conditions:
          - condition: trigger
            id: opened
        sequence:
          - action: scene.create
            data:
              scene_id: "{{ this.entity_id | replace('automation.', '') }}"
              snapshot_entities:
                - !input climate_entity
          - action: climate.set_hvac_mode
            target:
              entity_id: !input climate_entity
            data:
              hvac_mode: "off"
      - conditions:
          - condition: trigger
            id: closed
        sequence:
          - action: scene.turn_on
            target:
              entity_id: "scene.{{ this.entity_id | replace('automation.', '') }}"
            continue_on_error: true

One instance per room

- alias: "Window → Heating: bedroom"
  use_blueprint:
    path: homeassistant/window_heating_control.yaml
    input:
      window_sensor: binary_sensor.bedroom_window
      climate_entity: climate.bedroom
      delay_minutes: 1

The full story: A Home Assistant Blueprint That Stops the Heat When a Window Opens

Outdoor lights on at sunset, off at midnight

Turns the outdoor lights on 15 minutes after sunset and off at midnight, all year, without adjusting a timer when the seasons change.

Trigger
Sunset plus 15 minutes for on, and 00:00 for off.
Conditions
None.
Actions
Turn the outdoor lights on at full brightness, then off again at midnight.
Requires
Any lights in Home Assistant. In my setup that is Govee and LEDVANCE.

Two automations

- alias: Outdoor lights — Sunset on
  trigger:
    - platform: sun
      event: sunset
      offset: "+00:15:00"
  action:
    - action: light.turn_on
      target:
        entity_id:
          - light.outdoor_1
          - light.outdoor_2
      data:
        brightness_pct: 100

- alias: Outdoor lights — Midnight off
  trigger:
    - platform: time
      at: "00:00:00"
  action:
    - action: light.turn_off
      target:
        entity_id:
          - light.outdoor_1
          - light.outdoor_2

The full story: Govee and LEDVANCE Outdoor Lights on a Sunset Schedule in Home Assistant

Circadian lighting from the sun’s elevation

Every 30 minutes, and whenever a lamp is switched on, the colour temperature follows the sun: cool at noon, warm at dusk. Lamps that are off stay off.

Trigger
Every 30 minutes, or a lamp has been on for five seconds.
Conditions
None in the trigger. Inside the loop, only lamps that are already on are touched.
Actions
Turn the sun’s elevation into 2200 to 6500 K and set that colour temperature on each lamp that is on.
Requires
Lamps with colour temperature support (WiZ in my setup) and the built-in sun entity.

Automation

alias: Circadian lighting
trigger:
  - platform: time_pattern
    minutes: "/30"
  - platform: state
    entity_id:
      - light.lamp_1
      - light.lamp_2
      - light.lamp_3
      - light.lamp_4
    to: "on"
    for: "00:00:05"
variables:
  elevation: "{{ state_attr('sun.sun', 'elevation') | float(0) }}"
  color_temp_k: >
    {{ [[5000 if elevation > 45
         else ((3500 + (elevation - 15) / 30 * 1500) | int) if elevation > 15
         else ((2700 + elevation / 15 * 800) | int) if elevation > 0
         else 2200,
        2200] | max,
       6500] | min }}
action:
  - repeat:
      for_each:
        - light.lamp_1
        - light.lamp_2
        - light.lamp_3
        - light.lamp_4
      sequence:
        - if:
            - condition: template
              value_template: "{{ is_state(repeat.item, 'on') }}"
          then:
            - action: light.turn_on
              target:
                entity_id: "{{ repeat.item }}"
              data:
                color_temp_kelvin: "{{ color_temp_k }}"

The full story: WiZ Circadian Lighting That Tracks the Sun's Color Temperature

Heating down to 17 °C when everyone is out

Drops every Tado zone to 17 °C when the last person leaves and hands control back to Tado’s own schedule when the first one comes home. The presence comes from your own logic, not from Tado’s geofencing.

Trigger
The household group changes to not_home, or back to home.
Conditions
None.
Actions
Away: set every zone to 17 °C. Home: set every zone back to auto.
Requires
The Tado integration, one climate entity per zone and a group or person entity that shows who is home.

Two automations

- alias: Tado — Away setback
  trigger:
    - platform: state
      entity_id: group.household_members
      to: not_home
  action:
    - action: climate.set_temperature
      target:
        entity_id:
          - climate.zone_living_room
          - climate.zone_bedroom
          - climate.zone_office
      data:
        temperature: 17

- alias: Tado — Restore on return
  trigger:
    - platform: state
      entity_id: group.household_members
      to: home
  action:
    - action: climate.set_hvac_mode
      target:
        entity_id:
          - climate.zone_living_room
          - climate.zone_bedroom
          - climate.zone_office
      data:
        hvac_mode: auto

The full story: A Tado Heating Dashboard With card_mod That's Actually Worth Looking At

Alert when a window is open and the heating runs

Sends a push when a window has been open for 20 minutes and the zone is still heating. It catches the window nobody closed, and costs nothing to run.

Trigger
A window sensor has been on for 20 minutes.
Conditions
The matching climate entity reports hvac_action heating.
Actions
Send a push with the room name, taken from the entity ID.
Requires
Tado window sensors named binary_sensor.zone_<room>_window, matching climate.zone_<room> entities and a notify service.

Automation

alias: Tado — Open window alert
trigger:
  - platform: state
    entity_id:
      - binary_sensor.zone_living_room_window
      - binary_sensor.zone_bathroom_window
    to: "on"
    for:
      minutes: 20
condition:
  - condition: template
    value_template: >
      {{ state_attr(trigger.entity_id | replace('binary_sensor.', 'climate.') | replace('_window', ''), 'hvac_action') == 'heating' }}
action:
  - action: notify.all_devices
    data:
      title: "Window open — heating running"
      message: >
        {{ trigger.entity_id
           | replace('binary_sensor.zone_', '')
           | replace('_window', '')
           | replace('_', ' ')
           | title }} has been open for 20 minutes.

The full story: A Tado Heating Dashboard With card_mod That's Actually Worth Looking At

Vacuum when you leave, dock when you return

The vacuum starts five minutes after you leave and goes back to the dock when you come home. The five minutes filter out GPS blips, so it never starts because your phone lost signal for a moment.

Trigger
The person entity is not_home for five minutes, or changes to home.
Conditions
Start: between 09:00 and 18:00 and the vacuum is docked. Dock: the vacuum is cleaning.
Actions
Start the vacuum, or send it back to base.
Requires
Any vacuum entity (Roborock in my setup) and the Companion app for presence.

Two automations

- alias: Vacuum — Clean on departure
  trigger:
    - platform: state
      entity_id: person.your_name
      to: not_home
      for:
        minutes: 5
  condition:
    - condition: time
      after: "09:00:00"
      before: "18:00:00"
    - condition: state
      entity_id: vacuum.your_vacuum
      state: docked
  action:
    - action: vacuum.start
      target:
        entity_id: vacuum.your_vacuum

- alias: Vacuum — Dock on return
  trigger:
    - platform: state
      entity_id: person.your_name
      to: home
  condition:
    - condition: state
      entity_id: vacuum.your_vacuum
      state: cleaning
  action:
    - action: vacuum.return_to_base
      target:
        entity_id: vacuum.your_vacuum

The full story: What's Actually Useful About the Roborock Map in Home Assistant

Push notification when the mailbox opens

Every phone gets a push when the mailbox door opens. A reed switch only knows open or closed, so there are no false alarms.

Trigger
The mailbox sensor changes from off to on.
Conditions
None.
Actions
Send a notification to the notify group.
Requires
A LoRa mailbox sensor (a MailBoxGuard in my setup) and a notify group for your phones.

Automation

alias: Mailbox — Notify on delivery
trigger:
  - platform: state
    entity_id: binary_sensor.mailboxguard
    from: "off"
    to: "on"
action:
  - action: notify.all_devices
    data:
      title: "Mail in the mailbox"
      message: "Something was delivered."

The full story: MailBoxGuard: LoRa Mailbox Sensor 200 Metres from the House

Living room lights follow the TV

When a film starts, the ceiling lights go off and the accent lights drop to 15 %. Pause or switch off and everything returns to full brightness. No scene button and no voice command.

Trigger
The TV media player changes to playing, paused, or idle/off.
Conditions
The time is after 18:00.
Actions
Playing: ceiling lights off, accent lights at 15 % and 2200 K. Paused or off: all lights at 100 % and 4000 K.
Requires
A media player entity for the TV (the Android TV integration in my setup) and lights with colour temperature. Mode restart stops a quick pause and play from flashing the room.

Automation

alias: Living room lights follow the TV
mode: restart
trigger:
  - platform: state
    entity_id: media_player.living_room_tv
    to: playing
    id: playing
  - platform: state
    entity_id: media_player.living_room_tv
    to: paused
    id: paused
  - platform: state
    entity_id: media_player.living_room_tv
    to: [idle, "off"]
    id: stopped
condition:
  - condition: time
    after: "18:00:00"
action:
  - choose:
      - conditions:
          - condition: trigger
            id: playing
        sequence:
          - action: light.turn_off
            target:
              entity_id:
                - light.ceiling_1
                - light.ceiling_2
          - action: light.turn_on
            target:
              entity_id:
                - light.accent_1
                - light.accent_2
            data:
              brightness_pct: 15
              color_temp_kelvin: 2200
      - conditions:
          - condition: trigger
            id: [paused, stopped]
        sequence:
          - action: light.turn_on
            target:
              entity_id:
                - light.ceiling_1
                - light.ceiling_2
                - light.accent_1
                - light.accent_2
            data:
              brightness_pct: 100
              color_temp_kelvin: 4000

The full story: WiZ Lights That React to the TV Without a Cinema Mode Button

Run the dishwasher in the cheapest hour

One script finds the cheapest remaining hour in today’s spot prices, sets the finish time to match and starts the machine. On a typical Danish weekday that is worth one to two kroner per wash.

Trigger
None. You start the script from a dashboard button once the machine is loaded.
Conditions
None. Only hours from now onwards are considered.
Actions
Read today’s prices, pick the cheapest hour, add the programme length, set the finish time and press start.
Requires
Energi Data Service (HACS) and a connected dishwasher with a finish-time select and a start button. Remote start must be enabled on the machine itself.

Script, started from a dashboard button

alias: Dishwasher — Schedule cheapest hour
sequence:
  - variables:
      prices: "{{ state_attr('sensor.energi_data_service', 'raw_today') | default([]) }}"
      now_h: "{{ now().hour }}"
      duration_h: 2
      best_hour: >
        {% set ns = namespace(hour=none, price=999) %}
        {% for h in prices %}
          {% if as_datetime(h.hour).hour >= now_h | int and h.price < ns.price %}
            {% set ns.price = h.price %}
            {% set ns.hour = h.hour %}
          {% endif %}
        {% endfor %}
        {{ ns.hour }}
  - action: select.select_option
    target:
      entity_id: select.dishwasher_finish_at
    data:
      option: >
        {{ (as_datetime(best_hour) + timedelta(hours=duration_h)).strftime('%H:%M') }}
  - action: button.press
    target:
      entity_id: button.dishwasher_start

The full story: Scheduling a Bosch Dishwasher in Home Assistant by Electricity Price

Push the shopping list when you reach the store

When a phone enters a store zone, the automation reads the shopping list and pushes the items for that store. It stays quiet if nothing on the list belongs there.

Trigger
A phone enters one of the store zones.
Conditions
At least one open list item has a description that starts with the store name.
Actions
Look up the store name, fetch the open items, filter them by store and send a push with the list.
Requires
The eTilbudsavis integration with the patched todo.py from the post, one zone per store and the Companion app. Any to-do list works if the store name sits in the description.

Automation, two stores shown

alias: Shopping list — Push at the store
trigger:
  - platform: zone
    entity_id:
      - device_tracker.phone_1
      - device_tracker.phone_2
    zone: zone.supermarket_a
    event: enter
  - platform: zone
    entity_id:
      - device_tracker.phone_1
      - device_tracker.phone_2
    zone: zone.supermarket_b
    event: enter
variables:
  store_lookup:
    zone.supermarket_a: "Supermarket A"
    zone.supermarket_b: "Supermarket B"
  store_name: "{{ store_lookup[trigger.zone.entity_id] | default('') }}"
action:
  - action: todo.get_items
    target:
      entity_id: todo.shopping_list
    data:
      status: needs_action
    response_variable: todo_result
  - variables:
      found: >
        {% set ns = namespace(items=[]) %}
        {% for item in todo_result['todo.shopping_list']['items'] | default([]) %}
          {% if store_name != '' and item.description | default('') | regex_match(store_name) %}
            {% set ns.items = ns.items + [item.summary] %}
          {% endif %}
        {% endfor %}
        {{ ns.items }}
  - condition: template
    value_template: "{{ found | count > 0 }}"
  - action: notify.all_devices
    data:
      title: "{{ store_name }}: {{ found | count }} item(s) on the list"
      message: "{{ found | join('\n') }}"

The full story: eTilbudsavis in Home Assistant: Sorted by Store, with Proximity Alerts

Spoken morning briefing at 06:00

Reads out the weather, today’s calendar, waste collection and the electricity price on a kitchen speaker. This is a trimmed version of the one I run, which also covers traffic and the car.

Trigger
The time is 06:00.
Conditions
None. Add a weekday condition if you want quiet weekends.
Actions
Fetch today’s events, build the text in a template and speak it with tts.speak.
Requires
A calendar, a weather entity, a TTS engine and a media player. The waste and price sensors are optional, so cut those lines if you have none.

Automation, trimmed version

alias: Morning briefing — spoken at 06:00
mode: single
trigger:
  - platform: time
    at: "06:00:00"
action:
  - action: calendar.get_events
    target:
      entity_id: calendar.family
    data:
      start_date_time: "{{ today_at('00:00') }}"
      end_date_time: "{{ today_at('23:59') }}"
    response_variable: calendar_result
  - action: tts.speak
    target:
      entity_id: tts.your_tts_engine
    data:
      media_player_entity_id: media_player.kitchen_speaker
      language: en-US   # change language and message text to your own
      message: >-
        {% set events = calendar_result['calendar.family']['events'] %}
        {% set temp = state_attr('weather.forecast_home', 'temperature') %}
        {% set waste_days = states('sensor.next_waste_collection') | int(99) %}
        {% set price = states('sensor.energi_data_service') | float(0) | round(2) %}
        Good morning. It is {{ now().strftime('%A') }}.
        The temperature outside is {{ temp }} degrees.
        {% if events | length > 0 %}
        You have {{ events | length }} appointment(s) today:
        {% for event in events %}{{ event.summary }}{% if not loop.last %}, {% endif %}{% endfor %}.
        {% else %}Nothing in the calendar today.
        {% endif %}
        {% if waste_days <= 1 %}The bins are collected today.
        {% elif waste_days == 2 %}The bins are collected tomorrow.
        {% endif %}
        The electricity price is {{ price }} kroner per kilowatt hour.

The full story: A Spoken Morning Briefing in Home Assistant: Calendar, Weather, and Electricity Price