iB86/.qoder/quests/small-screen-wifi-config.md

15 KiB
Raw Permalink Blame History

小屏幕WiFi+蓝牙配网功能设计

1. 概述

本设计针对504×410分辨率的小屏幕设备实现蓝牙配网功能。用户通过长按屏幕左上角进入配网模式使用蓝牙与移动端配网APP建立连接完成WiFi网络配置。

核心特性

  • 小屏幕优化: 专为504×410分辨率设计的触摸友好界面
  • 蓝牙配网: 通过蓝牙连接进行网络配置
  • 手势触发: 长按左上角触发配网模式
  • 状态反馈: 实时显示配网进度和连接状态
  • 自动重试: 配网失败时自动重试连接

2. 技术架构

2.1 系统架构图

``mermaid graph TD A[用户长按触发] --> B[配网模式检测器] B --> C[蓝牙配网管理器]

C --> D[蓝牙配网服务]

D --> F[蓝牙广播服务]
D --> G[配网数据接收器]

F --> J[移动端配网APP]

G --> L[网络连接器]

L --> M[连接状态管理器]
M --> N[配网结果反馈]

### 2.2 核心组件

#### BluetoothConfigManager (蓝牙配网管理器)
``mermaid
classDiagram
    class BluetoothConfigManager {
        -BluetoothConfigService bluetoothService
        -ConnectionStatusManager statusManager
        +startConfigMode()
        +stopConfigMode()
        +switchConfigMode()
        +onConfigResult()
    }
    
    class BluetoothConfigService {
        -BluetoothAdapter adapter
        -ConfigDataReceiver receiver
        +startAdvertising()
        +stopAdvertising()
        +onDataReceived()
    }
    
    class WiFiHotspotConfigService {
        -WifiManager wifiManager
        -HTTPConfigServer server
        +createHotspot()
        +startConfigServer()
        +onConfigReceived()
    }

3. 功能模块设计

3.1 触发机制

长按检测器 (LongPressDetector)

``mermaid sequenceDiagram participant U as 用户 participant D as LongPressDetector participant M as ConfigNetworkManager participant UI as ConfigModeUI

U->>D: 长按左上角区域
D->>D: 检测按压时长(3秒)
D->>M: triggerConfigMode()
M->>UI: showConfigModeDialog()
UI->>U: 显示配网选择界面

#### 触摸区域定义
- **触发区域**: 左上角50×50dp区域
- **长按时长**: 3秒钟
- **视觉反馈**: 渐进式圆形进度指示器

### 3.2 BLE配网模式

#### BLE服务端架构
```mermaid
flowchart TD
    A[小程序客户端] --> B[连接设备iB86]
    B --> C[BLE GATT服务器]
    
    C --> D[Service 0xFA00]
    D --> E[Characteristic 0xEA01<br/>状态通知]
    D --> F[Characteristic 0xEA03<br/>扫描指令]
    D --> G[Characteristic 0xEA05<br/>SSID配置]
    D --> H[Characteristic 0xEA06<br/>密码配置]
    
    F --> I[WiFi扫描器]
    I --> J[扫描结果]
    J --> E
    
    G --> K[配网管理器]
    H --> K
    K --> L[WiFi连接器]
    L --> M[连接状态]
    M --> E

BLE协议规范

设备信息

  • 设备名称: iB86
  • Service UUID: 0xFA00
  • 角色: BLE服务端GATT Server

Characteristic定义

UUID 权限 功能描述
0xEA01 Notify 状态通知和扫描结果回传
0xEA03 Write 接收扫描指令
0xEA05 Write 接收WiFi SSID
0xEA06 Write 接收WiFi密码

AT命令协议

状态码定义

AT+STATE=0  # 当前无操作
AT+STATE=1  # 收到扫描指令,开始扫描网络
AT+STATE=2  # 收到SSID和密码开始连接网络
AT+STATE=3  # 已连接WiFi并获取IP
AT+STATE=6  # 密码错误
AT+STATE=7  # 没有找到该WiFi

指令格式

# 扫描指令
AT+SSID     # 或 AT+SCAN

# 扫描结果回传格式
AT+SSID=<数量>,<SSID1>,<SSID2>,...,<SSIDn>
# 示例: AT+SSID=1603,iLock,TP-LINK15DA,HUAWEI-AB8D

配网流程

sequenceDiagram
    participant MP as 小程序
    participant BLE as BLE服务器
    participant WIFI as WiFi扫描器
    participant NET as 网络连接器
    
    MP->>BLE: 连接设备iB86
    MP->>BLE: 写入0xEA03 "AT+SSID"
    BLE->>BLE: 更新状态AT+STATE=1
    BLE->>WIFI: 开始WiFi扫描
    WIFI->>BLE: 返回扫描结果
    BLE->>MP: 通过0xEA01回传扫描结果
    
    MP->>BLE: 写入0xEA05 目标SSID
    MP->>BLE: 写入0xEA06 WiFi密码
    BLE->>BLE: 更新状态AT+STATE=2
    BLE->>NET: 尝试连接WiFi
    
    alt 连接成功
        NET->>BLE: 连接成功并获取IP
        BLE->>BLE: 更新状态AT+STATE=3
        BLE->>MP: 通过0xEA01通知成功
    else 密码错误
        NET->>BLE: 认证失败
        BLE->>BLE: 更新状态AT+STATE=6
        BLE->>MP: 通过0xEA01通知密码错误
    else 网络未找到
        NET->>BLE: 网络不存在
        BLE->>BLE: 更新状态AT+STATE=7
        BLE->>MP: 通过0xEA01通知网络未找到
    end

4. 用户界面设计

4.1 小屏幕适配规范

布局约束

``xml

504x410dp 48dp 16sp 16dp 12dp ```

