Trigger on Washing Machine finish

Here’s something simple that you can experiment with and enhance.

- alias: example 1
  trigger:
  - platform: numeric_state
    entity_id: sensor.washingmachinepower
    above: 500
    for: "00:01:00"
  action:
  - wait_for_trigger:
    - platform: state
      entity_id: sensor.washingmachinepower
      to: 0
      for: "00:00:05"
  - service: persistent_notification.create
    data:
      title: "{{ now().timestamp() | timestamp_local() }}"
      message: "Washing is done."

How it works:

  • It uses a Numeric State Trigger to trigger when power exceeds 500 and remains above 500 for a duration of at least a minute. You can adjust the duration to suit your needs. The point of using for: is to ensure it doesn’t trigger due to a spurious, momentary power spike.

  • After it triggers, it proceeds to execute action: where it waits for another trigger, a State Trigger, when the power drops to 0 and remains 0 for a duration of 5 seconds (adjust to suit your needs or even eliminate it if you feel it’s not needed).

  • Finally, it calls the persistent_notification service to post a message in the UI consisting of the current date and time and a brief description (change this to whatever service you prefer).

You can enhance wait_for_trigger with a wait_timeout to protect from waiting forever should, for some unexpected reason, the power never return to 0.


Washer Monitor

If you’re interested, I’m currently doing something a bit more sophisticated for my washing machine. Based on its power consumption characteristics over an entire washing cycle, I’m inferring what it’s doing.

I gathered data for five wash cycles and discovered that I could not determine the difference between power consumed during washing and rinsing because their respective power ranges overlapped (i.e. the same power consumption is reported for washing and rinsing).

Here’s a sample waveform of the stop/fill/wash/spin/drain phases followed by fill/wait phases (the trough) and then the rinse/spin/drain/stop phases.

The resulting Template Sensor can report:

- stop (no power consumed)
- fill (filling water for either washing or rinsing)
- run (agitation for either washing or rinsing phase)
- pulse (representing the power spike when the spin cycle begins after washing or rinsing)
- wait (short waiting period before the rinse cycle begins)

However it can’t differentiate between run being a wash or a rinse purely on power consumption (or fill or pulse).

The solution is an automation, triggered by changes to the Template Sensor, that steps through the discrete phases of a normal wash cycle:

      - 'stop'
      - 'wash fill'
      - 'wash'
      - 'wash spin'
      - 'wash drain'
      - 'rinse fill'
      - 'rinse wait'
      - 'rinse'
      - 'rinse spin'
      - 'rinse drain'
      - 'unknown'

The phase are stored in an input_select and the automation steps through them based on the Template Sensor’s previous state and current state. In other words, if the Template Sensor changes from stop to fill, the automation is triggered and sets the input_select to wash fill. When it changes from fill to run, the input_select is set to wash. From run to pulse, sets it to wash spin and so on and so on.

This blog post by Phil Hawthorne inspired me to use an automation and input_select to report the washer’s current operating phase. I simply adapted it to use a Template Sensor because of the inability to distinguish between washing and rinsing phases directly from the current power consumption.

NOTE

The associated Template Sensor and automation are posted below.

14 Likes

