Make pir sensor turn on siren for 2 minutes

I want to build an simple alarm system for my basement, and i use Blynk for turning alarm on/of etc. (the code is not 100% finish regards to on/off button)

I need help to one thing i just not understand.

When PIR sensor detect movement and goes high for 1-2 seconds i want to turn on a siren for 2 minutes. I want the siren to keep on going until i turn off with button in Blynk app or resets the board with physical switch.

Here is my code:

#define BLYNK_PRINT Serial
#include <WiFi.h>
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>

int siren = 18;
int pirSensor = 4;
int orangeLED = 27;
int otherLED = 26;

int pirValue = 0;

int durationValue = 0;

//---SET THE AMOUNT OF LED BLINK ON STARTUP--------------

int LEDblink = 5;
int fastBlink = 10;

//-------------------------------------------------------

//---WIFI CRIDENTIALS FOR CONNECTING TO BLYNK SERVER-----

char auth[] = *****";

char ssid[] = "*****";
char pass[] = "*****";

//-------------------------------------------------------

//---DECLARATION OF BLYNK TIMER -------------------------

BlynkTimer timer;

//-------------------------------------------------------

void setup() {
  Serial.begin(9600);
  Blynk.begin(auth, ssid, pass);
  pinMode(siren, OUTPUT);
  pinMode(pirSensor, INPUT);
  pinMode(orangeLED, OUTPUT);
  pinMode(otherLED, OUTPUT);
  digitalWrite(siren, LOW);
  Sequence();
  timer.setInterval(100L, alarm);
}

void Sequence() {
  for (int i=0; i<LEDblink; i++) {
    digitalWrite(orangeLED, HIGH);
    delay(1000);
    digitalWrite(orangeLED, LOW);
    delay(1000);
  }
  for (int b=0; b<fastBlink; b++) {
    digitalWrite(orangeLED, HIGH);
    delay(150);
    digitalWrite(orangeLED, LOW);
    delay(150);
  }
  digitalWrite(otherLED, HIGH);
  digitalWrite(orangeLED, LOW); 
  alarm();
}

void alarm() {
  pirValue = digitalRead(pirSensor);
  Serial.println(pirValue);

  if (pirValue == 1) {
    digitalWrite(siren, HIGH);
    Blynk.virtualWrite(V1, "ALARM AKTIVERT!");
  }
  else {
    digitalWrite(siren, LOW);
    Blynk.virtualWrite(V1, " ");
  }
}

void loop() {
  Blynk.run();
  timer.run();
}

When PIR sensor detect movement and goes high for 1-2 seconds

are you sure it's configured to stay high only for 1 or 2 seconds ? won't it stay high as long as presence is detected ?

One way to do this type of code is what is called a "state machine".

You need to maintain in a variable the state of your system (alarmOff, alarmOn, alarmExpired for example) and detect the events that will let you change from one state to the other.

for example the start state is alarmOff
if your PIR is triggered, then you start the alarm, take note of the current time, and go to state alarmOn

in the state alarmOn, you monitor the Blynk event or if 2 minutes have elapsed.

  • if you get the Blynk event, then you turn off the alarm and go back to alarmOff state.
  • if 2 minutes have gone by since you started the alarm, you turn off the alarm and go to alarmExpired state

in the alarmExpired state, you await for the Blynk event again to go back to alarmOff state (and possibly check your PIR if you want to re-trigger).

PS: Note that in many countries alarms are regulated and can't go on forever if the siren can be heard from outside your property

Thanks :slight_smile:

Bit do you have an example code please?

I could write one but that’s not the purpose of this forum

Give it a try and we will help along the way

Ok.

to not let you without some structure for a state machine, here is what a simple code could be (without all your bells and whistles)

enum : byte {alarmOFF, alarmON, alarmExpired} currentState = alarmOFF;

const byte pirPin = 4;
const byte sirenPin = 18;
unsigned long sirenStartTime;
const unsigned long maxSirenDuration = 120000ul; // 2 minutes in ms
bool deactivationReceived = false;

void checkCommunication()
{
  /* some code that would set deactivationReceived to true if you get the message */
  if (random(0, 100) > 90) deactivationReceived = true; // just random stuff here
}


void checkAlarm()
{
  switch (currentState) {
    case alarmOFF: // alarm is OFF, we check if it needs to be turned on
      if (digitalRead(pirPin) == HIGH) {
        digitalWrite(sirenPin, HIGH); // start siren
        sirenStartTime = millis();
        deactivationReceived = false;
        currentState = alarmON;
      }
      break;

    case alarmON: // alarm is ON, we check if it's being deactivated or max time elapsed
      if (deactivationReceived) {
        // we received the notification to turn the siren off
        digitalWrite(sirenPin, LOW); // turn off siren
        currentState = alarmOFF;
      } else if (millis() - sirenStartTime >= maxSirenDuration) {
        digitalWrite(sirenPin, LOW); // turn off siren
        currentState = alarmExpired;
      }
      break;

    case alarmExpired: // alarm sounded and was not deactivated in due time
      if (deactivationReceived) {
        // we received the notification to turn the siren off
        currentState = alarmOFF;
      }
      break;
  }
}

void setup() {
  pinMode(sirenPin, OUTPUT);
  pinMode(pirPin, INPUT);
}

void loop() {
  checkAlarm();
  checkCommunication();
  // here you can do other stuff if needed if it's not too long (and non blocking of course)
}

My tutorial on How to write Timers and Delays in Arduino has a number of potted solutions, but not exactly that one.

@J-M-L state machine is the way to go.

The millisDelay class in How to write Timers and Delays in Arduino will reduce the number of states you have to handle because it keeps track of if the timer is running or not.
the millisDelay timer is also easy to stop when you get the override, just use the stop() method

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.