Home AssistantESPHome

Relay auto-off timer

Turning on a switch, relay, or smart plug starts a Home Assistant timer, writes the planned off time to an input_datetime for dashboards, cancels on manual off, and still finishes after a HA restart.

Difficulty · BeginnerSetup · 20–40 minutesHA · current stable (blueprint)ESPHome · current stable
Get the pack · from $19Have us set it up

Some hardware links on this page are affiliate links. As an Amazon Associate I earn from qualifying purchases. We may earn a commission if you buy through them, at no extra cost to you. See the affiliate disclosure.

A bathroom fan, a soldering iron, or a heater on a plug should not still be on three hours later because someone walked out. This workflow binds a switch (ESP-01S relay, a smart plug, a fan entity) to a Home Assistant timer helper: turn the device on and the timer starts for a duration you set; the pack also writes now + duration into an input_datetime so a dashboard can show the planned off clock. Turn the device off by hand and the timer is cancelled. When the timer finishes, the device turns off. The timer is created with restore, so a Home Assistant restart mid-countdown still has a remaining time and still turns the relay off.

Entity ids are blueprint inputs. Do not publish a live plug name.

What problem it solves

You want “on means it will go off” — a visible end time on a dashboard, no leftover timer after a manual off, and no forgotten load after HA reboots.

How it works

  1. Device on — switch / light / fan goes on. If the timer is idle, timer.start with the default duration (or a remaining duration you compute to a fixed clock time). Then set input_datetime.planned_off to now + remaining so a glance card can show a real timestamp, not just a ring.
  2. Device off (manual) — if the timer is still active, timer.cancel. Clear or leave the datetime (pack default: clear). Nothing else runs; you already turned it off.
  3. Timer finishes — timer goes from active to idle because it expired (not because you cancelled). homeassistant.turn_off on the device. That is the auto-off.
  4. Restart — create the timer helper with Restore enabled (Helpers UI, or restore: true in YAML). HA puts the timer back in active with remaining time. When it later hits idle, step 3 still runs. An automation delay would have been forgotten; a restored timer is not.
  5. Duration vs clock — pick one mode per instance. Duration: “always 30 minutes from on.” Clock: “off at 22:30,” duration computed as seconds until that time, wrapping past midnight. Both write the same datetime helper so the dashboard does not care which mode you chose.

Do not also put an off_delay on the ESPHome switch if the HA timer owns the off. Two timers fight.

Hardware notes

  • Any HA switch. A smart plug, a fan, a GPIO relay already adopted. The pack does not care about the transport.
  • ESP-01S relay. Common 5 V module: GPIO0 or GPIO2 driving the relay, flash via USB-TTL once, then OTA. Keep mains in a proper enclosure; this is a dry-contact pattern, not a lesson in mains wiring.
  • Loads. Match the relay or plug to the load. A heater or iron wants a rated plug, not a hobby relay on a breadboard.
  • No extra hub. If the entity already toggles in HA, this is a timer, a datetime helper, and a blueprint.

Snippet

The pack ships a blueprint. Inputs replace real entity ids:

trigger:
  - platform: state
    entity_id: !input relay_switch
    to: "on"
    id: started
  - platform: state
    entity_id: !input relay_switch
    to: "off"
    id: stopped
  - platform: state
    entity_id: !input off_timer
    from: active
    to: idle
    id: expired
action:
  - choose:
      - conditions:
          - condition: trigger
            id: started
        sequence:
          - service: timer.start
            target:
              entity_id: !input off_timer
            data:
              duration: !input default_duration
          - service: input_datetime.set_datetime
            target:
              entity_id: !input planned_off
            data:
              datetime: >
                {{ (now() + timedelta(seconds=duration_s)).strftime('%Y-%m-%d %H:%M:%S') }}
      - conditions:
          - condition: trigger
            id: stopped
        sequence:
          - service: timer.cancel
            target:
              entity_id: !input off_timer
      - conditions:
          - condition: trigger
            id: expired
          - condition: state
            entity_id: !input relay_switch
            state: "on"
        sequence:
          - service: homeassistant.turn_off
            target:
              entity_id: !input relay_switch

Timer helper (restore is the restart-safe part):

timer:
  relay_auto_off:
    name: Relay auto-off
    duration: "00:30:00"
    restore: true

Optional ESPHome relay (credentials stay in secrets.yaml):

switch:
  - platform: gpio
    pin: GPIO0
    name: "Utility relay"
    id: utility_relay
    restore_mode: RESTORE_DEFAULT_OFF

Setup outline

  1. Confirm the switch entity toggles from HA. Create a timer helper with Restore on, and an input_datetime (date and time).
  2. Import the blueprint. Fill switch, timer, datetime, and either a duration or a clock-off time.
  3. Turn the switch on. Confirm: timer active, datetime is now + duration, dashboard card shows that clock.
  4. Test the three paths: wait it out → switch off; toggle off early → timer cancelled; turn on, restart HA, wait the remainder → switch still goes off.

Troubleshooting

  • Timer never starts. You turned the switch on from the same automation that starts the timer in a loop, or the entity is a binary_sensor, not a switch. Trigger must be the device you touch.
  • Manual off leaves the timer running. The off trigger is missing, or you used timer.finish (that looks like an expiry and will bounce the off action). Use timer.cancel on manual off.
  • Off time blank after reboot. The datetime helper was written, but you looked at a timer-only card. Put the input_datetime on the dashboard; the restored timer is the authority for remaining seconds.
  • Forgot to turn off after a restart. Restore is off on the helper (Helpers → the timer → Restore). delay: in an automation will not come back; the pack’s timer will.
  • Relay chatters. Two automations own the same switch (ESPHome off_delay plus this pack). Pick one off path.

Credits

Based on the community blueprints Sync Device and Timer and Sync Device and Scheduled Off-Time. This write-up is an original overview of the restore-safe timer plus planned-off datetime pattern.

Changelog

v1.0 · Oct 17, 2026: First publish.