Dart 实现与蓝牙设备的通信
要使用 Dart 实现与蓝牙设备的通信,需要按照以下步骤进行。以下是详细的实现思路和代码示例:
1. 理解蓝牙协议
从提供的表格中可以看到,该蓝牙协议包含以下关键部分:
- 包头:
0x59 0x59
- 包长:
0x06
(表示数据包长度) - 功能项:
0x0a
(标识功能类别) - 功能参数:具体的功能指令(如
01
、02
等) - 校验和:
ADD8
校验和(通常是对数据包内容的累加校验)
协议要点
-
包结构:
- 固定包头:
0x59 0x59
- 包长:
0x06
(固定值) - 功能项:
0x0a
- 功能参数:根据功能需求动态变化
- 校验和:对包头、包长、功能项和功能参数的累加校验
- 固定包头:
-
校验和计算规则:
- 将包头、包长、功能项和功能参数的所有字节相加,取低 8 位作为校验和。
2. Dart 中的蓝牙通信
Dart 提供了 flutter_blue
插件,用于实现蓝牙通信。以下是实现步骤:
步骤 1:添加依赖
在 pubspec.yaml
文件中添加 flutter_blue
依赖:
dependencies:
flutter_blue: ^latest_version
步骤 2:初始化蓝牙模块
在应用中初始化蓝牙模块,并扫描设备:
import 'package:flutter_blue/flutter_blue.dart';
FlutterBlue flutterBlue = FlutterBlue.instance;
// 扫描蓝牙设备
Future<void> scanDevices() async {
await flutterBlue.startScan(timeout: Duration(seconds: 4));
List<BluetoothDevice> devices = [];
flutterBlue.scanResults.listen((results) {
for (var r in results) {
if (!devices.contains(r.device)) {
devices.add(r.device);
print('Found device: ${r.device.name} - ${r.device.id}');
}
}
});
}
步骤 3:连接蓝牙设备
找到目标设备后,连接到设备并获取服务和特征:
Future<void> connectToDevice(BluetoothDevice device) async {
try {
await device.connect();
print('Connected to device: ${device.name}');
// 获取服务
List<BluetoothService> services = await device.discoverServices();
for (var service in services) {
print('Service UUID: ${service.uuid.toString()}');
for (var characteristic in service.characteristics) {
print('Characteristic UUID: ${characteristic.uuid.toString()}');
}
}
} catch (e) {
print('Failed to connect: $e');
}
}
步骤 4:发送数据
根据协议构造数据包,并通过特征写入数据:
void sendData(BluetoothCharacteristic characteristic, int functionCode, int parameter) {
// 构造数据包
List<int> packet = [
0x59, 0x59, // 包头
0x06, // 包长
0x0a, // 功能项
functionCode, // 功能码
parameter, // 参数
calculateChecksum([0x59, 0x59, 0x06, 0x0a, functionCode, parameter]) // 校验和
];
// 发送数据
characteristic.write(packet).then((_) {
print('Data sent successfully: $packet');
}).catchError((error) {
print('Failed to send data: $error');
});
}
int calculateChecksum(List<int> data) {
int checksum = 0;
for (var byte in data) {
checksum += byte;
}
return checksum & 0xFF; // 取低 8 位
}
步骤 5:接收数据
如果设备有反馈,可以通过监听特征值的变化来接收数据:
void listenForData(BluetoothCharacteristic characteristic) {
characteristic.value.listen((data) {
print('Received data: $data');
// 解析接收到的数据
});
}
3. 示例代码
以下是完整的示例代码,展示如何连接蓝牙设备并发送指令:
import 'package:flutter/material.dart';
import 'package:flutter_blue/flutter_blue.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
home: BluetoothApp(),
);
}
}
class BluetoothApp extends StatefulWidget {
_BluetoothAppState createState() => _BluetoothAppState();
}
class _BluetoothAppState extends State<BluetoothApp> {
FlutterBlue flutterBlue = FlutterBlue.instance;
BluetoothDevice? connectedDevice;
BluetoothCharacteristic? writeCharacteristic;
void initState() {
super.initState();
initBluetooth();
}
Future<void> initBluetooth() async {
await flutterBlue.initialize();
scanDevices();
}
Future<void> scanDevices() async {
await flutterBlue.startScan(timeout: Duration(seconds: 4));
flutterBlue.scanResults.listen((results) {
for (var r in results) {
print('Found device: ${r.device.name} - ${r.device.id}');
connectToDevice(r.device);
}
});
}
Future<void> connectToDevice(BluetoothDevice device) async {
try {
await device.connect();
setState(() {
connectedDevice = device;
});
// 获取服务和特征
List<BluetoothService> services = await device.discoverServices();
for (var service in services) {
for (var characteristic in service.characteristics) {
if (characteristic.properties.write) {
writeCharacteristic = characteristic;
break;
}
}
}
if (writeCharacteristic != null) {
print('Found writable characteristic: ${writeCharacteristic!.uuid}');
}
} catch (e) {
print('Failed to connect: $e');
}
}
void sendData(int functionCode, int parameter) {
if (writeCharacteristic == null) return;
List<int> packet = [
0x59, 0x59, // 包头
0x06, // 包长
0x0a, // 功能项
functionCode, // 功能码
parameter, // 参数
calculateChecksum([0x59, 0x59, 0x06, 0x0a, functionCode, parameter]) // 校验和
];
writeCharacteristic!.write(packet).then((_) {
print('Sent data: $packet');
}).catchError((error) {
print('Failed to send data: $error');
});
}
int calculateChecksum(List<int> data) {
int checksum = 0;
for (var byte in data) {
checksum += byte;
}
return checksum & 0xFF; // 取低 8 位
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Bluetooth App')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () => sendData(0x01, 0x00), // 按摩椅开机
child: Text('开机'),
),
ElevatedButton(
onPressed: () => sendData(0x02, 0x00), // 开关机
child: Text('开关机'),
),
ElevatedButton(
onPressed: () => sendData(0x00, 0x00), // 按摩开始
child: Text('按摩开始'),
),
],
),
),
);
}
}
4. 注意事项
-
权限管理:
- 在 Android 和 iOS 上,确保申请了蓝牙相关的权限。
- Android 需要在
AndroidManifest.xml
中声明蓝牙权限:<uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
-
设备兼容性:
- 不同设备的蓝牙服务和特征可能不同,需要根据实际设备调整服务和特征的 UUID。
-
错误处理:
- 蓝牙通信可能会出现超时或连接失败的情况,需要做好异常捕获和重试机制。
-
校验和验证:
- 确保校验和的计算逻辑与设备端一致,避免因校验和错误导致通信失败。
5. 总结
通过上述步骤,您可以使用 Dart 和 flutter_blue
插件实现与蓝牙设备的通信,并根据提供的协议发送和接收数据。关键在于正确解析协议格式,并确保数据包的完整性(包括校验和)。