Button and Clock issues

So I am making a cactus babysitter that does a few things.

  1. Leaves a fluorescent light on from a certain hour to another certain hour. For this it uses a realtime clock and a relay.

  2. Pumps water from a vase to the watering system every Sunday at noon for a calculated amount of time to get the rough amount of milliliters per plant needed. For this it uses a realtime clock, a pump and a relay.

  3. Has two RGB lights that vary depending on the desired temp. (both green if good, one or two blue if cold, and one or two red if hot)

  4. Has an LCD screen to display the variables (time light on, time light off, milliliters, and desired temp)

  5. Has four buttons used to change these variables on the go (time light on, time light off, milliliters, and desired temp)

So basically everything works right now except for two things.

• The buttons do not change the variables like they should. If I press in a button, everything turns off (LCD, LEDs, Arduino LEDs, Relay LEDs) but then I release the button and the code resets. It’s really bizarre and I don’t know what’s wrong. I believe the wiring is right but it could be wrong. The wiring is really complicated so I wanted to avoid having to post that if it was just an obvious coding issue.

• The clock randomly resets back to 1/1/2000 – 00:00:00. Just last night I had the big light working at like 1am, I programmed it to turn on at 1am, but then at 7:20am the light turned back on again, meaning the clock reset itself an hour earlier to this. I checked the code this morning and sure enough the clock was reset a few hours ago. I’m not sure why this is going on either. The two problems may be related.

Any insight you guys could provide would be awesome.

#include <Wire.h>
#include <DS3231.h>
#include <LiquidCrystal_I2C.h>

//initialize the DS3231 clock using the hardware interface
DS3231  rtc(SDA, SCL);

//set the LCD address to 0x27 for a 20 char and 4 line display
LiquidCrystal_I2C lcd(0x27, 20, 4);

//pin setup
const int tempLED1RedPin = 3;
const int tempLED1GreenPin = 5;
const int tempLED1BluePin = 6;
const int tempLED2RedPin = 9;
const int tempLED2GreenPin = 10;
const int tempLED2BluePin = 11;
const int relayPin = 7;
const int pumpPin = 8;
const int timeOnButtonPin = 13;
const int timeOffButtonPin = 2;
const int waterButtonPin = 4;
const int tempButtonPin = 12;


void setup(){
  
  //initialize the rtc
  rtc.begin();
  
  //the following lines can be uncommented to set the date and time
  //rtc.setDOW(THURSDAY);      // Set Day-of-Week to WEDNESDAY
  //rtc.setTime(0, 11, 0);     // Set the time to 12:00:00 (24hr format)
  //rtc.setDate(3, 8, 2017);   // Set the date to January 1st, 2014
  
  //initialize the lcd
  lcd.init();
  
  //open the backlight
  lcd.backlight(); 
  
  //setup serial connection at 115200 baud
  Serial.begin(115200);
  
  while(!Serial){
    //wait for serial port to connect
  }
 
  //setting inputs
  pinMode(timeOnButtonPin, INPUT);
  pinMode(timeOffButtonPin, INPUT);
  pinMode(waterButtonPin, INPUT);
  pinMode(tempButtonPin, INPUT);
 
  //setting outputs
  pinMode(tempLED1RedPin, OUTPUT);
  pinMode(tempLED1GreenPin, OUTPUT);
  pinMode(tempLED1BluePin, OUTPUT);
  pinMode(tempLED2RedPin, OUTPUT);
  pinMode(tempLED2GreenPin, OUTPUT);
  pinMode(tempLED2BluePin, OUTPUT);
  pinMode(relayPin, OUTPUT);
  pinMode(pumpPin, OUTPUT);

}