界面层级结构

graph TD
    A[长按触发] --> B[BLE配网页面]
    
    B --> C[BLE服务器启动]
    B --> D[等待小程序连接]
    B --> E[WiFi扫描状态]
    B --> F[配网进度显示]
    B --> G[连接结果页面]
    
    G --> H[返回主界面]

4.2 状态指示器设计

配网状态机

stateDiagram-v2
    [*] --> 待机模式
    待机模式 --> 配网触发检测 : 长按左上角
    配网触发检测 --> BLE服务启动 : 触发成功
    
    BLE服务启动 --> 等待连接 : AT+STATE=0
    等待连接 --> WiFi扫描 : 收到AT+SSID指令
    WiFi扫描 --> 扫描中 : AT+STATE=1
    扫描中 --> 等待配置 : 回传扫描结果
    
    等待配置 --> 连接WiFi : 收到SSID和密码
    连接WiFi --> 连接中 : AT+STATE=2
    
    连接中 --> 连接成功 : AT+STATE=3
    连接中 --> 密码错误 : AT+STATE=6
    连接中 --> 网络未找到 : AT+STATE=7
    
    连接成功 --> [*]
    密码错误 --> 等待配置 : 重新配置
    网络未找到 --> 等待配置 : 重新配置

5. 数据模型

5.1 配网配置模型

WiFiConfigData

public class WiFiConfigData {
    private String ssid;           // WiFi名称
    private String password;       // WiFi密码
    private SecurityType security; // 加密类型
    private boolean isHidden;      // 是否隐藏网络
    private String ipConfig;       // IP配置类型
    private String proxyConfig;    // 代理配置
}

BluetoothConfigStatus

public class BluetoothConfigStatus {
    private ConfigState state;         // 配网状态
    private String message;            // 状态消息
    private int progress;              // 进度百分比
    private long timestamp;            // 时间戳
}
}

5.2 枚举定义

public enum ConfigState {
    IDLE("待机"),                    // AT+STATE=0
    DETECTING("检测触发"),
    BLE_SERVER_STARTING("BLE服务启动"),
    WAITING_CONNECTION("等待连接"),
    WIFI_SCANNING("WiFi扫描中"),      // AT+STATE=1
    WAITING_CONFIG("等待配置"),
    CONNECTING_WIFI("连接WiFi中"),   // AT+STATE=2
    SUCCESS("连接成功"),           // AT+STATE=3
    PASSWORD_ERROR("密码错误"),    // AT+STATE=6
    NETWORK_NOT_FOUND("网络未找到"); // AT+STATE=7
}

6. 核心服务实现

6.1 配网触发服务

LongPressGestureDetector

public class LongPressGestureDetector {
    private static final long LONG_PRESS_DURATION = 3000; // 3秒
    private static final int TRIGGER_AREA_SIZE = 50; // 50dp
    
    public boolean isInTriggerArea(float x, float y) {
        return x <= dpToPx(TRIGGER_AREA_SIZE) && 
               y <= dpToPx(TRIGGER_AREA_SIZE);
    }
    
    public void handleTouchEvent(MotionEvent event) {
        // 处理触摸事件逻辑
    }
}

6.2 BLE配网服务

BleConfigGattServer

public class BleConfigGattServer {
    // UUID定义
    private static final UUID SERVICE_UUID = UUID.fromString("0000fa00-0000-1000-8000-00805f9b34fb");
    private static final UUID STATUS_CHAR_UUID = UUID.fromString("0000ea01-0000-1000-8000-00805f9b34fb");
    private static final UUID SCAN_CHAR_UUID = UUID.fromString("0000ea03-0000-1000-8000-00805f9b34fb");
    private static final UUID SSID_CHAR_UUID = UUID.fromString("0000ea05-0000-1000-8000-00805f9b34fb");
    private static final UUID PASSWORD_CHAR_UUID = UUID.fromString("0000ea06-0000-1000-8000-00805f9b34fb");
    
    private BluetoothGattServer gattServer;
    private ATCommandProcessor atProcessor;
    
