Continue Discussion 59 replies
March 2018

ladaowner

You sir are a legend, I am going to use a modified version of this to create a washing machine sensor.

If I only need one MPU6050 (got a washer/dyer combo unit) then do I only need to connect the 5V GND SCL SDA pins. The AD0 pin is only needed for an additional MPU6050.

March 2018

fversteegen

Great trick! Just a question from my end; why not going for a solution that measures the absorbed electricity? That’s what I am using quite reliable.

1 reply
March 2018 ▶ fversteegen

kanga_who

I have this exact use case, a Sonoff Pow monitoring the power usage, with an automation that sends a push bullet when the wattage drops below 5 watts for 2 mins, then switches off the Sonoff Pow.

Works perfectly and reliably.

1 reply
March 2018

ladaowner

Can you post your code from home assistant for me too look at, I got loads of pre-flashed Sonoffs boxes just laying around.

1 reply
March 2018 ▶ ladaowner

ladaowner

figured out the code needed for a POW Sonoff.

March 2018

timpro

This is great. When the washer hits the soak cycle, does that report that it’s complete? I never would have thought of using an accelerometer, I’m going to have to try this.

March 2018

masterkenobi

May I know where and how do you attach the accelerometer? Do you need to open up the washing machine? A picture will definitely help.

February 2019

Studebaker

What did you use to monitor the x, y and z ranges in order to set the threshold values?

March 2019

SpikeyGG

A couple of questions about this implementation:

  1. Looking at the NodeMCU pin-out it appears as though it does not have 5V, SCL and SDA pins. So, how do you hook the MPU-6050 to the NodeMCU?
  2. What are the resistor values used for the reed switches? Do you have an actual wiring diagram of this implementation?

Thanks,
-Greg

1 reply
April 2019 ▶ SpikeyGG

everythings12

Greg,

SCL is D1 and SDA is D2 on the NodeMCU. At least from what I could find. Came to ask about the library for programming. I couldn’t figure out which #include “I2Cdev.h” to use. I found a rowberg on github but I couldn’t figure out how to get it to compile. I got it all together and programmed but it’s not responding to anything other than MQTT.

The reed switches I built I used 330k, no idea if that works though. I couldn’t get a single MPU6050 to respond to the program. I’m guessing it’s the library I used.

OP hasn’t responded ever in this thread so I’m guessing we’re on our own. If you find another setup that works with ESP & 6050’s come back and post it plz. I’ll do the same.

April 2019

Drew.B

Have you thought about doing it in EspHome? The I2C bus is simple to set up, but I haven’t used it with one of these MPU sensors, only with a pressure sensor. It doesn’t seem like it would be too difficult, the data for individual axis’ would be available straight to HA and you could automate from there.
I just bought a couple on Aliexpress, so I’ll know in about 3-4 weeks…

2 replies
April 2019 ▶ Drew.B

everythings12

Drew - absolutely keep me posted. I’m using ESPHome and for what it’s worth it looks easy, hard to tell because I haven’t been able to get a response out of the 6050’s. I’m only using one for now. I did read that adding 3v to the AD0 will give a secondary address for the i2c stuff so I think one esp will work for both. If you’d shoot me a message on here and let me know when you’re heading down that path I’d appreciate it. As I’m completely new to ESPHome. It seems easy but took me a while to figure out how to add the YAML entries, I’m still uncertain if I’ve selected everything that I should.

1 reply
April 2019

SpikeyGG

Great idea. I might try that first. I like the idea of having the sensor data available in HA for some reason. :stuck_out_tongue:

April 2019 ▶ everythings12

Drew.B

No worries, they shouldn’t be too far off now…:crossed_fingers:

May 2019

SpikeyGG

Okay, I’ve got my NodeMCU and I’m playing around with ESPHome. I was able to get an ESPHome configuration file written up so that when I program the thing through USB, I can see the MQTT messages come through from all sensors (washer and dryer x/y/z/door). I’m actually floored that I was able to get this far, I’ve spent the majority of the day on it today.

EDIT:

