ESP Heart Rate Monitor

Updates browser couple times a second with realtime heartrate graph, displays heartrate and oxygen concentration.

Public Chat
Similar projects worth following
Initially posted this project about a year ago, have recently made major changes. Link to github code repository added.

This is a project with an ESP32, MAX30102 heartrate monitor module, an SSD1306 OLED display was recently added. Link to ESP-IDF github repository, with instructions to get working, included below.


The MAX chip has a red led and an ir led along with photo detectors that measure the amount of red and ir light returning to the chip. When you put a capillary rich part of your body on (or near) the chip a significant amount of both red and ir light is returned. The MAX chip digitizes the red and ir measurements and places the results in a fifo where the 24 bit data is read out with the i2c interface at 100 samples per second. The predominate feature of this data is substantial low frequency variation when you move your finger even a little, however, on top of this is an about 0.5% variation occurring approximately every 1 second.

My understanding is that - it turns out that as you heart beats new, oxygenated, blood is swept into the capillarys and the amount of reflected light into the MAX chip changes. The color of blood changes as oxygenation changes, so, there is an established relationship between the heartbeat related ac component of the returned red and ir light and the oxygen concentration of the blood ( spo2% = 110-25(%redac/%irac) ).

My ESP32 is running two tasks. The first task runs about five times per second, it i2c reads how many samples are stored in MAX30102 fifo, it reads the samples, it passes the samples through 0.5-5Hz 2nd order butterworth band pass filter, does cycle peak and ac/dc magnitude extraction on data stream, calculates heartrate and spo2 concentrations (and averages over five samples), once every ~1 second updates oled display and saves raw data in tcp response string for other task. The other task hosts up index.html page with javascipt to read raw data from ESP32 - the script displays heartrate and spo2 numbers, uses plotly to graph raw data and provides an interface to pause javascript, switch between raw and filtered data and to change led intensities.

The Code and Hookup

Hookup is straight forward - vcc goes to 3.3v (NOT 5V), sda and scl pins defined main/heartrate.c:25 - around there.

Checked with two releases of isp-idf (as reported in esp-idf directory with git describe) v4.1-dev-2055 and v3.3-beta1-506. v4.1 gives a couple obsolete soft warnings during compile that I haven't tracked down yet. v3.3 requires extra include file added to main/heartrate.c (#include "esp_event_loop.h").

So all needs be done (hopefully - once you have esp-idf environment setup) is "git clone <link below>", "cd esp32-max30102-website" and "make flash monitor" (when menuconfig comes up setup correct correct tty port and the ~1Mbuad rate works good for me). That's what worked for me on a couple clean linux systems.

Never posted code before so not sure if I gave enough information, feel free to contact.

Note on Accuracy

The time bases in esp and max30102 agree very well, and both look good over a 10 minute stopwatch count (<.1%), so I'm pretty sure the heartrate is accurate (although it does vary from pulse to pulse ~10% or so - keeping a running average of five pulses seems to steady it out to ~1% about). I just plugged the measurements into the spO2 equation published by maxim integrated and got the result that I am usually reading is 99% +/-1 (unless the signal is too small) - I don't really know how to calibrate the spO2 - but I did do this dumb experiment where I was breathing into plastic bag and did get the spO2 to decrease - started getting pretty dizzy approaching 92% - hypoxic. Although having copd or a bad case of the flu can get you lower than that, anything under 90% or a 3% drop in short amount of time googled up very bad. Disclaimer - these are my impressions gained working project and have not done a detailed experiment.

Improvements that I would like to make include - mode where LED powers are automatically optimized and data logging for...

Read more »


Project in action about halfway through finger is placed on device.

