ESP32, MAX30100 and Firebase [code example]

Hey I had an issue with MAX30100 not taking readings when combined with code that sends the data to firebase. I found another post here in the forums that described the same issue. however, they offered a solution that is to turn off the sensor while sending then turn it back on once data is sent. I found a better solution but the thread has been closed so I thought I'd share this solution in a new post. The best solution for this issue is multi tasking. creating a task (process) for taking sensor reading and another one for sending those readings to the firebase. The solution is 100% working and I tested it on ESP32 which more or less the same as Arduino in terms of coding style. I had one issue for this solution to work which is how to determine stack depth (memory size) for each process. I assumed a reasonable depth like 5000 bytes for taking sensor readings and 8000 for sending to firebase then within each process print the free space in the stack. finally reduce the free stack number to about 500 bytes. and It works great.

2 Likes

Thanks for sharing a solution.

If you could share a simple example code, it would make a good tutorial.

Sure. This is how I did it in ESP32, I'm sure it would be similar to any Arduino board.

  • You need to install MAX30100 library
  • Install Firebase ESP Client Library
  • If ESP is not recognised from your PC make sure to install the latest driver update from espressif site.
  • The code sends data as soon as firebase is ready, If you want you could add an if statement to send the data on regular intervals like once per second.
  • You could make the process to send data is dependant on the process that takes sensor readings. That is after the reading process is finished it sends a semaphore to the sending process to start.
  • If you changes the memory size of a process and the ESP32 crashed it means that there is a process that requires more memory than whats assigned to it. you should test each process alone and see if it runs then combine the code.
  • Don't forget to add API and URL of your Real Time Database. And make sure that the write security rule is True or that your application is authinticated.
  • Add your wifi creditionals and you're all set.

Good Luck

The code :

#include <math.h>

//Start Wifi
#include <WiFi.h>
#include <Firebase_ESP_Client.h>
#define WIFI_SSID ""
#define WIFI_PASSWORD ""
//End Wifi

//Start Firebase
#include "addons/TokenHelper.h" //Provide the token generation process info.
#include "addons/RTDBHelper.h"  //Provide the RTDB payload printing info and other helper functions.
#define API_KEY "" // Insert Firebase project API Key
#define DATABASE_URL "" // Insert RTDB URLefine the RTDB URL */

FirebaseData FirebaseData;  //Firebase data object
FirebaseAuth auth;  //Firebase authentication object
FirebaseConfig config;  //Firebase configuration object

TaskHandle_t PostToFirebase;
bool signupOK = false;
// End Firebase

// Start Function Declaration
void SendReadingsToFirebase();
void InitializeWifi();
void SignUpToFirebase();
void InitializePOX();
// End Function Declaration

// Start Pulse Oximeter
#include <Wire.h>
#include "MAX30100_PulseOximeter.h"
#define POX_REPORTING_PERIOD_MS  1000

PulseOximeter pox;  // Create a PulseOximeter object

TaskHandle_t GetReadings;
uint8_t _spo2;
uint8_t _heartRate;

uint32_t poxLastReport = 0;
uint32_t prevMillis = 0;
// End Pulse Oximeter

void setup() {
  
  Serial.begin(115200); //Begin serial communication

  InitializeWifi();

  SignUpToFirebase();

  InitializePOX();

  xTaskCreatePinnedToCore(SensorReadings, "GetReadings", 1724, NULL, 0, &GetReadings, 0);
  
  xTaskCreatePinnedToCore(SendReadingsToFirebase, "PostToFirebase", 6268, NULL, 0, &PostToFirebase, 1);
}

void SensorReadings(void * parameter)
{
  for(;;)
  {
    // Read from the sensor
    pox.update();
      
    if (millis() - poxLastReport > POX_REPORTING_PERIOD_MS) {
      _heartRate = round(pox.getHeartRate());
      _spo2 = round(pox.getSpO2());
    
      Serial.print("Heart rate:");  
      Serial.print(_heartRate);
      Serial.print("bpm / SpO2:");
      Serial.print(_spo2);
      Serial.println("%");
    
      poxLastReport = millis();
    }
    // Memory Sizing
    //if (millis() - prevMillis > 6000)
    //{
    //  unsigned long remainingStack = uxTaskGetStackHighWaterMark(NULL);
    //  Serial.print("Free stack: ");
    //  Serial.print(remainingStack);
    //  prevMillis = millis();
    //}
    // End Memory Sizing
  }
}

void SendReadingsToFirebase(void * parameter)
{
  for(;;)
  {
    if (Firebase.ready() && signupOK){
      
      if (Firebase.RTDB.setInt(&FirebaseData, "HEARTRATE", _heartRate)){
          Serial.println("PATH: " + FirebaseData.dataPath());
          Serial.println("TYPE: " + FirebaseData.dataType());
      }
      else 
      {
          Serial.println("Failed to send Heartrate");
          Serial.println("REASON: " + FirebaseData.errorReason());
      }
    
      if (Firebase.RTDB.setInt(&FirebaseData, "SPO2", _spo2)){
          Serial.println("PATH: " + FirebaseData.dataPath());
          Serial.println("TYPE: " + FirebaseData.dataType());
     }
      else 
      {
          Serial.println("Failed to send SPO2");
          Serial.println("REASON: " + FirebaseData.errorReason());
      }
    }
  }
}

void InitializeWifi()
{
  // Wifi Initialize ...
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  Serial.print("Connecting to Wi-Fi");
  
  while (WiFi.status() != WL_CONNECTED){
    Serial.print(".");
    delay(300);
  }
  
  Serial.println();
  Serial.print("Connected with IP: ");
  Serial.println(WiFi.localIP());
  Serial.println();
}

void SignUpToFirebase()
{
  /* Assign the api key (required) */
  config.api_key = API_KEY;

  /* Assign the RTDB URL (required) */
  config.database_url = DATABASE_URL;

  /* Sign up */
  if (Firebase.signUp(&config, &auth, "", ""))
  {
    Serial.println("ok");
    signupOK = true;
  }
  else
  {
    Serial.printf("%s\n", config.signer.signupError.message.c_str());
  }

  /* Assign the callback function for the long running token generation task */
  config.token_status_callback = tokenStatusCallback; //see addons/TokenHelper.h
  
  Firebase.begin(&config, &auth);
  Firebase.reconnectWiFi(true);
}

void InitializePOX()
{
  Serial.print("Initializing pulse oximeter..");

  // Initialize sensor
  if (!pox.begin()) {
    Serial.println("FAILED");
    for(;;);
  } else {
    Serial.println("SUCCESS");
  }

  // Configure sensor to use 7.6mA for LED drive
  //pox.setIRLedCurrent(MAX30100_LED_CURR_7_6MA);
}

void loop()
{
  delay(1);  
}
3 Likes

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