Laundry Sensors with NodeMCU and Home Assistant

I’m planning to use an MPU-6050 to monitor the movement of an outdoor structure sitting on concrete footings over time.

So using this solution I should be able to get gyro readings that have to be calibrated as a reference point and then from there look at the delta across time (weeks, month, years). The ESP sends the values regularly to Home Assistant for reporting (or creates “movement alerts”) as part of the ESPHome code and sends these to Home Assistant. How sensitive is the MPU-6050? Didn’t really understand the gyro specs shown in the data sheet.

Could I adopt this for this use case?

unless the structure is literally collapsing or being pushed with a bulldozer, I dont think you are going to get any useful data

1 Like

Yeah, also the sensors do tend to drift. Originally, I was using absolute values for determining vibrations and found that I had to recalibrate the values periodically (like monthly) because of the drift. I now use a delta value so I don’t have to deal with that anymore. For you, if the structure is going to be in the same place day after day the drift will likely make it look like it moved when it hasn’t.

Ok so sounds like a bit of a sledgehammer approach to an instrument I can’t keep constant.

Any delta I pick up can be because of the drift or actual movement but given I have no way to conclusively determine which of the two it is it’s kind of pointless to build it.

Is the drift a function of age, temperature, humidity or possibly a combination of all?

You’re asking the wrong guy. I’m just looking at empirical data I collected because I was trying to trust the absolutes. I haven’t done a correlation study on the drift. I just changed my methodology and moved on. I think you’ll need to ask the engineer who designed the MPU6050 or do that study yourself…

Fair enough.

Weighing up the benefits vs the effort in this case means I’ll have to park this as an idea. Many more other important projects in the pipeline

This seems to be close to what I’m looking for. Can u guys please have a look at here and give your experienced input?

Your contribution is highly appreciated!
Thank you in advance

Hey Spikey, can you provide an updated circuit diagram of your project? I’m having some trouble reading the values with my NodeMCU ESP8266 and would love to be able to do a sanity check! Also, thanks so much for your detailed updates and explanations! Your comments have been SUPER helpful (despite the fact that I’m still struggling with this one haha)!!!

EDIT: It turns out that I was doing everything correctly, but I was testing on a breadboard before designing my board layout and soldering up the pins and apparently a few of the pins weren’t making enough contact *face palm*.

Since I had posted up looking for a sanity check, I wanted to at least share my working prototype circuit, from my breadboard.

Please note that I only had one spare reed switch laying around and am waiting on more to arrive this week, so for now my circuit has just one “door sensor”. I’ll post updated photos once I’ve finalized the build.

Also, I wanted to briefly add that the resister used for the reed switch is a 10KΩ resistor (not that you can’t do the math, but frankly it’s been a long time since I had to use Ohm’s Law, and I went cross-eyed for a minute or two figuring this one out, so maybe this helps someone avoid the same or at least saves someone some time :smiley:). When I add in the second reed switch, I’ll need to also add a second 10KΩ resistor in for that one too.

Sorry, I didn’t respond earlier @zkniebel. I’ve found that these sensors and SOCs are pretty durable and incredibly cheap (I usually buy like 5 ESP8266s or ESP32s at at time!). So, if you don’t have an electronics background, internet research and trial and error is your friend. LOL, I have an electronics background (BS in CompE) but I still ended up doing internet research and trial and error on all my projects. On the bright side, I’ve never burned one up and I’ve got like 20+ SOCs scattered all around my house doing various jobs. :smiley:

From your pictures it looks like you got it working on a breadboard. :+1: I’ve found the breadboard config to be a great way to test out a circuit completely before soldering everything up onto a proto board. When I built this one, I hadn’t started using dupont sockets for all the components. I do that now so I can swap out sensors and SOCs if necessary (surprisingly, I’ve actually never had to swap out sensors or SOCs!!, knock on wood).

Good luck!

Thanks so much Spikey, and no worries at all :slight_smile: My resupply of reed switches arrived this morning, so hopefully I’ll get the prototype finished today.

