The YF-S201 is a small turbine in a ½-inch pipe section: water spins a magnet past a Hall sensor, which gives one pulse per turn. Count the pulses and you get flow in litres per minute and the total volume — useful for tank-filling monitors, borewell pump logs and water-bill checks.
On the ESP32 DevKit V1 it needs 5 V from VIN to run, and a 10 kΩ / 20 kΩ divider on the pulse line so the GPIO only ever sees about 3.3 V. The sketch counts pulses in an interrupt and prints flow and total every second.
Wiring
| ESP32 DevKit V1 | YF-S201 water flow sensor (½″) | Wire | Notes |
|---|---|---|---|
| VIN | VCC | red | Red wire. The sensor’s Hall chip needs 5 V; VIN is 5 V on USB. |
| GND | GND | black | Black wire. |
| D27 | SIG | yellow | Via 10 kΩ / 20 kΩ divider — Yellow wire. 10 kΩ from SIG to D27, 20 kΩ from D27 to GND, so a 5 V pulse arrives as about 3.3 V. |
5–18 V (use 5 V) part, 3.3 V board. Powered from 5 V, the pulse output can swing close to 5 V. On ESP32 and Pico feed SIG through a 10 kΩ / 20 kΩ divider (or a 1 kΩ / 2 kΩ one). On Uno connect it directly.
Board quirks
- Why the divider: powered from 5 V, the pulse output can swing close to 5 V, which an ESP32 pin must not see. We assume the common case of an output that pulls up towards VCC inside the sensor; the divider makes it safe either way. If pulses go missing, measure SIG’s HIGH level at D27 with a meter — it should be 2.5–3.3 V.
- Counting happens in an
IRAM_ATTRinterrupt on the falling edge, so no pulse is lost while the ESP32 is busy with Wi-Fi. At full flow (30 L/min) that is only about 225 pulses a second. - The 7.5 and 450 figures are typical, not exact. Fill a 10-litre bucket, read the pulse total, and set
PULSES_PER_LITRE= pulses ÷ 10 for your sensor and pipe. - Below about 1 L/min the rotor stalls and reads zero — a slowly dripping tap won’t register. Mount the sensor with the arrow along the flow and the pipe full of water, not upside down on a vertical pipe.
- For overhead-tank monitoring the ESP32 can keep the total across resets in
Preferences(flash), and power cuts won’t wipe it.
Code
// YF-S201 water flow sensor on an ESP32 DevKit V1.
// VCC (red) → VIN (5 V), GND (black) → GND,
// SIG (yellow) → 10 kΩ → D27 (GPIO27), with 20 kΩ from D27 to GND (5 V pulses → about 3.3 V).
// About 7.5 pulses per second per L/min (≈ 450 pulses per litre) — calibrate for your sensor.
constexpr uint8_t FLOW_PIN = 27;
constexpr float PULSES_PER_LITRE = 450.0f;
volatile uint32_t pulses = 0;
void IRAM_ATTR onPulse() { pulses++; }
void setup() {
Serial.begin(115200);
pinMode(FLOW_PIN, INPUT); // the divider sets the level; no internal pull
attachInterrupt(digitalPinToInterrupt(FLOW_PIN), onPulse, FALLING);
Serial.println("YF-S201 on GPIO27 — open the tap");
}
void loop() {
static uint32_t lastTotal = 0;
delay(1000);
noInterrupts();
uint32_t total = pulses;
interrupts();
uint32_t perSecond = total - lastTotal;
lastTotal = total;
float litresPerMin = perSecond / 7.5f;
float litres = total / PULSES_PER_LITRE;
Serial.printf("Flow %.2f L/min | Total %.2f L (%lu pulses)\n", litresPerMin, litres, (unsigned long)total);
}// YF-S201 water flow sensor on an ESP32 DevKit V1.
// VCC (red) → VIN (5 V), GND (black) → GND,
// SIG (yellow) → 10 kΩ → D27 (GPIO27), with 20 kΩ from D27 to GND (5 V pulses → about 3.3 V).
// About 7.5 pulses per second per L/min (≈ 450 pulses per litre) — calibrate for your sensor.
constexpr uint8_t FLOW_PIN = 27;
constexpr float PULSES_PER_LITRE = 450.0f;
volatile uint32_t pulses = 0;
void IRAM_ATTR onPulse() { pulses++; }
void setup() {
Serial.begin(115200);
pinMode(FLOW_PIN, INPUT); // the divider sets the level; no internal pull
attachInterrupt(digitalPinToInterrupt(FLOW_PIN), onPulse, FALLING);
Serial.println("YF-S201 on GPIO27 — open the tap");
}
void loop() {
static uint32_t lastTotal = 0;
delay(1000);
noInterrupts();
uint32_t total = pulses;
interrupts();
uint32_t perSecond = total - lastTotal;
lastTotal = total;
float litresPerMin = perSecond / 7.5f;
float litres = total / PULSES_PER_LITRE;
Serial.printf("Flow %.2f L/min | Total %.2f L (%lu pulses)\n", litresPerMin, litres, (unsigned long)total);
}Expected serial output
YF-S201 on GPIO27 — open the tap
Flow 0.00 L/min | Total 0.00 L (0 pulses)
Flow 6.27 L/min | Total 0.10 L (47 pulses)
Flow 8.40 L/min | Total 0.24 L (110 pulses)
Flow 8.53 L/min | Total 0.39 L (174 pulses)YF-S201 on GPIO27 — open the tap Flow 0.00 L/min | Total 0.00 L (0 pulses) Flow 6.27 L/min | Total 0.10 L (47 pulses) Flow 8.40 L/min | Total 0.24 L (110 pulses) Flow 8.53 L/min | Total 0.39 L (174 pulses)
Common errors
Flow always 0
No 5 V on the red wire (VIN only has 5 V on USB or a 5 V supply), the arrow pointing against the flow, or flow below about 1 L/min.
Readings jump even with the tap closed
Noise on a long sensor cable. Keep the divider at the ESP32 end, twist the yellow wire with black, and add a 10 nF capacitor from D27 to GND.
Total litres is 10–20 % off
Normal for this sensor out of the box. Calibrate PULSES_PER_LITRE with a bucket of known volume.