#ESP32 # BLE #COVID19 #Coronavirus #SocialDistancing #FlattenTheCurve #DeltaVariant #Pandemic

In this Project, We will show you how to create a Social Distancing Monitor using ESP32 Wi-Fi/BLE Controller with some LEDs and Buzzer.

Watch the Video Tutorial

You can watch the Video Tutorial by clicking the link below or continue reading the written instructions below:


Project Brief

The emergence of COVID-19 in 2019 led to a global pandemic, profoundly affecting health, economies, and daily life. Governments worldwide adopted strategies to contain the virus, including a pivotal measure: Social Distancing

This approach involves maintaining physical distance, typically around 6 feet or 2 meters, to impede the spread of contagious diseases like COVID-19 by minimizing close contact.

Social distancing is crucial against COVID-19 for three reasons:
1) It stops virus-laden droplets from infecting others by maintaining distance.
2) It limits the spread from asymptomatic carriers.
3) It safeguards vulnerable populations.

Social distancing was instrumental in slowing transmission and reducing the virus's impact.



However effectively implementing social distancing measures can be challenging and in this project we will create a wearable device which will help to ensure proper social distancing protocols are monitored and maintained.

Project Objectives

By addressing these objectives, we can create a robust ESP32-based wearable device for social distancing monitoring that promotes safe interactions in various settings.


Parts Components List

To make our  ESP32-based wearable device for social distancing monitoring we will use the following components:

Schematic Wiring Diagram

Before we can proceed further, we need to connect all our components with respect to the wiring diagram below: 

While connecting all the components together , please ensure the following:
  1.  ESP32 Controller or RGB Module has its male header pins soldered properly.
  2. All Jumper Wires are properly inserted in the breadboard.
  3. ESP32 Controller is fully inserted on the breadboard and should not have any gap between the controller & the breadboard.



Project Methodology


BLE stands for Bluetooth Low Energy, and it is a wireless communication technology that is a variant of the standard Bluetooth technology. 

Here's an overview of BLE and the key differences between BLE and standard Bluetooth:



Bluetooth Low Energy (BLE):

1. Low Power Consumption: BLE is designed to operate with minimal power consumption, making it suitable for battery-powered devices such as wearables, fitness trackers, and IoT devices. It allows devices to run for extended periods on small coin cell batteries.

2. Short Range: BLE is optimized for short-range communication, typically within a range of about 10 meters (30 feet). This short range helps conserve power.

3. Data Transfer Rate: BLE has a lower data transfer rate compared to standard Bluetooth. It is ideal for transmitting small bursts of data, such as sensor readings or control commands.

4. Connectionless Communication: BLE supports both connection-oriented and connectionless communication. It allows devices to transmit data without establishing a full connection, which is useful for broadcasting data to multiple devices.

5. Simplified Pairing: BLE uses simplified pairing methods, such as passkey entry and out-of-band (OOB) pairing, to simplify the process of connecting devices securely.

6. Profile-Based Communication: BLE communication is organized into profiles and services, making it easy for devices to understand each other's capabilities and exchange data efficiently.

7. Beacon Technology: BLE beacons are widely used for location-based services and proximity marketing. Beacons broadcast small packets of data at regular intervals to nearby devices.


Standard Bluetooth (Classic Bluetooth):

1. Higher Power Consumption: Standard Bluetooth, also known as Classic Bluetooth, consumes more power compared to BLE. It is commonly used for devices that have a continuous need for higher data transfer rates.

2. Longer Range: Classic Bluetooth offers a longer communication range, typically up to 100 meters (300 feet), but this comes at the cost of increased power consumption.

3. Higher Data Transfer Rate: Standard Bluetooth provides higher data transfer rates, suitable for applications like audio streaming (e.g., wireless headphones or speakers) and file transfers.

4. Complex Pairing: Pairing devices using standard Bluetooth can be a more complex process compared to BLE. It often involves entering PINs or passkeys.

5. Less Efficient for Low-Power Devices: Classic Bluetooth is less efficient for battery-powered and low-power devices due to its higher power consumption.

In summary, BLE is optimized for low power consumption and short-range communication, making it ideal for applications like fitness trackers, IoT devices, and beacon technology. Standard Bluetooth, on the other hand, offers higher data rates and longer range but consumes more power, making it suitable for applications like audio streaming and file transfers. 



For this project, we will utilize BLE for its short range and low power consumption, making it ideal for our social distancing monitor application.



ESP32 Dev Board Controller is a highly versatile microcontroller board known for its robust capabilities. 

It features the ESP32 chip, which not only offers powerful processing but also includes built-in Bluetooth Low Energy (BLE) functionality. 

This BLE capability makes it well-suited for a wide range of applications, particularly in the realm of IoT and wearables. Developers can leverage the ESP32's BLE capabilities to create energy-efficient and wireless connections between devices, making it a popular choice for projects that require both Wi-Fi and BLE connectivity. 

In summary, the ESP32 Dev Board Controller's integration of BLE enhances its potential for IoT and wireless communication applications.




ESP32 Based Social Distancing Monitor Control Methodology will be followed to achieve the desired objectives of this project.




ESP32 Controller scans for BLE Devices by configured names of “ESP32_SDM”  (BLE Device Names are configurable via coding in Arduino 2.0 )

If NO BLE devices with the respective name is found then:
  • RGB LED remains OFF
  • Buzzer remains OFF


ESP32 Controller scans for BLE Devices by configured names of “ESP32_SDM”  (BLE Device Names are configurable via coding in Arduino 2.0 )

If Devices is available with the respective name and its distance between each other is greater than 1.5 meters then:
  • RGB LED blinks GREEN
  • Buzzer remains OFF



ESP32 Controller scans for BLE Devices by configured names of “ESP32_SDM”  (BLE Device Names are configurable via coding in Arduino 2.0 )

If Devices is available with the respective name and its distance between each other is near to approximately 1.5 meters then:
  • RGB LED blinks YELLOW
  • Buzzer remains OFF



ESP32 Controller scans for BLE Devices by configured names of “ESP32_SDM”  (BLE Device Names are configurable via coding in Arduino 2.0 )

If Devices is available with the respective name and its distance between each other lesser 1.5 meters then:
  • RGB LED blinks RED
  • Buzzer turns ON


Arduino IDE 2.0 ESP32 Board Installation

You will need to install ESP32 Board in order to detect and program the controller accordingly, kindly follow the steps below:

 A) Open Arduino IDE 2.0 and update to latest version, you will arrive at the default empty sketch as shown below


 B)  Go to File and then click Preferences.



C) Once Preferences opens, click Additional Board Manager URLs and paste the following Link: https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json



D) Click on Okay on Additional Board Manager URL and Okay on the Preferences Page


E) Now go to Tools and then click Board, you will see ESP32, click on that and it will expand all the ESP32 variants. For this project we will select ESP32 Dev Module



F) We will now confirm if ESP32 Drivers have been installed successfully, for this we will need to upload an example sketch of Blink which can make the LED on the ESP32 Board blink respectively.

Copy the code below and paste into the Arduino IDE.

/*
  Knight Automation Services
  Blink Example Sketch Modified for ESP32 Dev Board
 
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.
 
  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.

  Blink Example Sketch Modified from
  https://www.arduino.cc/en/Tutorial/BuiltInExamples/Blink
*/

#define LED_BUILTIN 2

// the setup function runs once when you press reset or power the board
void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(LED_BUILTIN, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
  digitalWrite(LED_BUILTIN, HIGH);  // turn the LED on (HIGH is the voltage level)
  delay(1000);                      // wait for a second
  digitalWrite(LED_BUILTIN, LOW);   // turn the LED off by making the voltage LOW
  delay(1000);                      // wait for a second
}

G) After pasting the code, plug in your ESP32 Controller via the USB Cable. Once plugged in, go to Arduino IDE , click on Tools and then Port and select the port available for ESP32.



NOTE: If you don't see any available port in Arduino IDE when ESP32 is connected, then kindly try installing CP210x USB to UART Bridge VCP Drivers


H) Now Click on Verify (Tick Button) and after successful compilation it will update the status on the Output window 



I) Click on Upload (Arrow Button) and after successful uploading, your ESP32 controller Built In LED will start to blink indicating a successful installation of ESP32 Drivers and Board into Arduino 2.0



J) ESP32 Built In LED will Flash after every second as defined in the blink sketch. The below picture shows the LED which will flash on the ESP32 dev board.

Arduino IDE 2.0 Code

Perfect, now we are ready to upload our Main Code into Both of our ESP32 Controllers for this ESP32 Social Distancing Monitor Project.

Open Arduino IDE and Copy the Below Code :

/*
   Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleScan.cpp
   Ported to Arduino ESP32 by Evandro Copercini
   Modifed by Knight Automation Services for ESP32 Social Distancing Monitor

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.
 
  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*/

/////////////////////////////////////////////////////// LIBRARIES ////////////////////////////////////////////////////////////////

#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEScan.h>
#include <BLEAdvertisedDevice.h>
#include <BLEServer.h>


/////////////////////////////////////////////////////// CONFIGURATIONS ////////////////////////////////////////////////////////////////

int Very_Close_Proximity_RSSI_Threshold = -70;
int Moderate_Proximity_RSSI_Threshold = -80;
int Far_Proximity_RSSI_Threshold = -85;

/////////////////////////////////////////////////////// CONNECTIONS ////////////////////////////////////////////////////////////////

int RGB_LED_R_Pin = 25;  //4
int RGB_LED_G_Pin = 26;  //4
int RGB_LED_B_Pin = 27;  //4
int Buzzer_Pin = 5;

/////////////////////////////////////////////////////// LOGICAL OPERATIONS ////////////////////////////////////////////////////////////////

int scanTime = 5;  //In seconds
BLEScan *pBLEScan;
int RSSI_STS = 0;
int LED_BUZZER_FREQUENCY = 0;

unsigned long previousMillis = 0;   // will store last time LED was updated
unsigned long previousMillis2 = 0;  // will store last time LED was updated
unsigned long previousMillis3 = 0;  // will store last time LED was updated

int LED_STATE = 0;



/////////////////////////////////////////////////////// BLE VARIABLES ////////////////////////////////////////////////////////////////



BLEClient *pClient;
bool deviceFound = false;

String knownAddresses[] = { ":  :  :  :  :  ", " :  :  :  :  : " };

String knownNames[] = { ":  :  :  :  :  ", "ESP32_SDM" };

static BLEAddress *pServerAddress;

std::string pServerName;

#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"


static void notifyCallback(
  BLERemoteCharacteristic *pBLERemoteCharacteristic,
  uint8_t *pData,
  size_t length,
  bool isNotify) {
  Serial.print("Notify callback for characteristic ");
  Serial.print(pBLERemoteCharacteristic->getUUID().toString().c_str());
  Serial.print(" of data length ");
  Serial.println(length);
}

class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks {
  /**
         Called for each advertising BLE server.
    */
  void onResult(BLEAdvertisedDevice advertisedDevice) {
    Serial.printf("Advertised Device: %s \n", advertisedDevice.toString().c_str());
    pServerAddress = new BLEAddress(advertisedDevice.getAddress());
    pServerName = advertisedDevice.getName();

    Serial.print("Name =  ");
    Serial.println(pServerName.c_str());

    bool known = false;
    bool known2 = false;
    for (int i = 0; i < (sizeof(knownAddresses) / sizeof(knownAddresses[0])); i++) {
      if (strcmp(pServerAddress->toString().c_str(), knownAddresses[i].c_str()) == 0) known = true;
    }

    for (int i = 0; i < (sizeof(knownNames) / sizeof(knownNames[0])); i++) {
      if (strcmp(pServerName.c_str(), knownNames[i].c_str()) == 0) known2 = true;
    }
    Serial.print("known2: ");
    Serial.println(known2);

    if (known2) {
      Serial.print("Device found: ");
      Serial.println(advertisedDevice.getRSSI());
      RSSI_STS = (advertisedDevice.getRSSI());
      if (advertisedDevice.getRSSI() > -150) deviceFound = true;
      else deviceFound = false;
      Serial.println(pServerAddress->toString().c_str());
      advertisedDevice.getScan()->stop();
    } else {
      deviceFound = false;
    }
    /******** This releases the memory when we're done. ********/
    delete pServerAddress;
  }
};

void setup() {
  Serial.begin(115200);
  Serial.println("Scanning...");

  Pin_Mode_Configurations();
  BLE_Setup_Stage();
}

void loop() {
  // put your main code here, to run repeatedly:

  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= 2000) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;

    BLEScanResults foundDevices = pBLEScan->start(scanTime, false);
    Serial.print("Devices Nos: ");
    Serial.println(foundDevices.getCount());
    Serial.println("Scan done!");
    pBLEScan->clearResults();  // delete results fromBLEScan buffer to release memory
  }

  if (currentMillis - previousMillis2 >= 2000) {
    // save the last time you blinked the LED
    previousMillis2 = currentMillis;
    Serial.print("deviceFound STS ");
    Serial.println(deviceFound);

    Serial.print("RSSI_STS : ");
    Serial.println(RSSI_STS);

    if (RSSI_STS > Very_Close_Proximity_RSSI_Threshold) {
      Serial.println("Very Close Proximity");
    } else if ((RSSI_STS <= Very_Close_Proximity_RSSI_Threshold && RSSI_STS > Moderate_Proximity_RSSI_Threshold)) {
      Serial.println("Moderate Proximity");

    } else if (RSSI_STS <= Far_Proximity_RSSI_Threshold) {
      Serial.println("Far Proximity");
    }
  }


  if (deviceFound) {
    if (RSSI_STS > Very_Close_Proximity_RSSI_Threshold) {
      // Serial.println("Very Close Proximity");

      unsigned long currentMillis2 = millis();
      if (currentMillis2 - previousMillis3 >= 150) {  // ON Period
        // save the last time you blinked the LED
        previousMillis3 = currentMillis2;

        if (LED_STATE == 1) {

          digitalWrite(RGB_LED_R_Pin, HIGH);
          digitalWrite(RGB_LED_G_Pin, LOW);
          digitalWrite(RGB_LED_B_Pin, LOW);
          digitalWrite(Buzzer_Pin, HIGH);
          LED_STATE = 0;
        } else if (LED_STATE == 0) {
          digitalWrite(RGB_LED_R_Pin, LOW);
          digitalWrite(RGB_LED_G_Pin, LOW);
          digitalWrite(RGB_LED_B_Pin, LOW);
          digitalWrite(Buzzer_Pin, LOW);
          LED_STATE = 1;
        }
      }


    } else if ((RSSI_STS <= Very_Close_Proximity_RSSI_Threshold && RSSI_STS > Moderate_Proximity_RSSI_Threshold)) {
      // Serial.println("Moderate Proximity");
      unsigned long currentMillis2 = millis();

      if (currentMillis2 - previousMillis3 >= 500) {  // ON Period
        // save the last time you blinked the LED
        previousMillis3 = currentMillis2;
        if (LED_STATE == 1) {
          digitalWrite(RGB_LED_R_Pin, HIGH);
          digitalWrite(RGB_LED_G_Pin, HIGH);
          digitalWrite(RGB_LED_B_Pin, LOW);
          digitalWrite(Buzzer_Pin, LOW);
          LED_STATE = 0;
        } else if (LED_STATE == 0) {
          digitalWrite(RGB_LED_R_Pin, LOW);
          digitalWrite(RGB_LED_G_Pin, LOW);
          digitalWrite(RGB_LED_B_Pin, LOW);
          digitalWrite(Buzzer_Pin, LOW);
          LED_STATE = 1;
        }
      }
    } else if (RSSI_STS <= Far_Proximity_RSSI_Threshold) {
      // Serial.println("Far Proximity");

      unsigned long currentMillis2 = millis();

      if (currentMillis2 - previousMillis3 >= 1000) {  // ON Period
        // save the last time you blinked the LED
        previousMillis3 = currentMillis2;
        if (LED_STATE == 1) {
          digitalWrite(RGB_LED_R_Pin, LOW);
          digitalWrite(RGB_LED_G_Pin, HIGH);
          digitalWrite(RGB_LED_B_Pin, LOW);
          digitalWrite(Buzzer_Pin, LOW);
          LED_STATE = 0;
        } else if (LED_STATE == 0) {
          digitalWrite(RGB_LED_R_Pin, LOW);
          digitalWrite(RGB_LED_G_Pin, LOW);
          digitalWrite(RGB_LED_B_Pin, LOW);
          digitalWrite(Buzzer_Pin, LOW);
          LED_STATE = 1;
        }
      }
    }

  } else {
    // Serial.println("NO! Proximity");
    RSSI_STS = -110;
    digitalWrite(RGB_LED_R_Pin, LOW);
    digitalWrite(RGB_LED_G_Pin, LOW);
    digitalWrite(RGB_LED_B_Pin, LOW);
    digitalWrite(Buzzer_Pin, LOW);
  }
}


