Problem about using ESP32 send data to MQTT broker (Raspberry Pi Node-RED))

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();
}

Closing the serial monitor resets the board.
Do you get MQTT messages if the Serail Monitor is closed or do you just get that last message and no others after that?

Once I close the serial monitor, after 20-30s, I am still able to get the MQTT message and see it on Node-RED. Initially, the message "Finger Please" is displayed when I move my finger away from the MAX30102 sensor. However, when I place my finger on the sensor to detect blood oxygen and heartbeat, the readings remain steady at 90 for blood oxygen and 0 for heartbeat (beatAvg = 0, ESpO2 = 90). These values return to normal and start to fluctuate once I reopen the serial monitor.

That code does nothing useful.

Why the hell do you call the sensor variable "particleSensor"? It has nothing to do with particles.

Oh, I found out, the developer of the library was that stupid (Sparkfun).

You ruin heartbeat detection if you publish a value for every peak detected. You even do that before you calculate the value.

Then you do the FIFO read for the EspO2 value but you read one value (which is OK if the loop() is called often enough) and then again publish the values, which needs some time

But after all I didn't found any part in the code that would keep it from executing if no Serial Monitor is displaying the values.

May I ask which exact ESP32 board you're using? If that's an exotic one we may have to investigate the hardware.

I am currently using a board called xiao esp32c3. I may use another ESP32, try to see if that solves the problem, thanks for your help🙏🏻

ES32C3 is not an ESP32! That's completely different, it has even a different processor architecture (RISC-V).

Many of the peripheral components are identical but not all, some features of the ESP32 are not available on the ESP32C3.

The ESP32C3 has an USB serial controller integrated into the processor core, so the behavior when the USB connection is removed is different from an ESP32 (where the USB2Serial converter is external).

It worked fine after I commented out the 'Serial.begin' . Thank you so much for inspiring me.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.