However, when I unplug the device from the USB port on the raspberry pi after programming it and power it externally (either through USB on my computer or via a 12V wall wart) it never comes up. I don’t get any MQTT messages on my mosquitto instance and ESPHome only ever shows the device I created as ‘Offline’. I can ping the IP and it’s alive but I can’t figure out how to tell it to ‘go start working’.

How can I make the thing come up automatically and start working when the power goes out?? I’m so close!!

I was able to solve this by not using mqtt and instead using the Native Home Assistant API. It works very well but I had to remove all the stale MQTT data that I had created. Now I’m trying to get an accurate representation of the MPU6050 temperature sensor but I’m finding that their response is non-linear! Check this out:
image
This was generated from me experimenting by putting the prototype circuit inside my oven, then fridge, then the oven again. In my house at ~70F the sensors read somewhere in the vicinity of 219C. When I stuck the boards in the fridge, the temperature reading from the MPU6050 falls to around 200C. When I put it in the oven it raises up to around 229C, then immediately jumps to 36C as the temperature (in reality) rises above ~94F.

I’ve found that the values from the accel and gyros need to be calibrated as well since they’re giving me weird results (when I’m not actually moving the boards):

[22:28:02][D][sensor.mpu6050:134]: Got accel={x=0.610 m/s², y=38.914 m/s², z=5.420 m/s²}, gyro={x=3992.643 °/s, y=3995.265 °/s, z=0.366 °/s}, temp=46.601°C
[22:28:11][D][sensor.mpu6050:134]: Got accel={x=38.857 m/s², y=39.166 m/s², z=9.519 m/s²}, gyro={x=3993.375 °/s, y=1.707 °/s, z=3994.106 °/s}, temp=49.754°C
[22:28:12][D][sensor.mpu6050:134]: Got accel={x=0.572 m/s², y=38.869 m/s², z=5.305 m/s²}, gyro={x=3992.399 °/s, y=3995.326 °/s, z=0.793 °/s}, temp=46.742°C
[22:28:21][D][sensor.mpu6050:134]: Got accel={x=38.891 m/s², y=0.017 m/s², z=9.705 m/s²}, gyro={x=3993.009 °/s, y=1.707 °/s, z=3994.350 °/s}, temp=49.942°C
[22:28:22][D][sensor.mpu6050:134]: Got accel={x=0.560 m/s², y=38.883 m/s², z=5.372 m/s²}, gyro={x=3992.521 °/s, y=3995.387 °/s, z=0.793 °/s}, temp=46.883°C
[22:28:31][D][sensor.mpu6050:134]: Got accel={x=38.874 m/s², y=39.197 m/s², z=9.712 m/s²}, gyro={x=3993.192 °/s, y=1.463 °/s, z=3994.228 °/s}, temp=50.036°C
[22:28:32][D][sensor.mpu6050:134]: Got accel={x=0.608 m/s², y=38.833 m/s², z=5.343 m/s²}, gyro={x=3992.338 °/s, y=3995.265 °/s, z=0.610 °/s}, temp=46.883°C
[22:28:41][D][sensor.mpu6050:134]: Got accel={x=38.819 m/s², y=39.137 m/s², z=9.600 m/s²}, gyro={x=3993.314 °/s, y=1.646 °/s, z=3994.228 °/s}, temp=50.271°C
[22:28:42][D][sensor.mpu6050:134]: Got accel={x=0.627 m/s², y=38.831 m/s², z=5.439 m/s²}, gyro={x=3992.460 °/s, y=3995.326 °/s, z=0.671 °/s}, temp=47.071°C
[22:28:51][D][sensor.mpu6050:134]: Got accel={x=38.924 m/s², y=39.142 m/s², z=9.636 m/s²}, gyro={x=3993.253 °/s, y=1.463 °/s, z=3994.228 °/s}, temp=50.412°C
[22:28:52][D][sensor.mpu6050:134]: Got accel={x=0.601 m/s², y=38.862 m/s², z=5.386 m/s²}, gyro={x=3992.460 °/s, y=3995.265 °/s, z=0.671 °/s}, temp=47.212°C
[22:29:01][D][sensor.mpu6050:134]: Got accel={x=38.862 m/s², y=39.156 m/s², z=9.600 m/s²}, gyro={x=3993.253 °/s, y=1.341 °/s, z=3994.228 °/s}, temp=50.506°C
[22:29:02][D][sensor.mpu6050:134]: Got accel={x=0.656 m/s², y=38.850 m/s², z=5.398 m/s²}, gyro={x=3992.338 °/s, y=3995.448 °/s, z=0.671 °/s}, temp=47.354°C
[22:29:11][D][sensor.mpu6050:134]: Got accel={x=38.874 m/s², y=39.173 m/s², z=9.574 m/s²}, gyro={x=3993.192 °/s, y=1.585 °/s, z=3994.106 °/s}, temp=50.648°C
[22:29:12][D][sensor.mpu6050:134]: Got accel={x=0.608 m/s², y=38.857 m/s², z=5.441 m/s²}, gyro={x=3992.521 °/s, y=3995.326 °/s, z=0.366 °/s}, temp=47.354°C
[22:29:21][D][sensor.mpu6050:134]: Got accel={x=38.862 m/s², y=0.043 m/s², z=9.610 m/s²}, gyro={x=3993.314 °/s, y=1.585 °/s, z=3994.228 °/s}, temp=50.742°C
[22:29:22][D][sensor.mpu6050:134]: Got accel={x=0.560 m/s², y=38.876 m/s², z=5.381 m/s²}, gyro={x=3992.399 °/s, y=3995.448 °/s, z=0.671 °/s}, temp=47.636°C

