Hackster is hosting Hackster Holidays, Ep. 6: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Monday!Stream Hackster Holidays, Ep. 6 on Monday!

BuzzBeat

It is an advanced health monitor for getting 4 vital stats (spo2, hr, hrv and body temp. ) via a heroku server, integrated with the buzz.

AdvancedFull instructions provided5 days1,768

Things used in this project

Hardware components

Espressif NodeMCU
Main controller, client device
×1
Maxim Integrated MAX30100
To get heart rate, spo2 and heart rate variability
×1
MLX90614
To get ambient temperature and body temperature
×1
TP4056 lipo charging module
To charge battery and power the circuit
×1
Battery, 3.7 V
Battery, 3.7 V
To power the circuit
×1
SSD1306 oled display 128*64 white monochrome
To display all data to the subject
×1
Rocker Switch, Non Illuminated
Rocker Switch, Non Illuminated
ON-OFF switch
×1
Neosensory Buzz
Neosensory Buzz
Worn by the doctor so that he can feel the health of the patients subconsciously.
×1

Software apps and online services

Heroku Dynos
Heroku Dynos
To host web server
Neosensory Buzz
SDK for Neosensory buzz
Edge Impulse Studio
Edge Impulse Studio
For training models and deploying them on the server
Node-RED
Node-RED
For fetching http posts from nodemcu client
Android Studio
Android Studio
App development

Hand tools and fabrication machines

3D Printer (generic)
3D Printer (generic)
Soldering iron (generic)
Soldering iron (generic)

Story

Read more

Custom parts and enclosures

Top cover STL

3D print file for top cover

Case STL

3D print file for bottom casing

Schematics

Full schematic

It is the full breadboard schematic of the project

Code

NodeMCU main code

Arduino
It is the main code to be uploaded in the Node MCU. For support files like display.h and sensor.h, or for server side code refer github repo attached
#include <Wire.h>
#include <FS.h>
#include <ArduinoJson.h>   
#include <math.h>
#include <Arduino.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <ESP8266HTTPClient.h>
#include <ESP8266WebServer.h>
#include <EEPROM.h>  
#include <ESP8266WiFi.h>
#include "display.h"
#include "sensor.h"
#include "MAX30100_PulseOximeter.h"
#define camTrigger D4
#define trigger D7
#define buzzer D5
#define REPORTING_PERIOD_MS     1000

#define FREQUENCY_HZ        50
#define INTERVAL_MS         (1000 / (FREQUENCY_HZ + 1))

int i = 0;
int statusCode;
const char* ssid = "text";
const char* passphrase = "text";
String st;
String content;
const String Count;
ESP8266WebServer server(80);
String sensorDataToTransmit;
bool shouldSaveConfig = false;
uint8_t stat;
long time1 = 0, time2 = 0;
double count = 0;
PulseOximeter pox;
uint32_t tsLastReport = 0;
long hrv_time1 = 0, hrv_time2 = 0;

//Function Decalration
bool testWifi(void);
void launchWeb(void);
void setupAP(void);

void onBeatDetected()
{
  count++;
  hrv_time1 = (millis() - hrv_time2);
  hrv_time2 = millis();
}

void setup() {
  Serial.begin(115200);
  pinMode(camTrigger,OUTPUT);
  pinMode(trigger,INPUT);
  pinMode(buzzer, OUTPUT);
  WiFi.disconnect();
  EEPROM.begin(512);
  delay(10);
  
  Serial.println("Reading EEPROM ssid");
  String esid;
  for (int i = 0; i < 32; ++i)
  {
    esid += char(EEPROM.read(i));
  }
  Serial.println();
  Serial.print("SSID: ");
  Serial.println(esid);
  Serial.println("Reading EEPROM pass");
  String epass = "";
  for (int i = 32; i < 96; ++i)
  {
    epass += char(EEPROM.read(i));
  }
  Serial.print("PASS: ");
  Serial.println(epass);

  WiFi.begin(esid.c_str(), epass.c_str());

  if (!testWifi()) {
    Serial.println("Connection Status Negative / D15 HIGH");
    Serial.println("Turning the HotSpot On");
    launchWeb();
    setupAP();// Setup HotSpot
  }
  
  Serial.println();
  Serial.println("Waiting.");
    
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(100);
    server.handleClient();Serial.print("IP address: ");
    Serial.println(WiFi.localIP());
  }
  
  mlx.begin(); 
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C); //Start the OLED display
  display.clearDisplay();
  Serial.println("Initializing pulse oximeter..");
    if (!pox.begin()) {
        Serial.println("FAILED");
        for(;;);
    } else {
        Serial.println("SUCCESS");
    }
    pox.setIRLedCurrent(MAX30100_LED_CURR_50MA);
    display_connected();
    // Register a callback for the beat detection
    pox.setOnBeatDetectedCallback(onBeatDetected);
    time1 = millis();
    time2 = millis();
    hrv_time1 = millis();
    hrv_time2 = millis();
//    server.on("/", handle_root);
//    server.begin();
//    Serial.println("HTTP server started");
}

void loop() {
       pox.update();
    // Asynchronously dump heart rate and oxidation levels to the serial
    // For both, a value of 0 means "invalid"
    
    if (millis() - tsLastReport > REPORTING_PERIOD_MS) {        
        hrv = (60000/(hb+1) - hrv_time1)/1000; 
        //hb = pox.getHeartRate();
        spo2 = pox.getSpO2();
        //oxi_temp = pox.getTemperature();
        display_home((String(hb,0)),1,(String(hrv,1)),(String(spo2,0)),(String(temperature,1)),(String(count,0)));
        tsLastReport = millis();
    };
   if(millis() - time1 > 30000){
    hb = count*2;
    count = 0;
    time1 = millis();
//    Serial.print("Heart rate:");
//    Serial.println(hb);
    temperature = mlx_read();
    Serial.println(temperature);
    
   }
   if(millis() - time2 > 3000) {
       Serial.print(hrv);
       Serial.print(",");
       Serial.print(spo2);
       Serial.print(",");
       Serial.print(temperature);
       Serial.print(",");
       Serial.println(count);
       time2 = millis();
       json_send();
   }
   // handle client connections  
   //server.handleClient();
}

void handle_root() {
  server.send(200, "text/html", sensorDataToTransmit);
}

void json_send() {
  StaticJsonBuffer<100> sensorValues;
  JsonObject& sensor = sensorValues.createObject(); 
  if (sensor.success()) {
      Serial.println("\nparsed json");
      sensor["spo2"] = spo2;
      sensor["hrv"] = hrv;
      sensor["hb"] = hb*2.5;
      //sensor["Ambient(degC)"] = mlx.readAmbientTempC();
      //sensor["oxi_temp"] = oxi_temp;
      sensor["temp"] = temperature;
      // clear any previous data
      sensorDataToTransmit = "";
      sensor.printTo(sensorDataToTransmit); 
      Serial.println("This is the sensor data that will be transmitted - ");
      Serial.println(sensorDataToTransmit);
      
      HTTPClient http;    //Declare object of class HTTPClient
       
      http.begin("http://spo2-registration.herokuapp.com/neoSenseSender");      //Specify request destination
      http.addHeader("Content-Type", "application/json");  //Specify content-type header
   
      int httpCode = http.POST(sensorDataToTransmit);   //Send the request
      String payload = http.getString();                                        //Get the response payload
   
      Serial.println(httpCode);   //Print HTTP return code
      Serial.println(payload);    //Print request response payload
   
      http.end();
      
      }
}

//-------- Fuctions used for WiFi credentials saving and connecting to it which you do not need to change 
bool testWifi(void)
{
  int c = 0;
  Serial.println("Waiting for Wifi to connect");
  while ( c < 20 ) {
    if (WiFi.status() == WL_CONNECTED)
    {
      return true;
    }
    delay(500);
    Serial.print("*");
    c++;
  }
  Serial.println("");
  Serial.println("Connect timed out, opening AP");
  return false;
}
 
void launchWeb()
{
  Serial.println("");
  if (WiFi.status() == WL_CONNECTED)
    Serial.println("WiFi connected");
  Serial.print("Local IP: ");
  Serial.println(WiFi.localIP());
  Serial.print("SoftAP IP: ");
  Serial.println(WiFi.softAPIP());
  createWebServer();
  // Start the server
  server.begin();
  Serial.println("Server started");
}
 
void setupAP(void)
{
  WiFi.mode(WIFI_STA);
  WiFi.disconnect();
  delay(100);
  int n = WiFi.scanNetworks();
  Serial.println("scan done");
  if (n == 0)
    Serial.println("no networks found");
  else
  {
    Serial.print(n);
    Serial.println(" networks found");
    for (int i = 0; i < n; ++i)
    {
      // Print SSID and RSSI for each network found
      Serial.print(i + 1);
      Serial.print(": ");
      Serial.print(WiFi.SSID(i));
      Serial.print(" (");
      Serial.print(WiFi.RSSI(i));
      Serial.print(")");
      Serial.println((WiFi.encryptionType(i) == ENC_TYPE_NONE) ? " " : "*");
      delay(10);
    }
  }
  Serial.println("");
  st = "<ol>";
  for (int i = 0; i < n; ++i)
  {
    // Print SSID and RSSI for each network found
    st += "<li>";
    st += WiFi.SSID(i);
    st += " (";
    st += WiFi.RSSI(i);
 
    st += ")";
    st += (WiFi.encryptionType(i) == ENC_TYPE_NONE) ? " " : "*";
    st += "</li>";
  }
  st += "</ol>";
  delay(100);
  WiFi.softAP("advanced_pulse_oxi", "");
  Serial.println("softap");
  launchWeb();
  Serial.println("over");
}
 
void createWebServer()
{
 {
    server.on("/", []() {
 
      IPAddress ip = WiFi.softAPIP();
      String ipStr = String(ip[0]) + '.' + String(ip[1]) + '.' + String(ip[2]) + '.' + String(ip[3]);
      content = "<!DOCTYPE HTML>\r\n<html>Hello from ESP8266 at ";
      content += "<form action=\"/scan\" method=\"POST\"><input type=\"submit\" value=\"scan\"></form>";
      content += ipStr;
      content += "<p>";
      content += st;
      content += "</p><form method='get' action='setting'><label>SSID: </label><input name='ssid' length=32><label>Password: </label><input name='pass' length=64><input type='submit'></form>";
      content += "</html>";
      server.send(200, "text/html", content);
    });
    server.on("/scan", []() {
      //setupAP();
      IPAddress ip = WiFi.softAPIP();
      String ipStr = String(ip[0]) + '.' + String(ip[1]) + '.' + String(ip[2]) + '.' + String(ip[3]);
 
      content = "<!DOCTYPE HTML>\r\n<html>go back";
      server.send(200, "text/html", content);
    });
 
    server.on("/setting", []() {
      String qsid = server.arg("ssid");
      String qpass = server.arg("pass");
      if (qsid.length() > 0 && qpass.length() > 0) {
        Serial.println("clearing eeprom");
        for (int i = 0; i < 96; ++i) {
          EEPROM.write(i, 0);
        }
        Serial.println(qsid);
        Serial.println("");
        Serial.println(qpass);
        Serial.println("");
 
        Serial.println("writing eeprom ssid:");
        for (int i = 0; i < qsid.length(); ++i)
        {
          EEPROM.write(i, qsid[i]);
          Serial.print("Wrote: ");
          Serial.println(qsid[i]);
        }
        Serial.println("writing eeprom pass:");
        for (int i = 0; i < qpass.length(); ++i)
        {
          EEPROM.write(32 + i, qpass[i]);
          Serial.print("Wrote: ");
          Serial.println(qpass[i]);
        }
        EEPROM.commit();
 
        content = "{\"Success\":\"saved to eeprom... reset to boot into new wifi\"}";
        statusCode = 200;
        ESP.reset();
      } else {
        content = "{\"Error\":\"404 not found\"}";
        statusCode = 404;
        Serial.println("Sending 404");
      }
      server.sendHeader("Access-Control-Allow-Origin", "*");
      server.send(statusCode, "application/json", content);
 
    });
  } 
}

