feat: add ble server-client code
This commit is contained in:
parent
7e2db36a8c
commit
01a54cdc63
173
ble_client/ble_client.ino
Normal file
173
ble_client/ble_client.ino
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
/*********
|
||||||
|
Rui Santos
|
||||||
|
Complete instructions at https://RandomNerdTutorials.com/esp32-ble-server-client/
|
||||||
|
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.
|
||||||
|
*********/
|
||||||
|
|
||||||
|
#include "BLEDevice.h"
|
||||||
|
|
||||||
|
//Default Temperature is in Celsius
|
||||||
|
//Comment the next line for Temperature in Fahrenheit
|
||||||
|
#define temperatureCelsius
|
||||||
|
|
||||||
|
//BLE Server name (the other ESP32 name running the server sketch)
|
||||||
|
#define bleServerName "ESP32"
|
||||||
|
#define bleServerAddress "64:e8:33:da:a2:b6"
|
||||||
|
|
||||||
|
/* UUID's of the service, characteristic that we want to read*/
|
||||||
|
// BLE Service
|
||||||
|
static BLEUUID bmeServiceUUID("91bad492-b950-4226-aa2b-4ede9fa42f59");
|
||||||
|
|
||||||
|
//Temperature Celsius Characteristic
|
||||||
|
static BLEUUID temperatureCharacteristicUUID("cba1d466-344c-4be3-ab3f-189f80dd7518");
|
||||||
|
|
||||||
|
//Flags stating if should begin connecting and if the connection is up
|
||||||
|
static boolean doConnect = false;
|
||||||
|
static boolean connected = false;
|
||||||
|
|
||||||
|
//Address of the peripheral device. Address will be found during scanning...
|
||||||
|
static BLEAddress *pServerAddress;
|
||||||
|
|
||||||
|
//Characteristicd that we want to read
|
||||||
|
static BLERemoteCharacteristic* temperatureCharacteristic;
|
||||||
|
|
||||||
|
//Activate notify
|
||||||
|
const uint8_t notificationOn[] = {0x1, 0x0};
|
||||||
|
const uint8_t notificationOff[] = {0x0, 0x0};
|
||||||
|
|
||||||
|
//Variables to store temperature and humidity
|
||||||
|
char* temperatureChar;
|
||||||
|
|
||||||
|
//Flags to check whether new temperature and humidity readings are available
|
||||||
|
boolean newTemperature = false;
|
||||||
|
|
||||||
|
//Connect to the BLE Server that has the name, Service, and Characteristics
|
||||||
|
bool connectToServer(BLEAddress pAddress) {
|
||||||
|
BLEClient* pClient = BLEDevice::createClient();
|
||||||
|
|
||||||
|
// Connect to the remove BLE Server.
|
||||||
|
pClient->connect(pAddress);
|
||||||
|
Serial.println(" - Connected to server");
|
||||||
|
|
||||||
|
// Obtain a reference to the service we are after in the remote BLE server.
|
||||||
|
BLERemoteService* pRemoteService = pClient->getService(bmeServiceUUID);
|
||||||
|
if (pRemoteService == nullptr) {
|
||||||
|
Serial.print("Failed to find our service UUID: ");
|
||||||
|
Serial.println(bmeServiceUUID.toString().c_str());
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Obtain a reference to the characteristics in the service of the remote BLE server.
|
||||||
|
temperatureCharacteristic = pRemoteService->getCharacteristic(temperatureCharacteristicUUID);
|
||||||
|
|
||||||
|
if (temperatureCharacteristic == nullptr) {
|
||||||
|
Serial.print("Failed to find our characteristic UUID");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Serial.println(" - Found our characteristics");
|
||||||
|
|
||||||
|
//Assign callback functions for the Characteristics
|
||||||
|
temperatureCharacteristic->registerForNotify(temperatureNotifyCallback);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Callback function that gets called, when another device's advertisement has been received
|
||||||
|
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
|
||||||
|
void onResult(BLEAdvertisedDevice advertisedDevice) {
|
||||||
|
Serial.print("Found Device: ");
|
||||||
|
Serial.println(advertisedDevice.getAddress().toString().c_str());
|
||||||
|
if (advertisedDevice.getAddress().toString() == bleServerAddress) { //Check if the name of the advertiser matches
|
||||||
|
advertisedDevice.getScan()->stop(); //Scan can be stopped, we found what we are looking for
|
||||||
|
pServerAddress = new BLEAddress(advertisedDevice.getAddress()); //Address of advertiser is the one we need
|
||||||
|
doConnect = true; //Set indicator, stating that we are ready to connect
|
||||||
|
Serial.println("Device found. Connecting!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int last_update = 0;
|
||||||
|
|
||||||
|
void deserialize_int16_t(uint8_t* buffer, int16_t* values, size_t count) {
|
||||||
|
for (size_t i = 0; i < count; ++i) {
|
||||||
|
values[i] = (int16_t)((buffer[i * 2 + 1] << 8) | buffer[i * 2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//When the BLE Server sends a new temperature reading with the notify property
|
||||||
|
static void temperatureNotifyCallback(BLERemoteCharacteristic* pBLERemoteCharacteristic,
|
||||||
|
uint8_t* pData, size_t length, bool isNotify) {
|
||||||
|
// Check if the length of the received data is as expected
|
||||||
|
if (length % 2 != 0) {
|
||||||
|
// Handle error: The length should be even for 2-byte integers
|
||||||
|
Serial.println("Error: Invalid data length");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assuming you know the number of int16_t values in the received data
|
||||||
|
size_t count = length / 2;
|
||||||
|
int16_t receivedValues[count];
|
||||||
|
|
||||||
|
// Deserialize the received data
|
||||||
|
deserialize_int16_t(pData, receivedValues, count);
|
||||||
|
|
||||||
|
// Process the received values as needed
|
||||||
|
for (size_t i = 0; i < count; ++i) {
|
||||||
|
Serial.print(receivedValues[i]);
|
||||||
|
Serial.print(" ");
|
||||||
|
}
|
||||||
|
Serial.println();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
|
||||||
|
//Start serial communication
|
||||||
|
Serial.begin(115200);
|
||||||
|
Serial.println("Starting Arduino BLE Client application...");
|
||||||
|
|
||||||
|
//Init BLE device
|
||||||
|
BLEDevice::init("");
|
||||||
|
|
||||||
|
// Retrieve a Scanner and set the callback we want to use to be informed when we
|
||||||
|
// have detected a new device. Specify that we want active scanning and start the
|
||||||
|
// scan to run for 30 seconds.
|
||||||
|
BLEScan* pBLEScan = BLEDevice::getScan();
|
||||||
|
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
|
||||||
|
pBLEScan->setActiveScan(true);
|
||||||
|
pBLEScan->start(30);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
// If the flag "doConnect" is true then we have scanned for and found the desired
|
||||||
|
// BLE Server with which we wish to connect. Now we connect to it. Once we are
|
||||||
|
// connected we set the connected flag to be true.
|
||||||
|
if (doConnect == true) {
|
||||||
|
if (connectToServer(*pServerAddress)) {
|
||||||
|
Serial.println("We are now connected to the BLE Server.");
|
||||||
|
//Activate the Notify property of each Characteristic
|
||||||
|
temperatureCharacteristic->getDescriptor(BLEUUID((uint16_t)0x2902))->writeValue((uint8_t*)notificationOn, 2, true);
|
||||||
|
connected = true;
|
||||||
|
} else {
|
||||||
|
Serial.println("We have failed to connect to the server; Restart your device to scan for nearby BLE server again.");
|
||||||
|
}
|
||||||
|
doConnect = false;
|
||||||
|
}
|
||||||
|
//if new temperature readings are available, print in the OLED
|
||||||
|
if (newTemperature){
|
||||||
|
newTemperature = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for a reset command from serial
|
||||||
|
if (Serial.available() > 0) {
|
||||||
|
char command = Serial.read();
|
||||||
|
|
||||||
|
// Check if the received command is 'R'
|
||||||
|
if (command == 'R' || command == 'r') {
|
||||||
|
Serial.println("Resetting...");
|
||||||
|
delay(1000); // Optional delay for visibility in the Serial Monitor
|
||||||
|
ESP.restart(); // This function resets the ESP32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delay(1000); // Delay a second between loops.
|
||||||
|
}
|
138
ble_server/ble_server.ino
Normal file
138
ble_server/ble_server.ino
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
#include <BLEDevice.h>
|
||||||
|
#include <BLEServer.h>
|
||||||
|
#include <BLEUtils.h>
|
||||||
|
#include <BLE2902.h>
|
||||||
|
#include <Wire.h>
|
||||||
|
#include "MPU6050.h"
|
||||||
|
|
||||||
|
//BLE server name
|
||||||
|
#define bleServerName "ESP32"
|
||||||
|
|
||||||
|
int16_t ax, ay, az;
|
||||||
|
int16_t gx, gy, gz;
|
||||||
|
|
||||||
|
bool deviceConnected = false;
|
||||||
|
|
||||||
|
// See the following for generating UUIDs:
|
||||||
|
// https://www.uuidgenerator.net/
|
||||||
|
#define SERVICE_UUID "91bad492-b950-4226-aa2b-4ede9fa42f59"
|
||||||
|
|
||||||
|
MPU6050 accelgyro;
|
||||||
|
BLEServer *pServer;
|
||||||
|
BLECharacteristic bmeTemperatureCelsiusCharacteristics("cba1d466-344c-4be3-ab3f-189f80dd7518", BLECharacteristic::PROPERTY_NOTIFY);
|
||||||
|
BLEDescriptor bmeTemperatureCelsiusDescriptor(BLEUUID((uint16_t)0x2902));
|
||||||
|
|
||||||
|
//Setup callbacks onConnect and onDisconnect
|
||||||
|
class MyServerCallbacks: public BLEServerCallbacks {
|
||||||
|
void onConnect(BLEServer* pServer) {
|
||||||
|
deviceConnected = true;
|
||||||
|
Serial.println("Device Connected");
|
||||||
|
};
|
||||||
|
void onDisconnect(BLEServer* pServer) {
|
||||||
|
deviceConnected = false;
|
||||||
|
Serial.println("Device Disconnected");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
// Start serial communication
|
||||||
|
Serial.begin(115200);
|
||||||
|
|
||||||
|
// setup software i2c
|
||||||
|
Wire.begin();
|
||||||
|
|
||||||
|
// initialize device
|
||||||
|
Serial.println("Initializing I2C devices...");
|
||||||
|
accelgyro.initialize();
|
||||||
|
|
||||||
|
// verify connection
|
||||||
|
Serial.println("Testing device connections...");
|
||||||
|
Serial.println(accelgyro.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");
|
||||||
|
|
||||||
|
// Create the BLE Device
|
||||||
|
BLEDevice::init(bleServerName);
|
||||||
|
|
||||||
|
// Create the BLE Server
|
||||||
|
pServer = BLEDevice::createServer();
|
||||||
|
pServer->setCallbacks(new MyServerCallbacks());
|
||||||
|
|
||||||
|
// Create the BLE Service
|
||||||
|
BLEService *bmeService = pServer->createService(SERVICE_UUID);
|
||||||
|
|
||||||
|
// Create BLE Characteristics and Create a BLE Descriptor
|
||||||
|
bmeService->addCharacteristic(&bmeTemperatureCelsiusCharacteristics);
|
||||||
|
bmeTemperatureCelsiusDescriptor.setValue("BME temperature Celsius");
|
||||||
|
bmeTemperatureCelsiusCharacteristics.addDescriptor(&bmeTemperatureCelsiusDescriptor);
|
||||||
|
|
||||||
|
// Start the service
|
||||||
|
bmeService->start();
|
||||||
|
|
||||||
|
// Start advertising
|
||||||
|
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
|
||||||
|
pAdvertising->addServiceUUID(SERVICE_UUID);
|
||||||
|
pServer->getAdvertising()->start();
|
||||||
|
Serial.println("Waiting a client connection to notify...");
|
||||||
|
}
|
||||||
|
|
||||||
|
int idx = 0;
|
||||||
|
|
||||||
|
void serialize_int16_t(uint8_t* buffer, int16_t* values, size_t count) {
|
||||||
|
for (size_t i = 0; i < count; ++i) {
|
||||||
|
buffer[i * 2] = (uint8_t)(values[i] & 0xFF);
|
||||||
|
buffer[i * 2 + 1] = (uint8_t)((values[i] >> 8) & 0xFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
|
||||||
|
idx++;
|
||||||
|
|
||||||
|
if (deviceConnected) {
|
||||||
|
|
||||||
|
// read raw accel/gyro measurements from device
|
||||||
|
accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
|
||||||
|
|
||||||
|
int16_t values[] = {ax, ay, az, gx, gy, gz};
|
||||||
|
size_t count = sizeof(values) / sizeof(values[0]);
|
||||||
|
|
||||||
|
// Serialize
|
||||||
|
uint8_t serializedBuffer[count * 2];
|
||||||
|
serialize_int16_t(serializedBuffer, values, count);
|
||||||
|
|
||||||
|
// Set characteristic value and notify connected client
|
||||||
|
bmeTemperatureCelsiusCharacteristics.setValue(serializedBuffer, count * 2);
|
||||||
|
bmeTemperatureCelsiusCharacteristics.notify();
|
||||||
|
if (idx % 20 == 0 && false) {
|
||||||
|
// display tab-separated accel/gyro x/y/z values
|
||||||
|
Serial.print("a/g:\t");
|
||||||
|
Serial.print(ax);
|
||||||
|
Serial.print("\t");
|
||||||
|
Serial.print(ay);
|
||||||
|
Serial.print("\t");
|
||||||
|
Serial.print(az);
|
||||||
|
Serial.print("\t");
|
||||||
|
Serial.print(gx);
|
||||||
|
Serial.print("\t");
|
||||||
|
Serial.print(gy);
|
||||||
|
Serial.print("\t");
|
||||||
|
Serial.println(gz);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for a reset command from serial
|
||||||
|
if (Serial.available() > 0) {
|
||||||
|
char command = Serial.read();
|
||||||
|
|
||||||
|
// Check if the received command is 'R'
|
||||||
|
if (command == 'R' || command == 'r') {
|
||||||
|
Serial.println("Resetting...");
|
||||||
|
delay(1000); // Optional delay for visibility in the Serial Monitor
|
||||||
|
ESP.restart(); // This function resets the ESP32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delay(20);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user