EDIT2:

you can see from all this data that the accel and gyro values are all over the map. I had to include (after the last update) filters in ESPHome for offset and multiplier. That brings the values closer to what I’d want but I’m still seeing a few of the values “wig out”. Like they go from min to max without me touching the device. I’m not sure if I need to debounce them or something… more debug to do here.

1 reply
May 2019 ▶ SpikeyGG

SpikeyGG

This was a great project. I have it working now and it works well. The mpu6050 is sensitive enough to register the motion of the washer and dryer. Here’s an example of it from a capture today, my wife did some laundry in the washer from about 2pm to 2:40pm:

For reference and anyone who’s trying to do this with ESPHome here are the important parts of my implementation.

ESPHome yaml file:

esphome:
  name: laundry
  platform: ESP8266
  board: nodemcuv2

wifi:
  ssid: "MySSID"
  password: "MyPASSWORD"
  domain: ".mydomain"

logger:
  # level: WARN

api:
  password: 'apiPASSWORD'

ota:
  password: 'otaPASSWORD'

i2c:
  sda: 4
  scl: 5
  scan: True

sensor:
  - platform: mpu6050
    # update_interval: 10s
    address: 0x68
    accel_x:
      name: "Dryer Accel X"
      filters:
        - offset: -0.35
    accel_y:
      name: "Dryer Accel Y"
      filters:
        - offset: -39.17
    accel_z:
      name: "Dryer Accel Z"
      filters:
        - offset: -11.32
    gyro_x:
      name: "Dryer Gyro X"
      filters:
        - offset: -3990.15
        - multiply: 0.0025
    gyro_y:
      name: "Dryer Gyro Y"
      filters:
        - offset: -3995.86
        - multiply: 0.0025
    gyro_z:
      name: "Dryer Gyro Z"
      filters:
        - offset: -3994.43
        - multiply: 0.0025
    temperature:
      name: "Dryer Temperature"
      filters:
        - calibrate_linear:
          - 37 -> 34.7
          - 53 -> 53
          - 200 -> 4.3
          - 219 -> 21.1
          - 229 -> 33.4
  - platform: mpu6050
    # update_interval: 10s
    address: 0x69
    accel_x:
      name: "Washer Accel X"
      filters:
        - offset: -0.85
    accel_y:
      name: "Washer Accel Y"
      filters:
        - offset: -38.50
    accel_z:
      name: "Washer Accel Z"
      filters:
        - offset: -28.05
    gyro_x:
      name: "Washer Gyro X"
      filters:
        - offset: -3994.38
        - multiply: 0.0025
    gyro_y:
      name: "Washer Gyro Y"
      filters:
        - offset: -3993.51
        - multiply: 0.0025
    gyro_z:
      name: "Washer Gyro Z"
      filters:
        - offset: -3993.53
        - multiply: 0.0025
    temperature:
      name: "Washer Temperature"
      filters:
        - calibrate_linear:
          - 37 -> 34.7
          - 53 -> 53
          - 200 -> 4.3
          - 219 -> 21.1
          - 229 -> 33.4
      
