Medi-Sense

by Jeetasha in Circuits > Raspberry Pi

261 Views, 1 Favorites, 0 Comments

Medi-Sense

WhatsApp Image 2023-10-19 at 09.02.06 (1).jpeg
WhatsApp Image 2023-10-19 at 09.02.06.jpeg

Medi-Sense is a state-of-the-art remote healthcare monitoring device that employs the use of various sensors in order to monitor various healthcare parameters of the user. Medi-Sense is more than just a technological endeavor and is about making healthcare more accessible, convenient, and responsive to the evolving needs of society. This project combines the power of the Max30100 pulse oximeter sensor, AD8232 ECG sensor, MLX90614 temperature sensor, Raspberry Pi, and the Arduino Nano 33 IoT.

Supplies

Screenshot 2023-10-19 125537.png
Max30100 sensor.jpg
Mlx90614 temperature sensor.jpg

Make the Required Connections

Circuit Diagram.jpeg
  • MAX30100 SENSOR :
  1. VCC - 3.3 V
  2. GND - GND of Arduino Nano 33 IOT board
  3. SCL - A5
  4. SDA - A4
  • MLX90614 TEMPERATURE SENSOR :
  1. VCC - 3.3V
  2. GND - GND
  3. SCL - SCL
  4. SDA - SDA
  • AD8232 ECG SENSOR MODULE :
  1. 3.3V - 3.3V of Arduino Nano 33 IOT
  2. GND - GND
  3. LO(-) - D11
  4. LO(+) - D10
  5. OUTPUT - A0

You can refer to the circuit diagram for the connections. Make sure the connections are tight. Consider making a PCB for same.

Setting Up Firebase

Firebase.png
Project Overview.png

You can refer to this YouTube video link for setting up a project with Firebase:-

https://www.youtube.com/watch?v=4B85lFGTL-U

After setting up the project you would need your database credentials in the Arduino Ide code.

Follow the below mentioned steps for finding the credentials:-

  • Go to firebase console and open the project that you have just created.
  • Click on the Project Overview option present on the left side of the dashboard and then click on project settings. Scroll down and you will get the database URL. For the database secret key go onto the service account tab present under the project settings option and click on database secrets. You will get your Firebase Secret key from there.

Setting Up an IFTTT Trigger

Ifttt.png
Documentation button.png

You need to create a trigger on IFTTT for storing the data on the Excel sheets. You can refer to the below-mentioned Youtube video to learn how to create a trigger for storing sensor data in Excel sheets.

https://www.youtube.com/watch?v=w-iBewJGY2s

You would need your IFTTT event name and key in the Arduino IDE code.

For finding the key click on the applet that you just created. After the applet details open up, click on the webhook icon present on the left side. After the webhook page opens up click on the documentation button and your key will be displayed to you.

The Code : Arduino Nano 33 IOT

Arduino Ide.png

In the Arduino Ide write the code for saving the data in the Excel sheet and updating the values in the real-time database of Firebase. The IFTTT webhook service has been used for saving the data on Excel sheets. You can consider the below-mentioned link for more knowledge about this webhook :-

https://randomnerdtutorials.com/esp32-esp8266-publish-sensor-readings-to-google-sheets/

You can refer to the Basic example of Firebase_Arduino_WiFiNINA.h library to get more knowledge about updating the Firebase Real-time data values using Arduino IDE.

Here is the Arduino Ide Code:-

Make sure you add your Wifi and Firebase credentials

/*

 Description: The code for storing sensor data in excel sheets and updating

 the firebase reatime database.

 

 Hardware: Arduino Nano 33 IOT, Max30100 sensor, MLX90614 Temperature sensor, AD8232 ECG sensor


 Note:

 => Libraries required

 - WifiNINA by Arduino

 - Wire.h

 - MAX30100_PulseOximeter.h

 - Adafruit_MLX90614.h

 - Firebase_Arduino_WiFiNINA.h


 Circuit Connections:

 MAX30100 SENSOR :

  VCC - 3.3 V

  GND - GND of Arduino Nano 33 IOT board

  SCL - A5

  SDA - A4

 MLX90614 TEMPERATURE SENSOR :

  VCC - 3.3V

  GND - GND

  SCL - SCL

  SDA - SDA

 AD8232 ECG SENSOR MODULE :

  3.3V - 3.3V of Arduino Nano 33 IOT

  GND - GND

  LO(-) - D11

  LO(+) - D10

  OUTPUT - A0


 Note:

 Make sure the connections are tight. Consider making a PCB for same.

*/


