My awning has an angle which is too shallow; rain doesn't run off the awning but pools on the awning and stretches the fabric. To prevent this, the awning has to be retracted when it begins to rain, but this is not possible when I'm not home. The rain sensor described here automatically retracts the awning when it begins to rain.

My motorized awning is radio controlled by Somfy. What I needed was a rain sensor that is radio controlled too, in order to avoid additional wiring. Also, the awning must automatically roll up when it gets dark since I do forget this frequently. Such a radio controlled rain sensor does not exist, therefore I have built one myself. 

Arduino radio controlled capacitive rain sensor
Arduino radio controlled capacitive rain sensor

Capacitive rain sensor from Telecontrolli

Resistive rain sensors are susceptible to corrosion and contamination. Capacitive rain sensors don't suffer from these disadvantages. The used sensor is from Telecontrolli. The capacitance is 100pF in dry condition and increases in wet condition.

Capacitive rain sensor Telecontrolli
Capacitive rain sensor Telecontrolli

Arduino capacitive rain sensor circuit
Arduino capacitive rain sensor circuit


Arduino rain sensor
Arduino rain sensor

Arduino rain sensor
Arduino rain sensor


Code 

/* Rain-sensor.ino

Copyright (C) 2015  Albert van Dalen
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License at http://www.gnu.org/licenses .
Version 16-11-2015
*/

#include <Arduino.h>
#include <Streaming.h>
#include <Albert.h> 
#include <FrequencyTimer2.h>
#include "Classes.h"
#include "Definitions.h"

Led led;
Somfy somfy;
RainSensor rainSensor; 
Heather heather;

void setup() 
{ Serial.begin(9600);  
  led.red(0); 
  led.blinking();
  heather.initISR(); // do after led.red(0)
  rainSensor.calibrate(); // calibration: power-up with dry and clean rainsensor   
}

void loop() 
{ if (dayLight() < dayLightMinValue) somfy.somfyUp();
  if(rainSensor.rain()) somfy.somfyUpWithHeather();
  Serial << "\n" << rainSensor.usec(), rainSensor.dry_us, dayLight(), dayLightMinValue; // operator ,
}

int dayLight()
{ return 1023-adcIn(daySensorADCpin, 100);
}

void heatherTimer2ISR() 
{ static int ms_counter, heatherOnCounter;
  if(ms_counter++ >= 50) // if 50ms
  { ms_counter = 0; 
    heather.on();  
    if(heatherOnCounter++ >= heather.procentOn) heather.off();  
    if(heatherOnCounter >= 100) heatherOnCounter = 0; // 100% = 5 seconds
  }
}

 

// Classes.ino

Somfy::Somfy()
{ openDrain(somfyUpPin, 1); // to protect Somfy electronics
}

void Somfy::somfyUp()
{ openDrain(somfyUpPin, 0); // sunshade up 
  led.red(1);
  delay(500); // button and LED on time
  openDrain(somfyUpPin, 1); 
  led.red(0);
}

void Somfy::somfyUpWithHeather()
{ somfyUp();
  unsigned long ms = millis();
  heather.procentOn = 100; // heather maximum 100%
  while(millis()-ms < heatherMaxOn_ms) Serial << "heathing ";
  heather.procentOn = heatherDefaultOnProcent;
}

//---------------------------------------------------------------------------------------------------------------------------------------------------------

Led::Led()
{ pinMode(ledRedPin, OUTPUT); 
  pinMode(ledGreenPin, OUTPUT);
}

void Led::red(bool red)
{ digitalWrite(ledRedPin, red);
  digitalWrite(ledGreenPin, !red);
}

void Led::blinking()
{ for(int i = 0; i<3; i++)
  { red(1);
    delay(300);
    red(0);
    delay(300);
  }
}

//---------------------------------------------------------------------------------------------------------------------------------------------------------

RainSensor::RainSensor()
{ pinMode(rainSensorOutPin, OUTPUT);          
  pinMode(rainSensorInPin, INPUT);    
}

bool RainSensor::rain()
{ return (usec() > (dry_us + rainSensorMinValue));
}

void RainSensor::calibrate()
{ rainSensor.dry_us = rainSensor.usec();
}

int RainSensor::usec()
{ long us=0;
  for (int i=0; i < rainSamples; i++) us += RCtime_us();
  us /= rainSamples;
  return us; 
}

int RainSensor::RCtime_us()
{ digitalWrite(rainSensorOutPin, 0);
  delay(1); // 1ms discharge
  unsigned long t1 = micros();
  digitalWrite(rainSensorOutPin, 1); // charge
  while(!digitalRead(rainSensorInPin) && (micros()-t1) < timeOut_us); // while < 2.5V
  int us = micros()-t1;
  
  delay(1); // 1ms charge to 5V
  unsigned long t0 = micros();
  digitalWrite(rainSensorOutPin, 0); // discharge
  while(digitalRead(rainSensorInPin) && (micros()-t0) < timeOut_us); // while > 2.5V 
  us += micros()-t0;
  return us;
}

//---------------------------------------------------------------------------------------------------------------------------------------------------------

Heather::Heather()
{ pinMode(heatherPin, OUTPUT); 
  procentOn = heatherDefaultOnProcent; 
}

void Heather::initISR()
{ FrequencyTimer2::setPeriod(heather.timer2); // static member function without object
  FrequencyTimer2::setOnOverflow(heatherTimer2ISR);
}

void Heather::on()
{ digitalWrite(heatherPin, 1);
  led.red(1); // test
}

void Heather::off()
{ digitalWrite(heatherPin, 0);
  led.red(0); // test
}

 

// Classes.h

class Somfy
{ 
public:
  Somfy();
  void somfyUp(); 
  void somfyUpWithHeather();
};

//---------------------------------------------------------------------------------------------------------------------------------------------------------

class Led
{ 
public:
  Led();
  void red(bool red);
  void blinking();
};

//---------------------------------------------------------------------------------------------------------------------------------------------------------

class RainSensor
{
public:
  RainSensor();
  int usec();
  bool rain();  
  void calibrate();
  
  int dry_us;
private:
  int RCtime_us();
  const int rainSamples = 128;
  const int timeOut_us = 1000;
};

//---------------------------------------------------------------------------------------------------------------------------------------------------------

class Heather
{
public:
  Heather();
  void initISR();
  void on();
  void off();
  
  int procentOn;
  const unsigned long timer2ISRInterval_us = 1000; // 1ms, max value 32768?
  const unsigned long timer2 = timer2ISRInterval_us*2; // weird setting 
};

 

// Definitions.h

const byte rainSensorInPin = 3;
const byte daySensorADCpin = 5;
const byte ledGreenPin = 6;
const byte ledRedPin = 7;
const byte somfyUpPin = 9;
const byte heatherPin = 10;
const byte rainSensorOutPin = 11;
const byte NTC_ADCpin = 1;

const int dayLightMinValue = 800;
const int rainSensorMinValue = 10;
const int heatherDefaultOnProcent = 20; // 100% = 5 seconds, 20% * 12V^2/42Ohm = 0,68W
const unsigned long heatherMaxOn_ms = 60000; // todo

 

 

 

 

 

 

 

 

Do you have any comments? Please let me know.
Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.