#include <Arduino.h>
#include <driver/i2s.h>
#include "arduinoFFT.h"
// 1. HARDWARE PINS
#define I2S_WS 25
#define I2S_SD 33
#define I2S_SCK 32
#define RELAY_PIN 27
#define LED G 5
// 2. FFT SETTINGS
const uint16_t samples = 1024;
const double samplingFrequency = 44100;
double vReal[samples];
double vImag[samples];
// Magnitude threshold to ensure an actual loud alarm is ringing, not ambient static noise
const double MAGNITUDE_THRESHOLD = 50000.0;
// Updated Version 2.0 Syntax
ArduinoFFT<double> FFT = ArduinoFFT<double>(vReal, vImag, samples, samplingFrequency);
void setup() {
// ==========================================
// USER-FACING PRINTS INITIALIZATION
// ==========================================
Serial.begin(115200);
// Guard for boards with native USB CDC circuitry (e.g., S3/C3 modules)
uint32_t timeout = millis();
while (!Serial && (millis() - timeout < 2500)) {
delay(10);
}
Serial.println("\n\n==============================================");
Serial.println(" HACK THE HARVEST - ACOUSTIC DETECTION ");
Serial.println("==============================================");
Serial.print("[INIT] Core CPU Frequency: ");
Serial.print(ESP.getCpuFreqMHz());
Serial.println(" MHz");
// Initialize Peripherals
pinMode(RELAY_PIN, OUTPUT);
digitalWrite(RELAY_PIN, LOW); // Force safe state on boot
Serial.println("[INIT] Relay control pin configured on GPIO 27.");
// Updated I2S Configuration
Serial.println("[INIT] Initializing I2S audio driver on Bus 0...");
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX),
.sample_rate = 44100,
.bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT,
.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 8,
.dma_buf_len = 1024,
.use_apll = false
};
i2s_pin_config_t pin_config = {
.bck_io_num = I2S_SCK,
.ws_io_num = I2S_WS,
.data_out_num = I2S_PIN_NO_CHANGE,
.data_in_num = I2S_SD
};
if (i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL) == ESP_OK) {
Serial.println("[SUCCESS] I2S Driver installed.");
} else {
Serial.println("[ERROR] Failed to install I2S driver!");
}
i2s_set_pin(I2S_NUM_0, &pin_config);
Serial.println("[SYSTEM] Baseline calibration complete. Monitoring audio stream...\n");
}
void loop() {
size_t bytes_read;
int32_t raw_samples[samples];
// Fetch block data from the DMA buffers
i2s_read(I2S_NUM_0, &raw_samples, sizeof(raw_samples), &bytes_read, portMAX_DELAY);
// Convert raw 32-bit I2S data to double-precision values for processing
for (int i = 0; i < samples; i++) {
vReal[i] = (double)raw_samples[i];
vImag[i] = 0.0;
}
// Execute FFT pipeline
FFT.windowing(FFT_WIN_TYP_HAMMING, FFT_FORWARD);
FFT.compute(FFT_FORWARD);
FFT.complexToMagnitude();
// Extract critical signal components
double peakFrequency = FFT.majorPeak();
// Calculate the raw magnitude value at the index corresponding to our peak frequency
double peakIndex = (peakFrequency * samples) / samplingFrequency;
double peakMagnitude = vReal[(int)peakIndex];
// Provide a live serial heartbeat every few seconds without blocking the processing pipeline
static uint32_t lastPrintTime = 0;
if (millis() - lastPrintTime > 2000) {
Serial.print("[MONITOR] Ambient Peak Frequency: ");
Serial.print(peakFrequency,2 );// 2 decimal places
Serial.print(" Hz | Magnitude: ");
Serial.println(peakMagnitude);
lastPrintTime = millis();
Serial.print("Current Peak Frequency: ");
Serial.print(peakFrequency);
Serial.println(" Hz");
}
// ==========================================
// FIRE ALARM DISPATCH ROUTINE (520Hz Target)
// ==========================================
if (peakFrequency >= 500.0 && peakFrequency <= 540.0 && peakMagnitude > MAGNITUDE_THRESHOLD) {
digitalWrite(RELAY_PIN, HIGH);
Serial.println("\nCRITICAL ALERT!!! ============================");
Serial.print("FIRE ALARM CONDITION MATCHED! Freq: ");
Serial.print(peakFrequency);
Serial.print(" Hz | Amplitude: ");
Serial.println(peakMagnitude);
Serial.println("Activating suppression/notification relay relays.");
Serial.println("==============================================");
// Add a structural tracking delay to keep the alarm tripped for at least 1 second
// to prevent rapid relay chattering/flickering.
delay(1000);
} else {
digitalWrite(RELAY_PIN, LOW);
}
}