I just came up with a plan for attaching the devices to the machines too. I saw your post about using caulk, which I think is a solid idea. Riffing on that a little, I have a couple of project boxes that I can secure the components to with some small screws, after which I should be able to caulk the boxes to the backs of the machines. I’ll take photos of that once I get to that point.

Sounds like you have a similar background to me, actually, albeit on the other side of the hardware/software fence. I actually have an electronics background too (BS in CompSci with a focus in CompE), and I build a lot of smart devices around the house :slight_smile:. That said, the majority of my devices use a NodeMCU ESP8266, so I don’t often have to use resistors (due to the built-in pull-ups and pull-downs) - for the few projects that do require resistors, my research usually turns up an article or two that I use for inspiration and which specifies the resistance needed, and I can just sanity check the math myself before wiring :laughing:. When I see something like that missing though, I like to post it for those who are new and might struggle figuring it out alone. I actually do the same as you with buying in bulk and keeping extras around, and I’m pretty much on a bi-monthly AliExpress schedule now :money_mouth_face:. Of course, AliExpress components aren’t always the most reliable, and since the boards were getting power and the LEDs were on, despite not giving me any readings, I was convinced that (:laughing: I was faaaaar too awesome to be at fault and) the boards were the culprits! And I was wrong.

Following up as promised, below are some photos of my completed build, pre-installation. I plan to install it later this evening, but because of the layout of my laundry room there won’t be a viable way to take pictures of the setup once installed.

I’ll do my best to walk through what I did in the photos as I go, for those who are more visual, but sadly I only took photos at the end of the build rather than during.


FULL VIEW OF COMPLETED BUILD
Let’s start with a holistic view of the full build. Don’t worry, we’re going to walk through each element step-by-step :wink:.

Now that we’ve seen the completed build, let’s dive in step-by-step.

STEP 1: ASSEMBLING THE CORE WIRE HARNESS
The first thing I assemble on pretty much any build I do with wired components is what I call the “core wire harness.”

The job of the core wire harness is to facilitate the connections between all of the different components of the build. The wire harness isn’t permanently affixed (read: “soldered”) to any components of the build, but rather exposes connectors to attach to them by cables. By building the core wire harness first, I’m able to keep the circuit lean and focused on the core functionality, as opposed to becoming dependent on any element of the build (for the software guys out there, this practice is basically a hardware application of the Dependency Inversion principle, building an abstraction to wire the rest of the build up to, also helping to support following hardware applications of the Single Responsibility Principle and the Open/Closed Principle).

With that said, best practices should be followed generally and broken tactically. In my case, as you’ll see in later photos, to save a little time I decided to configure the wire connector for the controller to fit the pinout of my NodeMCU ESP8266 directly. While this does create a soft dependency on my controller type, because one can easily add jumper cables from the 10-pin and 2-pin dupont connectors used to connect the core wire harness and use the jumpers to reconfigure the connections for another controller, I felt that it wasn’t worth the time or materials to add a separate connector for the cable to the controller component. Poetically, this decision turned out to be a big mistake in this case, as I’ll explain later :joy:.

Anyway, once my core wire harness was finished, I used jumper wires to wire it into my breadboard-based prototype and checked that everything was working normally. I didn’t photos of the testing, but it was a good thing I did it, because I’d accidentally swapped my I2C cables and was able to figure out the problem pretty quickly by tracing the relatively few wires that I’d assembled.

STEP 2: ASSEMBLING COMPONENT CABLES
The second thing I built was the component cables, and I think it’s important to discuss how I built them and why I decided to build them this way, since I definitely made them a little more involved than I would typically make them on the average project.

When planning my build, I was considering the physical conditions in my laundry room, and I decided that it would be a good idea to sleeve all of my component cables with PET cable mesh to protect them.

Door Sensor Cables
The space in which my washer and dryer sit in my laundry room is pretty tight, and there’s a pretty small gap between the washer and dryer - small enough that they occasionally touch each other while running. Because I plan to run the wires for the door sensors through that gap, I chose to sleeve the door sensor cables to protect them from any excessive wear that might occur.

