Convert to Arrays

I am building a very simple sprinkler controller to water my wife’s herb garden. She is going to be planting them in window sill type flower boxes. I plan on using a moisture sensor to determine the soil moisture and turn on the water flow for a specified time. The sketch below performs fine on the breadboard though I still have to tweak the values of MoistureLevel and SprinkleDuration once the boxes are finished and herbs are planted. While this sketch should do great for one box I’d like to expand this code to control more boxes. Of course there are countless ways to totally rewrite this sketch but I’m trying to learn a little something along the way as well. That said, I don’t think in loops very well and would like come help converting this code to use both “arrays” and “for” loops to monitor 6 boxes (A0-A5) and control their corresponding valves (pin 2-7). I only want one box monitored and watered at a time so the code needs to be “blocking” so that each box is checked and watered before moving on to the next one. Any ideas?

/*
  Sprinkler Controller
Ground moisture sensor turns on sprinkler for a specified time if the sensor
indicates that the ground moisture drops below a specified level.
 */

// Variable definitions 
#define MoistureLevel    512        // minimum soil moisture level
#define MoistureValue    0          // soil moisture value from the soil moisture sensor
#define SprinkleDuration 5          // time sprinkler will stay on

// Pin assignments
#define MoisturePin A0          // pin the moisture sensor inputs to
#define SprinklePin 2           // pin the sprinkler relay is controlled by

/* Rename variables according to their function
PIN...   = Pin assignments
LEVEL... = Pre-defined (or calibrated) level
VALUE... = Value obtained from an input
TIME...  = A value corresponding to a time measurement
*/
int PINmoisture   = MoisturePin;
int PINsprinkle   = SprinklePin;
int LEVELmoisture = MoistureLevel;
int VALUEmoisture = MoistureValue;    // variable to store the value from the moisture sensor
int TIMEsprinkle  = SprinkleDuration; // time sprinkler will stay on after turning on


void setup() {
  pinMode(PINsprinkle, OUTPUT);           // declare the PINsprinkle as an OUTPUT
  TIMEsprinkle = TIMEsprinkle * 1000;     // Time in seconds for testing
// TIMEsprinkle = TIMEsprinkle * 60000;   // Time in minutes
}

void loop() {
  digitalWrite(PINsprinkle, LOW);         // Preset sprinkler relay off
  VALUEmoisture = analogRead(PINmoisture);// Read soil moisture
  delay(150);                             // debounce delay
  while (VALUEmoisture < LEVELmoisture){  // do this while soil moisture is below level
     digitalWrite(PINsprinkle, HIGH);     // turn on sprinkler valve
     delay(TIMEsprinkle);                 // leave it on for this long and wait until finished
     break;                               // exit and allow sensor to recheck the moisture
  }               
}

for (int PINsprinkle= 1; PINsprinkle< 7; PINsprinkle++) {

digitalWrite(PINsprinkle+1, LOW); // Preset sprinkler relay off

VALUEmoisture = analogRead(PINmoisture);// Read soil moisture

delay(150); // debounce delay

while (VALUEmoisture < LEVELmoisture){ // do this while soil moisture is below level

digitalWrite(PINsprinkle, HIGH); // turn on sprinkler valve

delay(TIMEsprinkle); // leave it on for this long and wait until finished

VALUEmoisture = analogRead(PINmoisture);// Read soil moisture

}

}

PINsprinkle would start at 1 for sprinkler 1, in the loop I add 1 to it so it gets the correct pin.

i would do a case statement for PINmoisture based on PINsprinkle to assign A0-A5.

I don’t think the above will quite work. It lacks the functionality to change the analog pin used as the box to be watered changes (and 1 other oopsie). Here’s the above code snippet nicely formatted:

