"""
====================================================
VIRTUAL DOCTOR APPLICATION
====================================================
Platform: ESP32
Language: MicroPython
PROJECT OVERVIEW:
This project is a **Virtual Doctor Application** built using an ESP32,
temperature sensor (DHT22), heart rate signal simulation, LCD display,
buzzer, LED, and ThingSpeak IoT cloud.
The system continuously monitors:
- **Heart Rate (HR)** → simulated using a sine wave to mimic a pulse sensor.
- **Body Temperature (°C)** → measured with a DHT22 sensor.
It then:
- Displays the readings on a **16x2 LCD**.
- Provides **health feedback (Normal / Fever / Hypothermia / Bradycardia / Tachycardia)** like a doctor.
- Activates **alerts** (buzzer + LED) if abnormal conditions are detected.
- Sends the data to **ThingSpeak IoT cloud** every 20 seconds.
====================================================
WORKING PRINCIPLE:
====================================================
1. **WiFi Connection**
- The ESP32 connects to WiFi.
- Enables sending data to ThingSpeak for remote monitoring.
2. **Heartbeat Monitoring (Simulated)**
- Since no real pulse sensor exists in Wokwi, a **sine wave signal** is generated.
- Each wave peak is treated as a heartbeat → time between peaks is used to calculate **BPM**.
- Heart rate ranges are classified:
- <40 BPM → Bradycardia (Doctor Alert)
- 40-100 BPM → Normal
- 100-120 BPM → Slightly High
- 120-150 BPM → Abnormal HR (Doctor Alert)
- >150 BPM → Tachycardia Emergency
3. **Temperature Monitoring**
- DHT22 sensor measures body temperature.
- Temperature ranges are classified:
- <35°C → Hypothermia (Doctor Alert)
- 35-37.5°C → Normal
- 38-39.5°C → Fever (Doctor Alert)
- >39.5°C → High Fever Emergency
4. **LCD Display**
- Shows real-time HR and Temperature values.
- In case of abnormal readings, it displays **Doctor advice messages** like:
"Visit Doctor", "Emergency", "Stay Healthy".
5. **Alerts**
- If abnormal HR or Temp is detected → Buzzer beeps + LED blinks 3 times.
- Gives both **visual + audio alerts** for the patient.
6. **ThingSpeak IoT Upload**
- Every 20 seconds, HR, Temp, and Alert Code are sent to ThingSpeak.
- Alert Codes mapping:
0 → Normal
1 → Low Temp
2 → Fever
3 → High Fever Emergency
4 → Very Low HR
5 → Abnormal HR
6 → Very High HR
====================================================
"""
import network
import urequests
import machine
import time
import dht
import math
from machine import Pin, ADC, I2C
from lcd_api import LcdApi
from i2c_lcd import I2cLcd
# ===== WiFi Config =====
WIFI_SSID = "Wokwi-GUEST"
WIFI_PASS = ""
# ===== ThingSpeak Config =====
TS_WRITE_KEY = "FNGRXJ6BJWEACFRC"
TS_URL = "http://api.thingspeak.com/update"
# ===== Pin Setup =====
adc = ADC(Pin(34)) # Potentiometer or pulse sensor
adc.atten(ADC.ATTN_11DB) # Full range (0-3.3V)
d = dht.DHT22(Pin(4)) # DHT22 temperature sensor
buzzer = Pin(25, Pin.OUT) # Active buzzer
led = Pin(2, Pin.OUT) # Status LED
i2c = I2C(0, scl=Pin(22), sda=Pin(21), freq=400000)
lcd = I2cLcd(i2c, 0x27, 2, 16)
# ===== Connect WiFi =====
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(WIFI_SSID, WIFI_PASS)
print("Connecting to WiFi", end="")
while not wlan.isconnected():
print(".", end="")
time.sleep(0.5)
print("\nConnected:", wlan.ifconfig())
# ===== Beat detection variables =====
threshold = 2000 # Adjust for sensor/simulation
hysteresis = 150
in_peak = False
last_beat = 0
bpm = 0
bpm_values = [] # for smoothing
refractory_period = 300 # ms, to avoid double detection
# ===== Track ThingSpeak updates =====
last_update = time.ticks_ms()
# ===== Alert codes =====
alert_codes = {
"Normal": 0,
"Low Temp": 1,
"Fever": 2,
"High Fever Emergency": 3,
"Very Low HR": 4,
"Abnormal HR": 5,
"Very High HR": 6
}
# ===== Main Loop =====
while True:
now = time.ticks_ms()
# --- Simulated Pulse Signal (comment if using real sensor) ---
t = time.ticks_ms() / 1000 # seconds
val = int(2000 + 1000 * math.sin(2 * math.pi * 1.2 * t)) # ~72 bpm
# val = adc.read() # uncomment if using real pulse sensor
# --- Beat Detection ---
if not in_peak and val > threshold:
if time.ticks_diff(now, last_beat) > refractory_period:
in_peak = True
if last_beat != 0:
ibi = time.ticks_diff(now, last_beat) # ms
if 300 < ibi < 2000: # valid HR range
bpm = int(60000 / ibi)
bpm_values.append(bpm)
if len(bpm_values) > 5: # rolling average of last 5
bpm_values.pop(0)
bpm = sum(bpm_values) // len(bpm_values)
led.on()
buzzer.on()
time.sleep(0.05)
buzzer.off()
led.off()
last_beat = now
if in_peak and val < threshold - hysteresis:
in_peak = False
# --- Temperature ---
try:
d.measure()
temp = d.temperature()
except:
temp = None
# --- Debug Print for Clear Vision ---
print("ADC: {:4d} | BPM: {:3d} | Temp: {}".format(
val,
bpm if bpm > 0 else 0,
"{:.1f}C".format(temp) if temp is not None else "--"
))
# --- LCD Display ---
lcd.clear()
lcd.putstr("HR:{} bpm".format(bpm if bpm > 0 else "--"))
if temp is not None:
lcd.move_to(0, 1)
lcd.putstr("T:{:.1f}C".format(temp))
# --- Alerts & Doctor Features ---
alert = False
alert_msg = "Normal"
if temp is not None:
if temp < 35:
lcd.clear()
lcd.putstr("Hypothermia!")
lcd.move_to(0, 1)
lcd.putstr("See Doctor")
alert = True
alert_msg = "Low Temp"
elif 35 <= temp <= 37.5:
lcd.clear()
lcd.putstr("Normal Temp")
lcd.move_to(0, 1)
lcd.putstr("Stay Healthy")
elif temp > 39.5:
lcd.clear()
lcd.putstr("High Fever!")
lcd.move_to(0, 1)
lcd.putstr("Emergency")
alert = True
alert_msg = "High Fever Emergency"
elif temp > 38:
lcd.clear()
lcd.putstr("Fever! Visit")
lcd.move_to(0, 1)
lcd.putstr("Doctor")
alert = True
alert_msg = "Fever"
if bpm != 0:
if bpm < 40:
lcd.clear()
lcd.putstr("Bradycardia!")
lcd.move_to(0, 1)
lcd.putstr("See Doctor")
alert = True
alert_msg = "Very Low HR"
elif 40 <= bpm <= 100:
lcd.clear()
lcd.putstr("HR Normal")
lcd.move_to(0, 1)
lcd.putstr("Stay Healthy")
elif bpm > 150:
lcd.clear()
lcd.putstr("Tachycardia!")
lcd.move_to(0, 1)
lcd.putstr("Emergency")
alert = True
alert_msg = "Very High HR"
elif bpm > 120:
lcd.clear()
lcd.putstr("HR Abnormal!")
lcd.move_to(0, 1)
lcd.putstr("Visit Doctor")
alert = True
alert_msg = "Abnormal HR"
if alert:
for _ in range(3): # Beep + Blink 3 times
buzzer.on()
led.on()
time.sleep(0.2)
buzzer.off()
led.off()
time.sleep(0.2)
# --- Send to ThingSpeak (every 20s) ---
if time.ticks_diff(now, last_update) > 20000:
try:
alert_code = alert_codes.get(alert_msg, 0)
url = "{}?api_key={}&field1={}&field2={}&field3={}".format(
TS_URL, TS_WRITE_KEY,
bpm if bpm > 0 else 0,
temp if temp is not None else 0,
alert_code
)
r = urequests.get(url)
print("ThingSpeak:", r.text)
r.close()
except Exception as e:
print("HTTP error:", e)
last_update = now # reset timer
time.sleep(0.05)