ESP32低功耗蓝牙服务端的库介绍和实例演示

news2024/11/16 1:24:03

ESP32低功耗蓝牙服务端的库介绍和实例演示

1.概述

前面的文章介绍了经典蓝牙库和使用示例,这篇文章介绍低功耗蓝牙库的使用。
这篇文章不介绍低功耗蓝牙实现的架构知识,只介绍

  • 如何使用它的库文件实现应用开发
  • 只介绍服务端蓝牙开发方式

2.低功耗蓝牙最简单使用示例

2.1.低功耗蓝牙库介绍

低功耗蓝牙库的地址在
/Users/你的用户名称/Library/Arduino15/packages/esp32/hardware/esp32/3.0.3/libraries/BLE/src

1.常用的类库
类名称描述
BLEAddress蓝牙地址类
BLEDevice蓝牙设备类
BLEServer服务器类
BLEService服务类
BLECharacteristic特征类
BLEAdvertising广播类
BLEDescriptor描述符类
BLESecurity安全认证类
2.BLEDevice类常用方法
方法名称描述
static BLEClient* createClient()创建客户端
static bLEServer* createServer()创建服务器
static BLEAddress getAddress()获取本机蓝牙地址
static BLEScan* getscan()获取扫描蓝牙对象
static void init(std: string deviceName)初始化蓝牙
static void setEncryptionLevel(esp_ble_sec_act_t level)设置蓝牙加密的模式
static void setSecurityCallbacks(BLESecurityCallbacks*pCallbacks)设置蓝牙加密的回调函数
static esp_err_t setMTU(uint16_t mtu)设置MTU
static uint16_t getMTU()获取MTU
static bool getInitialized()判断蓝牙设备是否初始化
static void startAdvertising()开始广播
static void stopAdvertising()停止广播
3.BLEServer类常用方法
方法名称描述
uint32_t getConnectedCount()获取连接总数
BLEService* createService(const char* uuid)创建服务
BLEService* createService(BLEUUID uuid, uint32_t numHandles=15, uint8_t inst_id=0)
BLEAdvertising * getAdvertising()获取广播对象
void setCallbacks(BLEServerCallbacks* pCallbacks)设置回调函数,当设备建立连接和失去连接的时候调用
void startAdvertising()启动广播
void removeService(BLEService* service)删除服务
BLEService* getServiceByUUID(const char* uuid)根据UUID获取服务
BLEService* getServiceByUUID(BLEUUID uuid)
disconnect(uint16_t connId)断开连接
4.BLEService类常用方法
方法名称描述
void addCharacteristic(BLECharacteristic* pCharacteristic)添加一个创建好的特征
BLECharacteristic* createCharacteristic(const char* uuid, uint32 t properties)创建特征
BLECharacteristic* createCharacteristic(BLEUUID uuid, uint32 _t properties)
BLECharacteristic* getCharacteristic(const char* uuid)获取特征
BLECharacteristic* getCharacteristic(BLEUUID uuid)
BLEUUID getUUID()获取本特征的UUID
BLEServer* getserver()获取本特征关联的服务
void start()启动服务
void stop()关闭服务
uint16_t getHandle获取本服务对应的 句柄
m_instId =0
5.BLECharacteristic 类常用方法
方法名称描述
BLECharacteristic(const char* uuid, uint32_t properties = 0)
BLECharacteristic(BLEUUID uuid, uint32_t properties = 0)
void addDescriptor(BLEDescriptor* pDescriptor)添加描述符
BLEDescriptor* gtDescriptorByUUID(const char* descriptorUUID)获取描述符
BLEDescriptor* getDescriptorByUUID(BLEUUID descriptorUUID)
BLEUUID getUUID()获取本特征的UUID
void indicate()设置指示
void notify(bool is_notification = true)设置通知
void setCallbacks(BLECharacteristicCallbacks* pCallbacks)回调函数
uint16_t getHandle()获取特征句柄
void setAccessPermissions(esp_gatt_perm_t perm)设置特征访问属性
void setValue(uint32_t& data32)设置特征值
void setValue(uint16_t& data16)设置特征值
void setValue(uint8_t* data, size_t size)设置特征值
void setValue(std::string value)设置特征值
void setValue(int& data32)设置特征值
void setValue(float& data32)设置特征值
void setValue(double& data64)设置特征值
std::string getValue()获取特征值
uint8_t* getData()
size_t getLength();
6.BLEAdvertising类常用方法
方法名称描述
void addServiceUUID (BLEUUID serviceUUID)添加服务到广播
void addServiceUUID(const char* serviceUUID)添加服务到广播
void start()启动广播
void stop()停止广播
广播时间间隔的取值范围是0x0020—0x4000
void setMinInterval(uint16 t maxinterval)设置最短的广播时间间隔,单位0.625ms,默认0x20
void setMaxInterval(uint16 t mininterval)设置最长的广播时间间隔,单位0.625ms,默认0x40
void setMinPreferred(uint16 t)设置客户端首选的最小连接时间间隔,单位1.25ms,默认0x20
void setMaxPreferred(uint16 t)设置客户端首选的最大连接时间间隔,单位1.25ms,默认0x40
void setScanResponse(bool)是否发送扫描回应

2.2.创建一个最简单的蓝牙服务

创建一个低功耗蓝牙的服务需要经过如下几个步骤
1.蓝牙设备初始化
2.创建server服务器
3.创建service服务
4.创建characteristic(特征)
5.创建广播对象
6.将服务加入到广播
7.开发官博服务

1.创建服务代码

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

#define SERVICE_UUID        "b0afd88d-5807-4533-b27b-a48cc3a32e30"   //服务UUID
#define CHARACTERISTIC_UUID "7057310c-1e37-4a0a-9ae1-6ed8ccb995b1"   //特征UUID

