# BluFi蓝牙配网小程序开发需求说明书

## 1. 项目概述

### 1.1 项目背景
本项目需要开发一个微信小程序，用于与ESP32设备进行BluFi蓝牙配网。该小程序需要完全兼容ESP官方的espblufi应用程序功能，能够成功进行WiFi配网并返回配网成功报告。

### 1.2 项目目标
- 开发微信小程序，实现BluFi蓝牙配网功能
- 与ESP32设备建立稳定的蓝牙连接
- 完成WiFi网络配置和连接验证
- 提供用户友好的配网界面和状态反馈
- 确保与官方espblufi应用程序的完全兼容性

### 1.3 设备端配置信息
基于项目代码分析，设备端配置如下：

```javascript
// 设备端配置参数（来自bluetooth_provisioning_config.h）
const DEVICE_CONFIG = {
    // 设备名称配置
    DEFAULT_DEVICE_NAME: "Airhub_Ble",
    MAX_DEVICE_NAME_LEN: 32,
    
    // 超时配置
    ADV_TIMEOUT_MS: 0,  // 永不超时
    CLIENT_TIMEOUT_MS: 5 * 60 * 1000,  // 5分钟
    WIFI_TIMEOUT_MS: 100 * 1000,  // 100秒
    WIFI_MAX_RETRY: 5,
    
    // 安全配置
    SECURITY_ENABLED: false,
    REQUIRE_PAIRING: false,
    PSK: "Airhub2025",
    
    // 功能开关
    ENABLE_WIFI_SCAN: true,
    AUTO_REPORT_STATUS: true,
    AUTO_STOP_ON_SUCCESS: true,
    AUTO_STOP_DELAY_MS: 5000
};
```

## 2. 技术架构

### 2.1 系统架构图
```
微信小程序 <---> 蓝牙BLE <---> ESP32设备 <---> WiFi网络
    ↓              ↓              ↓
用户界面        BluFi协议      WiFi连接
状态管理        数据加密       网络验证
```

### 2.2 设备端架构
基于`bluetooth_provisioning.h`和`bluetooth_provisioning.cc`分析：

```javascript
// 设备端状态枚举（对应C++代码）
const BluetoothProvisioningState = {
    IDLE: 0,           // 空闲状态，未启动配网
    INITIALIZING: 1,   // 初始化中，正在初始化蓝牙和BluFi服务
    ADVERTISING: 2,    // 广播中，等待手机客户端连接
    CONNECTED: 3,      // 已连接，手机客户端已连接到设备
    PROVISIONING: 4,   // 配网中，正在接收和处理WiFi凭据
    SUCCESS: 5,        // 配网成功，WiFi连接建立成功
    FAILED: 6,         // 配网失败，WiFi连接失败或其他错误
    STOPPED: 7         // 已停止，配网服务已停止
};

// 设备端事件类型（对应C++代码）
const BluetoothProvisioningEvent = {
    STATE_CHANGED: 0,      // 状态改变事件，配网状态发生变化
    WIFI_CREDENTIALS: 1,   // 收到WiFi凭据事件，从手机接收到WiFi信息
    WIFI_CONNECTED: 2,     // WiFi连接成功事件，设备成功连接到WiFi网络
    WIFI_FAILED: 3,        // WiFi连接失败事件，设备连接WiFi失败
    CLIENT_CONNECTED: 4,   // 客户端连接事件，手机客户端连接到设备
    CLIENT_DISCONNECTED: 5 // 客户端断开事件，手机客户端断开连接
};
```

### 2.3 技术栈
- **前端**: 微信小程序框架
- **通讯协议**: BluFi (基于BLE)
- **设备端**: ESP-IDF BluFi组件
- **加密**: 可选AES加密（当前项目未启用）

## 3. BluFi协议详解

### 3.1 协议概述
BluFi是乐鑫开发的基于蓝牙通道的WiFi网络配置协议，通过安全的蓝牙连接传输WiFi凭据。

### 3.2 GATT服务和特征值

#### 3.2.1 BluFi服务UUID（ESP32标准）
```javascript
// BluFi GATT服务和特征值UUID
const BLUFI_SERVICE_UUID = "0000FFFF-0000-1000-8000-00805F9B34FB";
const BLUFI_CHAR_P2E_UUID = "0000FF01-0000-1000-8000-00805F9B34FB"; // 手机到设备（写）
const BLUFI_CHAR_E2P_UUID = "0000FF02-0000-1000-8000-00805F9B34FB"; // 设备到手机（通知）
```

#### 3.2.2 设备发现和命名规则
```javascript
// 设备名称识别（基于项目配置）
function isValidBluFiDevice(device) {
    // 检查设备名称是否符合项目规范
    const validNames = [
        "Airhub_Ble",     // 默认名称
        "XiaoZhi-AI"      // 备用名称
    ];
    
    return device.name && (
        validNames.includes(device.name) ||
        device.name.startsWith("Airhub-") ||
        device.name.startsWith("XiaoZhi-")
    );
}
```

### 3.3 数据包格式

#### 3.3.1 BluFi数据包结构
```javascript
// BluFi数据包格式（基于ESP-IDF实现）
class BluFiPacket {
    constructor() {
        this.type = 0x00;        // 数据包类型 (1字节)
        this.fc = 0x00;          // 帧控制 (1字节)
        this.sequence = 0x0000;  // 序列号 (2字节)
        this.length = 0x0000;    // 数据长度 (2字节)
        this.data = [];          // 数据内容 (变长)
        this.checksum = 0x0000;  // 校验和 (2字节)
    }
    
    // 构建数据包
    build(type, subtype, data = null) {
        const dataLength = data ? data.length : 0;
        const totalLength = 8 + dataLength;
        const buffer = new ArrayBuffer(totalLength);
        const view = new DataView(buffer);
        
        // 设置包头
        view.setUint8(0, type);                    // 类型
        view.setUint8(1, subtype);                 // 子类型  
        view.setUint16(2, this.sequence, true);    // 序列号（小端）
        view.setUint16(4, dataLength, true);       // 数据长度（小端）
        
        // 设置数据
        if (data && dataLength > 0) {
            const dataView = new Uint8Array(buffer, 6);
            dataView.set(new Uint8Array(data));
        }
        
        // 计算并设置校验和
        const checksum = this.calculateChecksum(buffer, totalLength - 2);
        view.setUint16(totalLength - 2, checksum, true);
        
        this.sequence++;
        return buffer;
    }
    
    // 计算校验和
    calculateChecksum(buffer, length) {
        let checksum = 0;
        const view = new Uint8Array(buffer);
        
        for (let i = 0; i < length; i++) {
            checksum += view[i];
        }
        
        return checksum & 0xFFFF;
    }
    
    // 解析数据包
    parse(buffer) {
        const view = new DataView(buffer);
        
        return {
            type: view.getUint8(0),
            subtype: view.getUint8(1),
            sequence: view.getUint16(2, true),
            length: view.getUint16(4, true),
            data: buffer.slice(6, 6 + view.getUint16(4, true)),
            checksum: view.getUint16(buffer.byteLength - 2, true)
        };
    }
}
```

#### 3.3.2 数据包类型定义
```javascript
// 控制包类型（基于ESP-IDF BluFi实现）
const BLUFI_TYPE_CTRL = {
    ACK: 0x00,                   // 确认包
    SET_SEC_MODE: 0x01,          // 设置安全模式
    SET_WIFI_OPMODE: 0x02,       // 设置WiFi操作模式
    CONNECT_WIFI: 0x03,          // 连接WiFi
    DISCONNECT_WIFI: 0x04,       // 断开WiFi
    GET_WIFI_STATUS: 0x05,       // 获取WiFi状态
    DEAUTHENTICATE: 0x06,        // 取消认证
    GET_VERSION: 0x07,           // 获取版本
    CLOSE_CONNECTION: 0x08,      // 关闭连接
    GET_WIFI_LIST: 0x09          // 获取WiFi列表
};

// 数据包类型（基于ESP-IDF BluFi实现）
const BLUFI_TYPE_DATA = {
    NEG: 0x00,                  // 协商数据
    STA_BSSID: 0x01,            // STA BSSID
    STA_SSID: 0x02,             // STA SSID
    STA_PASSWD: 0x03,           // STA 密码
    SOFTAP_SSID: 0x04,          // SoftAP SSID
    SOFTAP_PASSWD: 0x05,        // SoftAP 密码
    SOFTAP_MAX_CONN: 0x06,      // SoftAP最大连接数
    SOFTAP_AUTH_MODE: 0x07,     // SoftAP认证模式
    SOFTAP_CHANNEL: 0x08,       // SoftAP信道
    USERNAME: 0x09,             // 用户名
    CA_CERT: 0x0A,              // CA证书
    CLIENT_CERT: 0x0B,          // 客户端证书
    SERVER_CERT: 0x0C,          // 服务器证书
    CLIENT_PRIV_KEY: 0x0D,      // 客户端私钥
    SERVER_PRIV_KEY: 0x0E,      // 服务器私钥
    WIFI_REP: 0x0F,             // WiFi报告
    WIFI_LIST: 0x10             // WiFi列表
};

// 包类型标识
const BLUFI_FC_ENC = 0x01;      // 加密标志
const BLUFI_FC_CHECK = 0x02;    // 校验标志
const BLUFI_FC_DATA_DIR = 0x04; // 数据方向标志
const BLUFI_FC_REQUIRE_ACK = 0x08; // 需要确认标志
```

