The rain sensor is a printed plate with interleaved tracks, plus a small LM393 comparator board. Water bridging the tracks lowers the analog output and flips the digital one.
The ESP32 DevKit V1 lets you fix this module’s big weakness: instead of powering it all the time, GPIO25 supplies its VCC only while reading, which slows the plate’s corrosion dramatically. AO goes to D35 (ADC1, Wi-Fi safe) and DO to D26, and the sketch reports dry, drizzle or rain every ten seconds.
Wiring
| ESP32 DevKit V1 | Rain sensor (FC-37 / YL-83) | Wire | Notes |
|---|---|---|---|
| D25 | VCC | red | GPIO25 set HIGH supplies 3.3 V for 100 ms per reading. The module draws only a few mA (comparator plus LEDs). |
| GND | GND | black | |
| D35 | AO | yellow | ADC1, input-only — fine for an analog input and unaffected by Wi-Fi. |
| D26 | DO | green | LOW when the plate is wetter than the pot threshold (DO LED lights). |
3.3–5 V part, 3.3 V board. AO and DO swing up to VCC. Power the module from 3.3 V on ESP32/Pico so AO stays within the ADC range.
Board quirks
- A rain plate with current flowing all the time corrodes in one monsoon. Feeding VCC from a GPIO and switching it on only for a reading every 10 s cuts that by about 99 %.
- GPIO25 is a good power switch: not a strapping pin, quiet at boot. Its ADC2 function doesn’t matter because it is used as a digital output.
- Because the module runs from 3.3 V, AO and DO can never exceed the ESP32’s limit — no divider needed.
- AO goes on D35 (ADC1). Most rain alarms send a phone alert, and ADC2 pins stop reading once Wi-Fi starts.
- Read DO only while the module is powered — with VCC off it reads LOW and would look like “wet”.
- Mount the plate tilted (about 30°) so water runs off and the reading falls again after the rain. Keep the LM393 board indoors or in a sealed box; only the plate goes outside.
Code
// Rain sensor (FC-37 / YL-83 plate + LM393 board) on an ESP32 DevKit V1.
// VCC → D25 (GPIO25 powers the module only while reading), GND → GND,
// AO → D35 (GPIO35, ADC1), DO → D26 (GPIO26). Powering the plate briefly slows its corrosion.
constexpr uint8_t PWR_PIN = 25; // supplies the module (a few mA) — GPIO used as a switch
constexpr uint8_t AO_PIN = 35; // ADC1_CH7, input-only: fine for analog, works with Wi-Fi on
constexpr uint8_t DO_PIN = 26; // comparator output, LOW when wet on most boards
constexpr uint32_t PERIOD_MS = 10000;
void setup() {
Serial.begin(115200);
pinMode(PWR_PIN, OUTPUT);
digitalWrite(PWR_PIN, LOW);
pinMode(DO_PIN, INPUT);
Serial.println("Rain sensor: powered from GPIO25 for 100 ms every 10 s");
}
void loop() {
digitalWrite(PWR_PIN, HIGH);
delay(100); // let the comparator and plate settle
uint32_t sum = 0;
for (int i = 0; i < 10; i++) sum += analogReadMilliVolts(AO_PIN);
int mv = sum / 10;
bool wetDO = digitalRead(DO_PIN) == LOW;
digitalWrite(PWR_PIN, LOW);
int wet = constrain(map(mv, 3200, 800, 0, 100), 0, 100); // AO falls as water bridges the tracks
const char *state = wet < 10 ? "dry" : wet < 50 ? "drizzle" : "rain";
Serial.printf("AO %4d mV Wetness %3d %% DO %s → %s\n", mv, wet, wetDO ? "WET" : "dry", state);
delay(PERIOD_MS);
}// Rain sensor (FC-37 / YL-83 plate + LM393 board) on an ESP32 DevKit V1.
// VCC → D25 (GPIO25 powers the module only while reading), GND → GND,
// AO → D35 (GPIO35, ADC1), DO → D26 (GPIO26). Powering the plate briefly slows its corrosion.
constexpr uint8_t PWR_PIN = 25; // supplies the module (a few mA) — GPIO used as a switch
constexpr uint8_t AO_PIN = 35; // ADC1_CH7, input-only: fine for analog, works with Wi-Fi on
constexpr uint8_t DO_PIN = 26; // comparator output, LOW when wet on most boards
constexpr uint32_t PERIOD_MS = 10000;
void setup() {
Serial.begin(115200);
pinMode(PWR_PIN, OUTPUT);
digitalWrite(PWR_PIN, LOW);
pinMode(DO_PIN, INPUT);
Serial.println("Rain sensor: powered from GPIO25 for 100 ms every 10 s");
}
void loop() {
digitalWrite(PWR_PIN, HIGH);
delay(100); // let the comparator and plate settle
uint32_t sum = 0;
for (int i = 0; i < 10; i++) sum += analogReadMilliVolts(AO_PIN);
int mv = sum / 10;
bool wetDO = digitalRead(DO_PIN) == LOW;
digitalWrite(PWR_PIN, LOW);
int wet = constrain(map(mv, 3200, 800, 0, 100), 0, 100); // AO falls as water bridges the tracks
const char *state = wet < 10 ? "dry" : wet < 50 ? "drizzle" : "rain";
Serial.printf("AO %4d mV Wetness %3d %% DO %s → %s\n", mv, wet, wetDO ? "WET" : "dry", state);
delay(PERIOD_MS);
}Expected serial output
Rain sensor: powered from GPIO25 for 100 ms every 10 s
AO 3180 mV Wetness 0 % DO dry → dry
AO 2410 mV Wetness 32 % DO dry → drizzle
AO 1150 mV Wetness 85 % DO WET → rainRain sensor: powered from GPIO25 for 100 ms every 10 s AO 3180 mV Wetness 0 % DO dry → dry AO 2410 mV Wetness 32 % DO dry → drizzle AO 1150 mV Wetness 85 % DO WET → rain
Common errors
AO always reads 0 mV
The module isn’t powered: the sketch only powers it for 100 ms. If you wired VCC to 3V3 instead of D25, that also works (with more corrosion) — check AO is on D35.
Still shows “rain” long after the rain stopped
Water sitting on a flat plate, or dirt bridging the tracks. Tilt the plate and clean it with a soft brush and isopropyl alcohol.
Readings creep down over months
Corrosion on the plate’s tracks. Replace the plate (about ₹40) — and keep the power switched from the GPIO.