# Brainwave Visualization Using ESP32, BioAmpEXG, FastAPI, and Interactive Charts

Monitoring brainwave activity in real time has always fascinated me. I wanted to build something that could collect EEG signals, process them on a lightweight device, and display the results on a clean web dashboard. With an ESP32, a MAX30100 sensor, a small analog EEG input, and a FastAPI backend, I was able to create a portable system that measures Alpha, Beta, and Gamma brainwave bands and visualises them as simple bar graphs.

This article explains how I built the entire pipeline, from data collection to real-time visualisation.

I also wrote a short study based on this and used M5Stack for it:  
[https://www.researchgate.net/publication/391839761\_Short-Term\_Neurophysiological\_Changes\_During\_Transcendental\_Meditation\_A\_Pilot\_EEG\_and\_ECG-Based\_Study](https://www.researchgate.net/publication/391839761_Short-Term_Neurophysiological_Changes_During_Transcendental_Meditation_A_Pilot_EEG_and_ECG-Based_Study)

---

## **Why I Built This**

I wanted a portable and affordable setup that could:

* Collect EEG data through a simple analog pin
    
* Compute frequency bands using Fast Fourier Transform
    
* Add additional biometric data from a MAX30100 sensor
    
* Send all readings to a backend server over Wi-Fi
    
* Show clean and simple charts on a dashboard
    
* Make the system completely wireless
    

The ESP32 Zero 2 WH (or any small ESP32 board) was perfect because it is inexpensive, efficient, and supports both Wi-Fi and continuous sensor sampling.

---

# **Hardware Setup**

### **Components Used**

* **ESP32 (M5Core2 or Zero 2 WH)**
    
* **MAX30100 sensor** for infrared and red readings, later used ECG Module
    
* **EEG analog signal** (BioAmpEXG Pill) connected to an ADC pin
    
* **Wi-Fi** to push data to backend
    
* **Power source** (USB or portable battery)
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1764560486606/3f3113c1-b753-4137-bbc7-2dd29994d015.png align="center")

### **Wiring Overview**

* MAX30100 SDA → ESP32 SDA pin
    
* MAX30100 SCL → ESP32 SCL pin
    
* EEG analog output → ESP32 ADC pin
    
* Common ground for all components
    

The MAX30100 is optional for brainwave detection, but I wanted additional IR/RED data to calculate orderliness and signal health. This was the initial choice, but later I switched to AD8232

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1764560575071/f817df19-8025-4e42-9e76-bc2a3e158fdb.png align="center")

---

# **ESP32 Firmware Logic**

The ESP32 collects data continuously. Each cycle does the following:

1. Read **raw EEG analog values**
    
2. Read **IR and RED values** from MAX30100
    
3. Apply **Fast Fourier Transform** to EEG samples
    
4. Extract **band powers**:
    
    * Alpha (8 to 12 Hz)
        
    * Beta (12 to 30 Hz)
        
    * Gamma (30 to 100 Hz)
        
5. Package everything into a JSON payload
    
6. Send the JSON data to the FastAPI backend via Wi-Fi
    

### **Example JSON Payload**

```json
{
    "alpha": 42.3,
    "beta": 28.1,
    "gamma": 10.5,
    "orderliness": 0.82,
    "ir": 51200,
    "red": 50390
}
```

---

# **Backend: FastAPI Application**

The backend receives data, stores it, and serves it to the dashboard.

### **Key Features**

* Endpoint for receiving ESP32 JSON data
    
* In-memory store or Redis for fast access
    
* REST endpoint for the dashboard
    
* CORS enabled
    
* Very low latency
    

### **Example FastAPI Endpoint**

```python
from fastapi import FastAPI
from pydantic import BaseModel

class BrainwaveData(BaseModel):
    alpha: float
    beta: float
    gamma: float
    orderliness: float
    ir: int
    red: int

app = FastAPI()

latest_data = BrainwaveData(
    alpha=0, beta=0, gamma=0, orderliness=0, ir=0, red=0
)

@app.post("/update")
def update(data: BrainwaveData):
    global latest_data
    latest_data = data
    return {"status": "ok"}

@app.get("/data")
def get_data():
    return latest_data
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1764560497211/eacc795f-3981-41bf-868a-b44b4f8b659b.png align="center")

---

# **Building the Dashboard**

I wanted a clean visualisation with no curves, only bar graphs.  
The dashboard uses:

* **HTML + Bootstrap**
    
* **Chart.js** for bar charts
    
* Auto-refresh using JavaScript
    
* Smooth transitions
    

### **Why Bar Graphs?**

Bar graphs work well because brainwave bands are relative.  
The magnitude of Alpha versus Beta is the most important insight, and bars make comparison easy.

---

# **Dashboard Layout**

The dashboard has:

* A bar graph for Alpha, Beta, and Gamma
    
* A card showing orderliness
    
* A small panel showing IR and RED values
    
* A refresh interval of 1 second
    

### **Example Chart.js Code Snippet**

```javascript
const ctx = document.getElementById("brainChart");

const chart = new Chart(ctx, {
    type: "bar",
    data: {
        labels: ["Alpha", "Beta", "Gamma"],
        datasets: [{
            data: [0, 0, 0]
        }]
    },
    options: {
        animation: false,
        scales: {
            y: { beginAtZero: true }
        }
    }
});

async function refreshData() {
    const r = await fetch("/data");
    const d = await r.json();
    chart.data.datasets[0].data = [d.alpha, d.beta, d.gamma];
    chart.update();
}

setInterval(refreshData, 1000);
```

Here is a graph that I obtained:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1764560645072/95106eca-d1c8-44f5-90a1-6078d2ffc458.png align="center")

---

# **How It Works Together**

### **End-to-End Pipeline**

1. ESP32 reads EEG values and MAX30100 values
    
2. ESP32 performs FFT and computes band powers
    
3. ESP32 sends JSON to FastAPI backend
    
4. Dashboard fetches latest data through `/data`
    
5. Chart.js updates the bars in real time
    

---

# **Challenges I Faced**

### **1\. Noise in the EEG Signal**

Low-cost EEG is noisy.  
I had to apply:

* Moving average filters
    
* Calibration
    
* Proper grounding
    
* FFT windowing
    

### **2\. Sampling Rate Stability**

To extract accurate brainwave bands, the sampling rate must be stable.  
I locked the ESP32 ADC sampling to a consistent interval.

### **3\. Fast Refresh Rendering**

Continuous updates caused stuttering until I disabled animation in Chart.js.

---

# **Final Result**

The dashboard provides a clean and real-time visualisation of:

* Alpha, Beta, Gamma brain activity
    
* Signal orderliness
    
* Infrared and red biometric data
    

It works smoothly on both desktop and mobile browsers and updates once every second.

---

# **Future Improvements**

I plan to enhance the system with:

* WebSocket streaming instead of polling
    
* A rolling timeline view for long sessions
    
* Support for multiple users
    
* A database for storing and analysing sessions
    
* A machine learning model that detects focus, stress, or calmness
    

---

# **Conclusion**

This project showed me how much can be done with simple hardware and a clean backend architecture. By combining an ESP32, BioAmpEXG, FFT analysis, FastAPI, and a lightweight dashboard, it is possible to create a fully portable and real-time brainwave monitoring system.
