0

我想要达到的目标

使用flutter_blue将数据从 Flutter 应用程序发送到连接Pycom WiPy的Pycom Pytrack 2 板

问题

当我将测试数据从 Flutter 应用程序发送到 Pycom 板时,Pycom 代码中的写入回调处理程序方法永远不会被调用。在我看来,Pycom 代码似乎无法识别或收到我从 Flutter 应用程序向其发送和写入数据的通知。我不知道是什么原因造成的,也不知道问题存在于事件链的哪个位置。也许数据从一开始就没有成功发送,或者数据到达但我的回调方法代码中有问题,它监听 Pycom 板上的传入写入。

Flutter 应用代码(发送方)

我使用 flutter_blue 库编写的一个简单的蓝牙客户端:

import 'package:flutter_blue/flutter_blue.dart';

class BluetoothClient {
  Future<List<ScanResult>> scanForDevices() async {
    FlutterBlue flutterBlue = FlutterBlue.instance;

    var scanRes = <ScanResult>[];
    flutterBlue.scanResults.listen((scanResults) {
      for (ScanResult scanResult in scanResults) {
        scanRes.add(scanResult);
      }
    });

    await flutterBlue.startScan(timeout: Duration(seconds: 4));
    await flutterBlue.stopScan();

    scanRes = filterDuplicateResults(scanRes);
    sortScanResults(scanRes);

    printScanResults(scanRes);

    return scanRes;
  }

  List<ScanResult> filterDuplicateResults(List<ScanResult> scanResults) {
    var uniques = <ScanResult>[];

    for (var scanResult in scanResults) {
      var uniquesContain = scanResultsHave(uniques, scanResult);
      if (!uniquesContain) uniques.add(scanResult);
    }

    return uniques;
  }

  sortScanResults(List<ScanResult> scanResults) {
    scanResults.sort((a, b) => a.device.name.compareTo(b.device.name));
  }

  bool scanResultsHave(List<ScanResult> scanResults, ScanResult scanResult) {
    var index = scanResults
        .indexWhere((ScanResult sr) => sr.device.id == scanResult.device.id);
    return index >= 0;
  }

  Future<List<BluetoothService>> getServices(BluetoothDevice device) async {
    var services = await device.discoverServices();
    return services;
  }

  Future<List<BluetoothCharacteristic>> getCharacteristics(
      BluetoothDevice device) async {
    var services = await getServices(device);

    var characteristics = <BluetoothCharacteristic>[];
    for (var service in services)
      characteristics.addAll(service.characteristics);

    return characteristics;
  }

  List<BluetoothDevice> getDevicesFromResults(List<ScanResult> scanResults) {
    var devices = scanResults.map((scanResult) => scanResult.device).toList();
    return devices;
  }

  Future<BluetoothDeviceState> getDeviceState(BluetoothDevice device) async {
    var stateList = await device.state.toList();
    return stateList.first;
  }

  Future connect(BluetoothDevice device) async {
    var timeout = Duration(seconds: 10);
    var autoConnect = false;
    try {
      await device.connect(timeout: timeout, autoConnect: autoConnect);
    } catch (e) {
      print(e);
    }
  }

  printScanResults(List<ScanResult> scanResults) {
    for (var scanResult in scanResults) printScanResult(scanResult);
  }

  printScanResult(ScanResult scanResult) {
    print("==== BLUETOOTH DEVICE ====");
    print("Name: ${scanResult.device.name}");
    print("Local name: ${scanResult.advertisementData.localName}");
    print("Type: ${scanResult.device.type}");
    print("Id: ${scanResult.device.id}");
    print("Connectable: ${scanResult.advertisementData.connectable}");
    print("Power level: ${scanResult.advertisementData.txPowerLevel}");
    print(
        "Manufacturer data: ${scanResult.advertisementData.manufacturerData}");
    print("Service data: ${scanResult.advertisementData.serviceData}");
    print("==========================");
  }

  Future printDeviceInfo(BluetoothDevice device) async {
    try {
      var services = await getServices(device);
      var characteristics = await getCharacteristics(device);
      print("=== DEVICE INFO ===");
      for (var service in services) print(service);
      for (var characteristic in characteristics) print(characteristic);
      print("===================");
    } catch (e) {
      print(e);
    }
  }

  Future<BluetoothService> getHardwareBoardService(BluetoothDevice device) async {
    var services = await getServices(device);
    var service =
        services.firstWhere((serv) => serv.uuid.toString().startsWith("3"));
    return service;
  }

  BluetoothCharacteristic getHardwareBoardCharacteristic(
      BluetoothService service) {
    var characteristics = service.characteristics;
    var characteristic = characteristics
        .firstWhere((char) => char.uuid.toString().startsWith("3"));
    return characteristic;
  }

  bool writeAllowed(BluetoothCharacteristic characteristic) {
    var properties = characteristic.properties;
    return properties.write;
  }

  bool writeWithoutResponseAllowed(BluetoothCharacteristic characteristic) {
    var properties = characteristic.properties;
    return properties.writeWithoutResponse;
  }
}

一个测试页面,它创建一些测试数据并在连接到板后将其发送到板。它使用上面的蓝牙客户端类与 Pycom 板对话:

import 'dart:convert';

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_blue/flutter_blue.dart';
import 'package:..._mobile/clients/BluetoothClient.dart';
import 'package:..._mobile/helpers/DeviceHelper.dart';
import 'package:..._mobile/globals.dart' as globals;
import 'package:..._mobile/widgets/Buttons/CustomIconButton.dart';
import 'package:..._mobile/widgets/Buttons/CustomTextButton.dart';

