/*
* IoMT Patient Monitoring — ESP32 DevKit V1
* Module: LD7182 — AI for IoT
* Board : board-esp32-devkit-v1
*
* Pins:
* GPIO34 → SpO2 pot GPIO35 → HR pot
* GPIO32 → Systolic pot GPIO33 → Diastolic pot
* GPIO36 → Temp pot
* GPIO21 → OLED SDA GPIO22 → OLED SCL
* GPIO25 → Green LED GPIO26 → Red LED
* GPIO17 → Fall button GPIO18 → Disease button
*
* ThingSpeak Fields:
* Field 1 → SpO2 (%)
* Field 2 → Heart Rate (bpm)
* Field 3 → Systolic BP (mmHg)
* Field 4 → Diastolic BP (mmHg)
* Field 5 → Temperature (°C)
* Field 6 → Alert Status (0 = ALERT, 1 = NORMAL)
* Field 7 → Fall Detected (0 = No, 1 = Yes)
* Field 8 → Disease Index (0=Normal, 1=Hypertens., 2=Diabetes, 3=Asthma)
*/
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <WiFi.h>
#include <HTTPClient.h>
// ── WiFi ──────────────────────────────────────────────────────
const char* SSID = "Wokwi-GUEST"; // change for real hardware
const char* PASSWORD = "";
// ── ThingSpeak ────────────────────────────────────────────────
const char* TS_KEY = "EYOEB444VQDEJ6QV"; // ← Your Write API Key
const char* TS_SERVER = "http://api.thingspeak.com/update";
const unsigned long TS_INTERVAL = 20000; // 20s (free tier min = 15s)
unsigned long lastUpload = 0;
// ── OLED ────────────────────────────────────────────────────
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
// ── Pins ────────────────────────────────────────────────────
#define PIN_SPO2 34
#define PIN_HR 35
#define PIN_SYSTOLIC 32
#define PIN_DIASTOLIC 33
#define PIN_TEMP 36
#define LED_GREEN 25
#define LED_RED 26
#define BTN_FALL 17
#define BTN_DISEASE 18
// ── State ───────────────────────────────────────────────────
int diseaseIndex = 0;
bool fallDetected = false;
bool lastFallBtn = HIGH;
bool lastDiseaseBtn = HIGH;
unsigned long lastDebounce = 0;
const char* DISEASE_NAMES[] = { "Normal", "Hypertens.", "Diabetes", "Asthma" };
// ── Sensor Readers ──────────────────────────────────────────
float readSpO2() { return map(analogRead(PIN_SPO2), 0, 4095, 850, 1000) / 10.0f; }
float readHR() { return (float)map(analogRead(PIN_HR), 0, 4095, 40, 160); }
float readSystolic() { return (float)map(analogRead(PIN_SYSTOLIC), 0, 4095, 90, 200); }
float readDiastolic() { return (float)map(analogRead(PIN_DIASTOLIC), 0, 4095, 50, 130); }
float readTemp() { return map(analogRead(PIN_TEMP), 0, 4095, 340, 410) / 10.0f; }
// ── Decision Tree ───────────────────────────────────────────
int classifySpO2Alert(float spO2, float hr, float sys,
float dia, float temp,
int disease, bool fall) {
float isHypertension = (disease == 1) ? 1.0f : 0.0f;
float isDiabetes = (disease == 2) ? 1.0f : 0.0f;
float isFall = fall ? 1.0f : 0.0f;
if (spO2 <= 89.55f) {
if (spO2 <= 89.16f) {
if (spO2 <= 89.01f) return 0;
else {
if (spO2 <= 89.04f) return (spO2 <= 89.03f) ? 0 : 1;
else return 0;
}
} else {
if (hr <= 77.41f) {
if (hr <= 67.66f) return (dia <= 85.48f) ? 0 : 1;
else return (isHypertension <= 0.5f) ? 1 : 0;
} else {
if (sys <= 174.06f) return 0;
else return (isFall <= 0.5f) ? 1 : 0;
}
}
} else {
if (spO2 <= 89.91f) {
if (isDiabetes <= 0.5f) return 1;
else return (sys <= 156.27f) ? 1 : 0;
} else {
return 1;
}
}
}
// ── ThingSpeak Upload ────────────────────────────────────────
void uploadThingSpeak(float spO2, float hr, float sys,
float dia, float temp,
int alert, bool fall, int disease) {
if (WiFi.status() != WL_CONNECTED) {
Serial.println("[WiFi] Disconnected – skipping upload.");
return;
}
String url = String(TS_SERVER)
+ "?api_key=" + TS_KEY
+ "&field1=" + String(spO2, 1)
+ "&field2=" + String((int)hr)
+ "&field3=" + String((int)sys)
+ "&field4=" + String((int)dia)
+ "&field5=" + String(temp, 1)
+ "&field6=" + String(alert)
+ "&field7=" + String(fall ? 1 : 0)
+ "&field8=" + String(disease);
HTTPClient http;
http.begin(url);
int resp = http.GET();
http.end();
if (resp > 0) Serial.printf("[ThingSpeak] Entry: %d\n", resp);
else Serial.printf("[ThingSpeak] Error: %d\n", resp);
}
// ── WiFi Connect ─────────────────────────────────────────────
void connectWiFi() {
Serial.printf("[WiFi] Connecting to: %s\n", SSID);
WiFi.begin(SSID, PASSWORD);
int attempts = 0;
while (WiFi.status() != WL_CONNECTED && attempts < 20) {
delay(500); Serial.print("."); attempts++;
}
if (WiFi.status() == WL_CONNECTED) {
Serial.printf("\n[WiFi] Connected. IP: %s\n", WiFi.localIP().toString().c_str());
} else {
Serial.println("\n[WiFi] Failed – running offline.");
}
}
// ── Setup ───────────────────────────────────────────────────
void setup() {
Serial.begin(115200);
delay(300);
pinMode(LED_GREEN, OUTPUT); digitalWrite(LED_GREEN, LOW);
pinMode(LED_RED, OUTPUT); digitalWrite(LED_RED, LOW);
pinMode(BTN_FALL, INPUT_PULLUP);
pinMode(BTN_DISEASE, INPUT_PULLUP);
Wire.begin(21, 22);
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println("OLED failed"); while (1);
}
display.clearDisplay();
display.setTextSize(1); display.setTextColor(WHITE);
display.setCursor(15, 5); display.println("LD7182 - AI for IoT");
display.setCursor(20, 18); display.println("IoMT Monitor v2.0");
display.setCursor(25, 31); display.println("+ ThingSpeak");
display.setCursor(30, 44); display.println("Starting...");
display.display();
delay(1500);
connectWiFi();
Serial.println("=== IoMT Monitor Ready ===");
}
// ── Loop ────────────────────────────────────────────────────
void loop() {
unsigned long now = millis();
// Fall button toggle
bool fb = digitalRead(BTN_FALL);
if (fb == LOW && lastFallBtn == HIGH && (now - lastDebounce) > 250) {
fallDetected = !fallDetected;
lastDebounce = now;
Serial.print("Fall: "); Serial.println(fallDetected ? "ON" : "OFF");
}
lastFallBtn = fb;
// Disease cycle button
bool db = digitalRead(BTN_DISEASE);
if (db == LOW && lastDiseaseBtn == HIGH && (now - lastDebounce) > 250) {
diseaseIndex = (diseaseIndex + 1) % 4;
lastDebounce = now;
Serial.print("Disease: "); Serial.println(DISEASE_NAMES[diseaseIndex]);
}
lastDiseaseBtn = db;
// Read sensors
float spO2 = readSpO2();
float hr = readHR();
float sys = readSystolic();
float dia = readDiastolic();
float temp = readTemp();
// Run decision tree
int result = classifySpO2Alert(spO2, hr, sys, dia, temp,
diseaseIndex, fallDetected);
// Drive LEDs
digitalWrite(LED_GREEN, (result == 1) ? HIGH : LOW);
digitalWrite(LED_RED, (result == 0) ? HIGH : LOW);
// ThingSpeak upload every TS_INTERVAL ms
if (now - lastUpload >= TS_INTERVAL) {
lastUpload = now;
uploadThingSpeak(spO2, hr, sys, dia, temp,
result, fallDetected, diseaseIndex);
}
// Update OLED
display.clearDisplay();
display.setTextSize(1); display.setTextColor(WHITE);
display.setCursor(0, 0); display.println("=== IoMT Monitor ===");
display.setCursor(0, 12); display.print("SpO2: "); display.print(spO2, 1); display.println(" %");
display.setCursor(0, 22); display.print("HR: "); display.print((int)hr);
display.print(" bpm T:"); display.print(temp, 1); display.println("C");
display.setCursor(0, 32); display.print("BP: "); display.print((int)sys);
display.print("/"); display.print((int)dia); display.println(" mmHg");
display.setCursor(0, 42); display.print("Dx:"); display.print(DISEASE_NAMES[diseaseIndex]);
display.print(" Fall:"); display.println(fallDetected ? "YES" : "NO");
display.drawFastHLine(0, 52, 128, WHITE);
display.setCursor(0, 55);
display.println(result == 0 ? "!! SpO2 ALERT: LOW !!" : " STATUS: NORMAL ");
display.display();
// Serial log
Serial.printf("SpO2=%.1f HR=%.0f SYS=%.0f DIA=%.0f T=%.1f => %s\n",
spO2, hr, sys, dia, temp, result == 0 ? "ALERT" : "NORMAL");
delay(800);
}
Loading
esp32-devkit-v1
esp32-devkit-v1