Gustavs Andersons
Published © GPL3+

Security Station

An device that you can place on objects that require surveillance.

IntermediateFull instructions provided5 hours47
Security Station

Things used in this project

Hardware components

Espressif ESP32 Development Board - Developer Edition
Espressif ESP32 Development Board - Developer Edition
×1
LM2596 Buck Converter
from 12v to 5v https://www.aliexpress.com/item/1005007508685885.html?spm=a2g0o.productlist.main.1.ff28Ig2kIg2kmh&algo_pvid=3c8c396f-5692-4dae-a1c9-54e4d2b031fe&algo_exp_id=3c8c396f-5692-4dae-a1c9-54e4d2b031fe-0&pdp_ext_f=%7B%22order%22%3A%226397%22%2C%22eval%22%3A%221%2
×1
Dc jack
https://www.aliexpress.com/item/1005010695352286.html?spm=a2g0o.order_list.order_list_main.75.6e831802fWcvwi
×1
UPS
+ 2x 19650 batteries https://www.aliexpress.com/item/1005010398471367.html?spm=a2g0o.order_list.order_list_main.63.6e831802fWcvwi
×1
HLK-LD2410S
https://www.aliexpress.com/item/1005007196626302.html?spm=a2g0o.order_list.order_list_main.58.6e831802fWcvwi
×1
WS2812B Digital RGB LED Flexi-Strip 144 LED - 1 Meter
Seeed Studio WS2812B Digital RGB LED Flexi-Strip 144 LED - 1 Meter
×1
Buzzer
Buzzer
×2
General Purpose Transistor NPN
General Purpose Transistor NPN
×3

Software apps and online services

Arduino IDE
Arduino IDE
MIT App Inventor 2
MIT App Inventor 2

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)
3D Printer (generic)
3D Printer (generic)

Story

Read more

Custom parts and enclosures

3D case model P1

3D case model P2

3D case model P3

Code

ESP32 code

C/C++
#include <Arduino.h>
#include <HLK-LD2410S.h>
#include <FastLED.h>
#include "BluetoothSerial.h"
BluetoothSerial SerialBT;

// =======================
// LD2410S SENSOR SETUP
// =======================

unsigned long lastStatusMillis = 0;
constexpr size_t SERIAL_NUMBER_BUFFER_SIZE = 16;

// Sensor 1
constexpr int SENSOR1_RX_PIN = 16;
constexpr int SENSOR1_TX_PIN = 17;
LD2410S sensor1(Serial1, SENSOR1_RX_PIN, SENSOR1_TX_PIN);

// Sensor 2
constexpr int SENSOR2_RX_PIN = 22;
constexpr int SENSOR2_TX_PIN = 21;
LD2410S sensor2(Serial2, SENSOR2_RX_PIN, SENSOR2_TX_PIN);

// =======================
// LED STRIP SETUP
// =======================

constexpr int LED_PIN = 5;
constexpr int NUM_LEDS = 18;

CRGB leds[NUM_LEDS];

// =======================
// PSU CHECK SETTINGS
// =======================

constexpr int UPS_DETECT_PIN = 25;

const unsigned long YELLOW_FLASH_INTERVAL = 30000;
const unsigned long YELLOW_FLASH_TIME = 200;
const CRGB DIM_YELLOW = CRGB(50, 50, 0);

// =======================
// BUZZER SETTINGS
// =======================

unsigned long beepTime = 80;
unsigned long pauseTime1 = 0;
unsigned long pauseTime2 = 8000;

constexpr int BUZZER1_PIN = 33;
constexpr int BUZZER2_PIN = 32;

unsigned long lastBuzzerMillis = 0;
int buzzerState = 0;

// =======================
// ALARM SETTINGS
// =======================

const unsigned long ALARM_DURATION_MS = 5UL * 60UL * 1000UL; // 5 minutes
bool alarmTriggered = false;
unsigned long alarmStartMillis = 0;
bool previousMotionDetected = false;

// LED brightness: 0 - 255
constexpr uint8_t LED_BRIGHTNESS = 255;

// Wave color
constexpr uint8_t WAVE_RED   = 255;
constexpr uint8_t WAVE_GREEN = 255;
constexpr uint8_t WAVE_BLUE  = 255;