binary_sensor:
  - platform: gpio
    device_class: door
    name: "Dryer Door"
    pin:
      number: D7
      inverted: True
      mode: INPUT_PULLUP
  - platform: gpio
    device_class: door
    name: "Washer Door"
    pin:
      number: D8
      inverted: True
      mode: INPUT_PULLUP

If you review the yaml, you’ll notice that I put a calibrate_linear for the temp sensors. I found that they were very disjointed but this makes them respond in a way that is more accurate to home assistant reporting. Also, I calculated offsets and multipliers for all the accel and gyro values to make them less awkward to determine (I can surround 0, see in the binary_sensor template below). So long as I don’t touch the physical devices, we’re good for a long time. :slight_smile:

I originally put those update_intervals at 10 seconds so I could see more data quicker but found that after a half day of that much recorded data the charts were slow to load. I saw that ESPHome has some pretty advanced filtering potentials that I’d like to play with, I bet I can make the usage detection pretty spot-on and quick by playing with those for a while. Currently the raw values work well and when the washer or dryer finally stops shaking for 5 minutes, the sonos speakers say:
“The washer is done washing” or “The dryer is done drying”

To do this, I made a binary_sensor template for the values:

laundry_sensors.yaml (binary_sensors directory)

- platform: template
  sensors:
    washer_washing:
      device_class: vibration
      friendly_name: Washer Washing
      value_template: "{{ states('sensor.washer_accel_x') | float > 0.5 or states('sensor.washer_accel_x') | float < -0.5 or states('sensor.washer_accel_y') | float > 0.5 or states('sensor.washer_accel_y') | float < -0.5 or states('sensor.washer_accel_z') | float > 0.5 or states('sensor.washer_accel_z') | float < -0.5 }}"
    dryer_drying:
      device_class: vibration
      friendly_name: Dryer Drying
      value_template: "{{ states('sensor.dryer_accel_x') | float < -0.5 or states('sensor.dryer_accel_x') | float > 0.5 or states('sensor.dryer_accel_z') | float > 0.5 or states('sensor.dryer_accel_z') | float < -0.5 }}"

You can see, I ignored the accel_y values on the dryer. I’ve purchased 5 of these mpu6050s and only one of them so far has had smooth X/Y/Z reporting. The one I chose for the dryer has 2/3 axes that work. Anyway, you really only need one to detect the movement.

I then created a holder for the state values:

configuration.yaml

input_select:
  washer_state:
    name: Washer
    options:
      - Idle
      - Loading
      - Washing
    initial: Idle
    icon: mdi:washing-machine
  dryer_state:
    name: Dryer
    options:
      - Idle
      - Loading
      - Drying
    initial: Idle
    icon: mdi:tumble-dryer

After that all I needed to do was enable the automation, it’s three parts for the three states (there’s probably a better way to do this, if you have one, please share):

laundry.yaml (automation directory)

# Washer no vibration for five minutes, washer is done!
- id: set_washer_to_idle
  alias: Set Washer to Idle
  initial_state: true
  trigger:
    platform: state
    entity_id: binary_sensor.washer_washing
    to: 'off'
    for: '00:05:00'
  action:
  - service: input_select.select_option
    data:
      entity_id: input_select.washer_state
      option: Idle

# Washer vibration and door is open means washing
- id: set_washer_to_washing
  alias: Set Washer to Washing
  initial_state: true
  trigger:
    platform: state
    entity_id: binary_sensor.washer_washing
    to: 'on'
  condition:
    condition: and
    conditions:
      - condition: state
        entity_id: binary_sensor.washer_door
        state: 'off'
  action:
  - service: input_select.select_option
    data:
      entity_id: input_select.washer_state
      option: Washing