My washing machine is plugged on a TPLink HS110.
I’m using the consumption to detect start of wash cycle and end of it.
I use an input boolean to remember if a cycle is in progress. (called 'lavage") This lets me show the status of washing machine (for instance, if I ran a cycle, went away, my wife comes home and can see it’s in progress. Washer is in the basement)

Beginning of a cycle is consumption going over 30W. Could be more 500W for instance but I found this value enough to avoid any false positive.
End of a cycle is consumption going under 3W for 5mn. Pauses during cycle never drop so low for so long. Anyway, there’s a 1mn delay before you can open it…
You’ll have to check what your machine does. 0 isn’t a good value as there’s always a little bit power used (around 0.5W in standby, up to 5W when delayed start is active, around 2W when on)

2 automation, start and end :

- alias: 'A_ TEK Lavage début'
  mode: single
  trigger:
    - platform: numeric_state
      entity_id: switch.lave_linge
      attribute: current_power_w 
      above: 30
  condition:
    - condition: state
      entity_id: input_boolean.lavage
      state: 'off'
  action:
    service: input_boolean.turn_on
    entity_id: input_boolean.lavage

- alias: 'A_ TEK Lavage fin'
  mode: restart
  trigger:
    - platform: numeric_state
      entity_id: switch.lave_linge
      attribute: current_power_w 
      below: 3
      for:
        minutes: 5
  condition:
    - condition: state
      entity_id: input_boolean.lavage
      state: 'on'
  action:
    - service: light.turn_on
      data:
        entity_id: light.gateway_light_7811dcb06b6b
        brightness: 60
        rgb_color: [255, 255, 0]
    - service: input_boolean.turn_off
      entity_id: input_boolean.lavage
    - wait_template: "{{ is_state('binary_sensor.somebody_home', 'on') }}"
    - service: xiaomi_aqara.play_ringtone
      data:
        gw_mac: 7811dcb06b6b
        ringtone_id: 12
        ringtone_vol: 10
    - delay: 00:30:00
    - service: light.turn_off
      data:
        entity_id: light.gateway_light_7811dcb06b6b

Note that the “end” automation is a restart one, because it can last long (wait template until someone is home + 30mn) and it happens that another quick cycle is started at the end of the main (example : drying cycle )

This is another simple recipe that has all kinds of use cases.

I use a Tuya CE Smart Plug from Costco flashed with Tasmota/MQTT. After observing several different types of cycles (Normal, Bulky, Rinse etc) using History, I determined all I have to do is wait for the plug to go to trigger a current greater than the quiescent current + some (.75 Amps) and then wait for the current to go less that the quiescent current (.3 Amps) for at least 10 Minutes. The 10 minutes is less than any of the fill, wash, drain, spin actions. This will be different for each Washing Machine model.

I used the Tasmota command “TelePeriod 10” to send the power telemetry every 10 seconds. The magic in this recipe is the mode: restart which causes the automation to restart on each action.

alias: Alert Washing Machine Done
description: ''
trigger:
  - platform: numeric_state
    entity_id: sensor.washing_machine_energy_current
    above: '.75'
condition: []
action:
  - wait_for_trigger:
      - platform: numeric_state
        entity_id: sensor.washing_machine_energy_current
        below: '.3'
        for: '00:10'
    continue_on_timeout: false
  - service: notify.notify
    data:
      title: Washing machine
      message: 'Washing machine done, ready for the dryer'
  - service: tts.google_translate_say
    data:
      entity_id: all
      message: 'Washing machine done, ready for the dryer'
mode: restart
1 Like

Wouldn’t it be fairly simple to just add a esp behind the plastic and “read” the LEDs in the front panel?

We don’t have these luxury problems, our washing machine beeps so loud that the neighborhood knows it’s done, and it doesn’t stop beeping for like 30 minutes.

Could you share your automation? I’ve been collecting the power consumption profile of my washer and dryer and would like to map the numbers to your code if possible

Thanks

Here’s the Template Sensor that interprets the washer’s power consumption and reports an operating state. If it receives a power value that doesn’t correspond to a known range, it simply reports its previous state. For my washing machine, anything in the range of about 10-100 watts doesn’t correspond to a known operating state and is probably a spurious value. This Template Sensor only reports:

  • stop (0 W)
  • fill (3 to 9 W)
  • run (100 to 520 W)
  • pulse (over 520 W)
  • wait (1 or 2 W)

Template Sensor

    washer_state:
      friendly_name: Washer State
      value_template: >
        {% set s = states('sensor.washer_state') %}
        {% set p = states('sensor.washer_power') %}
        {% if p == 'unavailable' %} unavailable
        {% else %}
          {% set p = p | int %}
          {% if p == 0 %} stop
          {% elif p < 3 %} wait
          {% elif 3 <= p <= 9 %}
            {{ 'fill' if s in ['stop', 'run'] else s }}
          {% elif 100 < p < 520 %} run
          {% elif p > 520 %} pulse
          {% else %} {{s}}
          {% endif %}
        {% endif %}

Automation

The Template Sensor cannot tell the difference if “run” means the machine is washing or rinsing. The same for “fill”, it can’t tell if the machine is filling water for a wash or a rinse. That’s the automation’s job; it interprets the Template Sensor’s change of states into the machine’s true operating state (it sets an input_select):

  • stopped
  • filling water for washing
  • washing
  • spinning after a wash
  • draining the water after a wash
  • filling water for rinsing
  • waiting
  • rinsing
  • spinning after a rinse
  • draining the water after a rinse
  • stopped
- alias: Washer Operation
  trigger:
  - platform: state 
    entity_id: sensor.washer_state
  action:
    - service: input_select.select_option
      data:
        entity_id: input_select.washer_state
        option: >
          {% set s = states('input_select.washer_state') %}
          {% set fr = trigger.from_state.state %}
          {% set to = trigger.to_state.state %}
          {% if fr == 'stop' and to == 'fill' %} wash fill
          {% elif fr == 'fill' and to == 'run' %} wash
          {% elif fr == 'stop' and to == 'run' %} wash
          {% elif fr == 'run' and to == 'pulse' and s == 'wash' %} wash spin
          {% elif fr == 'pulse' and to == 'run' and s == 'wash spin' %} wash drain
          {% elif fr == 'run' and to == 'fill' %} rinse fill
          {% elif fr in ['fill', 'run'] and to == 'wait' %} rinse wait
          {% elif fr == 'wait' and to == 'run' %} rinse
          {% elif fr == 'run' and to == 'pulse' and s == 'rinse' %} rinse spin
          {% elif fr == 'pulse' and to == 'run' and s == 'rinse spin' %} rinse drain
          {% elif fr in ['run', 'fill', 'wait', 'unknown'] and to == 'stop' %} stop
          {% else %} unknown
          {% endif %}
7 Likes

Thanks for this.

My washer has a baseline of 5W even when it is doing nothing. I haven’t sat there watching the cycles but should do it to adjust the states if necessary. My power profile is 15, 210, 240, 15, 150, 9, 165 and finally 275 (probably the max extract spin cycle) before going back to 5. MQTT messages are sent every 5 minutes and it may be worth changing it to a faster rate temporarily to establish a baseline.

My adjusted thresholds look like this

Is the thought to use the input selector to send notifications?

Thanks

The input_selector is used to indicate the washer’s current operating phase:

      - 'stop'
      - 'wash fill'
      - 'wash'
      - 'wash spin'
      - 'wash drain'
      - 'rinse fill'
      - 'rinse wait'
      - 'rinse'
      - 'rinse spin'
      - 'rinse drain'
      - 'unknown'
      - 'soak'

When the machine is washing it uses between 320 and 420 watts (depends on whether it was set to hand-wash, regular, or heavy-duty). When it’s spinning/draining it’s between 335 and 525. Similarly, when rinsing it’s between 310 and 380. All of these power ranges overlap so if it’s currently reporting 350 watts, is it washing, spinning, or rinsing? You can’t tell the difference, all you can say is it’s in a “run” phase.

The automation’s job is to interpret the Template Sensor’s changes of state into the actual operating phases and set the input_select accordingly. For example, when the Template Sensor changes from ‘stop’ to ‘fill’ that’s the initial filling of water for the wash phase so the input_select is set to ‘wash fill’. A change from ‘fill’ to ‘run’ means ‘wash’ phase has started. From ‘run’ to ‘pulse’ means ‘wash spin’ and so on and so on.

For notifications, I have an automation that checks when the input_select changes from ‘rinse drain’ to ‘stop’. That’s the last phase of the cleaning process.

I’ve also added detection for a ‘soak’ phase. Sometimes I set the machine to pre-wash, where it does a very short wash and then leaves the clothes soaking in the wash water. It remains in ‘soak’ phase until you set the machine to a normal wash. The problem is sometimes I forget and it soaks for an hour (or much longer). Now I’ve set an announcement to report when the machine is in ‘soak’ for more than 20 minutes.

Thanks for the elaborate explanation.

I might start with reliably reporting when the washer is done and then get into more elaborate analysis. Which means watching the sequence of cycles and matching them to the input selector sequence rather than just the final drop from 275 to 5 watts.

i used this code to get the state.
image

config

#               TP Link HS110 switch en energie    #
####################################################
tplink:
 switch:           
   - host: !secret ip_tplink_wasmashine
input_number: ######################################
  kosten_per_kw:
    name: Kosten per KW/h
    initial: 0.27
    min: 0
    max: 100
    step: 0.01
    mode: box
input_select: ######################################
 state_wasmachine:
  name: Wasmachine state
  icon: mdi:tumble-washingmachine
  options:
    - Standby
    - Voorwas
    - Spoelen
    - Wassen
    - Centrifugeren
    - Kreukbeveiliging
    - Klaar
    - Uit
sensor: ############################################
 - platform: template
   sensors:
     wasmachine_amps:
       value_template: '{{ states.switch.wasmachine.attributes["current_a"] | replace(" A", "") | float }}'
       unit_of_measurement: 'A'
     wasmachine_watts:
       value_template: '{{ states.switch.wasmachine.attributes["current_power_w"] | replace(" W", "") | float }}'
       unit_of_measurement: 'W'
     wasmachine_kw:
       value_template: '{{ states.switch.wasmachine.attributes["total_energy_kwh"] | replace(" kW", "") | float }}'
       unit_of_measurement: 'kW'
     wasmachine_volts:
       value_template: '{{ states.switch.wasmachine.attributes["voltage"] | replace(" V", "") | float }}'
       unit_of_measurement: 'V'   
     wasmachine_today_energy:
       value_template: '{{ states.switch.wasmachine.attributes["today_energy_kwh"] | replace(" kW", "") | float }}'
       unit_of_measurement: 'kW' 

 - platform: template
   sensors:
     wasmachine_kosten_dag:
       friendly_name: "wasmachine koster per dag"
       unit_of_measurement: '€'
       icon_template: mdi:currency-eur
       value_template: "{{ ((states('sensor.wasmachine_today_energy') | float) * (states('input_number.kosten_per_kw') | float)) | round(2) }}"
automation: ########################################
#                      Wasmashine detectie         #
#################################################### 
  - alias: wasmachine inschakelen
    trigger:
      platform: state
      entity_id: switch.wasmachine
      to: 'on'
    action:
      - service: input_select.select_option
        data:
          entity_id: input_select.state_wasmachine
          option: 'Standby'
  
  - alias: wasmachine uitschakelen
    trigger:
      platform: state
      entity_id: switch.wasmachine
      to: 'off'
    action:
      - service: input_select.select_option
        data:
          entity_id: input_select.state_wasmachine
          option: 'Uit'

  - alias: wasmachine net aan
    trigger:
     - above: 750
       entity_id: sensor.wasmachine_watts
       for: 00:01:00
       platform: numeric_state
     - platform: state
       entity_id:
         - input_select.select_option
       from: 'Standby' 
    action:
      - service: input_select.select_option
        data:
          entity_id: input_select.state_wasmachine
          option: 'Wassen'
      - service: tts.google_translate_say
        data:
          entity_id: group.all_tts
          message: 'Ga jij wat leuks doen? Dan doe ik de was. Als de washingmachine klaar is geef ik een seintje'

  - id: wasmachine_washing
    alias: 'Wasmashine - Wassen'
    trigger:
     - above: 750
       entity_id: sensor.wasmachine_watts
       for: 00:01:00
       platform: numeric_state
    action:
      - service: timer.start
        entity_id: timer.wasmachine
      - service: input_select.select_option
        data:
          entity_id: input_select.state_wasmachine
          option: 'Wassen'

  - id: wasmachine_wassen
    alias: 'Wasmashine - Spoelen'
    trigger:
     - above: 50
       below: 140
       entity_id: sensor.wasmachine_watts
       for: 00:02:00
       platform: numeric_state
    action:
      - service: input_select.select_option
        data:
          entity_id: input_select.state_wasmachine
          option: 'Spoelen'

  - id: wasmachine_centrifugeren
    alias: 'Wasmashine - Centrifugeren'
    trigger:
     - above: 140
       below: 750
       entity_id: sensor.wasmachine_watts
       for: 00:02:00
       platform: numeric_state
    action:
      - service: input_select.select_option
        data:
          entity_id: input_select.state_wasmachine
          option: 'Centrifugeren'

  - id: wasmachine_centrifugeren
    alias: 'Wasmashine - Centrifugeren'
    trigger:
     - above: 140
       below: 750
       entity_id: sensor.wasmachine_watts
       for: 00:02:00
       platform: numeric_state
    action:
      - service: input_select.select_option
        data:
          entity_id: input_select.state_wasmachine
          option: 'Centrifugeren'

  - id: wasmachine_ready
    alias: 'Wasmashine - klaar'
    trigger:
     - above: 3
       below: 30
       entity_id: sensor.wasmachine_watts
       for: 00:02:00
       platform: numeric_state
    action:
      - service: timer.cancel
        entity_id: timer.wasmachine
      - service: input_select.select_option
        data:
          entity_id: input_select.state_wasmachine
          option: 'Klaar'
      - service: tts.google_translate_say
        data:
          entity_id: group.all_tts
          message: 'De wasmachine is klaar. Je kan energie besparen door hem uit te zetten.'

  - id: wasmachine_standby
    alias: 'Wasmashine - standby state'
    trigger:
     - below: 3
       entity_id: sensor.wasmachine_watts
       for: 00:02:00
       platform: numeric_state
    action:
     - service: input_select.select_option
       data:
         entity_id: input_select.state_wasmachine
         option: 'Standby'

Lovelace wasmachine card

elements:
  - entity: switch.wasmachine
    icon: 'mdi:flash-circle'
    tap_action:
      action: toggle
    style:
      right: 0.5%
      top: 6%
      '--paper-item-icon-color': green
    type: state-icon
  - type: state-label
    entity: input_select.state_wasmachine
    style:
      color: white
      font-size: 10px
      left: 50%
      top: 6.5%
  - type: state-label
    entity: sensor.wasmachine_watts
    style:
      bottom: 9%
      left: 6%
      font-size: 10px
      color: gray
      font-weight: 400
      transform: none
      max-width: 1px
  - type: state-label
    entity: sensor.wasmachine_today_energy
    style:
      bottom: 3%
      left: 6%
      font-size: 14px
      color: gray
      font-weight: 400
      transform: none
      max-width: 1px
  - type: state-label
    entity: sensor.wasmachine_kosten_dag
    style:
      bottom: 3%
      left: 40%
      font-size: 14px
      color: gray
      font-weight: 400
      transform: none
      max-width: 1px
image: local/wasmashine.png
type: picture-elements

Lovelace price card

type: entities
entities:
  - entity: input_number.kosten_per_kw

1 Like

Thank you for laying this out, just have a couple of questions.
I was able to translate all state option but these.
- Kreukbeveiliging (wrinkle/crease)
- Klaar (clear)
- Uit
Looked them up on the translate platform but not sure how they apply to laundry.
Also how are the states determined to start with.
Thank you
carltonb

1 Like

i hope i dit the translation oké

options:
- Standby = Standby (power plug turn on but washing machine off)
- Voorwas = Prewash
- Spoelen = Rinse
- Wassen = Washing
- Centrifugeren = Spin
- Kreukbeveiliging = wrinkle protection
- Klaar = Done
- Uit = Off (power plug turn off)

That is perfect, thank you.

Hello @ielbury,

I am trying your code, but it is not triggering the automation. Please check where I am making mistake. Thanks

I am testing by setting “for” time to 30 seconds.

- id: '1622563811541'
  alias: 'Washing Machine automation '
  description: ''
  trigger:
  - platform: numeric_state
    entity_id: sensor.sonoff_1000f417f4_power
    attribute: power
    for: 00:00:30
    above: '1'
  condition: []
  action:
  - wait_for_trigger:
    - platform: numeric_state
      entity_id: sensor.sonoff_1000f417f4_power
      below: '.3'
      for: 00:00:30
      attribute: power
    continue_on_timeout: false
  - service: tts.google_translate_say
    data:
      message: wash is done
      entity_id: media_player.bedroom_speaker
  - service: switch.turn_on
    target:
      entity_id: switch.lt_washroom_sw1
  - service: tts.google_translate_say
    data:
      entity_id: media_player.kitchen_speaker
      message: wash is done
  - service: notify.mobile_app_iphone
  mode: restart

update: Code is working fine. Not sure what happened in start but now it’s working fine without any change.

Can above and below be in single quotes ?
I would leave a number without it, I guess it’s a string then.

This code generated by Home Assistant GUI. I have added automation from GUI and copied code from automation.yaml file. So syntax is correct.

OK… Are you sure it’s not triggered ? Or that it is but never pass the wait_for_trigger next ?
Do you see it running ? Are there traces ?
What should it do. I understand that :
it should run when power is above 1 (W ?)
then it wait 30s max until consumption drops bellow .3 (W again ?)
But does this actually happen ? Ain’t that too short so it doesn’t ever continue ?

Hello,

It work some times and mostly not.
The above code was for test only so I set short times to check settings. Here is my final configuration.

I want to get google home device announce that wash is done. For this I have set following as my understanding.

  1. When machine starts, it takes 2- 5 watts while you set timer etc.
  2. When machine start washing it takes around 190-230 watts until completed.
  3. in between, it takes 6-5 watts again for water drain and refill.

So I have set that if machine take power more than 1 watt for atleast 10 minutes or more. It should trigger and added condition that power must be less than .3 for 30 seconds to run actions.

Because when machine is started, it takes more than 1 watt. and when it complete it takes 0 watts.

Now its not running and I don’t know why. Is there any way to troubleshoot? So I am making any mistake in my configuration?

Please advice.

- id: '1622563811541'
  alias: 'Washing Machine automation '
  description: ''
  trigger:
  - platform: numeric_state
    entity_id: sensor.sonoff_1000000_power
    attribute: power
    for: 00:10:00
    above: '1'
  condition: []
  action:
  - wait_for_trigger:
    - platform: numeric_state
      entity_id: sensor.sonoff_1000000_power
      below: '.3'
      for: 00:00:30
      attribute: power
    continue_on_timeout: false
  - service: media_player.volume_set
    target:
      entity_id:
      - media_player.kitchen_speaker
      - media_player.bedroom_speaker
      - media_player.office_speaker
    data:
      volume_level: 1
  - wait_template: 00:00:15
  - service: tts.google_translate_say
    data:
      message: washing done
      entity_id: media_player.bedroom_speaker
  - service: tts.google_translate_say
    data:
      entity_id: media_player.kitchen_speaker
      message: washing done
  - service: notify.mobile_app_iphone
    data:
      title: Washing is done
      message: Take of the cloths from machine
  - service: switch.turn_off
    target:
      entity_id: switch.sonoff_1000000
  mode: restart

It’s hard to tell.
Note that “above 1 for 10mn” means that the power must not drop under 1W for the whole 10mn to trigger.
Same for “below .3 for 30s”. So if there is only 1 instance of a 1.1W after 9:59, then it won’t trigger.
I’ve not chosen to go this way, but used a larger value (30W) no delay to detect beginning.
And then an higher value (3W) for a longer time (5mn) to detect end of cycle.

Hi, I like your code. But don’t know what is this, another helper?
“service: timer.start
entity_id: timer.wasmachine”
In your write up not find it.