App source code

Java
It is the source code for the Buzz Beat app. The java code consists of the main functionality of the buzz, with all the permission and location access to the range of receiving the json value and then sending it into the motor values
package com.example.neosensespo2draft;

import androidx.appcompat.app.AppCompatActivity;

import android.Manifest;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import com.neosensory.neosensoryblessed.NeosensoryBlessed;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Array;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Arrays;

import javax.net.ssl.HttpsURLConnection;

import pl.droidsonroids.gif.GifImageView;

public class MainActivity extends AppCompatActivity {
    private final String TAG = MainActivity.class.getSimpleName();

//    spo2 - 80 to 100
//    HR - 60-160
//    HRV - 0-120 ms
//    temp - 28-43 degC

    //Ranges for all differnet motors
    int spo2Start = 80;
    int spo2End=100;

    int hrStart = 60;
    int hrEnd =160;

    int hrvStart=20;
    int hrvEnd = 120;

    int tempStart = 28;

    int tempEnd = 43;

    // range for motor
    int startY = 40;
    int endY = 255;

    // UI components
    //before connect
    Button connect;
    TextView instruction;
    //after connect
    Button disconnect,start;
    TextView label1,label2,label3,label4,cliOutput,label5;
    TextView spooTag,temperatureTag,heartrateTag,hrvTag,trueInsightTag;
    GifImageView gif;
    // Constants
    private static final int ACCESS_LOCATION_REQUEST = 2;
    private static final int NUM_MOTORS = 4;

    //variables for motor roations
    int spooInt,tempInt,hrvInt,hrInt;

    // Access the library to leverage the Neosensory API
    private NeosensoryBlessed blessedNeo = null;


    // Variable to track whether or not the wristband should be vibrating
    private static boolean vibrating = false;
    private static boolean disconnectRequested =
            false; // used for requesting a disconnect within our thread
    Runnable vibratingPattern;
    Thread vibratingPatternThread;

    // class for downloading the json data from the node.js server
    public class  WeatherDownloader extends AsyncTask<String,Void,String>{

        @Override
        protected void onPostExecute(String s) {
            super.onPostExecute(s);
            try{
                JSONObject jsonObject = new JSONObject(s);
                String spo2 = jsonObject.getString("spo2");
                spooTag.setText(spo2);
                spooInt = (int) Float.parseFloat(spo2);
                String hr = jsonObject.getString("hr");
                heartrateTag.setText(hr);
                hrInt= (int) Float.parseFloat(hr);
                String temperature = jsonObject.getString("temperature");
                temperatureTag.setText(temperature);
                tempInt = (int)Float.parseFloat(temperature);
                String insight = jsonObject.getString("hrv");
                hrvTag.setText(insight);
                hrvInt = (int) Float.parseFloat(insight);
                String trueInsight = jsonObject.getString("insight");
                trueInsightTag.setText(trueInsight);


            } catch (JSONException e) {
                e.printStackTrace();
            }
        }

