A PIR sensor? It works like a regular pushbutton if you set the jumpers on the back correctly.
In the sketch I'm about to post, you don't need anything hooked up except a button to ESP Nano pin 2 (I've never used one, I'm assuming it's a GPIO but if not, change the pin 2 to a GPIO for your board).
It's based on example sketches blinkWithoutDelay and stateChangeDetection and I implemented a state machine (the switch (buttonState)
down to its closing curly brace) to mash things together.
This is a hands on hobby and you trying out this sketch will be better than my explaining it to you. It has parts relevant to what you're doing (as do the next two sketches that you'll sort of Frankenstein together to get what you're after).
/* detect button state change and blink without delay
Hallowed31
2024-07-21
A combo of example sketches blinkWithoutDelay and stateChangeDetection
because I seldom have a use for just a blinking led,
want to ditch the delay and prefer locked states of switch/case vs if/else
where possible. But if a repeating action for some time is desired, there's
a countdown timer that decrements every second while holding the LED HIGH
for 5 seconds.
This button method also automatically negates need for delay debouncer
since it's button state, not digitalRead driven
Works as intended
*/
const int buttonPin = 2; // connect button between 2 and GND
const int ledPin = LED_BUILTIN;
int buttonState, lastButtonState, buttonPushCounter;
int ledState;
unsigned long previousMillis;
unsigned long interval = 10; // interval to check buttonState vs lastButtonState
unsigned long lastLedActiveMillis;
const long countdownInterval = 1000; // to countdown in one second intervals
int timer = 15; // countdown the timer 5*1000 to hold the LED state HIGH every fourth button press
bool ledActivated; // keep track of appropriate message every fourth press which lights LED
void setup() {
Serial.begin(115200);
Serial.println(F("stateChangeWithoutDelayDeluxe by Hallowed31"));
pinMode(buttonPin, INPUT_PULLUP);
pinMode(ledPin, OUTPUT);
resetVariables();
}
void loop() {
unsigned long currentMillis = millis();
buttonState = digitalRead(buttonPin);
if (buttonState != lastButtonState) {
if (currentMillis - previousMillis > interval) {
previousMillis = currentMillis;
switch (buttonState) {
case LOW:
ledState = HIGH;
buttonPushCounter++;
Serial.println(F("ON"));
Serial.print("Button pressed: ");
Serial.print(buttonPushCounter);
if (buttonPushCounter == 1) Serial.println(" time");
else Serial.println(" times");
if (buttonPushCounter % 4 == 0) {
ledActivated = true;
digitalWrite(ledPin, ledState);
Serial.println(F("Activate LED"));
while (timer >= 0) {
unsigned long ledActiveMillis = millis();
if (ledActiveMillis - lastLedActiveMillis >= countdownInterval) {
lastLedActiveMillis = ledActiveMillis;
Serial.println(timer);
timer--;
}
}
if (timer <= 0)
{
timer = 5; // reset to five, or don't and make it truly one-shot
}
}
break;
case HIGH:
ledState = LOW;
switch (ledActivated) {
case false:
Serial.println(F("OFF"));
break;
case true:
Serial.println(F("Deactivate LED"));
ledActivated = false;
break;
}
digitalWrite(ledPin, ledState);
break;
}
}
lastButtonState = buttonState;
}
}
void resetVariables() {
buttonState = HIGH;
lastButtonState = HIGH;
buttonPushCounter = 0;
previousMillis = 0;
lastLedActiveMillis = 0;
ledState = LOW;
ledActivated = false;
}
You'll want to use a state machine. Make a global variable, something like int propState = 0;
and use switch/case to increment that variable when something changes. At the end, loop it back to the idle state propState = 0;
for the next trick or treater.
The next sketch you would type in chars in Serial to do the associated function, as selected by the state machine switch (vivMode) {
to the end of its curly brace.
In each of these functions, you could do the thing you need to do (turn on pump and lights or off or whatever) and since yours is to be a sequence, at the end of each function just set the vivMode
state value to whatever you need.
Note the datatype in this example is a char because that's the datatype used when you type chars into the Serial monitor.
You could change that to int or byte as needed based on the suggestion I gave about setting states at the end of each function to automatically move to the next state.
char vivMode;
void setup() {
Serial.begin(9600);
Serial.println(F("charDrivenStateMachine"));
delay(500);
Serial.println();
vivMode = '0'; // start at vivMode 0
}
void loop() {
if (Serial.available() > 0) {
vivMode = Serial.read();
switch (vivMode) {
case '0':
vivModeZero();
break;
case '1':
vivModeOne();
break;
case '2':
vivModeTwo();
break;
case '3':
vivModeThree();
break;
case '4':
vivModeFour();
break;
}
}
}
void vivModeZero() {
Serial.println("vivMode 0");
Serial.println("everything off function here");
Serial.println("");
}
void vivModeOne() {
Serial.println("vivMode 1");
Serial.println("lights on, heater on, mister on function here");
Serial.println("");
}
void vivModeTwo() {
Serial.println("vivMode 2");
Serial.println("lights on, heater on, mister off function here");
Serial.println("");
}
void vivModeThree() {
Serial.println("vivMode 3");
Serial.println("lights on, heater off, mister off function here");
Serial.println("");
}
void vivModeFour() {
Serial.println("vivMode 4");
Serial.println("lights on, heater off, mister on function here");
Serial.println("");
}
Finally, there's the pircatDoor sketch. Since your motion detector is probably going to be one of those, give it a rip and chop it up to use in your Texas Chainsaw Massacre face mask of a sketch you might opt to sew together from the others I've posted. Of note here is the pirState, again a state machine.
I can't stress how valuable a concept a state machine is to making Hallowe'en props with Arduino.
int ledPin = 13;
int pirPin = 2;
int ledState;
int lastLedState;
int pirState;
int lastPirState;
int eventCounter = 0;
unsigned long stopwatchRuntime = 0;
unsigned long lastStopwatchCheck = 0; // keep track of time that no detection changed to detction
unsigned long stopwatchTimer = 0; // keep track of time at every new detection event
unsigned long holdDoorOpenTimer = 0;
const long interval = 1000;
int timer = 5;
void setup() {
pinMode(ledPin, OUTPUT);
pinMode(pirPin, INPUT);
Serial.begin(115200);
Serial.println("PIRdetectWaitDoUndo");
Serial.println();
pirState = 0; // set initial state
lastPirState = 0;
ledState = 0;
lastLedState = 0;
}
void loop() {
stopwatchRuntime = millis(); // start free running timer that never actually stops
pirState = digitalRead(pirPin);
switch (pirState) {
case 0:
/* cat got door open by moving, time for device to obey cat */
theCatsOutOftheBag();
break;
case 1:
/* cat moving to open door, ie not just sleeping there */
ledState = pirState;
theCatsInTheBag();
break;
}
}
void theCatsInTheBag() {
stopwatchTimer = stopwatchRuntime - lastStopwatchCheck;
if (lastPirState == 0) {
lastPirState = 1;
eventCounter += 1;
}
catDetectING(); // print Serial debugging data for events and timer
if (stopwatchTimer > 3000) { // if cat keeps moving over timeframe of three seconds...
digitalWrite(ledPin, ledState); // do the thing (turn led on in this test)
lastLedState = ledState; // and set state to act upon so as soon as cat through door, it holds
}
}
void theCatsOutOftheBag() {
lastPirState = pirState;
lastStopwatchCheck = stopwatchRuntime;
if (lastLedState == 1) {
if (stopwatchRuntime - holdDoorOpenTimer >= interval) {
holdDoorOpenTimer = stopwatchRuntime;
catDetectED(); // print Serial debugging data for events, timer and door countdown
timer--;//decrease timer count
if (timer == -1)// less than 0
{
timer = 5; // reset timer variable for next door opening event
lastLedState = lastPirState;
}
}
digitalWrite(ledPin, lastLedState);
}
else{
lastLedState = 0;
digitalWrite(ledPin, lastLedState);
}
}
void catDetectED(){
Serial.print("Event Counter: ");
Serial.print(eventCounter);
Serial.print("\tTime since detection: ");
Serial.print(stopwatchTimer);
Serial.print("\tDoor open timer: ");
Serial.println(timer);
}
void catDetectING(){
Serial.print("Event Counter: ");
Serial.print(eventCounter);
Serial.print("\tTime since detection: ");
Serial.println(stopwatchTimer);
}
Good luck.
I'll try to check back in but the clock is ticking and I need every day between now and All Hallow's to finish my haunt. Yes, haunters are insane; but, if you get it, you get it.
For those about to Haunt, I salute you! 