## 4. 配网流程详细实现

### 4.1 第一阶段：蓝牙初始化和设备扫描

#### 4.1.1 小程序端实现
```javascript
// 蓝牙配网管理类
class BluFiProvisioning {
    constructor() {
        this.deviceId = null;
        this.serviceId = null;
        this.writeCharacteristicId = null;
        this.notifyCharacteristicId = null;
        this.sequenceNumber = 0;
        this.isConnected = false;
        this.provisioningState = 'idle';
        this.packet = new BluFiPacket();
    }
    
    // 初始化蓝牙适配器
    async initBluetooth() {
        try {
            console.log('初始化蓝牙适配器...');
            
            await new Promise((resolve, reject) => {
                wx.openBluetoothAdapter({
                    success: (res) => {
                        console.log('蓝牙适配器初始化成功:', res);
                        resolve(res);
                    },
                    fail: (err) => {
                        console.error('蓝牙适配器初始化失败:', err);
                        reject(new Error(`蓝牙初始化失败: ${err.errMsg}`));
                    }
                });
            });
            
            // 检查蓝牙状态
            await this.checkBluetoothState();
            
            return true;
        } catch (error) {
            console.error('蓝牙初始化异常:', error);
            throw error;
        }
    }
    
    // 检查蓝牙状态
    async checkBluetoothState() {
        return new Promise((resolve, reject) => {
            wx.getBluetoothAdapterState({
                success: (res) => {
                    console.log('蓝牙状态:', res);
                    if (!res.available) {
                        reject(new Error('蓝牙不可用'));
                    } else if (!res.discovering) {
                        console.log('蓝牙可用，准备扫描设备');
                        resolve(res);
                    } else {
                        resolve(res);
                    }
                },
                fail: (err) => {
                    reject(new Error(`获取蓝牙状态失败: ${err.errMsg}`));
                }
            });
        });
    }
    
    // 扫描BluFi设备
    async startScan(onDeviceFound) {
        try {
            console.log('开始扫描BluFi设备...');
            
            // 监听设备发现事件
            wx.onBluetoothDeviceFound((res) => {
                res.devices.forEach(device => {
                    console.log('发现设备:', device);
                    
                    // 检查是否为BluFi设备
                    if (this.isValidBluFiDevice(device)) {
                        console.log('发现BluFi设备:', device.name, device.deviceId);
                        onDeviceFound && onDeviceFound(device);
                    }
                });
            });
            
            // 开始扫描
            await new Promise((resolve, reject) => {
                wx.startBluetoothDevicesDiscovery({
                    services: [BLUFI_SERVICE_UUID],
                    allowDuplicatesKey: false,
                    interval: 0,
                    success: (res) => {
                        console.log('开始扫描设备成功:', res);
                        resolve(res);
                    },
                    fail: (err) => {
                        console.error('开始扫描设备失败:', err);
                        reject(new Error(`扫描失败: ${err.errMsg}`));
                    }
                });
            });
            
            return true;
        } catch (error) {
            console.error('扫描设备异常:', error);
            throw error;
        }
    }
    
    // 停止扫描
    async stopScan() {
        return new Promise((resolve) => {
            wx.stopBluetoothDevicesDiscovery({
                success: (res) => {
                    console.log('停止扫描成功:', res);
                    resolve(res);
                },
                fail: (err) => {
                    console.warn('停止扫描失败:', err);
                    resolve(); // 即使失败也继续
                }
            });
        });
    }
    
    // 验证是否为有效的BluFi设备
    isValidBluFiDevice(device) {
        if (!device.name) return false;
        
        const validNames = [
            "Airhub_Ble",     // 项目默认名称
            "XiaoZhi-AI"      // 备用名称
        ];
        
        return validNames.includes(device.name) ||
               device.name.startsWith("Airhub-") ||
               device.name.startsWith("XiaoZhi-");
    }
}
```

#### 4.1.2 设备扫描页面实现
```xml
<!-- pages/scan/scan.wxml -->
<view class="scan-container">
    <view class="scan-header">
        <text class="title">扫描BluFi设备</text>
        <text class="subtitle">请确保设备处于配网模式</text>
    </view>
    
    <view class="scan-status">
        <view wx:if="{{scanning}}" class="scanning">
            <view class="loading-icon"></view>
            <text>正在扫描设备...</text>
        </view>
        <button wx:else class="scan-btn" bindtap="startScan">开始扫描</button>
    </view>
    
    <view class="device-list">
        <view class="device-item" wx:for="{{devices}}" wx:key="deviceId" bindtap="selectDevice" data-device="{{item}}">
            <view class="device-info">
                <view class="device-name">{{item.name}}</view>
                <view class="device-id">{{item.deviceId}}</view>
                <view class="device-signal">信号强度: {{item.RSSI}}dBm</view>
            </view>
            <view class="device-action">
                <text class="connect-btn">连接</text>
            </view>
        </view>
    </view>
    
    <view wx:if="{{devices.length === 0 && !scanning}}" class="empty-state">
        <text>未发现设备，请检查设备是否开启配网模式</text>
    </view>
</view>
```

```javascript
// pages/scan/scan.js
Page({
    data: {
        scanning: false,
        devices: []
    },
    
    onLoad() {
        this.blufi = new BluFiProvisioning();
        this.initBluetooth();
    },
    
    async initBluetooth() {
        try {
            await this.blufi.initBluetooth();
            console.log('蓝牙初始化完成');
        } catch (error) {
            wx.showToast({
                title: '蓝牙初始化失败',
                icon: 'error'
            });
            console.error('蓝牙初始化失败:', error);
        }
    },
    
    async startScan() {
        if (this.data.scanning) return;
        
        this.setData({ 
            scanning: true,
            devices: []
        });
        
        try {
            await this.blufi.startScan((device) => {
                // 检查设备是否已存在
                const exists = this.data.devices.find(d => d.deviceId === device.deviceId);
                if (!exists) {
                    this.setData({
                        devices: [...this.data.devices, device]
                    });
                }
            });
            
            // 30秒后自动停止扫描
            setTimeout(() => {
                this.stopScan();
            }, 30000);
            
        } catch (error) {
            this.setData({ scanning: false });
            wx.showToast({
                title: '扫描失败',
                icon: 'error'
            });
            console.error('扫描失败:', error);
        }
    },
    
    async stopScan() {
        if (!this.data.scanning) return;
        
        try {
            await this.blufi.stopScan();
            this.setData({ scanning: false });
        } catch (error) {
            console.error('停止扫描失败:', error);
        }
    },
    
    selectDevice(e) {
        const device = e.currentTarget.dataset.device;
        console.log('选择设备:', device);
        
        // 停止扫描
        this.stopScan();
        
        // 跳转到连接页面
        wx.navigateTo({
            url: `/pages/connect/connect?deviceId=${device.deviceId}&deviceName=${device.name}`
        });
    },
    
    onUnload() {
        this.stopScan();
    }
});
```

### 4.2 第二阶段：设备连接和GATT服务发现

