在ESP32-Arduino中使用低功耗蓝牙BLE
蓝牙蓝牙!Bluetooth🟦🦷!
Author: kkl
写在前面
以往项目中使用的蓝牙相关的例程都是一些鸡毛蒜皮的拼接,终于有空闲的时间可以来专门学习一下ESP32-Arduino中低功耗蓝牙BLE的使用方法啦,同时了解了解BLE的工作原理。
本篇文章将简述如何迅速地学会在ESP32-Arduino中使用BLE的API。
我的环境
- 开发板:ESP32S3N16R8
- 开发平台:Arduino + PlatformIO + Vscode
开始
原理

BLE蓝牙服务端编程的流程:
蓝牙设备初始化 -> 创建Server -> 创建Service -> 创建Characteristic -> 创建广播对象 -> 将服务加入到广播中 -> 开始广播提供服务
…
使用
…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
|
#include <BLEDevice.h> #include <BLEUtils.h> #include <BLEServer.h>
#define SERVICE_UUID "b0afd88d-5807-4533-b27b-a48cc3a32e30" #define CHARACTERISTIC_UUID "7057310c-1e37-4a0a-9ae1-6ed8ccb995b1"
bool isAdvertising = true; int clientCount = 0;
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("Fish Fish"); 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(); BLEAdvertising *pAdvertising = BLEDevice::getAdvertising(); pAdvertising->addServiceUUID(SERVICE_UUID); 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); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
| #include <BLEDevice.h> #include <BLEServer.h> #include <BLEUtils.h> #include <BLE2902.h>
#define SERVICE_UUID "7F7C610C-7A86-4892-94BA-88B70DC790F5"
#define CHARACTERISTIC_UUID_RX "C02E69C2-E503-43F8-A74D-B95C1F5AF088"
#define CHARACTERISTIC_UUID_TX "D914E6B6-509C-4803-9FB5-9454782478A6"
#define _LOG(format, args...) printf(format, ##args)
class HugoBLE : public BLEServerCallbacks, public BLECharacteristicCallbacks { private: bool _isConnected = false; bool _isInitialized = false; BLEServer *pServer = nullptr; BLECharacteristic *pTxCharacteristic = nullptr; std::string deviceName = "HugoBLE"; std::string rxBle; std::string txBle; std::queue<std::string> dataQueue;
public: HugoBLE(std::string deviceName = "hugoBleDevice"); ~HugoBLE() {}
void begin(void); void end(void); void loop(void); void process(void); void setName(std::string deviceName) { this->deviceName = deviceName; }
void onConnect(BLEServer *pServer); void onDisconnect(BLEServer *pServer); void onWrite(BLECharacteristic *pCharacteristic);
};
HugoBLE::HugoBLE(std::string deviceName) : deviceName(std::string(deviceName).substr(0, 15)) { }
void HugoBLE::begin(void) { if (!_isInitialized) { _LOG("[BLE] BLE init begin!\n");
BLEDevice::init("HugoBLE"); pServer = BLEDevice::createServer(); pServer->setCallbacks(this); BLEService *pService = pServer->createService(SERVICE_UUID); pTxCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID_TX, BLECharacteristic::PROPERTY_NOTIFY); pTxCharacteristic->addDescriptor(new BLE2902()); BLECharacteristic *pRxCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID_RX, BLECharacteristic::PROPERTY_WRITE); pRxCharacteristic->setCallbacks(this);
pService->start(); pServer->getAdvertising()->start();
_isInitialized = true;
_LOG("[BLE] BLE init successed!\n"); } else { _LOG("[BLE] BLE has been init!\n"); } }
void HugoBLE::end(void) { }
void HugoBLE::loop(void) { while (!dataQueue.empty()) { std::string data = dataQueue.front(); dataQueue.pop(); rxBle = data; process(); } }
void HugoBLE::process(void) { }
void HugoBLE::onConnect(BLEServer *pServer) { this->_isConnected = true; }
void HugoBLE::onDisconnect(BLEServer *pServer) { this->_isConnected = false; delay(300); pServer->startAdvertising(); }
void HugoBLE::onWrite(BLECharacteristic *pCharacteristic) { std::string rxStr = pCharacteristic->getValue();
if (!rxStr.empty() && rxStr.length() < rxBle.max_size()) { dataQueue.push(rxStr); _LOG("[BLE] RX: %s\n", rxStr.c_str()); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
|
#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" #define CHARACTERISTIC_UUID "7057310c-1e37-4a0a-9ae1-6ed8ccb995b1" #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 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 true; } };
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("Fish Fish"); BLEDevice::setEncryptionLevel(ESP_BLE_SEC_ENCRYPT_MITM); BLEDevice::setSecurityCallbacks(new MySecurity());
BLESecurity *pSecurity = new BLESecurity(); pSecurity->setStaticPIN(112233); 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());
BLEDescriptor *pCountName = new BLEDescriptor(BLEUUID((uint16_t)0x2901)); pCountName->setValue("My Counter"); countCharacteristic->addDescriptor(pCountName); countCharacteristic->setCallbacks(new MyCharacteristicCallbacks());
pService->start(); BLEAdvertising *pAdvertising = BLEDevice::getAdvertising(); pAdvertising->addServiceUUID(SERVICE_UUID); pAdvertising->setScanResponse(true); pAdvertising->setMinPreferred(0x12); BLEDevice::startAdvertising();
Serial.println("Characteristic defined! Now you can read it in your phone!");
t.setInterval([]{ value++; if(countCharacteristic && clientCount>0) { countCharacteristic->setValue(value); countCharacteristic->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(); }
|
写在后面
鸣谢以下教程:
小鱼的教程涵盖了编写BLE蓝牙服务端时的大部分情况,豁然开朗。
koolins对小鱼的教程做了大致的总结,快速写出代码。