// Lower number = faster movement
constexpr unsigned long WAVE_SPEED_MS = 40;

// Lower number = faster strobe
constexpr unsigned long STROBE_SPEED_MS = 75;

// Bigger number = shorter trail
constexpr int WAVE_FADE_AMOUNT = 60;

unsigned long lastWaveMillis = 0;
unsigned long lastStrobeMillis = 0;

int wavePosition = 0;
bool strobeOn = true;

bool alarmArmed = false;

// =======================
// BLUETOOTH STATUS SETTINGS
// =======================

unsigned long lastBluetoothStatusMillis = 0;
const unsigned long BLUETOOTH_STATUS_INTERVAL = 2000;

// =======================
// Sensor parameters read function
// =======================

void sensorParamRead() {
  // Common parameters
  uint32_t farDistance = 0;
  uint32_t nearDistance = 0;
  uint32_t delayTime = 0;
  uint32_t freqStatus = 0;
  uint32_t freqDistance = 0;
  uint32_t responseTime = 0;
  // Read common parameters - Sensor 1
  Serial.println();
  Serial.println("==== Reading Sensor 1 Parameters ====");
  if (sensor1.readCommonParametersCommand(farDistance, nearDistance, delayTime, freqStatus, freqDistance, responseTime)) {
    Serial.printf("Far Distance: %lu\n", farDistance);
    Serial.printf("Near Distance: %lu\n", nearDistance);
    Serial.printf("Delay Time: %lu\n", delayTime);
    Serial.printf("Frequency Status: %lu\n", freqStatus);
    Serial.printf("Frequency Distance: %lu\n", freqDistance);
    Serial.printf("Response Time: %lu\n", responseTime);
  } else {
    Serial.println("Failed to read sensor parameters");
  }
  // Read common parameters - Sensor 2
  Serial.println();
  Serial.println("==== Reading Sensor 2 Parameters ====");
  if (sensor2.readCommonParametersCommand(farDistance, nearDistance, delayTime, freqStatus, freqDistance, responseTime)) {
    Serial.printf("Far Distance: %lu\n", farDistance);
    Serial.printf("Near Distance: %lu\n", nearDistance);
    Serial.printf("Delay Time: %lu\n", delayTime);
    Serial.printf("Frequency Status: %lu\n", freqStatus);
    Serial.printf("Frequency Distance: %lu\n", freqDistance);
    Serial.printf("Response Time: %lu\n", responseTime);
  } else {
    Serial.println("Failed to read sensor parameters");
  }
}

// =======================
// Sensor info read function
// =======================

void sensorRead() {
  if (millis() - lastStatusMillis >= 1000) {
    Serial.println();
    Serial.println("==== Sensor 1 ====");
    Serial.printf("Target Distance: %d cm\n", sensor1.getDistance());
    Serial.println(sensor1.isMotionDetected() ? "Motion" : "Static");
    Serial.println("==== Sensor 2 ====");
    Serial.printf("Target Distance: %d cm\n", sensor2.getDistance());
    Serial.println(sensor2.isMotionDetected() ? "Motion" : "Static");
    lastStatusMillis = millis();
  }
}

// =======================
// Alarm LED function
// =======================

void alarmLed() {
  unsigned long currentMillis = millis();
  // Update strobe state
  if (currentMillis - lastStrobeMillis >= STROBE_SPEED_MS) {
    lastStrobeMillis = currentMillis;
    strobeOn = !strobeOn;
  }
  // Move wave position
  if (currentMillis - lastWaveMillis >= WAVE_SPEED_MS) {
    lastWaveMillis = currentMillis;
    wavePosition++;
    if (wavePosition >= NUM_LEDS) {
      wavePosition = 0;
    }
  }
  FastLED.setBrightness(LED_BRIGHTNESS);
  FastLED.clear();
  if (strobeOn) {
    for (int i = 0; i < NUM_LEDS; i++) {
      int distance = abs(i - wavePosition);
      distance = min(distance, NUM_LEDS - distance);
      int brightness = 255 - distance * WAVE_FADE_AMOUNT;
      if (brightness < 0) {
        brightness = 0;
      }
      leds[i] = CRGB(
        (WAVE_RED   * brightness) / 255,
        (WAVE_GREEN * brightness) / 255,
        (WAVE_BLUE  * brightness) / 255
      );
    }
  }
  FastLED.show();
}

