#include <FirebaseESP32.h>
#include <SD.h>
#include <DHT.h>
#include <Wire.h>
#include <SoftwareSerial.h>
#include <HTTPClient.h>
#include <SPI.h>
#include <Audio.h> // Include your audio library
#include <esp_task_wdt.h>
// Firebase setup
#define FIREBASE_HOST "your-project-id.firebaseio.com" // Your Firebase project
#define FIREBASE_AUTH "your-firebase-auth-key" // Your Firebase API key
// Pin Definitions
#define DHTPIN 13
#define DHTTYPE DHT11
#define GAS_PIN 34
#define SIM800_TX 17
#define SIM800_RX 16
#define SD_CS 5 // Chip select pin for SD card
#define AUDIO_PIN 23 // Pin connected to the audio output
DHT dht(DHTPIN, DHTTYPE);
SoftwareSerial sim800(SIM800_RX, SIM800_TX);
Audio audio; // Create an Audio object
// Firebase and SIM800 Setup
FirebaseData fbData;
String basePath = "/sensorData";
// Message and Sound Setup
String incomingSMS;
// SD Card setup for sound
File soundFile;
// Maximum number of retries for sending data to Firebase
const int MAX_RETRIES = 2;
// Watchdog timer configuration
const int WDT_TIMEOUT = 10; // Timeout set to 10 seconds
// Function prototypes
void sendCommandToSIM800(String command);
void checkSMSForCodes(String sms);
void playSound(String soundFileName);
void sendDataToFirebase(float temp, float hum, int gas, int AQI, String collectedTime, String sentTime);
String getISOTime();
int calculateAQI(int gasValue);
void playAlertAudio();
void playDisasterAudio(String code);
void rebootSystem();
void fullSystemScan();
void emergencyReboot();
void initSIM800();
bool isPlaying = false; // To track if audio is currently playing
void setup() {
Serial.begin(115200);
sim800.begin(9600);
esp_task_wdt_init(WDT_TIMEOUT, true);
esp_task_wdt_add(NULL);
// Initialize DHT sensor
dht.begin();
// Initialize SD card
if (!SD.begin(SD_CS)) {
Serial.println("SD card initialization failed");
return;
}
audio.setPin(AUDIO_PIN); // Set the pin for audio output
Serial.println("SD card initialized successfully");
// Firebase initialization
Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH);
Firebase.reconnectWiFi(true);
// SIM800 initialization
initSIM800(); // Initialize the SIM module
}
void loop() {
static unsigned long lastSendTime = 0;
static int retryCount = 0;
esp_task_wdt_reset(); // Reset the watchdog timer
// Check for incoming SMS
if (sim800.available()) {
incomingSMS = sim800.readString();
checkSMSForCodes(incomingSMS);
}
// Read sensors
float temp = dht.readTemperature();
float hum = dht.readHumidity();
int gasValue = analogRead(GAS_PIN);
// Calculate Air Quality Index (dummy logic for now)
int AQI = calculateAQI(gasValue);
// Get timestamps
String dataCollected = getISOTime();
String dataSent = getISOTime(); // Assume data is sent right after collection
// Send data to Firebase with retries
bool dataSentSuccessfully = sendDataToFirebase(temp, hum, gasValue, AQI, dataCollected, dataSent);
if (!dataSentSuccessfully) {
retryCount++;
if (retryCount <= MAX_RETRIES) {
Serial.println("Retrying to send data...");
delay(5000); // Wait before retrying
sendDataToFirebase(temp, hum, gasValue, AQI, dataCollected, dataSent); // Retry sending data
} else {
Serial.println("Data send failed after retries. Performing full system scan and reboot.");
fullSystemScan(); // Perform full system scan
rebootSystem(); // Reboot the system
}
} else {
retryCount = 0; // Reset retry count on successful send
}
// Check if audio is playing
if (!isPlaying) {
playAlertAudio(); // Play the alert audio first
}
delay(10000); // Delay 10 seconds between readings
}
void initSIM800() {
sendCommandToSIM800("AT");
delay(1000);
sendCommandToSIM800("AT+CMGF=1"); // Set SMS text mode
delay(1000);
sendCommandToSIM800("AT+CNMI=1,2,0,0,0"); // Immediate SMS notification
delay(1000);
}
void sendCommandToSIM800(String command) {
sim800.println(command);
delay(1000);
while (sim800.available()) {
Serial.println(sim800.readString());
}
}
void checkSMSForCodes(String sms) {
// Split incoming SMS codes using comma as a delimiter
int startIndex = 0;
int endIndex;
while ((endIndex = sms.indexOf(',', startIndex)) != -1) {
String code = sms.substring(startIndex, endIndex);
playDisasterAudio(code); // Play audio for the disaster code
startIndex = endIndex + 1;
}
// Check the last code after the last comma
if (startIndex < sms.length()) {
playDisasterAudio(sms.substring(startIndex)); // Play audio for the last code
}
}
void playSound(String soundFileName) {
soundFile = SD.open(soundFileName);
if (soundFile) {
// Play sound logic (send data to speaker)
Serial.println("Playing: " + soundFileName);
soundFile.close();
} else {
Serial.println("Failed to open sound file: " + soundFileName);
}
}
bool sendDataToFirebase(float temp, float hum, int gas, int AQI, String collectedTime, String sentTime) {
FirebaseJson json;
json.set("sensorData/temperature", temp);
json.set("sensorData/humidity", hum);
json.set("sensorData/gasReadings/CO2", gas);
json.set("sensorData/gasReadings/CO", gas * 0.05); // Example conversion
json.set("sensorData/gasReadings/NH3", gas * 0.03);
json.set("sensorData/gasReadings/NOx", gas * 0.02);
json.set("sensorData/gasReadings/benzene", gas * 0.01);
json.set("sensorData/airQualityIndex", AQI);
json.set("timestamps/dataCollected", collectedTime);
json.set("timestamps/dataSent", sentTime);
json.set("status", "active");
if (Firebase.pushJSON(fbData, basePath, json)) {
Serial.println("Data sent to Firebase");
return true; // Data sent successfully
} else {
Serial.println("Failed to send data: " + fbData.errorReason());
return false; // Data send failed
}
}
String getISOTime() {
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
Serial.println("Failed to obtain time");
return "";
}
char buffer[30];
strftime(buffer, sizeof(buffer), "%Y-%m-%dT%H:%M:%SZ", &timeinfo);
return String(buffer);
}
int calculateAQI(int gasValue) {
// Simple AQI calculation (example logic)
return map(gasValue, 0, 1023, 0, 500);
}
void playAlertAudio() {
String alertFilePath = "/disaster/Alert.wav"; // Path to the alert audio file
if (SD.exists(alertFilePath)) {
if (!audio.isPlaying()) { // Only play if not already playing
audio.play(alertFilePath); // Play alert audio
isPlaying = true; // Set the playing status to true
Serial.println("Playing alert audio: " + alertFilePath);
}
} else {
Serial.println("Alert audio file not found: " + alertFilePath);
}
}
void playDisasterAudio(String code) {
String soundFilePath = "/disaster/" + code + ".wav"; // Assuming files are named according to the code
if (SD.exists(soundFilePath)) {
audio.play(soundFilePath);
isPlaying = true; // Set the playing status to true
Serial.println("Playing disaster audio: " + soundFilePath);
} else {
Serial.println("Disaster audio file not found: " + soundFilePath);
}
}
void rebootSystem() {
Serial.println("Rebooting system...");
ESP.restart(); // Restart the ESP32
}
void fullSystemScan() {
Serial.println("Performing full system scan...");
// Implement full system scan logic here (if applicable)
}
void emergencyReboot() {
Serial.println("Emergency reboot triggered.");
rebootSystem(); // Reboot the system
}
Project Overview: This Early Warning System (EWS) is a comprehensive setup for real-time monitoring of weather and air quality data to enhance disaster preparedness in rural areas. The system collects data using the SHT31 temperature and humidity sensor and the MQ-135 gas sensor, which monitors air quality. All data is sent to a dedicated website for real-time display and tracking, which can also be used for demonstration. The system’s alert feature is activated via a SIM module, which receives warning codes to trigger specific audio alerts via loudspeakers, ensuring that communities receive timely notifications.
Key Features
1. Data Collection and Transmission
- Sensors: The SHT31 sensor continuously collects temperature and humidity data, while the MQ-135 gas sensor monitors air quality and detects hazardous gases.
- Real-Time Updates: The ESP32 microcontroller processes and formats the data in JSON before sending it to a small website hosted on Firebase via HTTP POST requests every 5 minutes.
- Historical Data: The website displays graphs showing temperature, humidity, and AQI trends over the past two weeks, enabling comparison and analysis of pollution and air quality changes.
2. Website Development and Display
- Real-Time Data Display: The website provides real-time updates of temperature, humidity, and AQI data as transmitted from the ESP32.
- Graphs and Charts: Data visualization includes easy-to-read graphs showing both current readings and trends over the last two weeks.
- Simple and Accessible UI: Designed as a school project, the website has a straightforward, user-friendly interface to make data representation clear and accessible.
- Demonstration Tool: For science exhibition purposes, the website can send specific codes to the system to activate the relevant audio alerts, showcasing the alert system’s functionality in real-time. Buttons on the site correspond to stored alert codes, allowing for quick testing and demonstration.
3. Alert System and Audio Playback
- SIM Module: The SIM800l 3G SIM module is responsible for receiving alert codes from national authorities.
- Code-Activated Audio Alerts: When the SIM module receives an alert code, the ESP32 processes it to activate the corresponding audio file stored on a microSD card. This file is then amplified by the LM386 audio amplifier and broadcast through loudspeakers to alert the public.
- Area-Specific Alerts: Alert codes include specific area information to ensure that warnings are relevant to the affected regions. This approach avoids miscommunication, especially during widespread evacuations.
4. Core Components
- ESP32-WROOM-32: Serves as the main microcontroller, managing data collection, communication, and alert responses.
- SHT31 and MQ-135 Sensors: Collects data on temperature, humidity, and air quality.
- Quectel EC25 (4G SIM Module): Receives alert codes via the mobile network.
- LM386 Audio Amplifier: Amplifies audio signals for effective public alerting.
- MC34063AD (DC-DC Converter): Stabilizes power supply for consistent performance.
- microSD Card: Stores audio files associated with different alerts.
5. Technical Requirements for Coding
- Data Format and Transmission Protocol: All sensor data from the SHT31 and MQ-135 is formatted in JSON before transmission. The ESP32 sends data to the website through HTTP POST requests.
- Alert Codes and Audio Files: Codes received via the SIM module activate specific audio files stored on the microSD card. The ESP32 checks the incoming alert code against its memory, including area-specific information if applicable, to trigger the correct audio file.
- Self-Scan Capability: The system conducts a regular self-scan and sends its status to the website to ensure smooth operation.
6. Real-Time Data Handling and User Interface
- Data Logging: The website retains past data points to create a continuous record without overwriting older readings.
- User Interface (UI): The UI includes intuitive buttons or controls for triggering alerts, testing, and viewing data trends. It allows users to select specific codes to activate corresponding alerts for demonstration purposes.
Implementation Languages and Tools
- ESP32 Code: Developed in C++ to handle data collection, communication, and alert processing.
- Website Development: JavaScript will be used to display data and manage real-time updates.
- Firebase Hosting: The website will be hosted on Firebase for ease of access and demonstration.