Knetrix

Physical Security System With ESP32

Hardware Used

ESP32 Serves As The System’s Brain, Offering Dual-Core 240 MHz Processing, Built-In Wi-Fi/Bluetooth, and GPIO For Multiple Sensors / Tools.

Software / Technology Used

How Was Project Done?

First Of All, Sensors and Tools Had To Be Connected With ESP32 On The Breadboard. Due To Some Restrictions Of ESP32, It Took Me Some Time To Determine Which Pins Would Be Used. Finally, I Got The Result In The Pictures Below.

Then I Had To Install Services Like MQTT Broker (Mosquitto), Node-RED On The Server. Since I Don’t Have A Server, I Decided To Run These Services On My Own Computer. It Is Possible To Install These Services As Docker Services On An Operating System Like Ubuntu Server. There Are Even Systems Like IOTstack That Make This Process Easier.

But I Didn’t Go That Route Because I Was Introduced To The Debian-Based Diet-Pi Operating System, Which Has Very Low System Requirements and Includes Optimized Services That Are Ready To Be Installed With A Single Command.

Since I Use Multiple Services, I Didn’t Want To Use A Single Diet-Pi Operating System. I Decided To Install Each Service On A Separate Diet-Pi Operating System and Keep The Operability High. But There Were Two Ways To Do This:

Of Course, I Chose The Second Way. I Installed Proxmox And Made Settings Such As Static IP. At This Stage, You Need To Install Diet-Pi As A Normal Operating System In Proxmox And Turn It Into A Container. Then We Can Get Clone From This Container With One Click. The Amount Of RAM Used By A Single Diet-Pi Container Is Only 20-30 MB.

I Installed My Services In These Containers I created and I Also Assigned Static IP To All Of Them.

I Used Homer For Easy Access To The Web Interface Of These Services I Created (I Installed It In Mosquitto Container).

ESP32 Code

