Get a phone alert when the washing machine finishes

An MPU-6050 in a printed pod feels the washing machine shaking. When the shaking stops for good, Blynk sends a notification that your washing is done.
  • Level:Advanced
  • Duration: 1 h
  • Ages 12+
  • Platform: ESP32

Tools for this lesson

Helpful for this build. Open a tool to see tips and more projects that use it.

Get a phone alert when the washing machine finishes – EEMENTOR STEM™ lesson

Washing machines beep when they finish, but you don't hear it in another room, and wet washing left in the drum starts to smell. In this lesson you build a sensor that feels the machine shaking. It works out when a wash has started and, when the shaking stops for three minutes, sends a notification to your phone. It works with any washing machine or dryer, because nothing is connected to the machine: the sensor just sits on top.

What you'll learn

  • How to read an accelerometer directly over I2C with the Wire library
  • How to measure vibration as the change between readings
  • How to tell a real stop from a short pause
  • How to show a level and a status in Blynk

What you need

  • ESP32 board, expansion board and USB cable (ESP32 IoT Starter Kit)
  • GY-521 MPU-6050 module (45-in-1 Sensor Kit)
  • 4 female-to-male jumper wires, long enough to reach from the machine to the ESP32
  • A free Blynk account and the Blynk IoT app on a phone
  • A 2.4 GHz Wi-Fi network
  • A strong double-sided mounting strip
  • The printed parts from the 3D printing box below (sensor pod and lid), or the cardboard version described there
  • Breadboard and jumper wires (ESP32 IoT Starter Kit)

Wiring

Breadboard wiring diagram: Get a phone alert when the washing machine finishes
Breadboard view. Check each connection against the wiring table below.
From To
MPU-6050 VCC ESP32 3V3
MPU-6050 GND GND
MPU-6050 SCL ESP32 GPIO 22
MPU-6050 SDA ESP32 GPIO 21

Safety: a washing machine uses mains electricity and water. Only stick the pod on the outside of the machine, keep the ESP32 and its USB charger away from water, and never open the machine.

Set up Blynk

In the Blynk console, create a new template called Laundry Alert (hardware ESP32, connection type Wi-Fi) and add these datastreams. Lesson 1 of this path shows each step in detail.

Virtual pin Name Data type Range Phone widget
V0 Status String – Label
V1 Vibration Integer 0–100 Gauge or Superchart
V2 Minutes running Integer 0–300 Value display

Then open the template's Events & Notifications tab, add an event with the code laundry_done (name: Laundry done) and turn on push notifications for it. The event code must match the sketch exactly.

Save the template, create a new device from it and copy its three BLYNK_… lines. In the phone app, open the device, tap the wrench icon and add a Label (V0), a Gauge or Superchart (V1) and a Value display (V2). Link each widget to its datastream.

Example screen for: Get a phone alert when the washing machine finishes
Example screen with sample values. Yours may look different.

The sketch

Replace the three BLYNK_… lines at the top with the ones from your device's Device info page, and add your Wi-Fi name and password (2.4 GHz only). The BLYNK_… lines must stay above #include <BlynkSimpleEsp32.h>.

This sketch reads the MPU-6050 directly with the built-in Wire library, so it needs no extra sensor library.

#define BLYNK_TEMPLATE_ID "YOUR_TEMPLATE_ID"
#define BLYNK_TEMPLATE_NAME "Laundry Alert"
#define BLYNK_AUTH_TOKEN "YOUR_AUTH_TOKEN"
#define BLYNK_PRINT Serial          // show connection messages in the Serial Monitor

#include <WiFi.h>
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>
#include <Wire.h>

char ssid[] = "YOUR_WIFI_NAME";
char pass[] = "YOUR_WIFI_PASSWORD";

const int MPU = 0x68;                      // I2C address of the MPU-6050
const int SHAKING = 12;                    // vibration level that counts as "running"
const unsigned long START_AFTER = 60000;   // shaking for 1 min = a wash has started
const unsigned long DONE_AFTER = 180000;   // still for 3 min = the wash is over

int16_t lastX, lastY, lastZ;
long vibrationSum = 0;
int samples = 0;
bool running = false;
unsigned long shakingSince = 0, stillSince = 0, startedAt = 0;
BlynkTimer timer;

void readAccel(int16_t &x, int16_t &y, int16_t &z) {
  Wire.beginTransmission(MPU);
  Wire.write(0x3B);                        // first acceleration register
  Wire.endTransmission(false);
  Wire.requestFrom(MPU, 6);
  x = (Wire.read() << 8) | Wire.read();
  y = (Wire.read() << 8) | Wire.read();
  z = (Wire.read() << 8) | Wire.read();
}