Additionally, because my controller requires a 10KΩ resistor to be used as a voltage divider before the reed switch wire comes into the data pin, I added the resistor into the component cable. This was a mistake. What I should’ve done is add that resistor to a separate component cable used to connect my controller (Remember the best practice that I tactically broke? Yeah, I shouldn’t have done that. Oh well - nobody’s perfect :wink:). If ever I have to update the controller or the door sensor cables, I’ll be sure to fix that mistake - otherwise, I can live with it.

With that mistake in mind, however, note that my door sensor cables go from 2 wires for the sensor to 3 wires (and the spliced in resistor) just before the cable connects to the core wire harness.

Accelerometer Sensor Cables
The accelerometer cables also posed some concerns about strength and resilience to the physical conditions of the installation location. There isn’t quite as much storage space in the laundry room as would be ideal, so my wife and I tend to organize things like detergent, softeners, stain removers and other things on top of the washer and dryer units. Occasionally, these items fall behind the units and, because some of the items are quite heavy, I decided to sleeve the accelerometer cables as well to add some extra strength and protect them from damage that might otherwise occur from falling items

A Note on Component Cable Length
As a final note on the cables, it’s worth commenting on the length of the cable runs, as they’re pretty long. The outlet I plan to use to power the circuit isn’t directly behind the machines, which is why I decided to make the runs a little longer.

More Testing
Once the cables had been assembled, there was no further need for my breadboard prototype. I hooked the build up to power and tested to make sure that everything was still working. Aside from a cabe with a loose pin that I was able to quickly isolate and resolve, there were no issues.

STEP 3: CREATING HOUSINGS FOR MOUNTING AND PROTECTING THE COMPONENTS
In order to protect the different components of the circuit and make it easier to mount them to their installation locations, I decided to cut up a project box to make a housing for the controller and each of the accelerometers.

These project boxes were just cheap, plastic boxes I got for a few cents each from Alibaba a few years ago. I was able to make all three housings with a single box that I cut up and hot glued together as needed.

STEP 4: ANNOTATING WITH LABELS AND DIAGRAMS
The next and final step before installation was to create and affix labels for each of the cables and components.

Please note that although it’s not shown here, I include a circuit diagram in the labels for all of my projects near or attached to the controller board. A friend of mine graciously offered to laminate copy for me, and so I will be adding attaching the diagram to the controller box via a cable tie, once I get the laminated copy.

If you’re wondering how I made the labels, a couple of years back, I picked up a D10 label maker from Amazon on Black Friday for something like $20, and it was one of the best purchases I’ve ever made (though I’m now looking to upgrade to something a little bigger that can print larger labels).

Hey Spikey, I’m starting in on the automation aspect of the project, and I have a question for you regarding the use of the lambda vs using the delta filter with on_value. Was there a particular issue you encountered or another reason why you chose to go with the expression?

I tried to get the delta to work but was unsuccessful in having it do what I wanted to do. If you can get it working and the YAML is more concise, please share it!

Fair enough - yeah I was thinking of trying that out. I’m going to work on collecting some data first and figuring out what my ideal threshold is first (a delta of 1.00 was high for my washer initially and I have the threshold down to 0.75 now, following a binary search, to see if that’s better for my setup). Once I have the setup working I’ll give delta and on_value a try.

You also mentioned that you were looking to get your computation working with the door sensor. I’ve been thinking about that myself. My first thought was, for example, that if the wash is detected to be running then the state should be “washing” while running and ideally change to something like “washed” if active vibrations are no longer detected and the washer door has not been opened since the state changed to “washing”. The complexity there is that over the course of a wash, for which duration can vary, the sensor may periodically report the state as “washed” then “washing” then back to “washed” and so on, due to changes in the cycles (e.g. wash, rinse, spin). What I was thinking about doing for this is trying out the max filter to try to collect over a larger period, but I’m not happy with it - the washer would notify of completion (for example) 5 minutes after finishing.

I know you said that you haven’t managed to get that part working yet, but before I start down the rabbit hole, did you have any ideas of how you planned to approach it?

I was curious as to how/why this post/project qualifies or was selected as a “blog” post?