MPEG-4 Video - 7.31 MB - 02/28/2019 at 18:07


  • 1 × ESP8266 D1mini Module
  • 1 × MAX30100 Module
  • 1 × Four wires for I2C and 5v power
  • 1 × USB micro cable to Host Supplies ESP8266 power and serial comms

  • Moved butterworth over to ESP32

    markwarren.ee03/04/2019 at 00:27 0 comments

    The process of moving my filtering from JS up to the esp went very smooth. I couldn't get the esp8266 to hold it but had no problem with the esp32.

    Currently am using a 100Hz 2nd order butterworth with poles at 0.5 and 25 Hz. Raw data averages are needed on the client side to calculate SpO2 concentration and adjust led brightness which are calculated by the esp and transmitted in the tcp return packet.

    Also learning my way around github and plan to pub code and instructions shortly.

  • ESP32 and MAX30102 - massive upgrade

    markwarren.ee03/02/2019 at 18:09 0 comments

    A couple of days ago I got my first ESP32 module and a MAX30102 module and decided to upgrade.

    The ESP32 is a real good upgrade - I tripled my tcp update rate and doubled the max30102 sampling rate to 100Hz, while decreasing the number of dropped packets by 95+%. The ESP32 has much more memory so my buffer sizes are no longer an issue and don't have to worry about task stack allocation sizes.

    I feel emboldened to move the dsp ops over to the esp, including butterworth filtering, raw data averaging and floating point conversion.

    My daughter is attending a  'Girls Who Code' Club meeting over at WPI this winter and is learning some html coding - so I got her on the rope to add at least a few style tags to the html page.

    ps. Upgrading from esp8266 was not bad. I am currently maintaining separate IDF toolchains (but it looks possible that the esp32 tools might work with the 8266 as long as you configure in menuconfig - which would be worth doing), some of the library functions changed slightly but we're talking 99% of code portable.

  • ESP8266 Heartrate Moniitor

    markwarren.ee02/28/2019 at 18:26 0 comments

    This project collects data from a max30100 heart rate monitor device and presents a webpage to a connected browser displaying the real time data as well as the dsp derived Pulse Rate and Oxygen concentration results.

    Here we are using the Espressif IoT Developemnt Framework to compile user application code, build the ESP code image and flash it into the ESP device. The setup is pretty easy and well documented on several websites.

    The ESP device establishes a wi-fi connection, then configures the max30100 to collect 50 samples per second of red and IR data. It then continuously runs two tasks:     a) read max30100 buffer pointers and construct a read of available sample data with I2C bus, configure data into words and load into local buffer,     b) setup tcp server socket and listens for http request. When http request packet is received it is parsed to extract whether it is requesting a) a file, like index.html or index.css or a js file, b) a request for a data string dump or c)a POST append containing variables altered within the client browser (or a curl command).

    This nets a single C program with no non-ESP8266_RTOS_SDK dependencies of about 300 lines, most of which were cut and pasted from the sdk examples folder. The other coding portion of this program is an .html (about 200 lines) that is embedded in the esp read only memory at compile time (if referenced in The .html file is served via tcp to your browser when the esp's url is addressed.

    The JavaScript in the .html runs a setInterval function a few times a second to make a tcp HTTP Request to the esp to getData it them performs a bunch of bookkeeping for each plot update cycle :    a)control of plot modes, ie run/pause, display data type raw/filtered    b)send POST variable data from browser tags to esp (for things like controlling led brightness)    c)downloads plotly.js for handling graph real time output display    d)formats data returned from esp into plotly format    e)performs dsp operations to bandpass filter (4 pole butterworh) raw data and extract and display heartrate and oxygen concentration measurements.

View all 3 project logs

Enjoy this project?


Discussions wrote 01/10/2020 at 17:20 point

checked modules - 4.7k pullups

  Are you sure? yes | no

BlackCrowBlues wrote 01/07/2020 at 10:32 point

I don't see any pull-up resistors on your SDA/SCL lines. This could be a problem

  Are you sure? yes | no

Sam wrote 11/14/2019 at 22:05 point

Hey, I would LOVE to see your source code for this, I want to make something similar!

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates