#include "Arduino.h"
#include <Preferences.h>
//#include "HomeSpan.h"
#include "LatchingButton.h"
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////// GLOBAL VARIABLES ////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// Flash Memory Storage Setup
Preferences preferences;
// Debugging Level
// Sensor Thresholds
#define ConnectionError 0
#define Dry 3150
#define Wet 1200
// Sensor Masked Thresholds
#define MAP_min 0
#define MAP_max 100
#define Mask_Variance 10
#define Dry_Threshold 60
#define Wet_Threshold 85
// Sensor Reading Looop Rates
#define Loop_Rate 5000
#define HomeSpan_Loop_Rate 5000
// Debug Detail Level
volatile int debugLevel = 5;
// HomeSpan Variable Definitions
#define valveDuration 840 // in seconds
#define LEDBlinkRate 500 // in milliseconds
#define HSResetDelay 10 // number of loops / calls to homeSpan.poll() after main_override is pressed
// Fail Safes
#define MaxCyclesDaily 2
#define MaxRunTime 2040000 // in milliseconds (34 mins)
#define MaxFoutainFillTime 2100000 // in milliseconds (35 mins)
#define MinFountainReadingTime 6000 // in milliseconds (1 min)
// Sprinkler Active Status
volatile int HS_Sprinkler_Status = 0;
volatile int HS_Loop_Override_Status = 0;
// Valve Name updates
volatile String Fountain_Planters_Name = "1 Fountain Planters";
volatile String Porch_Planters_Name = "2 Porch Planters";
volatile String Maple_Planter_Name = "3 Maple Planter";
volatile String Lawn_Planters_Name = "4 Lawn Planters";
volatile String Fill_Fountain_Name = "5 Fountain Level";
//////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////// SENSOR PINS ///////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// sensor pins
#define fountain_planters_top_sensor_pin 36 // RED
#define fountain_planters_bottom_sensor_pin 39 // GRN
#define porch_planters_sensor_pin 37 // GRN GRN
#define maple_sensor_pin 38 // RED RED
#define lawn_planters_left_sensor_pin 34 // BLU BLU
#define lawn_planters_right_sensor_pin 35 // YLW YLW
#define fountain_sensor_pin 19 // BLU
// sensor value initialization
int fountain_sensor_value = 0;
//////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////// BUTTON PINS ///////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// push button pins
#define main_override_button_pin 10
#define water_all_planters_button_pin 23
#define fill_fountain_button_pin 9
#define calibrate_sensors_button_pin 18
#define loop_override_button_pin 3
#define homespan_override_button_pin 5
#define homespan_input_pin 14
// initializing push buttons
LatchingButton Main_Override_Button(main_override_button_pin); // Red
LatchingButton Water_All_Planters_Button(water_all_planters_button_pin); // Green
LatchingButton Fill_Fountain_Button(fill_fountain_button_pin); // Blue
LatchingButton Calibrate_Sensors_Button(calibrate_sensors_button_pin); // Black
LatchingButton Loop_Override_Button(loop_override_button_pin); // Orange //debounce interval was set to 10 5/26/24 @2:31pm
LatchingButton HomeSpan_Override_Button(homespan_override_button_pin); // Yellow
// initializing status states to ensure toggles only triggers once per button press
int HS_Sprinkers_State = 0;
int Main_Override_State = 0;
int Loop_Override_State = 0;
int HomeSpan_Override_State = 0;
//////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////// VALVE PINS ////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// valve pins
#define fountain_planters_valve_pin 33
#define porch_planters_valve_pin 21
#define maple_valve_pin 4
#define lawn_planters_valve_pin 22
#define fill_fountain_valve_pin 27
//#define drain_fountain_valve_pin 19
//////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////// SHIFT REGISTER PINS ///////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// shift register pins
#define ledRegisterData_pin 25
#define ledRegisterClock_pin 26
#define ledRegisterLatch_pin 32
// LED pinout high/low definitions
byte ledStatus = 0b00000000;
const byte ROW_HIGH[] = { 0b00000001, 0b00000010, 0b00000100, 0b00001000, 0b00010000,
0b00100000, 0b01000000, 0b10000000 };
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// //
// MAIN STRUCT DEFINITIONS //
// //
//////////////////////////////////////////////////////////////////////////////////////////
// //
// LED STRUCT - MAIN //
// //
//////////////////////////////////////////////////////////////////////////////////////////
struct LED {
int _pin;
int state = 0;
unsigned long blinkTimer = millis();
String _name = "NULL";
void latchLEDRegister() {
digitalWrite(ledRegisterLatch_pin, HIGH);
digitalWrite(ledRegisterLatch_pin, LOW);
}
void updateLEDs() {
digitalWrite(ledRegisterLatch_pin, LOW);
shiftOut(ledRegisterData_pin, ledRegisterClock_pin, MSBFIRST, ledStatus);
digitalWrite(ledRegisterLatch_pin, HIGH);
}
void initialize(int pin, String name) {
_pin = pin;
_name = name;
ledStatus = 0;
updateLEDs();
state = 0;
}
void on() {
if (state != 1) {
ledStatus = ledStatus + ROW_HIGH[_pin];
updateLEDs();
state = 1;
}
}
void off() {
if (state != 0) {
ledStatus = ledStatus - ROW_HIGH[_pin];
updateLEDs();
state = 0;
}
}
void blink() {
if (millis() - blinkTimer > LEDBlinkRate) {
if (state != 1) {
ledStatus = ledStatus + ROW_HIGH[_pin];
updateLEDs();
state = 1;
} else {
ledStatus = ledStatus - ROW_HIGH[_pin];
updateLEDs();
state = 0;
}
blinkTimer = millis();
}
}
};
//////////////////////////////////////////////////////////////////////////////////////////
// //
// SENSOR STRUCT - MAIN //
// //
//////////////////////////////////////////////////////////////////////////////////////////
struct SENSOR {
int _pin;
int _dry = Dry;
int _wet = Wet;
int _value;
int _reading;
bool _error;
bool _enabled;
String _name;
String _NVS_Dry;
String _NVS_Wet;
void initialize(int pin, String name) {
_pin = pin;
_name = name;
_enabled = true;
_NVS_Dry = _name + "_dry";
_NVS_Wet = _name + "_wet";
preferences.begin("Calibration",false);
if(preferences.getInt(_NVS_Dry.c_str()) != 0){
_dry = preferences.getInt(_NVS_Dry.c_str());
}
if(preferences.getInt(_NVS_Wet.c_str()) != 0){
_wet = preferences.getInt(_NVS_Wet.c_str());
}
preferences.end();
}
bool checkError() {
_reading = analogRead(_pin);
_value = map(_reading, _dry, _wet, MAP_min, MAP_max);
if (_reading <= 0 + Mask_Variance) {
_error = true;
_enabled = false;
} else {
_error = false;
_enabled = true;
}
return _error;
}
void calibrate() {
_reading = analogRead(_pin);
if (!checkError()) {
_dry = analogRead(_pin);
_wet = _dry - 1950;
preferences.begin("Calibration",false);
preferences.putInt(_NVS_Dry.c_str(), _dry);
preferences.putInt(_NVS_Wet.c_str(), _wet);
preferences.end();
}
}
int getValue() {
if (!checkError()) {
_value = map(_reading, _dry, _wet, MAP_min, MAP_max);
return _value;
} else {
return -100;
}
}
boolean isDry() {
if (getValue() <= Dry_Threshold) {
return true;
} else {
return false;
}
}
boolean isWet() {
if (getValue() >= Wet_Threshold) {
return true;
} else {
return false;
}
}
};
struct DIGITAL_SENSOR {
int _pin;
int _dry = 1;
int _wet = 0;
int _reading;
unsigned long _dry_timer;
unsigned long _wet_timer;
bool _dry_timer_active = false;
bool _wet_timer_active = false;
String _name;
void initialize(int pin, String name) {
_pin = pin;
_name = name;
pinMode(_pin, INPUT_PULLUP);
}
int getValue() {
_reading = digitalRead(fountain_sensor_pin);
return _reading;
}
bool isDryTimerActive(){
return _dry_timer_active;
}
void startDryTimer(){
_dry_timer = millis();
_dry_timer_active = true;
}
void resetDryTimer(){
_dry_timer = millis();
_dry_timer_active = false;
}
unsigned long dryTimer(){
return millis() - _dry_timer;
}
bool isWetTimerActive(){
return _wet_timer_active;
}
void startWetTimer(){
_wet_timer = millis();
_wet_timer_active = true;
}
void resetWetTimer(){
_wet_timer = millis();
_wet_timer_active = false;
}
unsigned long wetTimer(){
return millis() - _wet_timer;
}
boolean isDry() {
if (getValue() == 1) {
if (isDryTimerActive() == false){
startDryTimer();
} else if (dryTimer() >= MinFountainReadingTime){
if(isWetTimerActive()){
resetWetTimer();
}
return true;
} else {
return false;
}
} else {
if (isWetTimerActive() == false){
startWetTimer();
} else if (wetTimer() >= MinFountainReadingTime){
if(isDryTimerActive()){
resetDryTimer();
}
return false;
} else {
return true;
}
}
}
boolean isWet() {
if (getValue() == 0) {
return true;
} else {
return false;
}
}
};
//////////////////////////////////////////////////////////////////////////////////////////
// //
// VALVE STRUCT - MAIN //
// //
//////////////////////////////////////////////////////////////////////////////////////////
struct VALVE {
int _pin;
int state = 0;
int cyclesToday = 0;
int dailyTimer = 0;
int runTime = 0;
String _name = "NULL";
unsigned long _valveTimer;
void initialize(int pin, String name) {
_pin = pin;
_name = name;
pinMode(_pin, OUTPUT);
digitalWrite(_pin, LOW);
state = 0;
}
void debug(){
Serial.print(_name);
Serial.print(": ");
if(state == 0){
Serial.println("CLOSED");
} else {
Serial.println("OPEN");
}
Serial.print(_name);
Serial.print(".dailyTimer: ");
Serial.println(dailyTimer);
Serial.print(_name);
Serial.print(".cyclesToday: ");
Serial.println(cyclesToday);
Serial.print(_name);
Serial.print("._valveTimer: ");
Serial.println(_valveTimer);
Serial.print(_name);
Serial.print(".runTime: ");
Serial.println(runTime);
Serial.print(_name);
Serial.print(".state: ");
Serial.println(state);
Serial.println("");
Serial.println("");
}
void open() {
if (state != 1) {
if(millis() - dailyTimer >= 86400000){ //num of milliseconds in a 24 hour period
cyclesToday = 0;
runTime = 0;
}
_valveTimer = millis();
digitalWrite(_pin, HIGH);
//bot.sendMessage(CHAT_ID, _name+" Drippers On", "");
state = 1;
cyclesToday += 1;
if(cyclesToday == 1){
dailyTimer = millis();
}
//debug();
}
}
void close() {
if (state != 0) {
digitalWrite(_pin, LOW);
//bot.sendMessage(CHAT_ID, _name+" Drippers OFF", "");
runTime += millis() - _valveTimer;
state = 0;
//debug();
}
}
};
/*
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// //
// HOMESPAN STRUCT DEFINITIONS //
// //
//////////////////////////////////////////////////////////////////////////////////////////
// //
// DEV VALVE - HOMESPAN //
// //
//////////////////////////////////////////////////////////////////////////////////////////
struct DEV_Valve : Service::Valve { // ON/OFF VALVE
int valvePin;
int hsOverridePin;
int overridePin;
int activatePin;
int overridePinStatus = 0;
int main_state = 0;
const char *displayOnly = "6 Drain Fountain";
const char *valveName;
VALVE *vValve;
SpanCharacteristic *active = new Characteristic::Active(0);
SpanCharacteristic *inUse = new Characteristic::InUse(0);
SpanCharacteristic *enabled = new Characteristic::IsConfigured(1, true);
SpanCharacteristic *setDuration;
SpanCharacteristic *remainingDuration = new Characteristic::RemainingDuration(0);
SpanCharacteristic *name;
// Constructor for Valves override-able
DEV_Valve(const char *vName, int valvePin, int overridePin, int HSoverridePin, int activatePin, int duration)
: Service::Valve() {
new Characteristic::ValveType(1);
name = new Characteristic::ConfiguredName(vName,true); // This Characteristic was introduced for TV Services, but works well here
setDuration = new Characteristic::SetDuration(duration);
enabled->addPerms(PW);
valveName = vName; // Adding "PW" to the IsConfigured Characteristic allws for enabling/disabling valves
Serial.print("Configuring Valve"); // initialization message
Serial.print("\n");
new SpanButton(overridePin);
new SpanButton(activatePin);
this->valvePin = valvePin;
this->hsOverridePin = HSoverridePin;
this->overridePin = overridePin;
this->activatePin = activatePin;
this->overridePinStatus = 0;
}
// Constructor for Valves not override-able from Main Override Pin
DEV_Valve(const char *valveName, int valvePin, int activatePin, int duration)
: Service::Valve() {
new Characteristic::ValveType(1);
name = new Characteristic::ConfiguredName(valveName,true); // This Characteristic was introduced for TV Services, but works well here
setDuration = new Characteristic::SetDuration(duration);
enabled->addPerms(PW); // Adding "PW" to the IsConfigured Characteristic allws for enabling/disabling valves
Serial.print("Configuring Valve"); // initialization message
Serial.print("\n");
new SpanButton(activatePin);
this->valvePin = valvePin;
this->activatePin = activatePin;
this->overridePinStatus = 1;
}
DEV_Valve(const char *vName, int valvePin, int overridePin, int HSoverridePin, int activatePin, int duration, VALVE vvalve)
: Service::Valve() {
new Characteristic::ValveType(1);
name = new Characteristic::ConfiguredName(vName,true); // This Characteristic was introduced for TV Services, but works well here
setDuration = new Characteristic::SetDuration(duration);
enabled->addPerms(PW);
valveName = vName; // Adding "PW" to the IsConfigured Characteristic allws for enabling/disabling valves
Serial.print("Configuring Valve"); // initialization message
Serial.print("\n");
new SpanButton(overridePin);
new SpanButton(activatePin);
this->valvePin = valvePin;
this->hsOverridePin = HSoverridePin;
this->overridePin = overridePin;
this->activatePin = activatePin;
this->overridePinStatus = 0;
}
boolean update() override {
if (enabled->updated()) {
if (enabled->getNewVal()) {
Serial.printf("%s valve ENABLED\n", name->getString());
} else {
Serial.printf("%s valve DISABLED\n", name->getString());
if (active->getVal()) {
active->setVal(0);
inUse->setVal(0);
remainingDuration->setVal(0);
Serial.printf("%s is CLOSING\n", name->getString());
}
}
}
if (active->updated()) {
if (active->getNewVal()) {
Serial.printf("%s valve is OPEN\n", name->getString());
remainingDuration->setVal(setDuration->getVal());
HS_Sprinkler_Status += 1;
inUse->setVal(1);
digitalWrite(valvePin, HIGH);
} else {
Serial.printf("%s valve is CLOSED\n", name->getString());
remainingDuration->setVal(0);
HS_Sprinkler_Status -= 1;
inUse->setVal(0);
digitalWrite(valvePin, LOW);
}
}
return (true);
}
void button(int pin, int pressType) override {
LOG1("Found button press on pin: "); // always a good idea to log messages
LOG1(pin);
LOG1(" type: ");
LOG1(pressType == SpanButton::LONG ? "LONG" : (pressType == SpanButton::SINGLE) ? "SINGLE" : "DOUBLE");
LOG1("\n");
int newLevel;
if (overridePinStatus == 1 && pin == activatePin) {
if (pressType == SpanButton::SINGLE) { // if a SINGLE press of the power button...
active->setVal(1 - active->getVal()); // ...toggle the value of the power Characteristic
inUse->setVal(1 - inUse->getVal());
Serial.printf("%s override and statement", name->getString());
}
}
if (pin == overridePin) {
if (pressType == SpanButton::SINGLE) {
if (active->getVal() == 1) {
active->setVal(0);
inUse->setVal(0);
digitalWrite(valvePin, LOW);
HS_Sprinkler_Status -= 1;
remainingDuration->setVal(0);
}
overridePinStatus = !overridePinStatus;
}
}
}
void loop() override {
if (valveName != displayOnly) {
if (active->getVal()) {
int remainingTime = (setDuration->getVal() - active->timeVal() / 1000);
if (remainingTime <= 0) {
//Serial.printf("%s valve is CLOSED (%d-second timer is complete)\n", name->getString(), setDuration->getVal());
active->setVal(0);
inUse->setVal(0);
digitalWrite(valvePin, LOW);
HS_Sprinkler_Status -= 1;
remainingDuration->setVal(0);
} else if (remainingTime < remainingDuration->getVal()) {
remainingDuration->setVal(remainingTime, false);
}
}
if (digitalRead(valvePin) == 1 && !active->getVal()){
active->setVal(1);
inUse->setVal(1);
remainingDuration->setVal(setDuration->getVal());
} else if(digitalRead(valvePin) == 0 && active->getVal()){
active->setVal(0);
inUse->setVal(0);
remainingDuration->setVal(0);
}
}
//this->name->setVal( name+"vValve->cyclesToday,true);
}
};
//////////////////////////////////////////////////////////////////////////////////////////
// //
// DEV VALVE LATCHING- HOMESPAN //
// //
//////////////////////////////////////////////////////////////////////////////////////////
struct DEV_Valve_Latching : Service::Valve { // ON/OFF VALVE
int valvePin;
int hsOverridePin;
int overridePin;
int activatePin;
int overridePinStatus = 0;
int main_state = 0;
int sensorPin;
int _maxDuration;
const char *displayOnly = "6 Drain Fountain";
const char *valveName;
SpanCharacteristic *active = new Characteristic::Active(0);
SpanCharacteristic *inUse = new Characteristic::InUse(0);
SpanCharacteristic *enabled = new Characteristic::IsConfigured(1, true);
SpanCharacteristic *setDuration;
SpanCharacteristic *remainingDuration = new Characteristic::RemainingDuration(0);
SpanCharacteristic *name;
// Constructor for Valves override-able
DEV_Valve_Latching(const char *vName, int valvePin, int overridePin, int HSoverridePin, int activatePin, int sensor_Pin, int MaxDuration)
: Service::Valve() {
new Characteristic::ValveType(1);
name = new Characteristic::ConfiguredName(vName,true); // This Characteristic was introduced for TV Services, but works well here
_maxDuration = MaxDuration / 1000;
setDuration = new Characteristic::SetDuration(_maxDuration);
enabled->addPerms(PW);
valveName = vName; // Adding "PW" to the IsConfigured Characteristic allws for enabling/disabling valves
Serial.print("Configuring Valve"); // initialization message
Serial.print("\n");
new SpanButton(overridePin);
new SpanButton(activatePin);
this->valvePin = valvePin;
this->hsOverridePin = HSoverridePin;
this->overridePin = overridePin;
this->activatePin = activatePin;
this->sensorPin = sensor_Pin;
this->overridePinStatus = 0;
}
boolean update() override {
if (enabled->updated()) {
if (enabled->getNewVal()) {
Serial.printf("%s valve ENABLED\n", name->getString());
} else {
Serial.printf("%s valve DISABLED\n", name->getString());
if (active->getVal()) {
active->setVal(0);
inUse->setVal(0);
remainingDuration->setVal(0);
Serial.printf("%s is CLOSING\n", name->getString());
}
}
}
if (active->updated()) {
if (active->getNewVal()) {
Serial.printf("%s valve is OPEN\n", name->getString());
remainingDuration->setVal(setDuration->getVal());
HS_Sprinkler_Status += 1;
inUse->setVal(1);
digitalWrite(valvePin, HIGH);
} else {
Serial.printf("%s valve is CLOSED\n", name->getString());
remainingDuration->setVal(0);
HS_Sprinkler_Status -= 1;
inUse->setVal(0);
digitalWrite(valvePin, LOW);
}
}
return (true);
}
void button(int pin, int pressType) override {
LOG1("Found button press on pin: "); // always a good idea to log messages
LOG1(pin);
LOG1(" type: ");
LOG1(pressType == SpanButton::LONG ? "LONG" : (pressType == SpanButton::SINGLE) ? "SINGLE" : "DOUBLE");
LOG1("\n");
int newLevel;
if (overridePinStatus == 1 && pin == activatePin) {
if (pressType == SpanButton::SINGLE) { // if a SINGLE press of the power button...
active->setVal(1 - active->getVal()); // ...toggle the value of the power Characteristic
inUse->setVal(1 - inUse->getVal());
Serial.printf("%s override and statement", name->getString());
}
}
if (pin == overridePin) {
if (pressType == SpanButton::SINGLE) {
if (active->getVal() == 1) {
active->setVal(0);
inUse->setVal(0);
digitalWrite(valvePin, LOW);
HS_Sprinkler_Status -= 1;
remainingDuration->setVal(0);
}
overridePinStatus = !overridePinStatus;
}
}
}
void loop() override {
if (valveName != displayOnly) {
if (active->getVal()) {
int remainingTime = (setDuration->getVal() - active->timeVal() / 1000);
if (remainingTime <= 0) {
active->setVal(0);
inUse->setVal(0);
digitalWrite(valvePin, LOW);
HS_Sprinkler_Status -= 1;
remainingDuration->setVal(0);
} else if (remainingTime < remainingDuration->getVal()) {
remainingDuration->setVal(remainingTime, false);
}
}
if (digitalRead(valvePin) == 1 && !active->getVal()){
active->setVal(1);
inUse->setVal(1);
remainingDuration->setVal(setDuration->getVal());
} else if(digitalRead(valvePin) == 0 && active->getVal()){
active->setVal(0);
inUse->setVal(0);
remainingDuration->setVal(0);
}
}
//this->name->setVal( name+"vValve->cyclesToday,true);
}
};
//////////////////////////////////////////////////////////////////////////////////////////
// //
// DEV SPRINKLER - HOMESPAN //
// //
//////////////////////////////////////////////////////////////////////////////////////////
struct DEV_Sprinkler : Service::IrrigationSystem {
// HomeKit requires this Characteristic, but it has no effect in Home App
SpanCharacteristic *active = new Characteristic::Active(0);
// HomeKit requires this Characteristic, but it is mostly for information purposes in home app
SpanCharacteristic *programMode = new Characteristic::ProgramMode(0);
// // // // // // // // // // // // // // // // // // // // // //
// NOTE: According to HAP-R2, the In Use Characteristic is also required for the //
// Irrigation System Service. However, adding this Characteristic seems to break //
// the Home App. Seems that the HAP-R2 spec is out of date and that the Home App //
// determines whether the Irrigation System is In Use simply by noting that one or //
// more linked Valves are In Use. Recommendation: Do NOT instatiate //
// Characteristic::InUse for the Irrigation Service. //
// // // // // // // // // // // // // // // // // // // // // //
};
//////////////////////////////////////////////////////////////////////////////////////////
// //
// DEV BUTTON - HOMESPAN //
// //
//////////////////////////////////////////////////////////////////////////////////////////
struct DEV_Button : Service::Switch {
int _pin;
String _name;
SpanCharacteristic *on = new Characteristic::On(0);
SpanCharacteristic *name;
DEV_Button(const char *devButtonName, int devButtonPin)
: Service::Switch() {
_name = devButtonName;
_pin = devButtonPin;
new SpanButton(_pin);
}
boolean update() override{
if(on->getNewVal()){
HS_Loop_Override_Status = 1;
Loop_Override_Button.toggleState();
Serial.println("Main Loop Override Activated HomeKit");
Serial.println("");
} else {
HS_Loop_Override_Status = 0;
Loop_Override_Button.reset();
Serial.println("Main Loop Override Deactivated HomeKit");
Serial.println("");
}
return true;
}
void button(int pin, int pressType) override {
if (pressType == SpanButton::SINGLE) { // if a SINGLE press of the power button...
on->setVal(1 - on->getVal()); // ...toggle the value of the power Characteristic
if(on->getVal()){
Serial.print(_name);
Serial.println(" Activated Manually");
} else {
Serial.print(_name);
Serial.println(" Deactivated Manyally");
}
}
}
};
//////////////////////////////////////////////////////////////////////////////////////////
// //
// DEV SENSOR - HOMESPAN //
// //
//////////////////////////////////////////////////////////////////////////////////////////
struct DEV_HumiditySensor : Service::HumiditySensor {
int sensorPin;
int calibratePin;
int _dry = Dry;
int _wet = Wet;
int _value;
int _reading;
// reference to the Current Humidity Characteristic
SpanCharacteristic *hum;
SpanCharacteristic *fault;
SpanCharacteristic *name;
DEV_HumiditySensor()
: Service::HumiditySensor() {
hum->setRange(-2, 600, 1);
}
// constructor() method
DEV_HumiditySensor(const char *sensorName, int sensorPin, int InputCalibratePin, int calibratedDry, int calibratedWet)
: Service::HumiditySensor() {
// instantiate the Current Temperature Characteristic
hum = new Characteristic::CurrentRelativeHumidity(0);
fault = new Characteristic::StatusFault(0);
// This Characteristic was introduced for TV Services, but works well here
name = new Characteristic::ConfiguredName(sensorName, true);
new SpanButton(InputCalibratePin);
this->sensorPin = sensorPin;
this->calibratePin = InputCalibratePin;
this->_dry = calibratedDry;
this->_wet = calibratedWet;
hum->setUnit("percentage");
hum->setRange(-6, 600, 1);
// initialization message
Serial.print("Configuring Humidity Sensor");
Serial.print("\n");
} // end constructoR
void button(int pin, int pressType) override {
LOG1("Found button press on pin: "); // always a good idea to log messages
LOG1(pin);
LOG1(" type: ");
LOG1(pressType == SpanButton::LONG ? "LONG" : (pressType == SpanButton::SINGLE) ? "SINGLE" : "DOUBLE");
LOG1("\n");
int newLevel;
if (pin == calibratePin) {
if (pressType == SpanButton::SINGLE) {
_reading = analogRead(sensorPin);
Serial.print("Calibrate HomeSpan ");
Serial.print(name->getString());
Serial.print("_ANALOG ");
Serial.print(" = ");
Serial.println(_reading);
if (_reading <= ConnectionError + Mask_Variance) {
fault->setVal(1, true);
} else {
fault->setVal(0, true);
this->_dry = _reading;
this->_wet = _dry - 1950;
}
}
}
}
void loop() {
// the humidity refreshes every 10 seconds by the elapsed time
if (hum->timeVal() > HomeSpan_Loop_Rate) {
// read humidity from sensor dht22
_reading = analogRead(sensorPin);
_value = map(_reading, _dry, _wet, MAP_min, MAP_max);
/*Serial.print("HomeSpan ");
Serial.print(name->getString());
Serial.print("_MAP ");
Serial.print(" = ");
Serial.println(_value);*//*
if (_value > MAP_max + Mask_Variance) {
fault->setVal(1);
hum->setVal(-6, true);
} else {
if (_value >= 0 && _value <= 100) {
fault->setVal(0);
hum->setVal(_value*6, true);
}
}
}
} // loop
};
//////////////////////////////////////////////////////////////////////////////////////////
// //
// DEV SENSOR DIGITAL - HOMESPAN //
// //
//////////////////////////////////////////////////////////////////////////////////////////
struct DEV_HumiditySensorDigital : Service::HumiditySensor {
int sensorPin;
int _dry = 0;
int _wet = 1;
int _value;
int _reading;
// reference to the Current Humidity Characteristic
SpanCharacteristic *hum;
SpanCharacteristic *fault;
SpanCharacteristic *name;
DEV_HumiditySensorDigital()
: Service::HumiditySensor() {
hum->setUnit("percentage");
hum->setRange(-6, 600, 1);
}
// constructor() method
DEV_HumiditySensorDigital(const char *sensorName, int sensorPin)
: Service::HumiditySensor() {
// instantiate the Current Temperature Characteristic
hum = new Characteristic::CurrentRelativeHumidity(0);
fault = new Characteristic::StatusFault(0);
name = new Characteristic::ConfiguredName(sensorName, true); // This Characteristic was introduced for TV Services, but works well here
this->sensorPin = sensorPin;
hum->setUnit("percentage");
hum->setRange(-6, 600, 1);
// initialization message
Serial.print("Configuring Humidity Sensor");
Serial.print("\n");
} // end constructor
void loop() {
// the humidity refreshes every 10 seconds by the elapsed time
if (hum->timeVal() > HomeSpan_Loop_Rate) {
// read humidity from sensor dht22
int humidity = digitalRead(sensorPin);
/*Serial.print("HomeSpan ");
Serial.print(name->getString());
Serial.print("_MAP ");
Serial.print(" = ");
Serial.println(humidity);*//*
if (humidity > MAP_max + Mask_Variance) {
fault->setVal(1);
hum->setVal(-6);
} else {
if (humidity == 1) {
fault->setVal(0);
hum->setVal(0, true);
} else if (humidity == 0) {
fault->setVal(0);
hum->setVal(100*6, true);
}
}
}
} // loop
};
*/
//////////////////////////////////////////////////////////////////////////////////////////
// //
// MAIN PROGRAM STRUCT DECLARATIONS //
// //
//////////////////////////////////////////////////////////////////////////////////////////
// //
// CREATE LEDs //
//////////////////////////////////////////////////////////////////////////////////////////
// __________________________________________________________________ // ____ WIRE ____ //
LED(Main_Override_LED); // Red //
LED(Water_All_Planters_LED); // Green //
LED(Calibrate_Sensors_LED); // WhiTe //
LED(Fill_Fountain_LED); // Blue //
LED(Loop_Override_LED); // Yellow //
LED(HomeSpan_Override_LED); // Orange //
// ------------------------------------------------------------------ // -------------- //
//////////////////////////////////////////////////////////////////////////////////////////
// //
// CREATE SENSORS //
//////////////////////////////////////////////////////////////////////////////////////////
// _________________________________________________ // ____ DOTS ____ | ____ WIRE ____ //
SENSOR(Fountain_Planters_Top_Sensor); // Red | Brown //
SENSOR(Fountain_Planters_Bottom_Sensor); // Green | Orange //
SENSOR(Porch_Planters_Sensor); // Green Green | Yellow //
SENSOR(Maple_Planter_Sensor); // Red Red | Greeen //
SENSOR(Lawn_Planters_Left_Sensor); // Blue Blue | Blue //
SENSOR(Lawn_Planters_Right_Sensor); // Yellow Yellow | Yellow //
DIGITAL_SENSOR(Fill_Fountain_Sensor); // Blue | White //
// ------------------------------------------------- // ------------------------------- //
//////////////////////////////////////////////////////////////////////////////////////////
// //
// CREATE VALVES //
//////////////////////////////////////////////////////////////////////////////////////////
// _____________________________ // _________________________________ // ____ WIRE ____ //
VALVE(Fountain_Planters_Valve); // // White //
VALVE(Porch_Planters_Valve); // // Maroon //
VALVE(Maple_Planter_Valve); // // Purple //
VALVE(Lawn_Planters_Valve); // // Yellow //
VALVE(Fill_Fountain_Valve); // // Orange //
//VALVE(Drain_Fountain_Valve); // // Black // - NOTE THIS VALVE IS NOT CURRENTLY BEING USED | THEREFORE THIS PIN CAN BE USED AS AN OPEN GPIO FOR OTHER NEEDS
// ----------------------------- // --------------------------------- // -------------- //
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// //
// SETUP //
// //
//////////////////////////////////////////////////////////////////////////////////////////
void setup() {
Serial.begin(9600);
Serial.println("Setup || Initializing ShiftRegister");
// initializing shift register pins
pinMode(ledRegisterData_pin, OUTPUT);
pinMode(ledRegisterClock_pin, OUTPUT);
pinMode(ledRegisterLatch_pin, OUTPUT);
Serial.println("Setup || Initializing Sensors");
// initializing sensor pins
//pinMode(fountain_sensor_pin, INPUT_PULLUP);
Fountain_Planters_Top_Sensor.initialize(fountain_planters_top_sensor_pin, "fountain_planters_top_sensor");
Fountain_Planters_Bottom_Sensor.initialize(fountain_planters_bottom_sensor_pin, "fountain_planters_bottom_sensor");
Porch_Planters_Sensor.initialize(porch_planters_sensor_pin, "porch_planters_sensor");
Maple_Planter_Sensor.initialize(maple_sensor_pin, "maple_planter_sensor");
Lawn_Planters_Left_Sensor.initialize(lawn_planters_right_sensor_pin, "lawn_planters_right_sensor");
Lawn_Planters_Right_Sensor.initialize(lawn_planters_left_sensor_pin, "lawn_planters_left_sensor");
Fill_Fountain_Sensor.initialize(fountain_sensor_pin, "fill_fountain_sensor");
Serial.println("Setup || Initializing Valves");
// initializing valve pins
Fountain_Planters_Valve.initialize(fountain_planters_valve_pin, "Fountain_Planters_Valve");
Porch_Planters_Valve.initialize(porch_planters_valve_pin, "Porch_Planters_Valve");
Maple_Planter_Valve.initialize(maple_valve_pin, "Maple_Planter_Valve");
Lawn_Planters_Valve.initialize(lawn_planters_valve_pin, "Lawn_Planters_Valve");
Fill_Fountain_Valve.initialize(fill_fountain_valve_pin, "Fill_Fountain_Valve");
//Drain_Fountain_Valve.initialize(drain_fountain_valve_pin, "Drain_Fountain_Valve");
Serial.println("Setup || Initializing LEDs");
// initializing LED pins
Main_Override_LED.initialize(7, "Main_Override_LED");
Water_All_Planters_LED.initialize(6, "Water_All_Planters_LED");
Fill_Fountain_LED.initialize(5, "Fill_Fountain_LED");
Calibrate_Sensors_LED.initialize(4, "Calibrate_Sensors_LED");
Loop_Override_LED.initialize(3, "Loop_Override_LED");
HomeSpan_Override_LED.initialize(2, "HomeSpan_Override_LED");
Serial.println("Setup || Initializing HomeSpan");
/*
// initializing homespan
homeSpan.enableOTA();
homeSpan.setControlPin(homespan_override_button_pin);
homeSpan.setStatusPin(homespan_input_pin);
homeSpan.setStatusAutoOff(60); // in seconds
homeSpan.begin(Category::Sprinklers, "Porch Irrigation");
new SpanAccessory();
new Service::AccessoryInformation();
new Characteristic::Identify();
(new DEV_Sprinkler())
->addLink((new DEV_Valve("1 Fountain Planters", fountain_planters_valve_pin, main_override_button_pin, homespan_override_button_pin, water_all_planters_button_pin, valveDuration))
->addLink(new DEV_HumiditySensor("1 Top Fountain Planter", fountain_planters_top_sensor_pin, calibrate_sensors_button_pin, Fountain_Planters_Top_Sensor._dry, Fountain_Planters_Top_Sensor._wet))
->addLink(new DEV_HumiditySensor("1 Bottom Fountain Planter", fountain_planters_bottom_sensor_pin, calibrate_sensors_button_pin, Fountain_Planters_Bottom_Sensor._dry, Fountain_Planters_Bottom_Sensor._wet)))
->addLink((new DEV_Valve("2 Porch Planters", porch_planters_valve_pin, main_override_button_pin, homespan_override_button_pin, water_all_planters_button_pin, valveDuration*2))
->addLink(new DEV_HumiditySensor("2 Porch Planters", porch_planters_sensor_pin, calibrate_sensors_button_pin, Porch_Planters_Sensor._dry, Porch_Planters_Sensor._wet)))
->addLink((new DEV_Valve("3 Maple Planter", maple_valve_pin, main_override_button_pin, homespan_override_button_pin, water_all_planters_button_pin, valveDuration*2))
->addLink(new DEV_HumiditySensor("3 Maple Planter", maple_sensor_pin, calibrate_sensors_button_pin, Maple_Planter_Sensor._dry, Maple_Planter_Sensor._wet)))
->addLink((new DEV_Valve("4 Lawn Planters", lawn_planters_valve_pin, main_override_button_pin, homespan_override_button_pin, water_all_planters_button_pin, valveDuration*2))
->addLink(new DEV_HumiditySensor("4 L Lawn Planter", lawn_planters_left_sensor_pin, calibrate_sensors_button_pin, Lawn_Planters_Left_Sensor._dry, Lawn_Planters_Left_Sensor._wet))
->addLink(new DEV_HumiditySensor("4 R Lawn Planter", lawn_planters_right_sensor_pin, calibrate_sensors_button_pin, Lawn_Planters_Right_Sensor._dry, Lawn_Planters_Right_Sensor._wet)))
->addLink((new DEV_Valve_Latching("5 Fill Fountain", fill_fountain_valve_pin, main_override_button_pin, homespan_override_button_pin, fill_fountain_button_pin, fountain_sensor_pin, MaxFoutainFillTime))
->addLink(new DEV_HumiditySensorDigital("5 Foutain Fill Level", fountain_sensor_pin)));
new SpanAccessory();
new Service::AccessoryInformation();
new Characteristic::Identify();
new DEV_Button("Main Loop Override",loop_override_button_pin);
*/
Serial.println("finished homespan setup");
}
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// //
// MAIN PROGRAM FUNCTION DEFINITIONS //
// //
//////////////////////////////////////////////////////////////////////////////////////////
// allows serial output of bit variables for debugging purposes
void printByte(byte rDir) {
for (int8_t aBit = 7; aBit >= 0; aBit--) {
Serial.print(bitRead(rDir, aBit) ? '1' : '0');
}
Serial.println("");
}
// raw mapped input from sensors - check dry function
bool check_dry(int Sensor_Value) {
if (Sensor_Value <= MAP_min + Mask_Variance) {
return true;
} else {
return false;
}
}
void debug_variable(int value, String varName) {
Serial.print(varName);
Serial.print(" = ");
Serial.println(value);
}
int HSDELAYTIMER = 0;
unsigned long loopTimer = millis();
unsigned long fountain_empty_timer = millis();
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// //
// MAIN FOR LOOP //
// //
//////////////////////////////////////////////////////////////////////////////////////////
void loop() {
if (debugLevel == '1234') {
Serial.println("0 off");
Serial.println("1 ");
Serial.println("2 led status value");
Serial.println("3 golbal override variable states");
Serial.println("4 button states");
}
if (debugLevel == 2) {
Serial.print("LedStatus Value = ");
printByte(ledStatus);
}
if (debugLevel == 3) {
Serial.print("Main_Override_State = ");
Serial.println(Main_Override_State);
Serial.print("HS_Sprinkler_Status = ");
Serial.println(HS_Sprinkler_Status);
}
//////////////////////////////////////////////////////////////////////////////////////////
// GLOBAL OVERRIDE //
//////////////////////////////////////////////////////////////////////////////////////////
if (Main_Override_Button.pushed()) {
if (Main_Override_State == 0) {
//debugLevel = Serial.parseInt();
// setting LED state
if (debugLevel == 4) {
Serial.println("Main Override Engaged");
}
// run homespan once to allow valves to reset
do {
//homeSpan.poll();
Serial.println("homeSpan.poll() Global Override Buffer");
HSDELAYTIMER++;
} while (HSDELAYTIMER < HSResetDelay);
HSDELAYTIMER = 0;
HS_Sprinkler_Status = 0;
// closing all valves
Fountain_Planters_Valve.close();
Porch_Planters_Valve.close();
Maple_Planter_Valve.close();
Lawn_Planters_Valve.close();
Fill_Fountain_Valve.close();
//Drain_Fountain_Valve.close();
// resetting buttons
HomeSpan_Override_Button.reset();
Water_All_Planters_Button.reset();
Fill_Fountain_Button.reset();
Calibrate_Sensors_Button.reset();
Main_Override_LED.on();
Main_Override_State = 1;
//bot.sendMessage(CHAT_ID, "Global Override Active", "");
}
// blink homespan & loop LEDs indicating inactive
HomeSpan_Override_LED.blink();
Loop_Override_LED.blink();
} else {
if (Main_Override_State == 1) {
HomeSpan_Override_LED.off();
Loop_Override_LED.off();
// setting LED state
Main_Override_LED.off();
Main_Override_Button.reset();
Main_Override_State = 0;
//bot.sendMessage(CHAT_ID, "Global Override Off", "");
//////////////////////////////////////////////////////////////////////////////////////////
// Water All & Fill Buttons, LEDs, & Valves - RESET //
//////////////////////////////////////////////////////////////////////////////////////////
// reset Water All Planters Button, LED, and Valves
if (Water_All_Planters_LED.state == 1) {
Water_All_Planters_Button.reset();
Water_All_Planters_LED.off();
Fountain_Planters_Valve.close();
Porch_Planters_Valve.close();
Maple_Planter_Valve.close();
Lawn_Planters_Valve.close();
if (debugLevel == 4) {
Serial.println("Water All Planters Off");
}
}
// reset Fill Fountain LED and Valve
if (Fill_Fountain_LED.state == 1) {
Fill_Fountain_Button.reset();
Fill_Fountain_LED.off();
Fill_Fountain_Valve.close();
if (debugLevel == 4) {
Serial.println("Fill Fountain Off");
}
}
if (debugLevel == 4) {
Serial.println("Main Override Off");
}
}
//////////////////////////////////////////////////////////////////////////////////////////
// HOMESPAN OVERRIDE //
//////////////////////////////////////////////////////////////////////////////////////////
if (HomeSpan_Override_Button.pushed()) {
if (HomeSpan_Override_State == 0) {
HomeSpan_Override_State = 1;
//bot.sendMessage(CHAT_ID, "HomeKit Override Active", "");
if (debugLevel == 4) {
Serial.println("HomeSpan Override Engaged");
}
// closing all valves
Fountain_Planters_Valve.close();
Porch_Planters_Valve.close();
Maple_Planter_Valve.close();
Lawn_Planters_Valve.close();
Fill_Fountain_Valve.close();
// resetting buttons
Water_All_Planters_Button.reset();
Fill_Fountain_Button.reset();
}
HomeSpan_Override_LED.blink();
} else {
if (HomeSpan_Override_State == 1) {
// setting LED state
HomeSpan_Override_Button.reset();
HomeSpan_Override_LED.off();
HomeSpan_Override_State = 0;
//bot.sendMessage(CHAT_ID, "HomeKit Override Off", "");
if (debugLevel == 4) {
Serial.println("HomeSpan Override Off");
}
}
// run homeSpan
//homeSpan.poll();
//Serial.println("homeSpan.poll()");
}
//////////////////////////////////////////////////////////////////////////////////////////
// HomeSpan Active //
//////////////////////////////////////////////////////////////////////////////////////////
if (HS_Sprinkler_Status > 0) {
if (!HomeSpan_Override_LED.state) {
HomeSpan_Override_LED.on();
}
Loop_Override_LED.blink();
}
//////////////////////////////////////////////////////////////////////////////////////////
// HomeSpan Not Active //
//////////////////////////////////////////////////////////////////////////////////////////
if (HS_Sprinkler_Status == 0) {
if (HomeSpan_Override_LED.state == 1) {
HomeSpan_Override_LED.off();
Loop_Override_LED.off();
}
/////////////////////////////////////////////////////////////////////////////////////////
// MAIN LOOP OVERRIDE //
/////////////////////////////////////////////////////////////////////////////////////////
if(Loop_Override_Button.pushed()){
if (Loop_Override_State == 0) {
Loop_Override_State = 1;
//bot.sendMessage(CHAT_ID, "Main Override Active", "");
if (debugLevel == 4) {
Serial.println("Loop Override Engaged");
}
// closing all valves
Fountain_Planters_Valve.close();
Porch_Planters_Valve.close();
Maple_Planter_Valve.close();
Lawn_Planters_Valve.close();
Fill_Fountain_Valve.close();
// resetting buttons
Water_All_Planters_Button.reset();
Fill_Fountain_Button.reset();
}
Loop_Override_LED.blink();
} else {
if (Loop_Override_State == 1) {
Loop_Override_LED.off();
Loop_Override_Button.reset();
Loop_Override_State = 0;
//bot.sendMessage(CHAT_ID, "Main Override Off", "");
if (debugLevel == 4) {
Serial.println("Loop Override Off");
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CHECK VALVE TIMERS - MAIN PROGRAM //
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
if(millis() - Fountain_Planters_Valve._valveTimer > MaxRunTime){
Fountain_Planters_Valve.close();
}
if(millis() - Porch_Planters_Valve._valveTimer > MaxRunTime*2){
Porch_Planters_Valve.close();
}
if(millis() - Maple_Planter_Valve._valveTimer > MaxRunTime){
Maple_Planter_Valve.close();
}
if(millis() - Lawn_Planters_Valve._valveTimer > MaxRunTime*2){
Lawn_Planters_Valve.close();
}
if(millis() - Fill_Fountain_Valve._valveTimer > MaxFoutainFillTime){
Fill_Fountain_Valve.close();
}
if (millis() - loopTimer > Loop_Rate) {
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Check Sensor Saturation Levels and Water if needed - FOUNTAIN PLANTERS - MAIN PROGRAM //
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
//debug_variable(analogRead(fountain_planters_top_sensor_pin), "fountain_planters_top_sensor_Analog");
//debug_variable(Fountain_Planters_Top_Sensor.getValue(), "fountain_planters_top_sensor_OBJECT");
//debug_variable(Fountain_Planters_Bottom_Sensor.getValue(), "fountain_planters_bottom_sensor_value_OBJECT");
if (Fountain_Planters_Top_Sensor._error == false && Fountain_Planters_Bottom_Sensor._error == false) {
if (Fountain_Planters_Top_Sensor.isDry() || Fountain_Planters_Bottom_Sensor.isDry()) {
if (Fountain_Planters_Valve.state == 0){
if(Fountain_Planters_Valve.cyclesToday <= MaxCyclesDaily){
Fountain_Planters_Valve.open();
} else {
Serial.println("fountain planters have passed the allowable number of activations for 24 hrs");
}
}
} else {
if (Fountain_Planters_Valve.state == 1){
Fountain_Planters_Valve.close();
}
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Check Sensor Saturation Levels and water if needed - PORCH PLANTERS - MAIN PROGRAM //
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
//debug_variable(Porch_Planters_Sensor.getValue(), "porch_planters_sensor_OBJECT");
if (Porch_Planters_Sensor._error == false) {
if (Porch_Planters_Sensor.isDry()) {
if (Porch_Planters_Valve.state == 0) {
if (Porch_Planters_Valve.cyclesToday <= MaxCyclesDaily){
Porch_Planters_Valve.open();
} else {
Serial.println("porch planters has passed the allowable number of activations for 24 hrs");
}
}
} else {
if (Porch_Planters_Valve.state == 1) {
Porch_Planters_Valve.close();
}
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Check Sensor Saturation Levels and water if needed - MAPLE PLANTERS - MAIN PROGRAM //
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
//debug_variable(Maple_Planter_Sensor.getValue(), "maple_platgner_sensor_OBJECT");
if (Maple_Planter_Sensor._error == false) {
if (Maple_Planter_Sensor.isDry()) {
if (Maple_Planter_Valve.state == 0){
if(Maple_Planter_Valve.cyclesToday <= MaxCyclesDaily){
Maple_Planter_Valve.open();
} else {
Serial.println("maple planter has passed the allowable number of activations for 24 hrs");
}
}
} else {
if (Maple_Planter_Valve.state == 1){
Maple_Planter_Valve.close();
}
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Check Sensor Saturation Levels and water if needed - LAWN PLANTERS - MAIN PROGRAM //
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
//debug_variable(Lawn_Planters_Left_Sensor.getValue(), "lawn_planters_left_sensor_value_OBJECT");
//debug_variable(Lawn_Planters_Right_Sensor.getValue(), "lawn_planters_right_sensor_value_OBJECT");
if (Lawn_Planters_Left_Sensor._error == false && Lawn_Planters_Right_Sensor._error == false) {
if (Lawn_Planters_Left_Sensor.isDry() || Lawn_Planters_Right_Sensor.isDry()) {
if (Lawn_Planters_Valve.state == 0){
if(Lawn_Planters_Valve.cyclesToday <= MaxCyclesDaily){
Lawn_Planters_Valve.open();
} else {
Serial.println("lawn planters have passed the allowable number of activations for 24 hrs");
}
}
} else {
if (Lawn_Planters_Valve.state == 1){
Lawn_Planters_Valve.close();
}
}
}
/*
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Check Sensor Saturation Levels and water if needed - FILL FOUNTAIN - MAIN PROGRAM //
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
fountain_sensor_value = digitalRead(fountain_sensor_pin);
//debug_variable(fountain_sensor_value, "fountain_sensor");
//Serial.println("");
//Serial.println("");
if (fountain_sensor_value == 1) {
if (Fill_Fountain_Valve.state == 0){
if (Fill_Fountain_Valve.cyclesToday <= MaxCyclesDaily){
Fill_Fountain_Valve.open();
} else {
Serial.println("fountain has passed the allowable number of activations for 24 hrs");
Fill_Fountain_Valve.close(); // added 6/15/24
}
}
} else {
if (Fill_Fountain_Valve.state == 1){
Fill_Fountain_Valve.close();
}
}*/
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Check Sensor Saturation Levels and water if needed - FILL FOUNTAIN - MAIN PROGRAM //
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
if (Fill_Fountain_Sensor.isDry()) {
if (Fill_Fountain_Valve.state == 0){
if (Fill_Fountain_Valve.cyclesToday <= MaxCyclesDaily){
Fill_Fountain_Valve.open();
} else {
Serial.println("fountain has passed the allowable number of activations for 24 hrs");
Fill_Fountain_Valve.close(); // added 6/15/24
}
}
} else {
if (Fill_Fountain_Valve.state == 1){
Fill_Fountain_Valve.close();
}
}
loopTimer = millis();
}
}
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////
// WATER ALL - BUTTON PUSHED //
//////////////////////////////////////////////////////////////////////////////////////////////////
if (Main_Override_Button.pushed() && Water_All_Planters_Button.pushed()) {
if (Water_All_Planters_LED.state == 0) {
Water_All_Planters_LED.on();
Fountain_Planters_Valve.open();
Porch_Planters_Valve.open();
Maple_Planter_Valve.open();
Lawn_Planters_Valve.open();
if (debugLevel == 4) {
Serial.println("Water All Planters Engaged");
}
}
} else {
if (Water_All_Planters_LED.state == 1) {
Water_All_Planters_LED.off();
Fountain_Planters_Valve.close();
Porch_Planters_Valve.close();
Maple_Planter_Valve.close();
Lawn_Planters_Valve.close();
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////
// FILL FOUNTAIN - BUTTON PUSHED //
//////////////////////////////////////////////////////////////////////////////////////////////////
if (Main_Override_Button.pushed() && Fill_Fountain_Button.pushed()) {
if (Fill_Fountain_LED.state == 0) {
Fill_Fountain_LED.on();
Fill_Fountain_Valve.open();
if (debugLevel == 4) {
Serial.println("Fill Fountain Engaged");
}
}
} else {
if (Fill_Fountain_LED.state == 1) {
Fill_Fountain_LED.off();
Fill_Fountain_Valve.close();
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////
// CALIBRATE SENSORS - BUTTON PUSHED //
//////////////////////////////////////////////////////////////////////////////////////////////////
if (Calibrate_Sensors_Button.pushed()) {
if (Calibrate_Sensors_LED.state == 0) {
Serial.println("Sensor Calibration Button Pressed");
Calibrate_Sensors_LED.on();
Fountain_Planters_Top_Sensor.calibrate();
Fountain_Planters_Bottom_Sensor.calibrate();
Porch_Planters_Sensor.calibrate();
Maple_Planter_Sensor.calibrate();
Lawn_Planters_Left_Sensor.calibrate();
Lawn_Planters_Right_Sensor.calibrate();
/*debug_variable(Fountain_Planters_Top_Sensor._dry, "Fountain_Planters_Top_Sensor._dry");
debug_variable(Fountain_Planters_Bottom_Sensor._dry, "Fountain_Planters_Bottom_Sensor._dry");
debug_variable(Porch_Planters_Sensor._dry, "Porch_Planters_Sensor._dry");
debug_variable(Maple_Planter_Sensor._dry, "Maple_Planter_Sensor._dry");
debug_variable(Lawn_Planters_Left_Sensor._dry, "Lawn_Planters_Left_Sensor._dry");
debug_variable(Lawn_Planters_Right_Sensor._dry, "Lawn_Planters_Right_Sensor._dry");
Serial.println("");
Serial.println("");*/
delay(10);
Calibrate_Sensors_LED.off();
//bot.sendMessage(CHAT_ID, "Sensors Calibrated", "");
}
Calibrate_Sensors_Button.reset();
}
delay(10);
}