# Washer vibration and door is open means loading
- id: set_washer_to_loading
  alias: Set Washer to Loading
  initial_state: true
  trigger:
    platform: state
    entity_id: binary_sensor.washer_washing
    to: 'on'
  condition:
    condition: and
    conditions:
      - condition: state
        entity_id: binary_sensor.washer_door
        state: 'on'
  action:
  - service: input_select.select_option
    data:
      entity_id: input_select.washer_state
      option: Loading

and finally, the sonos piece:

sonos_alerts.yaml (automation directory)

- id: sonos_alert_on_laundry_triggers
  alias: Sonos Alert on Laundry Triggers
  initial_state: true
  trigger:
    - platform: state
      entity_id: input_select.washer_state
      from: 'Washing'
      to: 'Idle'
    - platform: state
      entity_id: input_select.dryer_state
      from: 'Drying'
      to: 'Idle'
  action:
    - service: script.sonos_say
      data_template:
        sonos_primary: media_player.office_sonos
        volume: 0.5
        message: >
          The {{ trigger.to_state.attributes.friendly_name }} is done {{ trigger.from_state.state }}.
        delay: '00:00:05'
1 reply
May 2019

carloscae

I want this kind of sensors, but I’m more inclined on trying out with an energy consumption plug.
I believe it might be easier to read and implement.

Sure, if you have a super old appliance, you will have a hard time finding a plug that will support the amperage. So this solution is still very much valid.

EDIT: Added conclusion.

May 2019

LMR

I enjoyed reading about your project.

I recently built a similar project but instead of using accelerometers I’m using some very inexpensive SW-420 vibration sensors.

Your voice feedback really takes it to the next level!

June 2019

SpikeyGG