for (int PINsprinkle= 1; PINsprinkle< 7; PINsprinkle++) {
  digitalWrite(PINsprinkle+1, LOW); // Preset sprinkler relay off
  VALUEmoisture = analogRead(PINmoisture);// Read soil moisture
  delay(150); // debounce delay
  while (VALUEmoisture < LEVELmoisture){ // do this while soil moisture is below level
    digitalWrite(PINsprinkle, HIGH); // turn on sprinkler valve
    delay(TIMEsprinkle); // leave it on for this long and wait until finished
    VALUEmoisture = analogRead(PINmoisture);// Read soil moisture
  }
}

Note the analogRead(PINmoisture) doesn’t change from pass to pass of the loop while the PINsprinkle does. So one way (of a bunch) would be to slightly modify it like the below:

for (int x = 0; x < 6; x++) {
  digitalWrite(x+2, LOW); // Preset sprinkler relay off
  VALUEmoisture = analogRead(x);// Read soil moisture
  delay(150); // debounce delay
  while (VALUEmoisture < LEVELmoisture){ // do this while soil moisture is below level
    digitalWrite(x, HIGH); // turn on sprinkler valve
    delay(TIMEsprinkle); // leave it on for this long and wait until finished
    VALUEmoisture = analogRead(x);// Read soil moisture
  }
}

Note that x will vary from 0 - 5 for the 6 boxes, using pins 2 - 7 for sprinkler control while reading analogpins 0 - 5. That solves the problem above but it’s not very intuitive. I’ve hard coded which pins are used for what. What I think the OP wanted to do was use some arrays to designate which pins are used. So, to start, you could have 2 arrays and declare them as follows:

int PINsprinkle [] = {2, 3, 4, 5, 6, 7}   //these pins used to control sprinkler heads;
int PINmoisture [] = {0, 1, 2, 3, 4, 5}   //the are the analog pins used to read the moisture sensors;

This allows you to use whatever pins for whatever box you want. They don’t have to be in any order. So the code above now becomes :

for (int x = 0; x < 6; x++) {
  digitalWrite(PINsprinkle[x], LOW); // Preset sprinkler relay off
  VALUEmoisture = analogRead(PINmoisture[x]);// Read soil moisture
  delay(150); // debounce delay
  while (VALUEmoisture < LEVELmoisture){ // do this while soil moisture is below level
    digitalWrite(PINsprinkle[x], HIGH); // turn on sprinkler valve
    delay(TIMEsprinkle); // leave it on for this long and wait until finished
    VALUEmoisture = analogRead(PINmoisture[x]);// Read soil moisture
  }
}

As for other “improvements” I might suggest that instead of a hard coded 6 in the for loop, you use a constant called numBoxes which you set to 6 … or however many boxes you have. I suspect each moisture sensor will have it’s own threshold for a given moisture level, or perhaps you’ll want differing moisture levels … so make another array called LEVELmoisture [] and initialize that array like the others to whatever the desired levels are. Lastly I question the need for a “debounce” delay. It doesn’t hurt but it doesn’t really serve any purpose either.

Lastly … and this is a mistake that needs correcting IMO … you need to turn the sprinkler off when the level gets high enough. The “while” loop keeps setting the sprinkler on while the moisture is “low”. When that’s done, you need to set the sprinkler to off before going to the next box. Otherwise the sprinkler stays on until the for loop has cycled through all 6 boxes. Initialize all the sprinklers to “off” in the setup() area. Move …

digitalWrite(PINsprinkle[x], LOW); // Preset sprinkler relay off

… to after the while loop. :mrgreen:

http://arduino.cc/en/Reference/Array

Thanks to both of you.

A couple other things though:

I understand turning off the sprinkler BEFORE leaving the loop(). I actually had noticed that but with just one system it was not an issue because as soon as the sprinkler finished running (according to the value of TIMEsprinkle) the sketch would loop around and turn off the sprinkler then recheck the soil. I had considered an extended delay here to allow the soil to percolate a little before retesting.

This brings me my other dilemma - The soil moisture sensor placement:

If I plug the soil sensor into the soil from the top it will only measure the moisture of the soil on the surface of the box. Also if I use the sensor to determine when to turn off the water then the sensor would indicate “wet” almost immediately and won’t saturate the soil. This is why I decided on a preset watering time rather than a “water until wet” approach. I’m no good at growing things but I think in my feeble understanding of horticulture that the roots will chase the water downward as the soil dries on the surface thereby creating deeper, stronger roots. Sensor placement and the setting of “MoistureLevel” will obviously affect this. With only one variable for MoistureLevel I will be relying on the depth of the soil moisture sensors in each box to determine the actual soil saturation depth of each box. I’d like to be able to have different values for MoistureLevel and SprinklerDuration for each box if possible too.

More succinctly:

How can I assign values to elements in an array and use them in the loop?

Also how does this work with pinMode? If PINsprinkle is different for each system I assume I can rewrite this:

void setup() {
  pinMode(PINsprinkle, OUTPUT);           // declare the PINsprinkle as an OUTPUT
  TIMEsprinkle = TIMEsprinkle * 1000;     // Time in seconds for testing
// TIMEsprinkle = TIMEsprinkle * 60000;   // Time in minutes
}

to this:

void setup() {
  for (int index = 0; 0 < 6; index++) {
    pinMode(PINsprinkle[index], OUTPUT);              // declare the PINsprinkle as an OUTPUT
    TIMEsprinkle[index] = TIMEsprinkle[index] * 1000;     // Time in seconds for testing
//    TIMEsprinkle[index] = TIMEsprinkle[index] * 60000;   // Time in minutes
  }
}

But if I do that then will “index” and “x” be in sync? I’m guessing not.

Now this snippet of code obviously doesn’t work but I hope at least it conveys my intentions. Sorry for the overuse of #define statements but I like to use them but only if they work.

// Variable definitions
#define MoistureLevelBox1    111    // minimum soil moisture level of each Box
#define MoistureLevelBox2    222
#define MoistureLevelBox3    333
#define MoistureLevelBox4    444
#define MoistureLevelBox5    555
#define MoistureLevelBox6    666

#define SprinkleDurationBox1    1   // time each sprinkler will stay on
#define SprinkleDurationBox2    2
#define SprinkleDurationBox3    3
#define SprinkleDurationBox4    4
#define SprinkleDurationBox5    5
#define SprinkleDurationBox6    6

#define MoistureValue           0         // soil moisture value from the soil moisture sensor

int PINsprinkle[] = {2, 3, 4, 5, 6, 7};   //these pins used to control sprinkler heads
int PINmoisture[] = {0, 1, 2, 3, 4, 5};   //the are the analog pins used to read the moisture sensors

/* Rename variables according to their function
PIN...   = Pin assignments
LEVEL... = Pre-defined (or calibrated) level
VALUE... = Value obtained from an input
TIME...  = A value corresponding to a time measurement
*/
int LEVELmoisture[] = {0, 1, 2, 3, 4, 5};
LEVELmoisture[0] = MoistureLevelBox1;  //  111
LEVELmoisture[1] = MoistureLevelBox2;  //  222
LEVELmoisture[2] = MoistureLevelBox3;  //  333
LEVELmoisture[3] = MoistureLevelBox4;  //  444
LEVELmoisture[4] = MoistureLevelBox5;  //  555
LEVELmoisture[5] = MoistureLevelBox6;  //  666

int TIMEsprinkle[] = {0, 1, 2, 3, 4, 5};  // time each sprinkler will stay on after turning on
TIMEsprinkle[0] = SprinkleDurationBox1;  //  1
TIMEsprinkle[1] = SprinkleDurationBox2;  //  2
TIMEsprinkle[2] = SprinkleDurationBox3;  //  3
TIMEsprinkle[3] = SprinkleDurationBox4;  //  4
TIMEsprinkle[4] = SprinkleDurationBox5;  //  5
TIMEsprinkle[5] = SprinkleDurationBox6;  //  6

Take just this bit from above and leave the defines as they are:

int LEVELmoisture[] = {0, 1, 2, 3, 4, 5};
LEVELmoisture[0] = MoistureLevelBox1;  //  111
LEVELmoisture[1] = MoistureLevelBox2;  //  222
LEVELmoisture[2] = MoistureLevelBox3;  //  333
LEVELmoisture[3] = MoistureLevelBox4;  //  444
LEVELmoisture[4] = MoistureLevelBox5;  //  555
LEVELmoisture[5] = MoistureLevelBox6;  //  666

The first line the declares the array LEVELmoisture also sets the values in the array to 0 - 5. It then (tries to) immediately reset them to the values in MoistureLevelBox1-5, aka 111, 222 … 666. You could have simply declared the array and told the compiler that it has 6 elements. Then set them as you did but in the setup() function. That would look like :

int LEVELmoisture[6];                  //this creates an array with 6 elements
unsigned long TIMEsprinkle[6]

Your setup() function might look like this:

void setup() {
  for (int index = 0; index  < numBoxes; index++) {
    pinMode(PINsprinkle[index], OUTPUT);             // declare the PINsprinkle as an OUTPUT
    digitalWrite(PINsprinkle[index], LOW);           // ensure all outputs are off
  }
  LEVELmoisture[0] = MoistureLevelBox1;  //this sets the 1'st element to 111
  LEVELmoisture[1] = MoistureLevelBox2;  //this sets the 2'nd element to 222
  LEVELmoisture[2] = MoistureLevelBox3;  //this sets the 3'rd element to 333
  LEVELmoisture[3] = MoistureLevelBox4;  //this sets the 4'th element to 444
  LEVELmoisture[4] = MoistureLevelBox5;  //this sets the 5'th element to 555
  LEVELmoisture[5] = MoistureLevelBox6;  //this sets the 6'th element to 666
  
  TIMEsprinkle[0] = SprinkleDurationBox1;  //  1
  TIMEsprinkle[1] = SprinkleDurationBox2;  //  2
  TIMEsprinkle[2] = SprinkleDurationBox3;  //  3
  TIMEsprinkle[3] = SprinkleDurationBox4;  //  4
  TIMEsprinkle[4] = SprinkleDurationBox5;  //  5
  TIMEsprinkle[5] = SprinkleDurationBox6;  //  6
}

And if I used the arrays in an “improved” version of my snippet from below:

for (int x = 0; x < numBoxes; x++) {
  VALUEmoisture = analogRead(PINmoisture[x]);   // Read soil moisture
  while (VALUEmoisture < LEVELmoisture[x]){     // do this while soil moisture is below level
    digitalWrite(PINsprinkle[x], HIGH);         // turn on sprinkler valve
    delay(k*TIMEsprinkle[x]);                   // leave it on for this long
    VALUEmoisture = analogRead(PINmoisture[x]); // Read soil moisture
  }
  digitalWrite(PINsprinkle[x], LOW);            // Turn sprinkler relay off
}

Where k is your factor of 100 or 1000 or whatever you want (so long as the result is not greater than 4,294,967,295) and numBoxes = 6.

http://arduino.cc/en/Reference/Array

http://arduino.cc/en/Reference/Delay

SimTech:
But if I do that then will “index” and “x” be in sync? I’m guessing not.

Just to answer the above directly ... it doesn't matter. The "variable" x, index, k or whatever you use in the for loop only exists within it's own for loop. Once the code is done with that for loop, that variable is forgotten ... and if the loop is executed again ... it's created again. It's a very local variable. See the discussion of "scope" below.

http://arduino.cc/en/Tutorial/Variables

http://arduino.cc/en/Reference/For

As for the defines … I did want to point out while that may work (I think it will ??), it’s sure a lot of extra typing. Why not just set the array values directly ?

int LEVELmoisture[] = {111, 222, 333, 444, 555, 666};

http://arduino.cc/en/Reference/Const

Well I thought I had it. Please keep in mind that this is a learning exercise for me as I don’t do as well by reading how to do something as I do by actually doing it. I ditched the defines and tried to condense what you’ve taught me so far and I came up with this:

// Variable definitions
int VALUEmoisture   =   0;                              // initialize the soil moisture sensor
int NUMboxes        =   6;                              // number of boxes (= array elements)
int TIMEconstant    =   1000;                           // multiplier for watering time in ms
int PINsprinkle[]   =   {2, 3, 4, 5, 6, 7};             // sprinkler heads (DOs)
int PINmoisture[]   =   {0, 1, 2, 3, 4, 5};             // moisture sensors (AIs)
int TIMEsprinkle[]  =   {1, 2, 3, 4, 5, 6};             // time each sprinkler stays on
int LEVELmoisture[] =   {111, 222, 333, 444, 555, 666}; // minimum soil moisture levels

// Setup constants
void setup() {
  for (int k = 0; 0 < NUMboxes; k++) {                  // set each box's individual values
    pinMode(PINsprinkle[k], OUTPUT);                    // declare the PINsprinkle as an OUTPUT
    TIMEsprinkle[k] = TIMEsprinkle[k] * TIMEconstant;   // Watering time
  }
}

void loop() {
  for (int x = 0; x < NUMboxes; x++) {
    VALUEmoisture = analogRead(PINmoisture[x]);   // Read soil moisture
    delay(150);                                   // allow analogRead to compute VALUEmoisture
    while (VALUEmoisture < LEVELmoisture[x]){     // do this while soil moisture is below level
      digitalWrite(PINsprinkle[x], HIGH);         // turn on sprinkler valve
      delay(TIMEsprinkle[x]*TIMEconstant);        // leave it on for this long
      VALUEmoisture = analogRead(PINmoisture[x]); // Read soil moisture
    }
    digitalWrite(PINsprinkle[x], LOW);            // Turn sprinkler relay off
  }
}

It actually compiles beautifully but never trips the relay.

My test setup is a 10k pot attached to the analog in and a single relay attached to the digital out. Turning the pot should produce an audible click of the relay. Turning the pot back should cause the relay to disengage after TIMEsprinkle lapses. My sketch compiles now but no clicky clicky. What am I missing here?

SimTech:
What am I missing here?

At first glance it all looks OK. But then I looked very closely and saw that you must have looked at my posted code before I had a chance to correct a copy'n'paste error. To find it look at the for loop "test" in the setup() function. Usually I plug a few debugging print statements in to "see" what's really happening. So, below, is the code with the corrected for loop and some prints. See if this works (it seems to for me but I don't have the simulated sensors nor the relays). Adding in (?temporary?) print statements and temporarily commenting out suspect portions of code are simple yet powerful ways to debug something that's not working.
// Variable definitions
int VALUEmoisture   =   0;                              // initialize the soil moisture sensor
int NUMboxes        =   6;                              // number of boxes (= array elements)
int TIMEconstant    =   1000;                           // multiplier for watering time in ms
int PINsprinkle[]   =   {
  2, 3, 4, 5, 6, 7};             // sprinkler heads (DOs)
int PINmoisture[]   =   {
  0, 1, 2, 3, 4, 5};             // moisture sensors (AIs)
int TIMEsprinkle[]  =   {
  1, 2, 3, 4, 5, 6};             // time each sprinkler stays on
int LEVELmoisture[] =   {
  111, 222, 333, 444, 555, 666}; // minimum soil moisture levels

// Setup constants
void setup() {
  Serial.begin(9600);
  Serial.println("Hello");
  for (int k = 0; k < NUMboxes; k++) {                  // set each box's individual values
    pinMode(PINsprinkle[k], OUTPUT);                    // declare the PINsprinkle as an OUTPUT
    TIMEsprinkle[k] = TIMEsprinkle[k] * TIMEconstant;   // Watering time
  }
}