#### 4.2.1 连接设备实现
```javascript
// 在BluFiProvisioning类中添加连接方法
class BluFiProvisioning {
    // ... 前面的代码 ...
    
    // 连接设备
    async connectDevice(deviceId) {
        try {
            console.log('连接设备:', deviceId);
            this.deviceId = deviceId;
            
            // 建立BLE连接
            await new Promise((resolve, reject) => {
                wx.createBLEConnection({
                    deviceId: deviceId,
                    success: (res) => {
                        console.log('设备连接成功:', res);
                        this.isConnected = true;
                        resolve(res);
                    },
                    fail: (err) => {
                        console.error('设备连接失败:', err);
                        reject(new Error(`连接失败: ${err.errMsg}`));
                    }
                });
            });
            
            // 发现服务
            await this.discoverServices();
            
            // 发现特征值
            await this.discoverCharacteristics();
            
            // 启用通知
            await this.enableNotifications();
            
            console.log('设备连接和初始化完成');
            return true;
            
        } catch (error) {
            console.error('连接设备异常:', error);
            this.isConnected = false;
            throw error;
        }
    }
    
    // 自动发现GATT服务
    async discoverServices() {
        return new Promise((resolve, reject) => {
            wx.getBLEDeviceServices({
                deviceId: this.deviceId,
                success: (res) => {
                    console.log('发现服务:', res.services);
                    
                    // 查找BluFi服务
                    const blufiService = res.services.find(service => 
                        service.uuid.toUpperCase() === BLUFI_SERVICE_UUID.toUpperCase()
                    );
                    
                    if (blufiService) {
                        this.serviceId = blufiService.uuid;
                        console.log('找到BluFi服务:', this.serviceId);
                        resolve(blufiService);
                    } else {
                        reject(new Error('未找到BluFi服务'));
                    }
                },
                fail: (err) => {
                    console.error('发现服务失败:', err);
                    reject(new Error(`发现服务失败: ${err.errMsg}`));
                }
            });
        });
    }
    
    // 自动发现特征值
    async discoverCharacteristics() {
        return new Promise((resolve, reject) => {
            wx.getBLEDeviceCharacteristics({
                deviceId: this.deviceId,
                serviceId: this.serviceId,
                success: (res) => {
                    console.log('发现特征值:', res.characteristics);
                    
                    // 查找写特征值（手机到设备）
                    const writeChar = res.characteristics.find(char => 
                        char.uuid.toUpperCase() === BLUFI_CHAR_P2E_UUID.toUpperCase()
                    );
                    
                    // 查找通知特征值（设备到手机）
                    const notifyChar = res.characteristics.find(char => 
                        char.uuid.toUpperCase() === BLUFI_CHAR_E2P_UUID.toUpperCase()
                    );
                    
                    if (writeChar && notifyChar) {
                        this.writeCharacteristicId = writeChar.uuid;
                        this.notifyCharacteristicId = notifyChar.uuid;
                        console.log('找到BluFi特征值:');
                        console.log('写特征值:', this.writeCharacteristicId);
                        console.log('通知特征值:', this.notifyCharacteristicId);
                        resolve({ writeChar, notifyChar });
                    } else {
                        reject(new Error('未找到BluFi特征值'));
                    }
                },
                fail: (err) => {
                    console.error('发现特征值失败:', err);
                    reject(new Error(`发现特征值失败: ${err.errMsg}`));
                }
            });
        });
    }
    
    // 启用通知
    async enableNotifications() {
        return new Promise((resolve, reject) => {
            // 监听特征值变化
            wx.onBLECharacteristicValueChange((res) => {
                console.log('收到设备数据:', res);
                this.handleDeviceData(res.value);
            });
            
            // 启用通知
            wx.notifyBLECharacteristicValueChange({
                deviceId: this.deviceId,
                serviceId: this.serviceId,
                characteristicId: this.notifyCharacteristicId,
                state: true,
                success: (res) => {
                    console.log('启用通知成功:', res);
                    resolve(res);
                },
                fail: (err) => {
                    console.error('启用通知失败:', err);
                    reject(new Error(`启用通知失败: ${err.errMsg}`));
                }
            });
        });
    }
    
    // 处理设备数据
    handleDeviceData(buffer) {
        try {
            const packet = this.packet.parse(buffer);
            console.log('解析数据包:', packet);
            
            // 根据数据包类型处理
            switch (packet.type) {
                case 0x00: // 控制包
                    this.handleControlPacket(packet);
                    break;
                case 0x01: // 数据包
                    this.handleDataPacket(packet);
                    break;
                default:
                    console.warn('未知数据包类型:', packet.type);
            }
        } catch (error) {
            console.error('处理设备数据失败:', error);
        }
    }
    
    // 处理控制包
    handleControlPacket(packet) {
        switch (packet.subtype) {
            case BLUFI_TYPE_CTRL.ACK:
                console.log('收到确认包');
                break;
            case BLUFI_TYPE_CTRL.GET_WIFI_STATUS:
                console.log('设备请求WiFi状态');
                break;
            default:
                console.log('收到控制包:', packet.subtype);
        }
    }
    
    // 处理数据包
    handleDataPacket(packet) {
        switch (packet.subtype) {
            case BLUFI_TYPE_DATA.WIFI_REP:
                this.handleWiFiReport(packet.data);
                break;
            case BLUFI_TYPE_DATA.WIFI_LIST:
                this.handleWiFiList(packet.data);
                break;
            default:
                console.log('收到数据包:', packet.subtype);
        }
    }
    
    // 处理WiFi连接报告
    handleWiFiReport(data) {
        if (data.byteLength >= 2) {
            const view = new DataView(data);
            const status = view.getUint8(0);
            const reason = view.getUint8(1);
            
            console.log('WiFi连接报告 - 状态:', status, '原因:', reason);
            
            if (status === 0) {
                // 连接成功
                this.provisioningState = 'success';
                this.onProvisioningSuccess && this.onProvisioningSuccess();
            } else {
                // 连接失败
                this.provisioningState = 'failed';
                this.onProvisioningFailed && this.onProvisioningFailed(reason);
            }
        }
    }
    
    // 断开连接
    async disconnect() {
        if (!this.isConnected || !this.deviceId) return;
        
        try {
            await new Promise((resolve) => {
                wx.closeBLEConnection({
                    deviceId: this.deviceId,
                    success: (res) => {
                        console.log('断开连接成功:', res);
                        resolve(res);
                    },
                    fail: (err) => {
                        console.warn('断开连接失败:', err);
                        resolve(); // 即使失败也继续
                    }
                });
            });
            
            this.isConnected = false;
            this.deviceId = null;
            this.serviceId = null;
            this.writeCharacteristicId = null;
            this.notifyCharacteristicId = null;
            
        } catch (error) {
            console.error('断开连接异常:', error);
        }
    }
}
```

#### 4.2.2 连接页面实现
```xml
<!-- pages/connect/connect.wxml -->
<view class="connect-container">
    <view class="connect-header">
        <text class="title">连接设备</text>
        <view class="device-info">
            <text class="device-name">{{deviceName}}</text>
            <text class="device-id">{{deviceId}}</text>
        </view>
    </view>
    
    <view class="connect-status">
        <view wx:if="{{connecting}}" class="connecting">
            <view class="loading-icon"></view>
            <text>正在连接设备...</text>
        </view>
        
        <view wx:elif="{{connected}}" class="connected">
            <view class="success-icon">✓</view>
            <text>设备连接成功</text>
            <button class="next-btn" bindtap="goToConfig">开始配网</button>
        </view>
        
        <view wx:else class="disconnected">
            <text>设备未连接</text>
            <button class="retry-btn" bindtap="connectDevice">重新连接</button>
        </view>
    </view>
    
    <view class="connect-steps">
        <view class="step {{step >= 1 ? 'active' : ''}}">
            <view class="step-number">1</view>
            <text>建立BLE连接</text>
        </view>
        <view class="step {{step >= 2 ? 'active' : ''}}">
            <view class="step-number">2</view>
            <text>发现GATT服务</text>
        </view>
        <view class="step {{step >= 3 ? 'active' : ''}}">
            <view class="step-number">3</view>
            <text>初始化特征值</text>
        </view>
        <view class="step {{step >= 4 ? 'active' : ''}}">
            <view class="step-number">4</view>
            <text>启用数据通知</text>
        </view>
    </view>
</view>
```

```javascript
// pages/connect/connect.js
Page({
    data: {
        deviceId: '',
        deviceName: '',
        connecting: false,
        connected: false,
        step: 0
    },
    
    onLoad(options) {
        this.setData({
            deviceId: options.deviceId,
            deviceName: options.deviceName
        });
        
        this.blufi = new BluFiProvisioning();
        this.connectDevice();
    },
    
    async connectDevice() {
        if (this.data.connecting) return;
        
        this.setData({ 
            connecting: true,
            connected: false,
            step: 0
        });
        
        try {
            // 步骤1：建立BLE连接
            this.setData({ step: 1 });
            await new Promise(resolve => setTimeout(resolve, 500)); // 显示进度
            
            // 步骤2：发现GATT服务
            this.setData({ step: 2 });
            await new Promise(resolve => setTimeout(resolve, 500));
            
            // 步骤3：初始化特征值
            this.setData({ step: 3 });
            await new Promise(resolve => setTimeout(resolve, 500));
            
            // 步骤4：启用数据通知
            this.setData({ step: 4 });
            
            // 执行实际连接
            await this.blufi.connectDevice(this.data.deviceId);
            
            this.setData({ 
                connecting: false,
                connected: true
            });
            
            wx.showToast({
                title: '连接成功',
                icon: 'success'
            });
            
        } catch (error) {
            this.setData({ 
                connecting: false,
                connected: false,
                step: 0
            });
            
            wx.showToast({
                title: '连接失败',
                icon: 'error'
            });
            
            console.error('连接设备失败:', error);
        }
    },
    
    goToConfig() {
        if (!this.data.connected) return;
        
        // 跳转到WiFi配置页面
        wx.navigateTo({
            url: '/pages/config/config'
        });
    },
    
    onUnload() {
        // 页面卸载时断开连接
        if (this.blufi) {
            this.blufi.disconnect();
        }
    }
});
```

### 4.3 第三阶段：WiFi扫描和网络选择

#### 4.3.1 WiFi扫描实现
```javascript
// 在BluFiProvisioning类中添加WiFi扫描方法
class BluFiProvisioning {
    // ... 前面的代码 ...
    
    // 请求WiFi扫描
    async requestWiFiScan() {
        try {
            console.log('请求设备扫描WiFi...');
            
            // 构建获取WiFi列表的控制包
            const packet = this.packet.build(0x00, BLUFI_TYPE_CTRL.GET_WIFI_LIST);
            
            // 发送数据包
            await this.sendData(packet);
            
            console.log('WiFi扫描请求已发送');
            return true;
            
        } catch (error) {
            console.error('请求WiFi扫描失败:', error);
            throw error;
        }
    }
    
    // 发送数据到设备
    async sendData(buffer) {
        if (!this.isConnected || !this.deviceId || !this.writeCharacteristicId) {
            throw new Error('设备未连接或特征值未初始化');
        }
        
        return new Promise((resolve, reject) => {
            wx.writeBLECharacteristicValue({
                deviceId: this.deviceId,
                serviceId: this.serviceId,
                characteristicId: this.writeCharacteristicId,
                value: buffer,
                success: (res) => {
                    console.log('数据发送成功:', res);
                    resolve(res);
                },
                fail: (err) => {
                    console.error('数据发送失败:', err);
                    reject(new Error(`发送失败: ${err.errMsg}`));
                }
            });
        });
    }
    
    // 处理WiFi列表
    handleWiFiList(data) {
        try {
            console.log('收到WiFi列表数据:', data);
            
            // 解析WiFi列表数据
            const wifiList = this.parseWiFiList(data);
            console.log('解析的WiFi列表:', wifiList);
            
            // 触发回调
            this.onWiFiListReceived && this.onWiFiListReceived(wifiList);
            
        } catch (error) {
            console.error('处理WiFi列表失败:', error);
        }
    }
    
    // 解析WiFi列表数据
    parseWiFiList(data) {
        const wifiList = [];
        const view = new DataView(data);
        let offset = 0;
        
        try {
            while (offset < data.byteLength) {
                // 读取SSID长度
                if (offset >= data.byteLength) break;
                const ssidLength = view.getUint8(offset);
                offset += 1;
                
                if (ssidLength === 0 || offset + ssidLength > data.byteLength) break;
                
                // 读取SSID
                const ssidBytes = new Uint8Array(data, offset, ssidLength);
                const ssid = new TextDecoder('utf-8').decode(ssidBytes);
                offset += ssidLength;
                
                // 读取RSSI（信号强度）
                if (offset >= data.byteLength) break;
                const rssi = view.getInt8(offset);
                offset += 1;
                
                // 读取认证模式
                if (offset >= data.byteLength) break;
                const authMode = view.getUint8(offset);
                offset += 1;
                
                wifiList.push({
                    ssid: ssid,
                    rssi: rssi,
                    authMode: authMode,
                    security: this.getSecurityType(authMode)
                });
            }
        } catch (error) {
            console.error('解析WiFi列表数据异常:', error);
        }
        
        return wifiList;
    }
    
    // 获取安全类型描述
    getSecurityType(authMode) {
        const securityTypes = {
            0: 'OPEN',
            1: 'WEP',
            2: 'WPA_PSK',
            3: 'WPA2_PSK',
            4: 'WPA_WPA2_PSK',
            5: 'WPA2_ENTERPRISE',
            6: 'WPA3_PSK',
            7: 'WPA2_WPA3_PSK'
        };
        
        return securityTypes[authMode] || 'UNKNOWN';
    }
}
```

#### 4.3.2 WiFi配置页面实现
```xml
<!-- pages/config/config.wxml -->
<view class="config-container">
    <view class="config-header">
        <text class="title">WiFi配置</text>
        <text class="subtitle">选择要连接的WiFi网络</text>
    </view>
    
    <!-- WiFi扫描区域 -->
    <view class="scan-section">
        <view class="scan-header">
            <text>可用网络</text>
            <button class="scan-btn" bindtap="scanWiFi" disabled="{{scanning}}">
                {{scanning ? '扫描中...' : '刷新'}}
            </button>
        </view>
        
        <view class="wifi-list">
            <view class="wifi-item" wx:for="{{wifiList}}" wx:key="ssid" bindtap="selectWiFi" data-wifi="{{item}}">
                <view class="wifi-info">
                    <view class="wifi-name">{{item.ssid}}</view>
                    <view class="wifi-details">
                        <text class="wifi-signal">{{item.rssi}}dBm</text>
                        <text class="wifi-security">{{item.security}}</text>
                    </view>
                </view>
                <view class="wifi-icon">
                    <text class="signal-icon">📶</text>
                </view>
            </view>
        </view>
        
        <view wx:if="{{wifiList.length === 0 && !scanning}}" class="empty-wifi">
            <text>未发现WiFi网络，请点击刷新重新扫描</text>
        </view>
    </view>
    
    <!-- 手动输入区域 -->
    <view class="manual-section">
        <view class="section-title">或手动输入WiFi信息</view>
        
        <form bindsubmit="submitWiFiConfig">
            <view class="form-group">
                <label>WiFi名称 (SSID)</label>
                <input name="ssid" placeholder="请输入WiFi名称" value="{{selectedSSID}}" bindinput="onSSIDInput"/>
            </view>
            
            <view class="form-group">
                <label>WiFi密码</label>
                <input name="password" type="password" placeholder="请输入WiFi密码" value="{{wifiPassword}}" bindinput="onPasswordInput"/>
            </view>
            
            <view class="form-actions">
                <button form-type="submit" class="config-btn" disabled="{{!canSubmit}}">
                    开始配网
                </button>
            </view>
        </form>
    </view>
</view>
```

```javascript
// pages/config/config.js
Page({
    data: {
        scanning: false,
        wifiList: [],
        selectedSSID: '',
        wifiPassword: '',
        canSubmit: false
    },
    
    onLoad() {
        // 获取全局的BluFi实例
        const app = getApp();
        this.blufi = app.globalData.blufi;
        
        if (!this.blufi || !this.blufi.isConnected) {
            wx.showToast({
                title: '设备未连接',
                icon: 'error'
            });
            wx.navigateBack();
            return;
        }
        
        // 设置WiFi列表接收回调
        this.blufi.onWiFiListReceived = (wifiList) => {
            console.log('收到WiFi列表:', wifiList);
            this.setData({ 
                wifiList: wifiList,
                scanning: false
            });
        };
        
        // 自动扫描WiFi
        this.scanWiFi();
    },
    
    async scanWiFi() {
        if (this.data.scanning) return;
        
        this.setData({ 
            scanning: true,
            wifiList: []
        });
        
        try {
            await this.blufi.requestWiFiScan();
            
            // 设置超时
            setTimeout(() => {
                if (this.data.scanning) {
                    this.setData({ scanning: false });
                    wx.showToast({
                        title: '扫描超时',
                        icon: 'none'
                    });
                }
            }, 15000); // 15秒超时
            
        } catch (error) {
            this.setData({ scanning: false });
            wx.showToast({
                title: '扫描失败',
                icon: 'error'
            });
            console.error('WiFi扫描失败:', error);
        }
    },
    
    selectWiFi(e) {
        const wifi = e.currentTarget.dataset.wifi;
        console.log('选择WiFi:', wifi);
        
        this.setData({ 
            selectedSSID: wifi.ssid,
            wifiPassword: '' // 清空密码
        });
        
        this.checkCanSubmit();
    },
    
    onSSIDInput(e) {
        this.setData({ selectedSSID: e.detail.value });
        this.checkCanSubmit();
    },
    
    onPasswordInput(e) {
        this.setData({ wifiPassword: e.detail.value });
        this.checkCanSubmit();
    },
    
    checkCanSubmit() {
        const canSubmit = this.data.selectedSSID.trim().length > 0;
        this.setData({ canSubmit });
    },
    
    submitWiFiConfig(e) {
        const formData = e.detail.value;
        const ssid = formData.ssid || this.data.selectedSSID;
        const password = formData.password || this.data.wifiPassword;
        
        if (!ssid.trim()) {
            wx.showToast({
                title: '请输入WiFi名称',
                icon: 'none'
            });
            return;
        }
        
        console.log('提交WiFi配置:', { ssid, password: '***' });
        
        // 跳转到配网状态页面
        wx.navigateTo({
            url: `/pages/status/status?ssid=${encodeURIComponent(ssid)}&password=${encodeURIComponent(password)}`
        });
    }
});
```

### 4.4 第四阶段：WiFi凭据传输和连接确认

#### 4.4.1 WiFi凭据发送实现
```javascript
// 在BluFiProvisioning类中添加WiFi配网方法
class BluFiProvisioning {
    // ... 前面的代码 ...
    
    // 开始WiFi配网
    async startProvisioning(ssid, password) {
        try {
            console.log('开始WiFi配网:', ssid);
            this.provisioningState = 'provisioning';
            
            // 步骤1：发送SSID
            await this.sendWiFiSSID(ssid);
            await this.delay(500);
            
            // 步骤2：发送密码（如果有）
            if (password && password.trim().length > 0) {
                await this.sendWiFiPassword(password);
                await this.delay(500);
            }
            
            // 步骤3：发送连接命令
            await this.sendConnectWiFi();
            
            console.log('WiFi配网命令已发送，等待设备响应...');
            return true;
            
        } catch (error) {
            console.error('WiFi配网失败:', error);
            this.provisioningState = 'failed';
            throw error;
        }
    }
    
    // 发送WiFi SSID
    async sendWiFiSSID(ssid) {
        console.log('发送WiFi SSID:', ssid);
        
        const data = new TextEncoder().encode(ssid);
        const packet = this.packet.build(0x01, BLUFI_TYPE_DATA.STA_SSID, data);
        
        await this.sendData(packet);
        console.log('SSID发送完成');
    }
    
    // 发送WiFi密码
    async sendWiFiPassword(password) {
        console.log('发送WiFi密码');
        
        const data = new TextEncoder().encode(password);
        const packet = this.packet.build(0x01, BLUFI_TYPE_DATA.STA_PASSWD, data);
        
        await this.sendData(packet);
        console.log('密码发送完成');
    }
    
    // 发送连接WiFi命令
    async sendConnectWiFi() {
        console.log('发送连接WiFi命令');
        
        const packet = this.packet.build(0x00, BLUFI_TYPE_CTRL.CONNECT_WIFI);
        
        await this.sendData(packet);
        console.log('连接命令发送完成');
    }
    
    // 获取WiFi连接状态
    async getWiFiStatus() {
        console.log('请求WiFi连接状态');
        
        const packet = this.packet.build(0x00, BLUFI_TYPE_CTRL.GET_WIFI_STATUS);
        
        await this.sendData(packet);
        console.log('状态请求已发送');
    }
    
    // 延迟函数
    delay(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }
    
    // 设置配网回调
    setProvisioningCallbacks(callbacks) {
        this.onProvisioningSuccess = callbacks.onSuccess;
        this.onProvisioningFailed = callbacks.onFailed;
        this.onProvisioningProgress = callbacks.onProgress;
    }
}
```

#### 4.4.2 配网状态页面实现
```xml
<!-- pages/status/status.wxml -->
<view class="status-container">
    <view class="status-header">
        <text class="title">配网状态</text>
        <view class="wifi-info">
            <text class="wifi-name">{{ssid}}</text>
        </view>
    </view>
    
    <view class="progress-section">
        <view class="progress-circle {{provisioningState}}">
            <view wx:if="{{provisioningState === 'provisioning'}}" class="loading-animation"></view>
            <view wx:elif="{{provisioningState === 'success'}}" class="success-icon">✓</view>
            <view wx:elif="{{provisioningState === 'failed'}}" class="error-icon">✗</view>
            <view wx:else class="waiting-icon">⏳</view>
        </view>
        
        <view class="status-text">
            <text class="main-status">{{statusText}}</text>
            <text class="sub-status">{{subStatusText}}</text>
        </view>
    </view>
    
    <view class="steps-section">
        <view class="step {{step >= 1 ? 'completed' : step === 0 ? 'active' : ''}}">
            <view class="step-icon">1</view>
            <text>发送WiFi名称</text>
        </view>
        
        <view class="step {{step >= 2 ? 'completed' : step === 1 ? 'active' : ''}}">
            <view class="step-icon">2</view>
            <text>发送WiFi密码</text>
        </view>
        
        <view class="step {{step >= 3 ? 'completed' : step === 2 ? 'active' : ''}}">
            <view class="step-icon">3</view>
            <text>连接WiFi网络</text>
        </view>
        
        <view class="step {{step >= 4 ? 'completed' : step === 3 ? 'active' : ''}}">
            <view class="step-icon">4</view>
            <text>验证网络连接</text>
        </view>
    </view>
    
    <view class="actions-section">
        <button wx:if="{{provisioningState === 'success'}}" class="success-btn" bindtap="goHome">
            配网完成
        </button>
        
        <view wx:elif="{{provisioningState === 'failed'}}" class="failed-actions">
            <button class="retry-btn" bindtap="retryProvisioning">重新配网</button>
            <button class="back-btn" bindtap="goBack">返回修改</button>
        </view>
        
        <button wx:elif="{{provisioningState === 'provisioning'}}" class="cancel-btn" bindtap="cancelProvisioning">
            取消配网
        </button>
    </view>
    
    <!-- 错误信息显示 -->
    <view wx:if="{{errorMessage}}" class="error-section">
        <text class="error-title">错误信息：</text>
        <text class="error-message">{{errorMessage}}</text>
    </view>
</view>
```