void setup() {
  Serial.begin(115200);
  Serial.println("Starting BLE work!");
  delay(500);
  BLEDevice::init("BLE Bluetooth");                    //初始化蓝牙设备
  auto local_address = BLEDevice::getAddress();    //获取本机地址
  Serial.println(local_address.toString().c_str());
  BLEServer *pServer = BLEDevice::createServer();  //创建一个服务器

  BLEService *pService = pServer->createService(SERVICE_UUID);   //创建一个服务
  BLECharacteristic *pCharacteristic = pService->createCharacteristic(    //在服务里创建一个特征
                                         CHARACTERISTIC_UUID,
                                         BLECharacteristic::PROPERTY_READ |
                                         BLECharacteristic::PROPERTY_WRITE                                         
                                       );
  pCharacteristic->setValue("My name is BLE-Bluetooth.");        //给特征赋值


  pService->start();    //Service开始提供服务
  BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();      //获取广播器
  pAdvertising->addServiceUUID(SERVICE_UUID);                      //将Service加入广播
  pAdvertising->setScanResponse(true);                             //允许扫描回复
  pAdvertising->setMinPreferred(0x12);
  BLEDevice::startAdvertising();                                   //开始广播

  Serial.println("Characteristic defined! Now you can read it in your phone!");

}

void loop() {
}

2.查看蓝牙服务信息

首先在手机上安装BLE调试助手,然后打开调试助手下拉刷新就能看到搜索到的蓝牙列表
在这里插入图片描述
选择我们蓝牙的名称,然后点击连接。跳转到链接成功的页面,显示了创建的服务名称等信息
在这里插入图片描述
点击服务Service,在下拉菜单中点击接收图标向下的箭头
在这里插入图片描述
点击读取接收到了我们设置的特征值
在这里插入图片描述

2.3.增加控制客户端连接数和验证连接

上面的例子在连接时候不需要密码验证就可以连接,而且当有一个连接成功后就停止广播,如果断开连接,就不能再次连接。
下面对这两个问题进行改进。

1.实现可以多次广播并可以限制客户端连接数量

实现多次广播关键代码

//服务器连接与断开连接回调类,通过回调类来调用该类的方法实现增加和减少连接数
class MyServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
      Serial.println("client connected...");
      clientCount++;
      //这里用false表示他当前是停止广播状态
      isAdvertising = false;  
    };

    void onDisconnect(BLEServer* pServer) {
      Serial.println("client disconnected...");
      clientCount--;
    }
};


 //使用回调函数调用上面创建的MyServerCallbacks函数实现连接数的增加和减少
  pServer->setCallbacks(new MyServerCallbacks());

/*
  实现再次广播功能:
  getInitialized:判断蓝牙设备是否初始化完成
  isAdvertising:如果没有广播才调用广播函数
  clientCount<1: 设置蓝牙服务端最多接受几个客户端连接  
  */
  if(BLEDevice::getInitialized() && !isAdvertising && clientCount<1)
  {
    delay(500);  //让蓝牙设备留一段处理的时间
    BLEDevice::startAdvertising();  //重新开始广播 
    isAdvertising = true;
    Serial.println("start advertising");
  }

实现多次广播完整代码



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

#define SERVICE_UUID        "b0afd88d-5807-4533-b27b-a48cc3a32e30"   //服务UUID
#define CHARACTERISTIC_UUID "7057310c-1e37-4a0a-9ae1-6ed8ccb995b1"   //特征UUID

bool isAdvertising = true;  //是否在广播 
int clientCount = 0;    //目前已有客户端数量

//服务器连接与断开连接回调类
class MyServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
      Serial.println("client connected...");
      clientCount++;
      //这里用false表示他当前是停止广播状态
      isAdvertising = false;  
    };

    void onDisconnect(BLEServer* pServer) {
      Serial.println("client disconnected...");
      clientCount--;
    }
};

void setup() {
  Serial.begin(115200);
  Serial.println("Starting BLE work!");
  delay(500);
  BLEDevice::init("BLE Bluetooth");                    //初始化蓝牙设备
  auto local_address = BLEDevice::getAddress();    //获取本机地址
  Serial.println(local_address.toString().c_str());
  BLEServer *pServer = BLEDevice::createServer();  //创建一个服务器
  //使用回调函数调用上面创建的MyServerCallbacks函数实现连接数的增加和减少
  pServer->setCallbacks(new MyServerCallbacks());

  BLEService *pService = pServer->createService(SERVICE_UUID);   //创建一个服务
  BLECharacteristic *pCharacteristic = pService->createCharacteristic(    //在服务里创建一个特征
                                         CHARACTERISTIC_UUID,
                                         BLECharacteristic::PROPERTY_READ |
                                         BLECharacteristic::PROPERTY_WRITE                                         
                                       );
  pCharacteristic->setValue("Hello World.");        //给特征赋值


  pService->start();    //Service开始提供服务
  BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();      //获取广播器
  pAdvertising->addServiceUUID(SERVICE_UUID);                      //将Service加入广播
  pAdvertising->setScanResponse(true);                             //允许扫描回复
  pAdvertising->setMinPreferred(0x12);
  BLEDevice::startAdvertising();                                   //开始广播

  Serial.println("Characteristic defined! Now you can read it in your phone!");

}

void loop() {
  /*
  实现再次广播功能:
  getInitialized:判断蓝牙设备是否初始化完成
  isAdvertising:如果没有广播才调用广播函数
  clientCount<1: 设置蓝牙服务端最多接受几个客户端连接  
  */
  if(BLEDevice::getInitialized() && !isAdvertising && clientCount<1)
  {
    delay(500);  //让蓝牙设备留一段处理的时间
    BLEDevice::startAdvertising();  //重新开始广播 
    isAdvertising = true;
    Serial.println("start advertising");
  }

  delay(50);
}

使用BLE调试助手 再次连接蓝牙,这个时候点击断开连接,然后再点连接,他是可以连接的。

