🎥 Prefer to see it instead?
The problem #
We’ve got a bit of a problem with our washing machine.
It’s completely dumb… like most of them.
It lives out in the garage, so we never hear the “I’m finished” chime, which basically means it’s out of sight, out of mind.
I could blame our forgetfulness… but honestly, it’s easier to blame the washing machine.
What we actually want here is pretty simple.
We just want to know when the wash is finished… and get a nudge if we forget about it.
Why the obvious solution doesn’t quite work #
The first thing I tried was power monitoring.
When the power drops, the wash must be finished… right?
Sounds logical, but washing machines don’t behave that cleanly.
They ramp up and down, pause mid-cycle, and sometimes just sit there doing almost nothing before kicking back into life again.
That “doing nothing” looks exactly like “finished”.
So you end up with false alerts, missed alerts… or both.
What actually works #
What actually fixed it wasn’t more logic.
It was better signals.
Instead of trying to make one signal perfect, I started combining a few simple ones:
- power, to understand load
- vibration, to confirm movement
- lid state, to confirm someone’s actually dealt with it
None of these are perfect on their own.
But together, they give you enough context to make a much better call.
Sensors I’m using #
For this setup, I kept things pretty simple.
| Device | Type | Notes |
|---|---|---|
| ThirdReality Vibration Sensor | Zigbee | Detects spin/movement |
| ThirdReality Contact Sensor | Zigbee | Mounted on lid |
| Power Monitoring Plug | Any | Must report power usage |
If you don’t have Zigbee, their bridge is an easy way to get started:
👉 ThirdReality Smart Bridge MZ1
This lets you bring Zigbee devices into Matter ecosystems like Apple or Google.
Quick note on smart plugs #
If you’re buying a plug for this, it’s worth being a bit intentional about it.
You don’t actually need to control the washing machine. You just want to monitor it.
So ideally, you’re looking for something that does power monitoring only, without a relay.
Relay-based plugs can work, but they’re not really designed for motor loads long term. And you’re not using the switching anyway.
Personally, I’m keeping an eye on CT clamp options. That feels like the better long-term approach.
How the logic comes together #
The goal here isn’t to detect a single moment.
It’s to be confident the washing machine has actually finished.
If the power is up, or the machine is vibrating, we treat it as running. That covers most of the cycle without needing anything too clever.
Where things get tricky is when it looks like it’s finished.
Power drops. Vibration stops. Everything goes quiet.
But that’s also exactly what a soak cycle looks like.
So instead of reacting straight away, I just wait.
If it stays idle for a set period, then we call it finished. If it spins back up again, nothing happens and the timer resets.
Once that delay passes and everything is still quiet, we mark it as finished.
At that point:
- send a notification
- optionally announce it
- start a reminder loop
The part that actually makes it useful #
The reminders are what actually make this useful.
If the washing is still sitting there, it’ll just nudge you again.
Every 10 minutes.
And it stops as soon as the lid is opened.
Nothing complicated, but this is what solves the real problem.
Resetting everything #
As soon as the lid is opened, everything clears down.
If a new cycle starts before that, it resets itself automatically.
So the system just stays in sync without you needing to think about it.
The helpers behind it #
Before we get into the automations, we need a few helpers.
Nothing fancy here, just some simple building blocks so we can track state and control behaviour without hardcoding everything.
You can create these in the UI:
Settings → Devices & Services → Helpers → Create Helper
(This looks like a lot, but it’s really just a few helpers to make the logic easier to manage.)
Core state helpers #
| Name | Entity | Type | Purpose |
|---|---|---|---|
| Washer Running | input_boolean.washer_running |
Toggle | Tracks when a cycle is actively running |
| Washer Finished | input_boolean.washer_finished |
Toggle | Tracks when the wash has finished but hasn’t been emptied |
Timers #
| Name | Entity | Type | Purpose |
|---|---|---|---|
| Washer Finish Delay | timer.washer_finish_delay |
Timer | Prevents soak cycles being treated as finished |
| Washer Reminder Timer | timer.washer_reminder_timer |
Timer | Drives the repeat reminder loop |
Power thresholds #
| Name | Entity | Type | Purpose |
|---|---|---|---|
| Washer Running Power Threshold | input_number.washer_running_power_threshold |
Number | Above this = running |
| Washer Finish Power Threshold | input_number.washer_finish_power_threshold |
Number | Below this = idle/finished |
These will vary depending on your washing machine.
As a rough starting point:
- Running: ~20W+
- Finished: ~10W or lower
You’ll likely need to tweak these once you see your real power graph.
Quiet hours #
| Name | Entity | Type | Purpose |
|---|---|---|---|
| Quiet Hours Start | input_datetime.quiet_hours_start |
Time | When speaker announcements should stop |
| Quiet Hours End | input_datetime.quiet_hours_end |
Time | When they can resume |
This just stops your house yelling “washing machine finished” at 2am.
You’ll still get phone notifications during this time.
Optional (not required) #
| Name | Entity | Type | Purpose |
|---|---|---|---|
| Washing Machine State | input_select.washing_machine_state |
Select | Optional UI/state tracking |
| Washing Loads | counter.washing_loads |
Counter | Optional tracking |
You don’t need these for the automation to work, but they’re useful if you want to build this out further later.
The nice thing about doing it this way is you can tweak behaviour without touching the automations.
Change a threshold, adjust a timer, tweak quiet hours… everything just adapts.
The automation logic #
You don’t need to copy this line-for-line, but these examples show how the pieces fit together.
You will need to swap in your own entity names, especially the power sensor, vibration sensor, lid sensor, notification service, presence group, TTS engine, and speaker.
Quick note:
In my actual setup, this all lives in a single automation with multiple branches.
I’ve broken it out here purely to make the logic easier to follow.
If you’re just getting started, splitting things like this can make debugging a lot easier.
Once you’re comfortable, you can absolutely consolidate it back into one.
1. Detect when the washer is running #
This marks the washer as running when either the power rises above the running threshold or vibration is detected.
It also cancels any finish or reminder timers, because a new cycle or resumed activity means the old “finished” logic no longer applies.
Automation: Washer Running Detection
# Replace these entities with your own:
# - sensor.laundry_washing_machine_plug_power
# - binary_sensor.laundry_washing_machine_vibration
# - input_number.washer_running_power_threshold
# - input_boolean.washer_running
# - input_boolean.washer_finished
# - timer.washer_finish_delay
# - timer.washer_reminder_timer
alias: Laundry - Washer - Running Detection
description: >
Marks the washing machine as running when power rises above the running
threshold or vibration is detected.
mode: queued
max: 10
trigger:
- platform: numeric_state
entity_id: sensor.laundry_washing_machine_plug_power
above: input_number.washer_running_power_threshold
id: power_rose_above_running_threshold
- platform: state
entity_id: binary_sensor.laundry_washing_machine_vibration
to: "on"
id: vibration_detected
condition: []
action:
- service: timer.cancel
target:
entity_id:
- timer.washer_finish_delay
- timer.washer_reminder_timer
- service: input_boolean.turn_on
target:
entity_id: input_boolean.washer_running
- service: input_boolean.turn_off
target:
entity_id: input_boolean.washer_finished2. Detect when the washer may be finished #
This is where the soak cycle problem is handled.
When power drops below the finish threshold, or vibration has cleared for a while, the automation checks whether the washer is still meant to be running. If it is, and both power and vibration are quiet, it starts a finish delay.
If everything is still quiet when that timer finishes, the washer is marked as finished.
Automation: Washer Finish Detection
# Replace these entities with your own:
# - sensor.laundry_washing_machine_plug_power
# - binary_sensor.laundry_washing_machine_vibration
# - input_number.washer_finish_power_threshold
# - input_boolean.washer_running
# - input_boolean.washer_finished
# - timer.washer_finish_delay
# - timer.washer_reminder_timer
# - notify.mobile_app_*
# - group.family
# - tts.piper
# - media_player.*
alias: Laundry - Washer - Finish Detection
description: >
Starts a finish delay when power is low and vibration has stopped. If the
washer is still idle when the timer completes, it marks the wash as finished.
mode: queued
max: 10
variables:
power: "{{ states('sensor.laundry_washing_machine_plug_power') | float(0) }}"
vibrating: "{{ is_state('binary_sensor.laundry_washing_machine_vibration', 'on') }}"
finish_threshold: "{{ states('input_number.washer_finish_power_threshold') | float(0) }}"
quiet_hours: >
{% set start = states('input_datetime.quiet_hours_start') %}
{% set end = states('input_datetime.quiet_hours_end') %}
{% set now_time = now().strftime('%H:%M:%S') %}
{% if start <= end %}
{{ start <= now_time <= end }}
{% else %}
{{ now_time >= start or now_time <= end }}
{% endif %}
trigger:
- platform: numeric_state
entity_id: sensor.laundry_washing_machine_plug_power
below: input_number.washer_finish_power_threshold
id: power_fell_below_finish_threshold
- platform: state
entity_id: binary_sensor.laundry_washing_machine_vibration
to: "off"
for: "00:01:30"
id: vibration_cleared_for_1m30s
- platform: event
event_type: timer.finished
event_data:
entity_id: timer.washer_finish_delay
id: finish_timer_completed
condition: []
action:
- choose:
- alias: Start finish timer
conditions:
- condition: trigger
id:
- power_fell_below_finish_threshold
- vibration_cleared_for_1m30s
- condition: state
entity_id: input_boolean.washer_running
state: "on"
- condition: template
value_template: "{{ power < finish_threshold and not vibrating }}"
sequence:
- service: timer.start
target:
entity_id: timer.washer_finish_delay
data:
duration: "00:10:00"
- alias: Mark as finished and notify
conditions:
- condition: trigger
id: finish_timer_completed
- condition: state
entity_id: input_boolean.washer_running
state: "on"
- condition: template
value_template: "{{ power < finish_threshold and not vibrating }}"
sequence:
- service: input_boolean.turn_off
target:
entity_id: input_boolean.washer_running
- service: input_boolean.turn_on
target:
entity_id: input_boolean.washer_finished
- service: notify.mobile_app_steve
data:
title: Washing machine finished
message: The washing machine has finished.
- choose:
- conditions:
- condition: state
entity_id: group.family
state: home
- condition: template
value_template: "{{ not quiet_hours }}"
sequence:
- service: tts.speak
target:
entity_id: tts.piper
data:
cache: true
media_player_entity_id: media_player.dining_speaker_2
message: The washing machine has finished.
- service: timer.start
target:
entity_id: timer.washer_reminder_timer
data:
duration: "00:10:00"3. Repeat reminders until the washing is removed #
Once the washer is marked as finished, the reminder timer keeps looping.
It checks that the washer is still marked as finished and that the lid is still closed. If both are true, it sends another reminder and starts the timer again.
Automation: Washer Reminder Loop
# Replace these entities with your own:
# - binary_sensor.laundry_washing_machine_lid_contact
# - input_boolean.washer_finished
# - timer.washer_reminder_timer
# - notify.mobile_app_*
# - group.family
# - tts.piper
# - media_player.*
alias: Laundry - Washer - Reminder Loop
description: >
Repeats reminders while the washer is marked as finished and the lid remains
closed.
mode: queued
max: 10
variables:
quiet_hours: >
{% set start = states('input_datetime.quiet_hours_start') %}
{% set end = states('input_datetime.quiet_hours_end') %}
{% set now_time = now().strftime('%H:%M:%S') %}
{% if start <= end %}
{{ start <= now_time <= end }}
{% else %}
{{ now_time >= start or now_time <= end }}
{% endif %}
trigger:
- platform: event
event_type: timer.finished
event_data:
entity_id: timer.washer_reminder_timer
id: reminder_timer_completed
condition:
- condition: state
entity_id: input_boolean.washer_finished
state: "on"
- condition: state
entity_id: binary_sensor.laundry_washing_machine_lid_contact
state: "off"
action:
- service: notify.mobile_app_steve
data:
title: Washing machine reminder
message: The washing machine is finished.
- choose:
- conditions:
- condition: state
entity_id: group.family
state: home
- condition: template
value_template: "{{ not quiet_hours }}"
sequence:
- service: tts.speak
target:
entity_id: tts.piper
data:
cache: true
media_player_entity_id: media_player.dining_speaker_2
message: The washing machine is finished.
- service: timer.start
target:
entity_id: timer.washer_reminder_timer
data:
duration: "00:10:00"4. Clear everything when the lid opens #
The lid is the final confirmation that someone has actually dealt with the washing.
Once it opens, the finished state is cleared and the reminder timers are cancelled.
Automation: Washer Lid Reset
# Replace these entities with your own:
# - binary_sensor.laundry_washing_machine_lid_contact
# - input_boolean.washer_running
# - input_boolean.washer_finished
# - timer.washer_finish_delay
# - timer.washer_reminder_timer
alias: Laundry - Washer - Lid Reset
description: >
Clears the washer finished state and cancels timers when the lid is opened
after the wash is complete.
mode: single
trigger:
- platform: state
entity_id: binary_sensor.laundry_washing_machine_lid_contact
to: "on"
id: lid_opened
condition:
- condition: or
conditions:
- condition: state
entity_id: input_boolean.washer_finished
state: "on"
- condition: state
entity_id: timer.washer_finish_delay
state: active
action:
- service: input_boolean.turn_off
target:
entity_id:
- input_boolean.washer_running
- input_boolean.washer_finished
- service: timer.cancel
target:
entity_id:
- timer.washer_finish_delay
- timer.washer_reminder_timerHow it behaves in real life #
Once this is in place, it’s one of those automations you stop thinking about.
You get a notification when the wash actually finishes.
If you ignore it, you’ll get reminded.
If no one’s home, it waits.
And it won’t start announcing things in the middle of the night.
It just quietly does its job.
The bigger takeaway #
This works well for a washing machine, but the idea applies more broadly.
Single signals are fragile.
Once you start combining context, everything becomes a lot more reliable.
That’s really where Home Assistant shines.
Where to go next #
If you want to extend this:
- add speaker announcements
- apply the same logic to your dryer
- build a simple dashboard
- look into CT clamp monitoring