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

Health Monitor

" "
" "
BPM
" "
--
" "
SpO2 (%)
" "
--
" "
IR
" "
--
" "
RED
" "
--
" "
" "
" "
" "
" "
" "" "" ""; // ---------------- ROUTES ---------------- void handleGUI() { server.sendHeader("Cache-Control", "no-cache"); server.send_P(200, "text/html; charset=utf-8", GUI_PAGE); } void handleMetrics() { String json = "{"; json += "\"bpm\":" + String(g_bpm) + ","; json += "\"spo2\":" + String(g_spo2) + ","; json += "\"ir\":" + String(g_ir) + ","; json += "\"red\":" + String(g_red); json += "}"; server.send(200, "application/json", json); } // ---------------- SETUP ---------------- void setup() { Serial.begin(115200); Wire.begin(SDA_PIN, SCL_PIN); Wire.setClock(400000); // MAX30102 sensor.begin(Wire, I2C_SPEED_FAST); sensor.setup(); sensor.setLEDMode(2); // Red + IR sensor.setPulseAmplitudeRed(0xFF); sensor.setPulseAmplitudeIR(0xFF); sensor.setSampleRate(400); sensor.setPulseWidth(411); // OLED display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR); display.clearDisplay(); display.display(); // WIFI WiFi.begin(ssid, password); Serial.print("Connecting to WiFi"); while (WiFi.status() != WL_CONNECTED) { delay(300); Serial.print("."); } Serial.print("\nIP: "); Serial.println(WiFi.localIP()); // Web server server.on("/", handleGUI); server.on("/gui", handleGUI); server.on("/metrics", handleMetrics); server.begin(); } // ---------------- LOOP ---------------- void loop() { server.handleClient(); long ir = sensor.getIR(); long red = sensor.getRed(); g_ir = ir; g_red = red; // BPM if (checkForBeat(ir)) { long delta = millis() - lastBeat; lastBeat = millis(); bpm = 60.0 / (delta / 1000.0); } g_bpm = bpm; // SpO2 buffer irBuf[bufIndex] = ir; redBuf[bufIndex] = red; bufIndex = (bufIndex + 1) % 50; if (bufCount < 50) 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.setTextSize(2); display.setCursor(0,28); display.print("BPM "); display.println((int)bpm); display.setTextSize(1); display.setCursor(0,52); display.print("SpO2 "); display.print(spo2,1); display.print("%"); display.display(); }