在这里插入图片描述
Arduino IDE开发工具的调试窗口可以看到打印的链接信息
在这里插入图片描述

2.静态密码连接

设置静态访问密码关键代码

创建一个被安全认证回调的类,这个类的功能可以任意定制,当前开发的功能就是显示配对密码
class MySecurity : public BLESecurityCallbacks {
  uint32_t onPassKeyRequest(){
    Serial.println("PassKeyRequest!");
    return 113366;
  }

//判断认证结果是否成功
  void onAuthenticationComplete(esp_ble_auth_cmpl_t cmpl){
    if(cmpl.success){
      Serial.println("onAuthenticationComplete!");
    } else {
      Serial.println("onAuthentication not Complete!");
    }
  }

 //设置蓝牙加密模式
  BLEDevice::setEncryptionLevel(ESP_BLE_SEC_ENCRYPT_MITM);
  //设置蓝牙加密的回调函数,调用上面自己创建的MySecurity的构造方法
  BLEDevice::setSecurityCallbacks(new MySecurity());
  //创建密码访问对象
  BLESecurity *pSecurity = new BLESecurity();
  //设置静态访问密码
  pSecurity->setStaticPIN(113366);

静态访问密码完整代码

/**
 *  添加配对认证(静态密码)
 *  
 */


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

#define SERVICE_UUID        "b0afd88d-5807-4533-b27b-a48cc3a32e30"   //服务UUID
#define CHARACTERISTIC_UUID "7057310c-1e37-4a0a-9ae1-6ed8ccb995b1"   //特征UUID

bool isAdvertising = true;  //是否在广播
int clientCount = 0;    //目前已有客户端数量

创建一个被安全认证回调的类,这个类的功能可以任意定制,当前开发的功能就是显示配对密码
class MySecurity : public BLESecurityCallbacks {
  uint32_t onPassKeyRequest(){
    Serial.println("PassKeyRequest!");
    return 113366;
  }

  //显示本机要求的静态码,在使用静态密码时会被调用
  void onPassKeyNotify(uint32_t pass_key){
    Serial.printf("On passkey Notify number:%d", pass_key);
  }

  bool onSecurityRequest(){
    Serial.println("On Security Request!");
    return true;
  }

  //认证结果
  void onAuthenticationComplete(esp_ble_auth_cmpl_t cmpl){
    if(cmpl.success){
      Serial.println("onAuthenticationComplete!");
    } else {
      Serial.println("onAuthentication not Complete!");
    }
  }

  //显示动态码并确定是否同意配对
  bool onConfirmPIN(uint32_t pin){
    Serial.printf("onConfirmPIN %d !", pin);
    //return false;
    return true;  //返回true同意配对,返回false拒绝配对
  }
};

//服务器连接与断开连接回调类
class MyServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
      Serial.println("client connected...");
      clientCount++;
      isAdvertising = false;  //因为只要有客户端连上来,就会关闭广播
    };

    void onDisconnect(BLEServer* pServer) {
      Serial.println("client disconnected...");
      clientCount--;
    }
};

void setup() {
  Serial.begin(115200);
  Serial.println("Starting BLE work!");
  delay(500);
  BLEDevice::init("BLE Bluetooth");  //初始化蓝牙设备
  //设置蓝牙加密模式
  BLEDevice::setEncryptionLevel(ESP_BLE_SEC_ENCRYPT_MITM);
  //设置蓝牙加密的回调函数,调用上面自己创建的MySecurity的构造方法
  BLEDevice::setSecurityCallbacks(new MySecurity());
  //创建密码访问对象
  BLESecurity *pSecurity = new BLESecurity();
  //设置静态访问密码
  pSecurity->setStaticPIN(113366);
  
  auto local_address = BLEDevice::getAddress();    //获取本机地址
  Serial.println(local_address.toString().c_str());
  BLEServer *pServer = BLEDevice::createServer();  //创建一个服务器
  pServer->setCallbacks(new MyServerCallbacks());

  BLEService *pService = pServer->createService(SERVICE_UUID);   //创建一个服务
  BLECharacteristic *pCharacteristic = pService->createCharacteristic(    //在服务里创建一个特征
                                         CHARACTERISTIC_UUID,
                                         BLECharacteristic::PROPERTY_READ |
                                         BLECharacteristic::PROPERTY_WRITE                                         
                                       );
  pCharacteristic->setValue("Hello World.");        //给特征赋值


  pService->start();    //Service开始提供服务
  BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();      //获取广播器
  pAdvertising->addServiceUUID(SERVICE_UUID);                      //将Service加入广播
  pAdvertising->setScanResponse(true);                             //允许扫描回复
  pAdvertising->setMinPreferred(0x12);
  BLEDevice::startAdvertising();                                   //开始广播

  Serial.println("Characteristic defined! Now you can read it in your phone!");

}

void loop() {
  if(BLEDevice::getInitialized() && !isAdvertising && clientCount<1)
  {
    delay(500);  //让蓝牙设备留一段处理的时间
    BLEDevice::startAdvertising();  //重新开始广播
    isAdvertising = true;
    Serial.println("start advertising");
  }

  delay(50);
}

BLE 调试助手点击链接,此时会弹出配对验证窗口
在这里插入图片描述
输入的配对码不争取,则不允许连接
在这里插入图片描述
输入正确的验证码,连接成功
在这里插入图片描述

3.动态密码连接
//显示动态码并确定是否同意配对
  bool onConfirmPIN(uint32_t pin){
    Serial.printf("onConfirmPIN %d !", pin);
    //return false;
    return true;  //返回true同意配对,返回false拒绝配对
  }

