This project implements a non-invasive blood glucose monitor using:
- ESP32-C3 microcontroller (WeAct Studio devkit recommended)
- AS7263 6-channel spectral sensor (NIR/Visible: R=610nm, S=680nm, T=730nm, U=810nm, V=860nm, W=940nm)
- Dual OLED displays (built-in 72x40 + optional external 128x64)
- Custom algorithm: NIR-dominant spectral ratio scaled to mg/dL
How it works:
- Standby → Detects finger via intensity/ratio/stability checks.
- Takes 5 spectral measurements (bulb-stabilized).
- Computes glucose from NIR/vis ratio using weighted sum + linear scaling.
- Displays result + status for 10s.
| Component | Details |
|---|---|
| MCU | ESP32-C3-DevKitM-1 (WeAct) |
| Sensor | AS726x (SparkFun breakout, I2C addr 0x49) |
| Wires | SDA=GPIO8, SCL=GPIO9 |
| Display | Built-in SSD1306 72x40 (auto) + optional external 128x64 (GPIO3/4) |
| Bulb | Sensor's built-in LED (enabled during reads) |
Pinout (main.cpp):
I2C: SDA=8, SCL=9
OLED Builtin: SCL=6, SDA=5
OLED Ext: SCL=3, SDA=4
LED: BUILTIN
- Install PlatformIO (VSCode extension or CLI).
- Clone/Open this project.
- Build/Upload:
pio run -t upload -e esp32-c3-mini pio device monitor # Serial @115200 - Libraries auto-installed: U8g2, SparkFun AS726X.
- Flash & open Serial Monitor (115200 baud).
- Power on → I2C scan → Standby screen.
- Place CLEAN finger flat on sensor (steady pressure, ~5-10s).
- LED blinks → "Measuring..." → Result (e.g., "102 OK").
- Wait 10s or re-place finger for new measurement.
This prototype uses FIXED parameters. Accurate glucose requires USER calibration!
Watch [FINGER] diagnostics. Adjust if false positives/negatives:
[FINGER] Total=XXXX NIR/Vis=X.XX Stability=XXX
[FINGER] Pass: intensity=Y ratio=Y stability=Y => FINGER DETECTED/no finger
Tune in src/SensorManager.h & reflash:
// Finger detection thresholds
static constexpr float FINGER_MIN_SIGNAL = 500.0f; // Too low → ambient false pos
static constexpr float FINGER_MAX_SIGNAL = 50000.0f; // Too high → no finger/sat
static constexpr float FINGER_MAX_NIR_RATIO = 0.25f; // Finger: low ratio (~0.07)
static constexpr float FINGER_MAX_STABILITY = 500.0f; // Steady finger vs noise- Ambient light: Raise MIN_SIGNAL.
- Saturation: Lower MAX_SIGNAL or integrationTime.
- Shaky finger fails: Raise MAX_STABILITY.
- No detect: Lower MAX_NIR_RATIO.
Sensor config (main.cpp):
sensorConfig.gain = 3; // 0-16, higher=amplification
sensorConfig.integrationTime = 100; // 1-256ms, longer=more signal
sensorConfig.bulbStabilizeMs = 50; // LED settle timeExample Serial (good finger):
[FINGER] Total=12450.2 NIR/Vis=0.07 Stability=120.5
[FINGER] Pass: intensity=Y ratio=Y stability=Y => FINGER DETECTED
Goal: Fit GLUCOSE_SCALE/OFFSET to your sensor + users.
In src/GlucoseAlgorithm.h:
static constexpr float GLUCOSE_SCALE = 100.0f; // Slope: pixels -> mg/dL
static constexpr float GLUCOSE_OFFSET = 0.0f; // Intercept
// Weights (NIR heavy for glucose correlation)
static constexpr float WEIGHT_V = 0.30f; // 860nm
static constexpr float WEIGHT_W = 0.30f; // 940nmCalibration Process:
-
Collect Dataset (N=50+ readings):
Protocol Device Spectral (Serial [MEAS]) Reference (lab glucometer) Fasting (morning) Note R,S,T,U,V,W Measure same finger immediately Post-meal Wait 2h after eating etc. Variety: skin tones, hydration, times of day Log format (
[MEAS]Serial):[MEAS] Sample 1: R=1200 S=1100 T=950 U=800 V=6500 W=6800 total=17150 -
Compute Index: For each reading:
nir = WEIGHT_V*V + WEIGHT_W*W vis = WEIGHT_R*R + ... + WEIGHT_U*U index = nir / vis -
Fit Linear Model (Excel/Python):
glucose_ref = SCALE * index + OFFSET- Use least-squares regression.
- Target: MARD < 15% (clinical threshold).
-
Validate: New dataset, compute % error vs reference.
Example Python Fit (save CSV, run):
import pandas as pd
from sklearn.linear_model import LinearRegression
df = pd.read_csv('calibration_data.csv') # cols: index, glucose_ref
model = LinearRegression().fit(df[['index']], df['glucose_ref'])
print(f'SCALE={model.coef_[0]:.1f}, OFFSET={model.intercept_:.1f}')Pro Tip: Calibrate per-user/sensor (skin, optics vary).
[STATE] -> FINGER_DETECTED
[FINGER] Total=12450 NIR/Vis=0.07 Stability=120 => DETECTED
[MEAS] Sample 1: R=1200 ... W=6800 total=17150
New reading: 102.3 mg/dL
[STATE] Measurement done: level=102.1 valid=YES status=OK
| Issue | Fix |
|---|---|
| No sensor | Check I2C scan (0x49?), wiring |
| No finger detect | Clean sensor, steady pressure, tune thresholds |
| Crazy values | Check saturation (65k?), bulbStabilizeMs |
| Build fail | pio lib install |
| OLED blank | Check pins 5/6 (builtin) |
- Accuracy: Prototype; NIR correlation weak without ML/multivariate cal.
- No trend: Add history buffer.
- Battery: Add LiPo charging.
- Bluetooth: App sync.
- Clinical: Impossible without FDA path, but fun hack!
Contribute: PRs welcome (calibration data, UI, ML models).
Built with ❤️ using PlatformIO & SparkFun AS726x