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