//设置蓝牙加密模式
  BLEDevice::setEncryptionLevel(ESP_BLE_SEC_ENCRYPT_MITM);
  //设置蓝牙加密的回调函数,调用上面自己创建的MySecurity的构造方法
  BLEDevice::setSecurityCallbacks(new MySecurity());
  //创建密码访问对象 
  BLESecurity *pSecurity = new BLESecurity();
  //设置认证模式:交互模式
  pSecurity->setAuthenticationMode(ESP_LE_AUTH_REQ_SC_MITM_BOND);
  pSecurity->setCapability(ESP_IO_CAP_IO);  //显示yes,no
  //pSecurity->setCapability(ESP_IO_CAP_NONE);  //没有IO设备
  pSecurity->setInitEncryptionKey(ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK);

完整代码

/**
 *  添加配对认证(交互认证)
 *  
 */


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

#define SERVICE_UUID        "b0afd88d-5807-4533-b27b-a48cc3a32e30"   //服务UUID
#define CHARACTERISTIC_UUID "7057310c-1e37-4a0a-9ae1-6ed8ccb995b1"   //特征UUID

bool isAdvertising = true;  //是否在广播
int clientCount = 0;    //目前已有客户端数量

class MySecurity : public BLESecurityCallbacks {
  uint32_t onPassKeyRequest(){
    Serial.println("PassKeyRequest!");
    return 334455;
  }

  //显示本机要求的静态码
  void onPassKeyNotify(uint32_t pass_key){
    Serial.printf("On passkey Notify number:%d", pass_key);
  }

  bool onSecurityRequest(){
    Serial.println("On Security Request!");
    return true;
  }

  //认证结果
  void onAuthenticationComplete(esp_ble_auth_cmpl_t cmpl){
    if(cmpl.success){
      Serial.println("onAuthenticationComplete!");
    } else {
      Serial.println("onAuthentication not Complete!");
    }
  }

  //显示动态码并确定是否同意配对
  bool onConfirmPIN(uint32_t pin){
    Serial.printf("onConfirmPIN %d !", pin);
    //return false;
    return true;  //返回true同意配对,返回false拒绝配对
  }
};

//服务器连接与断开连接回调类
class MyServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
      Serial.println("client connected...");
      clientCount++;
      isAdvertising = false;  //因为只要有客户端连上来,就会关闭广播
    };

    void onDisconnect(BLEServer* pServer) {
      Serial.println("client disconnected...");
      clientCount--;
    }
};

void setup() {
  Serial.begin(115200);
  Serial.println("Starting BLE work!");
  delay(500);
  BLEDevice::init("BLE Bluetooth"); //初始化蓝牙设备
  //设置蓝牙加密模式
  BLEDevice::setEncryptionLevel(ESP_BLE_SEC_ENCRYPT_MITM);
  //设置蓝牙加密的回调函数,调用上面自己创建的MySecurity的构造方法
  BLEDevice::setSecurityCallbacks(new MySecurity());
  //创建密码访问对象 
  BLESecurity *pSecurity = new BLESecurity();
  //设置认证模式:交互模式
  pSecurity->setAuthenticationMode(ESP_LE_AUTH_REQ_SC_MITM_BOND);
  pSecurity->setCapability(ESP_IO_CAP_IO);  //显示yes,no
  //pSecurity->setCapability(ESP_IO_CAP_NONE);  //没有IO设备
  pSecurity->setInitEncryptionKey(ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK);
  
  auto local_address = BLEDevice::getAddress();    //获取本机地址
  Serial.println(local_address.toString().c_str());
  BLEServer *pServer = BLEDevice::createServer();  //创建一个服务器
  pServer->setCallbacks(new MyServerCallbacks());

  BLEService *pService = pServer->createService(SERVICE_UUID);   //创建一个服务
  BLECharacteristic *pCharacteristic = pService->createCharacteristic(    //在服务里创建一个特征
                                         CHARACTERISTIC_UUID,
                                         BLECharacteristic::PROPERTY_READ |
                                         BLECharacteristic::PROPERTY_WRITE                                         
                                       );
  pCharacteristic->setValue("Hello World.");        //给特征赋值


  pService->start();    //Service开始提供服务
  BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();      //获取广播器
  pAdvertising->addServiceUUID(SERVICE_UUID);                      //将Service加入广播
  pAdvertising->setScanResponse(true);                             //允许扫描回复
  pAdvertising->setMinPreferred(0x12);
  BLEDevice::startAdvertising();                                   //开始广播

  Serial.println("Characteristic defined! Now you can read it in your phone!");

}

void loop() {
  if(BLEDevice::getInitialized() && !isAdvertising && clientCount<1)
  {
    delay(500);  //让蓝牙设备留一段处理的时间
    BLEDevice::startAdvertising();  //重新开始广播
    isAdvertising = true;
    Serial.println("start advertising");
  }

  delay(50);
}

在``BLE蓝牙调试工具连接蓝牙会显示动态配对码
在这里插入图片描述

2.4. 创建多个特征-加密权限-通知

1.多特征代码以及开启通知和指示功能介绍
/*
创建多个特征,在第二个特征中开启通知和指示功能,给客户端发送通知或指示。
*/

 //创建一个服务
  BLEService *pService = pServer->createService(SERVICE_UUID);
  //在服务里创建一个特征
  BLECharacteristic *pCharacteristic = pService->createCharacteristic(
    CHARACTERISTIC_UUID,
    BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE);
    // 给特征设置权限:读和写都要权限
  pCharacteristic->setAccessPermissions(ESP_GATT_PERM_READ_ENCRYPTED | ESP_GATT_PERM_WRITE_ENCRYPTED);
  pCharacteristic->setValue("Hello World.");  //给特征赋值
//创建第二个特征,开启通知和指示功能
  countCharacteristic = pService->createCharacteristic(
    COUNT_CHARACTERISTIC_UUID,
    //  只允许客户端读取,不能写
    BLECharacteristic::PROPERTY_READ |
      //  开启通知
      BLECharacteristic::PROPERTY_NOTIFY |
      //  开启指示
      BLECharacteristic::PROPERTY_INDICATE);
  // 给通知的特征设置一个初始值
  countCharacteristic->setValue(value);
  //要启用notify和indicate的都要添加这个描述符
  countCharacteristic->addDescriptor(new BLE2902());
  //设置描述符信息  
  BLEDescriptor *pCountName = new BLEDescriptor(BLEUUID((uint16_t)0x2901));
  pCountName->setValue("My Counter");
  countCharacteristic->addDescriptor(pCountName);

/*
给客户端发送通知或指示
*/

//每3秒计数器加1,并发通知
  t.setInterval([] {
    Serial.println("plus...");
    value++;
    if (countCharacteristic && clientCount > 0) {
      countCharacteristic->setValue(value);
      // 给客户端发送通知,不需要客户端回复
      countCharacteristic->notify();
      // 给客户端发送指示,需要客户端回复
      //countCharacteristic->indicate();
      Serial.println("notify");
    }
  },
                3000);
2.完整代码
/**
 *  多特征,加密及notify
 *  
 */

#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#include <AsyncTimer.h>
//通知和指示用到的库
#include <BLE2902.h>
#include <BLEUUID.h>

#define SERVICE_UUID "b0afd88d-5807-4533-b27b-a48cc3a32e30"               //服务UUID
#define CHARACTERISTIC_UUID "7057310c-1e37-4a0a-9ae1-6ed8ccb995b1"        //特征UUID
#define COUNT_CHARACTERISTIC_UUID "37582929-48c3-4dd0-8e4f-0b29c5640489"  //计数器特征

uint32_t value = 0;
BLECharacteristic *countCharacteristic = NULL;
AsyncTimer t;

bool isAdvertising = true;  //是否在广播
int clientCount = 0;        //目前已有客户端数量

class MySecurity : public BLESecurityCallbacks {
  uint32_t onPassKeyRequest() {
    Serial.println("PassKeyRequest!");
    return 334455;
  }

  //显示本机要求的静态码
  void onPassKeyNotify(uint32_t pass_key) {
    Serial.printf("On passkey Notify number:%d", pass_key);
  }

  bool onSecurityRequest() {
    Serial.println("On Security Request!");
    return true;
  }

  //认证结果
  void onAuthenticationComplete(esp_ble_auth_cmpl_t cmpl) {
    if (cmpl.success) {
      Serial.println("onAuthenticationComplete!");
    } else {
      Serial.println("onAuthentication not Complete!");
    }
  }

  //显示动态码并确定是否同意配对
  bool onConfirmPIN(uint32_t pin) {
    Serial.printf("onConfirmPIN %d !", pin);
    //return false;
    return true;  //返回true同意配对,返回false拒绝配对
  }
};

//服务器连接与断开连接回调类
class MyServerCallbacks : public BLEServerCallbacks {
  void onConnect(BLEServer *pServer) {
    Serial.println("client connected...");
    clientCount++;
    isAdvertising = false;  //因为只要有客户端连上来,就会关闭广播
  };

  void onDisconnect(BLEServer *pServer) {
    Serial.println("client disconnected...");
    clientCount--;
  }
};

void setup() {
  Serial.begin(115200);
  Serial.println("Starting BLE work!");
  delay(500);
  BLEDevice::init("BLE Bluetooth");  //初始化蓝牙设备
  BLEDevice::setEncryptionLevel(ESP_BLE_SEC_ENCRYPT_MITM);
  BLEDevice::setSecurityCallbacks(new MySecurity());

  BLESecurity *pSecurity = new BLESecurity();
  pSecurity->setStaticPIN(113366);  //这个是设置静态密码

  auto local_address = BLEDevice::getAddress();  //获取本机地址
  Serial.println(local_address.toString().c_str());
  BLEServer *pServer = BLEDevice::createServer();  //创建一个服务器
  pServer->setCallbacks(new MyServerCallbacks());

  //创建一个服务
  BLEService *pService = pServer->createService(SERVICE_UUID);
  //在服务里创建一个特征
  BLECharacteristic *pCharacteristic = pService->createCharacteristic(
    CHARACTERISTIC_UUID,
    BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE);
  // 给特征设置权限:读和写都要权限
  pCharacteristic->setAccessPermissions(ESP_GATT_PERM_READ_ENCRYPTED | ESP_GATT_PERM_WRITE_ENCRYPTED);
  pCharacteristic->setValue("Hello World.");  //给特征赋值

  countCharacteristic = pService->createCharacteristic(
    COUNT_CHARACTERISTIC_UUID,
    //  只允许客户端读取,不能写
    BLECharacteristic::PROPERTY_READ |
      //  开启通知
      BLECharacteristic::PROPERTY_NOTIFY |
      //  开启指示
      BLECharacteristic::PROPERTY_INDICATE);
  // 给通知的特征设置一个初始值
  countCharacteristic->setValue(value);
  //要启用notify和indicate的都要添加这个描述符
  countCharacteristic->addDescriptor(new BLE2902());
  //设置描述符信息  
  BLEDescriptor *pCountName = new BLEDescriptor(BLEUUID((uint16_t)0x2901));
  pCountName->setValue("My Counter");
  countCharacteristic->addDescriptor(pCountName);

  pService->start();                                           //Service开始提供服务
  BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();  //获取广播器
  pAdvertising->addServiceUUID(SERVICE_UUID);                  //将Service加入广播
  pAdvertising->setScanResponse(true);                         //允许扫描回复
  pAdvertising->setMinPreferred(0x12);
  BLEDevice::startAdvertising();  //开始广播

  Serial.println("Characteristic defined! Now you can read it in your phone!");

  //每3秒计数器加1,并发通知
  t.setInterval([] {
    Serial.println("plus...");
    value++;
    if (countCharacteristic && clientCount > 0) {
      countCharacteristic->setValue(value);
      // 给客户端发送通知,不需要客户端回复
      countCharacteristic->notify();
      // 给客户端发送指示,需要客户端回复
      //countCharacteristic->indicate();
      Serial.println("notify");
    }
  },
                3000);

  //处理自动广播问题
  t.setInterval([] {
    if (BLEDevice::getInitialized() && !isAdvertising && clientCount < 1) {
      delay(500);                     //让蓝牙设备留一段处理的时间
      BLEDevice::startAdvertising();  //重新开始广播
      isAdvertising = true;
      Serial.println("start advertising");
    }
  },
                50);
}

