The general approach for non-blocking code is to use millis() and compare durations:
bool active = false;
unsigned long start = 0;
const unsigned long duration = 25000; // 25 seconds
void loop() {
unsigned long now = millis();
if (start_condition) {
active = true;
start = now;
turn_on();
}
if (active && now - start >= duration) {
active = false;
turn_off();
}
}
Properly written non-blocking code never uses delay() but instead records time stamps and
compares durations to see when to do something.
One trap for beginners: Never compare times, only durations!
Because millis() wraps around (after 2^32 msec which is ~49.7 days) you can have a start time
that is greater than the current time, but if you subtract 2 times it always gives a proper
duration (as long as the duration is itself less than 50 days)
So the only correct way to do time checks with millis is:
(later_time - earlier_time) compared-with duration
There is a library I like that makes all of this so easy: "Ticker"
One subtlety with Ticker is the resolution - it can use milliseconds or microseconds, and the time can be specified in milliseconds or microsecoonds.
The default is to use microsecond resolution with millisecond specification:
Ticker x(callback, time_in_millisec); // repeat defaults to 0 (continuous), resolution to MICROS
This only works for durations up to 70 minutes, for longer durations you have to use milliseconds:
Ticker x(callback, time_in_millisec, /*repeat=*/0, /*resolution=*/MILLIS);
When specifying a callback for ticker you can use a function that takes no args and no return value:
void mycallback() {dostuff();}
Ticker x(mycallback, ....);
Or you can use a C++ lambda expression to create an unnamed function that does the same thing.
Ticker x([](){dostuff();}, ....);
Here is your code rewritten with Ticker with some assumptions on my part about what you intend, you should be able to adapt the ideas
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Ticker.h>
#define ONE_WIRE_BUS 4
#define TEMPERATURE_PRECISION 9
#define motor 6
#define valve 7
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
// use a separatethreshold for on/off to give some hysteresis
const float on_thld = 36;
const float off_thld = 35;
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
void check_sensors();
// This Ticker will call check_sensors every 2seconds
Ticker ticker_sensors(check_sensors, 2000, 0);
// When we turn on the valves, we'll use this to schedule turning on the motor 5 seconds later (a 1-time event each time we do start())
Ticker ticker_motor_start({ digitalWrite(motor, LOW); }, 5000, 1);
// if you dislike this syntax, you could use:
// void turn_on_motor() {digitalWrite(motor, LOW);}
// Ticker ticker_motor_start(turn_on_motor, 500, 1);
// When we turn off the motor, we'll use this to schedule turning off the valve 5 seconds later (a 1-time event each time we do start())
Ticker ticker_valve_off({ digitalWrite(valve, HIGH); }, 5000, 1);
void check_sensors() {
sensors.requestTemperatures();
float temp = sensors.getTempCByIndex(0);
Serial.println(temp);
Serial.println((char)176);
Serial.println("C | ");
if (temp > on_thld) {
if (ticker_motor_start.state() != RUNNING) {
// cancel any pending valve turn-off
ticker_valve_off.stop();
// turn on valve and schedule motor turn-on
digitalWrite(valve, HIGH);
ticker_motor_start.start();
}
} else if (temp < off_thld) {
if (ticker_motor_start.state() == RUNNING) {
// turn off motor and schedule valves to turn off
digitalWrite(motor, HIGH);
ticker_valve_off.start();
}
}
display.clearDisplay();
display.setCursor(0, 0);
display.setTextSize(1);
display.println("Temperature");
display.setCursor(0, 30);
display.println("Soil & Water Engg.");
display.setTextSize(2);
display.setCursor(0,10);
display.println(temp);
display.setCursor(75, 10);
display.println("C");
display.setCursor(0,40);
display.display();
}
void setup() {
Serial.begin(115200);
digitalWrite(motor, HIGH); // set value before enabling output
digitalWrite(valve, HIGH); // set value before enabling output
pinMode(motor, OUTPUT);
pinMode(valve, OUTPUT);
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64
Serial.println(F("SSD1306 allocation failed"));
for(;;);
}
display.setTextColor(WHITE);
ticker_sensors.start();
}
void loop() {
// update all the tickers - if they're not running it's a no-op
// They only check times and decide when to call their callbacks during update()
ticker_sensors.update();
ticker_motor_start.update();
ticker_valve_off.update();
}