我想要达到的目标
使用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 代码没有得到通知或运行写回调方法?
谢谢!