The Short Answer
Float Switch - Simple On/Off Detection
What it does
Wiring diagram:
Arduino 5V -------+------- Float Switch ------ Arduino Pin 7
| |
[10k pull-down] [INPUT_PULLUP]
| |
GND ------------------------------ GND
Arduino code
const int FLOAT_PIN = 7;
void setup() {
Serial.begin(9600);
pinMode(FLOAT_PIN, INPUT_PULLUP); // use internal pull-up, no external resistor needed
}
void loop() {
bool waterHigh = digitalRead(FLOAT_PIN) == LOW; // LOW = water above setpoint
Serial.print("Water: ");
Serial.println(waterHigh ? "HIGH" : "LOW");
delay(500);
}
Pros and Cons
|
Pros |
Cons |
|
Dirt cheap ($1-3) |
On/off only - no continuous level data |
|
Dead simple wiring |
Moving parts - can stick or jam in dirty water |
|
Works with any Arduino pin |
Must physically place it at the exact switch point |
|
No calibration needed |
Usually single setpoint - add multiple for multiple levels |
|
Handles AC/DC pump switching directly |
Contact wear over time in frequently switching applications |
HC-SR04 Ultrasonic Sensor - Continuous Non-Contact Level
What it does
Wiring diagram:
HC-SR04 Arduino Uno
-------- -----------
VCC --------> 5V
GND --------> GND
TRIG --------> Pin 9
ECHO --------> Pin 10 (via 1k ohm resistor if needed)
Arduino code (NewPing library)
#include <NewPing.h>
const int TRIG_PIN = 9;
const int ECHO_PIN = 10;
const int MAX_DISTANCE = 200; // cm - max range of HC-SR04
const float TANK_HEIGHT_CM = 30.0; // measure your actual tank height
NewPing sonar(TRIG_PIN, ECHO_PIN, MAX_DISTANCE);
void setup() {
Serial.begin(9600);
}
void loop() {
int distance_cm = sonar.ping_cm();
if (distance_cm == 0) {
Serial.println("Out of range");
} else {
float water_level_cm = TANK_HEIGHT_CM - distance_cm;
float fill_pct = (water_level_cm / TANK_HEIGHT_CM) * 100.0;
Serial.print("Distance: "); Serial.print(distance_cm); Serial.print(" cm | ");
Serial.print("Water level: "); Serial.print(water_level_cm); Serial.print(" cm | ");
Serial.print("Fill: "); Serial.print(fill_pct); Serial.println(" %");
}
delay(500);
}
Pros and Cons
|
Pros |
Cons |
|
Non-contact - nothing in the water |
Accuracy degrades in steam, condensation, or heavy foam |
|
Continuous level - not just on/off |
HC-SR04 is 5V - use a voltage divider on ECHO for 3.3V boards |
|
Cheap (~$3) |
Temperature affects speed of sound - add DS18B20 for temperature compensation |
|
Easy to install |
Beam angle means it needs clearance above water surface |
|
Works for tanks, sumps, reservoirs |
Not ideal for very small containers due to minimum detection distance |
The condensation problem
Pressure Sensor (MPX5010 / Submersible) - Depth Measurement
What it does
MPX5010 wiring (analog, 5V Arduino):
MPX5010 VOUT -----> Arduino A0
MPX5010 GND -----> Arduino GND
MPX5010 VCC -----> Arduino 5V
(also connect a tube from the MPX5010 pressure port to the tank)
Arduino code (MPX5010)
const int PRESSURE_PIN = A0;
const float SENSOR_MAX_KPA = 10.0; // MPX5010 = 0-10 kPa
const float ADC_MAX = 1023.0;
const float GRAVITY = 0.9806; // kPa per cm of water
void setup() { Serial.begin(9600); }
void loop() {
int raw = analogRead(PRESSURE_PIN);
float voltage = (raw / ADC_MAX) * 5.0;
float pressure_kPa = (raw / ADC_MAX) * SENSOR_MAX_KPA;
float depth_cm = pressure_kPa / GRAVITY;
Serial.print("Raw: "); Serial.print(raw);
Serial.print(" | Pressure: "); Serial.print(pressure_kPa, 2); Serial.print(" kPa");
Serial.print(" | Depth: "); Serial.print(depth_cm, 1); Serial.println(" cm");
delay(500);
}
Pros and Cons
|
Pros |
Cons |
|
Direct depth measurement in cm |
MPX5010 is not submersible - requires a tube to the tank |
|
Very accurate - 0.5% typical error |
Submersible modules cost more ($15-30) |
|
Works through condensation, foam, steam |
Tube-based systems can get moisture inside the tube |
|
Analog output - works with any Arduino |
Needs calibration - zero at empty tank, span at full tank |
Capacitive Sensor - Non-Metallic Tank Water Detection
What it does
DIY capacitive sensor wiring:
DIY capacitive plate ----+---> Arduino Pin 2 (send)
|
[1M-10M resistor]
|
+---> Arduino Pin 3 (receive)
|
GND
Arduino code (CapacitiveSensor library)
#include <CapacitiveSensor.h>
// 1M resistor between pins 2 and 3; sensor wire on pin 3
CapacitiveSensor cs = CapacitiveSensor(2, 3);
const long THRESHOLD = 500; // calibrate this value for your setup
void setup() {
Serial.begin(9600);
cs.set_CS_AutocaL_Millis(0xFFFFFFFF); // auto-calibrate
}
void loop() {
long sensorValue = cs.capacitiveSensor(30);
bool waterPresent = sensorValue > THRESHOLD;
Serial.print("Capacitance: "); Serial.print(sensorValue);
Serial.print(" | Water: "); Serial.println(waterPresent ? "YES" : "NO");
delay(200);
}
Pros and Cons
|
Pros |
Cons |
|
Works through non-conductive tank walls - no holes needed |
Requires calibration in the actual tank and liquid |
|
No moving parts, no contact with liquid |
Does not work through metal tanks |
|
Very sensitive to thin water films |
Conductivity of the liquid affects the reading - saltwater reads differently from pure water |
|
DIY-friendly and cheap ($2-5 for DIY) |
Long sensor wires pick up electrical noise - keep wires short or use shielded cable |
|
Multiple sensors can be arranged for multiple setpoints |
Temperature changes the baseline - re-calibrate seasonally |
Optical TIR Sensor (TCRT5000 / Generic) - Point-Level With No Moving Parts
What it does
Wiring:
VCC (3.3-5V) -----> Arduino 3.3V or 5V
GND -----> Arduino GND
DO (digital out) -----> Arduino Pin 8
AO (analog out) -----> Arduino A1 (optional)
Arduino code
const int SENSOR_DIGITAL = 8;
const int SENSOR_ANALOG = A1;
void setup() {
Serial.begin(9600);
pinMode(SENSOR_DIGITAL, INPUT);
}
void loop() {
int digitalVal = digitalRead(SENSOR_DIGITAL); // HIGH = air, LOW = water
int analogVal = analogRead(SENSOR_ANALOG);
Serial.print("Digital: "); Serial.print(digitalVal ? "DRY" : "WET");
Serial.print(" | Analog: "); Serial.println(analogVal);
delay(200);
}
Pros and Cons
|
Pros |
Cons |
|
No moving parts - reliable in dirty water |
Point-level only - one setpoint per sensor |
|
Fast response (1-5 ms) |
Sensor tip must be in contact with or very close to the liquid |
|
Compact - fits in small spaces |
Prism tip sensitive to fouling - algae or scale changes the TIR condition |
|
Works with Arduino at 3.3V or 5V |
Not suitable for opaque or highly coloured liquids |
|
Both digital (ON/OFF) and analog output |
Requires IR LED current-limiting resistor (typically 100-330 ohm) |
Side-by-Side Comparison
|
Sensor |
Type |
Cost |
Arduino Voltage |
Best For |
Key Gotcha |
|
Float Switch |
Point-level |
$1-3 |
5V |
Simple pump control, sump pits |
Moving parts jam in debris |
|
HC-SR04 Ultrasonic |
Continuous |
$3-5 |
5V (3.3V with resistor) |
Water tanks, non-contact, DIY |
Condensation causes false echoes |
|
MPX5010 Pressure |
Continuous |
$10-15 |
5V analog |
Accurate depth in cm |
Tube-based, not submersible |
|
Submersible Pressure Module |
Continuous |
$15-30 |
5V analog or 3.3V |
Deep tanks, wells |
Needs waterproof cable |
|
DIY Capacitive Sensor |
Point or multi-level |
$2-5 |
5V or 3.3V |
Non-metallic tanks, no holes needed |
Requires calibration in your tank |
|
Optical TIR Sensor |
Point-level |
$3-8 |
3.3V or 5V |
Compact detection, clean liquids |
Prism tip fouls in dirty water |
Which Sensor Should You Use?
Use a float switch if...
You only need to know when the water reaches one point - like turning a pump on or off
You want the absolute cheapest, simplest solution
Your tank has debris or fibrous material that would jam a float
Use an HC-SR04 if...
You want continuous fill percentage and your tank has an open top with headroom above the water
You want to monitor a large tank or sump pit without touching the liquid
You are okay doing some math in code to convert distance to fill percentage
Use a pressure sensor if...
You need depth in centimetres and your tank is sealed or underground
You want accuracy better than 1 cm and are willing to calibrate
You are monitoring a sump pit or reservoir and can route a small tube to the sensor
Use a capacitive sensor if...
You cannot put anything inside your tank (food-safe, sealed, pressurized)
You are using a plastic, glass, or ceramic container
You want multiple detection points and can arrange several DIY plates
Use an optical TIR sensor if...
You want point-level detection with no moving parts
Your application is clean water or you can keep the prism tip clean
You need a fast response time (under 10 ms)
Calibration Tips That Forum Posts Skip
Ultrasonic: Temperature Compensation
speed_of_sound = 331.3 + (0.606 * temperature_C); // m/s
distance = (speed_of_sound * travel_time_us / 2) / 10000; // cm
Pressure: Two-Point Calibration
offset = reading_at_empty
span_reading = reading_at_full - reading_at_empty
span_depth = actual_full_height_cm
depth_cm = (current_reading - offset) / span_reading * span_depth
Capacitive: Find Your Threshold
void calibrate() {
Serial.println("Empty tank - leave sensor exposed to air..."); delay(2000);
long dryReading = cs.capacitiveSensor(30);
Serial.println("Now fill tank above sensor, then press a key..."); delay(2000);
long wetReading = cs.capacitiveSensor(30);
long threshold = (dryReading + wetReading) / 2;
Serial.print("Threshold set to: "); Serial.println(threshold);
}