// =======================
// Alarm buzzer function
// =======================

void alarmBuzzers() {
  unsigned long currentMillis = millis();
  if (buzzerState == 0) { // buzzer1 on
    digitalWrite(BUZZER1_PIN, HIGH);
    digitalWrite(BUZZER2_PIN, LOW);
    if (currentMillis - lastBuzzerMillis >= beepTime) {
      lastBuzzerMillis = currentMillis;
      buzzerState = 1;
    }
  }
  else if (buzzerState == 1) { // buzzer1 pause
    digitalWrite(BUZZER1_PIN, LOW);
    digitalWrite(BUZZER2_PIN, LOW);
    if (currentMillis - lastBuzzerMillis >= pauseTime1) {
      lastBuzzerMillis = currentMillis;
      buzzerState = 2;
    }
  }
  else if (buzzerState == 2) { // buzzer2 on
    digitalWrite(BUZZER1_PIN, LOW);
    digitalWrite(BUZZER2_PIN, HIGH);
    if (currentMillis - lastBuzzerMillis >= beepTime) {
      lastBuzzerMillis = currentMillis;
      buzzerState = 3;
    }
  }
  else if (buzzerState == 3) { // buzzer2 pause
    digitalWrite(BUZZER1_PIN, LOW);
    digitalWrite(BUZZER2_PIN, LOW);
    if (currentMillis - lastBuzzerMillis >= pauseTime2) {
      lastBuzzerMillis = currentMillis;
      buzzerState = 0;
    }
  }
}

// =======================
// Motion check function
// =======================

void checkMotion() {
  FastLED.clear();
  FastLED.show();
  digitalWrite(BUZZER1_PIN, LOW);
  digitalWrite(BUZZER2_PIN, LOW);

  if (sensor1.isMotionDetected()) { // Motion from sensor1
    alarmLed();
    alarmBuzzers();
  }
  if (sensor2.isMotionDetected()) { // Motion from sensor2
    alarmLed();
    alarmBuzzers();
  }
}

// =======================
// Bluetooth function
// =======================

void bluetoothControl() {
  if (SerialBT.available()) {
    String command = SerialBT.readStringUntil('\n');
    command.trim();
    Serial.print("Bluetooth command: ");
    Serial.println(command);
    if (command == "ARM") {
      alarmArmed = true;
      alarmTriggered = false;
      previousMotionDetected = false;
      fill_solid(leds, NUM_LEDS, CRGB::Green);
      FastLED.show();
      delay(500);
      FastLED.clear();
      FastLED.show();
    }
    else if (command == "DISARM") {
      alarmArmed = false;
      stopAlarm();
      FastLED.clear();
      FastLED.show();
      digitalWrite(BUZZER1_PIN, LOW);
      digitalWrite(BUZZER2_PIN, LOW);
      fill_solid(leds, NUM_LEDS, CRGB::Red);
      FastLED.show();
      delay(500);
      FastLED.clear();
      FastLED.show();
    }
  }
}

void sendBluetoothStatus() {
  if (!SerialBT.hasClient()) {
    return; // If not connected - skip
  }

  unsigned long currentMillis = millis();

  if (currentMillis - lastBluetoothStatusMillis >= BLUETOOTH_STATUS_INTERVAL) {
    lastBluetoothStatusMillis = currentMillis;

    bool upsPowerConnected = digitalRead(UPS_DETECT_PIN) == LOW;

    String alarmStatus = alarmArmed ? "Aktva" : "Izslgta";
    String upsStatus = upsPowerConnected ? "Savienots" : "Atvienots";

    String sensor1Status = sensor1.isMotionDetected() ? "Kustba" : "Statisks";
    String sensor2Status = sensor2.isMotionDetected() ? "Kustba" : "Statisks";

    float sensor1DistanceM = sensor1.getDistance() / 100.0;
    float sensor2DistanceM = sensor2.getDistance() / 100.0;

    String message = "";

    message += alarmStatus;

    message += ";";
    message += upsStatus;

    message += ";";
    message += sensor1Status;

    message += ";";
    message += String(sensor1DistanceM, 2);
    message += " m";

    message += ";";
    message += sensor2Status;

    message += ";";
    message += String(sensor2DistanceM, 2);
    message += " m";

    SerialBT.println(message);
  }
}

