Components · 11 min read

TDS Sensor Arduino: Measure ppm, Calibrate, Monitor Water Quality

How to use a TDS sensor with Arduino: what ppm means, DS18B20 temperature compensation, calibration, drinking water, aquarium and hydroponic values, ESP32 log.

Combine a TDS sensor with Arduino and you get a cheap water quality meter that shows in a few seconds, in ppm (parts per million), how many dissolved minerals, salts and metals are in the water. TDS (Total Dissolved Solids) is the most practical measure for judging tap water hardness, checking whether a water filter still works, knowing when to change aquarium water or gauging the strength of a hydroponic nutrient solution. Pen-style TDS meters work on the same principle; with an Arduino you can log the measurement continuously, show it on a display and raise an alert when a threshold is crossed.

In this post we cover step by step what ppm means, how the sensor actually measures conductivity, how temperature affects the result and how to correct it with a DS18B20, calibration with a reference solution, the Arduino Uno code, value tables for drinking water, aquariums and hydroponics, water filter monitoring, timestamped logging with the ESP32 and Raspberry Pi Pico code. In the last section you'll see how a TDS sensor differs from a pH sensor and the most common mistakes.

TDS water quality and conductivity sensor
TDS sensor: a waterproof two-electrode probe and the board that processes the signal; the board has VCC, GND and analog output (A) pins.

What is TDS and what does ppm mean?

TDS is the total amount of all substances dissolved in a litre of water: ions such as calcium, magnesium, sodium, potassium, bicarbonate, chloride, sulphate and nitrate make up most of it. The unit is ppm (parts per million) or its water equivalent mg/L; 1 ppm means 1 milligram of dissolved matter in 1 litre of water. For example, every litre of 250 ppm tap water contains a quarter of a gram of minerals. Pure (distilled) water has a TDS very close to zero, while seawater is around 35,000 ppm.

It's important to know from the start that TDS alone doesn't tell you whether water is "clean or dirty". A mineral-rich spring water can have a high TDS and be perfectly healthy; on the other hand, low-TDS water may contain bacteria, lead or pesticides, because these barely change the water's conductivity. A TDS sensor is perfect for tracking the mineral load of water and changes in that load; for microbiological safety you need a lab analysis.

How does a TDS sensor work? From conductivity to ppm

TDS sensors sold for Arduino are really conductivity (EC) meters. Pure water hardly conducts electricity at all; the more dissolved ions it contains, the higher its conductivity. The board applies a small voltage between the two electrodes at the tip of the probe and measures the current that flows. This voltage is alternating rather than direct current: with DC, gas bubbles would build up on the electrodes (polarisation), the reading would drift and the electrodes would wear quickly. The board turns the result into an analog voltage between 0 and 2.3 V; the Arduino reads it, converts it first to conductivity (µS/cm) and then to TDS with a conversion factor.

Going from conductivity to TDS is an approximation: TDS (ppm) = EC (µS/cm) × k. Most meters, and the code in this post, use k = 0.5 (the sodium chloride or "500" scale). Some hydroponic meters use 0.7, so two meters can show the same water as 500 and 700 ppm and both are "right". Check which factor is used when comparing values, and in hydroponics work directly with EC (mS/cm) where you can.

FeatureValue (common TDS module)
Supply3.3–5.5 V
Output0–2.3 V analog
Measuring range0–1000 ppm
AccuracyAbout ±10% (at 25 °C, of full scale)
ExcitationAlternating current (prevents polarisation)
ProbeWaterproof, two electrodes; up to about 55 °C
BoardNot waterproof, keep it dry

Temperature compensation: why you need a DS18B20

Water conductivity changes noticeably with temperature: ions move faster as they warm up, and the same water appears about 2% more conductive for every 1 °C. Readings of the same water at 15 °C and 30 °C differ by roughly a third; that's a far bigger error than the measurement itself. That's why TDS readings are corrected to 25 °C: corrected voltage = measured voltage / (1 + 0.02 × (T − 25)). The best sensor for water temperature is the waterproof, stainless-steel-sheathed DS18B20; you put it in the same water next to the TDS probe.

DS18B20 temperature sensor
DS18B20: a single-wire digital temperature sensor; its waterproof version goes into the water next to the TDS probe for temperature compensation.

