#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

2. Website Development and Display

3. Alert System and Audio Playback

4. Core Components

5. Technical Requirements for Coding

6. Real-Time Data Handling and User Interface

Implementation Languages and Tools