Miguel Montiel Vega
Published

Water Level Monitoring and Flood Alert System

Smart water level & flood alert system using LoRaWAN. Real-time data + env. sensors = early warnings with zero connectivity cost.

IntermediateWork in progress11 hours132
Water Level Monitoring and Flood Alert System

Things used in this project

Hardware components

RAK19007
×1
RAK3172
×1
RAK12030
×1
RAK1906
×1
RAK12003
×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

Water Level Monitoring and Flood Alert System

C/C++
// Project : Water Level Monitoring and Flood Alert System
// Board: RAK3372 (STM32WL5)
// Base: RAK1907
// Sensors: RAK12005 Rain Sensor, RAK12030 BME680 Environment Sensor, RAK12032 DS18B20 Temperature Sensor
// Display: RAK1821 OLED (Optional)
// LoRaWAN Platform: The Things Stack
 
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME680.h> // For BME680
#include <OneWire.h>         // For DS18B20
#include <DallasTemperature.h> // For DS18B20
#include <LoRaWan-RAK3372.h> // LoRaWAN library for RAK3372
#include <SPI.h>
 
// 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 RAIN_SENSOR_PIN WB_A0 // Analog pin for rain sensor
#define ONE_WIRE_BUS WB_IO2 // Pin for DS18B20 sensor (ambient/water temperature)
 
// Sensor Instances
Adafruit_BME680 bme; // I2C
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
 
// Variables to store readings
bool is_raining;
float air_temperature, air_humidity, air_pressure;
float external_temperature; // DS18B20 Temperature
 
void setup() {
  Serial.begin(115200);
  delay(100);
  Serial.println("Starting IoT Flood Monitoring...");
 
  Wire.begin();
 
  // Initialize BME680
  if (!bme.begin()) {
    Serial.println("Could not find a valid BME680 sensor, check wiring!");
    while (1);
  }
  bme.setTemperatureOversampling(BME680_OVERSAMPLING_8X);
  bme.setHumidityOversampling(BME680_OVERSAMPLING_4X);
  bme.setPressureOversampling(BME680_OVERSAMPLING_4X);
  bme.setIIRFilterSize(BME680_FILTER_SIZE_3);
  bme.setGasHeater(320, 150);
 
  // Initialize DS18B20
  sensors.begin();
 
  // Initialize rain sensor
  pinMode(RAIN_SENSOR_PIN, INPUT);
 
  // Initialize LoRaWAN
  if (api.lorawan.setRegion(loraWanRegion)) {
    Serial.printf("LoRaWAN region configured to %d\n", loraWanRegion);
  } else {
    Serial.println("Failed to configure 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)...");
  if (api.lorawan.join()) {
    Serial.println("Joined LoRaWAN network!");
  } else {
    Serial.println("Failed to join LoRaWAN network. Retrying...");
    while(1);
  }
  delay(2000);
}
 
void loop() {
  readSensors();
  sendLoRaWANData();
 
  // Flood alert logic (simple example)
  if (is_raining && air_pressure < 980.0) { // Rain and low pressure
    Serial.println("POSSIBLE FLOOD ALERT!");
    // A specific, higher priority alert packet could be sent here
  }
 
  Serial.println("Entering low power mode...");
  api.system.sleep.all(120000); // Sleep for 2 minutes (120000 ms)
}
 
void readSensors() {
  // Read rain sensor
  int rain_analog_val = analogRead(RAIN_SENSOR_PIN);
  is_raining = (rain_analog_val < 500); // Simple threshold: if value is low, it's raining
  Serial.printf("Rain Sensor: %d (Raining: %s)\n", rain_analog_val, is_raining? "Yes" : "No");
 
  // Read BME680
  if (!bme.performReading()) {
    Serial.println("Failed to perform BME680 reading.");
  } else {
    air_temperature = bme.temperature;
    air_humidity = bme.humidity;
    air_pressure = bme.pressure / 100.0; // hPa
    Serial.printf("Air Temp: %.2f C, Air Hum: %.2f %%, Air Pres: %.2f hPa\n", air_temperature, air_humidity, air_pressure);
  }
 
  // Read DS18B20
  sensors.requestTemperatures();
  external_temperature = sensors.getTempCByIndex(0);
  if (external_temperature == DEVICE_DISCONNECTED_C) {
    Serial.println("Failed to read DS18B20.");
  } else {
    Serial.printf("External Temp: %.2f C\n", external_temperature);
  }
}
 
void sendLoRaWANData() {
  // Payload format:
  // Byte 0: Rain (0 or 1)
  // Byte 1-2: Air temperature (x100)
  // Byte 3-4: Air humidity (x100)
  // Byte 5-6: Air pressure (x10)
  // Byte 7-8: External temperature (x100)
 
  uint8_t payload[9]; // Adjusted payload size
  int16_t air_temp_int = (int16_t)(air_temperature * 100);
  uint16_t air_hum_int = (uint16_t)(air_humidity * 100);
  uint16_t air_pres_int = (uint16_t)(air_pressure * 10);
  int16_t ext_temp_int = (int16_t)(external_temperature * 100);
 
  payload[0] = is_raining? 1 : 0;
  payload[1] = (air_temp_int >> 8) & 0xFF;
  payload[2] = air_temp_int & 0xFF;
  payload[3] = (air_hum_int >> 8) & 0xFF;
  payload[4] = air_hum_int & 0xFF;
  payload[5] = (air_pres_int >> 8) & 0xFF;
  payload[6] = air_pres_int & 0xFF;
  payload[7] = (ext_temp_int >> 8) & 0xFF;
  payload[8] = ext_temp_int & 0xFF;
 
  Serial.print("Sending LoRaWAN packet: ");
  for (int i = 0; i < sizeof(payload); i++) {
    Serial.printf("%02X ", payload[i]);
  }
  Serial.println();
 
  if (api.lorawan.send(sizeof(payload), payload, 1, true)) {
    Serial.println("LoRaWAN packet sent successfully.");
  } else {
    Serial.println("Failed to send LoRaWAN packet.");
  }
}
 
// Example Payload Formatter (Decoder) for The Things Stack (Custom Javascript)
/*
function decodeUplink(input) {
  var data = {};
  var bytes = input.bytes;
 
  // Decode Rain (1 byte, boolean)
  data.is_raining = (bytes[0] === 1);
 
  // Decode air temperature (2 bytes, int16, x100)
  data.air_temperature = ((bytes[1] << 8 | bytes[2]) / 100.0);
 
  // Decode air humidity (2 bytes, uint16, x100)
  data.air_humidity = ((bytes[3] << 8 | bytes[4]) / 100.0);
 
  // Decode air pressure (2 bytes, uint16, x10)
  data.air_pressure = ((bytes[5] << 8 | bytes[6]) / 10.0);
 
  // Decode external temperature (2 bytes, int16, x100)
  data.external_temperature = ((bytes[7] << 8 | bytes[8]) / 100.0);
 
  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