//Including the required libraries

#include <WiFiNINA.h>

#include <Wire.h>

#include "MAX30100_PulseOximeter.h"

#include <Adafruit_MLX90614.h>

#include "Firebase_Arduino_WiFiNINA.h"


//Add your database credentials

#define DATABASE_URL "" //<databaseName>.firebaseio.com or <databaseName>.<region>.firebasedatabase.app

#define DATABASE_SECRET ""

//Add your Wifi Credentials

#define WIFI_SSID ""

#define WIFI_PASSWORD ""


// Define Firebase data object

FirebaseData fbdo;


#define REPORTING_PERIOD_MS 1000

Adafruit_MLX90614 mlx = Adafruit_MLX90614();


PulseOximeter pox;

uint32_t tsLastReport = 0;


void onBeatDetected() {

 Serial.println("Beat!");

}


// Ifttt settings

const char* server = "maker.ifttt.com";

String eventName = "";//Write your event name here

String IFTTT_Key = "";//Write your IFTTT key here


float value1 = 0.0;

float value2 = 0.0;

float value3 = 0.0;


String path = "/ ";//Write the name of the Realtime datbase field after /


void setup() {

 Serial.begin(9600);


 Serial.print("Connecting to Wi-Fi");

 int status = WL_IDLE_STATUS;

 while (status != WL_CONNECTED) {

  status = WiFi.begin(WIFI_SSID, WIFI_PASSWORD);

  Serial.print(".");

  delay(100);

 }

 Serial.println();

 Serial.print("Connected with IP: ");

 Serial.println(WiFi.localIP());

 Serial.println();


 // Provide the authentication data

 Firebase.begin(DATABASE_URL, DATABASE_SECRET, WIFI_SSID, WIFI_PASSWORD);

 Firebase.reconnectWiFi(true);


 Serial.println("Setting Sensor Data");


 // Initializing Pulse Oximeter sensor

 Serial.println();

 Serial.print("Initializing pulse oximeter..");


 // Initialize the PulseOximeter instance

 // Failures are generally due to an improper I2C wiring, missing power supply

 // or wrong target chip

 if (!pox.begin()) {

  Serial.println("FAILED");

  for (;;) {

  }

 } else {

  Serial.println("SUCCESS");

 }

 pox.setIRLedCurrent(MAX30100_LED_CURR_7_6MA);


 // Initializing the MLX90614 temperature sensor

 Wire.begin();

 mlx.begin();


 pinMode(10, INPUT); // Setup for leads off detection LO +

 pinMode(11, INPUT); // Setup for leads off detection LO -

 

}


void sendDataToIFTTT() {

 // Prepare the URL with event name and values

 String url = "/trigger/" + eventName + "/with/key/" + IFTTT_Key +

        "?value1=" + String(value1) + "&value2=" + String(value2) +

        "&value3=" + String(value3);


 Serial.println("Sending data to IFTTT: " + url);


 // Create a WiFiClient object

 WiFiClient client;


 // Connect to the server

 if (client.connect(server, 80)) {

  // Send an HTTP request

  client.print("GET " + url + " HTTP/1.1\r\n");

  client.print("Host: " + String(server) + "\r\n");

  client.print("Connection: close\r\n\r\n");

  // Read and print the response

  while (client.connected()) {

   if (client.available()) {

    String line = client.readStringUntil('\n');

    Serial.println(line);

   }

  }

  // Disconnect from the server

  client.stop();

 } else {

  Serial.println("Failed to connect to the server");

 }

}