The DS18B20 uses a single-data-wire protocol called OneWire and gives ±0.5 °C accuracy. It needs a 4.7 kΩ pull-up resistor between the data line and VCC; if you don't know the colour code, check the resistor colour code tool. For sensor details and connecting several DS18B20s on the same line, read the DS18B20 temperature sensor post. Without a temperature sensor the code assumes 25 °C, which is fine for simple tests at room temperature.

Wiring: Arduino Uno, ESP32 and Pico

Part pinArduino UnoESP32Raspberry Pi Pico
TDS VCC (+)5V3V33V3 (OUT)
TDS GND (−)GNDGNDGND
TDS A (signal)A0GPIO 34 (ADC1)GP26 (ADC0)
DS18B20 VCC (red)5V3V33V3 (OUT)
DS18B20 GND (black)GNDGNDGND
DS18B20 DATA (yellow)D2 + 4.7 kΩ to VCCGPIO 4 + 4.7 kΩ to 3V3GP22 + 4.7 kΩ to 3V3
The TDS module's signal board is not waterproof; only the probe goes in the water. Don't let the probe touch the bottom or sides of the container, keep it at least a few centimetres away; readings drift in metal containers. If you run the TDS probe and a pH probe in the same container at the same time, the two sensors can disturb each other's readings; either don't measure simultaneously or use a module that electrically isolates one of them.

Arduino TDS code: median filter and compensation

  1. Install the OneWire and DallasTemperature libraries from the Library Manager.
  2. Wire the TDS module and the DS18B20 as in the table; put the probe and the temperature sensor in the same water.
  3. Upload the code and open the Serial Monitor at 115200 baud.
  4. Wait 20–30 seconds for the numbers to settle; the first readings fluctuate when the probe has just gone into the water.
  5. If you have a known calibration solution, put the probe in it and type, for example, cal:707 in the Serial Monitor.
