Skip to content

neobitlab/neoPPG

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

neoPPG

An ESP-IDF component for the DFRobot Gravity: MAX30102 PPG Heart Rate and Oximeter Sensor (SEN0518). Provides a clean C API for reading heart rate (BPM), blood oxygen saturation (SpO2), and die temperature over I2C.

⚠️ This is NOT a generic MAX30102 driver. It is written specifically for the DFRobot Gravity SEN0518 module. That module pairs the MAX30102 chip with an onboard MCU that runs the full PPG signal processing pipeline (peak detection, DC removal, SpO2 ratio calculation) and exposes the already-computed results via its own I2C register map. If you wire a bare MAX30102 chip to this and expect it to work, it won't — the register layout is completely different.

Features

  • Read SpO2 (%) and heart rate (BPM) from precomputed sensor registers
  • Read die temperature from the sensor
  • Controlled measurement sessions via neoPPG_start_collect / neoPPG_end_collect
  • Device ID verification on init to catch wiring mistakes early
  • Minimal footprint — pure C, no heap-heavy abstractions

Requirements

  • ESP-IDF (uses the legacy i2c driver — compatible with ESP-IDF v4.x and v5.x)
  • DFRobot Gravity Heart Rate and SpO2 Sensor (MAX30102-based module, I2C)

Hardware Setup

Connect the sensor module to your ESP32:

Sensor Pin ESP32 Pin
VCC 3.3V or 5V
GND GND
SDA I2C_MASTER_SDA_IO (defined in neoPPG.h)
SCL I2C_MASTER_SCL_IO (defined in neoPPG.h)

The default I2C address is 0x57 (DFRobot SEN0518 default).

Installation

Clone or copy this component into your project's components/ directory:

cd your_project/components
git clone https://github.com/neobitlab/neoPPG.git

Configuration

Before building, set your pin assignments in include/neoPPG.h:

#define I2C_MASTER_SCL_IO   22
#define I2C_MASTER_SDA_IO   21
#define I2C_MASTER_NUM      I2C_NUM_0
#define I2C_MASTER_FREQ_HZ  100000
#define DEVICE_ADDRESS      0x57   // DFRobot SEN0518 default

Quick Start

#include "neoPPG.h"

void app_main(void) {
    neoPPG_handle_t sensor = {0};

    // Initialize I2C and verify device ID
    ESP_ERROR_CHECK(neoPPG_init(&sensor));

    // Start a measurement session
    ESP_ERROR_CHECK(neoPPG_start_collect(&sensor));

    // Wait for the sensor to acquire data
    vTaskDelay(pdMS_TO_TICKS(4000));

    // Read SpO2 and BPM
    ESP_ERROR_CHECK(neoPPG_measure(&sensor));

    if (sensor.readings.SPO2 != -1 && sensor.readings.BPM != -1) {
        printf("SpO2: %d%%  |  BPM: %d\n",
               sensor.readings.SPO2,
               sensor.readings.BPM);
    } else {
        printf("No valid reading — make sure finger is on sensor.\n");
    }

    // Read die temperature
    float temp;
    ESP_ERROR_CHECK(neoPPG_get_temperature(&sensor, &temp));
    printf("Die temp: %.2f °C\n", temp);

    // End measurement session
    ESP_ERROR_CHECK(neoPPG_end_collect(&sensor));
}

API Reference

Initialization

// Initialize I2C master and verify the sensor is reachable at the expected address.
// Returns ESP_ERR_NOT_FOUND if the device doesn't respond (check wiring and I2C address).
esp_err_t neoPPG_init(neoPPG_handle_t *dev);

Measurement Control

// Tell the sensor module to start collecting PPG data
esp_err_t neoPPG_start_collect(neoPPG_handle_t *dev);

// Stop collection
esp_err_t neoPPG_end_collect(neoPPG_handle_t *dev);

Data Acquisition

// Read SpO2 and BPM from the sensor registers.
// Results are stored in dev->readings.SPO2 and dev->readings.BPM.
// Returns -1 for a field if the sensor reports no valid reading.
esp_err_t neoPPG_measure(neoPPG_handle_t *dev);

// Read the sensor module's die temperature in °C
esp_err_t neoPPG_get_temperature(neoPPG_handle_t *dev, float *temperature);

Handle Structure

typedef struct {
    i2c_port_t i2c_port;
    uint8_t    device_addr;
    struct {
        int32_t SPO2;  // Blood oxygen saturation (%), or -1 if invalid
        int32_t BPM;   // Heart rate (beats per minute), or -1 if invalid
    } readings;
} neoPPG_handle_t;

Notes

  • The sensor module needs a few seconds to stabilize after neoPPG_start_collect. A 3–5 second delay before calling neoPPG_measure is typical.
  • Invalid readings (-1) usually mean no finger is detected or the contact is poor.
  • This component initializes its own I2C driver. If you're sharing the I2C bus with other peripherals, you'll need to either refactor the init or ensure i2c_driver_install is only called once.

Acknowledgements

Inspired by DFRobot_BloodOxygen_S by DFRobot.

About

An ESP-IDF component for the DFRobot Gravity: MAX30102 PPG Heart Rate and Oximeter Sensor (SEN0518)

Resources

License

Stars

Watchers

Forks

Contributors