Flutter蓝牙设备配置插件esp_provisioning_ble的使用

发布于 1周前 作者 htzhanglong 来自 Flutter

Flutter蓝牙设备配置插件esp_provisioning_ble的使用

概述

esp_provisioning_ble 是一个用于通过蓝牙低功耗(BLE)对ESP32设备进行配置的库。本文档将详细介绍如何使用该插件,并提供一个完整的示例代码。

入门指南

创建EspProv实例

该包有一个抽象类 ProvTransport,你需要使用你选择的蓝牙包来实现它。在 示例 文件夹中,有一个使用 flutter_ble_lib_ios_15 包实现的 ProvTransport

prov = EspProv(
    transport: TransportBLE(peripheral),
    security: Security1(
        pop: pop,
    ),
);
  • transport 属性只接受 ProvTransport 类型。
  • security 属性只接受 ProvSecurity 类型,其中 Security1 是一个实现,用于传递 Proof-of-Possession (PoP)。

建立与设备的会话

建立会话需要调用 establishSession 函数,该函数返回三种类型的 EstablishSessionStatus

  1. Connected: 设备成功建立连接。
  2. Disconnected: 建立连接时发生错误。
  3. KeyMismatch: Proof-of-Possession (PoP) 不正确。
var sessionStatus = await prov.establishSession();
log.d("Session Status = $sessionStatus");
switch (sessionStatus) {
    case EstablishSessionStatus.Connected:
        emit(BleWifiEstablishedConnectionState());
    case EstablishSessionStatus.Disconnected:
        emit(BleWifiEstablishedConnectionFailedState());
    case EstablishSessionStatus.Keymismatch:
        emit(BleWifiEstablishedConnectionKeyMismatch());
}

扫描设备的Wi-Fi网络

使用 startScanWiFi 函数扫描Wi-Fi网络,该函数返回一个 WifiAp 对象列表,每个对象包含以下属性:

  • String ssid
  • int rssi
  • bool active
  • bool private
var listWifi = await prov.startScanWiFi();
log.d('Found ${listWifi.length} Wi-Fi networks');
for (var obj in listWifi) {
    log.d('Wi-Fi network: ${obj.ssid}');
}

发送并应用Wi-Fi配置

使用 sendWifiConfigapplyWifiConfig 函数分别发送和应用Wi-Fi配置。

await prov.sendWifiConfig(ssid: event.ssid, password: event.password);
await prov.applyWifiConfig();

获取应用Wi-Fi配置的状态

使用 getStatus 函数获取状态,该函数返回一个 ConnectionStatus 类型。ConnectionStatus 包含以下属性:

  • WifiConnectionState state: 包含四种状态:
    • Connected
    • Connecting
    • Disconnected
    • ConnectionFailed: 当状态为 ConnectionFailed 时,WifiConnectFailedReason 属性指示错误类型。
  • String? deviceIp: 注册设备的IP地址。
  • WifiConnectFailedReason? failedReason: 包含两种失败原因:
    • AuthError: Wi-Fi密码输入错误。
    • NetworkNotFound: Wi-Fi SSID输入错误。
ConnectionStatus status = await prov.getStatus();
switch (status.state) {
    case WifiConnectionState.Connecting:
        add(BleWifiLoadingEvent());
    case WifiConnectionState.Connected:
        log.d("Device IP: ${status.deviceIp}");
        add(BleWifiConnectedEvent());
    case WifiConnectionState.Disconnected:
        add(BleWifiDisconnectedEvent());
    case WifiConnectionState.ConnectionFailed:
        add(
            BleWifiConnectionFailedEvent(
                failedReason: status.failedReason!,
            ),
        );
}

发送自定义数据

使用 sendReceiveCustomData 函数发送和接收自定义数据。

var customAnswerBytes = await prov.sendReceiveCustomData(
    Uint8List.fromList(
        utf8.encode(customSendMessage),
    ),
);
var customAnswer = utf8.decode(customAnswerBytes);
log.i("Custom data answer: $customAnswer");

协议通信概述

协议通信(protocomm)组件管理安全会话,并为多种传输方式提供框架。应用程序也可以直接使用 protocomm 层,以扩展特定于应用程序的配置或非配置用例。

可用的配置功能

  • 应用级别的通信安全
    • protocomm_security0(无安全)
    • protocomm_security1(Curve25519 密钥交换 + AES-CTR 加密/解密)
    • protocomm_security2(SRP6a 基于的密钥交换 + AES-GCM 加密/解密)
  • Proof-of-possession(仅支持 protocomm_security1
  • Salt 和 Verifier(仅支持 protocomm_security2

传输方式

  • 蓝牙低功耗(BLE)
  • Wi-Fi(SoftAP + HTTPD)
  • 控制台,此时设备端自动处理处理器调用。

比较

esp_provisioning_softap 包的比较:

Repo softap support ble support cryptography protobuf
esp_provisioning_softap ✔️ ✖️ ✔️ (2.0.1) ✔️ (2.0.0)
esp_provisioning_ble ✖️ ✔️ ✔️ (2.5.0) ✔️ (3.0.0)

待办事项

  • 测试并创建使用其他蓝牙包的示例。
    • flutter_blue_plus

致谢

示例代码

以下是 esp_provisioning_ble 的一个完整示例代码:

import 'package:flutter/material.dart';
import 'package:esp_provisioning_ble/esp_provisioning_ble.dart';
import 'package:flutter_ble_lib_ios_15/flutter_ble_lib_ios_15.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'ESP32 Provisioning',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: ProvisioningScreen(),
    );
  }
}

class ProvisioningScreen extends StatefulWidget {
  @override
  _ProvisioningScreenState createState() => _ProvisioningScreenState();
}

class _ProvisioningScreenState extends State<ProvisioningScreen> {
  late CentralManager centralManager;
  late Peripheral peripheral;
  late EspProv prov;

  @override
  void initState() {
    super.initState();
    initBle();
  }

  Future<void> initBle() async {
    centralManager = CentralManager();
    await centralManager.requestAuthorization();
    centralManager.scanForPeripherals();
    centralManager.onStateChange().listen((state) {
      if (state == ManagerState.poweredOn) {
        centralManager.stopScan();
        peripheral = await findPeripheral();
        connectToPeripheral(peripheral);
      }
    });
  }

  Future<Peripheral> findPeripheral() async {
    // Implement your logic to find the specific peripheral
    return await centralManager.connectedPeripherals().firstWhere((p) => p.name == 'ESP32');
  }

  void connectToPeripheral(Peripheral peripheral) async {
    await peripheral.connect();
    prov = EspProv(
      transport: TransportBLE(peripheral),
      security: Security1(pop: 'your_proof_of_possession'),
    );

    var sessionStatus = await prov.establishSession();
    print("Session Status = $sessionStatus");

    switch (sessionStatus) {
      case EstablishSessionStatus.Connected:
        print('Session established successfully');
        break;
      case EstablishSessionStatus.Disconnected:
        print('Session establishment failed');
        break;
      case EstablishSessionStatus.Keymismatch:
        print('Proof-of-Possession mismatch');
        break;
    }

    var listWifi = await prov.startScanWiFi();
    print('Found ${listWifi.length} Wi-Fi networks');
    for (var obj in listWifi) {
      print('Wi-Fi network: ${obj.ssid}');
    }

    await prov.sendWifiConfig(ssid: 'your_ssid', password: 'your_password');
    await prov.applyWifiConfig();

    ConnectionStatus status = await prov.getStatus();
    print('Connection Status: ${status.state}');
    if (status.state == WifiConnectionState.Connected) {
      print("Device IP: ${status.deviceIp}");
    } else if (status.state == WifiConnectionState.ConnectionFailed) {
      print("Connection Failed: ${status.failedReason}");
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('ESP32 Provisioning'),
      ),
      body: Center(
        child: Text('Provisioning...'),
      ),
    );
  }
}

希望这篇文档对你理解和使用 esp_provisioning_ble 插件有所帮助!如果有任何问题或建议,请随时联系我。


更多关于Flutter蓝牙设备配置插件esp_provisioning_ble的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter蓝牙设备配置插件esp_provisioning_ble的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter项目中集成并使用esp_provisioning_ble插件来配置ESP蓝牙设备,通常涉及几个关键步骤:设置Flutter项目、添加依赖、编写蓝牙配置逻辑等。以下是一个简化的代码案例,展示如何在Flutter中使用esp_provisioning_ble插件。

步骤 1: 设置Flutter项目

首先,确保你已经有一个Flutter项目。如果没有,可以通过以下命令创建一个新的Flutter项目:

flutter create my_bluetooth_app
cd my_bluetooth_app

步骤 2: 添加依赖

pubspec.yaml文件中添加esp_provisioning_ble依赖(注意:这个插件可能是一个假想的名称,实际使用时需要替换为实际的蓝牙配置插件名称,或者如果这是一个私有插件,你需要通过正确的途径添加它):

dependencies:
  flutter:
    sdk: flutter
  esp_provisioning_ble: ^x.y.z  # 替换为实际的版本号

然后运行flutter pub get来安装依赖。

步骤 3: 编写蓝牙配置逻辑

接下来,在你的Flutter应用中编写蓝牙配置逻辑。以下是一个简化的示例,展示如何使用该插件扫描蓝牙设备并进行配置。

import 'package:flutter/material.dart';
import 'package:esp_provisioning_ble/esp_provisioning_ble.dart';  // 假设这是插件的导入路径

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  late ESPProvisioningBLE _espProvisioningBLE;
  List<BluetoothDevice> _devices = [];

  @override
  void initState() {
    super.initState();
    _espProvisioningBLE = ESPProvisioningBLE();
    _startScanning();
  }

  void _startScanning() async {
    _espProvisioningBLE.startScanning().listen((device) {
      setState(() {
        _devices.add(device);
      });
    }, onError: (error) {
      print('Scanning error: $error');
    }, onDone: () {
      print('Scanning done');
    });
  }

  void _stopScanning() {
    _espProvisioningBLE.stopScanning();
  }

  void _provisionDevice(BluetoothDevice device) async {
    // 假设有一个配置方法,这里仅作为示例
    try {
      await _espProvisioningBLE.provisionDevice(
        device: device,
        ssid: 'your_SSID',
        password: 'your_PASSWORD',
        // 其他配置参数...
      );
      print('Device provisioned successfully');
    } catch (e) {
      print('Provisioning error: $e');
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('ESP Bluetooth Provisioning'),
        ),
        body: Column(
          children: [
            Expanded(
              child: ListView.builder(
                itemCount: _devices.length,
                itemBuilder: (context, index) {
                  final device = _devices[index];
                  return ListTile(
                    title: Text(device.name ?? 'Unknown Device'),
                    trailing: IconButton(
                      icon: Icon(Icons.settings),
                      onPressed: () => _provisionDevice(device),
                    ),
                  );
                },
              ),
            ),
            ElevatedButton(
              onPressed: _stopScanning,
              child: Text('Stop Scanning'),
            ),
          ],
        ),
      ),
    );
  }

  @override
  void dispose() {
    _stopScanning();
    super.dispose();
  }
}

// 假设的BluetoothDevice类,实际使用时替换为插件提供的类
class BluetoothDevice {
  String? name;
  // 其他属性...

  BluetoothDevice({this.name});
}

注意事项

  1. 插件可用性esp_provisioning_ble是一个假设的插件名称。在实际应用中,你需要查找并使用具体的蓝牙配置插件。
  2. 权限处理:在Android和iOS平台上,你需要处理蓝牙权限和位置权限。这通常涉及到在AndroidManifest.xmlInfo.plist文件中添加相应的权限声明。
  3. 错误处理:示例代码中的错误处理较为简单。在实际应用中,你可能需要更复杂的错误处理和用户反馈机制。
  4. 插件文档:务必查阅所使用插件的官方文档,以获取最新的API信息和最佳实践。

这个代码案例提供了一个基本的框架,你可以根据实际需求进行调整和扩展。

回到顶部