    public void startGattServer() {
        BluetoothGattService service = new BluetoothGattService(
            SERVICE_UUID, BluetoothGattService.SERVICE_TYPE_PRIMARY);
            
        // 0xEA01 - 状态通知Characteristic
        BluetoothGattCharacteristic statusChar = new BluetoothGattCharacteristic(
            STATUS_CHAR_UUID,
            BluetoothGattCharacteristic.PROPERTY_NOTIFY,
            BluetoothGattCharacteristic.PERMISSION_READ);
            
        // 0xEA03 - 扫描指令Characteristic
        BluetoothGattCharacteristic scanChar = new BluetoothGattCharacteristic(
            SCAN_CHAR_UUID,
            BluetoothGattCharacteristic.PROPERTY_WRITE,
            BluetoothGattCharacteristic.PERMISSION_WRITE);
            
        // 0xEA05 - SSID配置Characteristic
        BluetoothGattCharacteristic ssidChar = new BluetoothGattCharacteristic(
            SSID_CHAR_UUID,
            BluetoothGattCharacteristic.PROPERTY_WRITE,
            BluetoothGattCharacteristic.PERMISSION_WRITE);
            
        // 0xEA06 - 密码配置Characteristic
        BluetoothGattCharacteristic passwordChar = new BluetoothGattCharacteristic(
            PASSWORD_CHAR_UUID,
            BluetoothGattCharacteristic.PROPERTY_WRITE,
            BluetoothGattCharacteristic.PERMISSION_WRITE);
        
        service.addCharacteristic(statusChar);
        service.addCharacteristic(scanChar);
        service.addCharacteristic(ssidChar);
        service.addCharacteristic(passwordChar);
        
        gattServer.addService(service);
    }
}

ATCommandProcessor

public class ATCommandProcessor {
    private WiFiScanManager wifiScanner;
    private WiFiConnectionManager wifiConnector;
    private BleConfigGattServer gattServer;
    
    public void processCommand(String command, UUID characteristicUuid) {
        if (SCAN_CHAR_UUID.equals(characteristicUuid)) {
            if ("AT+SSID".equals(command) || "AT+SCAN".equals(command)) {
                handleWiFiScan();
            }
        } else if (SSID_CHAR_UUID.equals(characteristicUuid)) {
            handleSSIDConfig(command);
        } else if (PASSWORD_CHAR_UUID.equals(characteristicUuid)) {
            handlePasswordConfig(command);
        }
    }
    
    private void handleWiFiScan() {
        notifyState(1); // AT+STATE=1
        wifiScanner.startScan(new WiFiScanCallback() {
            @Override
            public void onScanCompleted(List<String> ssidList) {
                String result = formatScanResult(ssidList);
                gattServer.notifyCharacteristic(STATUS_CHAR_UUID, result.getBytes());
            }
        });
    }
    
    private String formatScanResult(List<String> ssidList) {
        StringBuilder sb = new StringBuilder();
        sb.append("AT+SSID=").append(ssidList.size());
        for (String ssid : ssidList) {
            sb.append(",").append(ssid);
        }
        return sb.toString();
    }
    
    private void handleSSIDConfig(String ssid) {
        this.targetSSID = ssid;
        checkAndConnect();
    }
    
    private void handlePasswordConfig(String password) {
        this.targetPassword = password;
        checkAndConnect();
    }
    
    private void checkAndConnect() {
        if (targetSSID != null && targetPassword != null) {
            notifyState(2); // AT+STATE=2
            wifiConnector.connect(targetSSID, targetPassword, new WiFiConnectionCallback() {
                @Override
                public void onConnected(String ipAddress) {
                    notifyState(3); // AT+STATE=3
                }
                
                @Override
                public void onPasswordError() {
                    notifyState(6); // AT+STATE=6
                }
                
                @Override
                public void onNetworkNotFound() {
                    notifyState(7); // AT+STATE=7
                }
            });
        }
    }
    
    private void notifyState(int state) {
        String stateMsg = "AT+STATE=" + state;
        gattServer.notifyCharacteristic(STATUS_CHAR_UUID, stateMsg.getBytes());
    }
}

7. 安全性设计

7.1 数据传输安全

蓝牙配网安全

  • 配对验证: 使用PIN码配对验证
  • 数据加密: AES-128加密WiFi凭证
  • 超时机制: 配网会话5分钟超时
  • 设备认证: 验证设备MAC地址白名单

7.2 权限管理

必需权限清单

``xml


## 8. 测试策略

### 8.1 功能测试

#### 测试用例矩阵
| 测试场景 | 蓝牙配网 | 预期结果 |
|---------|---------|----------|
| 正常配网流程 | ✓ | 配网成功 |
| 错误WiFi凭证 | ✓ | 显示错误信息 |
| 网络连接超时 | ✓ | 自动重试 |
| 长按触发 | - | 正确进入配网 |
| 小屏幕适配 | ✓ | 界面正常显示 |

### 8.2 性能测试

#### 关键指标
- **触发响应时间**: < 500ms
- **蓝牙广播启动**: < 2s
- **配网完成时间**: < 30s
- **内存占用**: < 50MB
- **CPU占用**: < 20%

### 8.3 兼容性测试

#### 测试环境
- **Android版本**: API 26-34
- **蓝牙版本**: 4.0+
- **WiFi标准**: 802.11 b/g/n
- **屏幕分辨率**: 504×410dp
- **设备类型**: 嵌入式Android设备