DIY ELECTRONICSTR

← All projects

Rain Alert and Automatic Window

Beginner40 min

A setup that sounds an alert and closes the window by itself when it starts to rain: when water drops land on the rain sensor's plate, the buzzer plays a ding-dong three times, then a servo slowly closes the window. Some time after the plate dries, the window opens again. The sensor board is powered from one of the Arduino's pins and switched on only while measuring, so the plate does not corrode by electrolysis. It teaches turning an analog reading into a percentage, using two separate thresholds for rain and dry, timing a period (that starts over if the plate gets wet again) and turning a servo slowly, one step at a time. The Servo library comes with the Arduino IDE; there is nothing to install.

Build it step by step in the app

What you need

Wiring steps

  1. 1

    Connect the power rails (5V and GND)

    Connect the power rails (5V and GND)

    Connect one of the GND pins on the Arduino's power header to the breadboard's bottom blue (−) rail with a black male-male wire, and the 5V pin on the same header to the bottom red (+) rail with a red wire. At the right end of the breadboard, join the bottom (+) rail to the top (+) rail with a red wire and the bottom (−) rail to the top (−) rail with a black wire: the breadboard's top and bottom rails are not connected to each other. The servo and the buzzer will use the top rails.

    • Arduino GND → the bottom blue (−) rail (black wire)
    • Arduino 5V → the bottom red (+) rail (red wire)
    • the bottom red (+) rail → the top red (+) rail (red wire)
    • the bottom blue (−) rail → the top blue (−) rail (black wire)
  2. 2

    Plug in and wire the rain sensor

    Plug in and wire the rain sensor

    Plug the rain sensor's board (the small one with the trimmer and the LM393) in with its four pins in row E of the breadboard's bottom half: VCC in column 54, GND in 55, DO in 56 and AO in 57. Connect the plate to the two pins at the board's other end with the two-wire cable that comes with the sensor; the cable can go either way round. Connect the Arduino's A1 pin to column 54 (VCC) with a red wire and its A0 pin to column 57 (AO, the analog output) with a yellow wire (RAIN_POWER A1, RAIN_PIN A0). Connect column 55 to the bottom (−) rail with a short black wire. The DO pin stays empty; the code sets the threshold, so the trimmer needs no adjusting. The board takes its power from A1 rather than 5V: the code switches it on only while measuring, for a moment each second. With current through it all the time, the plate's tracks corrode by electrolysis within a few weeks. Put the plate where the rain will fall on it, tilted a little so water does not pool on it.

    • rain sensor board VCC → column 54, bottom half
    • rain sensor board GND → column 55, bottom half
    • rain sensor board DO → column 56, bottom half
    • rain sensor board AO → column 57, bottom half
    • Arduino A1 → column 54, bottom half (red wire)
    • Arduino A0 → column 57, bottom half (yellow wire)
    • column 55, bottom half → the bottom blue (−) rail (black wire)
  3. 3

    Add and wire the buzzer

    Add and wire the buzzer

    Plug the passive buzzer's + leg into column 5 in row F of the breadboard's top half and its other leg into column 6; the + leg is usually the longer one and the body has a + mark. Connect the Arduino's pin 8 to column 5 with a purple male-male wire (BUZZER_PIN 8). Connect column 6 to the top blue (−) rail with a short black wire.

    • buzzer + leg → column 5, top half
    • buzzer − leg → column 6, top half
    • Arduino pin 8 → column 5, top half (purple wire)
    • column 6, top half → the top blue (−) rail (black wire)
  4. 4

    Connect the servo and fit it to the window

    Connect the servo and fit it to the window

    Push three male-male wires into the servo's three-wire plug. Connect the orange (signal) wire to the Arduino's pin 9 (SERVO_PIN 9), the red (+) wire to the top red (+) rail and the brown (−) wire to the top blue (−) rail. You can make a cardboard window for it: tape the sash to the frame like a hinge and link the servo arm to the sash with a piece of wire or a stick. At start the code turns the servo to the open angle (OPEN_ANGLE 90), so fit the arm in that position with the window open. If the window closes the wrong way, swap the values of OPEN_ANGLE and CLOSED_ANGLE in the code. One unloaded servo runs fine on the Arduino's 5V; a heavy real window needs a stronger servo and a power supply of its own.

    • Arduino pin 9 → servo signal lead (orange wire)
    • servo + lead → the top red (+) rail (red wire)
    • servo − lead → the top blue (−) rail (brown wire)

Arduino sketch

// The Servo library comes with the IDE
#include <Servo.h>

// The rain board's AO (analog) output
const int RAIN_PIN = A0;
// The board's VCC comes from this pin:
// on only while measuring, so the plate
// does not corrode (an analog pin works
// as a digital output too)
const int RAIN_POWER = A1;
const int BUZZER_PIN = 8;
// The servo's orange (signal) wire
const int SERVO_PIN = 9;