Update on my side: after much internal debate, I decided to skip the washed-washing/dried-drying approach, as I couldn’t find a reliable set of thresholds that would enable me to confidently determine that the machine is “washing” vs “washed” for my machines. What I was able to do, however, is determine if the wash/dry is completed.


Determining if the Washer/Dryer is Complete

I created a separate input boolean as a HA helper to hold the “washer completed” and “dryer completed” value. Creating this as an input boolean allowed me to manually turn it on/off for debugging or runtime purposes. Once vibrations are detected, my automation runs and once a specified time threshold has passed (10 minutes in my case) the switch is flipped to “on”. If the door is opened, the switch is flipped back to off, as it’s assumed that you opened the door and moved the laundry. I did not see an easy way to do this through ESPHome, although I do plan to keep trying, as I would like to use this logic to update the text sensor to “washing” when vibrations are detected and “washed” if the timeout passes.


Visual Notifications Approach Overview

Originally, I had planned on setting up push notifications and voice alerts from Alexa, but my wife had other plans (which I actually like better, to be honest). What she wanted was a light notification, either through our Philips Hue lights or something else, that would remind us. I didn’t want the Philips Hue bulbs to do it, as that could easily disrupt the ambience of our home or interrupt whatever we’re doing rather than allowing us to make a decision as to whether we want to wait a few minutes before moving the laundry, so instead I decided to install a WLED strip behind our TV and change the colors to reflect the notification. For those interested in doing something similar, while I know API calls can be used to programmatically set the palette colors for the lights (and while I confess that’s the route I should have taken), I decided to be lazy and predefine my palettes as presets. I used a cyan/blue color for when the wash is done, orange when the dryer is done, and both rotating around the TV when both are done.


Automations Created in Home Assistant

Overall, I created 4 automations - 2 for the washer and 2 for the dryer - to manage the logic for my setup. Each machine has a “[Washer/Dryer] Completed” automation and a *"[Washer/Dryer] Door Opened" automation. The Machine Completed automation manages the helper I mentioned earlier and turns on the correct palette once the washer/dryer has finished, while the Door Opened automation tells the WLED to go back to the default color/palette once the door has been opened.

Below are the automations I created for the Washer. Note you would use the same ones for the dryer, just change around the entities and WLED preset IDs, as needed.

The following is my Washer Completed automation:

alias: Laundry Washer Activity Complete
description: ''
trigger:
  # run when the washer senses that it's washing
  - platform: state
    entity_id: sensor.washer
    to: Washing
condition: []
action:
  # wait 10 minutes after washer is detected to be washing before running the logic
  - delay:
      hours: 0
      minutes: 10
      seconds: 0
      milliseconds: 0
  # loop until the washer has been idle for 10 minutes (inclusive of the delay run before the loop)
  - repeat:
      until:
        - condition: state
          entity_id: sensor.washer
          state: Idle
          for:
            hours: 0
            minutes: 10
            seconds: 0
            milliseconds: 0
      sequence:
        # wait 30 seconds between checks to see if the washer is complete
        - delay:
            hours: 0
            minutes: 0
            seconds: 30
            milliseconds: 0
  # once the washer is complete, turn on the washer_complete toggle
  - service: input_boolean.turn_on
    target:
      entity_id: input_boolean.washer_complete
  # run the logic until the washer has been emptied (washer_complete is turned off)
  - repeat:
      until:
        - condition: state
          entity_id: input_boolean.washer_complete
          state: 'off'
      sequence:
        - choose:
            - conditions:
                # only run the logic every 40th loop, i.e. every 10 minutes (as the delay for this loop is 15 seconds)
                - condition: template
                  value_template: '{{ repeat.first or repeat.index % 40 == 0 }}'
              sequence:
                - choose:
                        # if the dryer is complete also, turn on the preset for both machines being complete, otherwise just turn on the preset for the washer being complete (this logic could be improved by checking the state of the WLED or creating a second helper to avoid edge-case issues)
                    - conditions:
                        - condition: state
                          entity_id: input_boolean.dryer_complete
                          state: 'on'
                      sequence:
                        - service: wled.preset
                          target:
                            entity_id: light.living_room_notification_lights
                          data:
                            preset: 5
                  default:
                    - service: wled.preset
                      target:
                        entity_id: light.living_room_notification_lights
                      data:
                        preset: 3
          default: []
        - delay:
            hours: 0
            minutes: 0
            seconds: 15
            milliseconds: 0
