I’d be glad to share my code snippet with you and have you assist me in identifying any compatibility issues with Blynk. Upon merging the two codes, I’ve noticed that my sensor readings fluctuate, and the results sent via Blynk.virtualWrite are not coherent. Strangely, each code functions perfectly when executed separately.
Here’s my code
#define BLYNK_TEMPLATE_ID "******"
#define BLYNK_TEMPLATE_NAME "******"
#define BLYNK_PRINT Serial
#include <WiFi.h>
#include <BlynkSimpleEsp32.h>
#include <Wire.h>
#include "MAX30105.h" //sparkfun MAX3010X library
#include "heartRate.h"
SimpleTimer timer;
MAX30105 particleSensor;
char auth[] = "******"; // You should get Auth Token in the Blynk App.
char ssid[] = "******"; // Your WiFi credentials.
char pass[] = "******";
#define INTERVAL_MESSAGE2 60000
unsigned long time_2 = 0;
int period = 2000;
unsigned long time_now = 0;
double avered = 0;
double aveir = 0;
double sumirrms = 0;
double sumredrms = 0;
int i = 0;
int Num = 100; //calculate SpO2 by this sampling interval
int oxygen;
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 3000 // if red signal is lower than this , it indicates your finger is not on the sensor
#define MINIMUM_SPO2 0.0
const byte RATE_SIZE = 4; //Increase this for more averaging. 4 is good.
byte rates[RATE_SIZE]; //Array of heart rates
byte rateSpot = 0;
long lastBeat = 0; //Time at which the last beat occurred
float beatsPerMinute;
int beatAvg;
#define USEFIFO
void setup() {
Serial.begin(115200);
Serial.println("Initializing...");
Blynk.begin(auth, ssid, pass);
// Initialize sensor
while (!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);
}
Serial.println("Place your index finger on the sensor with steady pressure.");
//Setup to sense a nice looking saw tooth on the plotter
byte ledBrightness = 255; // 0x7F Options: 0=Off to 255=50mA
byte sampleAverage = 4; //Options: 1, 2, 4, 8, 16, 32
byte ledMode = 2; //Options: 1 = Red only, 2 = Red + IR, 3 = Red + IR + Green
int sampleRate = 400; //1000 is best but needs processing power//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
particleSensor.enableDIETEMPRDY();
timer.setInterval(500, sendUptime);
}
void sendUptime() {
Blynk.virtualWrite(V4, oxygen);
Blynk.virtualWrite(V3, beatAvg);
}
void loop() {
Blynk.run();
timer.run(); // Initiates SimpleTimer
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
#ifdef MAX30105
red = particleSensor.getFIFORed(); //Sparkfun's MAX30105
ir = particleSensor.getFIFOIR(); //Sparkfun's MAX30105
#else
red = particleSensor.getFIFOIR(); //why getFOFOIR output Red data by MAX30102 on MH-ET LIVE breakout board
ir = particleSensor.getFIFORed(); //why getFIFORed output IR data by MAX30102 on MH-ET LIVE breakout board
#endif
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 Serial plotter by thin out
if (millis() > TIMETOBOOT) {
if (ir < FINGER_ON)
ESpO2 = MINIMUM_SPO2; //indicator for finger detached
float temperature = particleSensor.readTemperatureF();
if (ESpO2 <= -1) {
ESpO2 = 0;
}
if (ESpO2 > 100) {
ESpO2 = 100;
}
oxygen = ESpO2;
Serial.print(" Oxygen % = ");
Serial.println(oxygen);
}
}
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; //low pass filter
//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);
}
long irValue = particleSensor.getIR();
if (checkForBeat(irValue) == true) {
//We sensed a beat!
long delta = millis() - lastBeat;
lastBeat = millis();
beatsPerMinute = 60 / (delta / 1000.0);
if (beatsPerMinute < 255 && beatsPerMinute > 20) {
rates[rateSpot++] = (byte)beatsPerMinute; //Store this reading in the array
rateSpot %= RATE_SIZE; //Wrap variable
//Take average of readings
//beatAvg = 0;
for (byte x = 0; x < RATE_SIZE; x++)
beatAvg += rates[x];
beatAvg /= RATE_SIZE;
}
}
Serial.print("IR=");
Serial.print(irValue);
Serial.print(", BPM=");
Serial.print(beatsPerMinute);
Serial.print(", Avg BPM=");
Serial.println(beatAvg);
if (millis() > time_2 + INTERVAL_MESSAGE2 && oxygen < 93) {
time_2 = millis();
//Blynk.notify("Alert! Oxygen Saturation below 93% Detected");
Serial.print("Alert called");
}
#endif
}