Wrong approach controlling hydroponics? Need help combining time.now and button

Hi!
This is my first own project and it is so much fun learning but I have hit a bump in the road and do not know what to read/do now.

I would be very grateful if someone could point me in the right direction :slight_smile:

The main problem is that I can get the button to work, and I can get the rtc timing to work but i have no success combining them.

I think the (if else if) att the end of the code is badly programmed too but I think I will be able to fix that myself but would be grateful for any pointers regarding any of the posted code.

If i upload this code the button works for some time before it dies and thats all. It does not pull the relay once every hour. This is kind of a big problem since i have to manually water very often to keep the plants alive.

Regards

// Hydroponic enviromental control
// Display time, temp, rh and current action on tft
// Controlls humidity, light and watering cycle by rtc time, sensor value or user input

//RTC CONNECTIONS
//Connect the RTC VCC  to the Arduino  +5 v
//                       RTC GND to the Arduino GND
//                       RTC SDA to  the Arduino Analog Pin 4
//                       RTC SCL to  the Arduino Analog Pin 5


#include <SPI.h>
#include <RTClib.h>
#include <Wire.h>
#include <TFT_ILI9163C.h>
#include <Adafruit_GFX.h>
#include <gfxfont.h>
#include <DHT.h>


const int Mist = 4;                  
const int Drip = 6;
const int Fan = 7;
const int Light =8;                //SSR
const int Relay6 = A0;
const int Relay7 = A1;
const int Relay8 = A2;
const int DH = 2;                   // Temp/RH

#define DHTTYPE DHT22

#define __DC 9
#define __CS 10
#define __RST 12
// MOSI -->(SDA) --> D11
// SCLK --> (SCK) --> D13

#define  BLACK   0x0000
#define BLUE    0x001F
#define RED     0xF800
#define GREEN   0x07E0
#define CYAN    0x07FF
#define MAGENTA 0xF81F
#define YELLOW  0xFFE0  
#define WHITE   0xFFFF

const byte BUTTON=3; 
const byte Wall=5; 

unsigned long buttonPushedMillis; // when button was released
unsigned long WallTurnedOnAt; // when led was turned on
unsigned long turnOnDelay = 25; // wait to turn on LED
unsigned long turnOffDelay = 30000; // turn off LED after this time
bool WallReady = false; // flag for when button is let go
bool WallState = false; // for LED is on or not.

TFT_ILI9163C tft = TFT_ILI9163C(__CS, __DC, __RST);
DHT dht(DH, DHTTYPE);
RTC_DS1307 RTC;


