Introduction: Washing Machine Notification Sensor

This washing machine sensor sits on top of my washing machine and uses an accelerometer to detect vibration from the machine. When it senses the wash cycle has finished, it sends me a notification on my phone. I built this because the machine itself no longer beeps when it is finished and I was tired of forgetting to take out the laundry.

The code can be found here: https://github.com/alexspurling/washingmachine

Full parts list:

Step 1: Prototype

The device uses an ESP32 microcontroller. In this case I am using the Lolin32 development board by Wemos which you can buy on AliExpress for about $7. The accelerometer is the Sparkfun LIS3DH - it's important the accelerometer is digital rather than analog as you will see later. The battery I took from a old set of bluetooth speakers.

The ESP32 connects to the accelerometer via I2C. The first version of the code simply polled the three acceleration axes (x, y and z) for the measured acceleration value every 20ms. Placing the breadboard prototype on the washing machine and I produced the above graph which shows acceleration peaks during various phases of the wash cycle. Those peaks where absolute acceleration was greater than 125mg (125 thousandths of normal gravity) are shown in orange. We want to detect these periods and use them to determine the status of the washing machine.

How to determine if the machine is on or off?

One of the goals of building this device was that it would be entirely passive. I.e. no buttons should need to be pressed; it would just work. It also should be very low power as it was not really possible to extend power cables to the washing machine in my case.

Luckily the LIS3DH accelerometer has a feature where it can trigger an interrupt when acceleration exceeds a given threshold (note, this requires use of the accelerometer's built-in high-pass filter - see the code on Github for details) and the ESP32 can be woken up from its deep sleep mode via an interrupt. We can use this combination of features to create a very low power sleep mode that is triggered by movement.

The pseudo code would look something like this:

# Device wake up
notification_threshold = 240
counter = 10
accelerometer.set_threshold(96) #96mg
while counter > 0:
    if accelerometer.above_threshold():
        counter++
    else:
        counter--
    if counter > notification_threshold:
        # final spin cycle detected
    sleep(1 second)
accelerometer.set_threshold_interrupt()
esp32.set_wakeup_trigger_on_interrupt()
esp32.deep_sleep()

You can see here that we use a counter to detect how many seconds of acceleration we have detected during the current wake period. If the counter drops to zero then we can put the device back to sleep. If the counter reaches 240 (the notification threshold) then that means we have detected 4 minutes of vibration. We can tweak the values of these thresholds to make sure the device correctly detects the final spin cycle. Once sufficient vibration is detected, we can simply sleep for another 5 minutes (in my case this is how long it takes until the wash actually completes) before sending a notification.

Step 2: Sending a Notification Via Blynk

Blynk is a service designed to allow interaction with IoT devices with an app on your phone. In this case, I am using the push notification API which is triggered by a simple HTTP POST to the Blynk API.

Step 3: ​Measuring Power Consumption and Estimating Battery Life

The ESP32 chip is advertised as having very low power consumption when in deep sleep (as low as 5uA). Unfortunately, the circuitry on the many different development boards provide very different power consumption characteristics - not all ESP32 dev boards are created equal. For example, when I first started this project, I used the Sparkfun ESP32 Thing which would consume around 1mA of power in deep sleep mode (even after disabling the power LED). Since then I have been using the Lolin32 (not the Lite version) on which I measured a current of 144.5uA while in deep sleep mode. To do this measurement, I simply wired a multimeter in series with the battery and the device. This is certainly easier to do while prototyping with a breadboard. I also measured the current usage when the device is awake:

  • Deep sleep: 144.5uA
  • Awake: 45mA
  • Wifi enabled: 150mA

Assuming I use the machine twice a week, I estimated the following timings for the time the sensor spends in each state:

  • Deep sleep: 604090 seconds (~1 week)
  • Awake: 720 seconds (12 mins)
  • Wifi enabled: 10 seconds

From these figures, we can estimate how long the battery is going to last. I used this handy calculator to get an average power consumption of 0.2mA. Estimated battery life is 201 days or about 6 months! In reality I have found the device will stop working after about 2 months so there could be some errors in measurements or the capacity of the battery.

Step 4: Measuring Battery Level

I thought it would be nice if the device could tell me when the battery is running low so I know when to charge it. To measure this we need to measure the voltage of the battery. The battery has a voltage range of 4.3V - 2.2V (the minimum operating voltage of the ESP32). Unfortunately, the voltage range of the ADC pins of the ESP32 is 0-3.3V. This means, we need to step the voltage of the battery down from its maximum of 4.3 to 3.3 to avoid overloading the ADC. This is possible to do with a voltage divider. Simply wire two resistors with the appropriate values from the battery to ground and measure the voltage in the middle.

Unfortunately, a simple voltage divider circuit will drain power from the battery even when the voltage is not being measured. You can mitigate this by using high value resistors but the down side is that the ADC might not be able to draw enough current to make an accurate measurement. I decided to use resistors with values of 100kΩ and 330kΩ which will drop 4.3V to 3.3V according to the this voltage divider formula. Given a total resistance of 430kΩ, we would expect a current draw of 11.6uA (using Ohm's law). Given our deep sleep current usage is 144uA, it is a reasonably significant increase.

As we only want to measure the battery voltage once just before sending a notification, it makes sense to turn off the voltage divider circuit during the time when we aren't measuring anything. Luckily, we can do this with a couple of transistors connected to one of the GPIO pins. I used the circuit given in this stackexchange answer. You can see me testing the circuit with an Arduino and a breadboard in the photo above (note there is an error in the circuit which is the reason I am measuring a higher voltage than expected).

With the above circuit in place, I use the following pseudo code to obtain a battery percentage value:

battery_percentage():
    # enable battery voltage circuit
    gpio_set_level(BATTERY_EN_PIN, HIGH)
    # Battery level is returned as an integer between 0 and 4095
    adc_value = adc1_get_value(ADC_PIN)
    # enable battery voltage circuit
    gpio_set_level(BATTERY_EN_PIN, LOW)
    
    float adc_voltage = adc_value * 3.3 / 4095 
    # voltage divider uses 100k / 330k ohm resistors
    # 4.3V -> 3.223, 2.4 -> 1.842
    expected_max = 4.3*330/(100+330)
    expected_min = 2.4*330/(100+330)
    battery_level = (adc_voltage-expected_min)/(expected_max-expected_min)
    return battery_level * 100.0 <br>

Step 5: Making It Prettier

While the breadboard version works fine, I wanted to put it into a package that would be neater and more reliable (no wires that can come loose or short out). I managed to find the perfect project box for my needs which was the right size, included a pin board, mounting holds and screws to put it all together. Also, it was dead cheap at less than £2. After receiving the box, all I had to do was solder the components onto the pin board.

Perhaps the trickiest part of this was fitting all the battery voltage circuit components onto the small space next to the Lolin32. Luckily with a bit jiggery pokery and the appropriate connections made with solder the circuit fits in neatly. Also, since the Wemos Lolin32 does not have a pin to expose the positive battery terminal, I had to solder a wire from the battery connector to the pin board.

I also added an LED which flashes when the device has detected movement.

Step 6: Finishing Touches

I super-glued 4 6mm x 4mm neodymium magnets to the base of the box which allows it to stick securely to the metal top of the washing machine.

The project box already comes with a small hole to provide access for cables. Luckily, I was able to position the ESP32 board close to this hole to give access to the micro USB connector. After enlarging the hole with a craft knife, the cable fit perfectly to allow for easy charging of the battery.

If you are interested in any of the details of this project, please feel free to leave a comment. If you would like to see the code, please check it out on Github:

https://github.com/alexspurling/washingmachine