# if the wash is detected to be washing again before the automation completes then restart it because the washer is still running
mode: restart

The following is my Washer Door Opened automation:

alias: Laundry Washer Door Opened
description: ''
trigger:
  # run the automation when the washer door is opened
  - type: opened
    platform: device
    device_id: 265e95a3d9f77fe6997279f3d2496d85
    entity_id: binary_sensor.washer_door
    domain: binary_sensor
condition: []
action:
  # turn off the washer_complete helper, as the door has been opened (assume the washer is being emptied)
  - service: input_boolean.turn_off
    target:
      entity_id: input_boolean.washer_complete
  # if the dryer hasn't yet been moved, set the dryer complete preset, otherwise set the default preset
  - choose:
      - conditions:
          - condition: state
            entity_id: input_boolean.dryer_complete
            state: 'on'
        sequence:
          - service: wled.preset
            target:
              entity_id: light.living_room_notification_lights
            data: {}
    default:
      - service: wled.preset
        target:
          entity_id: light.living_room_notification_lights
        data:
          preset: 1
# since these run right away, there's no need to restart if a second door opened is detected
mode: single

If I can get that “washing” state figured out for ESPHome I’ll post another update.

Beyond that, good luck with your project!

@SpikeyGG, I got it working with the door and also managed update the washer/dryer sensors to report the states Idle, Running, and Complete. I have updated both the ESPHome and Automation configurations, which you can find below.

The states represent the following:

  • Idle: machine not running and nothing in it to be removed
  • Running: machine is currently running (vibrations were detected within a 10-minute sliding window - you can customize the window duration by editing the ESPHome config file)
  • Complete: machine is finished (vibrations no longer detected) and the door has not been open (assumption is there are clothes that need to be removed)

As a quick recap, that there is 1 ESPHome configuration for the hardware product, and 4 automations (2 for each machine, with one being for turning on the notification and the other being for turning it off) for managing the notifications for my setup. I am leveraging visual notifications for which I have a WLED light strip change to a predefined preset based on the following states:

  • Washer only is complete: washer color is shown
  • Dryer only is complete: dryer color is shown
  • Washer and dryer are both complete: both colors are shown
  • Neither is complete: default preset is shown


ESPHOME CONFIGURATION: Laundry Machine Sensors

esphome:
  name: laundry-machine-sensors

esp8266:
  board: nodemcuv2
  restore_from_flash: true

# Enable logging
logger:
  level: DEBUG

# Enable Home Assistant API
api:
  encryption:
    key: "XXXXXXXXXXXXXXXXXXXXXXXXXXX="

ota:
  password: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Laundry-Machine-Sensors"
    password: "XXXXXXXXXXXX"

captive_portal:

web_server:
  port: 80
    
i2c:
  sda: 4
  scl: 5
  scan: True

globals:
  # Washer/dryer delta thresholds
  - id: washer_delta_accel_min_threshold
    type: float
    initial_value: "0.75"
  - id: dryer_delta_accel_min_threshold
    type: float
    initial_value: "1.00"
  # Washer/dryer accelerometer reading deltas
  - id: washer_delta_accel_x
    type: float
  - id: washer_delta_accel_y
    type: float
  - id: washer_delta_accel_z
    type: float
  - id: dryer_delta_accel_x
    type: float
  - id: dryer_delta_accel_y
    type: float
  - id: dryer_delta_accel_z
    type: float

