const byte diagnostic = HIGH;
const int highThreshold = 120;
const int lowThreshold = 50;
// Set pins
const int Echo = 2;
const int Trigger = 3;
// Switch must be a PWM-enabled pin
const int Switch = 5;
// Duration, in milliseconds, between fade-in/out steps
const int fadeSpeed = 20;
// Duration, in minutes, of lights-on
int lightTime = 1;
// Duration, in seconds, between motion sensor checks
int motionCheckDelay = 5;
byte motionDetected = LOW;
unsigned long lastMotionCheck = millis();
unsigned long delayBetweenMotionChecks = diagnostic ? 5000 : (motionCheckDelay * 1000);
byte motionCheckState = LOW;
unsigned long lightTimeDuration = millis();
unsigned long timeToLightOff = diagnostic ? (30 * 1000) : (lightTime * 1000 * 60);
byte lightSwitchState = LOW;
/*
* Detecting moving objects with HC-SR04 ultrasonic sensor
*
* From https://www.industrialshields.com/blog/arduino-industrial-1/detecting-moving-objects-with-hc-sr04-ultrasonic-sensor-471
*
* To do:
* - Replace motion check and light-on delay() with millis for nonblocking code
* - Add PWM soft on/off [ DONE ]
* - Move motion state to function [ DONE ]
*
*/
void setup() {
if (diagnostic) Serial.begin(9600);
pinMode(Trigger, OUTPUT);
pinMode(Echo, INPUT);
digitalWrite(Echo, LOW);
// initialize digital pin LED_BUILTIN as an output.
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
// Fade in, hold 3s, fade out, on powerup
pinMode(Switch, OUTPUT);
fadeIn(Switch);
delay(3000);
fadeOut(Switch);
}
void loop() {
unsigned long timeNow = millis();
// is it time to do a motion check?
if (timeNow - lastMotionCheck > delayBetweenMotionChecks)
{
if (motionCheckState == LOW)
{
motionCheckState = HIGH;
// Motion detected?
if (motionCheck()) {
if (lightSwitchState == LOW)
{
if (diagnostic) {
Serial.print("Fading on LED for "); Serial.print(delayBetweenMotionChecks / 1000); Serial.println(" seconds.");
}
lightSwitchState = HIGH;
digitalWrite(LED_BUILTIN, HIGH);
fadeIn(Switch);
lightTimeDuration = timeNow;
}
}
}
else
{
motionCheckState = LOW;
}
lastMotionCheck = timeNow;
if (lightSwitchState == HIGH)
{
if (timeNow - lightTimeDuration > timeToLightOff && !motionDetected)
{
if (diagnostic) Serial.println("Light is on, but time's up, lights off.");
lightSwitchState = LOW;
digitalWrite(LED_BUILTIN, LOW);
fadeOut(Switch);
}
}
}
}
void fadeIn(int Pin) {
for (int fadeValue = 0 ; fadeValue <= 255; fadeValue += 5) {
analogWrite(Pin, fadeValue);
// wait for fadeSpeed (20-30) milliseconds to see the dimming effect
delay(fadeSpeed);
}
}
void fadeOut(int Pin) {
for (int fadeValue = 255 ; fadeValue >= 0; fadeValue -= 3) {
analogWrite(Pin, fadeValue);
// wait for fadeSpeed (20-30) * 2 milliseconds (fade slowly) to see the dimming effect
delay(fadeSpeed * 2);
// check for motion during fadeout, every 6 steps
// if motion, turn on light and break out of loop
if (fadeValue % 38 == 0) {
if (motionCheck()) {
lightSwitchState = HIGH;
digitalWrite(LED_BUILTIN, HIGH);
fadeIn(Switch);
lightTimeDuration = millis();
break;
}
}
}
}
bool motionCheck() {
long t;
long d;
blinkLED();
// Send 10 microsecond pulse to trigger
digitalWrite(Trigger, HIGH);
delayMicroseconds(10);
digitalWrite(Trigger, LOW);
// Listen for echo
t = pulseIn(Echo, HIGH);
// Calculate distance from echo time: d (cm) = t (us) / (2*29,5) = t (us) / 59
d = t / 59;
// Is distance within threshold range (50-200cm)?
if (d >= lowThreshold and d <= highThreshold) {
if (diagnostic) Serial.print("Motion detected at "); Serial.print(d); Serial.println(" cm.");
motionDetected = HIGH;
blinkLED();
return true;
} else {
motionDetected = LOW;
return false;
}
}
void blinkLED() {
// alternate blink depending on lightstate
digitalWrite(LED_BUILTIN, lightSwitchState ? LOW : HIGH);
delay(50);
digitalWrite(LED_BUILTIN, lightSwitchState ? HIGH : LOW);
}