void loop(){
  
  //defining variables
  int lightHourOn = 1;
  int lightHourOff = 22;
  boolean lightsOn = false;
 
  //these variables don't change with buttons so you may have to change them here.
  String wateringDay = "Sunday";
  int wateringHour = 12;
  
  int milliliters = 0;
  int waterTime = milliliters*500; //this is just desired mL / 6mL/sec flow * 3 pots * 1000ms/sec
  boolean gaveWater = false;
  
  float desiredTemp = 75;
  float tempC = 0;
  float tempF = 0;
  
  //infinite checks
  while(true){
    
    //getting day and hour strings
    String currentDay = rtc.getDOWStr();
    String currentTimeString = rtc.getTimeStr();
    String currentHourString = currentTimeString;
    currentHourString.remove(2);
    
    //converting hour strings into int
    int currentHour = currentHourString.toInt();
    
    //getting the temp in Celsius
    tempC = rtc.getTemp();
    
    //converting to Fahrenheit
    tempF = (tempC * 9/5) + 32;
    
    //starting button statuses
    int timeOnButtonCurrentState = 0;     
    int timeOnButtonLastState = 0;
    int timeOffButtonCurrentState = 0;     
    int timeOffButtonLastState = 0;
    int waterButtonCurrentState = 0;     
    int waterButtonLastState = 0;
    int tempButtonCurrentState = 0;     
    int tempButtonLastState = 0;
    
    //reading timeOnButton
    timeOnButtonCurrentState = digitalRead(timeOnButtonPin);
    //if button is pushed in and also different from last read
    if(timeOnButtonCurrentState != timeOnButtonLastState && timeOnButtonCurrentState == LOW){
      //up the time one hour or loop it back
      if(lightHourOn != 23){
        lightHourOn = lightHourOn + 1;
      }
      else{
         lightHourOn = 0;
      }
    }
    //set our state to our last state for the next check
    timeOnButtonLastState = timeOnButtonCurrentState;
    
    //reading timeOffButton
    timeOffButtonCurrentState = digitalRead(timeOffButtonPin);
    //if button is pushed in and also different from last read
    if(timeOffButtonCurrentState != timeOffButtonLastState && timeOffButtonCurrentState == LOW){
      //up the time one hour or loop it back
      if(lightHourOff != 23){
        lightHourOff = lightHourOff + 1;
      }
      else{
         lightHourOff = 0;
      }
    }
    //set our state to our last state for the next check
    timeOffButtonLastState = timeOffButtonCurrentState;
    
    //reading waterButton
    waterButtonCurrentState = digitalRead(waterButtonPin);
    //if button is pushed in and also different from last read
    if(waterButtonCurrentState != waterButtonLastState && waterButtonCurrentState == LOW){
      //up the water level 10ml
      if(milliliters != 200){
        milliliters = milliliters + 10;
      }
      else{
         milliliters = 0;
      }
    }
    //set our state to our last state for the next check
    waterButtonLastState = waterButtonCurrentState;
    
    //reading tempButton
    tempButtonCurrentState = digitalRead(tempButtonPin);
    //if button is pushed in and also different from last read
    if(tempButtonCurrentState != tempButtonLastState && tempButtonCurrentState == LOW){
      //up the temp 5º
      if(desiredTemp != 100){
        desiredTemp = desiredTemp + 5;
      }
      else{
         desiredTemp = 50;
      }
    }
    //set our state to our last state for the next check
    tempButtonLastState = tempButtonCurrentState;
    
    //checking lights
    if(currentHour == lightHourOn && lightsOn == false){
      digitalWrite(relayPin, HIGH);
      lightsOn = true;
    }
    
    //resets the lights when lightHourOff comes
    else if(currentHour == lightHourOff && lightsOn == true){
      digitalWrite(relayPin, LOW);
      lightsOn = false;
    }
    
    //checking water
    if(currentDay == wateringDay && currentHour == wateringHour && gaveWater == false){
      digitalWrite(pumpPin, HIGH);
      //water for the time calculated based on the input mL (ratio is specific to my pump system)
      delay(waterTime);
      digitalWrite(pumpPin, LOW);
      gaveWater = true;
    }
    
    //resets the watering boolean the next hour
    else if(currentHour != wateringHour && gaveWater == true){
      gaveWater = false;
    }
    
    //checking if temperature is in tolerable 5º range 
    if(tempF >= (desiredTemp-5.0) && tempF < (desiredTemp+5.0)){
      //setting two green LEDs
      setColor1(0, 0, 100);
      setColor2(0, 0, 100);
    }
    
    //checking if temperature is 5-10º colder than desired
    else if(tempF > desiredTemp-10 && tempF <= desiredTemp-5){
      //setting one blue and one green LED
      setColor1(150, 0, 0);
      setColor2(0, 0, 100);
    }
    
    //checking if temperature is 5-10º hotter than desired
    else if(tempF < desiredTemp+10 && tempF >= desiredTemp+5){
      //setting one green and one red LED
      setColor1(0, 0, 100);
      setColor2(0, 255, 0);
    }

    //checking if temperature is 10º colder than desired or more
    else if(tempF <= desiredTemp-10){
      //setting two blue LEDs
      setColor1(150, 0, 0);
      setColor2(150, 0, 0);
    }
    
    //checking if temperature is 10º hotter than desired or more
    else if(tempF >= desiredTemp+10){
      //setting two red LEDs
      setColor1(0, 255, 0);
      setColor2(0, 255, 0);
    }
   
   
  } 
  
}

Note I removed my debugging serial code, the RGB code, and the LCD code to be able to fit it all in one post.