C++ (Arduino IDE)
1#include <OneWire.h>
2#include <DallasTemperature.h>
3#include <EEPROM.h>
4
5const int TDS_PIN = A0;          // TDS modülü sinyal (A) / TDS module signal (A)
6const int DS_PIN = 2;            // DS18B20 veri, 4,7 kΩ pull-up / DS18B20 data, 4.7 kΩ pull-up
7const float VREF = 5.0;          // Uno ADC referansı / Uno ADC reference
8const int ORNEK = 30;            // medyan filtresi örnek sayısı / samples for the median filter
9
10OneWire oneWire(DS_PIN);
11DallasTemperature ds(&oneWire);
12
13int ornekler[ORNEK];
14int indeks = 0;
15float kFaktor = 1.0;             // kalibrasyon katsayısı (EEPROM'da) / calibration factor (in EEPROM)
16float sicaklik = 25.0;
17float gerilim = 0;
18unsigned long sonOrnek = 0, sonOlcum = 0;
19
20int medyan() {                   // gürültüye karşı ortanca değer / median against noise
21  int t[ORNEK];
22  memcpy(t, ornekler, sizeof(t));
23  for (int i = 1; i < ORNEK; i++) {          // ekleme sıralaması / insertion sort
24    int x = t[i], j = i - 1;
25    while (j >= 0 && t[j] > x) { t[j + 1] = t[j]; j--; }
26    t[j + 1] = x;
27  }
28  return (t[ORNEK / 2] + t[ORNEK / 2 - 1]) / 2;
29}
30
31float tdsHesapla(float volt, float derece, float k) {
32  float komp = 1.0 + 0.02 * (derece - 25.0); // %2/°C sıcaklık kompanzasyonu / 2 %/°C compensation
33  float v = volt / komp;                     // 25 °C'ye indirgenmiş gerilim / voltage at 25 °C
34  float ec = 133.42 * v * v * v - 255.86 * v * v + 857.39 * v;   // iletkenlik, µS/cm / conductivity
35  return ec * 0.5 * k;                       // TDS (ppm) = EC x 0,5 / TDS (ppm) = EC x 0.5
36}
37
38void setup() {
39  Serial.begin(115200);
40  ds.begin();
41  ds.setWaitForConversion(false);            // 750 ms beklemeden ölç / measure without blocking 750 ms
42  ds.requestTemperatures();
43  EEPROM.get(0, kFaktor);
44  if (isnan(kFaktor) || kFaktor < 0.5 || kFaktor > 2.0) kFaktor = 1.0;   // boş EEPROM / empty EEPROM
45  Serial.println("Kalibrasyon / calibration: cal:707 gibi yaz / type e.g. cal:707");
46}
47
48void loop() {
49  if (millis() - sonOrnek >= 40) {           // 40 ms'de bir örnek / one sample every 40 ms
50    sonOrnek = millis();
51    ornekler[indeks] = analogRead(TDS_PIN);
52    indeks = (indeks + 1) % ORNEK;
53  }
54
55  if (millis() - sonOlcum >= 1000) {         // saniyede bir sonuç / one result per second
56    sonOlcum = millis();
57    float t = ds.getTempCByIndex(0);
58    if (t != DEVICE_DISCONNECTED_C) sicaklik = t;   // sensör yoksa 25 °C / 25 °C if no sensor
59    ds.requestTemperatures();                // bir sonraki okuma için / for the next reading
60    gerilim = medyan() * VREF / 1024.0;
61    float tds = tdsHesapla(gerilim, sicaklik, kFaktor);
62    Serial.print("Sicaklik / temp: ");
63    Serial.print(sicaklik, 1);
64    Serial.print(" C  TDS: ");
65    Serial.print(tds, 0);
66    Serial.println(" ppm");
67  }
68
69  if (Serial.available()) {                  // "cal:707" -> bilinen sıvıya göre K / K from a known solution
70    String s = Serial.readStringUntil('\n');
71    s.trim();
72    if (s.startsWith("cal:")) {
73      float hedef = s.substring(4).toFloat();
74      float ham = tdsHesapla(gerilim, sicaklik, 1.0);
75      if (hedef > 0 && ham > 10) {
76        kFaktor = hedef / ham;
77        EEPROM.put(0, kFaktor);              // kalıcı kaydet / save permanently
78        Serial.print("Yeni K / new K: ");
79        Serial.println(kFaktor, 3);
80      }
81    }
82  }
83}
84
Code partWhat does it do?
analogRead every 40 msKeeps the last 30 readings (1.2 seconds) in a ring buffer
medyan()Unlike an average, completely ignores sudden spikes (noise, bubbles)
1 + 0.02 × (T − 25)Normalises the voltage to 25 °C; at 30 °C the divisor is 1.10
133.42 v³ − 255.86 v² + 857.39 vEmpirical voltage-to-conductivity curve for this sensor board
× 0.5Factor that converts conductivity to TDS (500 scale)
setWaitForConversion(false)Keeps sampling without waiting for the DS18B20's 750 ms conversion
cal:707 and EEPROMCalculates the K factor from a known solution and stores it permanently

The third-order polynomial in the code is an empirical curve that turns the board's output voltage into conductivity; a simple multiplier isn't enough because the circuit on the board isn't linear. This curve applies to the common Gravity-style TDS board; if you use a different board, use the manufacturer's formula or derive your own curve with a few known solutions. Remember that on a 5 V Uno the analog reading is relative to 5.0 V, and on the ESP32 and Pico to 3.3 V; if you don't set VREF for your board, the results are wrong from the start.

Calibrating the TDS sensor with a reference solution

Every probe and board differs slightly; for the most accurate results, calibrate the sensor with a liquid of known value. The 1413 µS/cm potassium chloride (KCl) standard solution, available from lab and electronics suppliers, is the most common choice; with the 0.5 factor it corresponds to about 707 ppm. The 342 ppm sodium chloride solution that comes with some pen TDS meters works too. To calibrate, rinse the probe with clean water, pat it dry with a paper towel, put it in the solution, wait 1–2 minutes and type cal: followed by the solution's ppm value in the Serial Monitor. The code saves the ratio between the measured and true value as the K factor in EEPROM, so the setting survives power-off.

If you don't have a calibration solution, a temporary method is to measure the same water with a good pen TDS meter and compare the two values. You can also make your own solution: 0.5 grams of pure salt (NaCl) in 1 litre of distilled water gives roughly 500 ppm; the accuracy of your scale directly affects the result. Repeat calibration every few months and never pour used solution back into the bottle.

