Well it is getting close to time that I am going to have to water the yard more than once a month, so I finally decided to get back to work on the irrigation system. I had run into a problem with the pronto related to the number of particle.functions I was using. I guess there is a limit based on the ram use on the board. Well, I thought I was well within the limit, but I guess not. After going back and forth with technical support, they suggested that I reduce the number of particle.functions calls and use the string passed in to differentiate the call for the different zones, programs, etc. I have done it and it seems that it is working again. I am not going to attach the whole program like I did before, as it has some sensitive information in it, but I hope to make it easy enough to follow.
So, let’s get started. First we need some variables: (Sorry in advance the spacing is not great with these posts.
//PUT YOUR VARIABLES HERE
//The "relay" is for the partice interfaces that will need to be written in order to start the zones.
int relay[] = {D0, D1, D2, D3, D4, D5, D6};
bool disabled = true;
//The relayDelay is an array to hold the timers for each of the zones to run.int relayDelay[] = {480000, 480000, 480000, 480000, 480000, 480000};
bool relayIsOn[] = {false, false, false, false, false, false};
//aRelayIsOn is my way of checking to make sure no two zones run at once.
bool aRelayIsOn = false;
//The rain variables are used to store the rain totals that are used to determine if it needs to run.
int yesterdaysRain = 0;
int todaysRain = 0;
int totalRain = 0;
int rainChecked = false;
//This is a bit map to use for the days in which to run setting.
int daysToRun = 0;
//The time values are the times of the day to run each program
int Time1hour = 1;
int Time1min = 0;
int Time2hour = 4;
int Time2min = 0;
//Current Time
int now = 0;
Now let’s get to the part where set everything up, think of this as the constructor I guess.
void setup()
{
Serial.begin(9600);
//The get functions allow the web page/app to check to see what the current settings/state are.
Particle.function("getState", getState);
Particle.function("status", statusCheck);
Particle.function("getTime", getTime);
Particle.function("getRain", getRain);
//Enable/Disable the system remotely
Particle.function("setEnabled", setEnabled);
Particle.function("setDisabled", setDisabled);
//Start/Stop one of the relays(zones) of the system remotely
Particle.function("relayPulse", relayPulse);
//Run ever zone based on the configured values of the system
Particle.function("runAllZones", runAllZones);
//Get/Set the days that the programs run
Particle.function("setDay", setDay);
Particle.function("getDays", getDays);
//Set the run time for each of the zones where the string passed in has the "zone,minutes" (ie. "1,10" where 1 is zone 1 (1's based value)
Particle.function("setRunTime", setRunTime);
Particle.function("getRunTime", getRunTime);
//Get/Set the start time for each of the programs
Particle.function("setTime1", setTime1);
Particle.function("getTime1", getTime1);
Particle.function("setTime2", setTime2);
Particle.function("getTime2", getTime2);
//Set the pin for each of the relays(zones) on the particle board
pinMode(relay[0], OUTPUT);
pinMode(relay[1], OUTPUT);
pinMode(relay[2], OUTPUT);
pinMode(relay[3], OUTPUT);
pinMode(relay[4], OUTPUT);
pinMode(relay[5], OUTPUT);
pinMode(relay[6], OUTPUT);
//Set the initial value for each of the pins to HIGH
digitalWrite(relay[0],HIGH);
digitalWrite(relay[1],HIGH);
digitalWrite(relay[2],HIGH);
digitalWrite(relay[3],HIGH);
digitalWrite(relay[4],HIGH);
digitalWrite(relay[5],HIGH);
digitalWrite(relay[6],HIGH);
//Check the rain when the system is initialized so that we have a starting value.
totalRain = checkRain("today");
}
Now I’ll go through roughly based on the order in the setup function.
int getState(String command) {
if(disabled==true) {
return 0;
}
else {
return 1;
}
}
//Check if any of the zones are running
int statusCheck(String command) {
if(relayIsOn[0]==true) { return 1; }
else if(relayIsOn[1]==true) { return 2; }
else if(relayIsOn[2]==true) { return 3; }
else if(relayIsOn[3]==true) { return 4; }
else if(relayIsOn[4]==true) { return 5; }
else if(relayIsOn[5]==true) { return 6; }
else { return 0; }
}
/Get the current time after setting it to CST/CDT
int getTime(String command) {
int currTime = Time.hour()-6;
if (isDST) {
currTime++;
}
if (currTime < 0) {
currTime = currTime + 24;
}
return (currTime*100+Time.minute());
}
//Send notification to the user via a web email script.
void sendNotice(String command) {
RestClient clientNotif = RestClient("yourdomainhere");
String throwAwayResponse = "";
clientNotif.get("where you save a php script to send an email", &throwAwayResponse);
return; //No return needed on this call
}
//Weather information retrieval
int checkRain(String command) {
RestClient client = RestClient("yourdomainhere");
String weatherResponse = "";
int statusCode = client.get("where you save a php script to get rain fall totals for the day", &weatherResponse);
return weatherResponse.toInt();
}
int getRain(String command) {
return totalRain;
}
//Handle the disabled flag
int setDisabled(String command) {
disabled = true;
return 0;
}
int setEnabled(String command) {
disabled = false;
return 0;
}
//Methods to pulse the relays and turn on or off the zones manually.
int relayPulse(String relayStr) {
int relayNum = relayStr.toInt(); //the zone to run
if(disabled==true){
return 2; //oops you shouldn't be doing this
}
if(relayIsOn[relayNum]==true) { //It's already on, turn it off
aRelayIsOn = false;
relayIsOn[relayNum] = false;
digitalWrite(relay[relayNum],HIGH);
return 3;
}
//Another relay is on, you can't turn another one on
if(aRelayIsOn==true) {
return 1;
}
//Turn on the zone and run it for the set delay then turn it off
digitalWrite(relay[relayNum],LOW);
digitalWrite(relay[6],LOW);
aRelayIsOn = true;
relayIsOn[relayNum] = true;
delay(relayDelay[relayNum]);
digitalWrite(relay[relayNum],HIGH);
digitalWrite(relay[6],HIGH);
aRelayIsOn = false;
relayIsOn[relayNum] = false;
return 1;
}
//Days to run get/set
int getDays(String command) {
return daysToRun;
}
int setDay(String dayToMod) {
daysToRun = daysToRun + dayToMod.toInt();
return 0;
}
So this is one of the tricky sets. I need to pass in the zone and the delay time. So I used the parameter as a string and passed in multiple values that were comma delineated. This saved me an external function for each of the zones, like I had before.
//Update the delays based on input from the web interface
int setRunTime(String runTime) {
int relay, relayDelayTmp;
char szArgs[13];
runTime.toCharArray(szArgs, 12);
sscanf(szArgs, "%d,%d", &relay, &relayDelayTmp);
relayDelay[relay-1] = relayDelayTmp*1000*60;
return 0;
}
int getRunTime(String relay) {
return relayDelay[relay.toInt()-1]/1000/60;
}
And for the next few, I will probably clean them up and use arrays like the rest of the similar values.
//Time of day to run get/set
int getTime1(String command) {
return((Time1hour*100)+Time1min);
}
int setTime1(String TToMod) {
char inputStr[64];
TToMod.toCharArray(inputStr,64);
char *p = strtok(inputStr,":");
Time1hour = atoi(p);
p = strtok(NULL,":");
Time1min = atoi(p);
return 0;
}
int getTime2(String command) {
return((Time2hour*100)+Time2min);
}
int setTime2(String TToMod) {
char inputStr[64];
TToMod.toCharArray(inputStr,64);
char *p = strtok(inputStr,":");
Time2hour = atoi(p);
p = strtok(NULL,":");
Time2min = atoi(p);
return 0;
}
So now for the meat of the program. The most important part. The run all zones function.
//Run the system based on all of the data we have
int runAllZones(String command) {
int i;
//Send notice that we are running the system
sendNotice("today");
if(totalRain > 1) {
return 1;
}
//Loop through and run all the zones
for(i=0; i<=sizeof(relay);i++) {
if(disabled==true){
return 1;
}
// In my case relay 6 is the line that is alway on for each zone
if(aRelayIsOn==true) { return 1; }
//LOW is the value that activates the relay
digitalWrite(relay[i],LOW);
digitalWrite(relay[6],LOW);
aRelayIsOn = true;
relayIsOn[i] = true;
// delay with the values set for this relay (ms)
delay(relayDelay[i]);
digitalWrite(relay[i],HIGH);
digitalWrite(relay[6],HIGH);
aRelayIsOn = false;
relayIsOn[i] = false;
}
return 1;
}
Now for the loop at the end of the program:
void loop()
{
now = getTime("now");
//Check the rainfall for the past two days and store the value. *should only run once a day
if(now==2350) {
yesterdaysRain = todaysRain;
todaysRain = checkRain("today");
totalRain = todaysRain+yesterdaysRain;
}
//Check if the system needs to run for the two programs
// First check if it has rained more than an inch total over the past two days and if it is time to run the system
if(((now==(Time1hour*100+Time1min))||(now==(Time2hour*100+Time2min))) && (totalRain < 1)) {
// Next check it is the right day to run
if(getToday("todaysDay") & daysToRun) {
// And finially if it has rained today over an inch (just incase it rained a lot since midnight) skip it
if(checkRain("today") < 1) {
runAllZones("runNow");
delay(relayDelay[0] + relayDelay[1] + relayDelay[2] + relayDelay[3] + relayDelay[4] + relayDelay[5] + 2000); // This allows the run to complete as it appears that functions don't wait to complete... Not sure on this
}
}
}
delay(55000);
}
So, there you have it. A functioning irrigation system on the particle side. Now all you need is an interface to set it all up and manually run zones, etc. I will try to get that part posted soon, but until then, happy coding.