Home Assistant

Bathroom light and fan timers

Motion turns the bathroom light on. Closing the door starts a separate delay before the exhaust fan. Each has its own off timer, and humidity can hold the fan until the air drops.

Difficulty · BeginnerSetup · 30–60 minutesHA · current stable (blueprint)
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 wants two clocks. The light should follow motion and then go out. The fan should wait until the door is shut, run long enough to clear the air, and not shut off the moment someone stands still. This pack uses a motion sensor, a door contact, and two Home Assistant timers. An optional humidity sensor keeps the fan on after the motion timer if the air is still damp.

Entity ids are blueprint inputs. Do not publish which room the contact belongs to.

This is not occupancy. Wasp-in-a-box occupancy latches a room as occupied for lights and climate while the door stays shut. This pack does not do that. It turns one light and one fan on and off. A plain “off after a while” for a single relay is relay auto-off timer. Whether opening a window would dry the room faster is the humidity window-vent guide.

What problem it solves

You want the light on when someone walks in, the fan on only after the door closes, and each of them off on its own timer — including after a Home Assistant restart.

How it works

For a contact with device_class: door, on is open and off is closed.

  1. Light — motion to on turns the light on and starts the light timer (pack default 90 seconds). Further motion restarts that timer. When the timer finishes and motion is off, the light turns off. Opening the door also starts the light timer, so a door that opens as someone leaves does not leave the light on indefinitely.
  2. Fan delay — the door going to off (closed) starts the fan-delay timer (pack default 90 seconds). When that timer finishes and the door is still closed, the fan turns on and the fan-off timer starts (pack default 10 minutes). Motion alone does not start the fan. An open door cancels a pending fan delay.
  3. Fan off — the fan turns off when its timer finishes, unless the optional humidity hold is active. Opening the door does not immediately kill a fan that is already running; the off timer does. That keeps a short crack of the door from ending the exhaust.
  4. Humidity hold — if you set a humidity sensor and a floor (pack default 65%), the fan stays on while humidity is above the floor even after the off timer. When humidity falls below the floor, a short run-on (pack default 2 minutes) finishes and the fan turns off. Leave the humidity input empty to skip this.
  5. Restart — both timers are created with restore, so a restart mid-countdown still completes the off. The fan delay does not restart a fan that was already off.
  6. Manual — a bypass boolean holds automation off so a fan you switched on for painting is not turned off by the timer. Clearing the bypass does not invent a new on; the next motion or door close does.

Hardware notes

  • Motion. Any motion binary sensor, or an HC-SR501 on an ESP32 GPIO. Point it at the standing area, not at the fan blades.
  • Door. A contact that is off when the door is shut. A door left ajar never starts the fan, which is what you want if the exhaust should only run for a closed room.
  • Loads. A smart plug or relay on the fan. The light can be a light entity you already have. Do not put a fan and a light on one relay if you want the two timers.
  • Humidity. Optional AHT20 or any humidity sensor in the room air, not in the fan inlet. The hold is a floor on relative humidity, not a second climate controller.

Snippet

Light on motion, fan after the door has been closed. Timers do the offs. The blueprint fills the entity ids.

trigger:
  - platform: state
    entity_id: !input motion_sensor
    to: "on"
    id: motion
  - platform: state
    entity_id: !input door_sensor
    to: "off"
    id: door_closed
  - platform: event
    event_type: timer.finished
    event_data:
      entity_id: !input light_timer
    id: light_off
  - platform: event
    event_type: timer.finished
    event_data:
      entity_id: !input fan_delay_timer
    id: fan_on
action:
  - choose:
      - conditions:
          - condition: trigger
            id: motion
        sequence:
          - action: light.turn_on
            target:
              entity_id: !input light
          - action: timer.start
            target:
              entity_id: !input light_timer
            data:
              duration: !input light_off_after
      - conditions:
          - condition: trigger
            id: door_closed
        sequence:
          - action: timer.start
            target:
              entity_id: !input fan_delay_timer
            data:
              duration: !input fan_on_delay
      - conditions:
          - condition: trigger
            id: fan_on
          - condition: state
            entity_id: !input door_sensor
            state: "off"
        sequence:
          - action: fan.turn_on
            target:
              entity_id: !input fan
          - action: timer.start
            target:
              entity_id: !input fan_timer
            data:
              duration: !input fan_run_for

The light-off branch, the humidity hold, and the bypass are in the full blueprint.

Setup outline

  1. Create three timer helpers with restore on: light off, fan delay, fan run. Create an optional bypass boolean.
  2. Confirm motion, door closed = off, the light, and the fan in Developer Tools.
  3. Import the blueprint. Set the light-off time, the fan delay, and the fan run. Leave humidity empty for the first test.
  4. Walk in: light on. Stand still longer than the light timer: light off. Close the door, wait out the delay: fan on. Wait out the fan timer: fan off.
  5. Optional: add the humidity sensor and floor. Steam the room, confirm the fan stays past the run timer, then confirm it stops after the air falls and the run-on ends.

Troubleshooting

  • Fan never starts. The door sensor is inverted, so “closed” is on, or the door never stays closed for the whole delay. Watch the contact while the delay timer runs.
  • Light stays on. Motion is stuck on (a PIR aimed at a vent or a swaying curtain). The timer only turns the light off when motion is off.
  • Fan dies when someone stands still. Humidity hold is empty and the fan run is tied to motion. The fan timer should not require motion. Check that the off trigger is timer.finished, not motion off.
  • Restart turns the fan off late or early. The timer was created without restore. Recreate it with restore enabled and let the blueprint use that entity.
  • Manual fan will not stay on. The bypass is off, so the run timer still owns the fan. Turn the bypass on before a long manual run.

Credits

The two-timer door and motion pattern follows Bathroom light and fan automation. The optional humidity hold follows the idea in Bathroom Humidity Exhaust Fan. This write-up is an original overview of the combined timers, not a paste of either blueprint.

Changelog

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