#include <WiFi.h>
#include <DHT.h>
#include <Servo.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <MQTTClient.h>
#include <ArduinoJson.h>
#define DHTPIN 13
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
#define MQ2PIN 32
#define PIRPIN 14
int pinStateCurrent = LOW;
int pinStatePrevious = LOW;
#define SERVOPIN 27
Servo servo;
#define LASERPIN 26
#define LDRPIN 33
#define BUZZERPIN 16
#define REDPIN 21
#define GREENPIN 19
#define BLUEPIN 18
struct Button
{
  const uint8_t PIN;
  bool pressed;
};
Button button1 = {17, false};
unsigned long button_time = 0;
unsigned long last_button_time = 0;
void IRAM_ATTR InterruptButton();
#define SCREEN_WIDTH 128 // OLED Display Width, In Pixels.
#define SCREEN_HEIGHT 64 // OLED Display Height, In Pixels.
#define OLED_RESET -1    // No Reset Pin.
#define SCREEN_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
#define CLIENT_ID "ESP32-001"
const char WIFI_SSID[] = "[REDACTED]";
const char WIFI_PASSWORD[] = "[REDACTED]";
const char MQTT_BROKER_ADRRESS[] = "192.168.1.160";
const int MQTT_PORT = 1883;
const char MQTT_USERNAME[] = "Knetrix";
const char MQTT_PASSWORD[] = "[REDACTED]";
#define PUBLISH_TOPIC "ESP32-001/send"
#define SUBSCRIBE_TOPIC "ESP32-001/receive"
#define PUBLISH_INTERVAL 5000 // 5 Second.
IPAddress local_IP(192, 168, 1, 180);
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);
IPAddress primaryDNS(192, 168, 1, 1);
IPAddress secondaryDNS(1, 1, 1, 1);
WiFiClient network;
MQTTClient mqtt = MQTTClient(256);
unsigned long lastPublishTime = 0;
void connectToMQTT();
void sendToMQTT();
int mqttMessage = 0;
void messageHandler(String &topic, String &payload);
void setup()
{
  Wire.begin(23, 22);
  // Initialize OLED Object.
  if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS))
  {
    Serial.println(F("SSD1306 Allocation Failed"));
    for (;;)
      ;
  }
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(WHITE);
  WiFi.config(local_IP, gateway, subnet, primaryDNS, secondaryDNS);
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  display.setCursor(0, 16);
  display.print("Connecting To Wifi");
  display.display();
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(1000);
    display.print(".");
    display.display();
  }
  display.fillRect(0, 16, 128, 8, BLACK);
  display.display();
  display.setCursor(40, 0);
  display.println("Welcome!");
  display.setCursor(0, 16);
  display.println("Connected To Wi-Fi!");
  display.setCursor(0, 24);
  display.print("IP: ");
  display.print(WiFi.localIP());
  display.display();
  connectToMQTT();
  mqtt.publish("ESP32-001/status", "boot");
  Serial.begin(115200);
  dht.begin();
  pinMode(PIRPIN, INPUT);
  servo.attach(SERVOPIN);
  pinMode(LASERPIN, OUTPUT);
  pinMode(BUZZERPIN, OUTPUT);
  pinMode(REDPIN, OUTPUT);
  pinMode(GREENPIN, OUTPUT);
  pinMode(BLUEPIN, OUTPUT);
  pinMode(button1.PIN, INPUT_PULLUP);
  attachInterrupt(button1.PIN, InterruptButton, FALLING);
  // Initial State (Alarm Off)
  analogWrite(REDPIN, 0);
  analogWrite(GREENPIN, 255);
  analogWrite(BLUEPIN, 0);
  // Initial State (Door Off)
  servo.write(0); // Door Close.
  // Initial State (Lazer On)
  digitalWrite(LASERPIN, HIGH);
}
void loop()
{
  mqtt.loop();
  if (!mqtt.connected())
  {
    display.fillRect(0, 32, 128, 8, BLACK);
    display.fillRect(0, 40, 128, 8, BLACK);
    display.fillRect(0, 48, 128, 8, BLACK);
    connectToMQTT();
  }
  else if (millis() - lastPublishTime > PUBLISH_INTERVAL)
  {
    sendToMQTT();
    lastPublishTime = millis();
  }
}
void IRAM_ATTR InterruptButton()
{
  button_time = millis();
  if (button_time - last_button_time > 250)
  {
    ets_printf("ISR Triggered.\n");
    button1.pressed = !button1.pressed;
    last_button_time = button_time;
  }
}
void connectToMQTT()
{
  mqtt.begin(MQTT_BROKER_ADRRESS, MQTT_PORT, network);
  mqtt.onMessage(messageHandler);
  display.setCursor(0, 32);
  display.print("Connecting To MQTT");
  display.display();
  while (!mqtt.connect(CLIENT_ID, MQTT_USERNAME, MQTT_PASSWORD))
  {
    delay(1000);
    display.print(".");
    display.display();
  }
  mqtt.subscribe(SUBSCRIBE_TOPIC);
  display.fillRect(0, 32, 128, 8, BLACK);
  display.setCursor(0, 32);
  display.print("Connected To MQTT!");
  display.display();
}
void sendToMQTT()
{
  mqttMessage++;
  float h = dht.readHumidity();
  float t = dht.readTemperature();
  int mq2Value = map(analogRead(MQ2PIN), 0, 4096, 0, 100);
  int pirValue = digitalRead(PIRPIN);
  int ldrValue = analogRead(LDRPIN);
  bool buttonPressed = button1.pressed;
  JsonDocument message;
  message["temperature"] = isnan(t) ? -999 : t;
  message["humidity"] = isnan(h) ? -999 : h;
  message["smoke"] = mq2Value;
  message["pir"] = pirValue;
  message["ldr"] = ldrValue;
  message["button"] = buttonPressed;
  char messageBuffer[512];
  serializeJson(message, messageBuffer);
  mqtt.publish(PUBLISH_TOPIC, messageBuffer);
  Serial.println("Sent To MQTT:");
  Serial.print("- Topic: ");
  Serial.println(PUBLISH_TOPIC);
  Serial.print("- Payload:");
  Serial.println(messageBuffer);
  Serial.println();
  display.setCursor(0, 40);
  display.print("Send To MQTT! - " + String(mqttMessage));
  display.setCursor(0, 48);
  display.print("Button State:");
  if (buttonPressed)
    display.print("ON");
  else
    display.print("OFF");
  display.display();
  display.fillRect(0, 40, 128, 8, BLACK);
  display.fillRect(0, 48, 128, 8, BLACK);
}
void beep(int delayms);
bool elseTriggered = false;
void messageHandler(String &topic, String &payload)
{
  // Serial.println("Received From MQTT:");
  // Serial.println("- Topic: " + topic);
  // Serial.print("- Payload: ");
  // Serial.println(payload);
  // You Can Process The Incoming Data As Json Object, Then Control Something.
  JsonDocument doc;
  deserializeJson(doc, payload);
  bool ldrAlarmState = doc["ldrAlarmState"].as<bool>();
  bool sensorAlarmState = doc["sensorAlarmState"].as<bool>();
  bool doorState = doc["doorState"].as<bool>();
  if (ldrAlarmState || sensorAlarmState)
  {
    analogWrite(REDPIN, 255);
    analogWrite(GREENPIN, 0);
    analogWrite(BLUEPIN, 0);
    beep(500);
    elseTriggered = false;
  }
  else
  {
    if (!elseTriggered)
    {
      analogWrite(REDPIN, 0);
      analogWrite(GREENPIN, 255);
      analogWrite(BLUEPIN, 0);
      elseTriggered = true;
    }
  }
  if (doorState)
  {
    digitalWrite(LASERPIN, LOW);
    servo.write(180);
  }
  else
  {
    servo.write(0);
    digitalWrite(LASERPIN, HIGH);
  }
}
void beep(int delayms)
{
  digitalWrite(BUZZERPIN, HIGH);
  delay(delayms);
  digitalWrite(BUZZERPIN, LOW);
  delay(delayms);
}

Node-RED Flow

Node-RED Dashboard

Telegram

Grafana

IoT MQTT Panel