thanks.
here is the sketch, without the calibration part. I need to finish the physical device and need a part or two.
note during debug I sped up time, so you have to fix the length of an hour; change oneHour to 3600000UL
You can review if you like. Any opportunity to improve is appreciated.
/*
Arduino Tipping Bucket Rain Gauge
June 15, 2014
Version 1.90b
Arduino Tipping Bucket Rain Gauge
Utilizing a tipping bucket sensor, your Vera home automation controller and the MySensors.org
gateway you can measure and sense local rain. This sketch will create two devices on your
Vera controller. One will display your total precipitation for the last 24, 48, 72, 96 and 120
hours. The other, a sensor that changes state if there is recent rain (up to last 120 hours)
above a threshold. Both these settings are user definable.
This sketch features the following:
* Allows you to set the rain threshold in mm
* Allows you to determine the interval window up to 120 hours.
* Displays the last 24, 48, 72, 96 and 120 hours total rain in Variable1 through Variable5
of the Rain Sensor device
* Configuration changes to Sensor device updated every 3 hours.
* SHould run on any Arduino
* Will retain Tripped/Not Tripped status and data in a power outage, saving small ammount
of data to EEPROM (Circular Buffer to maximize life of EEBPROM
* There is a unique setup requirement necessary in order to properly present the Vera device
variables. The details are outlined in the sketch below.
* LED status indicator
by Jim (BulldogLowell@gmail.com) for free public use
*/
#include <SPI.h>
#include <EEPROM.h>
#include <RF24.h>
#include <Sensor.h>
//
#define STATE_LOCATION 513 // stay away from EEPROM used with Sensor.h
#define EEPROM_BUFFER 514 // location of the EEPROM circular buffer
#define BUFFER_LENGTH 121
//
Sensor gw;
boolean metric = false;
//
int eepromIndex;
int tipSensorPin = 3;
int ledPin = 5; //PWM capable required
unsigned long dataMillis;
unsigned long serialInterval = 10000UL;
const unsigned long oneHour = 60000UL;
unsigned long lastTipTime;
unsigned long lastBucketInterval;
unsigned long startMillis;
int dayBuckets [5] [2] = {
{ V_VAR1, 24 },
{ V_VAR2, 48 },
{ V_VAR3, 72 },
{ V_VAR4, 96 },
{ V_VAR5, 120},
};
volatile byte rainBucket [120] ; // 5 days of data
const unsigned long calibrateFactor = 1UL; //Calibration in milimeters of rain per single tip
unsigned long rainRate = 0;
float currentRain = 0;
boolean wasTipped = false;
boolean updateVera;
int rainCount;
volatile int tipBuffer = 0;
byte rainWindow = 72;//default rain window in hours
int rainSensorThreshold = 15;//default rain sensor sensitivity in mm
byte hourCount = 24;
byte state;
byte oldState = -1;
unsigned long ledPulseTime = 500UL;
unsigned long pulseStart;
//
void setup()
{
Serial.begin(115200);
gw.begin();
//
pinMode(tipSensorPin, OUTPUT);
attachInterrupt (1, sensorTipped, CHANGE);
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, HIGH);
gw.sendSketchInfo("Rain Guage", "0.90b");
gw.sendSensorPresentation(1, S_RAIN);
gw.sendSensorPresentation(2, S_MOTION);
Serial.println(F("Sensor Presentation Complete"));
pinMode(tipSensorPin, INPUT);
//
state = EEPROM.read(STATE_LOCATION);
for (int i = 0; i < BUFFER_LENGTH; i++)
{
byte locator = EEPROM.read(EEPROM_BUFFER + i);
if (locator == 0xFF)
{
eepromIndex = EEPROM_BUFFER + i;
loadRainArray(eepromIndex);
Serial.println(eepromIndex);
break;
}
}
//
gw.sendVariable(2, V_TRIPPED, state);
dataMillis = millis();
startMillis = millis();
lastTipTime = millis() - oneHour;
// uncomment the following block the first time you include this device. The delays
// are necessary in order to create the five Variable buckets in the correct order.
// Once you create them, you can comment out these lines and re-upload to your arduino
//------------------------------------------------------
/*
for (int j = 0; j < 5; j++)
{
delay(2000);
gw.sendVariable(1, dayBuckets[j] [0], 1);
}
delay(2000);
gw.sendVariable(2,V_VAR1, 1);
delay(2000);
gw.sendVariable(2,V_VAR2, 1);
*/
//------------------------------------------------------
rainWindow = atoi(gw.getStatus(2, V_VAR1));
delay(2000);
rainSensorThreshold = atoi(gw.getStatus(2, V_VAR2));
gw.sendVariable(1, V_RAINRATE, 0);
Serial.print(F("Radio Done"));
analogWrite(ledPin, 20);
}
//
void loop()
{
unsigned long measure = 0; // Check to see if we need to show sensor tripped in this block
for (int i = 0; i < rainWindow; i++)
{
measure = measure + rainBucket [i];
}
measure >= rainSensorThreshold ? state = 1: state = 0;
if (millis() - pulseStart < ledPulseTime)
{
analogWrite(ledPin, 255);
}
else
{
analogWrite(ledPin, 20);
}
if (state != oldState)
{
gw.sendVariable(2, V_TRIPPED, state);
EEPROM.write(STATE_LOCATION, state);
oldState = state;
}
//
if (millis() - lastTipTime >= oneHour)// timeout for rain rate
{
if (rainRate != 0)
{
rainRate = 0;
gw.sendVariable(1, V_RAINRATE, rainRate);
}
}
if (updateVera)
{
gw.sendVariable(1, V_RAINRATE, rainRate);
updateVera = false;
}
//
if ( (millis() - dataMillis) >= serialInterval)//Comment back in this block to enable Serial prints
{
for (int i = 24; i <= 120; i=i+24)
{
updateSerialData(i);
}
dataMillis = millis();
}
//
if (tipBuffer > 0)
{
Serial.println(F("Sensor Tipped"));
rainBucket [0] ++;
pulseStart = millis();
if (rainBucket [0] > 253) rainBucket[0] = 253; // odd occurance but prevent overflow
int dayTotal = 0;
for (int i = 0; i < 24; i++)
{
dayTotal = dayTotal + rainBucket [i];
}
gw.sendVariable(1, V_RAIN, dayTotal);
unsigned long tipDelay = millis() - lastTipTime;
if (tipDelay <= oneHour)
{
rainRate = ((oneHour) / tipDelay);
gw.sendVariable(1, V_RAINRATE, rainRate);
Serial.print(F("RainRate= "));
Serial.println(rainRate);
}
lastTipTime = millis();
updateVera = true;
tipBuffer--;
}
if ( (millis()- startMillis) >= oneHour)
{
Serial.println("one hour elapsed");
//EEPROM write last value
EEPROM.write(eepromIndex, rainBucket[0]);
eepromIndex++;
Serial.println(eepromIndex);
if (eepromIndex > EEPROM_BUFFER + BUFFER_LENGTH) eepromIndex = EEPROM_BUFFER;
EEPROM.write(eepromIndex, 0xFF);
//
for (int i = 118; i >= 0; i--)//cascade an hour of values
{
rainBucket [i + 1] = rainBucket [i];
}
rainBucket[0] = 0;
gw.sendVariable(1, V_RAIN, tipCounter(24));// send 24hr tips
startMillis = millis();
for (int j = 0; j < 5; j++)
{
int total = 0;
for (int i = 0; i < dayBuckets[j][1]; i++)
{
total = total + rainBucket [i];
}
gw.sendVariable( 1, dayBuckets[j] [0], total);
}
hourCount++;
if (hourCount >=4)//8 times daily update the Sensor variables
{
rainWindow = atoi(gw.getStatus(2, V_VAR1));
if (rainWindow < 6)
{
rainWindow = 6;
gw.sendVariable( 2, V_VAR1, rainWindow);
}
if (rainWindow > 120)
{
rainWindow = 120;
gw.sendVariable( 2, V_VAR2, rainWindow);
}
rainSensorThreshold = atoi(gw.getStatus(2, V_VAR2));
delay(2000);
if (rainSensorThreshold < 1)
{
rainSensorThreshold = 1;
gw.sendVariable( 2, V_VAR2, rainSensorThreshold);
}
if (rainSensorThreshold > 1000)
{
rainSensorThreshold = 1000;
gw.sendVariable( 2, V_VAR2, rainSensorThreshold);
}
hourCount = 0;
}
}
}
//
void sensorTipped()
{
static unsigned long last_interrupt_time = 0;
unsigned long interrupt_time = millis();
if (interrupt_time - last_interrupt_time > 200)
{
tipBuffer++;
}
last_interrupt_time = interrupt_time;
}
//
unsigned long tipCounter(int x)
{
int tipCount = 0;
for ( int i = 0; i < x; i++)
{
tipCount = tipCount + rainBucket [i];
}
return tipCount;
}
//
void updateSerialData(int x)
{
Serial.print(F("Tips last "));
Serial.print(x);
Serial.print(F("hours: "));
int tipCount = 0;
for (int i = 0; i < x; i++)
{
tipCount = tipCount + rainBucket [i];
}
Serial.println(tipCount);
}
void loadRainArray(int value)
{
for (int i = 0; i < BUFFER_LENGTH - 1; i++)
{
value--;
Serial.println(value);
if (value < EEPROM_BUFFER)
{
value = EEPROM_BUFFER + BUFFER_LENGTH;
}
byte rainValue = EEPROM.read(value);
Serial.println(rainValue);
if (rainValue < 255)
{
rainBucket[i] = rainValue;
}
else
{
rainBucket [i] = 0;
}
}
}