Introduction: Arduino Ultrasonic Water Level Sensor for Espresso Machines

I have a very good but pretty old espresso coffee machine with a removable water tank, the problem is it doesn't provide a warning light for low water level, so I can't know such level before running out of water! OR at least without opening the tank lid, pulling the tank out (I can't see anything from outside, it's hidden inside black plastic external chassis) and and having a direct look to this tank!

I mean, running out of water in the middle of an espresso requires me to stop the pump, open the lid, pull out the tank, fill it with fresh water, put it back inside the machine, then start the motor to fill internal heating tank and wait until it reaches the proper temperature, makes the coffee almost undrinkable (especially for espresso estimators like italians...), in addition to being a very tedious and annoying task!

Why the heck they made a transparent tank if you can't see it from outside, is still a mystery for me.

Anyway, I decided to build a water sensor to warn me when the water is low, allowing me to easily do a couple of cups of coffee before re-filling the tank.

Many solutions found on the 'net were good for any other usage but unacceptable for a coffee machine. During this early phase I had a few limitations in mind:

  1. nothing should be put inside the tank: I don't want any object inside water I'll drink, so any kind of sensor should not release any kind of material/element that could in either result in bad taste or be dangerous (e.g. copper wires could release copper oxide, not exactly a healty drik)!
  2. the removable tank: any sensor should not be attached to the tank, as this could make refill operations pretty unconfortable due to wires;
  3. if possible, the solution should be generic enough to be implemented for most espresso machines (the ones missing internal water level check obviously...)

None of the project found around meet such conditions, so I started a brand new project.

The first version of my sensor was an optical one, a LED on one side and a photoresistor at the other: when the water level is higher than the sensors position, water itself will let the light flow up to the photoresistor, so "light" condition. When the water level is lower than sensor, tank plastic won't let enough light to reach the photoresistor, so this "dark" condition changes the value read (I attached the photoresistor to an Arduino analog input, with proper pullup resistor) should change to a lower one. This way both the limitations are met.

The main problem that comes out with this version was the fact that the difference between "light" and "dark" values was too small, making calibration a bit hard to let the sensor be completely reliable in any condition (e.g. the sensor is not adaptable to espresso machines without the same kind of tank, and if I open the lid the light coming inside changes the readings). thus I decided to move forward to something a bit different.

The best solution was to detect water level using ultrasound, a non-intrusive method, giving also the ability to report water level (and make actions based on such measuring) and not only an "almost empty" warning signal like the optical one.

Now, the front RGB LED will show a shiny and blue color when the tank is full (more than 80% water), green for normal load (30 to 80% full), red for "almost empty" (5 to 30%), and separated red "alarm" LED together with a buzzer sound for "I absolutely need water!" (less than 5%!).

Ok, so this is my UWS, Ultrasonic Water Sensor.

Step 1: Let's Start

My UWS is pretty simple: the sensor measures the distance of the water level based on the time a small high-frequency (40kHz) sound takes to reach the water and bounce back to sensor.

Depending on your espresso machine physical characteristics, you should locate a convenient place for the sensor, keep in mind it should "see" water surface as more vertically as possible. My espresso has a hinged lid over the tank, so I decided to put the sensor over there, but you can use different approaches (i.e. if you have a removable lid).

Parts list:

  • 1 x Arduino UNOr3 (or compatible)
  • 1 x SR04 or SRF05 (best) ultrasonic sensor
  • 1 x RGB LED
  • 1 x red LED
  • 2 x 220 Ohm resistors
  • 1 x buzzer
  • 1 x plastic case
  • 1 x 12V Arduino power supply
  • wires and some stripline pins to solder to

The solution I have chosen is to put the whole sensor+arduino+LEDS inside a single plastic box, installed at the top of the lid, but you can also decide to put the SRF05 over the lid, and Arduino on another side. In this case you should properly protect SRF05 circuit and cable.

The above picture shows the whole schematics.

Step 2: Install the Sensor

Once you decided where you can install your sensor, drill two holes the same size as the two elements of ultrasound module. In my case I put it exactly at the center of the lid, between the two internal spare pod holders (see picture).

Then make identical holes on the external plastic box, so SRF05 sensor will be able to "look" inside the tank while the other components will be safely inside the box, protected from any water contamination. Ultrasonic capsules should not move so pay attention to avoid making too loosy holes (while tight holes won't let you completely fit them), in case use a bit of hot glue to fix them.

Now have a look at the above pictures to make all other necessary holes to the box like the power and USB connectors on one side (next to where you'll put Arduino board), the two LED holes (to front side), then fix Arduino board to the box with a couple of screws and spacers. Now make cabling according to the previous schematics:

  • Ultrasonic sensor (SR04/SRF05):
    • Echo pin to D7 pin
    • Trig pin to D6 pin
    • Vcc and GND to Arduino +5V and GND
  • Buzzer: "+" pin to D3, "-" to GND
  • RGB LED: the three anodes to D9 (blue), D10 (green) and D11 (red), common cathod to GND through 220 Ohm resistor
  • Red (alarm) LED: anode to D12, cathod to GND througn a 220 Ohm resistor

That's it! As you can see on the above pictures, just to make things easier, I used a small piece of prefboard to connect RGB LED, SRF05 pins (I used 5 pin female header to connect them), and Arduino but you can choose whatever you want.

The last pictures above shows the completed work inside the box and how I installed it over the water lid, fixed using some soft double-sided adhesive tape.

Step 3: Upload the Program, and Happy Coffeeing!

Now download the program (both the sketch "WaterLevel.ino" and the library "", used to manage the ultrasonic sensor), connect USB cable and upload the program.

The only change you'll probably need is the sensor range defined by the variables "readFull" and "readEmpty": the values are in centimeters, and represent the measured distances for a full and (almost) empty tank.

To be able to better identify such values, temporarily enable the "#define DEBUG 1" line, and run the program with serial monitor running, the first time with an empty tank (I suggest not to leave it completely empty but with at least 5-10mm of water, to have a little margin), the second with a full one, and read corresponding values over serial. My tank was ok with 3 cm as full level, and 16cm for empty condition.

You can also edit the values for "lBlue", "lGreen", "lRed" and "lEmpty" variables, to change LED light strength (my RGB LED light is too much powerful, so I dimmed it), lower values make lower light levels.

The program also supports an optional 16x2 I2C LCD connected to analog pins A4 (SDA) and A5 (SCL), if you have enough space to fit the display. To enable LCD you need LiquidCrystal_I2C library, then uncomment the line "//#define IS_LCD 1" (i.e. remove the trailing slashes) and compile the sketch.

After proper calibrating "readFull" and "readEmpty" values, you can disable DEBUG line, upload your program and you're ready to use your espresso machine!