Pulse oximeters are in use since long during an operation, in intensive care, in the emergency room and other places such as in unpressurized aircraft. The COVID-19 pandemic made pulse oximetry technology for the consumers. Most of the finger pulse oximeters in the market lack BLE and Wi-Fi. There are only a few finger pulse oximeters which have a BLE to transmit data to the smartphone. Having a BLE to transmit data to the smartphone opens the way to sniff data with an ESP32 and send to any IoT platform. As finger pulse oximeters with BLE is still not common, we have to use ESP32, MAX30102 and IBM Watson IoT to create a project to show how we can remotely monitor anyone’s SpO2. In our previous guide on ESP32 MAX30102 Pulse Oximeter Code, we have shown a test code for ESP32 to get a graph of SpO2 on local computer using Arduino’s IDE. These kind of DIY projects are not for use as primary health monitoring devices.
We are using IBM Watson IoT because we are used with it and we have a lot of test codes on GitHub repository for doing many projects with IBM Watson IoT. Neither we get paid by IBM nor IBM charges for free IBM Cloud account. You’ll have no charge for using IBM Watson IoT within a limit. From IBM Watson IoT, we can use Node-RED to perform advanced works, like you can send an e-mail if SpO2 falls under a certain value. It worth mentioning that you can use the tools of IBM Watson for prediction.
What hardware required to start working?
You need an ESP32, MAX30102 (which looks like MAX30102 MH-ET LIVE breakout board) and a free IBM Cloud account. You need four female to female jumpers to connect ESP32 with MAX30102. You can use a power bank for the smartphones as a power supply to ESP32 or just use your computer’s USB port as a power source. Several power source options exist for ESP32.
---
Solder the 3.3v and middle jumpers of MAX30102 (see the photograph of our previous post). After soldering, test with a multimeter with resistance measurement settings to avoid short-circuit with 1V8 jumper. Put the MAX30102 inside a thin plastic wrap (like a thin plastic wrap of a cigarette pack) before keeping your finger on the sensor. You can use black tape to keep the MAX30102 attached with your finger and avoid light from external sources.
What software required to start working?
First, your Arduino IDE must be configured to run ESP32 (you can follow this guide to prepare the Arduino IDE).
Second, your Arduino IDE must be further tweaked to avoid Solve ESP32 Sketch Too Big Error on Arduino IDE ( you can follow this tutorial on how to Sketch Too Big Error on Arduino IDE).
Third, install the MAX30102 sensor library by Sparkfun and PubSubClient library.
Forth point is about configuring IBM Watson IoT. You can read our Getting Started With IBM Watson IoT Platform guide to get started. Like we have mentioned in the guide on WROOM ESP32 Example Codes, on IBM Watson IoT dashboard, you have to find out the Security option. Change the settings to TLS/HTTPS optional. This is a mandatory step to avoid seeing failing authorization on the log. How to use the dashboard widgets for Graphing/Visualization on IBM Watson IoT Platform is written in this guide.
What sketch required to start working?
This is the sketch. I modified this from the test code I have used in the previous article.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 | #include <Wire.h> #include "MAX30105.h" //sparkfun MAX3010X library #include <WiFi.h> #include <WiFiClient.h> #include <PubSubClient.h> MAX30105 particleSensor; //#define MAX30105 //if you have Sparkfun's MAX30105 breakout board , try #define MAX30105 #define USEFIFO // <------- CHANGE PARAMETERS BELOW THIS LINE ------------> const char ledPin = 2; const char* ssid = "YOUR-HOTSPOT-NAME"; const char* password = "YOUR-HOTSPOT-PASSWORD"; #define ORG "YOUR-ORG-NAME-ON-IBM-DASHBOARD" #define DEVICE_TYPE "YOUR-SET-DEVICE-TYPE" #define DEVICE_ID "YOUR-SET-DEVICE-TYPE" #define TOKEN "YOUR-SET-TOKEN-OR-AUTOGENERATED-TOKEN" // <------- CHANGE PARAMETERS ABOVE THIS LINE ------------> char server[] = ORG ".messaging.internetofthings.ibmcloud.com"; char pubTopic[] = "iot-2/evt/status/fmt/json"; char subTopic[] = "iot-2/cmd/test/fmt/String"; char authMethod[] = "use-token-auth"; char token[] = TOKEN; char clientId[] = "d:" ORG ":" DEVICE_TYPE ":" DEVICE_ID; WiFiClient wifiClient; PubSubClient client(server, 1883, NULL, wifiClient); void receivedCallback(char* pubTopic, byte* payload, unsigned int length) { Serial.print("Message received: "); Serial.println(pubTopic); Serial.print("payload: "); for (int i = 0; i < length; i++) { Serial.print((char)payload[i]); } Serial.println(); /* we got '1' -> on */ } void setup() { Serial.begin(115200); Serial.println("Initializing..."); Serial.print("Connecting to "); Serial.print(ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.print("WiFi connected, IP address: "); Serial.println(WiFi.localIP()); if (!client.connected()) { Serial.print("Reconnecting client to "); Serial.println(server); while (!client.connect(clientId, authMethod, token)) { Serial.print("."); delay(500); } client.setCallback(receivedCallback); if (client.subscribe(subTopic)) { Serial.println("subscribe to cmd OK"); } else { Serial.println("subscribe to cmd FAILED"); } Serial.println("IBM Watson IoT connected"); } // Initialize sensor if (!particleSensor.begin(Wire, I2C_SPEED_FAST)) //Use default I2C port, 400kHz speed { Serial.println("MAX30102 was not found. Please check wiring/power/solder jumper at MH-ET LIVE MAX30102 board. "); while (1); } //Setup to sense a nice looking saw tooth on the plotter byte ledBrightness = 0x7F; //Options: 0=Off to 255=50mA byte sampleAverage = 1; //Options: 1, 2, 4, 8, 16, 32 byte ledMode = 2; //Options: 1 = Red only, 2 = Red + IR, 3 = Red + IR + Green //Options: 1 = IR only, 2 = Red + IR on MH-ET LIVE MAX30102 board int sampleRate = 200; //Options: 50, 100, 200, 400, 800, 1000, 1600, 3200 int pulseWidth = 411; //Options: 69, 118, 215, 411 int adcRange = 16384; //Options: 2048, 4096, 8192, 16384 // Set up the wanted parameters particleSensor.setup(ledBrightness, sampleAverage, ledMode, sampleRate, pulseWidth, adcRange); //Configure sensor with these settings } double avered = 0; double aveir = 0; double sumirrms = 0; double sumredrms = 0; int i = 0; int Num = 100;//calculate SpO2 by this sampling interval double ESpO2 = 95.0;//initial value of estimated SpO2 double FSpO2 = 0.7; //filter factor for estimated SpO2 double frate = 0.95; //low pass filter for IR/red LED value to eliminate AC component #define TIMETOBOOT 3000 // wait for this time(msec) to output SpO2 #define SCALE 88.0 //adjust to display heart beat and SpO2 in the same scale #define SAMPLING 5 //if you want to see heart beat more precisely , set SAMPLING to 1 #define FINGER_ON 30000 // if red signal is lower than this , it indicates your finger is not on the sensor #define MINIMUM_SPO2 70.0 long lastMsg = 0; void loop() { uint32_t ir, red , green; double fred, fir; double SpO2 = 0; //raw SpO2 before low pass filtered #ifdef USEFIFO particleSensor.check(); //Check the sensor, read up to 3 samples while (particleSensor.available()) {//do we have new data red = particleSensor.getIR(); //why getFOFOIR outputs Red data by MAX30102 on MH-ET LIVE breakout board ir = particleSensor.getRed(); //why getFIFORed outputs IR data by MAX30102 on MH-ET LIVE breakout board i++; fred = (double)red; fir = (double)ir; avered = avered * frate + (double)red * (1.0 - frate);//average red level by low pass filter aveir = aveir * frate + (double)ir * (1.0 - frate); //average IR level by low pass filter sumredrms += (fred - avered) * (fred - avered); //square sum of alternate component of red level sumirrms += (fir - aveir) * (fir - aveir);//square sum of alternate component of IR level if ((i % SAMPLING) == 0) {//slow down graph plotting speed for arduino IDE toos menu by thin out //#if 0 if ( millis() > TIMETOBOOT) { if (ir < FINGER_ON) ESpO2 = MINIMUM_SPO2; //indicator for finger detached //Serial.print((2.0 * fir - aveir) / aveir * SCALE); // to display pulse wave at the same time with SpO2 data //Serial. print('\n'); // Serial.print((2.0 * fred - avered) / avered * SCALE); // to display pulse wave at the same time with SpO2 data //Serial. print('\n'); Serial.print(ESpO2); //low pass filtered SpO2 Serial. print('\n'); //#endif client.loop(); long now = millis(); if (now - lastMsg > 3000) { lastMsg = now; String payload = "{\"d\":{\"Name\":\"" DEVICE_ID "\""; payload += ",\"ESpO2\":"; payload += ESpO2; payload += "}}"; Serial.print("Sending payload: "); Serial.println(payload); if (client.publish(pubTopic, (char*) payload.c_str())) { Serial.println("Publish ok"); } else { Serial.println("Publish failed"); } } } } if ((i % Num) == 0) { double R = (sqrt(sumredrms) / avered) / (sqrt(sumirrms) / aveir); // Serial.println(R); SpO2 = -23.3 * (R - 0.4) + 100; //http://ww1.microchip.com/downloads/jp/AppNotes/00001525B_JP.pdf ESpO2 = FSpO2 * ESpO2 + (1.0 - FSpO2) * SpO2; // Serial.print(SpO2);Serial.print(",");Serial.println(ESpO2); sumredrms = 0.0; sumirrms = 0.0; i = 0; break; } particleSensor.nextSample(); //We're finished with this sample so move to next sample //Serial.println(SpO2); } #endif } |
We have kept the code on GitHub repository of ESP32 IBM Watson IoT Example. This is not a super-easy to follow guide. But, if you can follow then you can put any other medical electronics-related sensor in the same formula. As because I had 90% things ready, it took just a few hours to write the sketch.
Tagged With how to use max30102 with esp32 , how to connect max30102 to esp32 , pulse oximeter that connects to cloud