ESP 32 Sensor data collection

Hi all,
I am currently working on a project that require me to collect sensor data from many stand alone sensor nodes using BLE. The data collection will be through phone and UAV.
I have successfully configured two ESP32 to take in temperature and humidity sensor data and i am able to get the data using nRF connect application on my phone.

On the UAV, my plan is to configure an esp32 that can be attached to the UAV such that as it gets closer to the stand alone sensor nodes, The sensor data gets collected and displayed (Serial Monitor) by the attachable esp32. I would appreciate support on how to go about the code.

PS: BLE is required all through

Thank you.

UAV as in Unmanned Aerial Vehicle - a drone ? how do you attach the Serial monitor then - long USB cable?

basically the code is to setActiveScan(true); in the setup and in the loop you use a BLEScan instance and just test if you see something

  BLEScanResults foundDevices = pointerToBLEScan->start(5, false);
  for (int i = 0; i < foundDevices.getCount(); i++) {
    BLEAdvertisedDevice device = foundDevices.getDevice(i);
    // now typical BLE code from all the examples
    ... // check if it's your device and connect to the device
    ... // obtain a reference to the remote service 
    ... // and read sensor data from the characteristic
    ... // and disconnect from the BLE device
  }
  ... // delete results fromBLEScan buffer to release memory
}

of course you need to remember if you already extracted the data from the given device so that you don't do it twice.

Thank you for the response

Yes drone.
I will configure the esp32 before attaching it to the drone. This means i am fine with connecting the esp32 to the serial monitor.

The project is basically to see that a central esp32 can collect data from multiple sensor nodes as it gets closer.

At present, i can read sensor data on my phone (Using nRF connect) after successfully configuring two standalone esp32 sensor nodes with the code below:

#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
#include <DHT.h>

#define DHTPIN 27   // DHT11 sensor pin
#define DHTTYPE DHT11  // DHT11 sensor type

DHT dht(DHTPIN, DHTTYPE);

BLEServer* pServer = NULL;
BLECharacteristic* pCharacteristic = NULL;

const char* serviceUUID = "4fafc201-1fb5-459e-8fcc-c5c9c331914b";
const char* charUUID = "beb5483e-36e1-4688-b7f5-ea07361b26a8";

float temperature = 0.0;
float humidity = 0.0;

class MyServerCallbacks : public BLEServerCallbacks {
  void onConnect(BLEServer* pServer) {
    // Do something when a device connects
  }

  void onDisconnect(BLEServer* pServer) {
    // Do something when a device disconnects
  }
};

void setup() {
  Serial.begin(115200);
  dht.begin();

  BLEDevice::init("DHT11_Sensor_1");

  BLEServer *pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());

  BLEService *pService = pServer->createService(BLEUUID(serviceUUID));

  pCharacteristic = pService->createCharacteristic(
                      BLEUUID(charUUID),
                      BLECharacteristic::PROPERTY_READ |
                      BLECharacteristic::PROPERTY_NOTIFY
                    );

  pCharacteristic->addDescriptor(new BLE2902());

  pService->start();

  BLEAdvertising *pAdvertising = pServer->getAdvertising();
  pAdvertising->start();

  Serial.println("DHT11 BLE Sensor Node is running!");
}

void loop() {
  delay(10000);  // Update every 10 seconds

  temperature = dht.readTemperature();
  humidity = dht.readHumidity();

  Serial.print("Temperature: ");
  Serial.print(temperature);
  Serial.print(" °C, Humidity: ");
  Serial.print(humidity);
  Serial.println(" %");

  // Convert the data to a string
  String sensorData = String(temperature, 2) + "," + String(humidity, 2);

  // Update the characteristic with the sensor data
  pCharacteristic->setValue(sensorData.c_str());
  pCharacteristic->notify();
}

but the present challenge is that, i would like to configure the third esp32 as the data collector using BLE, then display the sensor data on its serial monitor.

I would appreciate if you can assist with a complete code template i can work with.Use code tags to format code for the forum

Can you do a favour to everyone using the forum (including yourself if you want help) and read How to get the best out of this forum and modify your post accordingly

