当前位置: 首页 > news >正文

Dart 实现与蓝牙设备的通信

要使用 Dart 实现与蓝牙设备的通信,需要按照以下步骤进行。以下是详细的实现思路和代码示例:


1. 理解蓝牙协议

从提供的表格中可以看到,该蓝牙协议包含以下关键部分:

  • 包头0x59 0x59
  • 包长0x06(表示数据包长度)
  • 功能项0x0a(标识功能类别)
  • 功能参数:具体的功能指令(如 0102 等)
  • 校验和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. 注意事项

  1. 权限管理

    • 在 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" />
      
  2. 设备兼容性

    • 不同设备的蓝牙服务和特征可能不同,需要根据实际设备调整服务和特征的 UUID。
  3. 错误处理

    • 蓝牙通信可能会出现超时或连接失败的情况,需要做好异常捕获和重试机制。
  4. 校验和验证

    • 确保校验和的计算逻辑与设备端一致,避免因校验和错误导致通信失败。

5. 总结

通过上述步骤,您可以使用 Dart 和 flutter_blue 插件实现与蓝牙设备的通信,并根据提供的协议发送和接收数据。关键在于正确解析协议格式,并确保数据包的完整性(包括校验和)。

相关文章:

  • JSON 基础知识(一)
  • 碰一碰发视频系统--基于H5场景开发
  • 【一起来学kubernetes】32、kubectl使用详解
  • 视频分析设备平台EasyCVR安消一体化解决方案,打造社区/园区全面可视化智能安消应用
  • HNSW(Hierarchical Navigable Small World,分层可导航小世界)用来高效搜索高维向量的最近邻
  • JAVA常见的 JVM 参数及其典型默认值
  • CMMI(能力成熟度模型集成)简介
  • 蓝桥复习2(温度开始)
  • 系统思考反馈
  • 写Prompt的技巧和基本原则
  • PyQt6基础_界面控件简单介绍III
  • 【夜话系列】DelayQueue延迟队列(上):原理剖析与实现机制
  • 公网专线IP和私网专线IP之间的区别是什么?
  • 定时任务(python)
  • nodejs:midi-writer-js 将基金净值数据转换为 midi 文件
  • 多线程猜数问题
  • AI CUDA 工程师:Agentic CUDA 内核发现、优化和组合
  • 前后台系统
  • JavaScript单例模式
  • JS—Token与JWT
  • 体坛联播|水晶宫队史首夺足总杯,CBA总决赛爆发赛后冲突
  • 香港特区政府强烈谴责美参议员恐吓国安人员
  • 舞者王佳俊谈“与AI共舞”:像多了一个舞伴,要考虑它的“感受”
  • 对谈|“大礼议”:嘉靖皇帝的礼法困境与权力博弈
  • 中国物流集团等10家央企11名领导人员职务任免
  • “家国万里时光故事会” 举行,多家庭共话家风与家国情怀