// Called 50 times a second: how much has the sensor moved since last time?
void sample() {
  int16_t x, y, z;
  readAccel(x, y, z);
  vibrationSum += abs(x - lastX) + abs(y - lastY) + abs(z - lastZ);
  samples++;
  lastX = x; lastY = y; lastZ = z;
}

// Called every 2 seconds: decide whether the machine is running
void decide() {
  int level = constrain(vibrationSum / max(samples, 1) / 10, 0, 100);
  vibrationSum = 0;
  samples = 0;
  unsigned long now = millis();
  bool shaking = level >= SHAKING;

  if (shaking) {
    stillSince = 0;
    if (shakingSince == 0) shakingSince = now;
  } else {
    shakingSince = 0;
    if (stillSince == 0) stillSince = now;
  }

  if (!running && shakingSince && now - shakingSince > START_AFTER) {
    running = true;
    startedAt = now;
    Blynk.virtualWrite(V0, "Washing...");
  }
  if (running && stillSince && now - stillSince > DONE_AFTER) {
    running = false;
    int minutes = (stillSince - startedAt) / 60000;
    Blynk.virtualWrite(V0, "Done! Empty the machine");
    Blynk.logEvent("laundry_done", String("Your washing is done after ") + minutes + " minutes.");
  }

  Blynk.virtualWrite(V1, level);
  Blynk.virtualWrite(V2, running ? (int)((now - startedAt) / 60000) : 0);
  Serial.printf("vibration %d %s\n", level, running ? "(running)" : "");
}

void setup() {
  Serial.begin(115200);
  Wire.begin(21, 22);
  Wire.beginTransmission(MPU);
  Wire.write(0x6B);                        // power register
  Wire.write(0);                           // wake the sensor up
  Wire.endTransmission();
  readAccel(lastX, lastY, lastZ);

  Blynk.begin(BLYNK_AUTH_TOKEN, ssid, pass);
  Blynk.virtualWrite(V0, "Waiting for a wash");
  timer.setInterval(20L, sample);
  timer.setInterval(2000L, decide);
}

void loop() {
  Blynk.run();
  timer.run();
}

Tune it to your machine

  1. Upload the sketch with the pod lying still on the table and open the Serial Monitor at 115200 baud. The vibration level should be 0 to 5.
  2. Tap the table next to it: the level jumps up for a moment.
  3. Stick the pod on the machine and start a wash. Watch the Vibration gauge in the app: when the drum turns it should stay above 12 most of the time.
  4. If it doesn't, make SHAKING smaller. If the level is above 12 even when the machine is off (for example because of a fridge nearby), make it bigger.

How it works

The MPU-6050 measures acceleration in three directions. When it lies still, the readings hardly change; when the machine shakes, they change a lot from one reading to the next. sample() adds up those changes 50 times a second, and decide() turns the average into a vibration level from 0 to 100.

A wash has pauses: the drum stops to change direction, and the machine waits while it fills with water. That is why the sketch only says "running" after a full minute of shaking and only says "done" after three minutes of stillness. Times like these, which stop a short change from switching the state, are called debouncing, the same idea as for buttons, only much slower.

Try this next

  • Also send a notification when the wash starts, with the time it is likely to finish.
  • Count washes per week and show them in a Superchart.
  • Use the same sensor on a tumble dryer or dishwasher. Do you need different times?

Troubleshooting

  • The device shows "Offline" in the app: check the Serial Monitor at 115200 baud. "Invalid auth token" means the BLYNK_AUTH_TOKEN line is wrong; if it never connects, check the Wi-Fi name and password, and that your network is 2.4 GHz.
  • The vibration level is always 0: check SDA on GPIO 21 and SCL on GPIO 22. The module needs 3V3, not 5V.
  • "Done" arrives in the middle of a wash: make DONE_AFTER longer, for example 300000 (5 minutes).
  • It never says "Washing": make SHAKING smaller, see above.
  • A printed part is too tight or too loose: printers differ by a few tenths of a millimetre. Sand or file a tight hole, and fix a loose part with a drop of hot glue or a strip of tape.

Build it yourself

Everything used in this lesson comes in one kit, with parts tested by our engineers.

ESP32 IoT Starter Kit | Arduino IDE Compatible | Free Tutorials $57.00

Shop the kit