➜ include code tags as it's hard to read as it stands


through WiFi you mean ?

if WiFi is available when you hover the sensors' ESP32, why don't you use WiFi to report the sensors' status to the base directly?

Thank you, I have included the code tag to my previous response.

The the esp32 will be connected to the serial monitor through USB cable (The usual port).

Based on the project, the only communicating protocol acceptable is Bluetooth (BLE).

OK I guess I did not get your setup then

I though you had a few ESP32 with sensors somewhere out there, then an ESP32 attached to a drone would go hover on top of those sensors and extract the data

is there another ESP32 connected to the Serial monitor somewhere in the picture?

Oh.

Yes, i have two separate ESP32 with sensors (DHT 11) configured to get values.

There is also a third ESP32 that is expected to be configured to extract data from the sensor nodes through BLE as it gets closer to the nodes. So, the logic is to do some sort of prototyping to see if the third ESP32 will be able to get those sensor data from the nodes and most importantly display the real time value on it's serial monitor (Using the IDE serial monitor after selecting the right port).

If that works, then i can scale the number of nodes with a corresponding effect on the third ESP32 before attaching it to the drone.

sorry, how can the third ESP32 be able to get close to the sensors in the field if it Is attached to an USB cable?
are you going to walk to the sensors with the ESP32 in one hand and your laptop in the other hand. to simulate the drone? and the printing to Serial is just to ensure all is OK and in the final version there will be no output?

I must appreciate your concern. Thank you

Yes, Exactly.

Walk around with my laptop while having the third ESP32 attached.

But the other two sensor nodes will be powered with a power bank separately and placed at different region on the field while i walk with my laptop to those nodes so i can see the flow of data transmission (basically, the sensor data)

If that works fine... Then i can proceed to implement the final packaging.

so it's pretty much what I described initially. Most likely any demo code using the BLEScan capabilities will do what you want

see ESP32 Bluetooth Low Energy (BLE) on Arduino IDE | Random Nerd Tutorials

Good Contribution,

I followed the steps stated. Yes, I am able to see various sensor nodes available (Including their various MAC Addresses) but the client is still unable to print the sensor data on the serial monitor.

This is exactly the issue. I want the client to act in capacity of collecting sensor data from the sensor nodes as it gets identified and further print the values on the serial monitor.

If you followed the tutorial you should have a sensor code that is reading some data and making it available through BLE advertising and you should have a scanning code looking for relevant sensors and you should have code extracting the value for a given characteristic

Then what’s the trouble printing that value ?

Post both codes

Okay, Here are my codes

Server code:

#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
#include <DHT.h>

#define DHTPIN 27   // DHT11 sensor pin
#define DHTTYPE DHT11  // DHT11 sensor type

DHT dht(DHTPIN, DHTTYPE);
 
BLEServer* pServer = NULL;
BLECharacteristic* pCharacteristic = NULL;

const char* serviceUUID = "4fafc201-1fb5-459e-8fcc-c5c9c331914b";
const char* charUUID = "beb5483e-36e1-4688-b7f5-ea07361b26a8";

float temperature = 0.0;
float humidity = 0.0;

class MyServerCallbacks : public BLEServerCallbacks {
  void onConnect(BLEServer* pServer) {
    // Do something when a device connects
  }

  void onDisconnect(BLEServer* pServer) {
    // Do something when a device disconnects
  }
};

void setup() {
  Serial.begin(115200);
  dht.begin();

  BLEDevice::init("DHT11_Sensor_1");

  BLEServer *pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());

  BLEService *pService = pServer->createService(BLEUUID(serviceUUID));

  pCharacteristic = pService->createCharacteristic(
                      BLEUUID(charUUID),
                      BLECharacteristic::PROPERTY_READ |
                      BLECharacteristic::PROPERTY_NOTIFY
                    );

  pCharacteristic->addDescriptor(new BLE2902());

  pService->start();

  BLEAdvertising *pAdvertising = pServer->getAdvertising();
  pAdvertising->start();

  Serial.println("DHT11 BLE Sensor Node is running!");
}

