Introduction: Arduino Ultrasonic Water Level Sensor for Espresso Machines

Picture of 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

Picture of 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

Picture of 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!

Picture of Upload the Program, and Happy Coffeeing!

Now download the program (both the sketch "WaterLevel.ino" and the library "SRF05.zip", 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!

Comments

ChristophS9 (author)2016-02-17

Hi there, great project! Thinking about putting it into a black water (sewage) tank on my boat. What would you expect as a max. distance from sensor to the liquid to make a successful reading? Would you see any difficulties, if the tank is made from steel?

Cheers
Chris

Palms (author)ChristophS92016-02-18

You could try, but I don't think is a good solution for your tank.

First of all, if even clear water could damage the sensor (due to evaporation and general humidity), sewage could do it very quickly due to its corrosive nature...

Secondly, water inside an espresso tank is static, meaning the measured distance to the liquid surface is virtually (almost) a constant, but you can't say it for a tank in a moving and shaking boat. Ultrasonic sensors have a cylindric sensing area, so what you actually read is just the distance of the nearest part of the target (the water/sewage surface), thus you'll get a very "floating" value from it.

Anyway, if want to give it a try you should change sensing routine to store a larger number of consecutive readings (e.g. 50) quickly acquired (e.g. 5 per second) and consider their average as "current value", as already done by the sketch (just increase NUREADS to 50 or more and decrease READINT to 200 or less, and see what happens).

This could let you have a somehow "constant" reading value, proportional to the liquid level, and updated each NUMREADS*READINT/1000 seconds.

For a better "moving average" you can store the latest "n" values in an array, use a pointer to the last read, and a routine to "shift" the array for each new input, something like this:

#define NUMREADS 20
float Dist[20] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
int ptr = -1;
...
void getValue() {
if ( Sensor.Read() >= 0 ) {
float d = Sensor.Distance;
if ( d == 0 )
return;
if ( ptr < NUMREADS-1 )
ptr++;
else
for (int i=1; i<ptr; i++)
Dist[i-1] = Dist[i];
Dist[ptr] = 1.0*d;
float vTot = 0;
for (int i=0; i<=ptr; i++)
vTot += Dist[i];
sensor = vTot / (ptr+1);

Hope it helps.

ChristophS9 (author)Palms2016-02-18

Many thanks, will let you know about the outcome!

Dhiyaa (author)2015-12-03

Hi I tried to make it but I'm getting an error message when i try to verify & compile

Arduino: 1.6.6 (Windows 7), Board: "Arduino/Genuino Uno"

C:\Users\user\Desktop\WaterLevel\WaterLevel.ino:23:51: fatal error: LiquidCrystal_I2C.h: No such file or directory

#include <LiquidCrystal_I2C.h> // Libreria LCD I2C

^

compilation terminated.

exit status 1
Error compiling.

This report would have more information with
"Show verbose output during compilation"
enabled in File > Preferences

i guessed that i had a missing library for the LCD crystal so i searched the library & added it & then compiled again but i got this error:

Arduino: 1.6.6 (Windows 7), Board: "Arduino/Genuino Uno"

WaterLevel:25: error: 'POSITIVE' was not declared in this scope

LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

^

C:\Users\user\Desktop\WaterLevel\WaterLevel.ino: In function 'void setup()':

WaterLevel:72: error: no matching function for call to 'LiquidCrystal_I2C::begin(int, int)'

lcd.begin(16,2);

^

C:\Users\user\Desktop\WaterLevel\WaterLevel.ino:72:17: note: candidate is:

In file included from C:\Users\user\Desktop\WaterLevel\WaterLevel.ino:23:0:

C:\Users\user\Documents\Arduino\libraries\Arduino-LiquidCrystal-I2C-library-master/LiquidCrystal_I2C.h:76:7: note: void LiquidCrystal_I2C::begin()

void begin();

^

C:\Users\user\Documents\Arduino\libraries\Arduino-LiquidCrystal-I2C-library-master/LiquidCrystal_I2C.h:76:7: note: candidate expects 0 arguments, 2 provided

exit status 1
'POSITIVE' was not declared in this scope

This report would have more information with
"Show verbose output during compilation"
enabled in File > Preferences.

thanks for your help in advaance i appreciate it

Palms (author)Dhiyaa2015-12-07

I edited the sketch, now it won't require LiquidCrystal_I2C library anymore, so you should now compile it without any change! Download the updated sketch, and let me know. If in future you'll need 16x2 LCD, uncomment the line "//#define IS_LCD 1" (i.e. remove the trailing slashes) and recompile the sketch. Hope it helps!

Palms (author)Dhiyaa2015-12-04

Edit: btw if you need to let LCD work, check how you installed the library LiquidCrystal_I2C. While searching around the net, I found some topics where users had the same error you encountered, it seems to be related either to an old library release, or a bad installation (e.g. did you make sure to close any open instances of the IDE after changing libraries?). Try loading the "hello world" Example and see if you can compile and execute it.

Palms (author)Dhiyaa2015-12-04

Yep, I included LCD to let me connect a display as an enhancement.

I suspect we're using different library versions, btw If you don't need LCD, simply comment out (or remove) any reference to LiquidCrystal_I2C library and "lcd" object and it'll compile fine!

Palms (author)2015-10-19

I initially forgot to include SRF05 library (despite the name, it handles many ultrasonic sensors like SRF05), now I edited the article and added a ZIP file. you can install it as usual using the IDE, or by manually creating the folder under Arduino "libraries".

tomatoskins (author)2015-10-15

This is great! Thanks for sharing and welcome to the community!

Palms (author)tomatoskins2015-10-15

Thanks! :-)

About This Instructable

5,202views

99favorites

License:

More by Palms:Quick'n'easy fireplace for nativity scene (presepe)Riparare i tasti di un telecomandoHalloween Arduino skeleton
Add instructable to: