/*
THIS PROJECT LOOKS FORWARD TO CAPTURE VITALS OF PATIENT AND UPLOAD TO UBIDOTS PLATFORM.
THE FOLLOWING VITALS ARE FIRST CAPTURED BEFORE LOGGED TO THE CLOUD;
TEMPERATURE
HEARTRATE
SP02
*/
/********************************
* Libraries included
*******************************/
#include <SPI.h>
#include <WiFiNINA.h>
#include <avr/dtostrf.h>
#include <Wire.h>
#include "MAX30105.h"
#include "spo2_algorithm.h"
#include "heartRate.h"
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define MAX_BRIGHTNESS 255
/********************************
* Constants and objects
*******************************/
Adafruit_SSD1306 display(OLED_RESET); //Declaring the display name (display)
MAX30105 particleSensor; //Declaring the Pulse sensor ( particleSensor)
uint32_t irBuffer[100]; //infrared LED sensor data
uint32_t redBuffer[100]; //red LED sensor data
int32_t bufferLength; //data length
int32_t spo2; //SPO2 value
int8_t validSPO2; //indicator to show if the SPO2 calculation is valid
int32_t heartRate; //heart rate value
int8_t validHeartRate; //indicator to show if the heart rate calculation is valid
float temperature;
//COMMENT BOTH LINES IF YOU DON'T WANT TO ADD LEDS TO INDICATE HEARTBEATS BY BLINKING
byte pulseLED = 11; //Must be on PWM pin
byte readLED = 13; //Blinks with each data read
#define DEVICE_LABEL "patient1" //Device Label should match that of Ubidots (CASE SENSITIVE: small letters recommended with no white space)
#define TOKEN "BBFF-fqHRKYVPndnLKJtta6PtBUkNyH0NkR" //Token can be accessed from API documentation on Ubidots
char const * VARIABLE_LABEL_1 = "spO2"; //Variable to store first sensor reading (SpO2) "O" is a letter not a number of
char const * VARIABLE_LABEL_2 = "heartrate"; //Variable to store second sensor reading (Heart Rate)
char const * VARIABLE_LABEL_3 = "temperature"; //Variable to store third sensor reading (Temperature)
char payload[700]; //combines all sensor readings to be sent to Ubidots platform
char str_val_1[30];
char str_val_2[30];
char str_val_3[30];
//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 MKR Wifi 1010";
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 = "Turbo"; // Put here your SSID name
char const * SSID_PASS = "HONEYHIVE"; // 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;
}
}
}
//FUNCTION TO UPLOAD DATA TO CLOUD
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);
pinMode(pulseLED, OUTPUT);
pinMode(readLED, OUTPUT);
byte ledBrightness = 60; //Options: 0=Off to 255=50mA
byte sampleAverage = 4; //Options: 1, 2, 4, 8, 16, 32
byte ledMode = 2; //Options: 1 = Red only, 2 = Red + IR, 3 = Red + IR + Green
byte sampleRate = 100; //Options: 50, 100, 200, 400, 800, 1000, 1600, 3200
int pulseWidth = 411; //Options: 69, 118, 215, 411
int adcRange = 4096; //Options: 2048, 4096, 8192, 16384
display.begin(SSD1306_SWITCHCAPVCC, 0x3C); //Start the OLED display
display.clearDisplay(); //Clear the display
display.display();
delay(3000);
// Initialize sensor
particleSensor.begin(Wire, I2C_SPEED_FAST);
particleSensor.setup(ledBrightness, sampleAverage, ledMode, sampleRate, pulseWidth, adcRange); //Configure sensor with these settings
particleSensor.setPulseAmplitudeRed(0x0A); //Turn Red LED to low to indicate sensor is running
particleSensor.enableDIETEMPRDY(); //Enable the temp ready interrupt. This is required.
Serial.println("Please wear the device.");
// check for the WiFi module:
if (WiFi.status() == WL_NO_MODULE) {
Serial.println("Communication with WiFi module failed!");
// don't continue
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(10,0);
display.println("Failed to connect");
display.setCursor(10,10);
display.println("to WiFi");
display.display();
while (true);
}
// attempt to connect to WiFi network:
while (status != WL_CONNECTED) {
Serial.print("Attempting to connect to SSID: ");
Serial.println(SSID_NAME);
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(10,0);
display.println("Connecting to");
display.setCursor(10,10);
display.println(SSID_NAME);
display.display();
// 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();
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(10,0);
display.println("Connected to");
display.setCursor(10,10);
display.println(SSID_NAME);
display.display();
}
void loop(){
long irValue = particleSensor.getIR();
if(irValue > 7000){ //IF DEVICE IS ATTACHED TO WEARER
//SPO2 and HEART RATE
bufferLength = 100; //buffer length of 100 stores 4 seconds of samples running at 25sps
//read the first 100 samples, and determine the signal range
for (byte i = 0 ; i < bufferLength ; i++)
{
while (particleSensor.available() == false) //do we have new data?
particleSensor.check(); //Check the sensor for new data
redBuffer[i] = particleSensor.getRed();
irBuffer[i] = particleSensor.getIR();
particleSensor.nextSample(); //We're finished with this sample so move to next sample
Serial.print(F("red="));
Serial.print(redBuffer[i], DEC);
Serial.print(F(", ir="));
Serial.println(irBuffer[i], DEC);
}
//calculate heart rate and SpO2 after first 100 samples (first 4 seconds of samples)
maxim_heart_rate_and_oxygen_saturation(irBuffer, bufferLength, redBuffer, &spo2, &validSPO2, &heartRate, &validHeartRate);
//Continuously taking samples from MAX30102. Heart rate and SpO2 are calculated every 1 second
//dumping the first 25 sets of samples in the memory and shift the last 75 sets of samples to the top
for (byte i = 25; i < 100; i++)
{
redBuffer[i - 25] = redBuffer[i];
irBuffer[i - 25] = irBuffer[i];
}
//take 25 sets of samples before calculating the heart rate.
for (byte i = 75; i < 100; i++)
{
while (particleSensor.available() == false) //do we have new data?
particleSensor.check(); //Check the sensor for new data
digitalWrite(readLED, !digitalRead(readLED)); //Blink onboard LED with every data read
redBuffer[i] = particleSensor.getRed();
irBuffer[i] = particleSensor.getIR();
particleSensor.nextSample(); //We're finished with this sample so move to next sample
//send samples and calculation result to terminal program through UART
Serial.print(F("red="));
Serial.print(redBuffer[i], DEC);
Serial.print(F(", ir="));
Serial.print(irBuffer[i], DEC);
Serial.print(F(", HR="));
Serial.print(heartRate, DEC);
Serial.print(F(", HRvalid="));
Serial.print(validHeartRate, DEC);
Serial.print(F(", SPO2="));
Serial.print(spo2, DEC);
Serial.print(F(", SPO2Valid="));
Serial.println(validSPO2, DEC);
//After gathering 25 new samples recalculate HR and SP02
maxim_heart_rate_and_oxygen_saturation(irBuffer, bufferLength, redBuffer, &spo2, &validSPO2, &heartRate, &validHeartRate);
}
//TEMPERATURE
float temperature = particleSensor.readTemperature();
Serial.print("temperatureC=");
Serial.print(temperature, 4);
float temperatureF = particleSensor.readTemperatureF(); //Because I am a bad global citizen
Serial.print(" temperatureF=");
Serial.print(temperatureF, 4);
Serial.println();
//DISPLAY THE VITALS ON THE OLED SCREEN
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0,0);
display.println("Sp02 :");
display.setCursor(40,0);
display.println(spo2);
display.setCursor(73,0);
display.println("HR :");
display.setCursor(99,0);
display.println(heartRate);
display.setCursor(0,20);
display.println("Temp :");
display.setCursor(40,20);
display.println(temperature);
display.display();
/*4 is the total length of number,maximum number accepted is 99.99*/
dtostrf(spo2, 4, 2, str_val_1);
dtostrf(heartRate, 4, 2, str_val_2);
dtostrf(temperature, 4, 2, str_val_3);
//The payload which contains all the sensor readings will be sent to the Ubidots platform in a JSON format, all at once
sprintf(payload, "%s","");
sprintf(payload, "{\"");
sprintf(payload, "%s%s\":%s", payload, VARIABLE_LABEL_1, str_val_1);
sprintf(payload, "%s,\"%s\":%s", payload, VARIABLE_LABEL_2, str_val_2);
sprintf(payload, "%s,\"%s\":%s", payload, VARIABLE_LABEL_3, str_val_3);
sprintf(payload, "%s}", payload);
//Send the payload to Ubidots
sendData(payload);
//delay(5000);
}
if (irValue < 7000){ //If device is removed it informs the user to put on the device
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(30,5);
display.println("Please wear ");
display.setCursor(30,15);
display.println("the device ");
display.display();
}
}
Comments