Is the wash done?

Checking if the washing machine is done is a popular (not to mention useful) application. This is often done by sticking LDRs to the washing machine, adding IMU sensors or analyzing mains power usage or even the sound emitted.

I needed a solution with minimal time effort as I have lots of other things I want to do so I went with a Raspberry Pi Zero W and a PiCamera. Starting as “wash monitor” it transformed to “appliance monitor” as any appliance can be monitored. I have a single Raspberry Pi keeping an eye on both the washing machine and the tumble dryer.

The idea is simple, take a picture, process and count pixels:

  • All black: lights are off and the machine is off
  • Most black: lights are off and the machine is on
  • Few black: lights are on, machine state is unknown

Next, the “lights” and “machine” states are tracked and a notification is sent when “machine” goes from “on” to “off”. Pushover is used as notification service and MQTT for general service monitoring.

There are a few prerequisites that make this solution actually work (yes I know you objected to the idea):

  1. My washing machine is in the basement, ie. in a “controlled light environment”.
  2. The lights in the laundry room are Ikea Trådfri ones activated by a motion sensor and they switch off after a few minutes meaning we will never be stuck in the “lights are on, machine state unknown” state.
  3. Normally no-one enters the laundry room minimising the risk of false positives by a person dressed in black pants standing in front of the camera.

The system works great for me but might be completely useless to you 😀

MJPEG Streamer is used for snapping pictures and ImageMagick for processing. Pictures are cropped to only reveal the display which increases the percentage of non black pixels when the machine is on. Blurring is used to increase specular highlight of the LEDs, a threshold filter is applied making sure we end up with only black and white pixels (and no image sensor noise) and finally the histogram is calculated. The Pi is taped to the wall opposite the machines so it will not move (which would mess up the cropping).

Here is an unprocessed cropped picture of the washing machine display when the room is lit:

0% completely black pixels

(Applying blur and threshold filters now yields a completely white picture from which we can only determine the lights are on)

The same picture with the lights off:

Blur and threshold filters applied:

~84% completely black pixels

Lights off, machine off, blur and threshold filters applied:

100% completely black pixels

Installing and configuring

First clone this the Appliance Monitor repo:

git clone

You need ImageMagick, Python Requests and Paho MQTT and MJPG Streamer (and of course lots of stuff to be able to build):

sudo apt-get install imagemagick
sudo apt-get install python3-pip
sudo pip3 install paho-mqtt requests
sudo apt-get install build-essential git libjpeg8-dev imagemagick libv4l-dev cmake
git clone
cd mjpg-streamer/mjpg-streamer-experimental
make && sudo make install

To spare the poor MicroSD card I use a RAM disk for image processing and a script is provided that adds the RAM disk to /etc/fstab:

sudo ./

Next, copy sampleconfig.yml and modify as needed (there are lots of comments to guide you). The “image processing parameters” section can be skipped for now.

A start script for MJPG Streamer is included where parameters such as white balance can be set:

sudo /home/pi/appliancemon/ start

If this fails, check the bcm2835 Video4Linux driver module is loaded and then try to start MJPG Streamer again:

sudo modprobe bcm2835-v4l2

To make it load on boot:

sudo echo "bcm2835-v4l2" >> /etc/modules

Snap a picture:

curl -so image.jpg "http://wash.local:8080/?action=snapshot.png"

Use this image to determine the crop area specified in ImageMagick style (blur and threshold are also IM style, check the ImageMagick documentation for help).

Now try the cropping and calculate the black level. The last two zeroes are “blur” and “threshold” (zero means disable).

./ -c washconfig.yml -t "290x120+20+410 0 0" ; open image-proc-washer.png
Black level: 0%

Now turn on the machine, turn off the lights and apply blur and threshold:

./ -c washconfig.yml -t "290x120+20+410 0x6 6"
Black level: 94%

And finally turn the machine off:

./ -c washconfig.yml -t "290x120+20+410 0x6 6"
Black level: 100%

You may need to elaborate with the blur and threshold parameters to get satisfactory black levels. I use the ones in the sample config for both my washing machine and tumble dryer.

Finally add the following lines to crontab -e:

@reboot /home/pi/appliancemon/ start
@reboot /home/pi/appliancemon/ -c /home/pi/washconfig.yml &
@reboot /home/pi/appliancemon/ -c /home/pi/dryerconfig.yml &

Code on GitHub as always.

Building a low cost wifi camera

Update! Here is a post with the BOM for the project.

Sometime ago I came across the Arducam Mini which is quite a nice camera module from UCTronics. It is a small PCB with a two megapixel OmniVision OV2640 sensor, an interchangeable lens and an FPGA to do the heavy lifting of image processing and JPEG encoding. Priced at around 24 Euros (lens included) you can easily buy a few without hurting your wallet and combined with an ESP8266 you can build quite a low cost wifi camera. Or several. Because designing and building PCBs is both fun and inexpensive I designed a board to go with the ESP8266/Arducam Mini combo, aptly named the Esparducam. And uniquely named too, try googeling for “esparducam“. Heck, even the domain name is available at the time of writing 🙂

The Espaducam board
The Espaducam board

Anyhow. The Esparducam board is a development board for the Arducam Mini module and is quite well suited for ESP8266 development in general.

Espaducam with Arducam Mini module
Espaducam with Arducam Mini module

The board is powered through a barrel connector at a minimum of 5V (upper limit untested) and all the IO pins on the ESP8266 are available on pin headers. The double rows are intended for the design of small breakout boards that sit on the inner 0.1″ aligned headers while the outer headers allow for connecting logic analyzers/oscilloscopes and so on. The Arducam Mini module plugs right into the front header and the standard FTDI connector is at the back of the board.

Image quality is, imho, quite decent at this price point, here are a few samples.

An optional SPI flash can be mounted for image storage and you can connect a standard eBay PIR module to the white JST header next to the FTDI connector if you want to build a motion triggered camera.

I am no hardware engineer but if you are and you find any silly design mistakes please let me know.


You can order the Esparducam board form DirtyPBCs and I would love to know if you build one. I plan to build a few for house monitoring, kite photography, reading my water meter and whatever else I can come up with.

The demo application listens to port 80 for HTTP GETs and will capture and return an image. It also has a command line interface on the serial port and the command ‘upload:<ip number>’ will capture an image and upload it via HTTP. A Python script is included that will receive and display the image using your system’s default image viewer. Note that the demo application is just that, a demo application. It does not handle simultaneous clients, errors or anything else that occurs in the real world.

IMG_3761Lastly a note about the lens. It uses a mount called M12xP0.5 and there are plenty of lenses to choose between. The one included with the Arducam Mini module has about the same field of view as a normal 50mm lens on a full frame DSLR. I would recommend getting a 3.2mm lens or shorter for some more wide angle if you plan to use the module for surveillance applications. The 3.2mm lens (called LS-40136) can focus at a very short distance making it a candidate for water meter reading applications.

I have yet to try the even shorter ones like the LS-20150 at 2.8mm or the LS-40166 at 2.6mm.

The Esparducam turned out so nice it became my preferred ESP8266 development board, why is a different post.

Code and hardware schematics as always on Github.