This project is an embedded early sepsis detection prototype built on an Arduino Nano ESP32 running MicroPython.
It integrates multiple biomedical and environmental sensors and a 1.3" OLED display to acquire and visualize:
- Core body temperature (TMP117)
- Pulse waveform + SpO₂ estimate (GY-MAX30102)
- Motion/orientation data (BMI160 IMU)
- Real-time status and readings on an SSD1306-based OLED
The goal is to create a small, low-power, I²C‑based sensing platform that can be extended into a more advanced early warning system for sepsis.
- MCU: Arduino Nano ESP32 (MicroPython firmware)
- Language: MicroPython
- Buses:
- I²C0 for all sensors + OLED (shared bus)
- Sensors:
- TMP117 high-accuracy digital temperature sensor (Texas Instruments)
- MAX30102 optical pulse oximeter + heart-rate sensor module (GY-MAX30102)
- BMI160 6‑axis IMU (accelerometer + gyroscope, DFRobot SEN0250)
- Display:
- 1.3" 128×64 OLED using SSD1306-compatible controller over I²C
- Signal processing:
- Rolling buffers for pulse data
- AC/DC separation and ratio‑of‑ratios (R) for SpO₂ estimation
- Architecture:
- Each sensor wrapped in its own MicroPython class
- Shared utility functions for SpO₂ processing
- OLED used as a simple real‑time UI
- Digital I²C temperature sensor.
- Raw reading is a signed 16‑bit value with 0.0078125 °C/LSB resolution.
- Conversion:
[ T_{C} = \text{raw} \times 0.0078125 ]
The MAX30102 provides raw optical signals from Red and IR LEDs measured through the fingertip.
Steps:
-
Raw data acquisition
- Read 18‑bit samples from the MAX30102 FIFO:
red[n],ir[n].
- Read 18‑bit samples from the MAX30102 FIFO:
-
Window / rolling buffer
- Maintain a buffer of N samples (e.g. N ≈ 100) for Red and IR:
red_buf = [red_0, ..., red_{N-1}]ir_buf = [ir_0, ..., ir_{N-1}]
- On each new sample: append new, drop oldest.
- Maintain a buffer of N samples (e.g. N ≈ 100) for Red and IR:
-
Separate AC and DC components
- DC component ≈ mean value over the window:
dc_red = mean(red_buf)dc_ir = mean(ir_buf)
- AC component = signal – DC; we use RMS of AC:
- ( AC_{\text{red,RMS}} = \sqrt{\frac{1}{N}\sum (red_i - dc_{red})^2} )
- ( AC_{\text{ir,RMS}} = \sqrt{\frac{1}{N}\sum (ir_i - dc_{ir})^2} )
- DC component ≈ mean value over the window:
-
Ratio-of-ratios (R) [ R = \frac{AC_{red} / DC_{red}}{AC_{ir} / DC_{ir}} ]
-
SpO₂ approximation
- Use an empirical linear fit (approximate): [ SpO_2 \approx 104 - 17 \cdot R ]
- Clamp / reject values outside physiological range (0–100%).
This implementation is only a non‑medical, approximate estimator, for development and research purposes.
- Read raw accelerometer and gyro data (16‑bit signed) from BMI160.
- Configuration: typical ±4 g, ±2000 °/s, ~100 Hz ODR.
- Provides basic motion awareness (activity, movement artifacts affecting PPG, etc.).
Using the SSD1306 driver:
- Create I²C instance → create
SSD1306_I2C(width, height, i2c, addr=0x3C)object. - Render logic:
oled.fill(0)– clear screenoled.text("Message", x, y)– draw text starting at pixel(x, y)oled.show()– update the physical display
Typical UI loop:
- Read sensors → compute values → format strings → draw text →
oled.show().
Example structure on the MicroPython filesystem:
/
├── boot.py
├── main.py
└── Firmware
├── __init__.py
├── Sensors
│ ├── __init__.py
│ ├── tmp117.py # TMP117 temperature sensor class
│ ├── max30102.py # MAX30102 pulse oximeter sensor class
│ ├── bmi160.py # BMI160 IMU sensor class
│ └── ssd1306.py # SSD1306 OLED driver (copied library)
└── utils.py # Shared utilities (SpO₂ calc, helpers)
/
Common
- All sensors + OLED on the same I²C bus.
- Example (Arduino Nano ESP32):
- SDA → GPIO 11
- SCL → GPIO 12
TMP117
- VCC → 3.3 V
- GND → GND
- SDA/SCL → shared I²C lines
- ADD0 → GND (address 0x48)
GY-MAX30102
- VCC → 3.3 V
- GND → GND
- SDA/SCL → shared I²C lines
- Typical I²C address: 0x57
BMI160 (DFRobot SEN0250)
- VCC → 3.3–5 V (per module rating)
- GND → GND
- SDA/SCL → shared I²C
1.3" OLED (SSD1306)
- VCC → 3.3 V or 5 V (according to module)
- GND → GND
- SDA/SCL → shared I²C
- Typical I²C address: 0x3C or 0x3D
- Flash MicroPython to Arduino Nano ESP32 (using Arduino Lab for MicroPython or
esptool). [web:102] - Upload project files:
boot.py,main.pyFirmware/folder withSensors/andutils.py- Ensure
__init__.pyexists inFirmware/andFirmware/Sensors/.
- SSD1306 driver:
- Download
ssd1306.pyfrom:- https://github.com/stlehmann/micropython-ssd1306 [web:93][web:127]
- Place it as
Firmware/Sensors/ssd1306.pyor in the root, adjusting imports accordingly.
- Download
- Run:
- Reset the board.
- The display should show boot text (e.g. “Early Sepsis Detection – Initializing…”).
- Main loop will show temperature, SpO₂ estimate, and possibly raw R / Red values.
- Library:
ssd1306.py - Source: MicroPython SSD1306 driver (PyPI / GitHub fork).
- GitHub: https://github.com/stlehmann/micropython-ssd1306 [web:93][web:127]
- Original MicroPython docs: https://docs.micropython.org/en/latest/esp8266/tutorial/ssd1306.html [web:90]
- Datasheet: MAX30102 Pulse Oximeter and Heart-Rate Sensor. [web:21]
- Example MicroPython driver (conceptual reference):
- https://github.com/n-elia/MAX30102-MicroPython-driver [web:61][web:130]
- Datasheet: TMP117 High-Accuracy Digital Temperature Sensor (Texas Instruments).
- MicroPython driver reference:
- https://pypi.org/project/micropython-tmp117/ [web:42][web:44]
- Datasheet: BMI160 Small, low-power IMU (Bosch Sensortec). [web:35]
- DFRobot module docs (Gravity: BMI160 6-Axis IMU, SEN0250): [web:32][web:38]
- The SpO₂ algorithm is a simplified, non‑medical approximation based on DC/AC ratio-of-ratios and a linear mapping, and is not calibrated for clinical use.
- Motion, poor finger contact, ambient light, and sensor placement will strongly affect accuracy.
- This project is intended for research, learning, and prototyping, not for diagnostic or therapeutic decisions.