#include #include #include #include #include #include #include "heartRate.h" // ================================ // WIFI SETTINGS // ================================ const char* ssid = "MIT"; const char* password = "kwN4@9{UwQ"; // ================================ // OLED SETTINGS // ================================ #define OLED_WIDTH 128 #define OLED_HEIGHT 64 #define OLED_ADDR 0x3C Adafruit_SSD1306 display(OLED_WIDTH, OLED_HEIGHT, &Wire); // ================================ // MAX30102 SETTINGS // ================================ #define SDA_PIN 5 #define SCL_PIN 6 MAX30105 sensor; long lastBeat = 0; float bpm = 0; bool beatFlag = false; // ================================ // SpO2 BUFFER // ================================ const int BUFFER_SIZE = 50; long irBuf[BUFFER_SIZE]; long redBuf[BUFFER_SIZE]; int bufIndex = 0; int bufCount = 0; float spo2 = 0.0; unsigned long lastSpO2Update = 0; // ================================ // WEB SERVER // ================================ WebServer server(80); // GLOBALS FOR WEB GUI long g_ir = 0; long g_red = 0; float g_bpm = 0; float g_spo2 = 0; // ================================ // SpO2 CALCULATION // ================================ void computeSpO2() { if (bufCount < BUFFER_SIZE) return; double sumIR = 0, sumRED = 0; for (int i = 0; i < BUFFER_SIZE; i++) { sumIR += irBuf[i]; sumRED += redBuf[i]; } double dcIR = sumIR / BUFFER_SIZE; double dcRED = sumRED / BUFFER_SIZE; double sumSqIR = 0, sumSqRED = 0; for (int i = 0; i < BUFFER_SIZE; i++) { double acIR = irBuf[i] - dcIR; double acRED = redBuf[i] - dcRED; sumSqIR += acIR * acIR; sumSqRED += acRED * acRED; } double rmsIR = sqrt(sumSqIR / BUFFER_SIZE); double rmsRED = sqrt(sumSqRED / BUFFER_SIZE); if (dcIR <= 0 || dcRED <= 0 || rmsIR <= 0) return; double R = (rmsRED / dcRED) / (rmsIR / dcIR); double estSpO2 = 110.0 - 25.0 * R; estSpO2 = constrain(estSpO2, 70.0, 100.0); spo2 = estSpO2; } // ================================ // GUI HTML PAGE // ================================ const char GUI_PAGE[] PROGMEM = R"rawliteral( ESP32 MAX30102 Dashboard

Health Monitor

BPM
--
SpO₂ (%)
--
IR
--
RED
--
)rawliteral"; // ================================ // WEB ROUTES // ================================ void handleGUI() { server.send(200, "text/html", GUI_PAGE); } void handleMetrics() { String json = "{"; json += "\"bpm\":" + String(g_bpm, 2) + ","; json += "\"spo2\":" + String(g_spo2, 2) + ","; json += "\"ir\":" + String(g_ir) + ","; json += "\"red\":" + String(g_red); json += "}"; server.send(200, "application/json", json); } // ================================ // SETUP // ================================ void setup() { Serial.begin(115200); delay(300); Wire.begin(SDA_PIN, SCL_PIN); Wire.setClock(400000); Serial.println("Initializing MAX30102..."); sensor.begin(Wire, I2C_SPEED_FAST); sensor.setup(); sensor.setLEDMode(2); sensor.setPulseAmplitudeRed(0x3F); sensor.setPulseAmplitudeIR(0x3F); sensor.setSampleRate(100); sensor.setPulseWidth(411); // OLED display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR); display.clearDisplay(); display.setTextColor(SSD1306_WHITE); // WIFI WiFi.begin(ssid, password); Serial.print("Connecting to WiFi"); while (WiFi.status() != WL_CONNECTED) { delay(300); Serial.print("."); } Serial.println("\nConnected!"); Serial.print("IP: "); Serial.println(WiFi.localIP()); // WEB SERVER server.on("/", handleGUI); server.on("/gui", handleGUI); server.on("/metrics", handleMetrics); server.begin(); } // ================================ // MAIN LOOP // ================================ void loop() { server.handleClient(); long ir = sensor.getIR(); long red = sensor.getRed(); g_ir = ir; g_red = red; if (checkForBeat(ir)) { long delta = millis() - lastBeat; lastBeat = millis(); bpm = 60.0 / (delta / 1000.0); beatFlag = true; } g_bpm = bpm; irBuf[bufIndex] = ir; redBuf[bufIndex] = red; bufIndex = (bufIndex + 1) % BUFFER_SIZE; if (bufCount < BUFFER_SIZE) bufCount++; if (millis() - lastSpO2Update > 300) { computeSpO2(); g_spo2 = spo2; lastSpO2Update = millis(); } // OLED: display.clearDisplay(); display.setCursor(0, 0); display.print("IR: "); display.println(ir); display.setCursor(0, 10); display.print("RED: "); display.println(red); display.setCursor(0, 25); display.setTextSize(2); display.print("BPM: "); display.println((int)bpm); display.setTextSize(1); display.setCursor(0, 50); display.print("SpO2: "); display.print(spo2, 1); display.print("%"); display.display(); }