If you are building a hydroponics controller, a reverse osmosis (RO) monitor, or an automated aquarium doser, you need to know exactly what is dissolved in your water. A total dissolved solids sensor outputs an analog voltage (typically 0V to 3.3V) proportional to the water's electrical conductivity. To get a usable physical unit (parts per million, or ppm), you must convert that raw ADC reading into voltage, apply a manufacturer-specific polynomial curve, and compensate for water temperature.
Below is the exact bench-tested procedure for interfacing an analog TDS module with an ESP32, including the raw-to-PPM math, the ESP32-specific ADC quirks you must avoid, and a hard recommendation on which module to buy.
How a Total Dissolved Solids Sensor Actually Measures Water Quality
A TDS sensor does not count individual particles; it measures electrical conductivity (EC). Pure water is an excellent insulator. However, when inorganic salts, minerals, and metals dissolve in water, they break apart into positively and negatively charged ions. These ions carry electrical current. The sensor's probe applies an alternating current (AC) voltage across two or more electrodes and measures the resulting current flow. Higher ion concentration means higher conductivity and lower electrical resistance.
Because TDS is technically a gravimetric measurement (evaporating the water and weighing the residue), electronic sensors actually calculate an estimate of TDS by multiplying the measured EC by a conversion factor (usually between 0.5 and 0.7, depending on the dominant dissolved salts). Crucially, quality sensors use AC excitation rather than DC. If a cheap sensor uses DC voltage, it causes electrolysis—bubbles form on the probe, the metal electrodes corrode, and the sensor destroys itself within a few days of continuous submersion.
Wiring, Pinout, and Signal Output Specifications
The most common hobbyist and prosumer module is the DFRobot Gravity Analog TDS Sensor (V2). It features an onboard signal conditioning circuit that outputs a clean analog voltage. While it is marketed for 5V Arduino boards, it operates perfectly on 3.3V logic systems like the ESP32, provided you wire it correctly and adjust your math.
| Sensor Pin | ESP32 Pin | Supply Range | Notes & Bench Tips |
|---|---|---|---|
| VCC | 3V3 | 3.3V to 5.5V | Use the 3.3V pin. Powering with 5V on an ESP32 will feed 5V into the ADC, risking silicon damage. |
| GND | GND | N/A | Keep the ground return path short to avoid 50/60Hz mains hum. |
| AOUT | GPIO 34 | 0V to 3.3V | GPIO 34 is input-only and ADC1-capable. Do not use ADC2 (GPIO 25-27) if WiFi is active. |
The ESP32's internal ADC is notoriously non-linear at the extreme ends of its range (below 0.1V and above 3.1V). If your TDS reading is very low (near 0 ppm) or very high (saturating the probe), the raw ADC values will drift. For critical applications, use the ESP-IDF
adc_cal_characterize() function or stick to the mid-range of the ADC curve (0.5V to 2.5V) by selecting the correct probe range for your expected water quality.
The Raw-to-PPM Math: Converting ADC Reads to TDS
The output signal is strictly analog voltage. To get from a raw 12-bit integer to a physical ppm value, you must pass the reading through three mathematical stages: voltage conversion, polynomial curve fitting, and temperature compensation.
Step 1: ADC to Voltage
The ESP32 features a 12-bit ADC (0 to 4095) with a 3.3V reference. Rather than doing floating-point division manually, use the modern Arduino-ESP32 core function analogReadMilliVolts(), which applies the factory-stored eFuse calibration data automatically.
float voltage = analogReadMilliVolts(34) / 1000.0; // Returns mV, convert to V
Step 2: Voltage to TDS (Polynomial Curve)
Conductivity sensors are not perfectly linear across wide ranges. The manufacturer derives a cubic polynomial to map voltage to ppm for the 0–1000 ppm range. Based on the DFRobot SEN0244 datasheet, the formula at the reference temperature of 25°C is:
float tds_raw = (133.42 * pow(voltage, 3) - 255.86 * pow(voltage, 2) + 857.39 * voltage) * 0.5;
Step 3: Temperature Compensation (TC)
This is where most DIY builds fail. Electrical conductivity changes by approximately 2% per degree Celsius. If you calibrate your sensor in 25°C water and then measure 15°C water, the sensor will read artificially low, even if the TDS hasn't changed. You must pair the TDS probe with a waterproof DS18B20 temperature sensor and apply the standard TC formula:
// tempC is from your DS18B20
float compensationCoefficient = 1.0 + 0.02 * (tempC - 25.0);
float tds_final = tds_raw / compensationCoefficient;
Interference, Calibration, and Failure Modes
When troubleshooting erratic TDS readings on the bench, check these three interference sources before assuming the sensor is dead:
- Air Bubbles on the Electrodes: If a bubble gets trapped between the probe's metal rings, it breaks the electrical path, causing the reading to drop to zero or fluctuate wildly. Fix: Vigorously shake the probe underwater or tap it against the side of the beaker to dislodge bubbles before taking a reading.
- 50/60Hz Mains Noise: Because the sensor measures tiny changes in resistance, it acts as an antenna for AC hum from nearby power supplies or water pumps. Fix: Use a twisted-pair cable for the probe connection, keep the signal wire away from AC lines, and implement a software moving-average filter (e.g., sampling 20 times over 2 seconds and averaging the median).
- Probe Fouling and Scaling: Over time, calcium and biological films coat the electrodes, insulating them from the water. Fix: Clean the probe monthly with a mild vinegar solution or isopropyl alcohol. Never use abrasive pads, which will scratch the platinum/titanium coating and alter the cell constant.
According to the US Geological Survey (USGS), specific conductance is highly dependent on the types of ions present. If you are measuring a solution with unusual salts (like heavy hydroponic nutrient mixes high in potassium sulfate), the default 0.5 conversion factor in the polynomial may be slightly off. For absolute lab-grade accuracy, you must perform a two-point calibration using distilled water (0 ppm) and a known 342 ppm NaCl calibration solution.
Decision Matrix: Which TDS Module Should You Buy?
The market is flooded with generic "TDS modules" that lack proper AC excitation or signal conditioning. Use this decision path to select the right hardware for your embedded project.
| Module Type | Example Part Number | Price Range | Output | Best Use Case |
|---|---|---|---|---|
| Generic Bare Probe + Op-Amp Board | Unbranded (Amazon/eBay) | $5 - $12 | Analog (Noisy) | Avoid. Often uses DC excitation, destroying the probe via electrolysis within weeks. |
| Integrated Analog Gravity Module | DFRobot SEN0244 (V2) | $30 - $45 | Analog (0-3.3V) | Hydroponics, RO water monitoring, ESP32/Arduino DIY builds requiring good accuracy. |
| Lab-Grade Digital/I2C Module | Atlas Scientific EZO-TDS | $160 - $190 | I2C / UART / RS-485 | Commercial aquaculture, industrial process control, environments requiring NIST-traceable calibration. |
The Final Decision Path
- IF your budget is under $50, you are using an ESP32/Arduino, and you are building a hydroponic, aquarium, or home RO system → Choose the DFRobot Gravity Analog TDS (SEN0244). The onboard AC excitation and voltage conditioning save you hours of analog circuit design.
- IF you are building a commercial product, require I2C/RS-485 isolation to prevent ground loops, or need NIST-certified accuracy for regulatory compliance → Choose the Atlas Scientific EZO-TDS. It handles all polynomial math and temperature compensation internally, outputting a clean digital string.
- IF you are tempted to buy the $8 unbranded generic TDS module with a bare 4-pin op-amp board → Stop. The lack of proper AC driving circuitry will result in probe degradation and unusable noise.
analogReadMilliVolts() function on an ESP32 ADC1 pin, and apply the temperature compensation formula above. You will achieve ±10% accuracy, which is more than sufficient for managing nutrient dosing and water filtration systems.