void loop() {

 // Read sensor values

 // Make sure to call update as fast as possible

 pox.update();

 if (millis() - tsLastReport > REPORTING_PERIOD_MS) {

  // Read heart rate and SpO2 values

  float heartRate = pox.getHeartRate();

  float SpO2Value = pox.getSpO2();

  float ecg=analogRead(A0);

  if (heartRate > 0 && SpO2Value > 0) {

   Serial.print("Heart rate: ");

   Serial.print(heartRate);

   Serial.print(" bpm / SpO2: ");

   Serial.print(SpO2Value);

   Serial.println("%");

   value2 = static_cast<float>(heartRate);

   value3 = static_cast<float>(SpO2Value);

   //Measuring Temp

   value1=static_cast<double>(mlx.readAmbientTempC());

   // Send data to IFTTT

   sendDataToIFTTT();

   // Sending data to Firebase

   if (Firebase.setFloat(fbdo, path + "/Heart", value2)) {

    Serial.println("Heart rate uploaded to Firebase");

   } else {

    Serial.println("Error uploading Heart rate to Firebase: " + fbdo.errorReason());

   }

   if (Firebase.setFloat(fbdo, path + "/Spo2", value3)) {

    Serial.println("SpO2 uploaded to Firebase");

   } else {

    Serial.println("Error uploading SpO2 to Firebase: " + fbdo.errorReason());

   }

   if (Firebase.setDouble(fbdo, path + "/Temp", value1)) {

    Serial.println("Temp uploaded to Firebase");

   } else {

    Serial.println("Error uploading SpO2 to Firebase: " + fbdo.errorReason());

   }

   if (Firebase.setDouble(fbdo, path + "/ECG", ecg)) {

    Serial.println("ECG uploaded to Firebase");

   } else {

    Serial.println("Error uploading ecg to Firebase: " + fbdo.errorReason());

   }

  } else {

   Serial.println("Invalid Heart rate or SpO2 values");

  }

  tsLastReport = millis();

 }

 // Continue with other code...

}

Appscript Server Code

Screenshot 2023-10-19 115217.png

After getting sensor data to google sheets we need to setup our cloud Firestore. For this, open google firebase. Sign in using the same google account in which you created the sheets. If you are already signed in then your google profile pic will be visible at the top right corner. After signing in click on ‘Go to console’.

Open your project and click on cloud firestore. After that click on create database button.

Choose the database creation mode - go with 'test' for DIY projects. You can change it later by modifying Firebase rules. Then, click 'Next'.

Choose an appropriate location and your firestore database is created.

For finding your project credentials follow the steps given in the below mentioned link.

https://ashnizaster.medium.com/how-to-send-sensor-data-to-firebase-firestore-using-google-app-script-part-2-432cb55f3f27

Consider starting from step 5 as all the previous steps have been already performed.

For writing the app script code open up your Excel sheet and click on the Appscript option present under the extensions option.

Write this code in the code.gs file:-

function doGet(e) {

 Logger.log( JSON.stringify(e) ); // view parameters

 var result = 'Ok'; // assume success

 if (e.parameter == 'undefined') {

  result = 'No Parameters';

 }

 else {

  var sheet_id = ' ';  // Spreadsheet ID

  var sheet = SpreadsheetApp.openById(sheet_id).getActiveSheet(); // get Active sheet

  var newRow = sheet.getLastRow() + 1;      

  var rowData = [];

  for (var param in e.parameter) {

   Logger.log('In for loop, param=' + param);

   var value = stripQuotes(e.parameter[param]);

   Logger.log(param + ':' + e.parameter[param]);

   switch (param) {

    case 'Temperature': //Parameter

     rowData[0] = value; //Value in column A

     result = 'Written on column A';

     break;

    case 'Humidity': //Parameter

     rowData[1] = value; //Value in column B

     result += ' ,Written on column B';

     break; 

    default:

     result = "unsupported parameter";

   }

  }

  Logger.log(JSON.stringify(rowData));

  // Write new row below

  var newRange = sheet.getRange(newRow, 1, 1, rowData.length);

  newRange.setValues([rowData]);

 }

 // Return result of operation

 firestore();

 return ContentService.createTextOutput(result);

}

/**

* Remove leading and trailing single or double quotes

*/

function stripQuotes( value ) {

 return value.replace(/^["']|['"]$/g, "");

}


