Software apps and online services
Hand tools and fabrication machines
Healthcare is rapidly developing every day. With an increased number of patients needing care around the world, hospitals have to be on top of their game and people aware of their health. But one should not be needing to visiting a doctor to get an SpO2 test as this would crowd hospitals.
The problem is that with technology advancing, healthcare must keep up the pace and enter the age of IoT. Hospitals have taken great leaps to digitalise their records and recipes but what happens when the patient leaves the hospital with a disease such as COPD? How does the doctor know if the patient is recovering without the need of constant visits?
As people become more conscious of their health, they will want to monitor their vitals easily without the need of an overpriced oximeter that uncomfortably squeezes their arm. There must be a quicker and more convenient way of achieving this reading!
Introducing MyPulse, a smart IoT device that can sample the user’s heart rate and SpO2 (blood oxygen) levels in 30 seconds. MyPulse is a device that can be placed anywhere in a house or a hospital. All the user has to do to get their pulse is place their finger on the sensor.
This means that hospitals would not need to assign nurses to take the patient’s pulse before a check-up as the patient will be able to record it in seconds by simply placing their finger on the sensor.
The doctor will not need to create appointments to ensure that his COPD patient is feeling better as the patient can record his/her own vitals and the doctor can access this data in seconds from any device, at any time.
Finally, one does not need to strap on a band that squeezes their wrist and stand still for two minutes to get their heart rate after an exercise, but only place their finger on the sensor for 30 seconds. They can then visualise their progress over time from their phone or even their smart watch on an interactive dashboard.
Today, data is the most valuable resource, but the catch is that:
If data cannot be shared nor distributed, it has no value.
MyPulse aims to bring technology to both the user at home and the hospital by creating a simple device that can easily be interfaced by anyone. The application includes an online dashboard that can be visualised from any device by the user and/or doctor.
Therefore, the doctor can see their recovering patient’s vitals without needing to leave the office. But heart rate and blood oxygen levels are not all that matter!
A typical device will only record the user’s vitals, but I think that a truly comprehensive application needs to measure atmospheric variables such as temperature and barometric pressure.
Recent studies correlate temperature and barometric pressure with the chance of stroke. A study by NCBI relates that the chances of acute stroke increase by 2.4% per a 1°C change in temperature. Another study by NCBI relates that the majority of people rushed to the doctor with a stroke have been exposed to fluctuations in barometric pressure. Therefore the doctor will want to monitor the temperature of the patient’s home remotely and inform them if the temperature exposes them to a risk.
The table below illustrates the data collected by the device.
Normal Values for Vitals
Although the heart rate depends heavily on the individual’s age, generally, a resting heart rate of 60bpm – 100bpm is normal. Anything below or above this indicates a possible disease like diabetes or atrial fibrillation.
The SpO2 levels are not age reliant and the health limit is 95% oxygen for most people. Anything below can indicate that there is not enough oxygen pumped around the body meaning that there may be a problem with anything from the lungs to the production of red blood cells in the individual. Diseases include emphysema, bronchitis and pneumonia.
Collecting the Data
These values are collected from the individual in 30 seconds. The device can be left plugged in all the time or can be plugged in when used. The user has to follow the routine below to take his/her pulse and SpO2 readings.
1. Press the button attached to the device
2. Place the finger on the sensor head of the device
3. Hold the finger down while the LED is blinking
4. Remove the finger when the buzzer is heard
5. Wait for the LED to go white
The data is then collected, compiled and sent to the cloud.
The benefits of using MyPulse for an individual and a hospital are listed below.
1. Rapidly get the heart rate and SpO2 levels by only placing a finger on the device.
2. The device reports the data to a server which stores all the data allowing the user to access it.
3. The data is visualised on a dashboard that the user can access from anywhere at any time.
4. The dashboard allows the user to visualise vitals over a period of time.
5. Get a visual warning from the device if the SpO2 or heart rate is abnormal.
1. A device can be placed in the waiting room at the hospital allowing the patients to get their heart rate and SpO2 levels before going into the check-up making the process faster.
2. A device can be given to the patients to bring home and monitor their vitals. The device can alert the patients if they need to see a doctor.
3. The doctor will be able to remotely monitor the vitals of his/her patients without the need of a check-up lowering the doctor’s workload.
4. The data is illustrated on a dashboard allowing the doctor and/or the patient to visualise the vitals.
5. The data is stored in a scalable server allowing an array of devices to be used and distributed.
I think that it is very important to be able to access the data from anywhere, at any time. The solution is to have an online dashboard that illustrates this data live that can be accessed on any device; phone or laptop.
The solution is a Power Bi dashboard. Power Bi allows dashboards to be hosted on an online environment that can only be accessed by accredited people. Dashboards are easily shareable with specific people allowing an easy patient to doctor exchange. Data is streamed directly into the dashboard which is always up to date.
I also chose Power Bi because of its powerful graphs and presentations making it easy and beautiful to navigate through the data. The parts of the dashboard are labelled below.
This is a special case as a patient that has atrial fibrillation got infected with COPD.
Atrial Fibrillation is a disease caused by high blood pressure or heart attack, this is a disease that causes an irregular rhythm in the pulse. Patients with this disease are exposed to a higher risk of heart attack.
The patient is now also infected with a mild form of COPD which is not severe but can put the patient’s life at risk increasing the chances of stroke. The patient’s heart rate and SpO2 levels must be monitored.
An obese individual is required to maintain a strict diet as their SpO2 levels are low. The diet includes an alimentary diet and exercise. The individual is required to sample their SpO2 levels and heart rate before and after each exercise to see his improvement.
The trainer needs the data to be available immediately after each workout but also has a lot of people on this program and so needs the data to be organised so that the data does not end up representing the wrong person. The trainer also needs a solution on premises at the training facility to allow the vitals to be easily monitored.
The two case studies show the versatility of the device and the fact that it is not isolated to a hospital but can be used in other circumstances.
The project consists of a frontend and a backend.
Frontend refers to the device that is positioned on the scene. This device samples the vitals and atmospheric variables and sends this data to the cloud when it is received.
Backend Processes and displays the data on a dashboard. The data starts off in an IoT hub and is then pushed into a Power Bi report.
In the case of MyPulse, the trigger is event based, this means that the device will send data to the cloud when the button is pressed and a sample is taken.
The diagram above describes the processes taken by the device.
1. The device is turned on when the button is pressed.
2. The device then samples the vitals from the sensor.
3. The device will then check if the sample is successful.
4. If the sample is successful, the device will take the temperature and barometric pressure samples and send the data to the backend.
5. The data is then received by Azure IoT Hub and queried by the stream analytics job.
6. The data is finally outputted to Power Bi and displayed on a dashboard.
The frontend of the project refers to the device that collects the data about the vitals and atmospheric conditions from the user and sends it to the backend.
Device Overview – Azure Sphere
I chose to build this project using the Azure Sphere development board as it offers industrial grade security that ensures that the system cannot be tampered with. IoT security is essential in healthcare as intentional or deliberate damaging of the device can potentially cost lives.
Three modules are being interfaced with the device in this project. Two of these modules are built onto the device. The other module is interfaced through the MikroE sockets.
LPS22HH Built-in module that measures barometric pressure. This module is used to collect the barometric pressure after the vitals have been recorded.
LSM6DSO The second built-in module that reports the temperature to the device. This module is also interfaced after vitals have been collected.
MikroE Heart Click 4 This is the external sensor that is connected to Mikro Electronika click socket 1 on the device. The device probes the SpO2 and heart rate of the user.
Vitals are sampled by the MikroE heart click. When the user presses the button, the module is turned on and prepared. The sensor then attempts to read the vitals of the individual. The sensor will check if a finger is placed on it and will then attempt to get the pulse and SpO2 levels.
The sample takes 30 seconds because a 15 second sample would be too short for the device to detect the finger and achieve multiple readings. A one minute sample would be too long so a 30 second one is perfect.
The device is equipped with an RGB LED and a buzzer to provide the user with feedback. The buzzer will buzz to alert the user’s attention to the RGB LED throughout the program. Below are the LED colours and their meanings:
A purple blinking LED indicates that there is a problem with the firmware of the device that is preventing the program to execute successfully. The device should be reset in this case.
A blue blinking LED informs the user that the device is currently sampling vitals using the MikroE module. The user should have their finger on the device’s module.
A red blinking LED accompanied by buzzes warns the user that their SpO2 and/or heart rate readings are bad and that they should try sampling again and then seek medical assistance on the same outcome.
A green LED indicates that the device sampled the user’s vitals and all the vitals are nominal. This informs the user that they do not need to seek medical assistance.
A light blue LED indicates that the device is online and is awaiting the user to start taking a sample. The user should press the button attached to the device to take a sample.
The backend refers to all the computing that happens in the cloud and the dashboard that displays the data collected by the device.
I have used Azure cloud by Microsoft because of two reasons.
1. The Azure Sphere device is designed to be connected to Azure IoT. I have decided to make use of this connection as it is secure and reliable.
2. Azure is my cloud of choice due to the beautiful interface and integration with Office 365 and Windows.
Backend Program Overview
The infographic below illustrates the steps taken by the backend to process the data.
Below are a list of features that would be added in a further developed version of the project.
- The frontend device can be equipped with an OLED display that will inform the user about their heart rate and SpO2 levels as well as the temperature and barometric pressure when the sample is successful.
- The device could have a background function that reads the temperature and barometric pressure while the device is in stand-by and prints them on the OLED display.
- The data could be streamed into Cosmos DB for safekeeping.
- The backend could analyse trends in the vitals of the user and predict when they will be needing an appointment.
I wanted to confirm that my device has registered with the server for more than 30 days. I took screenshots of the server’s Power Bi app and attached them below.
Enough talk, let's start making the project.
Step1: Required Materials
Below is the list of all materials needed for this project:
Step 2: Prerequisites
Before we start building the project. You will need to ensure that you have access to a Windows 10 PC with Visual Studio 2017 or 2019 installed. You will also require the Azure Sphere SDK installed on your PC.
Note that I am working on version 19 and not the most recent version. Although there should be no problem loading project files using the new SDK, some bugs can occur.
You will then need to follow this well laid out guide provided by Microsoft to get started with your development board and set it up. When your device is in debug mode and connected to Wi-Fi, you can continue with the guide.
Step 3: Connecting the Circuit
The next thing to do is wire the circuit. I used a breadboard for prototyping but the final device should be soldered together. The Fritzing Schematics are attached below. Ensure to connect the MikroE heart click to MikroE socket 1.
Step 4: Acknowledging the Code
The project's code is composed of 4 main sections:
- Get Button
- Get Heart Rate
- Analyse Data
- Send Data to Azure
int getButton() // this loop checks if the button is pressed
int result = GPIO_GetValue(buttonAOpen, &newButtonAState); // read the GPIO value
if (result < 0) // if read was not allowed
Log_Debug(" [ERROR] Access to Pin Denied \n");
This function samples the button and checks if it is pressed.
Get Heart Rate
// wait until button is pressed and then sample Hr
println("[Program] Preapring Sample");
float n_spo2 = 0;
float ratio = 0;
float correl = 0;
int8_t ch_spo2_valid = 0; //indicator to show if the SPO2 calculation is valid
int32_t n_heart_rate = 0; //heart rate value
int8_t ch_hr_valid = 0; //indicator to show if the heart rate calculation is valid
uint32_t aun_ir_buffer[BUFFER_SIZE]; //infrared LED sensor data
uint32_t aun_red_buffer[BUFFER_SIZE]; //red LED sensor data
int32_t i = 0;
int32_t average_hr = 0;
float average_spo2 = 0;
int32_t nbr_readings = 0;
struct timeval time_start;
struct timeval time_now;
bool turn = false;
memset(aun_ir_buffer, 0, 128);
memset(aun_red_buffer, 0, 128);
println("[Program] Press Button to get heart rate");
while (!getButton()) // wait until the button is pressed.
dowork(); // buffer events in the meanwhile
buzz(1000); // buzzer
println("[Program] Initialising MikroE Device");
maxim_max30102_init(); // initialise the sensor and send the on command
Log_Debug("[Program] Running test for %d seconds\n", run_time);
println("[Program] Place Finger on Sensor - Starting in 5 seconds");
println("[Program] Reading Heart Rate");
// get the start time of the sampling
time_now = time_start;
average_hr = nbr_readings = 0;
average_spo2 = 0.0;
while (difftime(time_now.tv_sec, time_start.tv_sec) < run_time) // run for defined time
// blink the blue LED
turn = false;
turn = true;
for (i = 0; i < BUFFER_SIZE; i++)
} while (intVal == 1); //wait until the interrupt pin asserts
maxim_max30102_read_fifo((aun_red_buffer + i), (aun_ir_buffer + i)); //read from MAX30102 FIFO
//calculate heart rate and SpO2 after BUFFER_SIZE samples (ST seconds of samples) using Robert's method
rf_heart_rate_and_oxygen_saturation(aun_ir_buffer, BUFFER_SIZE, aun_red_buffer, &n_spo2, &ch_spo2_valid, &n_heart_rate, &ch_hr_valid, &ratio, &correl);
if (ch_hr_valid && ch_spo2_valid) // if sample is valid
println("[Program] Success - Sample is Good");
Log_Debug("Blood Oxygen Level %.2f%% \n", n_spo2);
Log_Debug("Heart Rate %d BPM \n", n_heart_rate);
average_hr += n_heart_rate;
average_spo2 += n_spo2;
println("[Program] Sample is Bad");
gettimeofday(&time_now, NULL); // refresh the time
println("[Program] Samples Collated");
// process the sample
avgOxygen = average_spo2 / (float)nbr_readings;
avgRate = average_hr / nbr_readings;
// playing around with the values for testing
//avgOxygen = 66;
//avgRate = 40;
Log_Debug("Blood Oxygen Level %.2f%% \n", avgOxygen);
Log_Debug("Heart Rate %d BPM \n", avgRate);
// ensure that the data is not corrupted again
println("[Program] Veryfying Data");
if (avgOxygen != 0 && avgRate != 0)
println("[Program] Sample is Good");
println("[Program] Moving On");
println("[Program] Error - All Samples are Corrupted");
println("[Program] Not sending data to Azure");
for (int i = 0; i < 2; i++)
This is the heart of the code, the device will wait until the button is pressed and then take a 30 second sample of the heart rate and SpO2 levels. The device will then compile the values and check if they are valid moving on to the next function.
// analyse the data to check if vitals are OK
println("[Program] Checking Vitals against WHO healthy standards");
println("[Program] Checking Heart Rate");
int problem = 0;
if (avgRate < minRate || avgRate > maxRate) // compare heart rate with WHO standards
println("[Warning] Heart Rate is not normal [60bpm - 100bmp]");
problem = 1;
println("[Info] Heart Rate is normal");
println("[Program] Checking Oxygen");
if (avgOxygen < minOxygen) // compare SpO2 with WHO standards
println("[Warning] SpO2 is not normal [95 - 100]");
if (problem == 1)
problem = 2;
problem = 3;
println("[Info] SpO2 is normal");
// check if there was a problem
if (problem == 0)
for (int i = 0; i < 5; i++)
This function analyses the vitals to see if the values are OK or out of health limits. The device will then alert the user respectively.
Send Data to Azure IoT
// parse the data to Azure
println("[Program] Formatting Data to Send to Azure");
char *pjsonBuffer = (char *)malloc(JSON_BUFFER_SIZE); // format a buffer
if (pjsonBuffer == NULL)
Log_Debug("ERROR: not enough memory to send telemetry");
for (int i = 0; i < 2; i++)
// append data to the buffer
// snprintf(bufferToSend, 128, JSON Payload Config (defined above), dataLable, dataValue);
snprintf(pjsonBuffer, JSON_BUFFER_SIZE, jsonFormat, "Oxygen", avgOxygen, "HeartRate", avgRate, "Temperature", temp, "Pressure", atmoPressure);
Log_Debug("[Info] Sending telemetry %s\n", pjsonBuffer);
AzureIoT_SendMessage(pjsonBuffer); // send the message
free(pjsonBuffer); // clear the JSON buffer
Finally, this function will append all the data collected together in a buffer and send it to Azure IoT.
Step 5: Setting up Azure IoT
Let's start working on the backend! Follow the steps below to set up an Azure IoT Hub.
Step 6: Changing Variables
It is very important to add your IoT hub connection to the application to allow the device to communicate with the backend. The steps below show you how to do this. The steps below illustrate this process.
Step 7: Setting up Streaming Job
The next step is to set up the streaming job that extracts the data from the IoT Hub and inputs it into the Power Bi dataset.
Oxygen as oxygen,
HeartRate as heartrate,
Temperature as temperature,
Pressure as pressure,
System.timestamp as timestamp
Step 8: Flashing the Code
We now have to flash the application to the device to send some data to the backend. For this test, the user will need to take a couple of samples using the device with the debug monitor on and see if the device is successfully sending data to the cloud and the data is found in the stream analytics job.
Step 9: Setting Up Power Bi
The final thing that we have to do is set up Power Bi. The steps below will guide you through this. If all the previous steps went well, a dataset called MyPulse should be in the datasets section of Power Bi.
If you need any help, you can always visit the Power Bi community, there is always someone there to help you.
Step 10: Enclosure
Finally, the project has to be enclosed. I reused the same enclosure for two projects to be ecological. I have attached the final image of the enclosure below.