class BluetoothTestPage extends StatefulWidget {
  @override
  _BluetoothTestPageState createState() => _BluetoothTestPageState();
}

class _BluetoothTestPageState extends State<BluetoothTestPage> {
  BluetoothClient bluetoothClient;
  List<BluetoothDevice> bluetoothDevices;
  ScrollController scrollController;

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

  init() {
    scrollController = new ScrollController();
    bluetoothClient = new BluetoothClient();
    bluetoothDevices = [];
  }

  @override
  Widget build(BuildContext context) {
    DeviceHelper.readDisplayDimensions(context);
    return Scaffold(
      body: buildBody(),
    );
  }

  buildBody() {
    return Container(
      width: globals.displayWidth,
      height: globals.displayHeight,
      child: Stack(
        children: [buildControlsLayer()],
      ),
    );
  }

  buildControlsLayer() {
    return Container(
        child: Column(
      mainAxisAlignment: MainAxisAlignment.center,
      mainAxisSize: MainAxisSize.max,
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [buildScanButton(), buildDeviceList()],
    ));
  }

  buildScanButton() {
    return Expanded(
      flex: 10,
      child: CustomTextButton(
        onPressed: onScanPressed,
        text: "Scan",
      ),
    );
  }

  onScanPressed() {
    clearDeviceList();
    scanDevices();
  }

  Future scanDevices() async {
    var scanResults = await bluetoothClient.scanForDevices();
    var devices = bluetoothClient.getDevicesFromResults(scanResults);
    setBluetoothDevices(devices);
  }

  setBluetoothDevices(List<BluetoothDevice> devices) {
    if (mounted)
      setState(() {
        bluetoothDevices = devices;
      });
    else
      bluetoothDevices = devices;
  }

  buildDeviceList() {
    return Expanded(
        flex: 100,
        child: Container(
          child: Scrollbar(
            controller: scrollController,
            child: ListView(
              controller: scrollController,
              children: buildDeviceButtons(),
            ),
          ),
        ));
  }

  List<Widget> buildDeviceButtons() {
    var deviceButtons = <Widget>[];
    for (var device in bluetoothDevices) {
      var deviceButton = buildDeviceButton(device);
      deviceButtons.add(deviceButton);
    }

    return deviceButtons;
  }

  Widget buildDeviceButton(BluetoothDevice device) {
    return Container(
      child: CustomIconButton(
        text: "${device.name}, ${device.id}",
        onTap: () {
          onDeviceButtonTap(device);
        },
        iconData: Icons.devices,
      ),
    );
  }

  Future onDeviceButtonTap(BluetoothDevice device) async {
    await bluetoothClient.connect(device);
    await runDeviceTests(device);
  }

  Future runDeviceTests(BluetoothDevice device) async {
    // Print device info
    bluetoothClient.printDeviceInfo(device);

    var service = await bluetoothClient.getHardwareBoardService(device);
    var characteristic = bluetoothClient.getHardwareBoardCharacteristic(service);
    print(service);
    print(characteristic);

    var testData = buildTestData();
    await writeDataWithoutResponseToCharacteristic(characteristic, testData);

    // Send test data to device
    // await writeToDevice(device, testData);
  }

  Future writeToDevice(BluetoothDevice device, List<int> data) async {
    var characteristics = await bluetoothClient.getCharacteristics(device);
    await writeDataToCharacteristics(characteristics, data);
  }

  Future writeDataToCharacteristics(
      List<BluetoothCharacteristic> characteristics, List<int> data) async {
    for (var characteristic in characteristics) {
      await writeDataWithoutResponseToCharacteristic(characteristic, data);
    }
  }

  Future writeDataToCharacteristic(
      BluetoothCharacteristic characteristic, List<int> data) async {
    if (!bluetoothClient.writeAllowed(characteristic)) return;

    try {
      await characteristic.write(data);
    } catch (e) {
      print(e);
    }
  }

  Future writeDataWithoutResponseToCharacteristic(
      BluetoothCharacteristic characteristic, List<int> data) async {
    if (!bluetoothClient.writeWithoutResponseAllowed(characteristic)) return;

    try {
      await characteristic.write(data, withoutResponse: true);
    } catch (e) {
      print(e);
    }
  }

  List<int> buildTestData() {
    var str = "Hello bluetooth space!";
    var bytes = utf8.encode(str);
    return bytes;
  }

  clearDeviceList() {
    setBluetoothDevices([]);
  }
}

Pycom板代码(接收器)

主要.py:

from network import Bluetooth
import time

bluetooth = Bluetooth()
bluetooth.set_advertisement(name='LoPy', service_uuid=b'1234567890123456')

def char_handler(chr, data):
    print("char_handler called!!!")
    events, value = data
    if events & Bluetooth.CHAR_WRITE_EVENT:
        print("Write request with value = {}".format(value))
    else:
        print('Read request on char 1')

service = bluetooth.service(uuid=b'1234567890123456', isprimary=True)
service.start()

characteristic = service.characteristic(uuid=b'2234567890123456', permissions=14, properties=14, value=64)
characteristic.callback(trigger=Bluetooth.CHAR_WRITE_EVENT | Bluetooth.CHAR_READ_EVENT, handler=char_handler)

bluetooth.advertise(True)

while True:
    print("Listening...")
    time.sleep(3)

char_handler尽管从 Flutter 应用程序写入数据,但永远不会调用write 回调方法。

到目前为止有效的方法

我已确认设备已连接。我还确认 Flutter 应用程序写入了我在 Pycom 代码中创建的服务和特性,以侦听传入的写入。

问题

为什么 Pycom 代码没有得到通知或运行写回调方法?

谢谢!

4

0 回答 0