function firestore(){

//add firebase library to script before running the code

//get firebase project credentials from GCP and add data from the created json key below

  const email = "firebase-adminsdk-4978y@sensordata-5b22b.iam.gserviceaccount.com";

  const key = " ";

  var firestore = FirestoreApp.getFirestore (email, key, projectId);


// get document data from ther spreadsheet

  var ss = SpreadsheetApp.getActiveSpreadsheet();

  //Give the sheetname of your spreadsheet

  var sheetname = "IFTTT_Maker_Webhooks_Events";

  var sheet = ss.getSheetByName(sheetname);

  // get the last row and column in order to define range

  var sheetLR = sheet.getLastRow(); // get the last row

  var sheetLC = sheet.getLastColumn(); // get the last column

  var dataSR = 2; // the first row of data

  // define the data range

  var sourceRange = sheet.getRange(2,1,sheetLR-dataSR+1,sheetLC);


  // get the data

  var sourceData = sourceRange.getValues();

  // get the number of length of the object in order to establish a loop value

  var sourceLen = sourceData.length;

 

 // Loop through the rows

  for (var i= sourceLen-1;i<sourceLen;i++){

   if (sourceData[i][1] !=='') {

    var data = {};

    

   data.timestamp = sourceData[i][0];

   data.temperature=sourceData[i][1];

   data.spo2 = sourceData[i][2];

   data.heartrate=sourceData[i][3];

    firestore.createDocument("patientData",data);


   }

  

 }

}

You need to write your sheet ID in this code. You can get this link from the excel sheet. The sheet Id is present between the d/ and /edit words in the link visible in the browser.

Create a new file and name it as firebase.html and write the below mentioned code in that file.

<script src="https://www.gstatic.com/firebasejs/10.4.0/firebase-app.js"></script>

<script src="https://www.gstatic.com/firebasejs/10.4.0/firebase-firestore.js"></script>

<script src="https://www.gstatic.com/firebasejs/10.4.0/firebase-SERVICE.js"></script>

Rasberry Pi Code

Rasberry Pi GUI.jpeg

Rasberry Pi was used for creating a GUI for displaying the data to the user. Open the thony editor on Rasberry Pi OS and crete a new file and write the following code into that file :-

import tkinter as tk

from tkinter import *

from tkinter import ttk

from tkcalendar import Calendar

import firebase_admin

from firebase_admin import credentials, firestore

from datetime import datetime

import pyrebase

import os

import requests


# Initialize Firebase Admin SDK with your JSON key file

cred = credentials.Certificate(" ")

firebase_admin.initialize_app(cred)


# Create a Firestore client

db = firestore.client()


def retrieve_historical_data():

  selected_date_str = date_picker.get_date()

  selected_time = time_entry.get()

  # Parse the selected date string to a datetime object

  selected_datetime_str = f"{selected_date_str} {selected_time}"


  # Parse the combined date and time string to a datetime object

  selected_datetime = datetime.strptime(selected_datetime_str, "%m/%d/%Y %I:%M%p")


  # Format the selected date to match the Firestore timestamp format

  formatted_date = selected_datetime.strftime("%B %d, %Y at %I:%M%p")


  # Access a Firestore collection and retrieve data from documents with a specific timestamp

  collection_ref = db.collection("patientData")


  # Define a query to filter documents by the timestamp field

  query = collection_ref.where("timestamp", "==", formatted_date)


  # Retrieve matching documents

  docs = query.stream()


  data_str = ""

  for doc in docs:

    data = doc.to_dict()

    data_str += f"Data: {data}\n"


  if data_str:

    result_label.config(text=data_str)

  else:

    result_label.config(text=f"No documents found for {formatted_date}")


def SubmitData():

  config = {

    "apiKey": "AIzaSyBeA6bASR9lDbAMQxyWMS6RpIOTjp2Rzjc",

    "authDomain": "sensordata-5b22b.firebaseapp.com",

    "databaseURL": "https://sensordata-5b22b-default-rtdb.asia-southeast1.firebasedatabase.app",

    "storageBucket": "sensordata-5b22b.appspot.com"

  }


  firebase = pyrebase.initialize_app(config)

  db_realtime = firebase.database()

  data = db_realtime.child("Patient Data").get().val()


  if data:

    HeartRate = data.get("Heart")

    SPO2 = data.get("Spo2")

    Temperature = data.get("Temp")