void Pin_Mode_Configurations() {

  pinMode(Buzzer_Pin, OUTPUT);
  pinMode(RGB_LED_R_Pin, OUTPUT);
  pinMode(RGB_LED_G_Pin, OUTPUT);
  pinMode(RGB_LED_B_Pin, OUTPUT);
}


void BLE_Setup_Stage() {

  BLEDevice::init("ESP32_SDM");

  BLEServer *pServer = BLEDevice::createServer();
  BLEService *pService = pServer->createService(SERVICE_UUID);
  BLECharacteristic *pCharacteristic = pService->createCharacteristic(
    CHARACTERISTIC_UUID,
    BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE);

  pCharacteristic->setValue("Hello World says Neil");
  pService->start();
  // BLEAdvertising *pAdvertising = pServer->getAdvertising();  // this still is working for backward compatibility
  BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
  pAdvertising->addServiceUUID(SERVICE_UUID);
  pAdvertising->setScanResponse(true);
  pAdvertising->setMinPreferred(0x06);  // functions that help with iPhone connections issue
  pAdvertising->setMinPreferred(0x12);
  BLEDevice::startAdvertising();
  Serial.println("Characteristic defined! Now you can read it in your phone!");



  pBLEScan = BLEDevice::getScan();  //create new scan
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
  pBLEScan->setActiveScan(true);  //active scan uses more power, but get results faster
  pBLEScan->setInterval(100);
  pBLEScan->setWindow(99);  // less or equal setInterval value
}

After uploading the same code to both ESP32 Dev Board, we are now ready to test our ESP32 Social Distancing Monitor.



Code Explanation

We start of the code by including the libraries which enable BLE to operate in ESP32
/////////////////////////////////////////////////////// LIBRARIES ////////////////////////////////////////////////////////////////

#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEScan.h>
#include <BLEAdvertisedDevice.h>
#include <BLEServer.h>

In this section , we will calibrate our BLE RSSI Signal with respective to the distances thresholds which will trigger our four different scenarios. 

Kindly note different ESP32 Dev Models can have different results. You might need to calibrate the distances here for best results with your respective setup. Some ESP32 Dev Modules comes with external antennas which might have different ranges compared to those with inbuilt antennas.

/////////////////////////////////////////////////////// CONFIGURATIONS ////////////////////////////////////////////////////////////////

int Very_Close_Proximity_RSSI_Threshold = -70;
int Moderate_Proximity_RSSI_Threshold = -80;
int Far_Proximity_RSSI_Threshold = -85;

Note: RSSI Signal strength ranges from -20 dBm which is the best signal strength all the way to - 110 dBm which is near to no signal. Use this respective range to calibrate the controller to correctly respond on distance thresholds.



In this section , we are defining the pin connections to our RGB LED and Buzzer, respective to the connections made in our wiring schematic diagram.
/////////////////////////////////////////////////////// CONNECTIONS ////////////////////////////////////////////////////////////////

int RGB_LED_R_Pin = 25;  //4
int RGB_LED_G_Pin = 26;  //4
int RGB_LED_B_Pin = 27;  //4
int Buzzer_Pin = 5;

We create the instances of BLE Client "BLEClient *pClient;" and BLE Scan "BLEScan *pBLEScan;" , after which we define our BLE Device Name as  "String knownNames[] = { ":  :  :  :  :  ", "ESP32_SDM" };" , where "ESP32_SDM"  is the BLE Device name which this Controller needs to detect during BLE Scans. (Note : Needs to be same for both Devices in order to detect each other).

In this Project, since we are only detecting the BLE Device Name, thats why we will not require to use BLE Service or Characteristics to identify the other BLE Device. 

We will only define our Service & Characteristic and not use it in our Logical Operations Section:
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"

/////////////////////////////////////////////////////// BLE VARIABLES ////////////////////////////////////////////////////////////////

BLEClient *pClient;
bool deviceFound = false;

String knownAddresses[] = { ":  :  :  :  :  ", " :  :  :  :  : " };

String knownNames[] = { ":  :  :  :  :  ", "ESP32_SDM" };

static BLEAddress *pServerAddress;

std::string pServerName;

#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"

Next in Setup Stage , we will initialize Serial monitor at a baud rate of 115200.  We will configure the pinModes in Pin_Mode_Configurations();  and we will initialize BLE using our   BLE_Setup_Stage();                

void setup() {
  Serial.begin(115200);
  Serial.println("Scanning...");

  Pin_Mode_Configurations();
  BLE_Setup_Stage();
}

We will configure PinMode of RGB LEDs and Buzzers Connections as Outputs as defined below
void Pin_Mode_Configurations() {

  pinMode(Buzzer_Pin, OUTPUT);
  pinMode(RGB_LED_R_Pin, OUTPUT);
  pinMode(RGB_LED_G_Pin, OUTPUT);
  pinMode(RGB_LED_B_Pin, OUTPUT);
}

For BLE Setup Stage we initialize our BLE Device with its name as "ESP32_SDM" using this command;   BLEDevice::init("ESP32_SDM");   (Note : Needs to be same for both Devices in order to detect each other).

In this stage, we will configure our BLE Server with the Service UUID and Characteristics ID which we defined at the top and with the respective Read and Write parameters. Since in this Project we are not utilizing characteristics thus we will not go into too much detail on this.

After all the BLE Parameters are set then  BLEDevice::startAdvertising();  will commence the |BLE Server, where we will scan for our other BLE Devices using pBLEScan = BLEDevice::getScan();  //create new scan  where we can see the details of the devices from the callback function at pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
 
void BLE_Setup_Stage() {

  BLEDevice::init("ESP32_SDM");

  BLEServer *pServer = BLEDevice::createServer();
  BLEService *pService = pServer->createService(SERVICE_UUID);
  BLECharacteristic *pCharacteristic = pService->createCharacteristic(
    CHARACTERISTIC_UUID,
    BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE);

  pCharacteristic->setValue("Hello World says Neil");
  pService->start();
  // BLEAdvertising *pAdvertising = pServer->getAdvertising();  // this still is working for backward compatibility
  BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
  pAdvertising->addServiceUUID(SERVICE_UUID);
  pAdvertising->setScanResponse(true);
  pAdvertising->setMinPreferred(0x06);  // functions that help with iPhone connections issue
  pAdvertising->setMinPreferred(0x12);
  BLEDevice::startAdvertising();
  Serial.println("Characteristic defined! Now you can read it in your phone!");



  pBLEScan = BLEDevice::getScan();  //create new scan
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
  pBLEScan->setActiveScan(true);  //active scan uses more power, but get results faster
  pBLEScan->setInterval(100);
  pBLEScan->setWindow(99);  // less or equal setInterval value
}

Within the void loop()   we are now scanning BLE Signals after every two seconds, and listing down all the available BLE Devices. void onResult(BLEAdvertisedDevice advertisedDevice)  within the BLE Callback function compares the Name of the BLE Device with the one we have saved. If the BLE Device name is "ESP32_SDM" then our bool deviceFound   will become true enabling the RGB and Buzzer operation with respect to the RSSI Signal Strength.
unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= 2000) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;

    BLEScanResults foundDevices = pBLEScan->start(scanTime, false);
    Serial.print("Devices Nos: ");
    Serial.println(foundDevices.getCount());
    Serial.println("Scan done!");
    pBLEScan->clearResults();  // delete results fromBLEScan buffer to release memory
  }


We are also obtaining RSSI Signal strength via the same BLE Callback function via  RSSI_STS = (advertisedDevice.getRSSI()); 

class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks {
  /**
         Called for each advertising BLE server.
    */
  void onResult(BLEAdvertisedDevice advertisedDevice) {
    Serial.printf("Advertised Device: %s \n", advertisedDevice.toString().c_str());
    pServerAddress = new BLEAddress(advertisedDevice.getAddress());
    pServerName = advertisedDevice.getName();

    Serial.print("Name =  ");
    Serial.println(pServerName.c_str());

    bool known = false;
    bool known2 = false;
    for (int i = 0; i < (sizeof(knownAddresses) / sizeof(knownAddresses[0])); i++) {
      if (strcmp(pServerAddress->toString().c_str(), knownAddresses[i].c_str()) == 0) known = true;
    }

    for (int i = 0; i < (sizeof(knownNames) / sizeof(knownNames[0])); i++) {
      if (strcmp(pServerName.c_str(), knownNames[i].c_str()) == 0) known2 = true;
    }
    Serial.print("known2: ");
    Serial.println(known2);

    if (known2) {
      Serial.print("Device found: ");
      Serial.println(advertisedDevice.getRSSI());
      RSSI_STS = (advertisedDevice.getRSSI());
      if (advertisedDevice.getRSSI() > -150) deviceFound = true;
      else deviceFound = false;
      Serial.println(pServerAddress->toString().c_str());
      advertisedDevice.getScan()->stop();
    } else {
      deviceFound = false;
    }
    /******** This releases the memory when we're done. ********/
    delete pServerAddress;
  }
};

Thus using int RSSI_STS  and  bool deviceFound  , we can now create a simple logic to operate our RGB LEDs and Buzzer using the RSSI Thresholds which we configured above at the start of the code.
if (deviceFound) {
    if (RSSI_STS > Very_Close_Proximity_RSSI_Threshold) {
      // Serial.println("Very Close Proximity");

      unsigned long currentMillis2 = millis();
      if (currentMillis2 - previousMillis3 >= 150) {  // ON Period
        // save the last time you blinked the LED
        previousMillis3 = currentMillis2;

        if (LED_STATE == 1) {

          digitalWrite(RGB_LED_R_Pin, HIGH);
          digitalWrite(RGB_LED_G_Pin, LOW);
          digitalWrite(RGB_LED_B_Pin, LOW);
          digitalWrite(Buzzer_Pin, HIGH);
          LED_STATE = 0;
        } else if (LED_STATE == 0) {
          digitalWrite(RGB_LED_R_Pin, LOW);
          digitalWrite(RGB_LED_G_Pin, LOW);
          digitalWrite(RGB_LED_B_Pin, LOW);
          digitalWrite(Buzzer_Pin, LOW);
          LED_STATE = 1;
        }
      }


    } else if ((RSSI_STS <= Very_Close_Proximity_RSSI_Threshold && RSSI_STS > Moderate_Proximity_RSSI_Threshold)) {
      // Serial.println("Moderate Proximity");
      unsigned long currentMillis2 = millis();

      if (currentMillis2 - previousMillis3 >= 500) {  // ON Period
        // save the last time you blinked the LED
        previousMillis3 = currentMillis2;
        if (LED_STATE == 1) {
          digitalWrite(RGB_LED_R_Pin, HIGH);
          digitalWrite(RGB_LED_G_Pin, HIGH);
          digitalWrite(RGB_LED_B_Pin, LOW);
          digitalWrite(Buzzer_Pin, LOW);
          LED_STATE = 0;
        } else if (LED_STATE == 0) {
          digitalWrite(RGB_LED_R_Pin, LOW);
          digitalWrite(RGB_LED_G_Pin, LOW);
          digitalWrite(RGB_LED_B_Pin, LOW);
          digitalWrite(Buzzer_Pin, LOW);
          LED_STATE = 1;
        }
      }
    } else if (RSSI_STS <= Far_Proximity_RSSI_Threshold) {
      // Serial.println("Far Proximity");

      unsigned long currentMillis2 = millis();

      if (currentMillis2 - previousMillis3 >= 1000) {  // ON Period
        // save the last time you blinked the LED
        previousMillis3 = currentMillis2;
        if (LED_STATE == 1) {
          digitalWrite(RGB_LED_R_Pin, LOW);
          digitalWrite(RGB_LED_G_Pin, HIGH);
          digitalWrite(RGB_LED_B_Pin, LOW);
          digitalWrite(Buzzer_Pin, LOW);
          LED_STATE = 0;
        } else if (LED_STATE == 0) {
          digitalWrite(RGB_LED_R_Pin, LOW);
          digitalWrite(RGB_LED_G_Pin, LOW);
          digitalWrite(RGB_LED_B_Pin, LOW);
          digitalWrite(Buzzer_Pin, LOW);
          LED_STATE = 1;
        }
      }
    }

  } else {
    // Serial.println("NO! Proximity");
    RSSI_STS = -110;
    digitalWrite(RGB_LED_R_Pin, LOW);
    digitalWrite(RGB_LED_G_Pin, LOW);
    digitalWrite(RGB_LED_B_Pin, LOW);
    digitalWrite(Buzzer_Pin, LOW);
  }