        @Override
        protected String doInBackground(String... strings) {
            String results="";
            URL url;

            HttpsURLConnection urlConnection = null;

            try {
                url = new URL(strings[0]);

                urlConnection = (HttpsURLConnection) url.openConnection();

                InputStream reader = urlConnection.getInputStream();

                int data = reader.read();

                while(data!=-1){
                    char current = (char)data;
                    results += current;
                    data = reader.read();

                }
                return results;
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //preconnect ui
        connect = (Button) findViewById(R.id.connectButton);
        instruction = (TextView) findViewById(R.id.instruction);
        //cli
        cliOutput = (TextView) findViewById(R.id.cli_response);
        //labels
        label1 = (TextView) findViewById(R.id.label1);
        label2=(TextView) findViewById(R.id.label2);
        label3=(TextView) findViewById(R.id.label3);
        label4 =(TextView) findViewById(R.id.label4);
        label5 =(TextView) findViewById(R.id.label5);
        //textViews
        spooTag = (TextView) findViewById(R.id.spooTag);
        heartrateTag = (TextView) findViewById(R.id.heartrateTag);
        temperatureTag = (TextView) findViewById(R.id.temperatureTag);
        hrvTag = (TextView) findViewById(R.id.insightTag);
        trueInsightTag = (TextView)findViewById(R.id.trueInsightTag);
        //button post connect
        disconnect = (Button) findViewById(R.id.button2);
        start = (Button) findViewById(R.id.button3);

        //gif
        gif = (GifImageView)findViewById(R.id.gif);

        displayInitialUI();

        NeosensoryBlessed.requestBluetoothOn(this);

        if(checkLocationPermissions()){
            displayInitConnectButton();
        }


        vibratingPattern= new VibratingPattern();
    }

    public double round(double d){
        return Math.floor(d+0.5);
    }

    public  int mapCustom(int yStart,int yend,int inputEnd,int input,int inputStart){
//        double slope= 1.0* (yend-yStart)/(inputEnd-inputStart);
//        double output = yStart + round(slope*(input-inputStart));
        int input_range = inputEnd-inputStart;
        int output_range = yend-yStart;
        int output = (input-inputStart)*output_range/input_range + yStart;
        if (output<0){
            return 0;
        }
        else if(output>yend){
            return yend;
        }
        else{
            return (int) output;
        }
    }
    class VibratingPattern implements Runnable {
        private int minVibration = 40;
        private int currentVibration = minVibration;

        public void run() {

            // loop until the thread is interrupted
            int motorID = 0;
            while (!Thread.currentThread().isInterrupted() && vibrating) {
                try {
                    Log.i("Vibration", String.valueOf(currentVibration) + "in motor "+String.valueOf(motorID));
                    Log.i("Tag",String.valueOf(motorID));
                    Log.i("max amp", String.valueOf(NeosensoryBlessed.MAX_VIBRATION_AMP));

                    Thread.sleep(1000);
                    WeatherDownloader task = new WeatherDownloader();
                    task.execute("https://spo2-registration.herokuapp.com/neoSenseSender");
                    int spo2M=mapCustom(minVibration,endY,spo2End,spooInt,spo2Start);
                    int hrvM=mapCustom(minVibration,endY,hrvEnd,hrvInt,hrvStart);
                    int tempM=mapCustom(minVibration,endY,tempEnd,tempInt,tempStart);
                    int hrM=mapCustom(minVibration,endY,hrEnd,hrInt,hrStart);

                    int[] motorPattern = new int[]{spo2M,hrvM, tempM,hrM};
//                    motorPattern[motorID] = currentVibration;
                    blessedNeo.vibrateMotors(motorPattern);
                    Log.i("array", Arrays.toString(motorPattern));
                    if (currentVibration == 0) {
                        currentVibration = minVibration;
                    }
                } catch (InterruptedException e) {
                    blessedNeo.stopMotors();
                    blessedNeo.resumeDeviceAlgorithm();
                    Log.i(TAG, "Interrupted thread");
                    e.printStackTrace();
                }
            }
            if (disconnectRequested) {
                Log.i(TAG, "Disconnect requested while thread active");
                blessedNeo.stopMotors();
                blessedNeo.resumeDeviceAlgorithm();
                // When disconnecting: it is possible for the device to process the disconnection request
                // prior to processing the request to resume the onboard algorithm, which causes the last
                // sent motor command to "stick"
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                blessedNeo.disconnectNeoDevice();
                disconnectRequested = false;
            }
        }
    }

    //////////////////////////
    // Cleanup on shutdown //
    /////////////////////////

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(BlessedReceiver);
        if (vibrating) {
            vibrating = false;
            disconnectRequested = true;
        }
        blessedNeo = null;
        vibratingPatternThread = null;
    }

