I've built a timer to control a hydroponic plant setup, but i'm having issues with reliability. Sometimes it will go for days without error, other times it'll fail to turn off the lights at night and back on in the morning. There were times where it would fail to turn the pump off too, and possibly on too but I haven't caught it in the act.
If the lights fail to turn on or off, both fail, not just one. If I physically press the buttons it works as expected. When I noticed the pump failing, the serial monitor reported that it had switched it off as normal, but it didn't. I never caught what the serial monitor said after the lights failed, failures are far more infrequent because they're only triggered twice a day vs 16 times for the pump.
I have tested the buttons responsiveness and they seem to work fine with a press as short as 50ms, I use 2 button presses of 600ms to be safe.
I'm uncertain as to whether the pins fail to be written high to low, or the remote fails to respond to the input.
rtc library used
Outlet control remote
Important/potentially problematic parts of the code:
#include <DS3231.h> // RTC Library
DS3231 rtc(SDA, SCL); // Define rtc pins
// Pins
const uint8_t remote[10] = {A1, A0, A3, A2, 2, 3, 6, 5, 8}; //(OFF,ON) (8,9 active HIGH)
class Button {
public:
Button(int, String);
String device;
bool getState();
void on();
void off();
void cycle(unsigned long interval); // on for interval, off
private:
uint8_t num; // button number
bool state;
};
Button pump(1, "Pump"), light(2, "Light"), light2(3, "Light2"), air(4, "Air");
void setup() {
Serial.begin(9600);
Serial.println("BOOT UP");
rtc.begin();
for (uint8_t i = 0; i <= 8; i++) {
pinMode(remote[i], OUTPUT);
digitalWrite(remote[i], LOW);
if (i < 4) { // press each off button
digitalWrite(remote[i], HIGH);
delay(200);
digitalWrite(remote[i], LOW);
delay(200);
}
}
// rtc.setTime(0, 54, 10); // set current 24h time (hour, min, sec)
// rtc.setTime(5, 59, 55); // Test condition
Serial.print("CURRENT TIME: "); displayTime(rtc.getTime());
air.on(); // air always on
}
void loop() {
bool dry;
Time t = rtc.getTime();
feed(t);
if (!light.getState() && t.hour >= 6) { // turn on lights after 6AM
light.on();
light2.on();
} else if (light.getState() && t.hour < 6) {
light.off();
light2.off();
}
if (pump.getState()) { // pump should always be off outside of cycle
pump.off(); // be sure pump is off
}
}
void feed(Time t) {
if (t.sec == 0 && t.min == 0) { // only check on the hour
if (t.hour % 3 == 0) { // every 3 hours
digitalWrite(remote[8], HIGH); // cycle drip pump
pump.cycle(90); // cycle pump for 90 sec
}
pump.off(); // turn off the goddamned pump
}
if(t.sec == 0 && t.min == 10 && t.hour % 3 == 0) { // turn off drip pump after 10 min
digitalWrite(remote[8], LOW);
}
}
/***************** Button Class *****************/
Button::Button(int buttNum, String devName) {
num = buttNum - 1;
device = devName;
state = false;
}
bool Button::getState() {
return state;
}
void Button::off() {
for (uint8_t i = 0; i < 2; i++) { // do it twice because it fails sometimes *Still fails sometimes?
digitalWrite(remote[num], HIGH);
delay(600);
digitalWrite(remote[num], LOW);
delay(100);
}
state = false;
String out = device + " OFF: ";
Serial.print(out); displayTime(rtc.getTime());
}
void Button::on() {
for (uint8_t i = 0; i < 2; i++) { // do it twice because it fails sometimes *Still fails sometimes?
digitalWrite(remote[num + 4], HIGH);
delay(600);
digitalWrite(remote[num + 4], LOW);
delay(100);
}
state = true;
String out = device + " ON: ";
Serial.print(out); displayTime(rtc.getTime());
}
void Button::cycle(unsigned long interval) {
Serial.println("Cycle Begin");
unsigned long curr = millis();
while (millis() - curr < interval * 1000UL) {
if (!this->getState()) {
this->on();
}
}
this->off();
}