I’d like to mention that with the new ESPHome release (1.13.6) there’s very little need to calibrate the sensors. Apparently, there was a data-type mismatch (https://github.com/esphome/esphome/pull/532) which was causing the poor correlation from X/Y/Z and Temp sensors and now the data looks pretty darn good:

I set my input_selects using all accel and gyro values and it’s is really representative of the actual washer/dryer state.

1 reply
July 2019 ▶ SpikeyGG

Kem

@SpikeyGG can you share your config i tried to do the same with esphome but the sensors work for a minute or two and stop updating and i get error that i2c: is disconnected or did not communicate with the sensor
thank you

1 reply
July 2019 ▶ Kem

SpikeyGG

Sure thing, here’s the latest one I’m using I corrected it for the small offset seen in the washer plots above (I’m anal):

esphome:
  name: laundry
  platform: ESP8266
  board: nodemcuv2

wifi:
  ssid: "MySSID"
  password: "MyPASSWORD"
  domain: ".mydomain"

logger:
  level: DEBUG

api:
  password: 'apiPASSWORD'

ota:
  password: 'otaPASSWORD'

i2c:
  sda: 4
  scl: 5
  scan: True

sensor:
  - platform: mpu6050
    update_interval: 15s
    address: 0x68
    accel_x:
      name: "Dryer Accel X"
      filters:
        - offset: -0.55
        - or:
          - throttle: 60s
          - delta: 1.0
    accel_y:
      name: "Dryer Accel Y"
      filters:
        - offset: -9.62
        - or:
          - throttle: 60s
          - delta: 1.0
    accel_z:
      name: "Dryer Accel Z"
      filters:
        - offset: 0.38
        - or:
          - throttle: 60s
          - delta: 1.0
    gyro_x:
      name: "Dryer Gyro X"
      filters:
        - offset: 1.77
        - or:
          - throttle: 60s
          - delta: 1.0
    gyro_y:
      name: "Dryer Gyro Y"
      filters:
        - offset: -1.83
        - or:
          - throttle: 60s
          - delta: 1.0
    gyro_z:
      name: "Dryer Gyro Z"
      filters:
        - offset: 2.10
        - or:
          - throttle: 60s
          - delta: 1.0
    temperature:
      name: "Dryer Temperature"
      filters:
        - throttle: 60s
  - platform: mpu6050
    update_interval: 15s
    address: 0x69
    accel_x:
      name: "Washer Accel X"
      filters:
        - offset: -0.96
        - or:
          - throttle: 60s
          - delta: 1.0
    accel_y:
      name: "Washer Accel Y"
      filters:
        - offset: -1.04
        - or:
          - throttle: 60s
          - delta: 1.0
    accel_z:
      name: "Washer Accel Z"
      filters:
        - offset: -8.81
        - or:
          - throttle: 60s
          - delta: 1.0
    gyro_x:
      name: "Washer Gyro X"
      filters:
        - offset: 2.21
        - or:
          - throttle: 60s
          - delta: 1.0
    gyro_y:
      name: "Washer Gyro Y"
      filters:
        - offset: 2.75
        - or:
          - throttle: 60s
          - delta: 1.0
    gyro_z:
      name: "Washer Gyro Z"
      filters:
        - offset: 2.37
        - or:
          - throttle: 60s
          - delta: 1.0
    temperature:
      name: "Washer Temperature"
      filters:
        - throttle: 60s
      
binary_sensor:
  - platform: gpio
    device_class: door
    name: "Dryer Door"
    pin:
      number: D7
      inverted: True
      mode: INPUT_PULLUP
  - platform: gpio
    device_class: door
    name: "Washer Door"
    pin:
      number: D8
      inverted: True
      mode: INPUT_PULLUP

One thing I might do differently if I was doing this from scratch is not use the D8 pin. I’ve found that my device can be a bit finicky to power up sometimes and I think it’s because of the use of D8. According to “TheHookUp”: https://www.youtube.com/watch?v=7h2bE2vNoaY if you use D8 and it’s pulled high during boot, the ESP8266 will fail to boot. I think I’m experiencing this with the washer door. D6 or D5 would be better choices for that according to the video. Anyway, beside that, the device works FANTASTICALLY.

3 replies
August 2019 ▶ SpikeyGG

postlund

I’ve built a sensor myself and stuck it to my washer and dryer, which are stacked on top of each other. I don’t care to differentiate them, just know that one is running. However, my values seem to drift over time. So after calibrating, the offset would have to be changed. I assumed that this could be related to temperature, but in that case I would also assume that it would return to normal after cooling off. Seen anything similar? Here’s a simple graph:

All sensors were aligned nicely around zero a couple hours prior.

1 reply
August 2019 ▶ postlund

swiftlyfalling

Depending on how sensitive your accelerometer is, the vibrations from a washing/drying can cause the position of the appliance to change enough to change the readings. Additionally, accelerometers are not perfect.

Instead of focusing on calibration to exactly ZERO and getting it to stay there, I’d focus on getting close to zero and using BIGGER changes in X,Y,Z to suggest movement/vibration. The only time you’d need to know the actual X,Y,Z is if you were using this to detect a door opening or something.

Base your sensor on the idea that the X,Y,Z have changed since your last reading, as opposed to what they have changed to.

1 reply
August 2019 ▶ swiftlyfalling

postlund

Yes, makes sense. So maybe it’s better to just look at the delta between current and previous reading, and use that as a value instead? In that case, calibrating to zero is more or less not needed too.

August 2019 ▶ SpikeyGG

Kem

thank you for you help im sorry i did not replay before i was out of the state for work
i have the sensor working thanks again
2 questions do you place the sensor on top of the dryer or on the side ?
do you use a template sensor to process the data that comes out on the mpu6050 sensor to know if it is on or off ?
if you dont mind posting the sensor config thanks again
i dont know anything about templates any help is greatly appreciated

1 reply
August 2019

SpikeyGG

Hi Kem, I have posted all the required config files onto this thread: Laundry Sensors with NodeMCU and Home Assistant - #19 by SpikeyGG. I did use template sensors to set the state of the washer/dryer, it’s also in the list of config files, called laundry_sensors.yaml.

I put both sensors on the back of the washer and dryer toward the top so I could easily reach the doors between the two units for the reed switches. I used caulking to adhere a piece of fridge magnet I cut to the bottom of the PCB. It wasn’t nearly strong enough to hold the device to the washer/dryer so I used more caulk to glue four neodymium magnets to the corners of that. They stick pretty good now.

Here are some photos I just snapped of my setup.


1 reply
August 2019 ▶ SpikeyGG

Kem

awesome thank you again

September 2019 ▶ SpikeyGG

Xtacy

SpikeyGG seriously thank you you made this really easy :slight_smile: i copy and pasted your esphome code and just changed D8 to something, as well as adjusted the offsets and it works great. i ended up using the gyro as the accel sensors weren’t working too well.

i used your templates too for the sensors and they worked great as well.

i did up a simple automation in node-red for the actual laundry stuff and it works fantastic. it basically waits for washer to turn on…once on it waits for 1 minute. if laundry sensor stays “on” for that entire minute it sets input boolean “stage1” to on. once laundry turns off (end of first rinse cycle), it waits again and when back on it sets stage2. once that turns off (if stage1 and 2 are on) it sends the notification and resets the booleans :smiley:

I can finally get rid of the last piece of my old smartthings setup!

December 2019

laca75tn

Thank you for sharing your project! Would you please answer the following questions?
Why is that you need to connect 3V from the MCU to the ADO of the second MPU-6050? Could you connect the 5V instead of the 3V?

Thank you in advance

1 reply
December 2019 ▶ laca75tn

CountParadox

If the mpu-6050 supports 5v then sure, you should be able to

July 2020

SpikeyGG

Even thought I really like seeing all the raw stats for the washer and dryer solution, I didn’t like how all the decision making was pushed to Home Assistant. I always felt like this was a cop-out when I should have written the ESPHome solution to determine the state of the washer and dryer… so I did!

The benefit of this is that it’s independent of the position of the MPU6050. Previously, I had painstakingly calibrated all my dimensions (accel_x, accel_y, accel_z, gyro_x, gyro_y, gyro_z for both dryer and washer!!). Now the solution is independent of the actual value because it watches for a difference of 1 on accel (movement). I’ve tested it for the last few days and it works great.

This solution keeps all the raw accel and gyro values behind the scenes (saving on database size) but you can always send them out if you want to. I figure: as long as it’s working correctly, no need to send out the raw data.

I use a set of globals to temporarily store the difference from the current value of the accel to the last value. The vibration template binary sensor takes those deltas and checks them against the threshold (in my case 1.0). If they’re all less than the threshold: no vibration and the unit is idle. If any of them is more than the threshold: there is vibration and the unit is working.

The text sensor was added so I could set the state. I wanted to include the door in the calculation like I did previously but I haven’t been able to get it to work the way I want it to and it doesn’t appear that I need it. If you happen to play around with this and find a way to improve it, please share back.

globals:
  - id: dryer_delta_accel_x
    type: float
  - id: dryer_delta_accel_y
    type: float
  - id: dryer_delta_accel_z
    type: float
  - id: washer_delta_accel_x
    type: float
  - id: washer_delta_accel_y
    type: float
  - id: washer_delta_accel_z
    type: float

i2c:
  sda: 4
  scl: 5
  scan: True

sensor:
  - platform: mpu6050
    update_interval: 0.25s
    address: 0x68
    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
  - platform: mpu6050
    update_interval: 0.25s
    address: 0x69
    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
      
binary_sensor:
  - platform: gpio
    device_class: door
    name: "Dryer Door"
    id: dryer_door
    pin:
      number: D7
      inverted: True
      mode: INPUT_PULLUP

  - platform: gpio
    device_class: door
    name: "Washer Door"
    id: washer_door
    pin:
      number: D8
      inverted: True
      mode: INPUT_PULLUP

  - 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)) > 1.0 or abs(id(dryer_delta_accel_y)) > 1.0 or abs(id(dryer_delta_accel_z)) > 1.0) {
        return(true);
      } else {
        return(false);
      }
    filters:
      - delayed_off: 120s
    on_press:
      then:
        - text_sensor.template.publish:
            id: dryer
            state: Drying
    on_release:
      then:
        - text_sensor.template.publish:
            id: dryer
            state: Idle

  - 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)) > 1.0 or abs(id(washer_delta_accel_y)) > 1.0 or abs(id(washer_delta_accel_z)) > 1.0) {
        return(true);
      } else {
        return(false);
      }
    filters:
      - delayed_off: 120s
    on_press:
      then:
        - text_sensor.template.publish:
            id: washer
            state: Washing
    on_release:
      then:
        - text_sensor.template.publish:
            id: washer
            state: Idle

