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

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调试助手连接到蓝牙,然后在点击服务打开下拉菜单。
点击向下箭头向上箭头给客户端发送消息和接收消息

在这里插入图片描述

### ESP32-C3 低功耗蓝牙功能概述 ESP32-C3 是一款集成了 2.4 GHz Wi-Fi Bluetooth 5 (LE) 功能的芯片,其低功耗蓝牙子系统支持 Bluetooth 5 Bluetooth mesh 技术[^1]。为了实现低功耗蓝牙的功能,开发者可以利用 Espressif 提供的 ESP-IDF 开发框架中的相关 API 来完成初始化、配置以及应用层开发。 以下是关于如何通过 ESP-IDF 实现 ESP32-C3 的低功耗蓝牙功能的具体方法: --- ### 初始化蓝牙控制器 在启用蓝牙功能前,需要先初始化并使能蓝牙控制器。可以通过以下函数来操作: ```c #include "esp_bt.h" // 初始化蓝牙控制器 esp_err_t ret = esp_bt_controller_init(&bt_cfg); if (ret != ESP_OK) { // 错误处理逻辑 } // 启用蓝牙控制器(设置为 BLE 模式) esp_bt_controller_enable(ESP_BT_MODE_BLE); ``` 这里 `esp_bt_controller_init` 函数用于初始化蓝牙控制器,而 `esp_bt_controller_enable` 则用来启动蓝牙模块,并指定工作模式为 BLE(Bluetooth Low Energy)。注意,在更改蓝牙模式时,应先禁用当前模式后再重新启用新模式[^2]。 --- ### 获取设备 MAC 地址 每个蓝牙设备都有唯一的 MAC 地址,可通过如下方式获取: ```c uint8_t bd_addr[6]; esp_bd_addr_type_t type; esp_bt_get_mac(bd_addr, &type); printf("Device MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n", bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]); ``` 此代码片段展示了如何读取本地蓝牙设备的 MAC 地址以便于后续通信或调试用途。 --- ### 创建 GATT Server 或 Client #### 配置 GATT Server GATT(Generic Attribute Profile)服务器允许其他设备连接并与之交互数据。创建一个简单的 GATT server 可按以下步骤执行: 1. 注册应用程序到 GAP/GATT 层级; 2. 定义服务 UUID 特征值; 3. 将这些定义的服务注册至 GATT 数据中。 示例代码如下所示: ```c static void gatt_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) { switch (event) { case ESP_GATTS_REG_EVT: printf("REGISTER APP DONE\n"); break; default: break; } } void init_gatt_server(void) { uint16_t app_id; esp_gatt_if_t gatts_if; // 注册回调事件处理器 esp_ble_gatts_register_callback(gatt_event_handler); // 注册 GATT 应用程序 esp_ble_gap_register_callback(gap_event_handler); // 添加服务服务特性... } ``` 以上代码实现了基本的 GATT server 构建流程,具体细节可以根据实际需求扩展。 #### 连接到远程 GATT Server 对于客户端角色而言,则需扫描周围可用的 BLE 设备并通过建立链接访问目标设备上的资源。主要涉及的操作包括但不限于发起扫描请求、解析广告包信息以及发送连接命令等。 --- ### 控制器状态管理及其他辅助功能 除了核心功能外,还有一些额外工具可以帮助优化性能或者节省电量消耗。例如: - **查询控制器状态**: 使用 `esp_bt_controller_get_status()` 方法实时监控蓝牙硬件的工作状况。 - **释放未使用的内存区域**: 当不再需要某些部分的数据结构时可调用相应的清理接口如 `esp_bt_mem_release()` ,从而减少不必要的开销。 - **进入省电模式**: 如果长时间处于待机状态下无任何活动发生的话可以让整个 SoC 转入深度休眠状态以进一步降低能耗水平。 --- ### 总结 综上所述,基于 ESP-IDF 平台能够轻松构建起围绕 ESP32-C3 微控制器为中心的各种类型的 IoT 解决方案,特别是针对那些注重电池续航时间的应用场景来说更是如此。借助丰富的文档资料技术社区的支持,即使是初学者也能快速掌握必要的技能去设计属于自己的项目作品! ---
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值