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.