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

DevOps & Cloud Engineer — building scalable, automated, and intelligent systems. Developer of sorts | Automator | Innovator
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
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)

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

ESP32 Firmware Logic
The ESP32 collects data continuously. Each cycle does the following:
Read raw EEG analog values
Read IR and RED values from MAX30100
Apply Fast Fourier Transform to EEG samples
Extract band powers:
Alpha (8 to 12 Hz)
Beta (12 to 30 Hz)
Gamma (30 to 100 Hz)
Package everything into a JSON payload
Send the JSON data to the FastAPI backend via Wi-Fi
Example JSON Payload
{
"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
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

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
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:

How It Works Together
End-to-End Pipeline
ESP32 reads EEG values and MAX30100 values
ESP32 performs FFT and computes band powers
ESP32 sends JSON to FastAPI backend
Dashboard fetches latest data through
/dataChart.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.






