PULSE OXIMETER AND HEART RATE SENSOR WITH UBIDOTS, PART 1
HARDWARE
In the image below I show you the electrical diagram that we will use in this chapter.
LIST OF PARTS:
HOW DOES IT WORK?
First, the WiFi connection is established between the Arduino NANO 33 IoT board and the Modem;
This sensor detects the percentage pulse oximeter (O2), and the heart rate (HR) of the finger;
Both values will print on the serial port and the Micro OLED Breakout screen for 10 seconds approx ;
Every 10 seconds the O2 and HR values will sent to the IoT server.
We will use the service provider IoT Ubidots, and the configuration will be seen in the next chapter.
SOFTWARE
PREREQUISITES FOR ARDUINO IDE:
Download and install the Micro OLED Breakout display library here.
Download and install the SparkFun Pulse Oximeter and Heart Rate Sensor library here
Once the libraries were installed, I used the Arduino IDE 1.8.11 to compile and upload the code to the Arduino NANO 33 IoT board. The code and comments are shown below: "ubidots_pulse_oximeter.ino"
// AUTHOR: GUILLERMO PEREZ GUILLEN
/********************************
* Libraries included
*******************************/
#include <SPI.h>
#include <WiFiNINA.h>
#include <avr/dtostrf.h>
#include <SparkFun_Bio_Sensor_Hub_Library.h>
#include <Wire.h>
#include <SFE_MicroOLED.h> // display instruction
#define PIN_RESET 9 // display instruction
#define DC_JUMPER 1 // display instruction
MicroOLED oled(PIN_RESET, DC_JUMPER); // display, I2C declaration
int resPin = 4;
int mfioPin = 5;
int algoRange = 80; // ADC Range (0-100%)
int algoStepSize = 20; // Step Size (0-100%)
int algoSens = 20; // Sensitivity (0-100%)
int algoSamp = 10; // Number of samples to average (0-255)
// Takes address, reset pin, and MFIO pin.
SparkFun_Bio_Sensor_Hub bioHub(resPin, mfioPin);
bioData body;
/********************************
* Constants and objects
*******************************/
#define DEVICE_LABEL "pulse-oximeter-arduino-nano-33"
#define TOKEN "BBFF-******************************"
char const * VARIABLE_LABEL_1 = "pulse";
char const * VARIABLE_LABEL_2 = "oximeter";
char const *SERVER="industrial.api.ubidots.com";
//Replace the above line if you are an Educational user char const *SERVER="things.ubidots.com";
const int HTTPPORT= 443;
char const *AGENT="Arduino Nano 33 IoT";
char const *HTTP_VERSION = " HTTP/1.1\r\n";
char const *VERSION ="1.0";
char const *PATH= "/api/v1.6/devices/";
char const * SSID_NAME = "*********"; // Put here your SSID name
char const * SSID_PASS = "************"; // Put here your password
int status = WL_IDLE_STATUS;
WiFiSSLClient client;
/********************************
* Auxiliar Functions
*******************************/
void printWiFiStatus() {
// print the SSID of the network you're attached to:
Serial.print("SSID: ");
Serial.println(WiFi.SSID());
// print your board's IP address:
IPAddress ip = WiFi.localIP();
Serial.print("IP Address: ");
Serial.println(ip);
// print the received signal strength:
long rssi = WiFi.RSSI();
Serial.print("signal strength (RSSI):");
Serial.print(rssi);
Serial.println(" dBm");
}
void getResponseServer() {
Serial.println(F("\nUbidots' Server response:\n"));
while (client.available()) {
char c = client.read();
Serial.print(c); // Uncomment this line to visualize the response on the Serial Monitor
}
}
void waitServer() {
int timeout = 0;
while (!client.available() && timeout < 5000) {
timeout++;
delay(1);
if (timeout >= 5000) {
Serial.println(F("Error, max timeout reached"));
break;
}
}
}
void sendData(char* payload) {
int contentLength = strlen(payload);
/* Connecting the client */
if (client.connect(SERVER, HTTPPORT)) {
Serial.println("connected to server");
client.print(F("POST "));
client.print(PATH);
client.print(DEVICE_LABEL);
client.print(F("/"));
client.print(HTTP_VERSION);
client.print(F("Host: "));
client.print(SERVER);
client.print(F("\r\n"));
client.print(F("User-Agent: "));
client.print(AGENT);
client.print(F("\r\n"));
client.print(F("X-Auth-Token: "));
client.print(TOKEN);
client.print(F("\r\n"));
client.print(F("Connection: close\r\n"));
client.print(F("Content-Type: application/json\r\n"));
client.print(F("Content-Length: "));
client.print(contentLength);
client.print(F("\r\n\r\n"));
client.print(payload);
client.print(F("\r\n"));
Serial.print(F("POST "));
Serial.print(PATH);
Serial.print(DEVICE_LABEL);
Serial.print(F("/"));
Serial.print(HTTP_VERSION);
Serial.print(F("Host: "));
Serial.print(SERVER);
Serial.print(F("\r\n"));
Serial.print(F("User-Agent: "));
Serial.print(AGENT);
Serial.print(F("\r\n"));
Serial.print(F("X-Auth-Token: "));
Serial.print(TOKEN);
Serial.print(F("\r\n"));
Serial.print(F("Connection: close\r\n"));
Serial.print(F("Content-Type: application/json\r\n"));
Serial.print(F("Content-Length: "));
Serial.print(contentLength);
Serial.print(F("\r\n\r\n"));
Serial.print(payload);
Serial.print(F("\r\n"));
waitServer();
getResponseServer();
}
/* Disconnecting the client */
client.stop();
}
/********************************
* Main Functions
*******************************/
void setup() {
//Initialize serial and wait for port to open:
Serial.begin(115200);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
// check for the WiFi module:
if (WiFi.status() == WL_NO_MODULE) {
Serial.println("Communication with WiFi module failed!");
// don't continue
while (true);
}
// attempt to connect to WiFi network:
while (status != WL_CONNECTED) {
Serial.print("Attempting to connect to SSID: ");
Serial.println(SSID_NAME);
// Connect to WPA/WPA2 network. Change this line if using open or WEP network:
status = WiFi.begin(SSID_NAME, SSID_PASS);
// wait 10 seconds for connection:
delay(10000);
}
Serial.println("Connected to wifi");
printWiFiStatus();
Wire.begin();
oled.begin(); // Initialize the OLED
oled.clear(ALL); // Clear the display's internal memory
oled.display(); // Display what's in the buffer (splashscreen)
int result = bioHub.begin();
if (result == 0) // Zero errors!
Serial.println("Sensor started!");
// Adjusting the Automatic Gain Control (AGC) Algorithm
int error = bioHub.setAlgoRange(algoRange);
if (error > 0){
Serial.println("Could not set algorithm's Range.");
}
error = bioHub.setAlgoStepSize(algoStepSize);
if (error > 0){
Serial.println("Could not set the step size.");
}
error = bioHub.setAlgoSensitivity(algoSens);
if (error > 0){
Serial.println("Could not set the sensitivity.");
}
error = bioHub.setAlgoSamples(algoSamp);
if (error > 0){
Serial.println("Could not set the sample size.");
}
// Let's read back what we set....
int algoVal = bioHub.readAlgoRange();
Serial.print("Algorithm set to: ");
Serial.println(algoVal);
int stepVal = bioHub.readAlgoStepSize();
Serial.print("Algorithm set to: ");
Serial.println(stepVal);
int senVal = bioHub.readAlgoSensitivity();
Serial.print("Algorithm set to: ");
Serial.println(senVal);
int sampVal = bioHub.readAlgoSamples();
Serial.print("Algorithm set to: ");
Serial.println(sampVal);
Serial.println("Configuring Sensor.");
error = bioHub.configBpm(MODE_ONE);
if (error > 0){
Serial.println("Could not configure the sensor.");
}
Serial.println("Loading up the buffer with data....");
delay(100);
oled.clear(PAGE); // display, Clear the buffer.
}
void loop(){
char payload[200];
char str_val_1[30];
char payload2[200];
char str_val_2[30];
for (int i = 1; i < 34; i++) {
body = bioHub.readBpm();
Serial.print("Heartrate: ");
Serial.println(body.heartRate);
Serial.print("Oxygen: ");
Serial.println(body.oxygen);
oled.clear(PAGE); // Clear the display
oled.setCursor(0, 0); // Set cursor to top-left
oled.setFontType(1); // Smallest font
oled.print("HR: "); // Print "A0"
oled.setFontType(2); // 7-segment font
oled.print(body.heartRate); // Print heart rate
oled.setCursor(0, 20); // Set cursor to top-middle-left
oled.setFontType(1); // Repeat
oled.print("O2: ");
oled.setFontType(2);
oled.print(body.oxygen); // Print body oxygen
oled.display();
delay(250);
}
/*4 is the total lenght of number,maximun number accepted is 99.99*/
dtostrf(body.heartRate, 4, 2, str_val_1);
sprintf(payload, "%s","");
sprintf(payload, "{\"");
sprintf(payload, "%s%s\":%s", payload, VARIABLE_LABEL_1, str_val_1);
sprintf(payload, "%s}", payload);
//Send the payload to Ubidots
sendData(payload);
delay(500);
dtostrf(body.oxygen, 4, 2, str_val_2);
sprintf(payload2, "%s","");
sprintf(payload2, "{\"");
sprintf(payload2, "%s%s\":%s", payload2, VARIABLE_LABEL_2, str_val_2);
sprintf(payload2, "%s}", payload2);
sendData(payload2);
delay(500);
}
INSTRUCTIONS:
1) You can download the code here: ubidots_pulse_oximeter.rar
2) Please type the name of your SSID and password in the code lines shown below:
char const * SSID_NAME = "*********"; // Put here your SSID name
char const * SSID_PASS = "************"; // Put here your password
3) In the next post (Blog #6) I will show you how to get the DEVICE_LABEL, TOKEN, VARIABLE_LABEL_1, and VARIABLE_LABEL_2 of your Dashboard created. Once done, please type the information in the code lines shown below:
#define DEVICE_LABEL "pulse-oximeter-arduino-nano-33"
#define TOKEN "BBFF-******************************"
char const * VARIABLE_LABEL_1 = "pulse";
char const * VARIABLE_LABEL_2 = "oximeter";
4) Finally verify and upload the code to the Arduino NANO 33 IoT board
3D PRINTING AND ASSEMBLING THE DEVICE
In the image below we show the box designed for this device (it's the same piece used in Blog #3).
Also, the image below shows the cover.
If you want to make a 3D impression of these designs, you can download the STL files here: health_monitoring_box.rar
The image below shows the assembled project.