    ////////////////////////////////////
    // SDK state change functionality //
    ////////////////////////////////////

    private final BroadcastReceiver BlessedReceiver =
            new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {
                    if (intent.hasExtra("com.neosensory.neosensoryblessed.CliReadiness")) {
                        // Check the message from NeosensoryBlessed to see if a Neosensory Command Line
                        // Interface
                        // has become ready to accept commands
                        // Prior to calling other API commands we need to accept the Neosensory API ToS
                        if (intent.getBooleanExtra("com.neosensory.neosensoryblessed.CliReadiness", false)) {
                            // request developer level access to the connected Neosensory device
                            blessedNeo.sendDeveloperAPIAuth();
                            // sendDeveloperAPIAuth() will then transmit a message back requiring an explicit
                            // acceptance of Neosensory's Terms of Service located at
                            // https://neosensory.com/legal/dev-terms-service/
                            blessedNeo.acceptApiTerms();
                            Log.i(TAG, String.format("state message: %s", blessedNeo.getNeoCliResponse()));
                            // Assuming successful authorization, set up a button to run the vibrating pattern
                            // thread above
                            displayVibrateButton();
                            displayDisconnectUI();
                        } else {
                            displayReconnectUI();
                        }
                    }

                    if (intent.hasExtra("com.neosensory.neosensoryblessed.CliMessage")) {
                        String notification_value =
                                intent.getStringExtra("com.neosensory.neosensoryblessed.CliMessage");
                        cliOutput.setText(notification_value);
                    }

                    if (intent.hasExtra("com.neosensory.neosensoryblessed.ConnectedState")) {
                        if (intent.getBooleanExtra("com.neosensory.neosensoryblessed.ConnectedState", false)) {
                            Log.i(TAG, "Connected to Buzz");
                        } else {
                            Log.i(TAG, "Disconnected from Buzz");
                        }
                    }
                }
            };



    public void displayVibrateButton() {
        connect.setVisibility(View.GONE);
        cliOutput.setVisibility(View.VISIBLE);
        gif.setVisibility(View.VISIBLE);
        label1.setVisibility(View.VISIBLE);
        label2.setVisibility(View.VISIBLE);
        label3.setVisibility(View.VISIBLE);
        label4.setVisibility(View.VISIBLE);
        label5.setVisibility(View.VISIBLE);
        spooTag.setVisibility(View.VISIBLE);
        heartrateTag.setVisibility(View.VISIBLE);
        hrvTag.setVisibility(View.VISIBLE);
        temperatureTag.setVisibility(View.VISIBLE);
        trueInsightTag.setVisibility(View.VISIBLE);
        instruction.setVisibility(View.GONE);
    }

    private void displayDisconnectUI() {
        disconnect.setVisibility(View.VISIBLE);
        disconnect.setClickable(true);
        start.setVisibility(View.VISIBLE);
        disconnect.setOnClickListener(
                new View.OnClickListener() {
                    public void onClick(View v) {
                        if (!vibrating) {
                            blessedNeo.disconnectNeoDevice();
                        } else {
                            // If motors are vibrating (in the VibratingPattern thread in this case) and we want
                            // to stop them on disconnect, we need to add a sleep/delay as it's possible for the
                            // disconnect to be processed prior to stopping the motors. See the VibratingPattern
                            // definition.
                            disconnectRequested = true;
                            vibrating = false;
                        }
                    }
                });
    }

