保姆级教程:用微信小程序蓝牙API控制ESP32开发板上的LED灯(附完整代码)
从零构建微信小程序蓝牙控制ESP32智能灯控系统
1. 项目概述与核心组件解析
智能硬件与移动端的无缝交互已成为物联网领域的标配能力。本项目将基于微信小程序蓝牙API与ESP32开发板,构建一套完整的LED灯控系统。不同于简单的功能演示,我们将深入剖析每个技术环节的设计原理与实现细节。
核心组件选型依据:
- ESP32开发板:集成双核处理器与蓝牙4.2/5.0双模支持,性价比远超传统Arduino
- 微信小程序:无需安装即可使用的跨平台解决方案,蓝牙API兼容iOS/Android
- BLE协议:低功耗特性适合持续连接的物联网场景,理论传输距离可达100米
硬件准备清单:
- ESP32开发板(推荐ESP32-WROOM-32)
- LED灯模块(或板载LED)
- 杜邦线若干
- Micro USB数据线
开发环境需求:
- Arduino IDE 2.0+(需安装ESP32开发板支持包)
- 微信开发者工具(最新稳定版)
- 智能手机(支持BLE 4.0以上)
2. ESP32固件开发深度优化
2.1 BLE服务架构设计
ESP32的BLE服务采用GATT(通用属性规范)架构,需要精确定义服务UUID和特征值。以下是通过UUID生成工具创建的标准化服务结构:
// UUID生成工具:https://www.uuidgenerator.net/ #define SERVICE_UUID "9a9e0000-332a-11ed-aaab-002590f5c000" #define CHARACTERISTIC_UUID_RX "9a9e0001-332a-11ed-aaab-002590f5c000" #define CHARACTERISTIC_UUID_TX "9a9e0002-332a-11ed-aaab-002590f5c000"2.2 增强型固件代码实现
以下代码增加了错误处理和状态反馈机制:
#include <BLEDevice.h> #include <BLEServer.h> #include <BLEUtils.h> #include <BLE2902.h> #define LED_PIN 2 // 使用GPIO2连接LED BLEServer *pServer; BLECharacteristic *pTxCharacteristic; bool deviceConnected = false; class MyServerCallbacks: public BLEServerCallbacks { void onConnect(BLEServer* pServer) { deviceConnected = true; Serial.println("设备已连接"); }; void onDisconnect(BLEServer* pServer) { deviceConnected = false; Serial.println("设备已断开"); pServer->getAdvertising()->start(); } }; class MyCallbacks: public BLECharacteristicCallbacks { void onWrite(BLECharacteristic *pCharacteristic) { std::string rxValue = pCharacteristic->getValue(); if (rxValue.length() > 0) { Serial.printf("收到数据: [%s]\n", rxValue.c_str()); switch(rxValue[0]) { case '1': digitalWrite(LED_PIN, HIGH); pTxCharacteristic->setValue("LED已开启"); break; case '0': digitalWrite(LED_PIN, LOW); pTxCharacteristic->setValue("LED已关闭"); break; default: pTxCharacteristic->setValue("无效指令"); } pTxCharacteristic->notify(); } } }; void setup() { Serial.begin(115200); pinMode(LED_PIN, OUTPUT); BLEDevice::init("SmartLight-ESP32"); pServer = BLEDevice::createServer(); pServer->setCallbacks(new MyServerCallbacks()); 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(new MyCallbacks()); pService->start(); pServer->getAdvertising()->start(); Serial.println("等待客户端连接..."); } void loop() { if (deviceConnected) { // 可添加定期状态推送逻辑 delay(1000); } }3. 微信小程序开发全流程
3.1 项目配置与权限管理
在app.json中必须声明蓝牙权限:
{ "permission": { "scope.bluetooth": { "desc": "需要蓝牙权限控制智能灯具" } } }3.2 蓝牙通信核心模块
创建bluetoothManager.js封装蓝牙操作:
const BTManager = { devices: [], connectedDevice: null, serviceId: '9a9e0000-332a-11ed-aaab-002590f5c000', rxCharId: '9a9e0001-332a-11ed-aaab-002590f5c000', txCharId: '9a9e0002-332a-11ed-aaab-002590f5c000', initBluetooth() { return new Promise((resolve, reject) => { wx.openBluetoothAdapter({ success: res => { console.log('蓝牙适配器初始化成功'); this.startDiscovery(); resolve(res); }, fail: err => { console.error('蓝牙初始化失败', err); reject(err); } }); }); }, startDiscovery() { wx.startBluetoothDevicesDiscovery({ allowDuplicatesKey: false, success: res => { console.log('开始搜索设备'); this.onDeviceFound(); } }); }, onDeviceFound() { wx.onBluetoothDeviceFound(devices => { devices.devices.forEach(device => { if (device.name && device.name.includes('SmartLight')) { this.devices.push(device); } }); }); }, connectDevice(deviceId) { return new Promise((resolve, reject) => { wx.createBLEConnection({ deviceId, success: res => { this.connectedDevice = deviceId; this.getService(); resolve(res); }, fail: reject }); }); }, getService() { wx.getBLEDeviceServices({ deviceId: this.connectedDevice, success: res => { res.services.forEach(service => { if (service.uuid === this.serviceId) { this.getCharacteristics(); } }); } }); }, getCharacteristics() { wx.getBLEDeviceCharacteristics({ deviceId: this.connectedDevice, serviceId: this.serviceId, success: res => { res.characteristics.forEach(char => { if (char.uuid === this.txCharId && char.properties.notify) { this.notifyCharacteristic(); } }); } }); }, notifyCharacteristic() { wx.notifyBLECharacteristicValueChange({ deviceId: this.connectedDevice, serviceId: this.serviceId, characteristicId: this.txCharId, state: true, }); wx.onBLECharacteristicValueChange(res => { console.log('收到通知:', this.ab2hex(res.value)); }); }, writeCommand(cmd) { const buffer = new ArrayBuffer(1); const dataView = new DataView(buffer); dataView.setUint8(0, cmd === 'on' ? 0x31 : 0x30); // ASCII '1' or '0' wx.writeBLECharacteristicValue({ deviceId: this.connectedDevice, serviceId: this.serviceId, characteristicId: this.rxCharId, value: buffer, }); }, ab2hex(buffer) { const hexArr = Array.prototype.map.call( new Uint8Array(buffer), bit => ('00' + bit.toString(16)).slice(-2) ); return hexArr.join(''); } }; export default BTManager;4. 用户界面设计与交互优化
4.1 设备扫描界面
<view class="container"> <view class="header"> <text>智能灯控系统</text> <button bindtap="initBluetooth">初始化蓝牙</button> </view> <view class="scan-area"> <button bindtap="startScan" disabled="{{isScanning}}"> {{isScanning ? '扫描中...' : '开始扫描'}} </button> <button bindtap="stopScan">停止扫描</button> </view> <scroll-view class="device-list" scroll-y> <view wx:for="{{devices}}" wx:key="deviceId" class="device-item" bindtap="connectDevice" ><view class="control-panel"> <view class="status"> <text>当前状态: {{lightStatus}}</text> </view> <view class="buttons"> <button bindtap="turnOn" type="primary" size="default">开启灯光</button> <button bindtap="turnOff" type="warn" size="default">关闭灯光</button> </view> <view class="log"> <text>操作日志:</text> <scroll-view scroll-y style="height: 200px;"> <text wx:for="{{logs}}" wx:key="time">{{item.time}} - {{item.message}}\n</text> </scroll-view> </view> </view>5. 高级功能扩展与调试技巧
5.1 蓝牙通信优化策略
连接稳定性方案:
- 实现自动重连机制
- 添加心跳包检测连接状态
- 使用队列管理发送指令
class ConnectionManager { constructor() { this.commandQueue = []; this.isSending = false; } addCommand(cmd) { this.commandQueue.push(cmd); this.processQueue(); } processQueue() { if (!this.isSending && this.commandQueue.length > 0) { this.isSending = true; const cmd = this.commandQueue.shift(); BTManager.writeCommand(cmd).then(() => { this.isSending = false; this.processQueue(); }).catch(err => { console.error('命令发送失败', err); this.isSending = false; setTimeout(() => this.processQueue(), 1000); }); } } }5.2 常见问题排查指南
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 搜索不到设备 | ESP32未正确广播 | 检查固件是否正常运行,确认服务UUID正确 |
| 连接后立即断开 | 服务特征值不匹配 | 验证小程序和固件的UUID是否完全一致 |
| 发送指令无响应 | 特征值属性配置错误 | 确认特征值具有write属性 |
| 数据接收乱码 | 编码格式不一致 | 统一使用ArrayBuffer进行数据传输 |
5.3 性能监控与调试
在ESP32端添加性能统计代码:
void printMemoryUsage() { Serial.printf("Free heap: %d bytes\n", ESP.getFreeHeap()); Serial.printf("Minimum free heap: %d bytes\n", ESP.getMinFreeHeap()); } void setup() { // ...原有代码... printMemoryUsage(); } void loop() { static unsigned long lastPrint = 0; if (millis() - lastPrint > 10000) { printMemoryUsage(); lastPrint = millis(); } }6. 项目进阶方向
智能家居集成方案:
- 通过MQTT协议实现云端控制
- 添加PWM调光功能
- 实现定时任务和情景模式
- 开发语音控制接口(对接小爱同学/天猫精灵)
硬件扩展建议:
- 使用继电器模块控制大功率灯具
- 添加光敏传感器实现自动亮度调节
- 集成温湿度传感器打造环境监测系统
- 使用RGB LED实现多彩灯光效果
实际开发中发现,ESP32的蓝牙堆栈偶尔会出现内存泄漏问题。建议在长时间运行的场景中,定期重启蓝牙服务:
void restartBluetooth() { BLEDevice::deinit(); delay(1000); BLEDevice::init("SmartLight-ESP32"); // 重新初始化服务和特征值... }