text_sensor:
  - platform: template
    icon: mdi:tumble-dryer
    name: Dryer
    id: dryer

  - platform: template
    icon: mdi:washing-machine
    name: Washer
    id: washer

The simplified output looks like this (much less chaff going into the database):

5 replies
August 2020 ▶ SpikeyGG

FredTheFrog

@SpikeyGG THANK YOU!!! for sharing your updated ESPHome code. I’m running separate ESP8266 modules, one each for washer and dryer. Simple, straight-forward, and an absolute piece of CAKE.

August 2020 ▶ SpikeyGG

FredTheFrog

@SpikeyGG - I have a washer-related question for you. How do you account for the drain/re-fill cycle before rinse? During this time, there is typically no vibration from the washer, and in my case, drain/refill requires a few minutes. I don’t want the automation going off during these few minutes, only after it’s completely done with the spin cycle. Thank you!!

1 reply
August 2020

SpikeyGG

Hi Fred!

You really need to collect some empirical data on how long it might take and set the delayed off value appropriately. Also, I put my vibration sensors close to the water lines on the washer and I think it may be sensitive enough to pick up the vibration of the water flow because I don’t have that problem.

August 2020

FredTheFrog

Okay, that’s what I thought I might have to do. I’ll try to relocate the sensor nearer the hose connections as you describe. Thanks!!