```javascript
// pages/status/status.js
Page({
    data: {
        ssid: '',
        password: '',
        provisioningState: 'waiting', // waiting, provisioning, success, failed
        statusText: '准备开始配网',
        subStatusText: '请稍候...',
        step: 0,
        errorMessage: ''
    },
    
    onLoad(options) {
        this.setData({
            ssid: decodeURIComponent(options.ssid || ''),
            password: decodeURIComponent(options.password || '')
        });
        
        // 获取全局的BluFi实例
        const app = getApp();
        this.blufi = app.globalData.blufi;
        
        if (!this.blufi || !this.blufi.isConnected) {
            wx.showToast({
                title: '设备未连接',
                icon: 'error'
            });
            wx.navigateBack();
            return;
        }
        
        // 设置配网回调
        this.blufi.setProvisioningCallbacks({
            onSuccess: () => this.onProvisioningSuccess(),
            onFailed: (reason) => this.onProvisioningFailed(reason),
            onProgress: (step, message) => this.onProvisioningProgress(step, message)
        });
        
        // 开始配网
        this.startProvisioning();
    },
    
    async startProvisioning() {
        try {
            this.setData({
                provisioningState: 'provisioning',
                statusText: '正在配网',
                subStatusText: '发送WiFi信息到设备...',
                step: 0,
                errorMessage: ''
            });
            
            // 步骤1：发送SSID
            this.updateProgress(1, '发送WiFi名称...');
            await this.delay(1000);
            
            // 步骤2：发送密码
            this.updateProgress(2, '发送WiFi密码...');
            await this.delay(1000);
            
            // 步骤3：连接WiFi
            this.updateProgress(3, '设备连接WiFi网络...');
            
            // 执行实际配网
            await this.blufi.startProvisioning(this.data.ssid, this.data.password);
            
            // 等待连接结果
            this.updateProgress(4, '等待连接结果...');
            
            // 设置超时检查
            this.timeoutTimer = setTimeout(() => {
                if (this.data.provisioningState === 'provisioning') {
                    this.onProvisioningFailed('连接超时');
                }
            }, 30000); // 30秒超时
            
        } catch (error) {
             console.error('配网过程异常:', error);
             this.onProvisioningFailed(error.message || '配网失败');
         }
     },
     
     updateProgress(step, message) {
         this.setData({
             step: step,
             subStatusText: message
         });
     },
     
     onProvisioningSuccess() {
         console.log('配网成功');
         
         if (this.timeoutTimer) {
             clearTimeout(this.timeoutTimer);
             this.timeoutTimer = null;
         }
         
         this.setData({
             provisioningState: 'success',
             statusText: '配网成功',
             subStatusText: '设备已成功连接到WiFi网络',
             step: 4
         });
         
         wx.showToast({
             title: '配网成功',
             icon: 'success'
         });
     },
     
     onProvisioningFailed(reason) {
         console.error('配网失败:', reason);
         
         if (this.timeoutTimer) {
             clearTimeout(this.timeoutTimer);
             this.timeoutTimer = null;
         }
         
         this.setData({
             provisioningState: 'failed',
             statusText: '配网失败',
             subStatusText: '设备连接WiFi失败',
             errorMessage: reason || '未知错误'
         });
         
         wx.showToast({
             title: '配网失败',
             icon: 'error'
         });
     },
     
     onProvisioningProgress(step, message) {
         this.updateProgress(step, message);
     },
     
     retryProvisioning() {
         this.startProvisioning();
     },
     
     goBack() {
         wx.navigateBack();
     },
     
     goHome() {
         wx.reLaunch({
             url: '/pages/index/index'
         });
     },
     
     cancelProvisioning() {
         if (this.timeoutTimer) {
             clearTimeout(this.timeoutTimer);
             this.timeoutTimer = null;
         }
         
         this.setData({
             provisioningState: 'waiting',
             statusText: '配网已取消',
             subStatusText: '用户取消了配网操作',
             step: 0
         });
     },
     
     delay(ms) {
         return new Promise(resolve => setTimeout(resolve, ms));
     },
     
     onUnload() {
         if (this.timeoutTimer) {
             clearTimeout(this.timeoutTimer);
         }
     }
 });
 ```
 
 ## 5. 小程序项目结构
 
 ### 5.1 目录结构
 ```
 blufi-miniprogram/
 ├── app.js                 // 小程序入口文件
 ├── app.json              // 小程序配置文件
 ├── app.wxss              // 全局样式文件
 ├── project.config.json   // 项目配置文件
 ├── pages/                // 页面目录
 │   ├── index/            // 首页
 │   │   ├── index.js
 │   │   ├── index.wxml
 │   │   └── index.wxss
 │   ├── scan/             // 设备扫描页面
 │   │   ├── scan.js
 │   │   ├── scan.wxml
 │   │   └── scan.wxss
 │   ├── connect/          // 设备连接页面
 │   │   ├── connect.js
 │   │   ├── connect.wxml
 │   │   └── connect.wxss
 │   ├── config/           // WiFi配置页面
 │   │   ├── config.js
 │   │   ├── config.wxml
 │   │   └── config.wxss
 │   └── status/           // 配网状态页面
 │       ├── status.js
 │       ├── status.wxml
 │       └── status.wxss
 ├── utils/                // 工具类目录
 │   ├── blufi.js          // BluFi协议实现
 │   ├── bluetooth.js      // 蓝牙工具类
 │   └── util.js           // 通用工具函数
 └── components/           // 组件目录
     ├── loading/          // 加载组件
     └── device-item/      // 设备列表项组件
 ```
 
 ### 5.2 小程序配置文件
 
 #### 5.2.1 app.json
 ```json
 {
   "pages": [
     "pages/index/index",
     "pages/scan/scan",
     "pages/connect/connect",
     "pages/config/config",
     "pages/status/status"
   ],
   "window": {
     "backgroundTextStyle": "light",
     "navigationBarBackgroundColor": "#fff",
     "navigationBarTitleText": "BluFi配网",
     "navigationBarTextStyle": "black",
     "backgroundColor": "#f8f8f8"
   },
   "permission": {
     "scope.bluetooth": {
       "desc": "用于连接BluFi设备进行WiFi配网"
     }
   },
   "requiredBackgroundModes": ["bluetooth-central"],
   "style": "v2",
   "sitemapLocation": "sitemap.json"
 }
 ```
 
 #### 5.2.2 project.config.json
 ```json
 {
   "description": "BluFi蓝牙配网小程序",
   "packOptions": {
     "ignore": []
   },
   "setting": {
     "urlCheck": false,
     "es6": true,
     "enhance": true,
     "postcss": true,
     "preloadBackgroundData": false,
     "minified": true,
     "newFeature": false,
     "coverView": true,
     "nodeModules": false,
     "autoAudits": false,
     "showShadowRootInWxmlPanel": true,
     "scopeDataCheck": false,
     "uglifyFileName": false,
     "checkInvalidKey": true,
     "checkSiteMap": true,
     "uploadWithSourceMap": true,
     "compileHotReLoad": false,
     "lazyloadPlaceholderEnable": false,
     "useMultiFrameRuntime": true,
     "useApiHook": true,
     "useApiHostProcess": true,
     "babelSetting": {
       "ignore": [],
       "disablePlugins": [],
       "outputPath": ""
     },
     "enableEngineNative": false,
     "useIsolateContext": true,
     "userConfirmedBundleSwitch": false,
     "packNpmManually": false,
     "packNpmRelationList": [],
     "minifyWXSS": true,
     "disableUseStrict": false,
     "minifyWXML": true,
     "showES6CompileOption": false,
     "useCompilerPlugins": false
   },
   "compileType": "miniprogram",
   "libVersion": "2.19.4",
   "appid": "your_app_id",
   "projectname": "blufi-provisioning",
   "debugOptions": {
     "hidedInDevtools": []
   },
   "scripts": {},
   "staticServerOptions": {
     "baseURL": "",
     "servePath": ""
   },
   "isGameTourist": false,
   "condition": {
     "search": {
       "list": []
     },
     "conversation": {
       "list": []
     },
     "game": {
       "list": []
     },
     "plugin": {
       "list": []
     },
     "gamePlugin": {
       "list": []
     },
     "miniprogram": {
       "list": []
     }
   }
 }
 ```
 
 ### 5.3 全局应用文件
 
 #### 5.3.1 app.js
 ```javascript
 // app.js
 App({
   globalData: {
     blufi: null,  // 全局BluFi实例
     deviceInfo: null,  // 当前连接的设备信息
     wifiConfig: null   // WiFi配置信息
   },
   
   onLaunch() {
     console.log('BluFi配网小程序启动');
     
     // 检查蓝牙支持
     this.checkBluetoothSupport();
     
     // 初始化全局数据
     this.initGlobalData();
   },
   
   checkBluetoothSupport() {
     wx.getSystemInfo({
       success: (res) => {
         console.log('系统信息:', res);
         
         // 检查是否支持蓝牙
         if (!wx.openBluetoothAdapter) {
           wx.showModal({
             title: '提示',
             content: '当前微信版本过低，无法使用蓝牙功能，请升级到最新微信版本后重试。',
             showCancel: false
           });
         }
       }
     });
   },
   
   initGlobalData() {
     // 初始化BluFi实例
     const BluFiProvisioning = require('./utils/blufi.js');
     this.globalData.blufi = new BluFiProvisioning();
   },
   
   onShow() {
     console.log('小程序显示');
   },
   
   onHide() {
     console.log('小程序隐藏');
   },
   
   onError(error) {
     console.error('小程序错误:', error);
   }
 });
 ```
 
 ## 6. 错误处理和重试机制
 
 ### 6.1 错误码定义
 ```javascript
 // utils/error-codes.js
 const BluFiErrorCodes = {
   // 蓝牙相关错误
   BLUETOOTH_NOT_AVAILABLE: {
     code: 1001,
     message: '蓝牙不可用，请检查蓝牙是否开启'
   },
   BLUETOOTH_ADAPTER_INIT_FAILED: {
     code: 1002,
     message: '蓝牙适配器初始化失败'
   },
   DEVICE_SCAN_FAILED: {
     code: 1003,
     message: '设备扫描失败'
   },
   DEVICE_NOT_FOUND: {
     code: 1004,
     message: '未发现BluFi设备'
   },
   
   // 连接相关错误
   CONNECTION_FAILED: {
     code: 2001,
     message: '设备连接失败'
   },
   CONNECTION_TIMEOUT: {
     code: 2002,
     message: '设备连接超时'
   },
   SERVICE_NOT_FOUND: {
     code: 2003,
     message: '未找到BluFi服务'
   },
   CHARACTERISTIC_NOT_FOUND: {
     code: 2004,
     message: '未找到BluFi特征值'
   },
   NOTIFICATION_ENABLE_FAILED: {
     code: 2005,
     message: '启用通知失败'
   },
   
   // 配网相关错误
   WIFI_SCAN_FAILED: {
     code: 3001,
     message: 'WiFi扫描失败'
   },
   WIFI_SCAN_TIMEOUT: {
     code: 3002,
     message: 'WiFi扫描超时'
   },
   WIFI_CREDENTIALS_INVALID: {
     code: 3003,
     message: 'WiFi凭据无效'
   },
   WIFI_CONNECTION_FAILED: {
     code: 3004,
     message: 'WiFi连接失败'
   },
   WIFI_CONNECTION_TIMEOUT: {
     code: 3005,
     message: 'WiFi连接超时'
   },
   PROVISIONING_TIMEOUT: {
     code: 3006,
     message: '配网超时'
   },
   
   // 数据传输错误
   DATA_SEND_FAILED: {
     code: 4001,
     message: '数据发送失败'
   },
   DATA_PARSE_FAILED: {
     code: 4002,
     message: '数据解析失败'
   },
   CHECKSUM_ERROR: {
     code: 4003,
     message: '数据校验失败'
   },
   
   // 通用错误
   UNKNOWN_ERROR: {
     code: 9999,
     message: '未知错误'
   }
 };
 
 module.exports = BluFiErrorCodes;
 ```
 
 ### 6.2 重试机制实现
 ```javascript
 // utils/retry.js
 class RetryManager {
   constructor(options = {}) {
     this.maxRetries = options.maxRetries || 3;
     this.retryDelay = options.retryDelay || 2000;
     this.backoffMultiplier = options.backoffMultiplier || 1.5;
     this.maxDelay = options.maxDelay || 10000;
   }
   
   async execute(operation, context = '') {
     let lastError;
     let currentDelay = this.retryDelay;
     
     for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
       try {
         console.log(`${context} - 尝试 ${attempt + 1}/${this.maxRetries + 1}`);
         const result = await operation();
         
         if (attempt > 0) {
           console.log(`${context} - 重试成功`);
         }
         
         return result;
         
       } catch (error) {
         lastError = error;
         console.error(`${context} - 尝试 ${attempt + 1} 失败:`, error);
         
         // 如果是最后一次尝试，直接抛出错误
         if (attempt === this.maxRetries) {
           break;
         }
         
         // 等待后重试
         console.log(`${context} - ${currentDelay}ms 后重试`);
         await this.delay(currentDelay);
         
         // 增加延迟时间（指数退避）
         currentDelay = Math.min(
           currentDelay * this.backoffMultiplier,
           this.maxDelay
         );
       }
     }
     
     console.error(`${context} - 所有重试都失败了`);
     throw lastError;
   }
   
   delay(ms) {
     return new Promise(resolve => setTimeout(resolve, ms));
   }
 }
 
 module.exports = RetryManager;
 ```
 
 ### 6.3 错误处理工具类
 ```javascript
 // utils/error-handler.js
 const BluFiErrorCodes = require('./error-codes.js');
 
 class ErrorHandler {
   static handleError(error, context = '') {
     console.error(`错误处理 [${context}]:`, error);
     
     let errorInfo = {
       code: BluFiErrorCodes.UNKNOWN_ERROR.code,
       message: BluFiErrorCodes.UNKNOWN_ERROR.message,
       detail: error.message || error.errMsg || '未知错误'
     };
     
     // 根据错误信息匹配错误码
     if (error.errMsg) {
       errorInfo = this.mapWxErrorToCode(error.errMsg);
     } else if (error.code) {
       errorInfo = this.findErrorByCode(error.code);
     } else if (error.message) {
       errorInfo = this.mapMessageToCode(error.message);
     }
     
     return errorInfo;
   }
   
   static mapWxErrorToCode(errMsg) {
     const errorMappings = {
       'bluetooth not available': BluFiErrorCodes.BLUETOOTH_NOT_AVAILABLE,
       'bluetooth adapter init fail': BluFiErrorCodes.BLUETOOTH_ADAPTER_INIT_FAILED,
       'createBLEConnection:fail': BluFiErrorCodes.CONNECTION_FAILED,
       'getBLEDeviceServices:fail': BluFiErrorCodes.SERVICE_NOT_FOUND,
       'getBLEDeviceCharacteristics:fail': BluFiErrorCodes.CHARACTERISTIC_NOT_FOUND,
       'notifyBLECharacteristicValueChange:fail': BluFiErrorCodes.NOTIFICATION_ENABLE_FAILED,
       'writeBLECharacteristicValue:fail': BluFiErrorCodes.DATA_SEND_FAILED
     };
     
     for (const [key, errorCode] of Object.entries(errorMappings)) {
       if (errMsg.includes(key)) {
         return {
           code: errorCode.code,
           message: errorCode.message,
           detail: errMsg
         };
       }
     }
     
     return {
       code: BluFiErrorCodes.UNKNOWN_ERROR.code,
       message: BluFiErrorCodes.UNKNOWN_ERROR.message,
       detail: errMsg
     };
   }
   
   static findErrorByCode(code) {
     for (const errorCode of Object.values(BluFiErrorCodes)) {
       if (errorCode.code === code) {
         return {
           code: errorCode.code,
           message: errorCode.message,
           detail: ''
         };
       }
     }
     
     return {
       code: BluFiErrorCodes.UNKNOWN_ERROR.code,
       message: BluFiErrorCodes.UNKNOWN_ERROR.message,
       detail: `错误码: ${code}`
     };
   }
   
   static mapMessageToCode(message) {
     const messageMappings = {
       '蓝牙不可用': BluFiErrorCodes.BLUETOOTH_NOT_AVAILABLE,
       '设备未连接': BluFiErrorCodes.CONNECTION_FAILED,
       '连接超时': BluFiErrorCodes.CONNECTION_TIMEOUT,
       '配网超时': BluFiErrorCodes.PROVISIONING_TIMEOUT,
       'WiFi连接失败': BluFiErrorCodes.WIFI_CONNECTION_FAILED
     };
     
     for (const [key, errorCode] of Object.entries(messageMappings)) {
       if (message.includes(key)) {
         return {
           code: errorCode.code,
           message: errorCode.message,
           detail: message
         };
       }
     }
     
     return {
       code: BluFiErrorCodes.UNKNOWN_ERROR.code,
       message: BluFiErrorCodes.UNKNOWN_ERROR.message,
       detail: message
     };
   }
   
   static showError(errorInfo, options = {}) {
     const title = options.title || '错误';
     const showDetail = options.showDetail !== false;
     
     let content = errorInfo.message;
     if (showDetail && errorInfo.detail) {
       content += `\n\n详细信息: ${errorInfo.detail}`;
     }
     
     wx.showModal({
       title: title,
       content: content,
       showCancel: false,
       confirmText: '确定'
     });
   }
   
   static showToast(errorInfo) {
     wx.showToast({
       title: errorInfo.message,
       icon: 'error',
       duration: 3000
     });
   }
 }
 
 module.exports = ErrorHandler;
 ```
 
 ## 7. 安全机制和数据保护
 
 ### 7.1 数据加密（可选）
 ```javascript
 // utils/encryption.js
 class BluFiEncryption {
   constructor(options = {}) {
     this.enabled = options.enabled || false;
     this.algorithm = options.algorithm || 'AES-128-CFB';
     this.key = options.key || null;
     this.iv = options.iv || null;
   }
   
   // 设置加密密钥
   setKey(key) {
     this.key = key;
   }
   
   // 设置初始化向量
   setIV(iv) {
     this.iv = iv;
   }
   
   // 加密数据
   encrypt(data) {
     if (!this.enabled || !this.key) {
       return data;
     }
     
     try {
       // 这里应该实现实际的AES加密
       // 由于微信小程序环境限制，可能需要使用第三方加密库
       console.log('数据加密（模拟）');
       return data; // 返回加密后的数据
     } catch (error) {
       console.error('数据加密失败:', error);
       throw error;
     }
   }
   
   // 解密数据
   decrypt(encryptedData) {
     if (!this.enabled || !this.key) {
       return encryptedData;
     }
     
     try {
       // 这里应该实现实际的AES解密
       console.log('数据解密（模拟）');
       return encryptedData; // 返回解密后的数据
     } catch (error) {
       console.error('数据解密失败:', error);
       throw error;
     }
   }
 }
 
 module.exports = BluFiEncryption;
 ```
 
 ### 7.2 数据校验
 ```javascript
 // utils/checksum.js
 class ChecksumCalculator {
   // 计算简单校验和
   static calculateSimpleChecksum(data) {
     let checksum = 0;
     const view = new Uint8Array(data);
     
     for (let i = 0; i < view.length; i++) {
       checksum += view[i];
     }
     
     return checksum & 0xFFFF;
   }
   
   // 验证校验和
   static verifyChecksum(data, expectedChecksum) {
     const calculatedChecksum = this.calculateSimpleChecksum(data);
     return calculatedChecksum === expectedChecksum;
   }
   
   // CRC16校验（可选）
   static calculateCRC16(data) {
     let crc = 0xFFFF;
     const polynomial = 0x1021;
     
     const view = new Uint8Array(data);
     
     for (let i = 0; i < view.length; i++) {
       crc ^= (view[i] << 8);
       
       for (let j = 0; j < 8; j++) {
         if (crc & 0x8000) {
           crc = (crc << 1) ^ polynomial;
         } else {
           crc <<= 1;
         }
         crc &= 0xFFFF;
       }
     }
     
     return crc;
   }
 }
 
 module.exports = ChecksumCalculator;
 ```
 
 ### 7.3 敏感数据处理
 ```javascript
 // utils/security.js
 class SecurityManager {
   // 清理敏感数据
   static clearSensitiveData() {
     // 清理WiFi密码等敏感信息
     const app = getApp();
     if (app.globalData.wifiConfig) {
       app.globalData.wifiConfig.password = null;
     }
     
     // 清理本地存储中的敏感数据
     try {
       wx.removeStorageSync('wifi_password');
       wx.removeStorageSync('encryption_key');
     } catch (error) {
       console.warn('清理本地存储失败:', error);
     }
   }
   
   // 验证WiFi凭据格式
   static validateWiFiCredentials(ssid, password) {
     const errors = [];
     
     // SSID验证
     if (!ssid || ssid.trim().length === 0) {
       errors.push('WiFi名称不能为空');
     } else if (ssid.length > 32) {
       errors.push('WiFi名称长度不能超过32个字符');
     }
     
     // 密码验证（可选）
     if (password && password.length > 64) {
       errors.push('WiFi密码长度不能超过64个字符');
     }
     
     return {
       valid: errors.length === 0,
       errors: errors
     };
   }
   
   // 生成随机序列号
   static generateSequenceNumber() {
     return Math.floor(Math.random() * 65536);
   }
 }
 
 module.exports = SecurityManager;
 ```
 
 ## 8. 测试和调试
 
 ### 8.1 调试工具
 ```javascript
 // utils/debug.js
 class DebugManager {
   constructor() {
     this.enabled = true; // 生产环境应设为false
     this.logLevel = 'DEBUG'; // DEBUG, INFO, WARN, ERROR
     this.logs = [];
     this.maxLogs = 1000;
   }
   
   log(level, message, data = null) {
     if (!this.enabled) return;
     
     const timestamp = new Date().toISOString();
     const logEntry = {
       timestamp,
       level,
       message,
       data
     };
     
     // 添加到日志数组
     this.logs.push(logEntry);
     
     // 限制日志数量
     if (this.logs.length > this.maxLogs) {
       this.logs.shift();
     }
     
     // 控制台输出
     const logMessage = `[${timestamp}] ${level}: ${message}`;
     switch (level) {
       case 'DEBUG':
         console.log(logMessage, data);
         break;
       case 'INFO':
         console.info(logMessage, data);
         break;
       case 'WARN':
         console.warn(logMessage, data);
         break;
       case 'ERROR':
         console.error(logMessage, data);
         break;
     }
   }
   
   debug(message, data) {
     this.log('DEBUG', message, data);
   }
   
   info(message, data) {
     this.log('INFO', message, data);
   }
   
   warn(message, data) {
     this.log('WARN', message, data);
   }
   
   error(message, data) {
     this.log('ERROR', message, data);
   }
   
   // 导出日志
   exportLogs() {
     return JSON.stringify(this.logs, null, 2);
   }
   
   // 清空日志
   clearLogs() {
     this.logs = [];
   }
   
   // 获取最近的错误日志
   getRecentErrors(count = 10) {
     return this.logs
       .filter(log => log.level === 'ERROR')
       .slice(-count);
   }
 }
 
 // 创建全局调试实例
 const debugManager = new DebugManager();
 
 module.exports = debugManager;
 ```
 
 ### 8.2 测试用例
 ```javascript
 // test/blufi-test.js
 class BluFiTest {
   constructor() {
     this.testResults = [];
   }
   
   // 运行所有测试
   async runAllTests() {
     console.log('开始BluFi测试...');
     
     await this.testBluetoothInit();
     await this.testDeviceScan();
     await this.testPacketParsing();
     await this.testChecksumCalculation();
     
     this.printTestResults();
   }
   
   // 测试蓝牙初始化
   async testBluetoothInit() {
     try {
       const blufi = new BluFiProvisioning();
       await blufi.initBluetooth();
       
       this.addTestResult('蓝牙初始化', true, '成功');
     } catch (error) {
       this.addTestResult('蓝牙初始化', false, error.message);
     }
   }
   
   // 测试设备扫描
   async testDeviceScan() {
     try {
       const blufi = new BluFiProvisioning();
       
       let deviceFound = false;
       await blufi.startScan((device) => {
         if (blufi.isValidBluFiDevice(device)) {
           deviceFound = true;
         }
       });
       
       // 等待5秒
       await new Promise(resolve => setTimeout(resolve, 5000));
       await blufi.stopScan();
       
       this.addTestResult('设备扫描', deviceFound, deviceFound ? '发现设备' : '未发现设备');
     } catch (error) {
       this.addTestResult('设备扫描', false, error.message);
     }
   }
   
   // 测试数据包解析
   testPacketParsing() {
     try {
       const packet = new BluFiPacket();
       
       // 构建测试数据包
       const testData = new TextEncoder().encode('test');
       const buffer = packet.build(0x01, 0x02, testData);
       
       // 解析数据包
       const parsed = packet.parse(buffer);
       
       const success = parsed.type === 0x01 && 
                      parsed.subtype === 0x02 && 
                      new TextDecoder().decode(parsed.data) === 'test';
       
       this.addTestResult('数据包解析', success, success ? '解析正确' : '解析错误');
     } catch (error) {
       this.addTestResult('数据包解析', false, error.message);
     }
   }
   
   // 测试校验和计算
   testChecksumCalculation() {
     try {
       const testData = new Uint8Array([0x01, 0x02, 0x03, 0x04]);
       const checksum = ChecksumCalculator.calculateSimpleChecksum(testData.buffer);
       
       // 预期校验和: 1+2+3+4 = 10
       const expected = 10;
       const success = checksum === expected;
       
       this.addTestResult('校验和计算', success, 
         success ? `校验和正确: ${checksum}` : `校验和错误: 期望${expected}, 实际${checksum}`);
     } catch (error) {
       this.addTestResult('校验和计算', false, error.message);
     }
   }
   
   addTestResult(testName, success, message) {
     this.testResults.push({
       name: testName,
       success: success,
       message: message,
       timestamp: new Date().toISOString()
     });
   }
   
   printTestResults() {
     console.log('\n=== BluFi测试结果 ===');
     
     let passCount = 0;
     let totalCount = this.testResults.length;
     
     this.testResults.forEach(result => {
       const status = result.success ? '✓ 通过' : '✗ 失败';
       console.log(`${status} ${result.name}: ${result.message}`);
       
       if (result.success) {
         passCount++;
       }
     });
     
     console.log(`\n总计: ${passCount}/${totalCount} 个测试通过`);
     
     if (passCount === totalCount) {
       console.log('🎉 所有测试都通过了！');
     } else {
       console.log('❌ 部分测试失败，请检查相关功能');
     }
   }
 }
 
 module.exports = BluFiTest;
 ```
 
 ## 9. 性能优化
 
 ### 9.1 内存管理
 ```javascript
 // utils/memory-manager.js
 class MemoryManager {
   static clearUnusedData() {
     // 清理不再使用的设备列表
     const app = getApp();
     if (app.globalData.deviceList) {
       app.globalData.deviceList = [];
     }
     
     // 清理WiFi列表缓存
     if (app.globalData.wifiList) {
       app.globalData.wifiList = [];
     }
     
     // 强制垃圾回收（如果支持）
     if (typeof wx.triggerGC === 'function') {
       wx.triggerGC();
     }
   }
   
   static monitorMemoryUsage() {
     if (typeof wx.getPerformance === 'function') {
       const performance = wx.getPerformance();
       if (performance.memory) {
         console.log('内存使用情况:', {
           used: performance.memory.usedJSHeapSize,
           total: performance.memory.totalJSHeapSize,
           limit: performance.memory.jsHeapSizeLimit
         });
       }
     }
   }
 }
 
 module.exports = MemoryManager;
 ```
 
 ### 9.2 连接优化
 ```javascript
 // utils/connection-optimizer.js
 class ConnectionOptimizer {
   constructor() {
     this.connectionPool = new Map();
     this.maxConnections = 1; // BluFi通常只需要一个连接
   }
   
   // 优化连接参数
   getOptimalConnectionParams() {
     return {
       timeout: 15000,        // 15秒连接超时
       interval: 100,         // 100ms扫描间隔
       allowDuplicatesKey: false,
       services: [BLUFI_SERVICE_UUID]
     };
   }
   
   // 连接重用
   reuseConnection(deviceId) {
     if (this.connectionPool.has(deviceId)) {
       const connection = this.connectionPool.get(deviceId);
       if (connection.isValid) {
         return connection;
       } else {
         this.connectionPool.delete(deviceId);
       }
     }
     return null;
   }
   
   // 添加连接到池
   addConnection(deviceId, connection) {
     // 如果池满了，移除最旧的连接
     if (this.connectionPool.size >= this.maxConnections) {
       const firstKey = this.connectionPool.keys().next().value;
       this.connectionPool.delete(firstKey);
     }
     
     this.connectionPool.set(deviceId, connection);
   }
   
   // 清理连接池
   clearPool() {
     this.connectionPool.clear();
   }
 }
 
 module.exports = ConnectionOptimizer;
 ```
 
 ## 10. 部署和发布
 
 ### 10.1 发布前检查清单
 - [ ] 所有功能测试通过
 - [ ] 与ESP官方espblufi应用对比测试完成
 - [ ] 错误处理机制完善
 - [ ] 用户界面友好性检查
 - [ ] 性能测试通过
 - [ ] 安全性检查完成
 - [ ] 代码审查完成
 - [ ] 文档更新完成
 
 ### 10.2 版本管理
 ```javascript
 // utils/version.js
 const VERSION_INFO = {
   version: '1.0.0',
   buildNumber: '20240101',
   releaseDate: '2024-01-01',
   features: [
     'BluFi设备扫描和连接',
     'WiFi网络配置',
     '配网状态监控',
     '错误处理和重试机制'
   ],
   compatibility: {
     minWechatVersion: '7.0.0',
     minSystemVersion: {
       ios: '10.0',
       android: '6.0'
     },
     espIdfVersion: '4.4+'
   }
 };
 
 module.exports = VERSION_INFO;
 ```
 
 ### 10.3 用户手册
 
 #### 10.3.1 使用步骤
 1. **准备工作**
    - 确保手机蓝牙已开启
    - 确保ESP32设备处于配网模式
    - 确保手机已连接到互联网
 
 2. **开始配网**
    - 打开BluFi配网小程序
    - 点击"开始扫描"按钮
    - 从设备列表中选择要配网的设备
 
 3. **连接设备**
    - 等待设备连接完成
    - 连接成功后会显示"设备连接成功"
 
 4. **配置WiFi**
    - 选择要连接的WiFi网络，或手动输入WiFi信息
    - 输入WiFi密码
    - 点击"开始配网"按钮
 
 5. **等待配网完成**
    - 等待设备连接到WiFi网络
    - 配网成功后会显示"配网完成"
 
 #### 10.3.2 常见问题解决
 
 **Q: 扫描不到设备怎么办？**
 A: 
 - 检查手机蓝牙是否开启
 - 确认设备是否处于配网模式
 - 尝试重新启动设备
 - 检查设备距离是否过远
 
 **Q: 连接设备失败怎么办？**
 A:
 - 确认设备未被其他应用占用
 - 尝试重启手机蓝牙
 - 重新扫描设备
 
 **Q: WiFi配网失败怎么办？**
 A:
 - 检查WiFi密码是否正确
 - 确认WiFi信号强度是否足够
 - 检查WiFi网络是否正常
 - 尝试重新配网
 
 ## 11. 附录
 
 ### 11.1 参考文档
 - [ESP-IDF BluFi官方文档](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/blufi.html)
 - [微信小程序蓝牙API文档](https://developers.weixin.qq.com/miniprogram/dev/api/device/bluetooth/wx.openBluetoothAdapter.html)
 - [BluFi协议规范](https://github.com/espressif/esp-idf/tree/master/examples/bluetooth/blufi)
 
 ### 11.2 技术支持
 - 开发团队：[联系方式]
 - 问题反馈：[反馈渠道]
 - 更新通知：[通知方式]
 
 ### 11.3 更新日志
 
 #### v1.0.0 (2024-01-01)
 - 初始版本发布
 - 实现基础BluFi配网功能
 - 支持设备扫描、连接、WiFi配置
 - 完善错误处理和重试机制
 
 ---
 
 **文档版本**: 2.0  
 **创建日期**: 2025年8月  
 **最后更新**: 2025年8月  
 **文档状态**: 已完成