void setup (void) {  
  tft.begin();
  dht.begin();
  Wire.begin();
  RTC.begin();

  pinMode(Mist, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(Drip, OUTPUT);
  pinMode(Fan, OUTPUT);
  pinMode(Light, OUTPUT);
  pinMode(Relay6, OUTPUT);
  pinMode(Relay7, OUTPUT);
  pinMode(Relay8, OUTPUT);
  pinMode(3, INPUT_PULLUP);       //button internal resistor

  digitalWrite(Mist, LOW);
  digitalWrite(5, LOW);
  digitalWrite(Drip, LOW);
  digitalWrite(Fan, HIGH);
  digitalWrite(Light, LOW);
  digitalWrite(Relay6, LOW);
  digitalWrite(Relay7, LOW);
  digitalWrite(Relay8, LOW);


  //delay(10000);//wait for RTC to Respond, if not set time
  RTC.adjust(DateTime(__DATE__, __TIME__));
}


void loop() {
  DateTime now = RTC.now(); //GRAB DATE AND TIME FROM RTC

  // get the time at the start of this loop()
  unsigned long currentMillis = millis(); 

  // check the button
  if (digitalRead(BUTTON) == LOW || (now.minute()== 00)) {
    // update the time when button was pushed
    buttonPushedMillis = currentMillis;
    WallReady = true;
  }


  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  float h = dht.readHumidity();
  // Read temperature as Celsius (the default)
  float t = dht.readTemperature();


  tft.setCursor(0, 0); 
  tft.setTextColor(WHITE, BLACK); 
  tft.setTextSize(2);

  tft.print(" ");

  if (now.hour()<10){   // Add a zero, if necessary, as above
    tft.print(0);
  }
  tft.print(now.hour());
  tft.print(":");
  if (now.minute()<10){   // Add a zero, if necessary, as above
    tft.print(0);
  }
  tft.print(now.minute());
  tft.print(":");
  if (now.second()<10){   // Add a zero, if necessary, as above
    tft.print(0);
  }
  tft.print(now.second());


  tft.println("");
  tft.setTextColor(CYAN, BLACK);
  tft.setTextSize(3);
  tft.print(" ");
  tft.print(h, 1);    //(h)
  tft.print("%");

  tft.println("");
  tft.setTextColor(RED, BLACK); 
  tft.setTextSize(3);
  tft.print(" ");
  tft.print( t, 1);    //( t)
  tft.println("C");
  tft.setTextColor(GREEN, BLACK);
  tft.setTextSize(3);

  if (isnan(h) || isnan(t)) {
    tft.println("DHT ERR");
    return;
  }
  // make sure this code isn't checked until after button has been let go
  if (WallReady) {
    //this is typical millis code here:
    if ((unsigned long)(currentMillis - buttonPushedMillis) >= turnOnDelay) {


      // okay, enough time has passed since the button was let go.
      digitalWrite(Wall, HIGH);
      // setup our next "state"
      WallState = true;
      // save when the LED turned on
      WallTurnedOnAt = currentMillis;
      // wait for next button press
      WallReady = false;
      tft.setTextColor(CYAN, BLACK); 
      tft.setTextSize(2);
      tft.println(":)");  
    }
  }

  // see if we are watching for the time to turn off LED
  if (WallState){
    // okay, led on, check for now long
    if ((unsigned long)(currentMillis - WallTurnedOnAt) >= turnOffDelay)  {
      WallState = false;
      digitalWrite(Wall, LOW);

    }
    delay(30);


    if(now.hour() == 13 && now.minute() == 00){
      digitalWrite(Drip, HIGH);  
      tft.println ("Watering");
    }    

    else if(now.hour ()!= 13 && now.minute() != 00){
      digitalWrite(Drip, LOW);  
    }

    if(dht.readHumidity()<= 45.00){
      digitalWrite(Mist, HIGH);
      tft.print("M ON ");
    }



    else if(dht.readHumidity()>= 45.00){
      tft.setTextColor(BLUE);
      tft.setTextSize(1);
      digitalWrite(Mist, LOW);
      tft.println("M OFF ");
    }






    tft.setTextColor(BLUE);
    tft.setTextSize(2);

    if(now.hour() == 07 && now.minute() == 00){
      digitalWrite(Light, HIGH);  
      tft.print ("LED ON");
    }    

    if(now.hour()== 22){
      digitalWrite(Light, LOW);  
    }




  }




}

It is very hard to follow your code with all that crap commented out. Too hard. I gave up.

Delete commented out code. Use Tools + Auto Format to fix the horrid indenting. Post the code again.

PaulS: It is very hard to follow your code with all that crap commented out. Too hard. I gave up.

Delete commented out code. Use Tools + Auto Format to fix the horrid indenting. Post the code again.

Thank you! I did that and edited the code, I hope it is (more) readable now :)