    private void displayReconnectUI() {
        cliOutput.setVisibility(View.GONE);
        gif.setVisibility(View.GONE);
        label1.setVisibility(View.GONE);
        label2.setVisibility(View.GONE);
        label3.setVisibility(View.GONE);
        label4.setVisibility(View.GONE);
        label5.setVisibility(View.GONE);
        spooTag.setVisibility(View.GONE);
        heartrateTag.setVisibility(View.GONE);
        hrvTag.setVisibility(View.GONE);
        temperatureTag.setVisibility(View.GONE);
        trueInsightTag.setVisibility(View.GONE);

        disconnect.setVisibility(View.GONE);
        start.setVisibility(View.GONE);
        connect.setVisibility(View.VISIBLE);
        instruction.setVisibility(View.VISIBLE);
        connect.setOnClickListener(
                new View.OnClickListener() {
                    public void onClick(View v) {
                        blessedNeo.attemptNeoReconnect();
                        toastMessage("Attempting to reconnect. This may take a few seconds.");
                    }
                });
    }

    private void displayInitConnectButton() {
        connect.setVisibility(View.VISIBLE);
        connect.setClickable(true);
        connect.setOnClickListener(
                new View.OnClickListener() {
                    public void onClick(View v) {
                        initBluetoothHandler();
                    }
                });
    }


    private void displayInitialUI() {
        displayReconnectUI();
        start.setOnClickListener(
                new View.OnClickListener() {
                    public void onClick(View v) {
                        if (!vibrating) {
                            blessedNeo.pauseDeviceAlgorithm();
                            start.setText("Stop");
                            vibrating = true;
                            // run the vibrating pattern loop
                            vibratingPatternThread = new Thread(vibratingPattern);
                            vibratingPatternThread.start();
                        } else {
                            start.setText("Start");
                            vibrating = false;
                            blessedNeo.resumeDeviceAlgorithm();
                        }
                    }
                }
        );
    }


    private void toastMessage(String s) {
        Toast.makeText(this, s, Toast.LENGTH_SHORT).show();
    }

    //////////////////////////////////////////////
    // Bluetooth and permissions initialization //
    //////////////////////////////////////////////

    private void initBluetoothHandler() {
        // Create an instance of the Bluetooth handler. This uses the constructor that will search for
        // and connect to the first available device with "Buzz" in its name. To connect to a specific
        // device with a specific address, you can use the following pattern:  blessedNeo =
        // NeosensoryBlessed.getInstance(getApplicationContext(), <address> e.g."EB:CA:85:38:19:1D",
        // false);
        blessedNeo =
                NeosensoryBlessed.getInstance(getApplicationContext(), new String[] {"Buzz"}, false);
        // register receivers so that NeosensoryBlessed can pass relevant messages and state changes to MainActivity
        registerReceiver(BlessedReceiver, new IntentFilter("BlessedBroadcast"));
    }


    private boolean checkLocationPermissions() {
        int targetSdkVersion = getApplicationInfo().targetSdkVersion;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
                && targetSdkVersion >= Build.VERSION_CODES.Q) {
            if (getApplicationContext().checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION)
                    != PackageManager.PERMISSION_GRANTED) {
                requestPermissions(
                        new String[] {Manifest.permission.ACCESS_FINE_LOCATION}, ACCESS_LOCATION_REQUEST);
                return false;
            } else {
                return true;
            }
        } else {
            if (getApplicationContext().checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION)
                    != PackageManager.PERMISSION_GRANTED) {
                requestPermissions(
                        new String[] {Manifest.permission.ACCESS_COARSE_LOCATION}, ACCESS_LOCATION_REQUEST);
                return false;
            } else {
                return true;
            }
        }
    }

}

Main repository

It is the main repository of the project, containing all code from client as well as server side

Credits

Sachin Singh Bhadoriya

Sachin Singh Bhadoriya

2 projects • 7 followers
Skilled in algorithm making for languages such as C++, Java, and Python. Engineering Student and an active contributor to the open source!
TheBlue Phoenix

TheBlue Phoenix

7 projects • 32 followers
I have represented India Internationally. I have knowledge of various boards and embedded coding, FPGAs, TI, ADI, On Semi, RPi, SBCs etc.
Satvik Deshmukh

Satvik Deshmukh

2 projects • 3 followers

Comments