sensor:
  # Washer Accelerometer Sensors
  - platform: mpu6050
    update_interval: 25s
    address: 0x68
    accel_x:
      accuracy_decimals: 1
      name: "Washer Accel X"
      id: washer_accel_x
      internal: true
      filters:
        - lambda: |-
            id(washer_delta_accel_x) = fabsf(id(washer_accel_x).state - x);
            return(x);
    accel_y:
      accuracy_decimals: 1
      name: "Washer Accel Y"
      id: washer_accel_y
      internal: true
      filters:
        - lambda: |-
            id(washer_delta_accel_y) = fabsf(id(washer_accel_y).state - x);
            return(x);
    accel_z:
      accuracy_decimals: 1
      name: "Washer Accel Z"
      id: washer_accel_z
      internal: true
      filters:
        - lambda: |-
            id(washer_delta_accel_z) = fabsf(id(washer_accel_z).state - x);
            return(x);
    temperature:
      name: "Washer Temperature"
      filters:
        - heartbeat: 600s
        
  # Dryer Accelerometer Sensors
  - platform: mpu6050
    update_interval: 25s
    address: 0x69
    accel_x:
      accuracy_decimals: 1
      name: "Dryer Accel X"
      id: dryer_accel_x
      internal: true
      filters:
        - lambda: |-
            id(dryer_delta_accel_x) = fabsf(id(dryer_accel_x).state - x);
            return(x);
    accel_y:
      accuracy_decimals: 1
      name: "Dryer Accel Y"
      id: dryer_accel_y
      internal: true
      filters:
        - lambda: |-
            id(dryer_delta_accel_y) = fabsf(id(dryer_accel_y).state - x);
            return(x);
    accel_z:
      accuracy_decimals: 1
      name: "Dryer Accel Z"
      id: dryer_accel_z
      internal: true
      filters:
        - lambda: |-
            id(dryer_delta_accel_z) = fabsf(id(dryer_accel_z).state - x);
            return(x);
    temperature:
      name: "Dryer Temperature"
      filters:
        - heartbeat: 600s
        
text_sensor:
  # Washer Text Sensor
  - platform: template
    icon: mdi:washing-machine
    name: Washer
    id: washer
    
  # Dryer Text Sensor
  - platform: template
    icon: mdi:tumble-dryer
    name: Dryer
    id: dryer
    
script:
  # Washer Completed Script
  - id: washer_completed_script
    mode: restart
    then:
      - delay: 8min
      - text_sensor.template.publish:
          id: washer
          state: Complete
          
  # Dryer Completed Script
  - id: dryer_completed_script
    mode: restart
    then:
      # change the delay time to control the duration of the sliding window (this value plus the value of the delayed_off filter for the vibration sensors is the total sliding window duration)
      - delay: 8min
      - text_sensor.template.publish:
          id: dryer
          state: Complete
        
binary_sensor:
  # Washer Door Sensor
  - platform: gpio
    id: washer_door
    device_class: door
    name: "Washer Door"
    pin:
      number: D7
      mode: INPUT_PULLUP
    on_press:
      then:
        - script.stop: washer_completed_script
        - text_sensor.template.publish:
            id: washer
            state: Idle
      
  # Dryer Door Sensor
  - platform: gpio
    id: dryer_door
    device_class: door
    name: "Dryer Door"
    pin:
      number: D5
      mode: INPUT_PULLUP
    on_press:
      then:
        - script.stop: dryer_completed_script
        - text_sensor.template.publish:
            id: dryer
            state: Idle
      
  # Washer Vibration Sensor
  - platform: template
    device_class: vibration
    name: "Washer Vibration"
    id: washer_vibration
    lambda: |-
      if (isnan(id(washer_delta_accel_x)) or isnan(id(washer_delta_accel_y)) or isnan(id(washer_delta_accel_z))) {
        id(washer).publish_state("Idle");
        return {};
      }
      else if (abs(id(washer_delta_accel_x)) > id(washer_delta_accel_min_threshold) or abs(id(washer_delta_accel_y)) > id(washer_delta_accel_min_threshold) or abs(id(washer_delta_accel_z)) > id(washer_delta_accel_min_threshold)) {
        return(true);
      } else {
        return(false);
      }
    filters:
      - delayed_off: 120s
    on_press:
      then:
        - text_sensor.template.publish:
            id: washer
            state: Running
        - script.execute: washer_completed_script
    on_release:
        - script.execute: washer_completed_script
            
  # Dryer Vibration Sensor
  - platform: template
    device_class: vibration
    name: "Dryer Vibration"
    id: dryer_vibration
    lambda: |-
      if (isnan(id(dryer_delta_accel_x)) or isnan(id(dryer_delta_accel_y)) or isnan(id(dryer_delta_accel_z))) {
        id(dryer).publish_state("Idle");
        return {};
      }
      else if (abs(id(dryer_delta_accel_x)) > id(dryer_delta_accel_min_threshold) or abs(id(dryer_delta_accel_y)) > id(dryer_delta_accel_min_threshold) or abs(id(dryer_delta_accel_z)) > id(dryer_delta_accel_min_threshold)) {
        return(true);
      } else {
        return(false);
      }
    filters:
      - delayed_off: 120s
    on_press:
      then:
        - text_sensor.template.publish:
            id: dryer
            state: Running
        - script.execute: dryer_completed_script
    on_release:
      then:
        - script.execute: dryer_completed_script
  


