Andrewf1
Published © GPL3+

Cardiograph

Here I show you how an ESP32 can take ECG and send this data to cloud. And how to set up web app to look at this data.

IntermediateFull instructions provided4 hours4,917
Cardiograph

Story

Read more

Schematics

Hardware diagram for ESP32 dev module

Code

script.js

JavaScript
// REPLACE <...> BY YOUR FIREBASE PROJECT CONFIGURATION:
const config = {
    apiKey: "",
    authDomain: "",
    databaseURL: "",
    projectId: "",
    storageBucket: "",
    messagingSenderId: ""
};

firebase.initializeApp(config);

function last_pack() {
    firebase.database().ref('measures').limitToLast(1).on('value', ts_measures => {
        console.log("last_pack");
        let timestamps = [];
        let values = [];
        let pack_time;
        ts_measures.forEach(ts_measure => {
            let list = ts_measure.val().data;
            pack_time=new Date(ts_measure.val().timestamp);
            document.getElementById("start-time").value=pack_time.toLocaleString();
            time = 0;
            for (i in list) {
                timestamps.push(time);
                time = time + 0.01;
                values.push(list[i]);
            }
        });

        myPlotDiv = document.getElementById('myPlot');

        const data = [{
            x: timestamps,
            y: values
        }];

        const layout = {
            title: '<b>Cardiogram('+pack_time.toLocaleString()+')</b>',
            titlefont: {
                family: 'Courier New, monospace',
                size: 16,
                color: '#000'
            },
            xaxis: {
                linecolor: 'black',
                linewidth: 2
            },
            yaxis: {
                title: '<b>8-bit value</b>',
                titlefont: {
                    family: 'Courier New, monospace',
                    size: 14,
                    color: '#000'
                },
                linecolor: 'black',
                linewidth: 2,
            },
            margin: {
                r: 50,
                pad: 0
            }
        }

        Plotly.newPlot(myPlotDiv, data, layout, { responsive: true });
    });
}

function update_plot() {
    finish = new Date(document.getElementById("start-time").value).getTime();
    start = finish - 12 * 60 * 60 * 1000;
    console.log(start + "--" + finish)
    firebase.database().ref('measures').orderByChild("timestamp").startAt(start).endAt(finish).limitToLast(1).on('value', ts_measures => {

        let timestamps = [];
        let values = [];
        let pack_time;
        let dataFound=false;
        ts_measures.forEach(ts_measure => {
            dataFound=true;
            var list = ts_measure.val().data;
            pack_time=new Date(ts_measure.val().timestamp);
            time = 0;                                
            for (i in list) {
                timestamps.push(time);
                time = time + 0.01;
                values.push(list[i]);
            }
        });
        if(dataFound){
        myPlotDiv = document.getElementById('myPlot');

        const data = [{
            x: timestamps,
            y: values
        }];

        const layout = {
            title: '<b>Cardiogram('+pack_time.toLocaleString()+')</b>',
            titlefont: {
                family: 'Courier New, monospace',
                size: 16,
                color: '#000'
            },
            xaxis: {
                linecolor: 'black',
                linewidth: 2
            },
            yaxis: {
                title: '<b>8-bit value</b>',
                titlefont: {
                    family: 'Courier New, monospace',
                    size: 14,
                    color: '#000'
                },
                linecolor: 'black',
                linewidth: 2,
            },
            margin: {
                r: 50,
                pad: 0
            }
        }

        Plotly.newPlot(myPlotDiv, data, layout, { responsive: true });
    }else{
        last_pack();
    }
    });

}

favicon.ico

HTML
It's simply icon.
HTML language is just for placeholder.
No preview (download only).

cardio_sender

Arduino
This code collecting measures and sends them to the cloud.
// Update - 17 Aug 2021
// Functions addInt() and addArray() were replaced with add() function to match newer version of FirebaseESP32 library

#include <WiFi.h>
#include "FirebaseESP32.h"


#define FIREBASE_HOST "" // do not include https:// in FIREBASE_HOST
#define FIREBASE_AUTH "" // database credentials
#define WIFI_SSID ""     // WIFI AP name
#define WIFI_PASSWORD "" // WIFI password


//Define Firebase Data object
FirebaseData firebaseData;

String path = "/measures";
String jsonStr;

FirebaseJson json;
FirebaseJsonArray jsonArr;

uint8_t previous_measure = 0;
uint8_t measure = 0;
void setup() {

  Serial.begin(115200);
  Serial.println();
  Serial.println();

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

  Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH);
  Firebase.reconnectWiFi(true);

  //Set database read timeout to 1 minute (max 15 minutes)
  Firebase.setReadTimeout(firebaseData, 1000 * 60);
  //tiny, small, medium, large and unlimited.
  //Size and its write timeout e.g. tiny (1s), small (10s), medium (30s) and large (60s).
  Firebase.setwriteSizeLimit(firebaseData, "tiny");

}

void loop() {  
  Serial.println("Collecting measures");
  jsonArr.clear();
  
  previous_measure = analogRead(36) >> 4;  
  for (int i = 0; i < 500; i++) {
    measure = analogRead(36) >> 4;
    measure = previous_measure/2 + (measure-30)/2;

    jsonArr.add(measure);
    delay(10);
  }
  
  Serial.println("Forming pack of data");
  json.clear();
  json.add("data", jsonArr);
  json.add("timestamp", 0);
  
  if (Firebase.pushJSON(firebaseData, "/measures/", json))  {
    Serial.println("PASSED");
    Serial.println("PATH: " + firebaseData.dataPath());
    Serial.print("PUSH NAME: ");
    Serial.println(firebaseData.pushName());
    Serial.println("ETag: " + firebaseData.ETag());
    Serial.println("------------------------------------");
    Serial.println();
  }
  else  {
    Serial.println("FAILED");
    Serial.println("REASON: " + firebaseData.errorReason());
    Serial.println("------------------------------------");
    Serial.println();
  }
  delay(10*60*1000);
}

cardio_test

Arduino
This code used to test does Heart rate module works.
void setup() {
  // initialize the serial communication:
  Serial.begin(115200);
}

void loop() {
  Serial.println(analogRead(A0));

  delay(1);
}

index.html

HTML
<!DOCTYPE html>
<html lang="fr">

<head>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<title>Cardiogram</title>
	<link rel="stylesheet" href="style.css">

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

	<!-- Include Plotly.js -->
	<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
	<script src="script.js"></script>
</head>

<body onload="last_pack()">
	<!-- Plotly chart will be drawn inside this div. -->
	<div id="myPlot" style="width: 100vw; max-height:75vh"></div>
	<p>Give time in which you want to see data</p>
	<span>Date-time<input id="start-time" type="datetime-local"/></span>	
	<button onclick="update_plot()">Get data</button> 
	
	
</body>

</html>

style.css

CSS
body
{
    font-family: Roboto, Helvetica, Arial, sans-serif; 
    margin: 0   
}

Credits

Andrewf1
7 projects • 17 followers
Contact

Comments

Please log in or sign up to comment.