void loop() {
  for (int x = 0; x < NUMboxes; x++) {
    VALUEmoisture = analogRead(PINmoisture[x]);   // Read soil moisture
    Serial.print("Mositure measured for box ");
    Serial.print(x + 1);
    Serial.print(" is ");
    Serial.println(VALUEmoisture);
    delay(150);                                   // allow analogRead to compute VALUEmoisture
    while (VALUEmoisture < LEVELmoisture[x]){     // do this while soil moisture is below level
      digitalWrite(PINsprinkle[x], HIGH);         // turn on sprinkler valve
      Serial.print("Turning on sprinkler ");
      Serial.println(x + 1);
      delay(TIMEsprinkle[x]*TIMEconstant);        // leave it on for this long
      VALUEmoisture = analogRead(PINmoisture[x]); // Read soil moisture
    }
    digitalWrite(PINsprinkle[x], LOW);            // Turn sprinkler relay off
    Serial.print("Turning off sprinkler ");
    Serial.println(x + 1);
  }
}

So it the above works* … let me ask a question or two. What happens if a wire to a sensor breaks or becomes unplugged ? Or shorted to ground ? You’ve got a while loop that might get stuck in an infinite loop if the measured moisture level doesn’t come up to the threshold (for whatever reason). I also wonder if you shouldn’t have some difference in the moisture level to turn on the sprinkler and the level to turn it off ? Should there be a max amount off water on time in any given day ? Perhaps some min time between any 2 consecutive water on periods (for a given box) ?

*check the min time that the water stays on for when activated. The delay() function uses an unsigned long type variable. You’re multiplying two int types. Their product might overflow the 2 bytes allotted to an int if the numbers are big enough. And even if it doesn’t, I’m not sure the delay() will be “happy” with an int type.

I note that in the setup() function you have this:

TIMEsprinkle[k] = TIMEsprinkle[k] * TIMEconstant; // Watering time

… and in the main loop() you also have :

delay(TIMEsprinkle[x]*TIMEconstant); // leave it on for this long

Was that intentional ?

Got it!

Here is the working sketch:

/*
  Sprinkler Controller
Ground moisture sensor turns on sprinkler for a specified time if the sensor
indicates that the ground moisture drops below a specified level.

Personal variables naming conventions according to their function
PIN...   = Pin assignments
LEVEL... = Pre-defined (or calibrated) level
VALUE... = Value obtained from an input
TIME...  = A value corresponding to a time measurement
NUM...   = A generic number type but most commonly an integer
*/

// Variable definitions
int VALUEmoisture   =   0;                    // initialize the soil moisture sensor
int NUMboxes        =   4;                    // number of boxes (= array elements)
int TIMEconstant    =   1000;                 // multiplier for watering time in ms
int PINsprinkle[]   =   {2, 3, 4, 5};         // sprinkler heads (DOs)
int PINmoisture[]   =   {0, 1, 2, 3};         // moisture sensors (AIs)
int TIMEsprinkle[]  =   {5, 10, 15, 20};         // time each sprinkler stays on
int LEVELmoisture[] =   {111, 222, 333, 444}; // minimum soil moisture levels

// Setup constants
void setup() {
  Serial.begin(9600);
  Serial.println("Hello");
  for (int k = 0; k < NUMboxes; k++) {                  // set each box's individual values
    pinMode(PINsprinkle[k], OUTPUT);                    // declare the PINsprinkle as an OUTPUT
    TIMEsprinkle[k] = TIMEsprinkle[k] * TIMEconstant;   // Watering time
  }
}

void loop() {
  for (int x = 0; x < NUMboxes; x++) {
    VALUEmoisture = analogRead(PINmoisture[x]); // Read soil moisture
    Serial.print("Mositure measured for box ");
    Serial.print(x + 1);
    Serial.print(" is ");
    Serial.println(VALUEmoisture);
    delay(150);                                 // allow analogRead to compute VALUEmoisture
    while (VALUEmoisture < LEVELmoisture[x]){   // do this while soil moisture is below level
      digitalWrite(PINsprinkle[x], HIGH);       // turn on sprinkler valve
      Serial.print("Turning on sprinkler ");
      Serial.println(x + 1);
      delay(TIMEsprinkle[x]);                   // leave it on for this long
      break;
    }
    digitalWrite(PINsprinkle[x], LOW);          // Turn sprinkler relay off
    Serial.print("Turning off sprinkler ");
    Serial.println(x + 1);
  }
}

