-2

Hi so I am making a self watering flower pot with a moisture sensor and a peristaltic pump, the code is as follows:

enter image description here

I want to add an indicator LED which turns on if the sensor value has been equal to or greater than MaxDryness for longer than twenty minutes.

How would I alter the code to do that?

4
  • 6
    why did you post a picture of the code? ... do you really think that someone will spend time typing it in so that it could be added to, and posted as an answer?
    – jsotola
    Nov 23, 2018 at 6:33
  • Ditch the delay() calls and learn the non-blocking coding style from the BlinkWithoutDelay example. It uses the millis() function, that returns the milliseconds since startup. You can use this as a clock to time the 20min. The coding style has been explained many times on the web.
    – chrisl
    Nov 23, 2018 at 6:57
  • 2
    @jyc43 please replace your source code picture with a code block, this will allow us to insert the lines of code you are looking for. Nov 23, 2018 at 10:18
  • Please code the text as text Nov 23, 2018 at 12:50

2 Answers 2

2

Following is an example how it could be coded.

Remember that the soil is dry by setting DrySoil = true.

Register the time at which a dry period starts in DrySoilBegin.

Check at each 'dry' reading whether DrySoil was true for more than 20 minutes.

Set DrySoil = false at every 'not dry' reading.

The ul after the constant 1200000 makes it an unsigned long value. This because millis() returns a unsigned long result. I am not 100% sure this is necessary (maybe the compiler takes care of this automatically).

As I don't have a plant watering system I couldn't verify the proper working..

#define WATERPIN 10
#define READSOILPIN A0
#define LEDPIN 13

// higher number is more dry
#define MAXDRYNESS 700

#define WATERDELAY 10000
#define WATERPOSTDELAY 5000

bool DrySoil = false; // State of soil
unsigned long DrySoilBegin; // Time when DrySoil became true

void setup() {
  Serial.begin(9600);
  pinMode(READSOILPIN, INPUT);
  pinMode(WATERPIN, OUTPUT);
  pinMode(LEDPIN, OUTPUT);
}

void loop() {
  int SensorValue = analogRead(READSOILPIN); //take a sample
  Serial.print(SensorValue);
  Serial.print(" ־ ");

  if(SensorValue >= MAXDRYNESS) {
    // Soil is too dry
    // Check if soil was already in a dry state
    if(DrySoil){
      // If already in a dry state check the duration
      if((millis()-DrySoilBegin) > 1200000ul){
        // If duration is longer than 20 minutes switch LED on
        //   or keep LED switched on
        digitalWrite(LEDPIN, HIGH);
      }
    }
    else{
      // First 'dry' result after 'wet' result(s)
      DrySoil = true; // Set DrySoil in true state
      DrySoilBegin = millis(); // Set beginning of DrySoil period
    }
    // start watering for 10 seconds then
    //    wait for 5 seconds before monitoring again
    Serial.println("Soil dry start watering");
    digitalWrite(WATERPIN, HIGH);
    delay(WATERDELAY); // wait until WATERDELAY milliseconds have passed
    digitalWrite(WATERPIN, LOW);
    delay(WATERPOSTDELAY); // wait until WATERPOSTDELAY milliseconds have passed
  }
  else{
    // Soil is not too dry
    DrySoil = false; // Set or keep DrySoil in state false
    digitalWrite(LEDPIN, LOW); // Switch LED off, or keep it switched off
    delay(50); // Wait 50 ms before next sampling
  }
}
2
  • 1. You should move your first else down so that it matches if(DrySoil). 2. You should replace while((millis()-TimerStart)<... by delay(). Using millis() in this blocking fashion has zero advantage over delay() and it makes the code harder to read. Nov 24, 2018 at 10:17
  • 1. Thank you, you are right. Have edited accordingly. 2. My guess was, this left more internal processes running. But I understand this is not true. Also corrected accordingly.
    – PimV
    Nov 24, 2018 at 16:10
0

Here's a little example how to do it. Adapt this way(if you want) by yourself.

// GLOBAL VARIABLES
unsigned long lowSensorTick = 0;
bool dry = false;

void loop()
{
    if (analogRead(/* PIN */) > /* THRESHOLD VALUE */)
    {
        // DRY
        if (dry == false)
        {
            lowSensorTick = millis();
            dry = true;
        }
        else
        {
            if (millis() - lowSensorTick > 720000) // 720000ms = 12min * 60000ms (1s = 1000ms) 
            {
                digitalWrite(LED_PIN, HIGH); // LED GOES HIGH/ON
            }
        }
    }
    else
    {
        // WET
        dry = false;
        digitalWrite(LED_PIN, LOW); // LED GOES LOW/OFF
    }
}
6
  • Note that zero is a perfectly valid timestamp. You should use a separate boolean variable, like in PimV's answer, rather having lowSensorTick perform double duty of storing the timestamp and a "timestamp valid" state. Nov 24, 2018 at 10:20
  • Why? millis() will never return zero as value. I use this way in my projects and it works without any problem.
    – Pararera
    Nov 24, 2018 at 13:29
  • millis() returns zero at the beginning of the program run, and then once again every 49.7 days. Nov 24, 2018 at 13:50
  • At the begining you have pinMode function. Zero stays for 1/1000s. For overflow that's another problem.
    – Pararera
    Nov 24, 2018 at 13:58
  • 1
    1. pinMode() executes in way less than a millisecond. 2. lowSensorTick = 0 is a kludge to shoehorn a valid/invalid status info into a variable that is meant to hold something else, and this can make the program misbehave, albeit very rarely. Other than laziness, there is no reason to not use a separate Boolean. If you want to take the (very tiny) risk on you own programs, that's OK. But when answering questions, you should avoid teaching bad practices, especially considering that there is already a perfectly valid answer. Nov 24, 2018 at 17:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.