零基础实战:用APP Inventor蓝牙插件玩转ESP32 BLE控制
当你手里拿着一块ESP32开发板,想用手机APP控制它点亮LED或者读取传感器数据时,BLE(低功耗蓝牙)通信无疑是最便捷的选择。但对于初学者来说,从零开始搭建整个通信链路可能会遇到各种"坑":UUID配置错误、数据格式不匹配、事件注册遗漏...本文将带你一步步绕过这些雷区,用最直观的方式实现手机与ESP32的"对话"。
1. 环境准备与工具链搭建
在开始之前,我们需要准备好两个核心工具:APP Inventor开发环境和ESP32开发环境。这两者的组合就像搭建一座连接手机和硬件的桥梁。
APP Inventor准备:
- 访问MIT APP Inventor官网并登录(推荐使用Google账号)
- 新建项目,命名为"ESP32_BLE_Controller"
- 在项目面板中点击"Extensions",搜索并添加"BluetoothLE"插件
ESP32开发环境:
- 安装Arduino IDE(1.8.x或更高版本)
- 在首选项中添加ESP32开发板管理URL:
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json - 通过开发板管理器安装"esp32"平台
提示:BluetoothLE插件是APP Inventor社区开发的第三方扩展,它专门为BLE设备通信设计,与传统蓝牙插件不兼容。这也是为什么直接使用内置蓝牙组件无法连接ESP32的原因。
2. BLE通信基础与UUID配置
理解BLE通信的基本架构是避免后续配置错误的关键。一个典型的BLE连接包含三个核心要素:
| 要素 | 作用 | 示例值 |
|---|---|---|
| Service UUID | 定义设备提供的服务类型 | "4fafc201-1fb5-459e-8fcc-c5c9c331914b" |
| Characteristic UUID | 定义服务下的具体数据特征 | "beb5483e-36e1-4688-b7f5-ea07361b26a8" |
| Descriptor UUID | 描述特征的附加信息(可选) | "00002902-0000-1000-8000-00805f9b34fb" |
在APP Inventor中配置这些参数时,需要确保与ESP32端的代码完全一致。一个常见的错误是使用了不同的UUID格式(如有的带连字符,有的不带),这会导致设备无法被发现或连接失败。
// ESP32端的UUID设置示例 #define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b" #define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"3. APP Inventor界面设计与事件处理
现在我们来构建手机APP的用户界面和逻辑。这个界面将包含设备扫描、连接控制和数据发送三个主要功能区域。
界面组件布局:
- 1个
ListPicker(用于显示和选择BLE设备) - 1个
Button(扫描设备) - 1个
Label(显示连接状态) - 1个
TextBox(输入要发送的数据) - 1个
Button(发送数据)
- 1个
关键事件处理逻辑:
- 当用户点击扫描按钮时,调用
BluetoothLE1.StartScanning方法 - 设备发现后更新
ListPicker的选项 - 连接成功后自动触发
Connected事件(必须在此注册数据接收处理)
- 当用户点击扫描按钮时,调用
// APP Inventor块编程示例 当 BluetoothLE1.Connected 设置 BluetoothLE1.SubscribeToCharacteristic 服务UUID "4fafc201..." 特征UUID "beb5483e..." 设置 Label1.Text 为 "已连接" 结束注意:Connected事件是BLE连接建立后的第一个关键点,很多初学者会忘记在这里注册数据接收处理(SubscribeToCharacteristic),导致后续无法接收ESP32发送的数据。
4. ESP32端BLE服务实现
ESP32作为BLE服务器,需要广播服务并处理来自手机的读写请求。以下是实现基本功能的完整代码框架:
#include <BLEDevice.h> #include <BLEUtils.h> #include <BLEServer.h> BLECharacteristic *pCharacteristic; bool deviceConnected = false; class MyServerCallbacks: public BLEServerCallbacks { void onConnect(BLEServer* pServer) { deviceConnected = true; } void onDisconnect(BLEServer* pServer) { deviceConnected = false; } }; class MyCallbacks: public BLECharacteristicCallbacks { void onWrite(BLECharacteristic *pCharacteristic) { std::string value = pCharacteristic->getValue(); if (value.length() > 0) { Serial.println("Received: "); for (int i = 0; i < value.length(); i++) Serial.print(value[i]); Serial.println(); } } }; void setup() { Serial.begin(115200); BLEDevice::init("ESP32_BLE_Device"); BLEServer *pServer = BLEDevice::createServer(); pServer->setCallbacks(new MyServerCallbacks()); BLEService *pService = pServer->createService(SERVICE_UUID); pCharacteristic = pService->createCharacteristic( CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_NOTIFY ); pCharacteristic->setCallbacks(new MyCallbacks()); pService->start(); BLEAdvertising *pAdvertising = BLEDevice::getAdvertising(); pAdvertising->addServiceUUID(SERVICE_UUID); pAdvertising->setScanResponse(true); pAdvertising->setMinPreferred(0x06); pAdvertising->setMinPreferred(0x12); BLEDevice::startAdvertising(); Serial.println("Waiting for a client connection..."); } void loop() { if (deviceConnected) { // 可以在此处添加定期发送数据的逻辑 delay(1000); } }5. 数据格式处理与常见问题排查
在BLE通信中,数据格式的一致性至关重要。APP Inventor和ESP32必须就数据类型达成一致,否则会出现乱码或解析失败。以下是几种常见的数据格式处理方式:
字符串传输:
- APP Inventor端直接发送文本
- ESP32端使用
getValue()获取std::string
字节数组传输:
- APP Inventor端使用
BluetoothLE1.WriteBytes方法 - ESP32端通过
pCharacteristic->getData()获取uint8_t数组
- APP Inventor端使用
常见问题排查清单:
设备无法发现:
- 检查ESP32是否在广播状态(查看串口输出)
- 确认手机蓝牙已开启
- 确保没有其他设备占用了相同的UUID
连接后立即断开:
- 检查Service和Characteristic UUID是否匹配
- 确认ESP32端的服务已正确启动(
pService->start())
数据接收不全或乱码:
- 两端使用相同的数据格式(同为字符串或字节数组)
- 检查发送和接收的编码格式(推荐使用UTF-8)
6. 实战案例:手机控制ESP32 LED
让我们通过一个具体案例来整合前面学到的知识——用手机APP控制ESP32板载LED的开关。
ESP32端新增代码:
// 在setup()中添加 pinMode(LED_BUILTIN, OUTPUT); // 在MyCallbacks类的onWrite方法中添加 if (value == "ON") { digitalWrite(LED_BUILTIN, HIGH); } else if (value == "OFF") { digitalWrite(LED_BUILTIN, LOW); }APP Inventor界面调整:
- 添加两个按钮,分别设置其文本为"开灯"和"关灯"
- 按钮点击事件分别发送"ON"和"OFF"字符串
当 按钮开灯.点击 调用 BluetoothLE1.WriteString 服务UUID "4fafc201..." 特征UUID "beb5483e..." 值 "ON" 结束 当 按钮关灯.点击 调用 BluetoothLE1.WriteString 服务UUID "4fafc201..." 特征UUID "beb5483e..." 值 "OFF" 结束在实际测试中,我发现当通信距离超过10米时,BLE连接会变得不稳定。这时可以通过增加ESP32的发射功率来改善:
// 在setup()中startAdvertising之前添加 esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV, ESP_PWR_LVL_P9); esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_SCAN, ESP_PWR_LVL_P9);