// The window's open and closed angles:
// swap them if the arm is fitted the
// other way round
const int OPEN_ANGLE = 90;
const int CLOSED_ANGLE = 0;
// Wetness above this percentage is rain
const int RAIN_ON = 30;
// Below this percentage counts as dry
const int DRY_BELOW = 10;
// Dry this long, the window opens again
// (make it 10-15 min for a real one)
const unsigned long REOPEN_AFTER = 60000;
// Time between readings (ms)
const unsigned long MEASURE_EVERY = 1000;
// The servo turns 1 degree, then waits
// this long: the window closes gently
// (ms)
const unsigned long STEP_TIME = 15;

Servo window;
int angle = OPEN_ANGLE;
int target = OPEN_ANGLE;
bool raining = false;
unsigned long dryStart = 0;
unsigned long lastMeasure = 0;
unsigned long lastStep = 0;

// How wet the plate is: 0 dry, 100 soaked
int readWetness() {
  digitalWrite(RAIN_POWER, HIGH);
  delay(10);
  int value = analogRead(RAIN_PIN);
  digitalWrite(RAIN_POWER, LOW);
  // A dry plate reads close to 1023
  return (1023L - value) * 100 / 1023;
}

// Rain warning: ding-dong three times
void rainChime() {
  for (int i = 0; i < 3; i++) {
    tone(BUZZER_PIN, 1200, 150);
    delay(200);
    tone(BUZZER_PIN, 900, 250);
    delay(450);
  }
}

void setup() {
  pinMode(RAIN_POWER, OUTPUT);
  Serial.begin(9600);
  // Raining at start: the window starts
  // closed
  if (readWetness() >= RAIN_ON) {
    raining = true;
    angle = CLOSED_ANGLE;
    target = CLOSED_ANGLE;
  }
  window.attach(SERVO_PIN);
  window.write(angle);
  Serial.println(raining ? "Raining: window closed." : "Ready: window open.");
}

void loop() {
  unsigned long now = millis();

  if (now - lastMeasure >= MEASURE_EVERY) {
    lastMeasure = now;
    int wet = readWetness();
    Serial.print("Wetness: ");
    Serial.print(wet);

    if (!raining && wet >= RAIN_ON) {
      raining = true;
      dryStart = 0;
      Serial.println("% | Rain! Closing the window.");
      rainChime();
      target = CLOSED_ANGLE;
    } else if (raining && wet < DRY_BELOW) {
      // Drying time: starts over if it
      // gets wet again
      if (dryStart == 0) dryStart = now;
      unsigned long dry = now - dryStart;
      if (dry >= REOPEN_AFTER) {
        raining = false;
        Serial.println("% | Dry again, opening the window.");
        tone(BUZZER_PIN, 1500, 100);
        target = OPEN_ANGLE;
      } else {
        Serial.print("% | Window opens in ");
        Serial.print((REOPEN_AFTER - dry) / 1000);
        Serial.println(" s.");
      }
    } else {
      if (raining) dryStart = 0;
      Serial.println(raining ? "% | Raining, window closed." : "% | No rain, window open.");
    }
  }

  // The window goes to the target angle
  // one step at a time
  if (angle != target && now - lastStep >= STEP_TIME) {
    lastStep = now;
    angle += angle < target ? 1 : -1;
    window.write(angle);
  }
}

What the Serial Monitor shows

SERIAL MONITOR · 9600 BAUD
Ready: window open.
Wetness: 1% | No rain, window open.
Wetness: 41% | Rain! Closing the window.
Wetness: 45% | Raining, window closed.
Wetness: 3% | Window opens in 60 s.
Wetness: 2% | Window opens in 59 s.
Wetness: 2% | Window opens in 1 s.
Wetness: 2% | Dry again, opening the window.

If a wire is loose

SERIAL MONITOR · 9600 BAUD
Raining: window closed.
Wetness: 100% | Raining, window closed.
Wetness: 100% | Raining, window closed.

What you will see

Once the code is uploaded the servo opens the window, and every second the Serial Monitor shows how wet the plate is as a percentage; a dry plate reads about 0-5%. Sprinkle a few drops of water on the plate with your finger: once the wetness passes 30% the buzzer plays a ding-dong three times, then the servo slowly closes the window. Dry the plate with a tissue: when the wetness drops below 10% a countdown starts in the Serial Monitor, and if it stays dry for 60 seconds the window opens again with a short beep. If the plate gets wet again meanwhile, the countdown starts over. For a real window, rain can pause for a minute, so raise REOPEN_AFTER in the code to 10-15 minutes. If a dry plate shows 100%, the board is not getting power: check that the red wire is on A1 and in column 54 and that the black wire goes to the (−) rail. If the reading does not change when the plate is wet, check that the yellow wire is on A0 and that the plate is connected to the board. If the servo jitters or the Arduino restarts by itself, the servo is carrying too much: make the window model lighter.

In the app, tick off every wire, match the parts to your inventory and pick up where you left off.

Build it step by step in the app