TDS chart: drinking water, aquarium and hydroponics

Knowing what your number means is as important as the sensor itself. According to the World Health Organization's taste assessment, water below 300 ppm is excellent in taste, 300–600 ppm good, 600–900 ppm fair, 900–1200 ppm poor and above 1200 ppm unacceptable. These are ranges for taste and usability, not health limits. The table below summarises typical values for common uses.

Type of waterTypical TDS (ppm)Comment
Distilled water, reverse osmosis (RO) output0–50Filter is working well
Mountain spring, low-mineral bottled water20–150Very light, soft
Tap water (depends on the city)100–500Varies by source; a sudden rise needs attention
Mineral bottled water300–1500+Deliberately high in minerals
Freshwater aquarium (general)150–350Measure before and after water changes
Shrimp aquarium (Caridina)80–150Set by adding minerals to RO water
African cichlid aquarium300–500Likes hard, mineral-rich water
SeawaterAbout 35,000Far outside this sensor's range

In hydroponics, nutrient solutions are usually expressed as conductivity (EC) and vary by plant. Watch out, though: this sensor's range ends at 1000 ppm, and the solution for hungry plants like tomatoes and peppers exceeds that. In that case, either dilute a sample with distilled water at a known ratio, measure it and multiply the result, or use an EC sensor with a wider range.

PlantRecommended EC (mS/cm)Approx. TDS (0.5 scale)
Lettuce, spinach0.8–1.2400–600 ppm
Basil, mint1.0–1.6500–800 ppm
Strawberry1.0–1.5500–750 ppm
Cucumber1.7–2.5850–1250 ppm (dilution needed)
Tomato, pepper2.0–3.51000–1750 ppm (dilution needed)

Monitoring a water filter

The most useful job for a TDS sensor at home is monitoring a reverse osmosis (RO) filter. A healthy RO membrane holds back most of the minerals in the incoming water; with 300 ppm going in, the output is usually around 10–30 ppm. You calculate performance with rejection rate = (1 − output / input) × 100: if 300 ppm goes in and 15 ppm comes out, the rate is 95%. As the membrane ages, output TDS slowly rises; when the rate starts dropping below 80–85%, it's nearly time to replace the membrane and pre-filters. An Arduino with two probes and two DS18B20s measuring inlet and outlet at the same time can chart this change over months.

Carbon and sediment filters remove odour, taste, chlorine and sediment but hardly reduce dissolved minerals; it's normal for TDS after these filters to stay the same as before. Only RO and ion-exchange (softener) systems can be meaningfully monitored with TDS. Also, low TDS at a filter's output doesn't mean the water is microbiologically safe.

Logging TDS with the ESP32

With the ESP32 you can log TDS readings once a minute with a timestamp and send them to the internet later. The code below gets the time from the internet with NTP, measures water temperature and TDS every minute, and appends "date,temperature,tds" lines to a file called "/tds.csv" on the LittleFS file system in the board's own flash memory. You can later open this file in Excel and draw a chart. The ESP32's ADC isn't linear, so the code uses analogReadMilliVolts(), which uses the calibration data stored on the chip. Connect the TDS signal to one of the ADC1 pins (GPIO 32–39), which work while Wi-Fi is on; ADC2 pins can't be used together with Wi-Fi. NTP time is covered in the ESP32 NTP clock post.