def retrieve_realtime_data():

  def update_realtime_data():

    config = {

       

    #Add your firebase credentials here

    }

    

    firebase = pyrebase.initialize_app(config)

    db_realtime = firebase.database()


    data = db_realtime.child("Patient Data").get().val()


    if data is not None:

      ECG = data.get("ECG")

      HeartRate = data.get("Heart")

      SPO2 = data.get("Spo2")

      Temperature = data.get("Temp")


      # Update your Tkinter UI with the new data

      data_str = f"Real-time Data:\nHeart Rate: {HeartRate}\nSPO2: {SPO2}\nTemperature: {Temperature}\nECG: {ECG}"

       

       

      realtime_label.config(text=data_str, font=("Helvetica", 30), bg="black", fg="white")


    # Schedule the next update in milliseconds (e.g., every 1000ms for 1 second)

    root.after(1000, update_realtime_data)


  realtime_window = tk.Toplevel()

  realtime_window.title("Real-Time Data")

   

  window_width = 800

  window_height = 400

  screen_width = realtime_window.winfo_screenwidth()

  screen_height = realtime_window.winfo_screenheight()

   

  x = (screen_width - window_width) // 2

  y = (screen_height - window_height) // 2

   

  realtime_window.geometry(f"{window_width}x{window_height}+{x}+{y}")

   


  realtime_label = tk.Label(realtime_window, text="", font=("Helvetica", 30), bg="black", fg="white")

  #realtime_label.pack()

  realtime_label.grid(row=0, column=0, sticky="nsew")

  # Use grid layout and sticky to fill the window

  submit_button = tk.Button(realtime_window, text="Submit Data", command=SubmitData, font=("Helvetica", 16))

  submit_button.grid(row=1, column=0, padx=20, pady=10)

  # Configure the grid to expand and fill the available space

  realtime_window.grid_rowconfigure(0, weight=1)

  realtime_window.grid_columnconfigure(0, weight=1)

  update_realtime_data()


root = tk.Tk()

root.title("Firestore Data Retrieval")


#root.attributes('-fullscreen', True)

# Create a date picker widget


style = ttk.Style()

style.configure("TButton", background="black", foreground="white")

style.configure("TLabel", background="black", foreground="white")

style.layout("TButton", [("Button.focus", {"children": [("Button.padding", {"children": [("Button.label", {"side": "left", "expand": 1})]})]})])


# Configure the Calendar widget

date_picker = Calendar(root, date_pattern="mm/dd/yyyy", background="black", foreground="white", headersbackground="black", headersforeground="white", bordercolor="black", normalbackground="black", normalforeground="white", othermonthbackground="black", othermonthforeground="grey")

date_picker.pack(fill='both', expand=True)

date_picker.config(font=('Helvetica', 20))

# Create a time entry field

time_label = tk.Label(root, text="Select a Time (e.g., 12:00AM):", font=('Helvetica', 16))

time_label.pack()

time_entry = tk.Entry(root, font=('Helvetica', 16))

time_entry.pack()

 

# Create buttons for switching between historical and real-time data

historical_button = tk.Button(root, text="Historical Data", command=retrieve_historical_data, font=('Helvetica', 16))

historical_button.pack()


realtime_button = tk.Button(root, text="Real-Time Data", command=retrieve_realtime_data , font=('Helvetica', 16))

realtime_button.pack()

# Create buttons to show login and signup windows


result_label = tk.Label(root, text="", font=('Helvetica', 16))

result_label.pack()


root.mainloop()

Using this code a GUI display would be created in which the user will have the option to view his real-time as well as his historical data. The historical data will be fetched from the Firestore database and the real-time data will be fetched from the Firebase real time database.

Note :-

In the config section you need to add the firebase credentials. You can get these credentials by clicking on the project settings option present under the project overview section.

Final Designing

WhatsApp Image 2023-10-19 at 09.02.06.jpeg

To make the project easy to use we need to consider the comfortability factor of the user. A wearable can be made and all the sensors can be integrated into the wearable. For this project, I made use of an elbow band. You will get the link for the elbow band in the supplies step. I fixed the PCB inside the elbow band. Integrating the MLX90614 and MAX30100 sensors into the finger bands makes temperature and pulse oximeter measurements easier and more accurate for the user. The ECG sensor can be fixed at the bottom of the band so that the probes can easily be connected to it.

And the project is ready..