Rain Gauge
Uploading initial rain gauge code and Vera files
This commit is contained in:
@@ -0,0 +1,523 @@
|
||||
{
|
||||
"flashicon": "icons/Humidity_Sensor.swf",
|
||||
"imgIconBody": "",
|
||||
"imgIconDimmable": "",
|
||||
"imgIconTurnable": "",
|
||||
"imgIconMin": "",
|
||||
"imgIconMax": "",
|
||||
"halloIconsDir": "pics\/hallo",
|
||||
"inScene": "0",
|
||||
"DisplayStatus": {},
|
||||
"doc_url": {
|
||||
"doc_language": 1,
|
||||
"doc_manual": 1,
|
||||
"doc_version": 1,
|
||||
"doc_platform": 0,
|
||||
"doc_page": "sensors"
|
||||
},
|
||||
|
||||
"Tabs": [
|
||||
{
|
||||
"Label": {
|
||||
"lang_tag": "tabname_control",
|
||||
"text": "Information"
|
||||
},
|
||||
"Position": "0",
|
||||
"TabType": "flash",
|
||||
"SceneGroup": [
|
||||
{
|
||||
"id": "1",
|
||||
"top": "1.5",
|
||||
"left": "0",
|
||||
"x": "2",
|
||||
"y": "2"
|
||||
}
|
||||
],
|
||||
"ControlGroup": [
|
||||
{
|
||||
"id": "1",
|
||||
"scenegroup": "1",
|
||||
"type": "info"
|
||||
},
|
||||
{
|
||||
"id": "2",
|
||||
"scenegroup": "1",
|
||||
"type": "info"
|
||||
}
|
||||
],
|
||||
"Control": [
|
||||
{
|
||||
"ControlGroup":"1",
|
||||
"ControlPair": "1",
|
||||
"ControlHeader": "1",
|
||||
"top": "1",
|
||||
"left": "0",
|
||||
"x": "1.25",
|
||||
"ControlType": "label",
|
||||
"Label": {
|
||||
"lang_tag": "rain_rate",
|
||||
"text": "Rate of Rain"
|
||||
},
|
||||
"Display": {
|
||||
"Top": 20,
|
||||
"Left": 50,
|
||||
"Width": 75,
|
||||
"Height": 20
|
||||
}
|
||||
},
|
||||
{
|
||||
"ControlGroup":"1",
|
||||
"ControlPair": "1",
|
||||
"ControlHeader": "1",
|
||||
"top": "1",
|
||||
"left": "1.25",
|
||||
"x": "0.75",
|
||||
"ControlType": "variable",
|
||||
"Display": {
|
||||
"Service": "urn:upnp-org:serviceId:RainSensor1",
|
||||
"Variable": "CurrentRain",
|
||||
"Top": 20,
|
||||
"Left": 150,
|
||||
"Width": 25,
|
||||
"Height": 20
|
||||
}
|
||||
},
|
||||
{
|
||||
"ControlType": "label",
|
||||
"Label": {
|
||||
"lang_tag": "total_rain_unit",
|
||||
"text": "mm/hr"
|
||||
},
|
||||
"Display": {
|
||||
"Top": 20,
|
||||
"Left": 200,
|
||||
"Width": 25,
|
||||
"Height": 20
|
||||
}
|
||||
},
|
||||
{
|
||||
"ControlGroup":"2",
|
||||
"ControlPair": "2",
|
||||
"ControlHeader": "1",
|
||||
"top": "0",
|
||||
"left": "0",
|
||||
"x": "1.25",
|
||||
"ControlType": "label",
|
||||
"Label": {
|
||||
"lang_tag": "total_rain",
|
||||
"text": "Rain Today:",
|
||||
},
|
||||
"Display": {
|
||||
"Top": 55,
|
||||
"Left": 50,
|
||||
"Width": 75,
|
||||
"Height": 20
|
||||
}
|
||||
},
|
||||
{
|
||||
"ControlGroup":"2",
|
||||
"ControlPair": "2",
|
||||
"ControlHeader": "1",
|
||||
"top": "0",
|
||||
"left": "1.25",
|
||||
"x": "0.75",
|
||||
"ControlType": "variable",
|
||||
"Display": {
|
||||
"Service": "urn:upnp-org:serviceId:RainSensor1",
|
||||
"Variable": "CurrentTRain",
|
||||
"Top": 55,
|
||||
"Left": 150,
|
||||
"Width": 25,
|
||||
"Height": 20
|
||||
}
|
||||
},
|
||||
{
|
||||
"ControlType": "label",
|
||||
"Label": {
|
||||
"lang_tag": "rain_rate_unit",
|
||||
"text": "mm"
|
||||
},
|
||||
"Display": {
|
||||
"Top": 55,
|
||||
"Left": 200,
|
||||
"Width": 25,
|
||||
"Height": 20
|
||||
}
|
||||
},
|
||||
{
|
||||
"ControlGroup":"3",
|
||||
"ControlPair": "3",
|
||||
"ControlHeader": "1",
|
||||
"top": "0",
|
||||
"left": "0",
|
||||
"x": "1.25",
|
||||
"ControlType": "label",
|
||||
"Label": {
|
||||
"lang_tag": "rain_forty",
|
||||
"text": "Yesterday:"
|
||||
},
|
||||
"Display": {
|
||||
"Top": 80,
|
||||
"Left": 50,
|
||||
"Width": 75,
|
||||
"Height": 20
|
||||
}
|
||||
},
|
||||
{
|
||||
"ControlGroup":"3",
|
||||
"ControlPair": "3",
|
||||
"ControlHeader": "1",
|
||||
"top": "0",
|
||||
"left": "1.25",
|
||||
"x": "0.75",
|
||||
"ControlType": "variable",
|
||||
"Display": {
|
||||
"Service": "urn:upnp-org:serviceId:VContainer1",
|
||||
"Variable": "Variable2",
|
||||
"Top": 80,
|
||||
"Left": 150,
|
||||
"Width": 25,
|
||||
"Height": 20
|
||||
}
|
||||
},
|
||||
{
|
||||
"ControlType": "label",
|
||||
"Label": {
|
||||
"lang_tag": "rain_unit",
|
||||
"text": "mm"
|
||||
},
|
||||
"Display": {
|
||||
"Top": 80,
|
||||
"Left": 200,
|
||||
"Width": 25,
|
||||
"Height": 20
|
||||
}
|
||||
},
|
||||
{
|
||||
"ControlGroup":"4",
|
||||
"ControlPair": "4",
|
||||
"ControlHeader": "1",
|
||||
"top": "0",
|
||||
"left": "0",
|
||||
"x": "1.25",
|
||||
"ControlType": "label",
|
||||
"Label": {
|
||||
"lang_tag": "rain_seventy",
|
||||
"text": "3 Days Ago:"
|
||||
},
|
||||
"Display": {
|
||||
"Top": 105,
|
||||
"Left": 50,
|
||||
"Width": 75,
|
||||
"Height": 20
|
||||
}
|
||||
},
|
||||
{
|
||||
"ControlGroup":"4",
|
||||
"ControlPair": "4",
|
||||
"ControlHeader": "1",
|
||||
"top": "0",
|
||||
"left": "1.25",
|
||||
"x": "0.75",
|
||||
"ControlType": "variable",
|
||||
"Display": {
|
||||
"Service": "urn:upnp-org:serviceId:VContainer1",
|
||||
"Variable": "Variable3",
|
||||
"Top": 105,
|
||||
"Left": 150,
|
||||
"Width": 25,
|
||||
"Height": 20
|
||||
}
|
||||
},
|
||||
{
|
||||
"ControlType": "label",
|
||||
"Label": {
|
||||
"lang_tag": "rain_unit1",
|
||||
"text": "mm"
|
||||
},
|
||||
"Display": {
|
||||
"Top": 105,
|
||||
"Left": 200,
|
||||
"Width": 25,
|
||||
"Height": 20
|
||||
}
|
||||
},
|
||||
{
|
||||
"ControlGroup":"5",
|
||||
"ControlPair": "5",
|
||||
"ControlHeader": "1",
|
||||
"top": "0",
|
||||
"left": "0",
|
||||
"x": "1.25",
|
||||
"ControlType": "label",
|
||||
"Label": {
|
||||
"lang_tag": "rain_forty",
|
||||
"text": "4 Days Ago:"
|
||||
},
|
||||
"Display": {
|
||||
"Top": 130,
|
||||
"Left": 50,
|
||||
"Width": 75,
|
||||
"Height": 20
|
||||
}
|
||||
},
|
||||
{
|
||||
"ControlGroup":"5",
|
||||
"ControlPair": "5",
|
||||
"ControlHeader": "1",
|
||||
"top": "0",
|
||||
"left": "1.25",
|
||||
"x": "0.75",
|
||||
"ControlType": "variable",
|
||||
"Display": {
|
||||
"Service": "urn:upnp-org:serviceId:VContainer1",
|
||||
"Variable": "Variable4",
|
||||
"Top": 130,
|
||||
"Left": 150,
|
||||
"Width": 25,
|
||||
"Height": 20
|
||||
}
|
||||
},
|
||||
{
|
||||
"ControlType": "label",
|
||||
"Label": {
|
||||
"lang_tag": "rain_unit2",
|
||||
"text": "mm"
|
||||
},
|
||||
"Display": {
|
||||
"Top": 130,
|
||||
"Left": 200,
|
||||
"Width": 25,
|
||||
"Height": 20
|
||||
}
|
||||
},
|
||||
{
|
||||
"ControlGroup":"6",
|
||||
"ControlPair": "6",
|
||||
"ControlHeader": "1",
|
||||
"top": "0",
|
||||
"left": "0",
|
||||
"x": "1.25",
|
||||
"ControlType": "label",
|
||||
"Label": {
|
||||
"lang_tag": "rain_hundred",
|
||||
"text": "5 Days Ago:"
|
||||
},
|
||||
"Display": {
|
||||
"Top": 155,
|
||||
"Left": 50,
|
||||
"Width": 75,
|
||||
"Height": 20
|
||||
}
|
||||
},
|
||||
{
|
||||
"ControlGroup":"6",
|
||||
"ControlPair": "6",
|
||||
"ControlHeader": "1",
|
||||
"top": "0",
|
||||
"left": "1.25",
|
||||
"x": "0.75",
|
||||
"ControlType": "variable",
|
||||
"Display": {
|
||||
"Service": "urn:upnp-org:serviceId:VContainer1",
|
||||
"Variable": "Variable5",
|
||||
"Top": 155,
|
||||
"Left": 150,
|
||||
"Width": 25,
|
||||
"Height": 20
|
||||
}
|
||||
},
|
||||
{
|
||||
"ControlType": "label",
|
||||
"Label": {
|
||||
"lang_tag": "rain_unit3",
|
||||
"text": "mm"
|
||||
},
|
||||
"Display": {
|
||||
"Top": 155,
|
||||
"Left": 200,
|
||||
"Width": 25,
|
||||
"Height": 20
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Label": {
|
||||
"lang_tag": "advanced",
|
||||
"text": "Advanced"
|
||||
},
|
||||
"Position": "1",
|
||||
"TabType": "javascript",
|
||||
"ScriptName": "shared.js",
|
||||
"Function": "advanced_device"
|
||||
},
|
||||
{
|
||||
"Label": {
|
||||
"lang_tag": "logs",
|
||||
"text": "Logs"
|
||||
},
|
||||
"Position": "2",
|
||||
"TabType": "javascript",
|
||||
"ScriptName": "shared.js",
|
||||
"Function": "device_logs"
|
||||
},
|
||||
{
|
||||
"Label": {
|
||||
"lang_tag": "notifications",
|
||||
"text": "Notifications"
|
||||
},
|
||||
"Position": "3",
|
||||
"TabType": "javascript",
|
||||
"ScriptName": "shared.js",
|
||||
"Function": "device_notifications"
|
||||
}
|
||||
],
|
||||
"eventList2": [
|
||||
{
|
||||
"id": 1,
|
||||
"label": {
|
||||
"lang_tag": "total_rain_goes_above",
|
||||
"text": "Total rain goes above"
|
||||
},
|
||||
"serviceId": "urn:upnp-org:serviceId:RainSensor1",
|
||||
"norepeat": "1",
|
||||
"argumentList": [
|
||||
{
|
||||
"id": 1,
|
||||
"dataType": "r8",
|
||||
"name": "CurrentTRain",
|
||||
"comparisson": ">",
|
||||
"prefix": {
|
||||
"lang_tag": "total_rain",
|
||||
"text": "Total rain"
|
||||
},
|
||||
"suffix": {
|
||||
"lang_tag": "total_rain_unit",
|
||||
"text": "mm"
|
||||
},
|
||||
"HumanFriendlyText": {
|
||||
"lang_tag": "hft_total_rain_goes_above",
|
||||
"text": "Total rain for _DEVICE_NAME_ goes above _ARGUMENT_VALUE_"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"label": {
|
||||
"lang_tag": "total_rain_goes_below",
|
||||
"text": "Total rain goes below"
|
||||
},
|
||||
"serviceId": "urn:upnp-org:serviceId:RainSensor1",
|
||||
"norepeat": "1",
|
||||
"argumentList": [
|
||||
{
|
||||
"id": 1,
|
||||
"dataType": "r8",
|
||||
"name": "CurrentTRain",
|
||||
"comparisson": "<",
|
||||
"prefix": {
|
||||
"lang_tag": "total_rain",
|
||||
"text": "Total rain"
|
||||
},
|
||||
"suffix": {
|
||||
"lang_tag": "total_rain_unit",
|
||||
"text": "mm"
|
||||
},
|
||||
"HumanFriendlyText": {
|
||||
"lang_tag": "hft_total_rain_goes_below",
|
||||
"text": "Total rain for _DEVICE_NAME_ goes below _ARGUMENT_VALUE_"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"label": {
|
||||
"lang_tag": "rain_rate_goes_above",
|
||||
"text": "Current rain goes above"
|
||||
},
|
||||
"serviceId": "urn:upnp-org:serviceId:RainSensor1",
|
||||
"norepeat": "1",
|
||||
"argumentList": [
|
||||
{
|
||||
"id": 1,
|
||||
"dataType": "r8",
|
||||
"name": "CurrentRain",
|
||||
"comparisson": ">",
|
||||
"prefix": {
|
||||
"lang_tag": "rain_rate",
|
||||
"text": "Current rain"
|
||||
},
|
||||
"suffix": {
|
||||
"lang_tag": "rain_rate_unit",
|
||||
"text": "mm/hr"
|
||||
},
|
||||
"HumanFriendlyText": {
|
||||
"lang_tag": "hft_rain_rate_goes_above",
|
||||
"text": "Current rain for _DEVICE_NAME_ goes above _ARGUMENT_VALUE_"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"label": {
|
||||
"lang_tag": "rain_rate_goes_below",
|
||||
"text": "Current rain goes below"
|
||||
},
|
||||
"serviceId": "urn:upnp-org:serviceId:RainSensor1",
|
||||
"norepeat": "1",
|
||||
"argumentList": [
|
||||
{
|
||||
"id": 1,
|
||||
"dataType": "r8",
|
||||
"name": "CurrentRain",
|
||||
"comparisson": "<",
|
||||
"prefix": {
|
||||
"lang_tag": "rain_rate",
|
||||
"text": "Current rain"
|
||||
},
|
||||
"suffix": {
|
||||
"lang_tag": "rain_rate_unit",
|
||||
"text": "mm/hr"
|
||||
},
|
||||
"HumanFriendlyText": {
|
||||
"lang_tag": "hft_rain_rate_goes_below",
|
||||
"text": "Current rain for _DEVICE_NAME_ goes below _ARGUMENT_VALUE_"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"label": {
|
||||
"lang_tag": "battery_level_goes_below",
|
||||
"text": "Battery level goes below"
|
||||
},
|
||||
"serviceId": "urn:micasaverde-com:serviceId:HaDevice1",
|
||||
"argumentList": [
|
||||
{
|
||||
"id": 1,
|
||||
"prefix": {
|
||||
"lang_tag": "Level",
|
||||
"text": "Level"
|
||||
},
|
||||
"dataType": "i4",
|
||||
"name": "BatteryLevel",
|
||||
"comparisson": "<",
|
||||
"suffix": {
|
||||
"lang_tag": "percent_sign",
|
||||
"text": "%"
|
||||
},
|
||||
"HumanFriendlyText": {
|
||||
"lang_tag": "hft_battery_level_goes_below",
|
||||
"text": "Battery level for _DEVICE_NAME_ go below _ARGUMENT_VALUE_%"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"DeviceType": "urn:schemas-micasaverde-com:device:RainSensor:1"
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0"?>
|
||||
<root xmlns="urn:schemas-upnp-org:device-1-0">
|
||||
<specVersion>
|
||||
<major>1</major>
|
||||
<minor>0</minor>
|
||||
</specVersion>
|
||||
<device>
|
||||
<deviceType>urn:schemas-micasaverde-com:device:RainSensor:1</deviceType>
|
||||
<Category_Num>12</Category_Num>
|
||||
<staticJson>D_RainSensor1.json</staticJson>
|
||||
<serviceList>
|
||||
<service>
|
||||
<serviceType>urn:schemas-upnp-org:service:RainSensor:1</serviceType>
|
||||
<serviceId>urn:upnp-org:serviceId:RainSensor1</serviceId>
|
||||
<SCPDURL>S_RainSensor1.xml</SCPDURL>
|
||||
</service>
|
||||
<service>
|
||||
<serviceType>urn:schemas-micasaverde-com:service:HaDevice:1</serviceType>
|
||||
<serviceId>urn:micasaverde-com:serviceId:HaDevice1</serviceId>
|
||||
<SCPDURL>S_HaDevice1.xml</SCPDURL>
|
||||
</service>
|
||||
</serviceList>
|
||||
</device>
|
||||
</root>
|
||||
@@ -0,0 +1,594 @@
|
||||
/*
|
||||
Arduino Tipping Bucket Rain Gauge
|
||||
|
||||
April 26, 2015
|
||||
|
||||
Version 1.4.1 alpha
|
||||
|
||||
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 5 days. 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.
|
||||
|
||||
There is a build overview video here: https://youtu.be/1eMfKQaLROo
|
||||
|
||||
This sketch features the following:
|
||||
|
||||
* Allows you to set the rain threshold in mm
|
||||
* Allows you to determine the tripped indicator window up to 120 hours.
|
||||
* Displays the last 5 days of rain in Variable1 through Variable5
|
||||
of the Rain Sensor device
|
||||
* Configuration changes to Sensor device updated every hour
|
||||
* Should run on any Arduino
|
||||
* Will retain Tripped/Not Tripped status and data in a power interruption, saving small amount
|
||||
of data to EEPROM (Circular Buffer to maximize life of EEPROM)
|
||||
* LED status indicator
|
||||
* Optional Temp/Humidity (DHT-22 or DHT-11) and Light LUX (BH1750) sensors. To use, uncomment
|
||||
#define DHT_ON and/or #define LUX_ON
|
||||
* Optionally send total accumulation of each day's rainfall or send only individual days rainfall totals.
|
||||
Comment out #define USE_DAILY to display individual daily rainfall.
|
||||
|
||||
by @BulldogLowell and @PeteWill for free public use
|
||||
|
||||
*/
|
||||
#include <SPI.h>
|
||||
#include <MySensor.h>
|
||||
#include <math.h>
|
||||
#include <Time.h>
|
||||
|
||||
#define NODE_ID 24 //or AUTO to let controller assign
|
||||
#define SKETCH_NAME "Rain Gauge"
|
||||
#define SKETCH_VERSION "1.4.1a"
|
||||
|
||||
#define DWELL_TIME 125 // this allows for radio to come back to power after a transmission, ideally 0
|
||||
|
||||
//#define DEBUG_ON // comment out this line to disable serial debug
|
||||
#define DHT_ON // uncomment out this line to enable DHT sensor
|
||||
#define LUX_ON // uncomment out this line to enable BH1750 sensor
|
||||
//#define USE_DAILY // displays each time segment as an accumulation of prior periods inclusive. Comment out to display individual daily rainfall totals in the variables sent to your controller.
|
||||
|
||||
#define CALIBRATE_FACTOR 60 // amount of rain per rain bucket tip e.g. 5 is .05mm
|
||||
#define DHT_LUX_DELAY 300000 //Delay in milliseconds that the DHT and LUX sensors will wait before sending data
|
||||
|
||||
#define CHILD_ID_RAIN_LOG 3 // Keeps track of accumulated rainfall
|
||||
#define CHILD_ID_TRIPPED_INDICATOR 4 // Indicates Tripped when rain detected
|
||||
#define EEPROM_BUFFER_LOCATION 0 // location of the EEPROM circular buffer
|
||||
#define E_BUFFER_LENGTH 240
|
||||
#define RAIN_BUCKET_SIZE 120
|
||||
|
||||
#ifdef DEBUG_ON
|
||||
#define DEBUG_PRINT(x) Serial.print(x)
|
||||
#define DEBUG_PRINTLN(x) Serial.println(x)
|
||||
#define SERIAL_START(x) Serial.begin(x)
|
||||
#else
|
||||
#define DEBUG_PRINT(x)
|
||||
#define DEBUG_PRINTLN(x)
|
||||
#define SERIAL_START(x)
|
||||
#endif
|
||||
//
|
||||
MySensor gw;
|
||||
//
|
||||
MyMessage msgRainRate(CHILD_ID_RAIN_LOG, V_RAINRATE);
|
||||
MyMessage msgRain(CHILD_ID_RAIN_LOG, V_RAIN);
|
||||
//
|
||||
MyMessage msgRainVAR1(CHILD_ID_RAIN_LOG, V_VAR1);
|
||||
MyMessage msgRainVAR2(CHILD_ID_RAIN_LOG, V_VAR2);
|
||||
MyMessage msgRainVAR3(CHILD_ID_RAIN_LOG, V_VAR3);
|
||||
MyMessage msgRainVAR4(CHILD_ID_RAIN_LOG, V_VAR4);
|
||||
MyMessage msgRainVAR5(CHILD_ID_RAIN_LOG, V_VAR5);
|
||||
//
|
||||
MyMessage msgTripped(CHILD_ID_TRIPPED_INDICATOR, V_TRIPPED);
|
||||
MyMessage msgTrippedVar1(CHILD_ID_TRIPPED_INDICATOR, V_VAR1);
|
||||
MyMessage msgTrippedVar2(CHILD_ID_TRIPPED_INDICATOR, V_VAR2);
|
||||
//
|
||||
#ifdef DHT_ON
|
||||
#include <DHT.h>
|
||||
#define CHILD_ID_HUM 0
|
||||
#define CHILD_ID_TEMP 1
|
||||
#define HUMIDITY_SENSOR_DIGITAL_PIN 8
|
||||
DHT dht;
|
||||
float lastTemp;
|
||||
float lastHum;
|
||||
boolean metric = true;
|
||||
MyMessage msgHum(CHILD_ID_HUM, V_HUM);
|
||||
MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP);
|
||||
#endif
|
||||
//
|
||||
#ifdef LUX_ON
|
||||
//BH1750 is connected to SCL (analog input A5) and SDA (analog input A4)
|
||||
#include <BH1750.h>
|
||||
#include <Wire.h>
|
||||
#define CHILD_ID_LIGHT 2
|
||||
BH1750 lightSensor;
|
||||
MyMessage msg(CHILD_ID_LIGHT, V_LIGHT_LEVEL);
|
||||
unsigned int lastlux;
|
||||
byte heartbeat = 10; //Used to send the light lux to gateway as soon as the device is restarted and after the DHT_LUX_DELAY has happened 10 times
|
||||
#endif
|
||||
unsigned long sensorPreviousMillis;
|
||||
int eepromIndex;
|
||||
int tipSensorPin = 3; // Pin the tipping bucket is connected to. Must be interrupt capable pin
|
||||
int ledPin = 5; // Pin the LED is connected to. PWM capable pin required
|
||||
unsigned long dataMillis;
|
||||
unsigned long serialInterval = 600000UL;
|
||||
const unsigned long oneHour = 3600000UL;
|
||||
unsigned long lastTipTime;
|
||||
unsigned long lastRainTime; //Used for rainRate calculation
|
||||
unsigned int rainBucket [RAIN_BUCKET_SIZE] ; /* 24 hours x 5 Days = 120 hours */
|
||||
unsigned int rainRate = 0;
|
||||
byte rainWindow = 72; //default rain window in hours. Will be overwritten with msgTrippedVar1.
|
||||
volatile int wasTippedBuffer = 0;
|
||||
int rainSensorThreshold = 50; //default rain sensor sensitivity in hundredths. Will be overwritten with msgTrippedVar2.
|
||||
byte state = 0;
|
||||
byte oldState = -1;
|
||||
int lastRainRate = 0;
|
||||
int lastMeasure = 0;
|
||||
boolean gotTime = false;
|
||||
byte lastHour;
|
||||
byte currentHour;
|
||||
//
|
||||
void setup()
|
||||
{
|
||||
SERIAL_START(115200);
|
||||
//
|
||||
// Set up the IO
|
||||
pinMode(tipSensorPin, INPUT_PULLUP);
|
||||
attachInterrupt (1, sensorTipped, FALLING); // depending on location of the hall effect sensor may need CHANGE
|
||||
pinMode(ledPin, OUTPUT);
|
||||
digitalWrite(ledPin, HIGH);
|
||||
//
|
||||
//Let's get the controller talking to the Arduino
|
||||
gw.begin(getVariables, NODE_ID);
|
||||
gw.sendSketchInfo(SKETCH_NAME, SKETCH_VERSION);
|
||||
gw.wait(DWELL_TIME);
|
||||
gw.present(CHILD_ID_RAIN_LOG, S_RAIN);
|
||||
gw.wait(DWELL_TIME);
|
||||
gw.present(CHILD_ID_TRIPPED_INDICATOR, S_MOTION);
|
||||
gw.wait(DWELL_TIME);
|
||||
DEBUG_PRINTLN(F("Sensor Presentation Complete"));
|
||||
//
|
||||
//Sync time with the server, this will be called hourly in order to keep time from creeping with the crystal
|
||||
//
|
||||
unsigned long functionTimeout = millis();
|
||||
while (timeStatus() == timeNotSet && millis() - functionTimeout < 30000UL)
|
||||
{
|
||||
gw.process();
|
||||
gw.requestTime(receiveTime);
|
||||
DEBUG_PRINTLN(F("Getting Time"));
|
||||
gw.wait(1000); // call once per second
|
||||
DEBUG_PRINTLN(F("."));
|
||||
}
|
||||
currentHour = hour();
|
||||
lastHour = hour();
|
||||
//
|
||||
//retrieve from EEPROM stored values on a power cycle.
|
||||
//
|
||||
boolean isDataOnEeprom = false;
|
||||
for (int i = 0; i < E_BUFFER_LENGTH; i++)
|
||||
{
|
||||
byte locator = gw.loadState(EEPROM_BUFFER_LOCATION + i);
|
||||
if (locator == 0xFE) // found the EEPROM circular buffer index
|
||||
{
|
||||
eepromIndex = EEPROM_BUFFER_LOCATION + i;
|
||||
DEBUG_PRINT(F("EEPROM Index "));
|
||||
DEBUG_PRINTLN(eepromIndex);
|
||||
//Now that we have the buffer index let's populate the rainBucket[] with data from eeprom
|
||||
loadRainArray(eepromIndex);
|
||||
isDataOnEeprom = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//
|
||||
if (!isDataOnEeprom) // Added for the first time it is run on a new Arduino
|
||||
{
|
||||
DEBUG_PRINTLN(F("I didn't find valid EEPROM Index, so I'm writing one to location 0"));
|
||||
eepromIndex = EEPROM_BUFFER_LOCATION;
|
||||
gw.saveState(eepromIndex, 0xFE);
|
||||
gw.saveState(eepromIndex + 1, 0xFE);
|
||||
//then I will clear out any bad data
|
||||
for (int i = 2; i <= E_BUFFER_LENGTH; i++)
|
||||
{
|
||||
gw.saveState(i, 0x00);
|
||||
}
|
||||
}
|
||||
dataMillis = millis();
|
||||
lastTipTime = millis() - oneHour; //why is this -oneHour?? Doesn't millis() start at 0 when first powered on?
|
||||
//
|
||||
gw.request(CHILD_ID_TRIPPED_INDICATOR, V_VAR1);
|
||||
gw.wait(DWELL_TIME);
|
||||
gw.request(CHILD_ID_TRIPPED_INDICATOR, V_VAR2);
|
||||
gw.wait(DWELL_TIME);
|
||||
//
|
||||
#ifdef DHT_ON
|
||||
dht.setup(HUMIDITY_SENSOR_DIGITAL_PIN);
|
||||
// Register all sensors to gw (they will be created as child devices)
|
||||
gw.present(CHILD_ID_HUM, S_HUM);
|
||||
gw.wait(DWELL_TIME);
|
||||
gw.present(CHILD_ID_TEMP, S_TEMP);
|
||||
gw.wait(DWELL_TIME);
|
||||
metric = gw.getConfig().isMetric;
|
||||
gw.wait(DWELL_TIME);
|
||||
#endif
|
||||
//
|
||||
#ifdef LUX_ON
|
||||
gw.present(CHILD_ID_LIGHT, S_LIGHT_LEVEL);
|
||||
gw.wait(DWELL_TIME);
|
||||
lightSensor.begin();
|
||||
#endif
|
||||
//
|
||||
DEBUG_PRINTLN(F("Radio Setup Complete!"));
|
||||
transmitRainData();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
gw.process();
|
||||
if (state)
|
||||
{
|
||||
prettyFade(); // breathe if tripped
|
||||
}
|
||||
else
|
||||
{
|
||||
slowFlash(); // blink if not tripped
|
||||
}
|
||||
#ifdef DEBUG_ON // Serial Debug Block
|
||||
if ( (millis() - dataMillis) >= serialInterval)
|
||||
{
|
||||
for (int i = 24; i <= 120; i = i + 24)
|
||||
{
|
||||
updateSerialData(i);
|
||||
}
|
||||
dataMillis = millis();
|
||||
}
|
||||
#endif
|
||||
//
|
||||
// let's constantly check to see if the rain in the past rainWindow hours is greater than rainSensorThreshold
|
||||
//
|
||||
int measure = 0; // Check to see if we need to show sensor tripped in this block
|
||||
for (int i = 0; i < rainWindow; i++)
|
||||
{
|
||||
measure += rainBucket [i];
|
||||
if (measure != lastMeasure)
|
||||
{
|
||||
// DEBUG_PRINT(F("measure value (total rainBucket within rainWindow): "));
|
||||
// DEBUG_PRINTLN(measure);
|
||||
lastMeasure = measure;
|
||||
}
|
||||
}
|
||||
//
|
||||
state = (measure >= (rainSensorThreshold * 100));
|
||||
if (state != oldState)
|
||||
{
|
||||
gw.send(msgTripped.set(state));
|
||||
gw.wait(DWELL_TIME);
|
||||
DEBUG_PRINT(F("New Sensor State... Sensor: "));
|
||||
DEBUG_PRINTLN(state ? "Tripped" : "Not Tripped");
|
||||
oldState = state;
|
||||
}
|
||||
//
|
||||
unsigned long tipDelay = millis() - lastRainTime;
|
||||
if (wasTippedBuffer) // if was tipped, then update the 24hour total and transmit to Vera
|
||||
{
|
||||
DEBUG_PRINTLN(F("Sensor Tipped"));
|
||||
DEBUG_PRINT(F("rainBucket [0] value: "));
|
||||
DEBUG_PRINTLN(rainBucket [0]);
|
||||
gw.send(msgRain.set((float)rainTotal(currentHour) / 100, 1)); //Calculate the total rain for the day
|
||||
gw.wait(DWELL_TIME);
|
||||
wasTippedBuffer--;
|
||||
rainRate = ((oneHour) / tipDelay);
|
||||
if (rainRate != lastRainRate)
|
||||
{
|
||||
gw.send(msgRainRate.set(rainRate, 1));
|
||||
gw.wait(DWELL_TIME);
|
||||
DEBUG_PRINT(F("RainRate= "));
|
||||
DEBUG_PRINTLN(rainRate);
|
||||
lastRainRate = rainRate;
|
||||
}
|
||||
lastRainTime = lastTipTime;
|
||||
}
|
||||
//
|
||||
currentHour = hour();
|
||||
if (currentHour != lastHour)
|
||||
{
|
||||
DEBUG_PRINTLN(F("One hour elapsed."));
|
||||
gw.send(msgRain.set((float)rainTotal(currentHour) / 100, 1)); // send today's rainfall
|
||||
gw.wait(DWELL_TIME);
|
||||
gw.saveState(eepromIndex, highByte(rainBucket[0]));
|
||||
gw.saveState(eepromIndex + 1, lowByte(rainBucket[0]));
|
||||
DEBUG_PRINT(F("Saving rainBucket[0] to eeprom. rainBucket[0] = "));
|
||||
DEBUG_PRINTLN(rainBucket[0]);
|
||||
for (int i = RAIN_BUCKET_SIZE - 1; i >= 0; i--)//cascade an hour of values back into the array
|
||||
{
|
||||
rainBucket [i + 1] = rainBucket [i];
|
||||
}
|
||||
gw.request(CHILD_ID_TRIPPED_INDICATOR, V_VAR1);
|
||||
gw.wait(DWELL_TIME);
|
||||
gw.request(CHILD_ID_TRIPPED_INDICATOR, V_VAR2);
|
||||
gw.wait(DWELL_TIME);
|
||||
rainBucket[0] = 0;
|
||||
eepromIndex = eepromIndex + 2;
|
||||
if (eepromIndex > EEPROM_BUFFER_LOCATION + E_BUFFER_LENGTH)
|
||||
{
|
||||
eepromIndex = EEPROM_BUFFER_LOCATION;
|
||||
}
|
||||
DEBUG_PRINT(F("Writing to EEPROM. Index: "));
|
||||
DEBUG_PRINTLN(eepromIndex);
|
||||
gw.saveState(eepromIndex, 0xFE);
|
||||
gw.saveState(eepromIndex + 1, 0xFE);
|
||||
gw.requestTime(receiveTime); // sync the time every hour
|
||||
gw.wait(DWELL_TIME);
|
||||
transmitRainData();
|
||||
rainRate = 0;
|
||||
gw.send(msgRainRate.set(rainRate, 1));
|
||||
gw.wait(DWELL_TIME);
|
||||
DEBUG_PRINTLN(F("Sending rainRate is 0 to controller"));
|
||||
lastHour = currentHour;
|
||||
}
|
||||
if (millis() - sensorPreviousMillis > DHT_LUX_DELAY)
|
||||
{
|
||||
#ifdef DHT_ON //DHT Code
|
||||
doDHT();
|
||||
#endif
|
||||
#ifdef LUX_ON
|
||||
doLUX();
|
||||
#endif
|
||||
sensorPreviousMillis = millis();
|
||||
}
|
||||
}
|
||||
//
|
||||
#ifdef DHT_ON
|
||||
void doDHT(void)
|
||||
{
|
||||
float temperature = dht.getTemperature();
|
||||
if (isnan(temperature))
|
||||
{
|
||||
DEBUG_PRINTLN(F("Failed reading temperature from DHT"));
|
||||
} else if (temperature != lastTemp)
|
||||
{
|
||||
lastTemp = temperature;
|
||||
if (!metric)
|
||||
{
|
||||
temperature = dht.toFahrenheit(temperature);
|
||||
}
|
||||
gw.send(msgTemp.set(temperature, 1));
|
||||
gw.wait(DWELL_TIME);
|
||||
DEBUG_PRINT(F("Temperature is: "));
|
||||
DEBUG_PRINTLN(temperature);
|
||||
}
|
||||
float humidity = dht.getHumidity();;
|
||||
if (isnan(humidity))
|
||||
{
|
||||
DEBUG_PRINTLN(F("Failed reading humidity from DHT"));
|
||||
} else if (humidity != lastHum)
|
||||
{
|
||||
lastHum = humidity;
|
||||
gw.send(msgHum.set(humidity, 1));
|
||||
gw.wait(DWELL_TIME);
|
||||
DEBUG_PRINT(F("Humidity is: "));
|
||||
DEBUG_PRINTLN(humidity);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
//
|
||||
#ifdef LUX_ON
|
||||
void doLUX(void)
|
||||
{
|
||||
unsigned int lux = lightSensor.readLightLevel();// Get Lux value
|
||||
DEBUG_PRINT(F("Current LUX Level: "));
|
||||
DEBUG_PRINTLN(lux);
|
||||
heartbeat++;
|
||||
if (lux != lastlux || heartbeat > 10)
|
||||
{
|
||||
gw.send(msg.set(lux));
|
||||
lastlux = lux;
|
||||
}
|
||||
if (heartbeat > 10)
|
||||
{
|
||||
heartbeat = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
//
|
||||
void sensorTipped()
|
||||
{
|
||||
unsigned long thisTipTime = millis();
|
||||
if (thisTipTime - lastTipTime > 100UL)
|
||||
{
|
||||
rainBucket[0] += CALIBRATE_FACTOR; // adds CALIBRATE_FACTOR hundredths of unit each tip
|
||||
wasTippedBuffer++;
|
||||
}
|
||||
lastTipTime = thisTipTime;
|
||||
}
|
||||
//
|
||||
int rainTotal(int hours)
|
||||
{
|
||||
int total = 0;
|
||||
for ( int i = 0; i <= hours; i++)
|
||||
{
|
||||
total += rainBucket [i];
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
void updateSerialData(int x)
|
||||
{
|
||||
DEBUG_PRINT(F("Rain last "));
|
||||
DEBUG_PRINT(x);
|
||||
DEBUG_PRINTLN(F(" hours: "));
|
||||
float tipCount = 0;
|
||||
for (int i = 0; i < x; i++)
|
||||
{
|
||||
tipCount = tipCount + rainBucket [i];
|
||||
}
|
||||
tipCount = tipCount / 100;
|
||||
DEBUG_PRINTLN(tipCount);
|
||||
}
|
||||
|
||||
void loadRainArray(int value) // retrieve stored rain array from EEPROM on powerup
|
||||
{
|
||||
for (int i = 0; i < RAIN_BUCKET_SIZE; i++)
|
||||
{
|
||||
value = value - 2;
|
||||
if (value < EEPROM_BUFFER_LOCATION)
|
||||
{
|
||||
value = EEPROM_BUFFER_LOCATION + E_BUFFER_LENGTH;
|
||||
}
|
||||
DEBUG_PRINT(F("EEPROM location: "));
|
||||
DEBUG_PRINTLN(value);
|
||||
byte rainValueHigh = gw.loadState(value);
|
||||
byte rainValueLow = gw.loadState(value + 1);
|
||||
unsigned int rainValue = rainValueHigh << 8;
|
||||
rainValue |= rainValueLow;
|
||||
rainBucket[i + 1] = rainValue;
|
||||
//
|
||||
DEBUG_PRINT(F("rainBucket[ value: "));
|
||||
DEBUG_PRINT(i + 1);
|
||||
DEBUG_PRINT(F("] value: "));
|
||||
DEBUG_PRINTLN(rainBucket[i + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
void transmitRainData(void)
|
||||
{
|
||||
DEBUG_PRINT(F("In transmitRainData. currentHour = "));
|
||||
DEBUG_PRINTLN(currentHour);
|
||||
int rainUpdateTotal = 0;
|
||||
for (int i = currentHour; i >= 0; i--)
|
||||
{
|
||||
rainUpdateTotal += rainBucket[i];
|
||||
DEBUG_PRINT(F("Adding rainBucket["));
|
||||
DEBUG_PRINT(i);
|
||||
DEBUG_PRINTLN(F("] to rainUpdateTotal."));
|
||||
}
|
||||
DEBUG_PRINT(F("TX Day 1: rainUpdateTotal = "));
|
||||
DEBUG_PRINTLN((float)rainUpdateTotal / 100.0);
|
||||
gw.send(msgRainVAR1.set((float)rainUpdateTotal / 100.0, 1)); //Send current day rain totals (resets at midnight)
|
||||
gw.wait(DWELL_TIME);
|
||||
#ifdef USE_DAILY
|
||||
rainUpdateTotal = 0;
|
||||
#endif
|
||||
for (int i = currentHour + 24; i > currentHour; i--)
|
||||
{
|
||||
rainUpdateTotal += rainBucket[i];
|
||||
DEBUG_PRINT(F("Adding rainBucket["));
|
||||
DEBUG_PRINT(i);
|
||||
DEBUG_PRINTLN(F("] to rainUpdateTotal."));
|
||||
}
|
||||
DEBUG_PRINT(F("TX Day 2: rainUpdateTotal = "));
|
||||
DEBUG_PRINTLN((float)rainUpdateTotal / 100.0);
|
||||
gw.send(msgRainVAR2.set((float)rainUpdateTotal / 100.0, 1));
|
||||
gw.wait(DWELL_TIME);
|
||||
#ifdef USE_DAILY
|
||||
rainUpdateTotal = 0;
|
||||
#endif
|
||||
for (int i = currentHour + 48; i > currentHour + 24; i--)
|
||||
{
|
||||
rainUpdateTotal += rainBucket[i];
|
||||
DEBUG_PRINT(F("Adding rainBucket["));
|
||||
DEBUG_PRINT(i);
|
||||
DEBUG_PRINTLN(F("] to rainUpdateTotal."));
|
||||
}
|
||||
DEBUG_PRINT(F("TX Day 3: rainUpdateTotal = "));
|
||||
DEBUG_PRINTLN((float)rainUpdateTotal / 100.0);
|
||||
gw.send(msgRainVAR3.set((float)rainUpdateTotal / 100.0, 1));
|
||||
gw.wait(DWELL_TIME);
|
||||
#ifdef USE_DAILY
|
||||
rainUpdateTotal = 0;
|
||||
#endif
|
||||
for (int i = currentHour + 72; i > currentHour + 48; i--)
|
||||
{
|
||||
rainUpdateTotal += rainBucket[i];
|
||||
DEBUG_PRINT(F("Adding rainBucket["));
|
||||
DEBUG_PRINT(i);
|
||||
DEBUG_PRINTLN(F("] to rainUpdateTotal."));
|
||||
}
|
||||
DEBUG_PRINT(F("TX Day 4: rainUpdateTotal = "));
|
||||
DEBUG_PRINTLN((float)rainUpdateTotal / 100.0);
|
||||
gw.send(msgRainVAR4.set((float)rainUpdateTotal / 100.0, 1));
|
||||
gw.wait(DWELL_TIME);
|
||||
#ifdef USE_DAILY
|
||||
rainUpdateTotal = 0;
|
||||
#endif
|
||||
for (int i = currentHour + 96; i > currentHour + 72; i--)
|
||||
{
|
||||
rainUpdateTotal += rainBucket[i];
|
||||
DEBUG_PRINT(F("Adding rainBucket["));
|
||||
DEBUG_PRINT(i);
|
||||
DEBUG_PRINTLN(F("] to rainUpdateTotal."));
|
||||
}
|
||||
DEBUG_PRINT(F("TX Day 5: rainUpdateTotal = "));
|
||||
DEBUG_PRINTLN((float)rainUpdateTotal / 100.0);
|
||||
gw.send(msgRainVAR5.set((float)rainUpdateTotal / 100.0, 1));
|
||||
gw.wait(DWELL_TIME);
|
||||
}
|
||||
|
||||
void getVariables(const MyMessage &message)
|
||||
{
|
||||
if (message.sensor == CHILD_ID_RAIN_LOG)
|
||||
{
|
||||
// nothing to do here
|
||||
}
|
||||
else if (message.sensor == CHILD_ID_TRIPPED_INDICATOR)
|
||||
{
|
||||
if (message.type == V_VAR1)
|
||||
{
|
||||
rainWindow = atoi(message.data);
|
||||
if (rainWindow > 120)
|
||||
{
|
||||
rainWindow = 120;
|
||||
}
|
||||
else if (rainWindow < 1)
|
||||
{
|
||||
rainWindow = 1;
|
||||
}
|
||||
if (rainWindow != atoi(message.data)) // if I changed the value back inside the boundries, push that number back to Vera
|
||||
{
|
||||
gw.send(msgTrippedVar1.set(rainWindow));
|
||||
}
|
||||
}
|
||||
else if (message.type == V_VAR2)
|
||||
{
|
||||
rainSensorThreshold = atoi(message.data);
|
||||
if (rainSensorThreshold > 10000)
|
||||
{
|
||||
rainSensorThreshold = 10000;
|
||||
}
|
||||
else if (rainSensorThreshold < 1)
|
||||
{
|
||||
rainSensorThreshold = 1;
|
||||
}
|
||||
if (rainSensorThreshold != atoi(message.data)) // if I changed the value back inside the boundries, push that number back to Vera
|
||||
{
|
||||
gw.send(msgTrippedVar2.set(rainSensorThreshold));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void prettyFade(void)
|
||||
{
|
||||
float val = (exp(sin(millis() / 2000.0 * PI)) - 0.36787944) * 108.0;
|
||||
analogWrite(ledPin, val);
|
||||
}
|
||||
|
||||
void slowFlash(void)
|
||||
{
|
||||
static boolean ledState = true;
|
||||
static unsigned long pulseStart = millis();
|
||||
if (millis() - pulseStart < 100UL)
|
||||
{
|
||||
digitalWrite(ledPin, !ledState);
|
||||
pulseStart = millis();
|
||||
}
|
||||
}
|
||||
|
||||
void receiveTime(unsigned long time)
|
||||
{
|
||||
DEBUG_PRINTLN(F("Time received..."));
|
||||
setTime(time);
|
||||
char theTime[6];
|
||||
sprintf(theTime, "%d:%2d", hour(), minute());
|
||||
DEBUG_PRINTLN(theTime);
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?xml version="1.0"?>
|
||||
<scpd xmlns="urn:schemas-upnp-org:service-1-0">
|
||||
<specVersion>
|
||||
<major>1</major>
|
||||
<minor>0</minor>
|
||||
</specVersion>
|
||||
<serviceStateTable>
|
||||
<stateVariable>
|
||||
<name>CurrentTRain</name>
|
||||
<sendEventsAttribute>yes</sendEventsAttribute>
|
||||
<dataType>r8</dataType>
|
||||
<shortCode>total_rain</shortCode>
|
||||
</stateVariable>
|
||||
<stateVariable>
|
||||
<name>CurrentRain</name>
|
||||
<sendEventsAttribute>yes</sendEventsAttribute>
|
||||
<dataType>r8</dataType>
|
||||
<shortCode>rain_rate</shortCode>
|
||||
</stateVariable>
|
||||
</serviceStateTable>
|
||||
<actionList>
|
||||
<action>
|
||||
<name>GetCurrentTRain</name>
|
||||
<argumentList>
|
||||
<argument>
|
||||
<name>RainValue</name>
|
||||
<direction>out</direction>
|
||||
<relatedStateVariable>CurrentTRain</relatedStateVariable>
|
||||
</argument>
|
||||
</argumentList>
|
||||
</action>
|
||||
<action>
|
||||
<name>GetCurrentRain</name>
|
||||
<argumentList>
|
||||
<argument>
|
||||
<name>RainValue</name>
|
||||
<direction>out</direction>
|
||||
<relatedStateVariable>CurrentRain</relatedStateVariable>
|
||||
</argument>
|
||||
</argumentList>
|
||||
</action>
|
||||
</actionList>
|
||||
</scpd>
|
||||
Reference in New Issue
Block a user