August 2020

FredTheFrog

Okay, I think I’m going to have to extend the basic YAML a bit, include global variables for cycle 1 (wash), cycle 2 (rinse), and cycle 3 (spin) to nail this down. Has anyone here done anything similar, perhaps with a different device? Any and all suggestions greatly appreciated!!

1 reply
August 2020 ▶ FredTheFrog

jivesinger

I found keeping things simple vastly improved reliability.

My washer now only has two states: washing and idle.
I don’t particularly care whether it’s washing/rinsing/spinning, as long as I can consistently tell when it’s finished, I’m happy.

To this end I’ve recently moved from vibration to power sensing as I was unable to reliably temperature compensate the vibration sensor.

1 reply
August 2020 ▶ jivesinger

FredTheFrog

In my case, I want to alert the spouse the washer has completed a cycle. With no discernment, the three vibration cycles are all pretty much the same, only grouped together with segments of idle time between them. Adding a minor bit of intelligence to the ESPHome YAML would make it almost perfect for me. Just gotta think, ask, figure it out. It’s definitely possible, I’m just not experienced enough to toss a few lines into it and have it work. :frowning:

January 2021 ▶ SpikeyGG

MarcoBe

This works pretty sweet, had to change the sensitivity down on the washer (0.35 seemed to do the trick) and increased the time to 5 minutes. Thank you!

August 2021 ▶ SpikeyGG

tfmeier

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?

1 reply
August 2021 ▶ tfmeier

richieframe

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

August 2021

SpikeyGG

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.

1 reply
August 2021 ▶ SpikeyGG

tfmeier

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?

1 reply
August 2021

SpikeyGG

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…

2 replies
August 2021 ▶ SpikeyGG

tfmeier

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

June 2022

nleitao

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

August 2022 ▶ SpikeyGG

zkniebel

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*.

1 reply
August 2022 ▶ zkniebel

zkniebel

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.

1 reply
August 2022 ▶ zkniebel

SpikeyGG

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!

1 reply
August 2022 ▶ SpikeyGG

zkniebel

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.

1 reply
September 2022 ▶ zkniebel

zkniebel

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).

September 2022 ▶ SpikeyGG

zkniebel

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?

1 reply
September 2022

SpikeyGG

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!

1 reply
September 2022 ▶ SpikeyGG

zkniebel

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?

September 2022

Mahko_Mahko

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

September 2022

zkniebel

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!

September 2022

zkniebel

@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:

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:


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 reply
September 2022 ▶ zkniebel

SpikeyGG

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 reply
September 2022 ▶ SpikeyGG

zkniebel

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.