Also it looks like my RGB values are wrong but we actually just wired them up wrong so it actually gives the correct colors.

You defined lighton in loop so every loop it will be reset to 1.

Change it to static or move def to global

Sry on a phone so its hard to type a proper explanation

gpop1: You defined lighton in loop so every loop it will be reset to 1.

Change it to static or move def to global

Sry on a phone so its hard to type a proper explanation

Ah okay I moved the button initializations out of "while(true)" loop so they aren't being wiped every loop. It still does the same thing though.

Another issue I've started having is my arduino changes ports after every upload for some reason.

I have moved all my variable definitions out of the loop code just to be sure and the same issue still arises.

How are you driving your relays? Directly from Arduino output pins or through a transistor?

The one relay is powered from a 5v Arduino pin and another is powered from a little USB adapter cube that is plugged into the wall. We added a little USB brick with two slots into the circuit of the light (it needs wall power to work) so the one USB slot powers the Arduino and the other powers the relay for the light. Then the other one (for the pump) is just hooked up to the Arduino 5V.

Both of the relays function as intended right now, despite the buttons being weird.

ok now I can see your code in the ide here's a few pointers

first use alt-t to format your code so people can read it from the forum with out having to copy it.

second "serial print" is your friend. The more complicated your code the harder it will be to find the error with out it

So looking at the code I see some problems

    int timeOnButtonCurrentState = 0;
    int timeOnButtonLastState = 0;
    int timeOffButtonCurrentState = 0;
    int timeOffButtonLastState = 0;
    int waterButtonCurrentState = 0;
    int waterButtonLastState = 0;
    int tempButtonCurrentState = 0;
    int tempButtonLastState = 0;

    //reading timeOnButton
    timeOnButtonCurrentState = digitalRead(timeOnButtonPin);
    //if button is pushed in and also different from last read
    if (timeOnButtonCurrentState != timeOnButtonLastState && timeOnButtonCurrentState == LOW) {
      //up the time one hour or loop it back
      if (lightHourOn != 23) {
        lightHourOn = lightHourOn + 1;
      }
      else {
        lightHourOn = 0;
      }
    }
    //set our state to our last state for the next check
    timeOnButtonLastState = timeOnButtonCurrentState;

    //timeOnButtonCurrentState is pushed so ==1 (high) as you used pinMode(timeOnButtonPin, INPUT);
    //maybe that should have been a pull up and the common of the button hooked to negative
    //timeOnButtonLastState would be 0 as the line above  int timeOffButtonLastState = 0; made
    //timeOffButtonLastState and set it to 0.
    //if (timeOnButtonCurrentState != timeOnButtonLastState && timeOnButtonCurrentState == LOW)
    //would never be true unless you was using a pullup input

    //  timeOnButtonLastState = timeOnButtonCurrentState; waste of time as you are reseting both to 0

If you want something to be remembered you either need to define it as a global (before setup) or add the word static to it

Yeah I moved those button variables up before the setup code. My code still has the same issues after doing that, but thanks.

Also I have a ton of serial print statements but I had to remove them in my code to post here (9000 character or less requirement)

I think I'm a bit confused as to the pull-up part. I'd show you our wiring diagram but it's pretty complicated. I can draw it out later tonight if need be.

I think I'm starting to see the issues now though. I originally thought HIGH would be when the button was pushed in but now I realize it's actually should be turning to LOW when the button is pushed.

Maybe I'm bit confused still. Either way I'm not sure why my entire circuit is turning off when I press a button.

AlexanderTheDecent: I think I'm a bit confused as to the pull-up part. I'd show you our wiring diagram but it's pretty complicated. I can draw it out later tonight if need be.

I think I see the issues now though. I originally thought HIGH would be when the button was pushed in but now I realize it's actually should be turning to LOW when the button is pushed.

a input pin sees 0v as low and 5v as high when its used like this

pinMode(timeOnButtonPin, INPUT);

so if you have a button that goes between + and the pin (timeOnButtonPin) it will read high when pressed and low when its not pressed.

in a perfect world this would be acceptable

but there are times when the button, wires etc can build up a charge that may read a few volts that can trip trick the arduino into thinking the button has been pushed so they came up with the idea of adding a resistor on the chip that can be turn on and off by code

pinMode (timeOnButtonPin, INPUT_PULLUP);

Now the pin is kept high by the resistor so the button has to short the pin to dc- for the arduino to read it as a Low

So the button goes from - to the arduino pin (timeOnButtonPin). When you press the button the arduino will see that as a low and when the button is not pressed it will see it as a high.

best thing you can do is to copy part of your code to a new window and set up serial print to see whats happening with the buttons. Once you get one to work correctly you will probably understand why the others have the same problem