C++ (Arduino IDE)
1#include <WiFi.h>
2#include <LittleFS.h>
3#include <OneWire.h>
4#include <DallasTemperature.h>
5#include <time.h>
6
7const char* WIFI_SSID = "AgAdi";
8const char* WIFI_PASS = "Sifre123";
9const int TDS_PIN = 34;                      // ADC1 kanalı, Wi-Fi ile çalışır / ADC1 channel, works with Wi-Fi
10const int DS_PIN = 4;
11const float K_FAKTOR = 1.0;                  // Arduino'daki gibi kalibre et / calibrate as on the Arduino
12const unsigned long ARALIK_MS = 60000;       // dakikada bir kayıt / one log per minute
13
14OneWire oneWire(DS_PIN);
15DallasTemperature ds(&oneWire);
16unsigned long sonKayit = 0;
17
18float gerilimOku() {                         // 30 örneğin ortancası, volt / median of 30 samples, volts
19  int mv[30];
20  for (int i = 0; i < 30; i++) { mv[i] = analogReadMilliVolts(TDS_PIN); delay(5); }
21  for (int i = 1; i < 30; i++) {
22    int x = mv[i], j = i - 1;
23    while (j >= 0 && mv[j] > x) { mv[j + 1] = mv[j]; j--; }
24    mv[j + 1] = x;
25  }
26  return mv[15] / 1000.0;
27}
28
29float tdsHesapla(float v, float derece) {
30  v = v / (1.0 + 0.02 * (derece - 25.0));    // sıcaklık kompanzasyonu / temperature compensation
31  return (133.42 * v * v * v - 255.86 * v * v + 857.39 * v) * 0.5 * K_FAKTOR;
32}
33
34void setup() {
35  Serial.begin(115200);
36  ds.begin();
37  LittleFS.begin(true);                      // ilk açılışta biçimlendir / format on first boot
38  WiFi.begin(WIFI_SSID, WIFI_PASS);
39  while (WiFi.status() != WL_CONNECTED) delay(500);
40  configTzTime("<+03>-3", "pool.ntp.org");   // zaman damgası için NTP / NTP for timestamps
41}
42
43void loop() {
44  if (millis() - sonKayit < ARALIK_MS && sonKayit != 0) return;
45  sonKayit = millis();
46
47  ds.requestTemperatures();                  // ~750 ms bekler / waits ~750 ms
48  float derece = ds.getTempCByIndex(0);
49  if (derece == DEVICE_DISCONNECTED_C) derece = 25.0;
50  float tds = tdsHesapla(gerilimOku(), derece);
51
52  struct tm t;
53  char zaman[20] = "saat-yok";
54  if (getLocalTime(&t, 2000)) strftime(zaman, sizeof(zaman), "%Y-%m-%d %H:%M:%S", &t);
55
56  char satir[64];
57  snprintf(satir, sizeof(satir), "%s,%.1f,%.0f", zaman, derece, tds);
58  File f = LittleFS.open("/tds.csv", FILE_APPEND);   // tarih,sicaklik,tds / date,temp,tds
59  if (f) { f.println(satir); f.close(); }
60  Serial.println(satir);
61}
62

If you want the log online, you can send the same line to a Google Sheets spreadsheet or to Home Assistant over MQTT instead of LittleFS; details in the ESP32 Google Sheets and ESP32 MQTT posts. Flash memory has a limited write life; a short line per minute is no problem, but rather than writing every second it's a good habit to collect readings in RAM and write them in batches.

TDS with the Raspberry Pi Pico (MicroPython)

On the Pico you connect the TDS signal to GP26 (ADC0) and the DS18B20 to GP22. In MicroPython the onewire and ds18x20 modules needed for the DS18B20 are built into the firmware, so nothing extra has to be installed. The Pico's ADC returns a value between 0 and 65535 with read_u16(); we convert it to a voltage relative to 3.3 V. The formula and compensation are the same as in the Arduino code; you can find K_FAKTOR with the Arduino calibration method and write it into the code.

