My idea was to compute an average of the analog value (post #73).
As for the latest version of the code, it seems to be working, so if you're fine with it, I'd leave it as is.
Personally, I'd refactor that entire if structure into a separate function that acts like a dual timer — the loop code would literally shrink to just four lines.
void loop() {
bool ovr = !digitalRead(SWITCH_PIN); // Manual override active?
bool isBright = !digitalRead(LDR_DIGITAL_PIN); // LOW = bright (depends on module)
bool tonofQ = tonof(isBright, ON_DELAY, OFF_DELAY, ovr);
digitalWrite(RELAY_PIN, tonofQ || ovr); // Final relay control
delay(20); // Smooth polling loop and switch debounce
}
And the behavior of this code can even be represented with a circuit diagram.
The function, for example:
bool tonof(bool x, unsigned long ton, unsigned long tof, bool reset) {
static unsigned long t; // Timestamp of the last input change or transition start
static bool q = 0; // Output state (filtered version of input x)
static bool f = 1; // Initialization flag
unsigned long now = millis(); // Current time
if (reset)
f = 1; // If reset is active, trigger reinitialization
if (f) { // Initialization
q = 0; // Reset output to false
f = 0; // Clear initialization flag
t = now; // Reset timer
}
if (x == q) {
// Input matches output, no transition in progress
// Reset timer to now to follow the current time
t = now;
} else if (now - t >= (q ? tof : ton)) {
// Delay has expired since input changed
q = x; // Output follows input after the proper delay
t = now; // Reset timer for potential next transition
}
return q; // Return the current filtered output state
}
