I program it using Arduino IDE. In my case, I use ESP32 to connect Max30102 to measure blood oxygen level and heartbeat, and then use MQTT method to transmit the data to Node-red on Raspberry Pi. But the problem is, if I open the Serial Monitor of Arduino IDE, the data can be displayed on Node-Red correctly. But when I close the Serial Monitor, it will be disconnected for a short period of time, and then only a fixed value can be displayed (beatAvg = 0, ESpO2 = 90), is there any solution?
//---- Setup update frequency -----//
const long TEMP_updateInterval = 1000; // How long to change temp and update, 10000 = 10 sec
unsigned long TEMP_currentMillis = 0;
unsigned long TEMP_previousMillis = 0; // store last time temp update
#include "MAX30105.h" //MAX3010x library
#include "heartRate.h" //Heart rate calculating algorithm
MAX30105 particleSensor;
//計算心跳用變數
const byte RATE_SIZE = 4; //多少平均數量
byte rates[RATE_SIZE]; //心跳陣列
byte rateSpot = 0;
long lastBeat = 0; //Time at which the last beat occurred
float beatsPerMinute;
int beatAvg;
//計算血氧用變數
double avered = 0;
double aveir = 0;
double sumirrms = 0;
double sumredrms = 0;
double SpO2 = 0;
double ESpO2 = 90.0;//初始值
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
int i = 0;
int Num = 30;//取樣30次才計算1次
#define FINGER_ON 7000 //紅外線最小量(判斷手指有沒有上)
#define MINIMUM_SPO2 90.0 //血氧最小量
int WIFILED = 5;
/*
SimpleMQTTClient.ino
The purpose of this exemple is to illustrate a simple handling of MQTT and Wifi connection.
Once it connects successfully to a Wifi network and a MQTT broker, it subscribe to a topic and send a message to it.
It will also send a message delayed 5 seconds later.
*/
#include "EspMQTTClient.h"
EspMQTTClient client(
"---------", // Wi-Fi AP name
"-------", // Wi-Fi Password
"---------", // MQTT Broker server ip/ Using What is my IP
"yat", // Broker user name; Can be omitted if not needed
"--------", // Broker password; Can be omitted if not needed
"MAX30102", // Client name that uniquely identify your device
1883 // The MQTT port, default to 1883. this line can be omitted
);
void setup()
{
Serial.begin(115200);
//Start DH11 sensor
//change
if (!particleSensor.begin(Wire, I2C_SPEED_FAST)) //Use default I2C port, 400kHz speed
{
Serial.println("Cant find MAX30102");
while (1);
}
//
byte ledBrightness = 0x7F; //suggest=127, 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(血氧)
int sampleRate = 800; //Options: 50, 100, 200, 400, 800, 1000, 1600, 3200
int pulseWidth = 215; //Options: 69, 118, 215, 411
int adcRange = 16384; //Options: 2048, 4096, 8192, 16384
particleSensor.setup(ledBrightness, sampleAverage, ledMode, sampleRate, pulseWidth, adcRange); //Configure sensor with these settings
particleSensor.enableDIETEMPRDY();
particleSensor.setPulseAmplitudeRed(0x0A); //Turn Red LED to low to indicate sensor is running
particleSensor.setPulseAmplitudeGreen(0); //Turn off Green LED
pinMode(WIFILED, OUTPUT);
// Optionnal functionnalities of EspMQTTClient :
client.enableDebuggingMessages(); // Enable debugging messages sent to serial output
//client.enableHTTPWebUpdater(); // Enable the web updater. User and password default to values of MQTTUsername and MQTTPassword. These can be overrited with enableHTTPWebUpdater("user", "password").
//client.enableLastWillMessage("TestClient/lastwill", "I am going offline"); // You can activate the retain flag by setting the third parameter to true
}
// This function is called once everything is connected (Wifi and MQTT)
// WARNING : YOU MUST IMPLEMENT IT IF YOU USE EspMQTTClient
void onConnectionEstablished()
{
// Subscribe to "mytopic/test" and display received message to Serial
client.subscribe("message/hello", [](const String &payload)
{ Serial.println(payload); });
// Subscribe to "mytopic/wildcardtest/#" and display received message to Serial
//client.subscribe("mytopic/wildcardtest/#", [](const String &topic, const String &payload)
// { Serial.println("(From wildcard) topic: " + topic + ", payload: " + payload); });
// Publish a message to "mytopic/test"
client.publish("studio/spo2", "Let's go!"); // You can activate the retain flag by setting the third parameter to true
client.publish("studio/bpm", "Let's go!"); // You can activate the retain flag by setting the third parameter to true
digitalWrite(WIFILED, HIGH);
// Execute delayed instructions
//client.executeDelayed(5 * 1000, []()
// { client.publish("mytopic/wildcardtest/test123", "This is a message sent 5 seconds later"); });
}
void loop()
{
TEMP_currentMillis = millis();
if(TEMP_currentMillis - TEMP_previousMillis >= TEMP_updateInterval){
TEMP_previousMillis = TEMP_currentMillis;
}
long irValue = particleSensor.getIR(); //Reading the IR value it will permit us to know if there's a finger on the sensor or not
//put the finger or not
if (irValue > FINGER_ON ) {
//check heart beat
if (checkForBeat(irValue) == true) {
Serial.print("Bpm="); Serial.println(beatAvg);//
client.publish("studio/bpm", String(beatAvg));
long delta = millis() - lastBeat;//計算心跳差
lastBeat = millis();
beatsPerMinute = 60 / (delta / 1000.0);//cal bpm
if (beatsPerMinute < 255 && beatsPerMinute > 20) {
//bpm must between 20-255
rates[rateSpot++] = (byte)beatsPerMinute; //save bpm
rateSpot %= RATE_SIZE;
beatAvg = 0;// cal avg
for (byte x = 0 ; x < RATE_SIZE ; x++) beatAvg += rates[x];
beatAvg /= RATE_SIZE;
}
}
// detect spo2
uint32_t ir, red ;
double fred, fir;
particleSensor.check(); //Check the sensor, read up to 3 samples
if (particleSensor.available()) {
i++;
ir = particleSensor.getFIFOIR(); //red IR
red = particleSensor.getFIFORed(); //read red
//Serial.println("red=" + String(red) + ",IR=" + String(ir) + ",i=" + String(i));
fir = (double)ir;//change to double
fred = (double)red;//change to double
aveir = aveir * frate + (double)ir * (1.0 - frate); //average IR level by low pass filter
avered = avered * frate + (double)red * (1.0 - frate);//average red level by low pass filter
sumirrms += (fir - aveir) * (fir - aveir);//square sum of alternate component of IR level
sumredrms += (fred - avered) * (fred - avered); //square sum of alternate component of red level
if ((i % Num) == 0) {
double R = (sqrt(sumirrms) / aveir) / (sqrt(sumredrms) / avered);
SpO2 = -23.3 * (R - 0.4) + 100;
ESpO2 = FSpO2 * ESpO2 + (1.0 - FSpO2) * SpO2;//low pass filter
if (ESpO2 <= MINIMUM_SPO2) ESpO2 = MINIMUM_SPO2; //indicator for finger detached
if (ESpO2 > 100) ESpO2 = 99.9;
//Serial.print(",SPO2="); Serial.println(ESpO2);
sumredrms = 0.0; sumirrms = 0.0; SpO2 = 0;
i = 0;
}
particleSensor.nextSample(); //We're finished with this sample so move to next sample
}
//display display in serial
Serial.print("Bpm:" + String(beatAvg));
client.publish("studio/bpm", String(beatAvg));
//BPM over 30, show SPO2
if (beatAvg > 30){
Serial.println(",SPO2:" + String(ESpO2));
client.publish("studio/spo2", String(ESpO2));
}
else {
Serial.println(",SPO2:" + String(ESpO2));
client.publish("studio/spo2", String(ESpO2));
}
}
//if no finger, display"Finger Please"
else {
//clear heart beat data
for (byte rx = 0 ; rx < RATE_SIZE ; rx++) rates[rx] = 0;
beatAvg = 0; rateSpot = 0; lastBeat = 0;
//clear SPO2 data
avered = 0; aveir = 0; sumirrms = 0; sumredrms = 0;
SpO2 = 0; ESpO2 = 90.0;
//顯示Finger Please
Serial.println("Finger Please");
//Publish
client.publish("studio/spo2", String("Finger Please"));
client.publish("studio/bpm", String("Finger Please"));
}
// Here is how to subscribe
//client.subscribe("message/hello", [](const String &payload) { Serial.println(payload); });
client.loop();
}