AUTOMATION: Laundry Washer Activity Complete v2

alias: Laundry Washer Activity Complete v2
description: ''
trigger:
  - platform: state
    entity_id: sensor.washer
    to: Complete
    # shouldn't need to set a time threshold on this, but was getting premature triggers - using this as a workaround until I can find the solution
    for:
      hours: 0
      minutes: 0
      seconds: 30
      milliseconds: 0
condition: []
action:
  - repeat:
      until:
        - condition: state
          entity_id: sensor.washer
          state: Idle
      sequence:
        - choose:
            - conditions:
                - condition: state
                  entity_id: sensor.dryer
                  state: Complete
              sequence:
                - service: wled.preset
                  target:
                    entity_id: light.living_room_notification_lights
                  data:
                    preset: 5
          default:
            - service: wled.preset
              target:
                entity_id: light.living_room_notification_lights
              data:
                preset: 3
        - delay:
            hours: 0
            minutes: 10
            seconds: 0
            milliseconds: 0
mode: restart


AUTOMATION: Laundry Washer Door Opened v2

alias: Laundry Washer Door Opened v2
description: ''
trigger:
  - type: opened
    platform: device
    device_id: 265e95a3d9f77fe6997279f3d2496d85
    entity_id: binary_sensor.washer_door
    domain: binary_sensor
condition: []
action:
  - choose:
      - conditions:
          - condition: state
            entity_id: sensor.dryer
            state: Complete
        sequence:
          - service: wled.preset
            target:
              entity_id: light.living_room_notification_lights
            data:
              preset: 2
    default:
      - service: wled.preset
        target:
          entity_id: light.living_room_notification_lights
        data:
          preset: 1
mode: single

So far, everything has been working perfectly, but if I do find any bugs I’ll be sure to post an update.

EDIT: An issue I started noticing today is that sometimes the triggers for my automation were inexplicably firing early, without the machine’s state actually changing to “Complete”. I’ve yet to figure out the cause (working on it and will post an update when I figure it out), but in the meantime I’ve worked around the issue by updating the triggers to require the state to be Complete for 30 seconds before the automation will run. This is a strange issue, but if anyone has any idea what could be causing it then please let me know.

1 Like

You have an interesting approach to this implementation. It looks like you’re hammering the two ‘complete’ scripts in hopes that there will be triggers continuously to restart the service while the washer and dryer are running. I think it should work but, to me, it feels a little risky about the method for keeping the state from reaching complete. Thinking about this further you could, instead, have a more generic laundy_completed_script and pass in the washer/dryer as a value keeping two separate states internally. I’ll have to think about this more, thanks for sharing it!

1 Like

Yeah, that’s a really good point. And there are some improvements too that I’d like to make, like being able to define the 8min timeout period as a variable. Overall, this value should be set / calibrated based on how your washer / dryer work, and the biggest caveat is that you have to wait for that timeout to elapse before the state is ultimately reported as Complete. I have had a couple premature Complete states shown, but was able to iron most of them out in testing. There’s a balance between that timeout and the delta thresholds you set, and also between the delta thresholds and false readings / washer picking up dryer vibrations and vice versa.

In an ideal world, the code would also look at something else, like power consumption, in order to figure out if the washer is still running, but that would involve adding another device into the mix.