Miguel Montiel Vega
Published

Gas Detector and Seismic Alert System for Home/Industrial Sa

This system integrates gas leak detection and seismic activity monitoring into a single, low-power IoT solution. Using precise sensors and r

IntermediateWork in progress10 hours107
Gas Detector and Seismic Alert System for Home/Industrial Sa

Things used in this project

Hardware components

RAK19003
×1
rak4630
×1
RAK12004
×1
RAK12027
×1
RAK12033
×1
RAK1921
×1
WisGate Edge Lite 2
Arduino WisGate Edge Lite 2
×1

Software apps and online services

Arduino IDE
Arduino IDE
The Things Stack
The Things Industries The Things Stack

Hand tools and fabrication machines

Multitool, Screwdriver
Multitool, Screwdriver

Story

Read more

Code

Gas Detector and Seismic Alert for Security

C/C++
// Project : Gas Detector and Seismic Alert for Security
// Board: RAK4631 (Nordic NRF52840)
// Base: RAK1903
// Sensors: RAK12035 MQ2 Gas Sensor, RAK12047 Dimron D75 Earthquake Sensor, RAK12033 IM-42652 6-axis Accelerometer
// Display: RAK1821 OLED
// LoRaWAN Platform: The Things Stack
 
#include <Wire.h>
#include <Adafruit_GFX.h>    // For OLED
#include <Adafruit_SSD1306.h> // For OLED
#include <LoRaWan-RAK4631.h> // LoRaWAN library for RAK4631
#include <SPI.h>
 
// Library for accelerometer (example, may vary based on exact IM-42652 model)
// #include <Adafruit_LIS3DH.h> // If using LIS3DH
// For IM-42652, you might need a library like SparkFun_ICM-20948_Arduino_Library or similar,
// or read directly via I2C/SPI. We'll use a simplified placeholder.
 
// LoRaWAN Configuration (OTAA) - REPLACE WITH YOUR THE THINGS STACK CREDENTIALS!
uint8_t nodeDeviceEUI[8] = {0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX};
uint8_t nodeAppEUI[8] = {0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX};
uint8_t nodeAppKey[16] = {0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX};
 
// LoRaWAN Region Configuration
LoRaMacRegion_t loraWanRegion = LORAMAC_REGION_EU868;
 
// Sensor Pins
#define MQ2_GAS_SENSOR_PIN WB_A0 // Analog pin for MQ2 gas sensor
#define EARTHQUAKE_SENSOR_PIN WB_IO1 // Digital pin for D75 earthquake sensor
 
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
 
// Instances
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); // I2C for OLED
// Adafruit_LIS3DH accel = Adafruit_LIS3DH(); // If using LIS3DH
 
// Variables to store readings and states
int mq2_gas_value;
bool earthquake_detected = false;
float accel_x, accel_y, accel_z;
bool movement_detected = false;
 
void setup() {
  Serial.begin(115200);
  delay(100);
  Serial.println("Starting IoT Security Detector...");
 
  Wire.begin();
 
  // Initialize OLED
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;);
  }
  display.display();
  delay(2000);
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0,0);
  display.println("Starting...");
  display.display();
 
  // Initialize sensor pins
  pinMode(MQ2_GAS_SENSOR_PIN, INPUT);
  pinMode(EARTHQUAKE_SENSOR_PIN, INPUT); // D75 is digital
 
  // Initialize accelerometer (placeholder)
  // if (!accel.begin(0x18)) { // LIS3DH I2C address
  //   Serial.println("Could not find accelerometer, check wiring!");
  //   display.clearDisplay(); display.setCursor(0,0); display.println("Error Accel!"); display.display();
  //   while (1);
  // }
  // accel.setRange(LIS3DH_RANGE_4_G); // Configure range
 
  // Initialize LoRaWAN
  if (api.lorawan.setRegion(loraWanRegion)) {
    Serial.printf("LoRaWAN region set to %d\n", loraWanRegion);
  } else {
    Serial.println("Failed to set LoRaWAN region.");
    while (1);
  }
 
  if (api.lorawan.setAppKey(nodeAppKey) &&
     api.lorawan.setAppEUI(nodeAppEUI) &&
     api.lorawan.setDevEUI(nodeDeviceEUI)) {
    Serial.println("LoRaWAN credentials configured.");
  } else {
    Serial.println("Failed to configure LoRaWAN credentials.");
    while (1);
  }
 
  Serial.println("Attempting to join LoRaWAN network (OTAA)...");
  display.clearDisplay(); display.setCursor(0,0); display.println("Joining LoRaWAN..."); display.display();
  if (api.lorawan.join()) {
    Serial.println("Joined LoRaWAN network!");
    display.clearDisplay(); display.setCursor(0,0); display.println("Joined LoRaWAN!"); display.display();
  } else {
    Serial.println("Failed to join LoRaWAN network. Retrying...");
    display.clearDisplay(); display.setCursor(0,0); display.println("Join Failed!"); display.display();
    while(1);
  }
  delay(2000);
}
 