// =======================
// UPS check function
// =======================

void checkUPS() {
  bool upsPowerConnected = digitalRead(UPS_DETECT_PIN) == LOW;
  if (upsPowerConnected) {
    // Connected to power
  }
  else {
    // Flash ylow every 30sec
    static unsigned long lastYellowFlashMillis = millis() - YELLOW_FLASH_INTERVAL;
    static unsigned long yellowFlashStartMillis = 0;
    static bool yellowFlashOn = false;

    unsigned long currentMillis = millis();

    if (!yellowFlashOn && currentMillis - lastYellowFlashMillis >= YELLOW_FLASH_INTERVAL) {
      lastYellowFlashMillis = currentMillis;
      yellowFlashStartMillis = currentMillis;
      yellowFlashOn = true;

      fill_solid(leds, NUM_LEDS, DIM_YELLOW);
      FastLED.show();
    }

    if (yellowFlashOn && currentMillis - yellowFlashStartMillis >= YELLOW_FLASH_TIME) {
      yellowFlashOn = false;

      FastLED.clear();
      FastLED.show();
    }
  }
}

// =======================
// Alarm function
// =======================

void startAlarm() {
  alarmTriggered = true;
  alarmStartMillis = millis();
  lastWaveMillis = millis();
  lastStrobeMillis = millis();
  lastBuzzerMillis = millis();
  wavePosition = 0;
  strobeOn = true;
  buzzerState = 0;
}

void stopAlarm() {
  alarmTriggered = false;
  FastLED.clear();
  FastLED.show();
  digitalWrite(BUZZER1_PIN, LOW);
  digitalWrite(BUZZER2_PIN, LOW);
}

void checkAlarmTrigger() {
  bool motionDetected = sensor1.isMotionDetected() || sensor2.isMotionDetected();
  if (alarmArmed && !alarmTriggered && motionDetected && !previousMotionDetected) {
    startAlarm();
  }
  previousMotionDetected = motionDetected;
}

void runAlarm() {
  unsigned long currentMillis = millis();
  if (currentMillis - alarmStartMillis >= ALARM_DURATION_MS) {
    stopAlarm();
    return;
  }
  alarmLed();
  alarmBuzzers();
}

// =======================
// setup
// =======================

void setup() {
  // Start serial
  Serial.begin(115200);
  delay(2000);
  Serial.println();
  Serial.println("Starting ...");

  SerialBT.begin("SS-01");
  Serial.println("Bluetooth started. Pair with SS-01");

  // Start sensors
  sensor1.begin();
  sensor2.begin();

  delay(1000);

  // LED setup
  FastLED.addLeds<WS2812B, LED_PIN, GRB>(leds, NUM_LEDS);
  FastLED.clear();
  FastLED.show();

  // Buzzer setup
  pinMode(BUZZER1_PIN, OUTPUT);
  pinMode(BUZZER2_PIN, OUTPUT);
  digitalWrite(BUZZER1_PIN, LOW);
  digitalWrite(BUZZER2_PIN, LOW);

  // UPS pin setup
  pinMode(UPS_DETECT_PIN, INPUT_PULLUP);

  Serial.println();
  Serial.println("Setup complete");

  // Start sensors
  sensor1.loop();
  sensor2.loop();
  delay(100);
  sensorParamRead();
}

void loop() {
  sensor1.loop();
  sensor2.loop();
  sensorRead();
  bluetoothControl();
  checkAlarmTrigger();
  if (alarmTriggered) {
    runAlarm();
  } else {
    checkUPS();
    digitalWrite(BUZZER1_PIN, LOW);
    digitalWrite(BUZZER2_PIN, LOW);
  }
  sendBluetoothStatus();
}

Credits

Gustavs Andersons
10 projects β€’ 7 followers
Like coding πŸ–₯️ , drone photography + FPV πŸ›« , soldering πŸ”‹ , 3d modeling πŸ–±οΈ , animations & video editing + event lights and audio 🎚️ !

Comments