2020-08-22 09:56:19 -06:00
/**
* A BLE client example that is rich in capabilities.
* There is a lot new capabilities implemented.
* author unknown
* updated by chegewara
* updated for NimBLE by H2zero
*/
2022-08-26 19:32:01 -06:00
2020-08-22 09:56:19 -06:00
/** NimBLE differences highlighted in comment blocks **/
/*******original********
#include "BLEDevice.h"
***********************/
#include "NimBLEDevice.h"
extern "C" { void app_main ( void );}
2022-10-23 19:16:33 -06:00
2020-08-22 09:56:19 -06:00
// The remote service we wish to connect to.
static BLEUUID serviceUUID ( "4fafc201-1fb5-459e-8fcc-c5c9c331914b" );
// The characteristic of the remote service we are interested in.
static BLEUUID charUUID ( "beb5483e-36e1-4688-b7f5-ea07361b26a8" );
static bool doConnect = false ;
static bool connected = false ;
static bool doScan = false ;
static BLERemoteCharacteristic * pRemoteCharacteristic ;
static BLEAdvertisedDevice * myDevice ;
static void notifyCallback (
BLERemoteCharacteristic * pBLERemoteCharacteristic ,
uint8_t * pData ,
size_t length ,
bool isNotify ) {
printf ( "Notify callback for characteristic %s of data length %d data: %s \n " ,
pBLERemoteCharacteristic -> getUUID (). toString (). c_str (),
length ,
( char * ) pData );
}
/** None of these are required as they will be handled by the library with defaults. **
2022-08-26 19:32:01 -06:00
** Remove as you see fit for your needs */
2020-08-22 09:56:19 -06:00
class MyClientCallback : public BLEClientCallbacks {
void onConnect ( BLEClient * pclient ) {
}
2022-08-26 19:51:19 -06:00
/** onDisconnect now takes a reason parameter to indicate the reason for disconnection
void onDisconnect(BLEClient* pclient) { */
void onDisconnect ( BLEClient * pclient , int reason ) {
2020-08-22 09:56:19 -06:00
connected = false ;
printf ( "onDisconnect" );
}
/***************** New - Security handled here ********************
****** Note: these are the same return values as defaults ********/
2024-06-06 19:36:14 -06:00
void onPassKeyEntry ( const NimBLEConnInfo & connInfo ){
printf ( "Server Passkey Entry \n " );
/** This should prompt the user to enter the passkey displayed
* on the peer device.
*/
NimBLEDevice :: injectPassKey ( connInfo , 123456 );
};
2020-08-22 09:56:19 -06:00
2024-06-06 19:36:14 -06:00
void onConfirmPIN ( const NimBLEConnInfo & connInfo , uint32_t pass_key ){
printf ( "The passkey YES/NO number: %" PRIu32 " \n " , pass_key );
/** Inject false if passkeys don't match. */
NimBLEDevice :: injectConfirmPIN ( connInfo , true );
};
/** Pairing process complete, we can check the results in connInfo */
void onAuthenticationComplete ( const NimBLEConnInfo & connInfo ){
if ( ! connInfo . isEncrypted ()) {
printf ( "Encrypt connection failed - disconnecting \n " );
/** Find the client with the connection handle provided in desc */
NimBLEDevice :: getClientByID ( connInfo . getConnHandle ()) -> disconnect ();
return ;
}
2020-08-22 09:56:19 -06:00
}
/*******************************************************************/
};
bool connectToServer () {
printf ( "Forming a connection to %s \n " , myDevice -> getAddress (). toString (). c_str ());
BLEClient * pClient = BLEDevice :: createClient ();
printf ( " - Created client \n " );
pClient -> setClientCallbacks ( new MyClientCallback ());
// Connect to the remove BLE Server.
pClient -> connect ( myDevice ); // if you pass BLEAdvertisedDevice instead of address, it will be recognized type of peer device address (public or private)
printf ( " - Connected to server \n " );
// Obtain a reference to the service we are after in the remote BLE server.
BLERemoteService * pRemoteService = pClient -> getService ( serviceUUID );
if ( pRemoteService == nullptr ) {
printf ( "Failed to find our service UUID: %s \n " , serviceUUID . toString (). c_str ());
pClient -> disconnect ();
return false ;
}
printf ( " - Found our service \n " );
// Obtain a reference to the characteristic in the service of the remote BLE server.
pRemoteCharacteristic = pRemoteService -> getCharacteristic ( charUUID );
if ( pRemoteCharacteristic == nullptr ) {
printf ( "Failed to find our characteristic UUID: %s \n " , charUUID . toString (). c_str ());
pClient -> disconnect ();
return false ;
}
printf ( " - Found our characteristic \n " );
// Read the value of the characteristic.
if ( pRemoteCharacteristic -> canRead ()) {
std :: string value = pRemoteCharacteristic -> readValue ();
printf ( "The characteristic value was: %s \n " , value . c_str ());
2022-10-23 19:16:33 -06:00
}
/** registerForNotify() has been removed and replaced with subscribe() / unsubscribe().
* Subscribe parameter defaults are: notifications=true, notifyCallback=nullptr, response=true.
* Unsubscribe parameter defaults are: response=true.
2020-08-22 09:56:19 -06:00
*/
if ( pRemoteCharacteristic -> canNotify ()) {
//pRemoteCharacteristic->registerForNotify(notifyCallback);
pRemoteCharacteristic -> subscribe ( true , notifyCallback );
}
connected = true ;
return true ;
}
/**
* Scan for BLE servers and find the first one that advertises the service we are looking for.
*/
class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks {
/**
* Called for each advertising BLE server.
*/
2022-08-26 19:32:01 -06:00
2020-08-22 09:56:19 -06:00
/*** Only a reference to the advertised device is passed now
2022-08-26 19:32:01 -06:00
void onResult(BLEAdvertisedDevice advertisedDevice) { **/
2020-08-22 09:56:19 -06:00
void onResult ( BLEAdvertisedDevice * advertisedDevice ) {
printf ( "BLE Advertised Device found: %s \n " , advertisedDevice -> toString (). c_str ());
// We have found a device, let us now see if it contains the service we are looking for.
/********************************************************************************
if (advertisedDevice.haveServiceUUID() && advertisedDevice.isAdvertisingService(serviceUUID)) {
********************************************************************************/
if ( advertisedDevice -> haveServiceUUID () && advertisedDevice -> isAdvertisingService ( serviceUUID )) {
BLEDevice :: getScan () -> stop ();
/*******************************************************************
myDevice = new BLEAdvertisedDevice(advertisedDevice);
*******************************************************************/
myDevice = advertisedDevice ; /** Just save the reference now, no need to copy the object */
doConnect = true ;
doScan = true ;
} // Found our server
} // onResult
}; // MyAdvertisedDeviceCallbacks
// This is the Arduino main loop function.
void connectTask ( void * parameter ){
for (;;) {
// If the flag "doConnect" is true then we have scanned for and found the desired
2022-10-23 19:16:33 -06:00
// BLE Server with which we wish to connect. Now we connect to it. Once we are
2020-08-22 09:56:19 -06:00
// connected we set the connected flag to be true.
if ( doConnect == true ) {
if ( connectToServer ()) {
printf ( "We are now connected to the BLE Server. \n " );
} else {
printf ( "We have failed to connect to the server; there is nothin more we will do. \n " );
}
doConnect = false ;
}
// If we are connected to a peer BLE Server, update the characteristic each time we are reached
// with the current time since boot.
if ( connected ) {
char buf [ 256 ];
snprintf ( buf , 256 , "Time since boot: %lu" , ( unsigned long )( esp_timer_get_time () / 1000000ULL ));
printf ( "Setting new characteristic value to %s \n " , buf );
2022-10-23 19:16:33 -06:00
2020-08-22 09:56:19 -06:00
// Set the characteristic's value to be the array of bytes that is actually a string.
/*** Note: write value now returns true if successful, false otherwise - try again or disconnect ***/
pRemoteCharacteristic -> writeValue (( uint8_t * ) buf , strlen ( buf ), false );
} else if ( doScan ){
2022-08-26 19:32:01 -06:00
BLEDevice :: getScan () -> start ( 0 ); // this is just eample to start scan after disconnect, most likely there is better way to do it
2020-08-22 09:56:19 -06:00
}
2022-10-23 19:16:33 -06:00
2020-08-22 09:56:19 -06:00
vTaskDelay ( 1000 / portTICK_PERIOD_MS ); // Delay a second between loops.
}
2022-10-23 19:16:33 -06:00
2020-08-22 09:56:19 -06:00
vTaskDelete ( NULL );
} // End of loop
void app_main ( void ) {
printf ( "Starting BLE Client application... \n " );
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 5 seconds.
BLEScan * pBLEScan = BLEDevice :: getScan ();
2022-08-27 13:13:27 -06:00
pBLEScan -> setScanCallbacks ( new MyAdvertisedDeviceCallbacks ());
2020-08-22 09:56:19 -06:00
pBLEScan -> setInterval ( 1349 );
pBLEScan -> setWindow ( 449 );
pBLEScan -> setActiveScan ( true );
2022-10-23 19:16:33 -06:00
2020-08-22 09:56:19 -06:00
xTaskCreate ( connectTask , "connectTask" , 5000 , NULL , 1 , NULL );
2022-08-26 19:32:01 -06:00
pBLEScan -> start ( 5 * 1000 , false );
2020-08-22 09:56:19 -06:00
} // End of setup.