Saving water when it rains

With the recent rain I noticed that my sprinkler system continued to do its job, even when the garden had more than enough water. Why not automatically disable the sprinkler when it’s raining.

Rain sensor + Processor + H Bridge Driver + Solenoid = Fixed!

The red rain sensor feeds into the processor (Adafruit 32u4 feather, overkill) which drives a H Bridge that accepts 9V to drive a latching solenoid
ItemDetail
ProcessorAdafruit 32u4 feather
Rain sensorJaycar Rain Sensor XC-4603
9V batteryEnergizer 9V
Latching SolenoidSunshoweronline IVL-NYMV75620DCL
H BridgeAdafruit DRV8871

Reading the rain sensor

Below code reads an analog value then re-maps it. We then use a switch/case to determine 3 broad actions to return.

int readRainSensor(){
  // read the sensor on analog A0:
  int sensorReading = analogRead(A0);
  Serial.print("Reading rain sensor, currently:"+String(sensorReading)+", re-maps to:");
  // map the sensor range (four options):
  // ex: 'long int map(long int, long int, long int, long int, long int)'
  int range = map(sensorReading, sensorMin, sensorMax, 0, 3);
  Serial.println(String(range));
  // range value:
  switch (range) {
 case 0:    // Sensor getting wet
    Serial.println("WET");
    break;
 case 1:    // Sensor getting wet
    Serial.println("MEDIUM");
    break;
 case 2:    // Sensor dry - To shut this up delete the " Serial.println("Not Raining"); " below.
    Serial.println("DRY");
    break;
  }
  
  return range;
  
  }

Driving the solenoid

I’ve chosen a ‘Latching’ solenoid for this application. This is to conserve the battery. A normal solenoid will down juice whenever you activate it while a latching only does to transition. The complication here is that a latching needs to recieve reverse polarity to ‘unlatch’. Ie drive it forward to open, and reverse voltage to close. As a result we cant use a relay, we will use a H-Bridge.

The below code sets up the two inputs of the H-Bridge then we can send it a valve request of OPEN or CLOSE. The latching solenoid needs power for a moment (I chose 300mS / 0.3 seconds) and then you can release to conserve battery.

This driver accepts:

Input 1Input 2Output
LowLowNothing / Coast
HighLowForward
LowHighReverse
HighHighBreak / Stop

I only mention the High + High out of interest. If this was a motor then we could apply the breaks with this mode.

#define MOTOR_IN1 9
#define MOTOR_IN2 10

#define OPEN 1
#define CLOSE 0

pinMode(MOTOR_IN1, OUTPUT);
pinMode(MOTOR_IN2, OUTPUT);

int valveControl(int request){
  int holdTime = 300;
  
  Serial.println("Setting valve to:"+String(request));
  digitalWrite(MOTOR_IN1, request);
  digitalWrite(MOTOR_IN2, !request);
  delay(holdTime);   
  //Stop power
  Serial.println("Releasing power");
  digitalWrite(MOTOR_IN1, LOW);
  digitalWrite(MOTOR_IN2, LOW);

  return request;
  
  }

All together now

#define MOTOR_IN1 9
#define MOTOR_IN2 10

#define OPEN 1
#define CLOSE 0

#define RAINING 0
#define WET 1
#define DRY 2

// lowest and highest sensor readings:
const int sensorMin = 0;     // sensor minimum
const int sensorMax = 1024;  // sensor maximum
int stateOfValve = 0;

void setup() {
  pinMode(MOTOR_IN1, OUTPUT);
  pinMode(MOTOR_IN2, OUTPUT);
  stateOfValve = valveControl(CLOSE); //Initalise valve
  Serial.begin(9600);
  Serial.println("Sentinel");
}

void loop() {

  int currentWetness = readRainSensor();
  Serial.println("currentWetness:"+String(currentWetness));
  
  if(currentWetness == RAINING && stateOfValve == OPEN){
    stateOfValve = valveControl(CLOSE);
    Serial.println("Valve Request: CLOSE");
  }else if(currentWetness == DRY && stateOfValve == CLOSE){
    stateOfValve = valveControl(OPEN);
    Serial.println("Valve Request: OPEN");
  }

  Serial.println("Valve State:"+returnValveState(stateOfValve));
  
  Serial.println("");
  delay(1000);  // delay between reads
}



int readRainSensor(){
  // read the sensor on analog A0:
  int sensorReading = analogRead(A0);
  Serial.print("Reading rain sensor, currently:"+String(sensorReading)+", re-maps to:");
  // map the sensor range (four options):
  // ex: 'long int map(long int, long int, long int, long int, long int)'
  int range = map(sensorReading, sensorMin, sensorMax, 0, 3);
  Serial.println(String(range));
  // range value:
  switch (range) {
 case 0:    // Sensor getting wet
    Serial.println("WET");
    break;
 case 1:    // Sensor getting wet
    Serial.println("MEDIUM");
    break;
 case 2:    // Sensor dry - To shut this up delete the " Serial.println("Not Raining"); " below.
    Serial.println("DRY");
    break;
  }
  return range;
  }

String returnValveState(int stateOfValve){
  switch (stateOfValve) {
    case 0:    // Sensor getting wet
      return "CLOSED";
      break;
    case 1:    // Sensor getting wet
      return "OPEN";
      break;
    }
  return "ERROR";
  }

int valveControl(int request){
  int holdTime = 300;
  
  Serial.println("Setting valve to:"+String(request));
  digitalWrite(MOTOR_IN1, request);
  digitalWrite(MOTOR_IN2, !request);
  delay(holdTime);   
  //Stop power
  Serial.println("Releasing power");
  digitalWrite(MOTOR_IN1, LOW);
  digitalWrite(MOTOR_IN2, LOW);

  return request;
  }

Items for improvement

  1. Run from Solar. For this we need a boost controller and capacitor as we need a higher voltage as the common LiPo input is 3.2V. The capacitor will allow the solenoid’s inrush to be satisfied.
  2. Adapt for low power consumption – could be done either by implementing sleep mode or adding external watchdog.

Leave a Reply

Your email address will not be published. Required fields are marked *