void loop() {
  t.handle();
}

3.客户端接受通知演示

使用BLE调试助手连接到蓝牙,然后在点击服务打开下拉菜单。
选择只有向下箭头的特征,点击向下箭头读取信息。
在这里插入图片描述
客户端读取信息

在这里插入图片描述

2.5.特征读写配置

读写回调类介绍

class BLECharacteristicCallbacks

virtual BLECharacteristicCallbacks();
//在读的时候触发回调
virtual void onRead(BLECharacteristic* pCharacteristic, esp_ble_gatts_cb_param_t* param);
//在写的时候触发回调
virtual void onWrite(BLECharacteristic* pCharacteristic, esp_ble_gatts_cb_param_t* param);
//在通知或指示的时候触发回调
virtual void onNotify(BLECharacteristic* pCharacteristic); };

2.重写回调类功能介绍
// setCallbacks方法是一个特征回调方法,当有事件触发就会自动调用该方法。然后在该方法中传入一个执行回调内容的对象。
 pCharacteristic->setCallbacks()

//自定义触发回调后执行的内容
// 自定义一个特征被回调调用的类该类继承BLECharacteristicCallbacks,重写他的方法,实现回调的功能
class MyCharacteristicCallbacks: public BLECharacteristicCallbacks{
	//读取触发执行的内容
	virtual void onRead(BLECharacteristic* pCharacteristic, esp_ble_gatts_cb_param_t* param)
  {
    auto p = param->read;
    auto conn_id = p.conn_id;
    BLEAddress address(p.bda);
    Serial.printf("Read.. %d, %s\r\n", conn_id, address.toString().c_str());
  }
	//写触发执行的内容
	virtual void onWrite(BLECharacteristic* pCharacteristic, esp_ble_gatts_cb_param_t* param)
  {
    auto p = param->read;
    auto conn_id = p.conn_id;
    BLEAddress address(p.bda);
    Serial.printf("Write.. %d, %s\r\n", conn_id, address.toString().c_str());
  }
	//通知触发执行的内容
	virtual void onNotify(BLECharacteristic* pCharacteristic)
  {
    Serial.println("notify...");
  }
};
3.完整代码
/**
 *  例5 特征回调例子
 *  
 */

#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#include <AsyncTimer.h>
#include <BLE2902.h>
#include <BLEUUID.h>

#define SERVICE_UUID        "b0afd88d-5807-4533-b27b-a48cc3a32e30"   //服务UUID
#define CHARACTERISTIC_UUID "7057310c-1e37-4a0a-9ae1-6ed8ccb995b1"   //特征UUID
#define COUNT_CHARACTERISTIC_UUID "37582929-48c3-4dd0-8e4f-0b29c5640489" //计数器特征

uint32_t value = 0;
BLECharacteristic *countCharacteristic = NULL;
AsyncTimer t;

bool isAdvertising = true;  //是否在广播
int clientCount = 0;    //目前已有客户端数量

// // 自定义一个特征被回调调用的类该类继承BLECharacteristicCallbacks,重写他的方法,实现回调的功能
class MyCharacteristicCallbacks: public BLECharacteristicCallbacks{

	virtual void onRead(BLECharacteristic* pCharacteristic, esp_ble_gatts_cb_param_t* param)
  {
    auto p = param->read;
    auto conn_id = p.conn_id;
    BLEAddress address(p.bda);
    Serial.printf("Read.. %d, %s\r\n", conn_id, address.toString().c_str());
  }

	virtual void onWrite(BLECharacteristic* pCharacteristic, esp_ble_gatts_cb_param_t* param)
  {
    auto p = param->read;
    auto conn_id = p.conn_id;
    BLEAddress address(p.bda);
    Serial.printf("Write.. %d, %s\r\n", conn_id, address.toString().c_str());
  }

	virtual void onNotify(BLECharacteristic* pCharacteristic)
  {
    Serial.println("notify...");
  }
};

class MySecurity : public BLESecurityCallbacks {
  uint32_t onPassKeyRequest(){
    Serial.println("PassKeyRequest!");
    return 334455;
  }

  //显示本机要求的静态码
  void onPassKeyNotify(uint32_t pass_key){
    Serial.printf("On passkey Notify number:%d", pass_key);
  }

  bool onSecurityRequest(){
    Serial.println("On Security Request!");
    return true;
  }

  //认证结果
  void onAuthenticationComplete(esp_ble_auth_cmpl_t cmpl){
    if(cmpl.success){
      Serial.println("onAuthenticationComplete!");
    } else {
      Serial.println("onAuthentication not Complete!");
    }
  }

  //显示动态码并确定是否同意配对
  bool onConfirmPIN(uint32_t pin){
    Serial.printf("onConfirmPIN %d !", pin);
    //return false;
    return true;  //返回true同意配对,返回false拒绝配对
  }
};

//服务器连接与断开连接回调类
class MyServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
      Serial.println("client connected...");
      clientCount++;
      isAdvertising = false;  //因为只要有客户端连上来,就会关闭广播
    };

    void onDisconnect(BLEServer* pServer) {
      Serial.println("client disconnected...");
      clientCount--;
    }
};