I reduced it to 4 and breadboarded some diodes and ran all the AIs through the pot. This allowed me to see what was going on. It was hanging on the watering delay. Then I noticed that “delay(TIMEsprinkle*TIMEconstant);” in the loop() was a repeat of “delay(TIMEsprinkle*TIMEconstant);” in the setup(). I changed the loop() line to just “delay(TIMEsprinkle)” and it works perfectly. I can slowly adjust the pot down from 1024 and once I hit 443 it turns on system 4 for 20 seconds. 332 turns on 3 for 15 seconds and 4 for 20 and so forth. I also added the “break” to the while as it was in the single system sketch. This should eliminate an infinite loop. As far as rechecking the moisture level immediately after watering or limiting the waterings per day I don’t care. In a yard system this might be a valid consideration but this will be for window size boxes. I don’t expect to use much water overall. Also once watered the sketch will move on and service the other systems and allow the soil to percolate a little and then return to each system and recheck the soil moisture before adding any more water. It may take several cycles for the soil to reach the desired moisture but that’s the beauty of this system. It don’t care how many times it runs nor how long. It will keep on going until it dies. All I will have to do is adjust the moisture levels as I want in each box.

Okay now I’ve done it. Now my gears are spinning thing about a pushbutton/LCD setup to be able to manipulate the moisture levels without code change. GAAAHHHHH! It never ends! Hmmmm where’s my 1602?

Thanks for all the help!

Good ! I have one thing to point out. You’ve declared the time constant and the water times to be ints. You then multiply them :

TIMEsprinkle[k] = TIMEsprinkle[k] * TIMEconstant; // Watering time

If that product is ever bigger than about 32 seconds your program will hang. I believe that so long as one of the 2 variables is an unsigned long, the compiler will instruct that the result also be the larger unsigned long datatype. However if you then store that back into the int type TIMEsprinkle, well you’re back where you were. My recommendation would be to either make TIMEsprinkle an unsigned long type or both to be unsigned long types. To be anal I’d keep the TIMEsprinkle array as ints (to save memory space) and have the TIMEconstant be the unsigned long and then do the multiplication inside the delay() (and eliminate the multiply above). That way the array could store times in minutes with the TIMEconstant being the conversion factor to msescs (60000).

Think about how (?if?) your while loop with a break in it is any different from the more common if().

if(moisture too low){
  turn on water for X mins
}

http://arduino.cc/en/Reference/If

SimTech:
I also added the “break” to the while as it was in the single system sketch. This should eliminate an infinite loop.

Yes you have and no not really. Let's see what happens in the situation where the systems been running and all the boxes are nicely moisturated. The code keeps looping checking the levels and everything is OK. No water gets turned on. So far, so good. Now a wire gets opened up because the cat chewed through it. When the loop gets around to checking that box what happens ? Well the voltage output by the sensor isn't there anymore so it appears that the moisture level is low. The water gets turned on. With the revised code, it gets turned on for some period of time and then gets shut off. With the old code it would have looped right there, infinitely. But now the water turns off after a timed period. Alas the loop will check the other boxes and then come back to the broken one, with the result that the water gets turned on again ... and again ... and again ... not really any practical difference from the prior infinite loop.

W/o knowing what you’ll have for sensors I can’t say how to fix the potential problem but a way other systems handle this type of thing is to test the sensor reading for some validity. The hardware is designed so an open (or a short) will result in a voltage that’s much higher or lower than could be expected from any working sensor. The readings are checked against a max limit and a low limit before the normal test. If a reading is too high or if a reading is too low, then the normal block of code is not run and some error block of code is run. That error code might turn off the water, it might flash an “error light”, it might stop reading from that sensor and use a nearby sensor instead. Anyway it pays to think about how your device can be tripped up by the real imperfect world and come up with code that fails safe and/or degrades gracefully.