一篇文章讲清低功率蓝牙连接

95 阅读4分钟

在移动设备和物联网(IoT)设备日益普及的今天,蓝牙技术已经成为我们日常生活中不可或缺的一部分。特别是在需要低功耗、短距离通信的应用场景中,低功耗蓝牙(BLE, Bluetooth Low Energy)因其节能特性而受到广泛关注。本文将详细介绍低功耗蓝牙连接的工作原理、优势以及如何实现一个完整的低功耗蓝牙连接过程。

BLE 的核心特点:

  • 低功耗:相比传统蓝牙,BLE 在待机状态下几乎不消耗电量。

  • 低成本:BLE 芯片成本较低,适合大规模部署。

  • 快速连接:BLE 设备之间的连接速度非常快,通常在几毫秒内完成。

  • 小数据包传输:适用于少量数据的频繁传输。

二、BLE 连接的基本流程

BLE 连接主要包括以下几个步骤:

  1. 扫描(Scanning)

    • 中心设备(Central Device)主动扫描周围广播的外围设备(Peripheral Device)。
    • 外围设备通过广播信道发送广告包(Advertising Packet),包含设备名称、服务 UUID 等信息。
  2. 连接建立(Connection Establishment)

    • 中心设备选择目标外围设备后,发起连接请求。
    • 双方协商连接参数,如连接间隔、超时时间等。
  3. 服务发现(Service Discovery)

    • 连接成功后,中心设备会查询外围设备提供的服务(Services)和特征值(Characteristics)。
  4. 数据交互(Data Exchange)

    • 通过读写特征值或使用通知机制进行数据交换。
  5. 断开连接(Disconnection)

  • 当不再需要通信时,任一方可以主动断开连接以节省能耗。

三、代码实践

1. 页面结构与 UI 设计

该页面提供了一个用户界面,允许用户搜索并选择附近的 BLE 设备进行打印操作。UI 包含标题、提示信息、设备列表等元素。

<template>
  <div class="bluetooth-container">
    <h2 class="bluetooth-title">请选择蓝牙设备进行打印</h2>
    <p class="bluetooth-hint">推荐使用低功耗蓝牙打印机,推荐型号:p_11</p>
    <div class="bluetooth-list">
      <div class="bluetooth-header">
        <div class="device-name">设备名称</div>
        <div class="device-status">设备状态</div>
      </div>
      <div v-for="(item, index) in matchDevice" :key="index" class="bluetooth-item" @click="handlePrint(item.id, index)">
        <div class="device-name">{{ item.name }}</div>
        <div class="device-status">{{ item.device_status === 1 ? "可用" : "不可用" }}</div>
      </div>
    </div>
  </div>
</template>

2. BLE 初始化与权限申请

初始化蓝牙模块

 async initBluetooth() {      console.log('开始初始化蓝牙模块---->',);      this.blueToothTip = "初始化蓝牙模块--------";      var _this = this;      // 打开蓝牙      plus.bluetooth.openBluetoothAdapter({        success: function(e) {          _this.blueToothTip = "蓝牙打开成功... ";        },        fail: function(e) {          _this.blueToothTip = "蓝牙打开失败,请手动操作...";          _this.loading = false;        },        // 打开蓝牙完成回调函数        complete(e) {          if (!e.errCode) {            _this.blueToothTip = "初始化完成...";            _this.blueToothTip = "开始搜索设备...";            // 开始搜索设备            _this.searchDevices();          } else if (e.errCode == 10001) {            _this.$toast({              icon: "none",              title: "请打开手机蓝牙"            });          } else {            _this.$toast({              icon: "none",              title: e.errMsg            });          }        }      });    },

3.Android 权限请求

由于 Android 对位置权限有严格限制,BLE 搜索必须先获取 ACCESS_COARSE_LOCATION 权限:

requestAndroidPermission(permissionID) {
  return new Promise((resolve, reject) => {
    plus.android.requestPermissions([permissionID], function(resultObj) {
      // 处理授权结果
    });
  });
}

4. 搜索 BLE 设备

searchDevices(address = "C8:47:54:BD:33:A8", index) {
  plus.bluetooth.startBluetoothDevicesDiscovery({
    success: function(e) {
      console.log("搜索设备成功");
    },
    fail: function(e) {
      console.error("搜索设备失败");
    },
    complete: async (e) => {
      if (!e.errCode) {
        let main = plus.android.runtimeMainActivity();
        let IntentFilter = plus.android.importClass("android.content.IntentFilter");
        let BluetoothDevice = plus.android.importClass("android.bluetooth.BluetoothDevice");

        let receiver = plus.android.implements("io.dcloud.android.content.BroadcastReceiver", {
          onReceive: function(context, intent) {
            if (intent.getAction() == "android.bluetooth.adapter.action.DISCOVERY_FINISHED") {
              main.unregisterReceiver(receiver);
              console.log("搜索结束");
            } else {
              let device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
              if (device.getName()) {
                let obj = {
                  id: device.getAddress(),
                  name: device.getName(),
                  device_status: device.getName() == "P11_PRINTER" ? 1 : 0
                };
                this.matchDevice.push(obj);
              }
            }
          }
        });

        let filter = new IntentFilter();
        filter.addAction(BluetoothDevice.ACTION_FOUND);
        main.registerReceiver(receiver, filter);
      }
    }
  });
}

5. BLE 打印逻辑实现

连接设备并发送打印指令

async handlePrint(deviceMac, index) {
  const UUID = plus.android.importClass("java.util.UUID");
  const uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");

  const BAdapter = plus.android.importClass("android.bluetooth.BluetoothAdapter").getDefaultAdapter();
  const device = BAdapter.getRemoteDevice(deviceMac);
  const bluetoothSocket = device.createInsecureRfcommSocketToServiceRecord(uuid);

  await bluetoothSocket.connect();

  const outputStream = bluetoothSocket.getOutputStream();
  const writer = new OutputStreamWriter(outputStream, "GBK");

  // 发送打印命令
  await writer.write("\x1B\x45\x01"); // 加粗
  await writer.write("车牌号:" + this.vehicleItem.licensePlate + "\r\n");
  await writer.write("停车地点:路侧test" + this.vehicleItem.berthNumber + "\r\n");
  await writer.write("入场时间:" + this.vehicleItem.entryTime + "\r\n");
  await writer.write("离场时间:" + this.vehicleItem.exitTime + "\r\n");
  await writer.write("需要缴费:" + this.vehicleItem.fee + "\r\n");
  await writer.flush();

  bluetoothSocket.close();
}

项目地址:gitee.com/caoshuguang…

这个是我连接的小票机(美恒通联系他客户可以给到项目测试源码,但是那个是小程序版本的),而且目前市场上也可以下载到美恒通官网提供的打印软件apk,问客户是否有apk版本的demo代码,他们说没有。

这里电脑跑的是小程序版本,手机跑的是自己的项目

这是打印出来的效果,还是支持打印二维码的,如上图。