Uploading the Code

Now we will upload our main Code into both of our ESP32 Dev board. Plug in both of your ESP32 one at a time via the USB Port and upload the Main Code as below:


Serial Monitor Results & Project Workings

After uploading our main code to both ESP32, Keep one ESP32 plugged into your computer and turn the other ESP32 Off to simulate our SCENARIO 1 : No other Device avaliable. 

Click on the icon to the most upper left of the Arduino IDE Window to open the Serial Monitor Window. After Serial Monitor pops up, expand its window to clearly view all the information and select the baud rate of 115200.

Once done, you should be seeing data coming in from the controller unto your serial monitor screen, let's analyze what it says.

on the 21:13:46.230 Mark, the ESP32 setups its BLE server characteristics and starts scanning for BLE devices within its area.

If you have any smart LCD TV or Laptop, then you might be seeing BLE devices in the scan results from 21:13:48. 656


Since we are scanning for BLE Names of "ESP32_SDM" and its not visible as we are keeping the other ESP32 Off for this experiment, our  deviceFound STS  remains off. Thus causing the ESP32 to not turn on its Buzzer or RGB LED as shown below:



Now we will simulate SCENARIO 2 : Device is available but is far away.
For this keep your current ESP32 plugged into the computer and power up your other ESP32 and place it further than 1.5 Meters or move it far until the RGB LED green Light starts flashing. If you are not getting any Flashing Green LED then check the RSSI value you are seeing on the serial monitor and update your configurations section shown below at the top of the main code:

int Very_Close_Proximity_RSSI_Threshold = -70;
int Moderate_Proximity_RSSI_Threshold = -80;
int Far_Proximity_RSSI_Threshold = -85; 



Now if we view the serial monitor then you will see our  "ESP32_SDM"  show up in the BLE Scans results and since its RSSI value falls  in between Far_Proximity_RSSI_Threshold   and Moderate_Proximity_RSSI_Threshold  , thus the code will make the Green RGB Flash.


Now we will simulate SCENARIO 3 : Device is available but is far nearby.
For this keep your current ESP32 plugged into the computer and power up your other ESP32 and place it near to approximately 1.5 Meters or move it until the RGB LED yellow Light starts flashing. If you are not getting any Flashing Green Yellow then check the RSSI value you are seeing on the serial monitor and update your configurations section at the top of the main code


Now we will simulate SCENARIO 4 : Device is available but is very near.
For this keep your current ESP32 plugged into the computer and power up your other ESP32 and place it lesser than 1.5 Meters or move it until the RGB LED red Light starts flashing & Buzzer sounds . If you are not getting any Flashing Green RED then check the RSSI value you are seeing on the serial monitor and update your configurations section at the top of the main code



Now if we view the serial monitor then you will see our  "ESP32_SDM"  show up in the BLE Scans results and since its RSSI value falls lesser than Very_Close_Proximity_RSSI_Threshold  , thus the code will make the RGB LED Flash Red and Buzzer will sound accordingly too.


Conclusion

With this project we demonstrated how to utilize a ESP32 BLE protocol and made it function as a wearable BLE Tag for deploying effective social distancing measures to better manage and combat the spread of infectious diseases such as the COVID-19 and its other variants too.

Hopefully we will stop COVID 19 forever and always remain vigilant and protected against future infectious diseases as well.