void loop() {
  delay(5000);  // Update every 10 seconds

  temperature = dht.readTemperature();
  humidity = dht.readHumidity();

  Serial.print("Temperature: ");
  Serial.print(temperature);
  Serial.print(" °C, Humidity: ");
  Serial.print(humidity);
  Serial.println(" %");

  // Convert the data to a string
  String sensorData = String(temperature, 2) + "," + String(humidity, 2);

  // Update the characteristic with the sensor data
  pCharacteristic->setValue(sensorData.c_str());
  pCharacteristic->notify();
}

Server Response(Serial monitor):

Sever response

Client code:

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

int scanTime = 5;
BLEScan* pBLEScan;

const char* serviceUUID = "4fafc201-1fb5-459e-8fcc-c5c9c331914b";
const char* charUUID = "beb5483e-36e1-4688-b7f5-ea07361b26a8";

BLEClient* pClient = NULL;
BLECharacteristic* pRemoteCharacteristic = NULL;

class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks {
  void onResult(BLEAdvertisedDevice advertisedDevice) {
    Serial.printf("Advertised Device: %s \n", advertisedDevice.toString().c_str());
    if (advertisedDevice.haveServiceUUID() && advertisedDevice.isAdvertisingService(BLEUUID(serviceUUID))) {
      BLEDevice::getScan()->stop();
      pClient = BLEDevice::createClient();
      pClient->connect(&advertisedDevice);
      BLERemoteService* pRemoteService = pClient->getService(BLEUUID(serviceUUID));
     
    }
  }
};

void setup() {
  Serial.begin(115200);
  Serial.println("Scanning for DHT11 Sensor Node...");
  BLEDevice::init("ESP32_Client");
  pBLEScan = BLEDevice::getScan();
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
  pBLEScan->setActiveScan(true);
  pBLEScan->start(5, false);
  

  
}

void loop() {

      // put your main code here, to run repeatedly:
  BLEScanResults foundDevices = pBLEScan->start(scanTime, false);
  Serial.print("Devices found: ");
  Serial.println(foundDevices.getCount());
  Serial.println("Scan done!");
  pBLEScan->clearResults();   // delete results fromBLEScan buffer to release memory
  delay(5000); // Adjust the delay as needed
  
  if (pClient && pClient->isConnected() && pRemoteCharacteristic) {
    std::string value = pRemoteCharacteristic->getValue();
    if (value.length() > 0) {
      Serial.println("Received sensor data: " + String(value.c_str()));
    }
  }
}

Client Response(Serial monitor):

The client saw the server but didn't display the sensor data

I am not sure of what modification i need to do on the client's code for proper sensor data extraction.

Yes, the client can see the sensor node but i would like to get the sensor data through the client and if possible using the same client to get sensor data from multiple sensor nodes.
I also understand that each sensor nodes have unique MAC Address but i am not sure if this will be helpful in making the communication between the client and each sensor nodes unique.

Once you have a match you need to ask for the expected characteristics

Study this other tutorial

Excellent !

Worked.

Thank you for the support @J-M-L ...

On a conclusive note: If i would like to take sensor data from multiple sensor nodes using a single BLE client, can i configure each sensor node with the same code then distance them apart such that the BLE client can't get to see two nodes broadcasting at the same time. will this work ?

or is there a better option you would recommend.

Thank you once again.

That’s a possibility but it would make more sense to just scan and get an ID from the sensor so that you read and store the values in an array and when your drone has finished its tour and comes home it can dump the data.

This will give you also flexibility and no worries about placement of the sensors

Oh ... I see

How best can i go about the ID scan. I guess that will make the communication between the client and sensor nodes unique and distinct. I also presume it will eliminate any form of interference in data transfer even when the sensor nodes are together.

But i am not sure on how to go about it.

Basically something like this. Study arrays and state machine

  • You run a scan
  • For each sensor you see
    • You get its ID
    • if you haven’t seen that ID yet in this run (since previous data dump)
      • you collect and store the data from that sensor
  • if the list is complete or battery running low
    - you go home to dump the data

Thank you for the insight.

I will check through and revert on my progress but i wouldn't mind if there are resources you could recommend to bootstrap my research.