I have edited my question for more clarity. I am including the whole sketch. I tried to do a shorter version of my sketch, for this question, which had some typos in it and the way it was wouldn't have compiled. Also, I said that the lines I am trying to condense with || was the same for 24 hours. It isn't.
I forgot to mention the NTS (Night Time Seconds) which energizes a relay during the night for an amount of seconds different then DTS (Daytime Seconds) daytime seconds.
The full sketch works as is, but surely there is a way to condense it with OR's and not have to list a line for every hour of the day. I've tried all kinds of things, but I just can't get it to work. I've been trying to add multiple OR's to it to condense the lines, but I can't get it to work. I think it is a matter of correct (), || or {} placement and possibly the Boolean.
I will try your suggestion and get back later with results. My main mistake has been that I have tried so many things, but haven't kept track of what I did. I will keep track of them from now on. Also, I want to build a small circuit for testing. I am constantly worried that I am going to hook up my USB connection at the same time as the power supply is hooked up to the ESP-32 and fry it or my computer or phone. I did this on a different project with an Arduino and the Arduino got fried. Anyway, if you want to see what my project is, look at the comments at the beginning of my sketch. I'll get back when I can. Here is the full sketch:
// This sketch "Talliahs_Rocket_WiFi" is to control lights and watering for a Sweet Plum bonsai tree in the glass sculpture "Talliah Travels the Sky" built by me (Tom Lahue).
// To see videos of the first version of the rocket and the story behind it, see my YouTube channel "tomlahue472".
// This sketch is modified by Tom Lahue from sketch "Code_ESP32_NTP_Timer_Relay" written by Tech StudyCell and code from "The EASY Guide To Over-The_Air (OTA) Updates
// With Arduino OTA" YouTube video by Programming Electronics Academy. See Libraries for their authors. Thanks to all the authors.
#include <WiFi.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <ArduinoOTA.h>
#include <Arduino_Secrets.h>
// Replace these with your WiFi credentials
const char* ssid = SECRET_SSID;
const char* password = SECRET_PASS;
// Define NTP Server address
const char* ntpServer = "pool.ntp.org"; // Modify as per your country
const long gmtOffset_sec = 72000; // Offset from UTC (in seconds) (India GMT 5:30 // 5.5*60*60 = 19800) Modify as per your country
const int daylightOffset_sec = 3600; // Daylight offset (in seconds)
// Define relay pin
const int pump1Pin = 25; // This is the ESP-32 pin connected to the pump relay
const int pump2Pin = 27; // This is the ESP-32 pin connected to the pump 2 relay // pump 2 is a future pump for the future moss garden
const int fanPin = 26; // This is the ESP-32 pin connected to the fan
const int llPin = 32; // This is theesp-32 pin connected to the lower light relay
const int ulPin = 33; // This is the ESP-32 pin that is connected to the upper light relay
// Define OLED parameters
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 32
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// Define NTP and WiFi objects
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, ntpServer, gmtOffset_sec, daylightOffset_sec);
// Define variables for relay control
int DTS = 42; // DTS = Daytime Seconds Bonsai Tree (Pump1 ON time each hour during daytime)
int NTS = 28; // NTS = Nighttime Seconds Bonsai Tree (Pump1 ON time each hour during nighttime)
int DTSM = 55; // DTSM = Daytime Seconds Moss Garden (Pump2 ON time each half hour during daytime)
int NTSM = 35; // NTSM = Nighttime Seconds Moss Garden (Pump2 ON time each half hour during nighttime)
void setup() {
Serial.begin(115200);
// Initialize OLED display
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;);
}
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
display.setTextSize(1);
display.setCursor(0, 0);
display.println("Initializing...");
display.display();
delay(1000);
// Connect to WiFi and start Arduino OTA
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi...");
}
Serial.println("Connected to WiFi");
ArduinoOTA.begin(); // Starts OTA
// Initialize pump1 relay pin as an output
pinMode(pump1Pin, OUTPUT);
digitalWrite(pump1Pin, LOW);
// Initialize pump2 relay pin as an output
pinMode(pump2Pin, OUTPUT);
digitalWrite(pump2Pin, LOW);
// intialize fan relay pin as an output
pinMode(fanPin, OUTPUT);
digitalWrite(fanPin, LOW);
// initialize lower light relay pin as an output
pinMode(llPin, OUTPUT);
digitalWrite(llPin, LOW);
// intiialize upper light relay pin as an output
pinMode(ulPin, OUTPUT);
digitalWrite(ulPin, LOW);
// Start NTP time sync
timeClient.begin();
timeClient.update();
}
void loop() {
ArduinoOTA.handle(); // Handles a code update requst
timeClient.update(); //Updates NTP time
// Get current time
time_t currentTime = timeClient.getEpochTime();
struct tm * timeinfo;
timeinfo = localtime(¤tTime);
// Display current time on OLED
display.clearDisplay();
display.setCursor(0, 0);
display.println(" Talliah");
display.println(" Travels the Sky");
display.print(" ");
display.println(timeClient.getFormattedTime());
display.print(" DTS = ");
display.print(DTS);
display.print(" NTS = ");
display.print(NTS);
display.display();
// The following lines set the on and off times for the pump1 relay
// If the Boolean becomes true, Pin 25 is HIGH until Boolean becomes false again
bool pump1State = false;
if (timeinfo->tm_hour == 6 && timeinfo->tm_min == 00 && timeinfo->tm_sec < DTS) pump1State = true; // Waters bonsai tree at 6am for daytime amount of seconds
if (timeinfo->tm_hour == 7 && timeinfo->tm_min == 00 && timeinfo->tm_sec < DTS) pump1State = true; // Waters bonsai tree at 7am for daytime amount of seconds
if (timeinfo->tm_hour == 8 && timeinfo->tm_min == 00 && timeinfo->tm_sec < DTS) pump1State = true; // Waters bonsai tree at 8am for daytime amount of seconds
if (timeinfo->tm_hour == 9 && timeinfo->tm_min == 00 && timeinfo->tm_sec < DTS) pump1State = true; // Waters bonsai tree at 9am for daytime amount of seconds
if (timeinfo->tm_hour == 10 && timeinfo->tm_min == 00 && timeinfo->tm_sec < DTS) pump1State = true; // Waters bonsai tree at 10am for daytime amount of seconds
if (timeinfo->tm_hour == 11 && timeinfo->tm_min == 00 && timeinfo->tm_sec < DTS) pump1State = true; // Waters bonsai tree at 11am for daytime amount of seconds
if (timeinfo->tm_hour == 12 && timeinfo->tm_min == 00 && timeinfo->tm_sec < DTS) pump1State = true; // Waters bonsai tree at 12am for daytime amount of seconds
if (timeinfo->tm_hour == 13 && timeinfo->tm_min == 00 && timeinfo->tm_sec < DTS) pump1State = true; // Waters bonsai tree at 1pm for daytime amount of seconds
if (timeinfo->tm_hour == 14 && timeinfo->tm_min == 00 && timeinfo->tm_sec < DTS) pump1State = true; // Waters bonsai tree at 2pm for daytime amount of seconds
if (timeinfo->tm_hour == 15 && timeinfo->tm_min == 00 && timeinfo->tm_sec < DTS) pump1State = true; // Waters bonsai tree at 3pm for daytime amount of seconds
if (timeinfo->tm_hour == 16 && timeinfo->tm_min == 00 && timeinfo->tm_sec < DTS) pump1State = true; // Waters bonsai tree at 4pm for daytime amount of seconds
if (timeinfo->tm_hour == 17 && timeinfo->tm_min == 00 && timeinfo->tm_sec < DTS) pump1State = true; // Waters bonsai tree at 5pm for daytime amount of seconds
if (timeinfo->tm_hour == 18 && timeinfo->tm_min == 00 && timeinfo->tm_sec < DTS) pump1State = true; // Waters bonsai tree at 6pm for daytime amount of seconds
if (timeinfo->tm_hour == 19 && timeinfo->tm_min == 00 && timeinfo->tm_sec < DTS) pump1State = true; // Waters bonsai tree at 7pm for daytime amount of seconds
if (timeinfo->tm_hour == 20 && timeinfo->tm_min == 00 && timeinfo->tm_sec < DTS) pump1State = true; // Waters bonsai tree at 8pm for daytime amount of seconds
if (timeinfo->tm_hour == 21 && timeinfo->tm_min == 00 && timeinfo->tm_sec < NTS) pump1State = true; // Waters bonsai tree at 9pm for nighttime amount of seconds
if (timeinfo->tm_hour == 22 && timeinfo->tm_min == 00 && timeinfo->tm_sec < NTS) pump1State = true; // Waters bonsai tree at 10pm for nighttime amount of seconds
if (timeinfo->tm_hour == 23 && timeinfo->tm_min == 00 && timeinfo->tm_sec < NTS) pump1State = true; // Waters bonsai tree at 11pm for nighttime amount of seconds
if (timeinfo->tm_hour == 24 && timeinfo->tm_min == 00 && timeinfo->tm_sec < NTS) pump1State = true; // Waters bonsai tree at 12pm for nighttime amount of seconds
if (timeinfo->tm_hour == 1 && timeinfo->tm_min == 00 && timeinfo->tm_sec < NTS) pump1State = true; // Waters bonsai tree at 1am for nighttime amount of seconds
if (timeinfo->tm_hour == 2 && timeinfo->tm_min == 00 && timeinfo->tm_sec < NTS) pump1State = true; // Waters bonsai tree at 2am for mighttime amount of seconds
if (timeinfo->tm_hour == 3 && timeinfo->tm_min == 00 && timeinfo->tm_sec < NTS) pump1State = true; // Waters bonsai tree at 3am for nighttime amount of seconds
if (timeinfo->tm_hour == 4 && timeinfo->tm_min == 00 && timeinfo->tm_sec < NTS) pump1State = true; // Waters bonsai tree at 4am for nighttime amount of seconds
if (timeinfo->tm_hour == 5 && timeinfo->tm_min == 00 && timeinfo->tm_sec < NTS) pump1State = true; // Waters bonsai tree at 5am for nighttime amount of seconds
if (pump1State == true)
digitalWrite(pump1Pin, HIGH);
else
digitalWrite(pump1Pin, LOW);
// The following lines set the on and off times for the pump2 relay
// If the Boolean becomes true, Pin 25 is HIGH until Boolean becomes false again
bool pump2State = false;
if (timeinfo->tm_hour == 6 && timeinfo->tm_min == 30 && timeinfo->tm_sec < DTSM) pump2State = true; // Waters moss garden at 6:30am for daytime amount of seconds
if (timeinfo->tm_hour == 7 && timeinfo->tm_min == 30 && timeinfo->tm_sec < DTSM) pump2State = true; // Waters moss garden at 7:30am for daytime amount of seconds
if (timeinfo->tm_hour == 8 && timeinfo->tm_min == 30 && timeinfo->tm_sec < DTSM) pump2State = true; // Waters moss garden at 8:30am for daytime amount of seconds
if (timeinfo->tm_hour == 9 && timeinfo->tm_min == 30 && timeinfo->tm_sec < DTSM) pump2State = true; // Waters moss garden at 9:30am for daytime amount of seconds
if (timeinfo->tm_hour == 10 && timeinfo->tm_min == 30 && timeinfo->tm_sec < DTSM) pump2State = true; // Waters moss garden at 10:30am for daytime amount of seconds
if (timeinfo->tm_hour == 11 && timeinfo->tm_min == 30 && timeinfo->tm_sec < DTSM) pump2State = true; // Waters moss gardem at 11:30am for daytime amount of seconds
if (timeinfo->tm_hour == 12 && timeinfo->tm_min == 30 && timeinfo->tm_sec < DTSM) pump2State = true; // Waters moss garden at 12:30pm for daytime amount of seconds
if (timeinfo->tm_hour == 13 && timeinfo->tm_min == 30 && timeinfo->tm_sec < DTSM) pump2State = true; // Waters moss garden at 1:30pm for daytime amount of seconds
if (timeinfo->tm_hour == 14 && timeinfo->tm_min == 30 && timeinfo->tm_sec < DTSM) pump2State = true; // Waters moss graden at 2:30pm for daytime amount of seconds
if (timeinfo->tm_hour == 15 && timeinfo->tm_min == 30 && timeinfo->tm_sec < DTSM) pump2State = true; // Waters moss garden at 3:30pm for daytime amount of seconds
if (timeinfo->tm_hour == 16 && timeinfo->tm_min == 30 && timeinfo->tm_sec < DTSM) pump2State = true; // Waters moss garden at 4:30pm for daytime amount of seconds
if (timeinfo->tm_hour == 17 && timeinfo->tm_min == 30 && timeinfo->tm_sec < DTSM) pump2State = true; // Waters moss garden at 5:30pm for daytime amount of seconds
if (timeinfo->tm_hour == 18 && timeinfo->tm_min == 30 && timeinfo->tm_sec < DTSM) pump2State = true; // Waters moss garden at 6:30pm for daytime amount of seconds
if (timeinfo->tm_hour == 19 && timeinfo->tm_min == 30 && timeinfo->tm_sec < DTSM) pump2State = true; // Waters moss garden at 7:30pm for daytime amount of seconds
if (timeinfo->tm_hour == 20 && timeinfo->tm_min == 30 && timeinfo->tm_sec < DTSM) pump2State = true; // Waters moss garden at 8:30pm for daytime amount of seconds
if (timeinfo->tm_hour == 21 && timeinfo->tm_min == 30 && timeinfo->tm_sec < NTSM) pump2State = true; // Waters moss garden at 9:30pm for nighttime amount of seconds
if (timeinfo->tm_hour == 22 && timeinfo->tm_min == 30 && timeinfo->tm_sec < NTSM) pump2State = true; // Waters moss garden at 10:30pm for nighttime amount of seconds
if (timeinfo->tm_hour == 23 && timeinfo->tm_min == 30 && timeinfo->tm_sec < NTSM) pump2State = true; // Waters moss garden at 11:30pm for mighttime amount of seconds
if (timeinfo->tm_hour == 24 && timeinfo->tm_min == 30 && timeinfo->tm_sec < NTSM) pump2State = true; // Waters moss garden at 12:30am for nighttime amount of seconds
if (timeinfo->tm_hour == 1 && timeinfo->tm_min == 30 && timeinfo->tm_sec < NTSM) pump2State = true; // Waters moss garden at 1:30am for nighttime amount of seconds
if (timeinfo->tm_hour == 2 && timeinfo->tm_min == 30 && timeinfo->tm_sec < NTSM) pump2State = true; // Waters moss garden at 2:30am for nighttime amount of seconds
if (timeinfo->tm_hour == 3 && timeinfo->tm_min == 30 && timeinfo->tm_sec < NTSM) pump2State = true; // Waters moss garden at 3:30am for nighttime amount of seconds
if (timeinfo->tm_hour == 4 && timeinfo->tm_min == 30 && timeinfo->tm_sec < NTSM) pump2State = true; // Waters moss garden at 4:30am for nighttime amount of seconds
if (timeinfo->tm_hour == 5 && timeinfo->tm_min == 30 && timeinfo->tm_sec < NTSM) pump2State = true; // Waters moss garden at 5:30am for nighttime amount of seconds
if (pump2State == true)
digitalWrite(pump2Pin, HIGH);
else
digitalWrite(pump2Pin, LOW);
// The following line set the on and off times for the fan
// If the Boolean becomes true, Pin 26 is HIGH until Boolean becomes false again
bool fanState = false;
if (timeinfo->tm_hour > 4 && timeinfo->tm_hour < 22) fanState = true;
// The test is true 5:00-21:59 and false 22:00-4:59
if (fanState == true)
digitalWrite(fanPin, HIGH);
else
digitalWrite(fanPin, LOW);
// The following lines set the on and off times for the lower light relay
// If the Boolean becomes true, Pin 32 is HIGH until Boolean becomes false again
bool llState = false;
if (timeinfo->tm_hour > 4 && timeinfo->tm_hour < 22) llState = true;
// The test is true 5:00-21:59 and false 22:00-4:59
if (llState == true)
digitalWrite(llPin, HIGH);
else
digitalWrite(llPin, LOW);
// The following lines set the on and off times for the upper light relay
// If the Boolean becomes true, Pin 33 is HIGH until Boolean becomes false again
bool ulState = false;
if (timeinfo->tm_hour > 5 && timeinfo->tm_hour < 21) ulState = true;
// The test is true 6:00-20:59 and false 21:00-5:59
if (ulState == true)
digitalWrite(ulPin, HIGH);
else
digitalWrite(ulPin, LOW);
// Wait for 1 second before checking time again
delay(1000);
}
4 Answers 4
const unsigned long DTS = 42; // DTS = Daytime Amount of Seconds pump1 runs
static int old_hour = -1;
static unsigned long time_turned_on = 0;
// turn pump on when the hour changes
if (timeinfo->tm_hour != old_hour && timeinfo->tm_min == 0)
{
digitalWrite(pump1Pin, HIGH); // turn pump on
old_hour = timeinfo->tm_hour; // save hour so we know when it changes
time_turned_on = millis(); // when did we turn it on?
}
// turn pump off after DTS seconds
if ((millis() - time_turned_on) >= (DTS * 1000))
{
digitalWrite(pump1Pin, LOW); // turn pump off
}
As the comments mention, using OR logic to check each of the 24 possible hours in a single line is a wildly inefficient way to do this. In case it isn't clear why, let me explain before I answer your question. In your code snippet, you check for 3 criteria: is the hour 6, is the minute 0, is the second less than DTS? You then run a few lines of code, which are identical to the lines of code you plan to run every other hour.
If you check each hour individually, Every single time your loop runs one of the if loops will evaluate true for the first criteria. Every single time. Therefore, the only things that actually decide whether or not your few lines of code should run are the second two criteria, regarding the minute and the second. Because of this, you can remove the first criteria from the if statement. In other words, if(timeinfo0>tm_min==0 && timeinfo->time_sec<DTS){ run code here}
is all you have to do.
However, since this can be a useful approach in other scenarios, it is still good to learn. You would do something like this:
if ( (timeinfo->tm_hour==0 && timeinfo->tm_min==0 && timeinfo->time_sec < DTS) || (timeinfo->tm_hour==1 && timeinfo->tm_min==0 && timeinfo->time_sec < DTS) || (timeinfo->tm_hour==2 && timeinfo->tm_min==0 && timeinfo->time_sec < DTS) ..... || (timeinfo->tm_hour==23 && timeinfo->tm_min==0 && timeinfo->time_sec < DTS)){run code here}
Expanding on InBedded16’s answer, with a more "formal logic" point of view...
You have 24 conditions that make pump1State
true
, and all look the
same except for the hour being tested for. Then, the variable
pump1State
becomes true
when any of the conditions is true. You
can therefore combine all these conditions into one using the or
operator (also spelled ||
). The condition for turning (or keeping) the
pump on is then:
(hour == 0 and min == 0 and sec < DTS)
or (hour == 1 and min == 0 and sec < DTS)
...
or (hour == 23 and min == 0 and sec < DTS)
And here is where a bit of logic can help you simplify the expression. By applying the distributivity of ‘and’ over ‘or’, you can factor the test for the minutes and the seconds, which gives you this simpler expression:
(hour == 0 or hour == 1 or ... or hour == 23) and min == 0 and sec < DTS
However, given that the hour is an integer between 0 and 23, the parethesized sub-expression is always true, thus:
true and min == 0 and sec < DTS
Given that true
is the identity for ‘and’, you can remove it
from the expression. You end up with simply:
min == 0 and sec < DTS
This is why you are being told to take the hour out of the equation: it follows from simple logic arguments that the hour is actually irrelevant.
In actual code, you may write:
if (timeinfo->tm_min == 0 && timeinfo->tm_sec < DTS)
digitalWrite(pump1Pin, HIGH);
else
digitalWrite(pump1Pin, LOW);
Edit: Answering the updated question.
Now your watering time depends on whether it is day or night. You can still apply the distributivity of ‘and’ over ‘or’, as I showed above, independently for daytime and nighttime. The condition is then:
(hour == 6 or hour == 7 or ... or hour == 20) and min == 0 and sec < DTS
or
(hour == 21 or hour == 22 or ... or hour == 5) and min == 0 and sec < NTS
The parenthesized expressions can be simplified:
(hour >= 6 and hour < 21) and min == 0 and sec < DTS
or
(hour >= 21 or hour < 6) and min == 0 and sec < NTS
Applying the distributivity again, min == 0
can be factored:
min == 0 and
(
(hour >= 6 and hour < 21) and sec < DTS
or
(hour >= 21 or hour < 6) and sec < NTS
)
This is easier to write if you define an auxiliary boolean variable
daytime
, which is hour >= 6 and hour < 21
. Using this variable, the
condition becomes:
min == 0 and ((daytime and sec < DTS) or (not daytime and sec < NTS))
Alternatively, you can define an integer variable watering_time
which
is DTS
in daytime and NTS
in nighttime. Then the condition is the
same as in the previous version of this answer, with DTS
replaced by
watering_time
:
min == 0 and sec < watering_time
In code, this could be written as:
int watering_time;
if (timeinfo->tm_hour >= 6 && timeinfo->tm_hour < 21)
watering_time = DTS;
else
watering_time = NTS;
pump1State = mtimeinfo->tm_min == 0 && timeinfo->tm_sec < watering_time;
I tried multiple ways to use ||, but as soon as I add a second ||, it doesn't work like I would think it should. I built a circuit for bench testing to check results of each change of the sketch. My trouble was with the hours, but I edited the minutes while troubleshooting so I wouldn't have to wait so long to see the results. I worked on the trouble with a retired programmer I know (my wife) and she came up with something similar to what Edgar Bonet suggested. Here is the solution to condensing the lines in the sketch:
// set pump1 on and off times
// If the Boolean becomes true, ESP-32 Pin 25 is HIGH until the Boolean becomes false again
bool pump1State = false;
// Water bonsai tree on the hour 6am-9pm for DTS amount of seconds
if (timeinfo->tm_hour >=6 && timeinfo->tm_hour <=21 && timeinfo->tm_min == 0 && timeinfo->tm_sec <DTS) pump1State = true;
// Water bonsai tree on the hour 10pm-5am for NTS amount of seconds
if (timeinfo->tm_hour >=22 || timeinfo->tm_hour <=5 && timeinfo->tm_min == 0 && timeinfo->tm_sec < NTS) pump1State = true;
if (pump1State == true)
digitalWrite(pump1Pin, HIGH);
else
digitalWrite(pump1Pin, LOW);
// set pump2 on and off times
// If the Boolean becomes true, ESP-32 Pin 27 is HIGH until Boolean becomes false again
bool pump2State = false;
// Water moss garden on the half hour 6am-9pm for DTS amount of seconds
if (timeinfo->tm_hour >=6 && timeinfo->tm_hour <=5 && timeinfo->tm_min == 30 && timeinfo->tm_sec <DTSM) pump2State = true;
// Water moss garden on the half hour 10pm-5am for NTS amount of seconds
if (timeinfo->tm_hour >=22 || timeinfo->tm_hour <=5 && timeinfo->tm_min == 30 && timeinfo->tm_sec <NTSM) pump2State = true;
if (pump2State == true)
digitalWrite(pump2Pin, HIGH);
else
digitalWrite(pump2Pin, LOW);
-
You are missing parentheses around
timeinfo->tm_hour >=22 || timeinfo->tm_hour <=5
: the&&
operator has higher precedence than||
, and without those parentheses the expression would be interpreted astm_hour >=22 || (tm_hour <=5 && tm_min == 0 && tm_sec < NTS)
, which is not what you mean.Edgar Bonet– Edgar Bonet04/07/2025 06:58:37Commented Apr 7 at 6:58 -
Thanks, that explains why the water drained all the way at night. I checked on it at around 23:20 and the pump was running constantly.Tom Lahue– Tom Lahue04/08/2025 15:19:05Commented Apr 8 at 15:19
const int pum1Pin = 25
and also afterint DTS = 42
.