/*
Forum: https://forum.arduino.cc/t/problems-with-this-code/1220732
Wokwi: https://wokwi.com/projects/389095437012058113
PIR Sketch II
2024/02/07
ec2021
*/
#define WOKWI
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <RTClib.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define SSD1306_I2C_ADDRESS 0x3C
#define PIR_PIN 5
#define LED_PIN 3
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire);
#ifdef WOKWI
RTC_DS1307 rtc;
#else
RTC_DS3231 rtc;
#endif
unsigned long previousMillisTime = 0;
unsigned long ledStartTime = 0;
bool ledOn = false;
const long intervalTime = 1000;
const long ledDuration = 10 * 1000; // 10 seconds in milliseconds
struct timeType {
private:
int hour;
int minute;
unsigned long totalSeconds;
public:
void set(int Hour, int Minute) {
hour = Hour;
minute = Minute;
totalSeconds = (hour * 60 + minute) * 60;
}
unsigned long inSeconds(){
return totalSeconds;
};
};
timeType pirActive;
timeType pirDeactive;
const int LED_BRIGHTNESS = 64; // LED brightness (0-255)
unsigned long currentMillis;
DateTime now;
boolean pirIsActive = false;
void setup() {
Serial.begin(115200);
pirActive.set(13, 30);
pirDeactive.set( 8, 55);
pinMode(PIR_PIN, INPUT);
pinMode(LED_PIN, OUTPUT);
if (!rtc.begin()) {
Serial.println("Unable to find RTC");
while (1);
}
#ifndef WOKWI
if (rtc.lostPower()) {
Serial.println("RTC lost power, setting the time!");
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
#endif
display.begin(SSD1306_I2C_ADDRESS, SSD1306_I2C_ADDRESS);
display.display();
display.clearDisplay();
}
void loop() {
now = rtc.now();
handleTime(); // Display time every second
checkPIR(); // Check PIR sensor and activate LED if conditions are met
}
void handleTime() {
if (millis() - previousMillisTime >= intervalTime) {
checkPirTime();
previousMillisTime = millis();
display.clearDisplay();
display.setTextSize(2, 5);
display.setTextColor(SSD1306_WHITE);
display.setCursor(10, 20);
printWithLeadingZero(now.hour(), true);
printWithLeadingZero(now.minute(), true);
printWithLeadingZero(now.second(), false);
display.display();
}
}
void printWithLeadingZero(int number, boolean displayColon) {
if (number < 10) {
display.print("0");
}
display.print(number, DEC);
if (displayColon) {
display.print(":");
}
}
void checkPirTime() {
unsigned long timeInSeconds = (now.hour() * 60 + now.minute()) * 60;
byte mode;
if (pirDeactive.inSeconds() < pirActive.inSeconds()) {
mode = 0; // Deactivation is earlier than activation
} else {
mode = 1; // Deactivation is later than activation
}
if (pirDeactive.inSeconds() == pirActive.inSeconds()) {
mode = 2; // Deactivation is at the same time as activation
}
switch (mode) {
case 0: // Deactivation earlier
pirIsActive = !(timeInSeconds >= pirDeactive.inSeconds() &&
timeInSeconds < pirActive.inSeconds());
break;
case 1: // Deactivation later
pirIsActive = (timeInSeconds >= pirActive.inSeconds() &&
timeInSeconds < pirDeactive.inSeconds());
break;
case 2: // At the same time ... ?!! Set PIR always active
pirIsActive = true;
break;
}
if (!pirIsActive && ledOn) {
digitalWrite(LED_PIN, LOW);
ledOn = false;
}
}
void checkPIR() {
if (pirIsActive && pirActivated() && !ledOn) {
digitalWrite(LED_PIN, HIGH);
ledStartTime = millis();
ledOn = true;
Serial.println("LED turned on");
}
if (ledOn && millis() - ledStartTime >= ledDuration) {
digitalWrite(LED_PIN, LOW);
ledOn = false;
Serial.println("LED turned off");
}
}
boolean pirActivated(){
static byte lastState = LOW;
byte actState = digitalRead(PIR_PIN);
if (actState != lastState){
lastState = actState;
return lastState;
}
return false;
}