void loop() {
  readSensors();
  displayData();
 
  // Send alert only if something is detected
  if (mq2_gas_value > 700 || earthquake_detected || movement_detected) { // Alert thresholds
    sendLoRaWANAlert();
    delay(5000); // Small pause after sending alert
  }
 
  Serial.println("Entering low power mode...");
  api.system.sleep.all(10000); // Sleep for 10 seconds for constant monitoring
}
 
void readSensors() {
  // Read MQ2 gas sensor
  mq2_gas_value = analogRead(MQ2_GAS_SENSOR_PIN);
  Serial.printf("MQ2 Gas: %d\n", mq2_gas_value);
 
  // Read D75 earthquake sensor
  earthquake_detected = (digitalRead(EARTHQUAKE_SENSOR_PIN) == LOW); // Assuming LOW when detected
  Serial.printf("Earthquake D75: %s\n", earthquake_detected? "DETECTED" : "NORMAL");
 
  // Read accelerometer (placeholder)
  // sensors_event_t event;
  // accel.getEvent(&event);
  // accel_x = event.acceleration.x;
  // accel_y = event.acceleration.y;
  // accel_z = event.acceleration.z;
  // Serial.printf("Accel X: %.2f, Y: %.2f, Z: %.2f\n", accel_x, accel_y, accel_z);
 
  // Simple movement detection logic with accelerometer (placeholder)
  // movement_detected = (abs(accel_x) > 1.0 || abs(accel_y) > 1.0 || abs(accel_z) > 1.0); // Movement threshold
  movement_detected = false; // Placeholder if actual accelerometer is not used
  Serial.printf("Movement: %s\n", movement_detected? "DETECTED" : "NORMAL");
}
 
void displayData() {
  display.clearDisplay();
  display.setCursor(0,0);
  display.printf("Gas: %d\n", mq2_gas_value);
  display.printf("Seismic: %s\n", earthquake_detected? "ALERT!" : "OK");
  display.printf("Move: %s\n", movement_detected? "ALERT!" : "OK");
 
  if (mq2_gas_value > 700) {
    display.setCursor(0, 40);
    display.println("HIGH GAS!");
  }
  if (earthquake_detected) {
    display.setCursor(0, 50);
    display.println("SEISMIC DETECTED!");
  }
  if (movement_detected) {
    display.setCursor(0, 50); // Might overlap, adjust position
    display.println("MOVEMENT!");
  }
  display.display();
}
 
void sendLoRaWANAlert() {
  // Alert payload format:
  // Byte 0: Alert Type (1=Gas, 2=Seismic, 3=Movement)
  // Byte 1: Severity (1=Low, 2=Medium, 3=High)
  uint8_t payload[2]; // Changed from 5 to 2 based on description
 
  if (mq2_gas_value > 700) {
    payload[0] = 1; // Type: Gas
    payload[1] = 3; // Severity: High
    Serial.println("Sending HIGH GAS alert!");
  } else if (earthquake_detected) {
    payload[0] = 2; // Type: Seismic
    payload[1] = 3; // Severity: High
    Serial.println("Sending SEISMIC alert!");
  } else if (movement_detected) {
    payload[0] = 3; // Type: Movement
    payload[1] = 2; // Severity: Medium
    Serial.println("Sending MOVEMENT alert!");
  } else {
    return; // No alert to send
  }
 
  if (api.lorawan.send(sizeof(payload), payload, 1, true)) { // Port 1, confirmed
    Serial.println("LoRaWAN alert sent successfully.");
  } else {
    Serial.println("Failed to send LoRaWAN alert.");
  }
}
 
// Example Payload Formatter (Decoder) for The Things Stack (Custom Javascript)
/*
function decodeUplink(input) {
  var data = {};
  var bytes = input.bytes;
 
  var alertType = bytes[0];
  var severity = bytes[1];
 
  switch (alertType) {
    case 1:
      data.alert_type = "Gas";
      break;
    case 2:
      data.alert_type = "Seismic";
      break;
    case 3:
      data.alert_type = "Movement";
      break;
    default:
      data.alert_type = "Unknown";
  }
 
  switch (severity) {
    case 1:
      data.severity = "Low";
      break;
    case 2:
      data.severity = "Medium";
      break;
    case 3:
      data.severity = "High";
      break;
    default:
      data.severity = "Unknown";
  }
 
  return {
    data: data,
    warnings: [],
    errors: []
  };
}

Credits

Miguel Montiel Vega
11 projects • 9 followers
Teacher at Maude Studio & Erasmus+ project member: "Developing Solutions to Sustainability Using IoT" (2022-1-PT01-KA220-VET-000090202)
Thanks to Jose Miguel Fuentes.

Comments