void setup() {
  Serial.begin(115200);
  Serial.println("Starting BLE work!");
  delay(500);
  BLEDevice::init("BLE Bluetooth");                    //初始化蓝牙设备
  BLEDevice::setEncryptionLevel(ESP_BLE_SEC_ENCRYPT_MITM);
  BLEDevice::setSecurityCallbacks(new MySecurity());

  BLESecurity *pSecurity = new BLESecurity();
  pSecurity->setStaticPIN(113366);  //这个是设置静态密码
  
  auto local_address = BLEDevice::getAddress();    //获取本机地址
  Serial.println(local_address.toString().c_str());
  BLEServer *pServer = BLEDevice::createServer();  //创建一个服务器
  pServer->setCallbacks(new MyServerCallbacks());

  BLEService *pService = pServer->createService(SERVICE_UUID);   //创建一个服务
  BLECharacteristic *pCharacteristic = pService->createCharacteristic(    //在服务里创建一个特征
                                         CHARACTERISTIC_UUID,
                                         BLECharacteristic::PROPERTY_READ |
                                         BLECharacteristic::PROPERTY_WRITE                                         
                                       );
  pCharacteristic->setAccessPermissions(ESP_GATT_PERM_READ_ENCRYPTED | ESP_GATT_PERM_WRITE_ENCRYPTED);
  pCharacteristic->setValue("Hello World.");        //给特征赋值
  // 触发回调特征
  pCharacteristic->setCallbacks(new MyCharacteristicCallbacks());

  countCharacteristic = pService->createCharacteristic(
                                         COUNT_CHARACTERISTIC_UUID,
                                         BLECharacteristic::PROPERTY_READ |
                                         BLECharacteristic::PROPERTY_NOTIFY |
                                         BLECharacteristic::PROPERTY_INDICATE
                                       );
  countCharacteristic->setValue(value);
  countCharacteristic->addDescriptor(new BLE2902());  //要启用notify和indicate的都要添加这个描述符

  BLEDescriptor *pCountName = new BLEDescriptor(BLEUUID((uint16_t)0x2901));
  pCountName->setValue("My Counter");
  countCharacteristic->addDescriptor(pCountName);
  // 触发回调特征
  countCharacteristic->setCallbacks(new MyCharacteristicCallbacks());

  pService->start();    //Service开始提供服务
  BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();      //获取广播器
  pAdvertising->addServiceUUID(SERVICE_UUID);                      //将Service加入广播
  pAdvertising->setScanResponse(true);                             //允许扫描回复
  pAdvertising->setMinPreferred(0x12);
  BLEDevice::startAdvertising();                                   //开始广播

  Serial.println("Characteristic defined! Now you can read it in your phone!");

  //每3秒计数器加1,并发通知
  t.setInterval([]{
    value++;
    if(countCharacteristic && clientCount>0)
    {
      countCharacteristic->setValue(value);
      countCharacteristic->notify();  //发通知
      //countCharacteristic->indicate();
    }
  }, 3000);

  //处理自动广播问题
  t.setInterval([]{
    if(BLEDevice::getInitialized() && !isAdvertising && clientCount<1)
    {
      delay(500);  //让蓝牙设备留一段处理的时间
      BLEDevice::startAdvertising();  //重新开始广播
      isAdvertising = true;
      Serial.println("start advertising");
    }
  }, 50);
}

void loop() {
  t.handle();
}

4.演示

使用BLE调试助手连接到蓝牙,然后在点击服务打开下拉菜单。
点击向下箭头向上箭头给客户端发送消息和接收消息

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1973934.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

R语言大尺度空间数据分析模拟预测及可视化:地统计与空间自相关、空间数据插值、机器学习空间预测、空间升降尺度、空间模拟残差订正、空间制图等

目录 专题一 R语言空间数据介绍及数据挖掘关键技术 专题二 R语言空间数据高级处理技术 专题三 R语言多维时空数据处理技术、数据清洗整合和时间序列分析 专题四 R语言地统计与空间自相关、空间插值方法 专题五 R语言机器学习与空间模型预测及不确定性评估 专题六 R语言空…

htsjdk库ReferenceSequenceFile接口介绍

ReferenceSequenceFile 是 HTSJDK 库中的一个接口,用于表示参考基因组文件。它定义了读取参考基因组序列的标准方法。这个接口使得不同类型的参考基因组文件(如 FASTA 格式)能够以统一的方式进行访问。 ReferenceSequenceFile 接口主要功能 访问参考序列: 提供获取参考基因…

如何在 Windows/Mac/iPhone/Android 上将 PDF 转换为 Word

PDF&#xff08;便携式文档格式&#xff09;是一种流行的格式&#xff0c;广泛用于在数字电子设备中呈现文档。输出文件小且兼容性强&#xff0c;使 PDF 如此受欢迎。但是&#xff0c;编辑 PDF 文件并非免费。您无需购买 PDF 编辑器&#xff0c;而是可以将 PDF 转换为 Word 进行…

嘉兴网站建设的思路

随着互联网的快速发展&#xff0c;网站已经成为企业宣传和推广的重要工具。作为浙江省的一个重要城市&#xff0c;嘉兴具有得天独厚的地理位置和经济实力&#xff0c;因此开展嘉兴网站建设具有重要意义。在进行网站建设的过程中&#xff0c;需要有一定的思路和规划&#xff0c;…

跑深度学习模型Ⅱ:一文安装正确pytorch及dgl

如果要用到GPU &#xff0c;先看这篇安装并保证cuda可用。跑深度学习模型I&#xff1a;一文正确使用CUDA-CSDN博客 啊每次都是pytorch版本问题引发的一系列错误&#xff01; 1. 查看自己的cuda版本 nvcc --version 可以看到我的cuda版本是11.8 nvidia-smi 查看NVIDIA驱动版…

智能变“智障”?云鲸扫地机器人频发故障引质疑

近年来&#xff0c;扫地机器人市场以其智能化技术革新和不断升级的产品功能&#xff0c;成功吸引了消费者的目光&#xff0c;甚至打破了家电行业的价格僵局&#xff0c;实现了价格与价值的双重攀升。然而&#xff0c;在这股智能家电的浪潮中&#xff0c;云鲸扫地机器人却因其频…

