If you need to measure liquid level in a standard plastic or fiberglass water tank with an ESP32, use a top-mounted JSN-SR04T V2.0 ultrasonic sensor. It outputs a 5V digital pulse representing time-of-flight, requires no tank-wall dielectric calibration, and costs around $12. While capacitive sensors seem easier to stick on the outside of a tank, they are highly susceptible to condensation and wall-thickness variations. Below is the exact wiring, raw-to-unit math, and decision framework to get your level sensor online without bricking your microcontroller.

The Sensing Principle: Ultrasonic vs. Capacitive Detection

Ultrasonic level sensors operate on the time-of-flight principle. A piezoelectric transducer emits a 40kHz acoustic pulse downward toward the liquid surface. The pulse reflects off the liquid-air boundary and returns to the receiver. By measuring the microsecond delay between the trigger pulse and the echo, the sensor calculates the distance to the liquid. Because sound travels at a known speed through air (roughly 343 meters per second at 20°C), this time delta translates directly into physical distance. The liquid level is then derived by subtracting this distance from the total known height of the tank.

Capacitive liquid level sensors, conversely, rely on dielectric permittivity. The sensor acts as one plate of a capacitor, while the liquid acts as the other (or alters the dielectric medium between plates). As the liquid rises, the capacitance increases because water has a much higher dielectric constant (≈80) than air (≈1). Non-contact capacitive sensors measure this change through the plastic wall of a tank. The internal ASIC converts this capacitance shift into a proportional analog voltage or a digital high/low threshold signal.

Wiring, Pinouts, and Output Signal Types

A common bench mistake is conflating digital pulse outputs with analog voltage outputs, or feeding a 5V echo signal directly into a 3.3V ESP32 GPIO. The table below defines the exact electrical characteristics for the two most common hobbyist/industrial-lite sensors.

Sensor Model Supply Range Output Type Output Signal ESP32 Wiring Note
JSN-SR04T V2.0 5.0V DC Digital (Pulse) 5V HIGH pulse width Requires 1kΩ/2kΩ voltage divider on Echo pin
DFRobot SEN0391 3.3V - 5.0V DC Analog (Voltage) 0V to 3.3V continuous Direct connect to ESP32 ADC1 pins (GPIO 32-39)
⚠️ Hardware Warning: The JSN-SR04T Echo pin outputs a 5V logic HIGH. The ESP32 GPIO pins are strictly 3.3V tolerant. Feeding 5V into GPIO 4 will permanently damage the pin's internal clamping diodes. Always use a voltage divider (e.g., 1kΩ resistor in series with the Echo pin, and a 2kΩ resistor to ground) to drop the 5V signal down to a safe ~3.3V.

The Math: Converting Raw Readings to Physical Units

Microcontrollers do not read liters or centimeters; they read clock cycles and ADC integers. Here is the exact math to convert those raw values into usable physical units.

Ultrasonic (JSN-SR04T): Time-of-Flight to Centimeters

The ESP32 pulseIn() function returns the duration of the echo in microseconds (µs). To find the distance in centimeters, multiply the time by the speed of sound in cm/µs, and divide by two (since the sound travels down and back).

// Speed of sound at 20°C = 343 m/s = 0.0343 cm/µs
float distance_cm = (pulse_duration_us * 0.0343) / 2.0;
float liquid_level_cm = tank_total_height_cm - distance_cm;

Calibration needed: The speed of sound changes by roughly 0.6 m/s for every 1°C change in air temperature. If your tank is outdoors or in an unheated garage, you must add a DS18B20 temperature probe to the enclosure and compensate the math: speed_of_sound = 331.4 + (0.606 * temp_celsius);.

Capacitive (SEN0391): ADC Raw to Percentage

The ESP32 features a 12-bit ADC, returning raw integers from 0 to 4095. However, the ESP32 ADC is notoriously non-linear below 0.1V and above 3.1V. To get an accurate reading, map the voltage to a percentage based on empirical empty and full readings.

int raw_adc = analogRead(34); // Read from GPIO 34
float voltage = raw_adc * (3.3 / 4095.0);

// Calibration constants gathered during bench testing
float v_empty = 0.45; // Voltage when tank is bone dry
float v_full = 2.85;  // Voltage when tank is 100% full

float level_percent = map(voltage, v_empty, v_full, 0, 100);
level_percent = constrain(level_percent, 0, 100);

Calibration needed: You must physically measure v_empty and v_full on your specific tank. The dielectric constant of the plastic, the wall thickness, and the exact adhesive placement will shift these baseline voltages by up to 15% between identical tanks.

Real-World Interference and Signal Conditioning

Both sensor types fail in specific environmental conditions. Understanding these interference sources prevents you from chasing software bugs when the issue is purely physical.

  • Ultrasonic Interference: Sound waves scatter when they hit turbulent surfaces or foam. If your tank is filled via a high-pressure top inlet, the splashing water will create acoustic noise, resulting in erratic pulseIn() timeouts. Furthermore, heavy vapor or condensation on the transducer face will dampen the 40kHz signal. Fix: Implement a 5-sample median filter in software and mount the sensor away from the direct fill stream.
  • Capacitive Interference: Non-contact capacitive sensors are highly sensitive to stray capacitance. If condensation forms on the outside of the tank wall where the sensor is mounted, the water droplets will trick the sensor into reading a falsely high level. Thick tank walls (>10mm) or double-walled IBC totes will completely block the capacitive field. Fix: Seal the sensor edge with marine-grade silicone to prevent moisture ingress behind the pad.

For deeper technical context on acoustic signal conditioning, refer to the Texas Instruments Ultrasonic Sensing Guide, which details hardware bandpass filtering for noisy environments. For ESP32-specific ADC quirks, consult the official Espressif ADC Oneshot Driver Documentation.

Decision Tree: Picking the Right Sensor for Your Tank

Do not default to the cheapest sensor on Amazon. Use this decision matrix to select the correct hardware for your specific tank geometry and liquid type.

Tank Condition / Constraint If True, Choose... Why?
Tank is metal (steel/aluminum) Top-Mount Ultrasonic Metal blocks capacitive fields entirely; ultrasonic reflects perfectly off liquid inside metal.
Liquid produces heavy foam/suds Submerged Hydrostatic Pressure Foam absorbs ultrasonic sound and alters capacitive dielectrics. Pressure ignores foam.
Tank is sealed, no top access Non-Contact Capacitive (XKC-Y25) Can read through the plastic wall from the outside without drilling holes.
Standard plastic water tank, top access available Top-Mount Ultrasonic (JSN-SR04T) Immune to outside-wall condensation; no dielectric calibration required.
🏆 The Default Pick: If you are building a standard home automation water tank monitor (e.g., a 1000L plastic rain barrel or IBC tote) and have access to the top lid, buy the JSN-SR04T V2.0. It costs roughly $12, the waterproof transducer head survives high humidity, and the time-of-flight math requires zero tank-specific dielectric calibration. Just remember to build that 1kΩ/2kΩ voltage divider for your ESP32.

By matching the sensing principle to your physical constraints and applying the correct raw-to-unit scaling, you eliminate the most common failure points in embedded fluid monitoring. Wire the divider, calibrate your baseline constants, and deploy your node.