Edit: And to clarify, what I want is for the relay "Wall"(5) to pass through current for 30 seconds every hour and also be able to trigger the 30 second on-time by my pushbutton.

    if(dht.readHumidity()<= 45.00){
      digitalWrite(Mist, HIGH);
      tft.print("M ON ");
    }



    else if(dht.readHumidity()>= 45.00){

Why are you reading the humidity from a slow sensor twice more? Is it likely to have changed significantly? If the humidity is not less than or equal 45%, is there any chance that it won’t be greater than or equal 45 %? If not, is there any reason to test that?

Literals with leading 0s are considered base 8. That does not appear to be what you want, so lose the leading 0s.

Printing the time on the TFT just screams for a function. Pull the ear plugs out and create one.

All the white

space does not make

your code more readable. Lose some of it.

  pinMode(Mist, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(Drip, OUTPUT);
  pinMode(Fan, OUTPUT);
  pinMode(Light, OUTPUT);
  pinMode(Relay6, OUTPUT);
  pinMode(Relay7, OUTPUT);
  pinMode(Relay8, OUTPUT);
  pinMode(3, INPUT_PULLUP);

Why the mix of name and numbers? You assigned names for pins 3 and 5. Use them.

If i upload this code the button works for some time before it dies

Put the button back on the shirt. Use a switch. Tell us how the switch is wired.

Well, the check for watering time is nested inside the if for "Wallstate". So if Wallstate is false, no watering will ever happen. Do you ever let Wallstate remain false?

  // check the button
  if (digitalRead(BUTTON) == LOW || (now.minute()== 00)) {
    // update the time when button was pushed
    buttonPushedMillis = currentMillis;
    WallReady = true;
  }

[Edited: mistook || for && - my bad]

Rather, for as long as minute() is 0, you continually simulate a button press. Maybe that's why you need a complicating timeout elsewhere to postpone the action "until button is released", which you never check for, by the way?

In the first part, you check that the hour and minute are a certain value. Then in the else, you check that the hour and minute are not the same value. Why? Of course they aren’t, you already checked.

    if(now.hour() == 13 && now.minute() == 00){
      digitalWrite(Drip, HIGH); 
      tft.println ("Watering");
    }   

    else if(now.hour ()!= 13 && now.minute() != 00){
      digitalWrite(Drip, LOW); 
    }

When I see things like that, I don’t want to read any more.

I understand you¬īre sick of all newbies making bad code. I did read a lot of tutorials and books and tried many of the things described and I thought it was time to start practice to get the knowledge to use but I guess I was to eager, I will read through all the reference list again and redo the code from the begining. I¬īm very grateful for all of your comments since they give me a lot of things to learn about :)

aarg: In the first part, you check that the hour and minute are a certain value. Then in the else, you check that the hour and minute are not the same value. Why? Of course they aren't, you already checked.

    if(now.hour() == 13 && now.minute() == 00){
      digitalWrite(Drip, HIGH); 
      tft.println ("Watering");
    }   

    else if(now.hour ()!= 13 && now.minute() != 00){       digitalWrite(Drip, LOW);     }




When I see things like that, I don't want to read any more.

Sometimes you just need someone to tell you how stupid something is before you see it, thanks!!

So I implemented some of the things you told me, I hope this code is easier to help me with?
I will try to fix the other things you told me too :slight_smile:
Is the code now usable to work on with?

// Hydroponic enviromental control
// Display time, temp, rh and current action on tft
// Controlls humidity, light and watering cycle by rtc time, sensor value or user input
//RTC CONNECTIONS
//Connect the RTC VCC  to the Arduino  +5 v
//                       RTC GND to the Arduino GND
//                       RTC SDA to  the Arduino Analog Pin 4
//                       RTC SCL to  the Arduino Analog Pin 5
#include <SPI.h>
#include <RTClib.h>
#include <Wire.h>
#include <TFT_ILI9163C.h>
#include <Adafruit_GFX.h>
#include <gfxfont.h>
#include <DHT.h>
const int Mist = 4;                  
const int Drip = 6;
const int Fan = 7;
const int Light =8;                //SSR
const int Relay6 = A0;
const int Relay7 = A1;
const int Relay8 = A2;
const int DH = 2;                   // Temp/RH
const byte BUTTON=3; 
const byte Wall=5; 
#define DHTTYPE DHT22
#define __DC 9
#define __CS 10
#define __RST 12
// MOSI -->(SDA) --> D11
// SCLK --> (SCK) --> D13
#define  BLACK   0x0000
#define BLUE    0x001F
#define RED     0xF800
#define GREEN   0x07E0
#define CYAN    0x07FF
#define MAGENTA 0xF81F
#define YELLOW  0xFFE0  
#define WHITE   0xFFFF
unsigned long buttonPushedMillis; // when button was released
unsigned long WallTurnedOnAt; // when led was turned on
unsigned long turnOnDelay = 25; // wait to turn on LED
unsigned long turnOffDelay = 30000; // turn off LED after this time
bool WallReady = false; // flag for when button is let go
bool WallState = false; // for LED is on or not.
TFT_ILI9163C tft = TFT_ILI9163C(__CS, __DC, __RST);
DHT dht(DH, DHTTYPE);
RTC_DS1307 RTC;

void setup (void) {  
  tft.begin();
  dht.begin();
  Wire.begin();
  RTC.begin();
  pinMode(Mist, OUTPUT);
  pinMode(Wall, OUTPUT);
  pinMode(Drip, OUTPUT);
  pinMode(Fan, OUTPUT);
  pinMode(Light, OUTPUT);
  pinMode(Relay6, OUTPUT);
  pinMode(Relay7, OUTPUT);
  pinMode(Relay8, OUTPUT);
  pinMode(BUTTON, INPUT_PULLUP);       //button internal resistor
  digitalWrite(Mist, LOW);
  digitalWrite(Wall, LOW);
  digitalWrite(Drip, LOW);
  digitalWrite(Fan, HIGH);
  digitalWrite(Light, LOW);
  digitalWrite(Relay6, LOW);
  digitalWrite(Relay7, LOW);
  digitalWrite(Relay8, LOW);
  //delay(10000);//wait for RTC to Respond, if not set time
  RTC.adjust(DateTime(__DATE__, __TIME__));
}

void loop() {
  DateTime now = RTC.now(); //GRAB DATE AND TIME FROM RTC
  // get the time at the start of this loop()
  unsigned long currentMillis = millis(); 
  // check the button
  if (digitalRead(BUTTON) == LOW) {
    // update the time when button was pushed
    buttonPushedMillis = currentMillis;
    WallReady = true;
  }
  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  float h = dht.readHumidity();
  // Read temperature as Celsius (the default)
  float t = dht.readTemperature();
  tft.setCursor(0, 0); 
  tft.setTextColor(WHITE, BLACK); 
  tft.setTextSize(2);
  tft.print(" ");
  if (now.hour()<10){   // Add a zero, if necessary, as above
    tft.print(0);
  }
  tft.print(now.hour());
  tft.print(":");
  if (now.minute()<10){   // Add a zero, if necessary, as above
    tft.print(0);
  }
  tft.print(now.minute());
  tft.print(":");
  if (now.second()<10){   // Add a zero, if necessary, as above
    tft.print(0);
  }
  tft.print(now.second());
  tft.println("");
  tft.setTextColor(CYAN, BLACK);
  tft.setTextSize(3);
  tft.print(" ");
  tft.print(h, 1);    //(h)
  tft.print("%");
  tft.println("");
  tft.setTextColor(RED, BLACK); 
  tft.setTextSize(3);
  tft.print(" ");
  tft.print( t, 1);    //( t)
  tft.println("C");
  tft.setTextColor(GREEN, BLACK);
  tft.setTextSize(3);
  if (isnan(h) || isnan(t)) {
    tft.println("DHT ERR");
    return;
  }
  // make sure this code isn't checked until after button has been let go
  if (WallReady) {
    //this is typical millis code here:
    if ((unsigned long)(currentMillis - buttonPushedMillis) >= turnOnDelay) {
      // okay, enough time has passed since the button was let go.
      digitalWrite(Wall, HIGH);
      // setup our next "state"
      WallState = true;
      // save when the LED turned on
      WallTurnedOnAt = currentMillis;
      // wait for next button press
      WallReady = false;
      tft.setTextColor(CYAN, BLACK); 
      tft.setTextSize(2);
      tft.println(":)");  
    }
  }
  // see if we are watching for the time to turn off Wall
  if (WallState){
    // okay, Wall on, check for now long
    if ((unsigned long)(currentMillis - WallTurnedOnAt) >= turnOffDelay)  {
      WallState = false;
      digitalWrite(Wall, LOW);
    }
    delay(30);
    if(now.hour() == 13 && now.minute() == 00){
      digitalWrite(Drip, HIGH);  
      tft.println ("Watering");
    }    
    if(dht.readHumidity()<= 45.00){
      digitalWrite(Mist, HIGH);
      tft.print("M ON ");
    }

    tft.setTextColor(WHITE, BLACK);
    tft.setTextSize(2);
    if(now.hour() == 07){
      digitalWrite(Light, HIGH);  
      tft.print ("LED ON");
    }    
    if(now.hour()== 22){
      digitalWrite(Light, LOW);  
    }
  }
}

I doubt that you want to set the RTC each time to the last time the sketch was compiled.

  RTC.adjust(DateTime(__DATE__, __TIME__));
    if ((unsigned long)(currentMillis - buttonPushedMillis) >= turnOnDelay) {
      // okay, enough time has passed since the button was let go.

Is buttonPushedMillis when the switch was pressed? Or when it was released? The name says one thing. The comment says the other?

  if (WallReady) {

I don't understand the name. How could a wall not be ready?

    if(now.hour() == 07){
      digitalWrite(Light, HIGH); 
      tft.print ("LED ON");
    }

You are going to be hosed if you want to change the on time to 8 or 9 AM.

PaulS:     if ((unsigned long)(currentMillis - buttonPushedMillis) >= turnOnDelay) {       // okay, enough time has passed since the button was let go.

Is buttonPushedMillis when the switch was pressed? Or when it was released? The name says one thing. The comment says the other?

  if (WallReady) {

I don't understand the name. How could a wall not be ready?

    if(now.hour() == 07){
      digitalWrite(Light, HIGH); 
      tft.print ("LED ON");
    }

You are going to be hosed if you want to change the on time to 8 or 9 AM.

Seems like the wise thing is to remove all that wallready, millis etc crap i got from an example and start from the beginning with the 30 sec delay? Originally was named "ledReady" etc so i just swapped every "led" for "Wall" since it is the name of the pump that is watering the vertical section of the garden. It is a lot of code just to keep the relay on for 30 seconds after the button(switch) is pressed without using delay. I thought i could use the same "delay" to water for 30 secs every hour. I guess I am overcomplicating things?

Whandall: I doubt that you want to set the RTC each time to the last time the sketch was compiled.

  RTC.adjust(DateTime(__DATE__, __TIME__));

True! :)

Pictures of circuit are on the way

Did not manage to get any good pictures under the LEDs but here they are:

Switch connected to gnd and (3) |500x281 |500x281

Apparently I was in way over my head so beside showing the time/temp and humidity I am just going to use it as a very dumb timer for the pumps to keep the plants alive:

if (digitalRead(Button) == LOW || (now.minute()== 00)){
    digitalWrite(Pump1, LOW);
    digitalWrite(Pump2, LOW);
    delay(60000);

    digitalWrite(Pump1, HIGH);
    digitalWrite(Pump2, HIGH);
  }

(low trigger relay) And use a mechanical timer for the lights.

I will order some c/c++ programming books to read during my vacation and then see if i can build something on my own without using a mix of examples and other peoples sketches.

At least I have green fingers :) |281x500 |500x281

At least I have green fingers

They made the plants turn red. What were you doing with them that embarrassed the plants? 8)

faff: I will order some c/c++ programming books to read during my vacation and then see if i can build something on my own without using a mix of examples and other peoples sketches.

That's the spirit! :-)

Karma point just for that!

Thanks for the help guys :) Any particular books you can recommend?

PaulS: They made the plants turn red. What were you doing with them that embarrassed the plants? 8)

Hehe that is my vampire that makes awesome black chilis |500x375 (not my picture)

One thing i¬īve noticed is that the LEDs (3x50w cob , cold white, warm white and ~red) bring out a lot more color in lettuce and other plants than hps or even the sun :) Going to plant a red basil today that i have big hopes for :)

You should probably learn C before C++, as C++ really is an extension of C.

The classic is the book "C Programming Language" by Kernighan and Ritchie, but I see it's quite pricey on amazon. I bought that one somewhere around 1990 I think, when moving from lower to higher degree in computer science at the university, as they switched to Unix at the time.

Damn I'm getting old. :-)

[/memory-lane]

Just search for "learning C" on google. Should get you going.

C++ can wait, as long as you accept there are certain "objects" in the Arduino environment, which magically come to life by just being declared, it seems like, and that you can call functions inside them, via dotted notation. Writing your own such objects is no problem, but then you will have to expand into learning C++.

Good luck!