MicroPython
1from machine import ADC, Pin
2import onewire, ds18x20, time
3
4adc = ADC(26)                     # GP26 = ADC0, TDS sinyali / TDS signal
5ds = ds18x20.DS18X20(onewire.OneWire(Pin(22)))   # DS18B20 veri pini / data pin
6roms = ds.scan()
7K_FAKTOR = 1.0                    # kalibrasyon katsayısı / calibration factor
8
9def gerilim_oku(n=31):            # ortanca ile gürültü filtresi / median noise filter
10    olcumler = []
11    for _ in range(n):
12        olcumler.append(adc.read_u16())
13        time.sleep_ms(5)
14    olcumler.sort()
15    return olcumler[n // 2] * 3.3 / 65535
16
17def tds_hesapla(v, derece):
18    v = v / (1.0 + 0.02 * (derece - 25.0))       # 25 °C'ye indir / normalise to 25 °C
19    ec = 133.42 * v ** 3 - 255.86 * v ** 2 + 857.39 * v
20    return ec * 0.5 * K_FAKTOR
21
22while True:
23    derece = 25.0
24    if roms:
25        ds.convert_temp()
26        time.sleep_ms(750)                       # DS18B20 dönüşüm süresi / conversion time
27        derece = ds.read_temp(roms[0])
28    tds = tds_hesapla(gerilim_oku(), derece)
29    print("Sicaklik: {:.1f} C  TDS: {:.0f} ppm".format(derece, tds))
30    time.sleep(1)
31

TDS sensor vs pH sensor

TDS and pH sensors are often confused in water quality projects, yet they measure completely different things. TDS shows the amount of ions in the water, while pH shows how acidic or alkaline it is (hydrogen ion activity). Add a few drops of lemon juice to a glass of water and the pH drops sharply while TDS barely changes; add a pinch of salt and TDS shoots up while pH stays almost the same. In aquariums and hydroponics, both are usually monitored together.

FeatureTDS sensorpH sensor
What it measuresAmount of dissolved ions (conductivity)Acidity / alkalinity (0–14)
Unitppm (mg/L) or µS/cmpH units
ProbeRobust pair of metal electrodesFragile glass electrode
CalibrationSingle point (e.g. 1413 µS/cm)Two or three points (pH 4, 7, 10 buffers)
MaintenanceOccasional cleaningStored wet, regular calibration, probe replaced every 1–2 years
PriceCheapMore expensive
Typical useFilter monitoring, hardness, nutrient strengthAquarium, pool, hydroponic pH control

TDS sensor project ideas

  • Filter alarm: sound a buzzer and show "replace filter" on a display when the RO output exceeds 50 ppm.
  • Aquarium monitor: show TDS, temperature and water level on one display and remind you when to change the water.
  • Hydroponic nutrient control: add nutrients with a peristaltic pump when EC drops; combine it with the smart greenhouse project.
  • Tap water log: record your home's water TDS for days and see changes in the supply on a chart.
  • Plant watering water: compare rainwater, tap water and filtered water and choose the best for salt-sensitive plants.
  • School experiment: dissolve different amounts of salt and sugar to show the link between conductivity and the type of dissolved substance.

Common mistakes and fixes

SymptomLikely causeFix
Value keeps fluctuatingProbe just went in or there are bubblesWait 20–30 seconds, shake the probe gently, use a median filter
Different results in warm and cold waterNo temperature compensationAdd a DS18B20 and feed the temperature into the formula
All values off by roughly 50%Wrong VREF (3.3 V instead of 5 V or vice versa)Set your board's ADC reference correctly
Different from a pen meterDifferent conversion factor (0.5 / 0.7) or no calibrationUse the same scale and calibrate with a known solution
Readings max out at high valuesThe sensor's range is 1000 ppmDilute the sample or use a wide-range EC sensor
Nonsense results alongside a pH sensorThe two probes disturb each other in the same waterMeasure one at a time or use an isolated module
ESP32 readings go wrong when Wi-Fi startsSignal connected to an ADC2 pinUse one of the ADC1 pins, GPIO 32–39
Rinse the probe with clean water after every measurement and store it dry. If it stays in water permanently (aquarium, hydroponics), clean off the biofilm with a soft brush every few weeks; dirty electrodes read lower over time.

A TDS sensor is the cheapest and easiest tool for turning water quality into a number: with proper temperature compensation and a simple calibration you can reliably monitor tap water, a filter, an aquarium or your hydroponic solution. When interpreting results, keep in mind that TDS doesn't measure microbiological safety. In the BlueGrays app you'll find step-by-step projects with circuit diagrams and code for a smart watering station and a timestamped temperature logger, and you can add a TDS sensor to them.

Frequently asked questions

What should the TDS level be?

For drinking water, the World Health Organization's taste assessment rates below 300 ppm as excellent and 300–600 ppm as good, while above 1200 ppm is considered unacceptable in taste. Reverse osmosis filter output is usually 10–50 ppm. For aquariums and hydroponics, the ideal value depends on the animals or plants.

What does a TDS meter measure, and does it show water is safe?

A TDS meter estimates the amount of dissolved minerals and salts from the water's conductivity. Contaminants such as bacteria, viruses, lead or pesticides hardly change conductivity, so low TDS doesn't make water safe. TDS should be used to monitor filter performance and changes in mineral load.

How do you calibrate a TDS sensor?

Clean the probe and put it in a calibration solution of known value, such as the 1413 µS/cm KCl standard (about 707 ppm). Once the reading settles, the ratio between the measured and true value is saved as a factor, and all later readings are multiplied by it. Temperature compensation should be active during calibration.

What is the difference between TDS and EC?

EC (electrical conductivity) directly measures how well water conducts electricity, in µS/cm or mS/cm. TDS is an estimated amount of dissolved matter (ppm) calculated from that conductivity with a factor, usually 0.5 or 0.7. EC is more common in hydroponics, TDS for drinking water.

Can a TDS sensor stay in the water permanently?

The probe is waterproof and can stay permanently in an aquarium or hydroponic tank, but it should be cleaned every few weeks; the signal board isn't waterproof and must stay dry. The probe shouldn't be used in water above about 55 °C. With long-term use, repeat calibration now and then to correct drift.

Can an Arduino TDS sensor measure pH?

No. A TDS sensor only measures conductivity and the dissolved solids derived from it; pH, or acidity, needs a separate pH sensor with a glass electrode. The two can be used in the same project, but because they can disturb each other's readings in the same container, measure one at a time or use an isolated module.

See all projects
Smart Irrigation Station
#83Advanced
Premium

Smart Irrigation Station

A gardener that waters your plants on its own, so they don't dry out while you're on vacation. A soil moisture sensor measures how wet the soil is; when it gets dry, the Arduino runs the water pump fo

5.0(42)
57
ESP32 Temperature Data Logger (DHT22 + DS1307 RTC + microSD + OLED)
#144Advanced
Premium

ESP32 Temperature Data Logger (DHT22 + DS1307 RTC + microSD + OLED)

Build a timestamped temperature logger with ESP32! Read DHT22 temperature/humidity every minute, get real-world time from DS1307 RTC, and log to microSD card as CSV. The OLED displays live temperature (large font), humidity percentage, timestamp, and log counter. The /temp_log.csv file on the SD card opens in Excel, Google Sheets, or Python pandas for analysis — perfect for greenhouse monitoring, home/room temperature tracking, laboratory data collection, food storage conditions, or beehiv

4.7(7)
12
ESP32 DHT22 Temperature and Humidity (with LCD Display)
#117Intermediate

ESP32 DHT22 Temperature and Humidity (with LCD Display)

This project measures ambient temperature and humidity using a DHT22 sensor and displays the data in real time on a 16x2 I2C LCD. Data is read from the sensor using the one-wire protocol via the Adafruit DHT library. This project serves as the foundation for IoT weather stations, smart home automation, or environmental monitoring systems in greenhouses. Communication with the DHT22 is established via the ESP32's GPIO 4 pin.

4.8(38)
56
Temperature and Humidity with DHT11
#55Intermediate

Temperature and Humidity with DHT11

How warm is your room, and is the air humid or dry? The DHT11 sensor measures temperature and humidity, and the Arduino writes the values on a two-line LCD screen, refreshing every couple of seconds.

4.7(47)
73
Temperature Measurement with NTC and 2x16 Lcd Display
#44Beginner
Premium

Temperature Measurement with NTC and 2x16 Lcd Display

Measure the temperature around you with a sensor that looks like a tiny bead. This part, called an NTC, lets electricity through more easily as it warms up; the Arduino reads that change, turns it int

4.5(33)
44
Digital Voltmeter with LCD Display
#56Intermediate
Premium

Digital Voltmeter with LCD Display

Find out how much voltage a battery or power adapter gives with a meter you built yourself. A divider made of two resistors brings high voltage down to a level the board can read, and the Arduino calc

4.5(27)
36
Measuring Light Intensity with an LDR
#11Beginner

Measuring Light Intensity with an LDR

Want to see how bright your room is as a number? The LDR, a small part that reacts to light, measures the light around it, and the Arduino writes the value to your computer screen every half second. C

4.6(81)
139