【C++从小白到大牛】栈和队列(优先级队列)

目录 引言&#xff1a; 使用方法篇&#xff1a; stack&#xff1a; queue priority_queue 使用方法&#xff1a; 模拟实现篇&#xff1a; stack&#xff1a; 原码&#xff1a; queue 原码&#xff1a; priority_queue 插入和删除数据的思想&#xff1a; 仿函数实…

TDEngine(taos) 涛思数据库-sql初识

一、基本使用 这里读者自行安装数据库&#xff1a;使用安装包立即开始 | TDengine 文档 | 涛思数据 (taosdata.com) // 下载gz文件&#xff0c;解压 tar -zxvf TDengine-server-<对应版本>-Linux-x64.tar.gz// 解压后启动 sudo ./install.sh 启动成功后&#xff0c;直…

动态规划之子数组系列问题

题型介绍 子数组系列动态规划问题长什么样 例题 力扣 53. 最大子数组和 解题步骤&#xff1a; 创建 dp 表以及确定 dp 表中所要填写位置的含义&#xff1a; 首先&#xff0c;根据写题经验&#xff0c;先确定出这道题应该使用的解题思路是 “以某一个位置为结尾进行分析”…

【编码心得】单元测试的那些事

【编码心得】单元测试的那些事 文章目录 单元测试定义&#xff1f;为什么需要单元测试&#xff1f;为重构保驾护航提高代码质量减少 bug快速定位 bug持续集成依赖单元测试团队编码规范要求大牛都写单元测试保住面子 TDD 测试驱动开发何谓 TDD&#xff1f;TDD的基本流程TDD 优缺…

全球轻型汽车市场规划预测:2030年市场规模将接近2502亿元,未来六年CAGR为2.8%

一、引言 随着全球经济的发展和消费者出行需求的增加&#xff0c;轻型汽车作为汽车市场中的重要组成部分&#xff0c;其市场重要性日益凸显。本文旨在探索轻型汽车行业的发展趋势、潜在商机及其未来展望。 二、市场趋势 全球轻型汽车市场的增长主要受全球经济发展、消费者对出…

海风小店微信商城小程序附后端一款免费开源的小程序源码

该商城小程序服务端api基于node.jsThinkJSMySQL&#xff0c;如果对这个不大熟悉的人&#xff0c; 可能有那么一点难度&#xff0c;但是如果只是搭建的话&#xff0c;作者的教程还是比较详细的&#xff0c;而且搭建步骤比较简单&#xff0c; 应该很容易上手&#xff0c;如果你…

【KAN】【API教程】索引

简单来说就是确定激活函数的坐标 from kan import *model = KAN(width=[2,3,2,1]) x = torch.normal(0,1,size=(100,2)) model(x); beta = 100 model.plot(beta=beta) # [2,3,2,1] means 2 input nodes # 3 neurons in the first hidden layer, # 2 neurons in the second hid…

知识图谱开启了一个可以理解的人工智能未来

概述 本文是对利用知识图谱&#xff08;KG&#xff09;的综合人工智能&#xff08;CAI&#xff09;的全面调查研究&#xff0c;其中 CAI 被定义为可解释人工智能&#xff08;XAI&#xff09;和可解释机器学习&#xff08;IML&#xff09;的超集。 首先&#xff0c;本文澄清了…

【Linux学习】实现一个简单版的Shell

&#x1f351;个人主页&#xff1a;Jupiter. &#x1f680; 所属专栏&#xff1a;Linux从入门到进阶 欢迎大家点赞收藏评论&#x1f60a; 目录 &#x1f4d5;前言&#x1f351;shell&#x1f4da;Shell的工作原理&#x1f512;Shell的高级功能 &#x1f680;shell的代码实现&am…

Mybatis实战:#{} 和 ${}的使用区别和数据库连接池

一.#{} 和 ${} #{} 和 ${} 在MyBatis框架中都是用于SQL语句中参数替换的标记&#xff0c;但它们在使用方式和处理参数值上存在一些显著的区别。 #{}的作用&#xff1a; #{} 是MyBatis中用于预编译SQL语句的参数占位符。它会将参数值放入一个预编译的PreparedStatement中&am…

JavaScript ES6语法详解(下)

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;我是码喽的自我修养&#xff01;今天给大家分享JavaScript ES6语法详解(下)&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到带大家&#xff0c;欢迎收藏关注…

信创企业级即时通讯发展趋势,私有化安全沟通

信创&#xff08;创新型科技公司&#xff09;在当今的商业环境中发挥着重要作用&#xff0c;因此&#xff0c;他们对于私有化安全沟通的需求日益增加。企业级即时通讯软件是为满足企业内部沟通和协作需求而设计的重要工具。在信创企业中&#xff0c;采用私有化安全沟通解决方案…

乐乐音乐Kotlin版

简介 乐乐音乐Kotlin版&#xff0c;主要是基于ExoPlayer框架开发的Android音乐播放器&#xff0c;它支持lrc歌词和动感歌词(ksc歌词、krc歌词、trc歌词、zrce歌词和hrc歌词等)、多种格式歌词转换器及制作动感歌词、翻译歌词和音译歌词。 编译环境 Android Studio Jellyfish | …

计算机毕业设计Python+Tensorflow股票推荐系统 股票预测系统 股票可视化 股票数据分析 量化交易系统 股票爬虫 股票K线图 大数据毕业设计 AI

1、用pycharm打开项目&#xff0c;一定要打开包含manage.py文件所在文件夹 2、配置解释器&#xff1a;建议使用Anaconda(Python 3.8(base))&#xff0c;低于3.8版本的&#xff0c;页面会不兼容 3、安装依赖库&#xff1a;打开pycharm的终端&#xff0c;输入&#xff1a; pip in…