uniapp对接打印机和电子秤

uniapp对接打印机和电子秤

连接电子秤和打印机,最难的不是连接蓝牙和电子成,而是打印机。因为打印机涉及到向打印机写数据操作,然后这个写的数据需要做一个编码转换。难就难在编码转换。如果是java那就是一句代码的事情,而js就没有那么简单了。其实js也是一句代码的事情,打印机接收的的编码为GBK,但是hbuilderx编码为 UTF-8。编码转换我们可以使用 encoding.js或者 GBK.js,但是这些引入方式为 var encode = require("./encoding.js");Vue3已经废弃 require这种引入方式,所以没有办法引入 。使用 new TextDecoder('gbk').decode(codes)可以解决,但是只能在浏览器里面解决,手机不支持这个命令。所有将编码转换成GBK,并且转换后返回10进制的数组打印。打印机编码可以设置为UTF-8,但是不靠谱,不通用,这样也面临着数据转成10进制后似乎也有问题。

我找到一个文件进过更改后可以解决这个问题,下面对接打印机详细讲解。

一、连接蓝牙

参考:https://uniapp.dcloud.net.cn/api/system/bluetooth.html#openbluetoothadapter

  1. 初始化蓝牙模块
  2. 开始搜寻附近的蓝牙外围设备
  3. 监听寻找到新设备的事件(这里可以设备信息)
  4. 连接低功耗蓝牙设备。
  5. 获取蓝牙设备所有服务(service)。
  6. 根据设备获取蓝牙特征值(一个设备特征值很多,这个设备 支持读,写,异步监听等就看这个特征值了。)

1.1、初始化蓝牙

// 初始化蓝牙
uni.openBluetoothAdapter({success: (res) => {that.connectLog.push("蓝牙初始化完成")},fail: (res) => {}
});

1.2、开始搜寻附近的蓝牙外围设备

这异步需要初始化蓝牙完成在操作

uni.startBluetoothDevicesDiscovery({// services: ['0000FFE0'],success: res => {},fail: res => {that.connectLog.push("查找设备失败")}
});

1.3、发现外围设备

这一步才是真正的搜索附近的蓝牙设备

uni.onBluetoothDeviceFound(res => {console.log(res)
});

这里会频繁的调用,因为搜索到一个设备调用一次。

在这里插入图片描述

注意:deviceId,name要保存下来,后面需要使用。

1.4、连接蓝牙设备

uni.createBLEConnection({ //创建蓝牙连接,连接低功耗蓝牙设备deviceId: item.deviceId, //传入刚刚获取的uuidsuccess(res) {},fail(res) {that.connectLog.push("创建连接失败")}
})

这里的 deviceId既是 uni.onBluetoothDeviceFound中过去到的 deviceId

1.5、获取蓝牙设备所有服务

蓝牙已经连接成功了,获取这个蓝牙设备有哪些服务,获取蓝牙特征值需要使用蓝牙服务的uuid。因为每个蓝牙有很多服务,每个服务的特征值不同,需要根据蓝牙特征值来寻找是否可以写,可以读,可以监听。

uni.getBLEDeviceServices({ //获取蓝牙设备所有服务deviceId: deviceId,success(res) { //为什么要用延时,因为不用延时就拿不到所有的服务,在上一步,连接低功耗蓝牙//设备的时候,需要一个600-1000毫秒的时间后,再去获取设备所有服务,不给延时就会一直返回错误码10004console.log("蓝牙可用服务:", res)},fail(res) {console.log("搜索蓝牙服务失败:", res)that.connectLog.push("搜索蓝牙服务失败")}
})

这里的 deviceId既是 uni.onBluetoothDeviceFound中过去到的 deviceId

在这里插入图片描述

1.6、获取蓝牙特征值

uni.getBLEDeviceCharacteristics({ //获取蓝牙设备某个服务中所有特征值deviceId: that.deviceId,serviceId: item.uuid, //这个serviceId可以在上一步获取中拿到,也可以在success(res) {console.log("获取特征值:", res)},fail(res) {}
})

这里的 deviceId既是 uni.onBluetoothDeviceFound中获取到的 deviceId

serviceId获取蓝牙服务时获取到的服务uuid

一台蓝牙设备有多个服务,一个服务可以获取多个蓝牙特征值,需要循环所有的蓝牙服务,去获取蓝牙特征值,找到符合自己需求的特征值即可,除非蓝牙设备不支持。

在这里插入图片描述

1.7、连接蓝牙完整步骤

// 第一步 在页面显示的时候判断是否已经初始化完成蓝牙适配器若成功,则开始查找设备
openBluetoothAdapter() {let that = this// 初始化蓝牙uni.openBluetoothAdapter({success: (res) => {// 初始化完毕开始搜索that.StartBluetoothDeviceDiscovery()},fail: (res) => {}});
},
/*** 第二步 在页面显示的时候判断是都已经初始化完成蓝牙适配器若成功,则开始查找设备*/
StartBluetoothDeviceDiscovery() {let that = thisuni.startBluetoothDevicesDiscovery({// services: ['0000FFE0'],success: res => {that.OnBluetoothDeviceFound();},fail: res => {that.connectLog.push("查找设备失败")}});
},
/*** 第三步  发现外围设备*/
OnBluetoothDeviceFound() {let that = thisuni.onBluetoothDeviceFound(res => {res.devices.forEach(device => { //这一步就是去筛选找到的蓝牙中,有没有你匹配的名称if (device.name === "MPT-II") {// 连接蓝牙that.CreateBLEConnection(device)// 找到需要连接的蓝牙了,可以关闭蓝牙搜索了。that.StopBluetoothDevicesDiscovery()}})});
},// 
/*** 第四步 停止搜索蓝牙设备*/
StopBluetoothDevicesDiscovery() {let that = thisuni.stopBluetoothDevicesDiscovery({success: res => {console.log("第四步 找到匹配的蓝牙后就关掉蓝牙搜寻:", JSON.stringify(res))},fail: res => {console.log('第四步 停止搜索蓝牙设备失败,错误码:' + res.errCode);}});
},
// 第五步 创建蓝牙连接,连接低功耗蓝牙设备
CreateBLEConnection(item) {let that = thisuni.createBLEConnection({ //创建蓝牙连接,连接低功耗蓝牙设备deviceId: item.deviceId, //传入刚刚获取的uuidsuccess(res) {that.GetBLEDeviceServices(item.deviceId) //获取蓝牙设备所有服务(service)。},fail(res) {that.connectLog.push("创建连接失败")}})
},//第六步 获取蓝牙设备所有服务(service)。
GetBLEDeviceServices(deviceId) {let that = thissetTimeout(() => {uni.getBLEDeviceServices({ //获取蓝牙设备所有服务deviceId: deviceId,success(res) { //为什么要用延时,因为不用延时就拿不到所有的服务,在上一步,连接低功耗蓝牙//设备的时候,需要一个600-1000毫秒的时间后,再去获取设备所有服务,不给延时就会一直返回错误码10004console.log("蓝牙可用服务:", res)that.GetBLEDeviceCharacteristics(deviceId, res) //获取蓝牙设备某个服务中所有特征值},fail(res) {console.log("搜索蓝牙服务失败:", res)that.connectLog.push("搜索蓝牙服务失败")}})}, 1000)
},
// 第七步 获取蓝牙特征值
GetBLEDeviceCharacteristics(deviceId, item) {let that = this// 获取当前连接这个蓝牙的可用服务setTimeout(() => {item.services.forEach((services) => {console.log("服务:", services)uni.getBLEDeviceCharacteristics({ //获取蓝牙设备某个服务中所有特征值deviceId: deviceId,serviceId: services.uuid, //这个serviceId可以在上一步获取中拿到,也可以在success(res) {console.log("特征值", res)// 循环筛选蓝牙特征值,筛选到符合打印机的特征值为止res.characteristics.forEach((ch) => {// 判断是否支持打印if (ch.properties.write) {// 连接蓝牙最终就是使用者三个值。console.log("蓝牙设备deviceId:", deviceId)console.log("使用蓝牙服务uuid:", services.uuid)console.log("特征值uuid:", ch.uuid)// 这里不能结束最外层循环,就让他全部循环完成把,反正也不多。return}})},fail(res) {that.connectLog.push("获取特征值失败")console.log("获取蓝牙设备某个服务中所有特征值失败:", JSON.stringify(res))}})})}, 2000)
},

二、对接电子秤

2.1、使用

uni.notifyBLECharacteristicValueChange({state: true, // 启用 notify 功能deviceId: that.deviceId, // 蓝牙设备 deviceIdserviceId: that.serviceId, // 蓝牙服务uuidcharacteristicId: that.characteristicId, // 蓝牙特征值uuidsuccess(res) {console.log('订阅电子秤成功', res.errMsg)// 电子秤回调事件uni.onBLECharacteristicValueChange(function(res) {const buffer = new Uint8Array(res.value);var dataString = "";for (var i = 0; i < buffer.length; i++) {dataString += String.fromCharCode(buffer[i]);}that.weight = dataString})}
})

需要的三个参数,连接蓝牙,的时候就说过怎么获取了。

这里千万需要注意: uni.onBLECharacteristicValueChange返回的是重量,这里要看电子秤厂商给我们返回啥。我的电子秤是和厂商说好的,值返回重量,所以这里直接把ArrayBuffer转成普通文本,我就能得到了重量。

在这里插入图片描述

2.2、完整案列

注意:连接电子秤部分,我直接将电子秤的蓝牙名称写死了,这样方便操作,今后电子秤蓝牙名称不同的,需要更改。

<template><!-- 打印 --><view class="balance-box"><!-- 操作区 --><view class="operation-box"><button @click="openBluetoothAdapter">连接蓝牙</button><input class="balance-input" :value="weight" placeholder="这里是电子秤返回数据" /></view><!-- 显示连接蓝牙日志 --><view class="connect-log"><view v-for="(log,index) in connectLog" :key="index">{{log}}</view></view></view>
</template><script>export default {data() {return {connectLog: [], // 日志weight: null, // 获取到的重量deviceId: null, // 蓝牙设备的 deviceId// 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取serviceId: null, // 蓝牙服务uuid// 这里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取characteristicId: null, // 蓝牙特征值uuid}},methods: {openBluetoothAdapter() {let that = this// 初始化蓝牙uni.openBluetoothAdapter({success: (res) => {// 初始化完毕开始搜索that.StartBluetoothDeviceDiscovery()},fail: (res) => {}});},/*** 第二步 在页面显示的时候判断是都已经初始化完成蓝牙适配器若成功,则开始查找设备*/StartBluetoothDeviceDiscovery() {let that = thisuni.startBluetoothDevicesDiscovery({// services: ['0000FFE0'],success: res => {that.OnBluetoothDeviceFound();},fail: res => {// that.connectLog.push("查找设备失败")}});},/*** 第三步  发现外围设备*/OnBluetoothDeviceFound() {let that = thisuni.onBluetoothDeviceFound(res => {res.devices.forEach(device => { //这一步就是去筛选找到的蓝牙中,有没有你匹配的名称if (device.name === "ANDZ") {// 连接蓝牙that.CreateBLEConnection(device)// 找到需要连接的蓝牙了,可以关闭蓝牙搜索了。that.StopBluetoothDevicesDiscovery()}})});},// /*** 第四步 停止搜索蓝牙设备*/StopBluetoothDevicesDiscovery() {let that = thisuni.stopBluetoothDevicesDiscovery({success: res => {console.log("第四步 找到匹配的蓝牙后就关掉蓝牙搜寻:", JSON.stringify(res))},fail: res => {console.log('第四步 停止搜索蓝牙设备失败,错误码:' + res.errCode);}});},// 第五步 创建蓝牙连接,连接低功耗蓝牙设备CreateBLEConnection(item) {let that = thisuni.createBLEConnection({ //创建蓝牙连接,连接低功耗蓝牙设备deviceId: item.deviceId, //传入刚刚获取的uuidsuccess(res) {that.GetBLEDeviceServices(item.deviceId) //获取蓝牙设备所有服务(service)。},fail(res) {}})},//第六步 获取蓝牙设备所有服务(service)。GetBLEDeviceServices(deviceId) {let that = thissetTimeout(() => {uni.getBLEDeviceServices({ //获取蓝牙设备所有服务deviceId: deviceId,success(res) { //为什么要用延时,因为不用延时就拿不到所有的服务,在上一步,连接低功耗蓝牙//设备的时候,需要一个600-1000毫秒的时间后,再去获取设备所有服务,不给延时就会一直返回错误码10004console.log("蓝牙可用服务:", res)that.GetBLEDeviceCharacteristics(deviceId, res) //获取蓝牙设备某个服务中所有特征值},fail(res) {console.log("搜索蓝牙服务失败:", res)}})}, 1000)},// 第七步 获取蓝牙特征值GetBLEDeviceCharacteristics(deviceId, item) {let that = this// 获取当前连接这个蓝牙的可用服务setTimeout(() => {item.services.forEach((services) => {console.log("服务:", services)uni.getBLEDeviceCharacteristics({ //获取蓝牙设备某个服务中所有特征值deviceId: deviceId,serviceId: services.uuid, //这个serviceId可以在上一步获取中拿到,也可以在success(res) {console.log("特征值", res)// 循环筛选蓝牙特征值,筛选到符合打印机的特征值为止res.characteristics.forEach((ch) => {// 判断是否支持打印if (ch.properties.notify) {// 连接蓝牙最终就是使用者三个值。// console.log("蓝牙设备deviceId:", deviceId)// console.log("使用蓝牙服务uuid:", services.uuid)// console.log("特征值uuid:", ch.uuid)that.deviceId = deviceIdthat.serviceId = services.uuidthat.characteristicId = ch.uuid// 这里不能结束最外层循环,就让他全部循环完成把,反正也不多。setTimeout(() => {that.onNotifyBLECharacteristicValueChange()}, 1500)return}})},fail(res) {console.log("获取蓝牙设备某个服务中所有特征值失败:", JSON.stringify(res))}})})}, 2000)},// 监听电子秤onNotifyBLECharacteristicValueChange() {let that = thisuni.notifyBLECharacteristicValueChange({state: true, // 启用 notify 功能deviceId: that.deviceId, // 蓝牙设备 deviceIdserviceId: that.serviceId, // 蓝牙服务uuidcharacteristicId: that.characteristicId, // 蓝牙特征值uuidsuccess(res) {console.log('订阅电子秤成功', res.errMsg)// 电子秤回调事件uni.onBLECharacteristicValueChange(function(res) {const buffer = new Uint8Array(res.value);var dataString = "";for (var i = 0; i < buffer.length; i++) {dataString += String.fromCharCode(buffer[i]);}that.weight = dataString})}})},}}
</script><style lang="scss">.balance-box {display: flex;.operation-box {width: 70%;overflow: auto;.balance-input {height: 80rpx;border-radius: 10rpx;border: 2rpx solid saddlebrown;}}.connect-log {display: flex;flex-direction: column;position: sticky;top: 0;width: 30%;color: #fff;height: 100vh;overflow: auto;background-color: rgba(0, 0, 0, 0.2);view {margin: 10rpx 0;}}}
</style>

三、对接打印机

3.1、对接打印机

// 第八步 发送二进制数据
WriteBLECharacteristicValue() {// returnlet that = this// 打印的内容uni.writeBLECharacteristicValue({// 蓝牙设备 deviceIddeviceId: that.deviceId,// 蓝牙服务uuidserviceId: that.serviceId,// 蓝牙特征值uuidcharacteristicId: that.characteristicId,// 打印的数据,ArrayBuffer 类型,数据为 10进制或者16进制。编码方式:GBKvalue: [178, 226, 202, 212, 163, 161, 163, 161, 163, 161, 13, 10],success(res) {console.log("打印成功")},fail(res) {console.log("打印失败", res)}})
},

对接打印机,难点在value的值,这个是ArrayBuffer类型的,这个里面可以放10进制和16进制,我是使用10进制的。例如:[27,100,2]表示走纸2行[27,100,3]表示走纸三行。为什么是[27,100,n]这个要看打印机的指令说明文档,里面有10进制和16进制的。不同厂商的打印机指令有差异。

并且value的数据最多只能有20个,多了需要拆分开,批量发送。

3.2、编码转换

编码转换就是在前言所说的这个困惑,由于我使用的是Vue3,所以不支持var encode = require("./encoding.js");方式引入。编码转换的jsencoding.jsGBK.js,但是这两种都是require引入的方式,所以Vue3无法使用,uniapp的手机端 不支持 new TextDecoder('gbk').decode(codes),百思不得其解的时刻,偶然间发现 GBK.js的另外一个版本有改动的希望,所以我使用 GBK.js的另外一个版本改动了一下,成功解决这个困惑。

3.2.1、GBK文件改动

文件来源:https://github.com/EtherDream/str2gbk

在这里插入图片描述

这个文件在Vue3中可以使用,但是有一个地方使用了 new TextDecoder('gbk').decode(codes),因为手机端不支持这个,但是浏览器支持。看看GBK.js源代码。

在这里插入图片描述

最终看到这里,因为这个js文件里面的 table数组的数据的来源是,根据codes参数通过 new TextDecoder('gbk').decode(codes)转换得到的,而 codes参数又是通过一段算法计算得到,都与我们的参数无关,可以说是一段死的数据。那么我们就可以在浏览器里面执行,将最终转换后的 table集合数据获取到,直接卸载文件里面,这样就可以解决 UTF-8编码转为GBK编码的问题,并且转换后 是10进制的 Uint8Array 数组,刚好符合打印条件。转换后的gbk.js这个文件已经放在当前目录的 doc文件夹下面。

3.2.2、使用GBK.js

  • 引入文件
import gbk from "./gbk.js"
  • 使用
let data = gbk("这是打印的内容,不得有误。")
console.log(data)
  • 返回数据案例
213,226,202,199,180,242,211,161,181,196,196,218,200,221,163,172,178,187,181,195,211,208,206,243,161,163

是个数组,只是打印出来的时候是这样子而已。这个数据可以直接打印了,只是不能超过20个,多的话需要拆分发送,3.3拆分打印数据有现成方法。

3.3、拆分打印数据

因为 value最多只能发送20个,所以需要拆分批量发送。

/*** 拆分打印数据并打印,将uint8Array打印的数据拆分成,最多 20* @param {Object} deviceId 蓝牙设备deviceId* @param {Object} serviceId 服务uuid* @param {Object} characteristicId 蓝牙特征值uuid* @param {Object} uint8Array 打印数据*/
senBlData(deviceId, serviceId, characteristicId, uint8Array) {var that = this;console.log('************deviceId = [' + deviceId + ']  serviceId = [' + serviceId +'] characteristics=[' + characteristicId + "]")var uint8Buf = Array.from(uint8Array);function split_array(datas, size) {var result = {};var j = 0for (var i = 0; i < datas.length; i += size) {result[j] = datas.slice(i, i + size)j++}console.log(result)return result}var sendloop = split_array(uint8Buf, 20);function realWriteData(sendloop, i) {var data = sendloop[i]if (typeof(data) == "undefined") {return}console.log("第【" + i + "】次写数据" + data)var buffer = new ArrayBuffer(data.length)var dataView = new DataView(buffer)for (var j = 0; j < data.length; j++) {dataView.setUint8(j, data[j]);}// 调动打印机打印uni.writeBLECharacteristicValue({deviceId,serviceId,characteristicId,value: buffer,success(res) {realWriteData(sendloop, i + 1);},fail(e) {console.log("点错误:", e)realWriteData(sendloop, i + 1);}})}var i = 0;realWriteData(sendloop, i);
},

3.4、打印指令讲解

打印指令就像是命令,发送什么样的命令干什么样的事情。打印机的指令有十进制和十六进制两种,如果使用十六进制的,会遇到 x011,0x0a,0x1c,0x10等,而这里的 x0C语言里面表示指令的意思,没有其他作用,但是发送的时候得这样写,真正的指令是后面的 11,0a,1c,10

不同打印机的指令不同,估计大多都一样把,我目前使用的打印机是 “便捷式打印机MoilePrinter”这种。

特备强调:打印机如果设置了,没有恢复,那么后面打印的所有内容都是按照设置后的打印,除非发送设置默认命令或者关机重启。例如:将行间距设置为150,那么后面打印的所有内容都是150行间距,如果发送了恢复行间距了,后面打印的行间距为默认行间距。

3.4.1、打印机指令使用说明

首先拿着打印机指令说明,需要看看打印机参数。比如:编码方式,多少点每行。这些都是需要使用的到,必须了解。

在这里插入图片描述

说明书里面的指令列表可以不同看,最关键的是指令详解。

在这里插入图片描述

在这里插入图片描述

案列
  • 走纸60 行
// 打印的内容
uni.writeBLECharacteristicValue({// 蓝牙设备 deviceIddeviceId: that.deviceId,// 蓝牙服务uuidserviceId: that.serviceId,// 蓝牙特征值uuidcharacteristicId: that.characteristicId,// 打印的数据,ArrayBuffer 类型,数据为 10进制或者16进制。编码方式:GBKvalue: [27,100,60],success(res) {console.log("打印成功")},fail(res) {console.log("打印失败", res)}
})

在这里插入图片描述

  • 打印 这是测试打印机 并走纸 2 行
printData() {// 打印的数据let command = []// 打印的数据,这里的 \r\n表示换行,必须要进过转码let data = gbk("这是测试打印机")data.forEach((d) => {command.push(d)})// 打印指令let instruct = [27, 100, 2]// 将打印指令增加到 打印的数据中,因为是打印为在走纸两行,所以说 27,100,2 要增加在打印数据的后面,【 27,100,2  这三个数字就相当于中文对人说 ,走纸两			行。而这里是对机器说走纸两行,机器的走纸两行的语言就是  27,100,2】instruct.forEach((d) => {command.push(d)})// 这里打印的数据可能超过20个字符了,所有拆分批量打印。this.senBlData(this.deviceId, this.serviceId, this.characteristicId, command)
},

“这是测试打印机”这几个中文通过 gbk()转码后得到的Uint8Array 数组是 213, 226, 202, 199, 178, 226, 202, 212, 180, 242, 211, 161, 187, 250,打印并走纸两行 的十进制是 27,100,2。是先打印然后在走纸,所以走纸的命令要增加在后面,所以最终打印数据为:

213, 226, 202, 199, 178, 226, 202, 212, 180, 242, 211, 161, 187, 250, 27, 100, 2

3.4.1、打印并进纸n行

27 100 n

0 ≤ n ≤ 255

在这里插入图片描述

3.4.2、设置行间距

在这里插入图片描述

  • 实例值
27, 51, 255

3.4.3、设置行间距为默认

在这里插入图片描述

  • 参数
27, 50

这个必须是这样,没有其他任何参数,因为是设置为默认。

3.4.4、字体大小

在这里插入图片描述

  • 设置字2倍宽
29, 33, 16
  • 设置字体2倍高度
29, 33, 1
  • 设置字体2倍宽和2倍高

直接在打印数组里面增加就行。

29, 33, 1, 29, 33, 16
  • 恢复字体宽高

直接使用 29, 33, 0 字体的宽高都恢复默认了。

29, 33, 0

3.4.5、字体对齐方式

在这里插入图片描述

  • 字体居左
27,97,0    或者   27,97,48
  • 字体居中
27,97,1    或者   27,97,49
  • 字体居右
27,97,2    或者   27,97,50

3.4.6、打印一维码

设置一维条码可读字符(HRI)打印位置

在这里插入图片描述

  • 实例
29,72,0
29,72,1
29,72,2
29,72,3
或者
29,72,48
29,72,49
29,72,50
29,72,51
设置一维条码高度

在这里插入图片描述

  • 实例值
29,104,100
设置一维条码宽度

在这里插入图片描述

  • 实例值
29,119,3
打印一维条码

在这里插入图片描述

这里分为 A 和 B两种情况,并且参数都有了,自己仔细观察。

  • 实例值
29,107,0,4829,107,65,11,48
// 打印一维码
let instruct = [29, 72, 2, 29, 104, 100, 29, 119, 6, 29, 107, 0, 48]
// let instruct = [29, 72, 3, 29, 104, 255, 29, 119, 1, 29, 107, 65, 11, 50]
let data = gbk("12345678901")

3.4.7、二维码打印

在这里插入图片描述

特别注意:这里的k计算出来是多个,那么二维码打印的内容必须就是多少个字节,如果k计算出来是2个字节,打印的内容才有1个或者3个字节都是错的。

  • 实例值
29,107,97,0,1,2,0
// 打印二维码
let instruct = [29,107,97,0,1,2,0]
// 里面必须 2 个字节,一个汉字 2个字节
let data = gbk("12")

注意:这里如果是中文,那么将中文通过 gkb()方法转换后,得到GKB编码的10进制,那么扫描出来的编码也是GBK,二维码里面最好不要保存中文。或者不要进行GBK转码,直接获取10进制数组。

在这里插入图片描述

在这里插入图片描述

3.4.8、完整案例

<template><!-- 打印 --><view class="print-box"><!-- 操作区 --><view class="operation-box"><button @click="onPrint">打印</button></view><!-- 显示连接蓝牙日志 --><view class="connect-log"><view v-for="(log,index) in connectLog" :key="index">{{log}}</view></view></view>
</template><script>import gbk from "./gbk.js"export default {data() {return {connectLog: [], // 日志deviceId: null, // 蓝牙设备的 deviceId// 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取serviceId: null, // 蓝牙服务uuid// 这里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取characteristicId: null, // 蓝牙特征值uuid}},methods: {// 打印onPrint() {// 判断是否连接蓝牙,已连接直接打印,未连接就去连接。if (this.deviceId) {this.printData()} else {this.openBluetoothAdapter()}},// 第一步 在页面显示的时候判断是否已经初始化完成蓝牙适配器若成功,则开始查找设备openBluetoothAdapter() {let that = this// 初始化蓝牙uni.openBluetoothAdapter({success: (res) => {that.connectLog.push("初始化蓝牙成功")// 初始化完毕开始搜索that.StartBluetoothDeviceDiscovery()},fail: (res) => {that.connectLog.push("初始化蓝牙失败")}});},/*** 第二步 在页面显示的时候判断是都已经初始化完成蓝牙适配器若成功,则开始查找设备*/StartBluetoothDeviceDiscovery() {let that = thisuni.startBluetoothDevicesDiscovery({// services: ['0000FFE0'],success: res => {that.connectLog.push("查找设备")that.OnBluetoothDeviceFound();},fail: res => {that.connectLog.push("查找设备失败")}});},/*** 第三步  发现外围设备*/OnBluetoothDeviceFound() {let that = thisuni.onBluetoothDeviceFound(res => {res.devices.forEach(device => { //这一步就是去筛选找到的蓝牙中,有没有你匹配的名称that.connectLog.push(`查找到设备${device.name}`)if (device.name === "MPT-II") {// 连接蓝牙that.CreateBLEConnection(device)// 找到需要连接的蓝牙了,可以关闭蓝牙搜索了。that.StopBluetoothDevicesDiscovery()}})});},// /*** 第四步 停止搜索蓝牙设备*/StopBluetoothDevicesDiscovery() {let that = thisuni.stopBluetoothDevicesDiscovery({success: res => {that.connectLog.push("关闭蓝牙搜索")console.log("第四步 找到匹配的蓝牙后就关掉蓝牙搜寻:", JSON.stringify(res))},fail: res => {that.connectLog.push("关闭蓝牙搜索失败")console.log('第四步 停止搜索蓝牙设备失败,错误码:' + res.errCode);}});},// 第五步 创建蓝牙连接,连接低功耗蓝牙设备CreateBLEConnection(item) {let that = thisthat.connectLog.push("创建蓝牙连接" + item.name)uni.createBLEConnection({ //创建蓝牙连接,连接低功耗蓝牙设备deviceId: item.deviceId, //传入刚刚获取的uuidsuccess(res) {that.connectLog.push("蓝牙连接成功")that.GetBLEDeviceServices(item.deviceId) //获取蓝牙设备所有服务(service)。},fail(res) {that.connectLog.push("蓝牙连接失败")}})},//第六步 获取蓝牙设备所有服务(service)。GetBLEDeviceServices(deviceId) {let that = thisthat.connectLog.push("开始搜索蓝牙服务")setTimeout(() => {uni.getBLEDeviceServices({ //获取蓝牙设备所有服务deviceId: deviceId,success(res) { //为什么要用延时,因为不用延时就拿不到所有的服务,在上一步,连接低功耗蓝牙//设备的时候,需要一个600-1000毫秒的时间后,再去获取设备所有服务,不给延时就会一直返回错误码10004console.log("蓝牙可用服务:", res)that.connectLog.push("搜索到蓝牙服务")that.GetBLEDeviceCharacteristics(deviceId, res) //获取蓝牙设备某个服务中所有特征值},fail(res) {that.connectLog.push("搜索蓝牙服务失败")console.log("搜索蓝牙服务失败:", res)}})}, 1000)},// 第七步 获取蓝牙特征值GetBLEDeviceCharacteristics(deviceId, item) {let that = thisthat.connectLog.push("开始获取蓝牙特征值")// 获取当前连接这个蓝牙的可用服务setTimeout(() => {item.services.forEach((services) => {console.log("服务:", services)uni.getBLEDeviceCharacteristics({ //获取蓝牙设备某个服务中所有特征值deviceId: deviceId,serviceId: services.uuid, //这个serviceId可以在上一步获取中拿到,也可以在success(res) {that.connectLog.push("蓝牙特征值获取成功")console.log("特征值", res)// 循环筛选蓝牙特征值,筛选到符合打印机的特征值为止res.characteristics.forEach((ch) => {// 判断是否支持打印机if (ch.properties.write) {// 连接蓝牙最终就是使用者三个值。// console.log("蓝牙设备deviceId:", deviceId)// console.log("使用蓝牙服务uuid:", services.uuid)// console.log("特征值uuid:", ch.uuid)that.deviceId = deviceIdthat.serviceId = services.uuidthat.characteristicId = ch.uuid// 这里不能结束最外层循环,就让他全部循环完成把,反正也不多。that.connectLog.push("找打符合条件特征值")return}})},fail(res) {that.connectLog.push("蓝牙特征值获取失败")console.log("获取蓝牙设备某个服务中所有特征值失败:", JSON.stringify(res))}})})}, 2000)},// 第八步 发送二进制数据WriteBLECharacteristicValue() {// returnlet that = this// 打印的内容uni.writeBLECharacteristicValue({// 蓝牙设备 deviceIddeviceId: that.deviceId,// 蓝牙服务uuidserviceId: that.serviceId,// 蓝牙特征值uuidcharacteristicId: that.characteristicId,// 打印的数据,ArrayBuffer 类型,数据为 10进制或者16进制。编码方式:GBKvalue: [27, 100, 60],success(res) {console.log("打印成功")},fail(res) {console.log("打印失败", res)}})},printData() {// 打印的数据let command = []// 打印的数据,这里的 \r\n表示换行,必须要进过转码// let data = gbk(// 	"这是打印的内容,我要写很多很多文字,然后打印出来看看看,什么行间距啊,什么间距啥的有没有设置好。如果没有设置好,自己看看到底是怪哪里,是我的编写问题,就更改。是厂商的问题,就寻找厂商。")// 设置行间距// let instruct = [27, 51, 255]// 设置行间距为默认 // let instruct = [27, 50]// 设置开始打印的位置// let instruct = [29, 33, 1, 29, 33, 16]// 字体恢复默认// let instruct = [29, 33, 0]// let data = gbk("这是打印的内容,反正是很多的那种,不止一行数据,自己看着办,结束。")// 居中字体// let instruct = [27, 97, 49]// 字体居中// let instruct = [27, 97, 1]// 字体居左// let instruct = [27, 97, 0]// let data = gbk("字体居左")// 字体居右// let instruct = [27, 97, 1]// let data = gbk("字体居右")// // 打印一维码// let instruct = [29, 72, 2, 29, 104, 100, 29, 119, 6, 29, 107, 0, 48]// // let instruct = [29, 72, 3, 29, 104, 255, 29, 119, 1, 29, 107, 65, 11, 50]// let data = gbk("12345678901")// 打印二维码let instruct = [29,107,97,0,1,2,0]// 里面必须 2 个字节,一个汉字 2个字节let data = gbk("12")// 将打印指令增加到 打印的数据中instruct.forEach((d) => {command.push(d)})data.forEach((d) => {command.push(d)})command.push(27)command.push(100)command.push(2)// 这里打印的数据可能超过20个字符了,所有拆分批量打印。this.senBlData(this.deviceId, this.serviceId, this.characteristicId, command)},/*** 拆分打印数据并打印,将uint8Array打印的数据拆分成,最多 20* @param {Object} deviceId 蓝牙设备deviceId* @param {Object} serviceId 服务uuid* @param {Object} characteristicId 蓝牙特征值uuid* @param {Object} uint8Array 打印数据*/senBlData(deviceId, serviceId, characteristicId, uint8Array) {var that = this;console.log('************deviceId = [' + deviceId + ']  serviceId = [' + serviceId +'] characteristics=[' + characteristicId + "]")var uint8Buf = Array.from(uint8Array);function split_array(datas, size) {var result = {};var j = 0for (var i = 0; i < datas.length; i += size) {result[j] = datas.slice(i, i + size)j++}console.log(result)return result}var sendloop = split_array(uint8Buf, 20);function realWriteData(sendloop, i) {var data = sendloop[i]if (typeof(data) == "undefined") {return}console.log("第【" + i + "】次写数据" + data)var buffer = new ArrayBuffer(data.length)var dataView = new DataView(buffer)for (var j = 0; j < data.length; j++) {dataView.setUint8(j, data[j]);}// 调动打印机打印uni.writeBLECharacteristicValue({deviceId,serviceId,characteristicId,value: buffer, // 打印的数据,ArrayBuffer 类型,数据为 10进制或者16进制。编码方式:GBKsuccess(res) {realWriteData(sendloop, i + 1);},fail(e) {console.log("点错误:", e)realWriteData(sendloop, i + 1);}})}var i = 0;realWriteData(sendloop, i);},}}
</script><style lang="scss">.print-box {display: flex;.operation-box {width: 70%;overflow: auto;.device-box {background-color: #8d98cc;margin: 20rpx;}.services-css {margin: 20rpx;background-color: #8d98cc;.char-css {margin: 20rpx;background-color: #ffffdc;}}}.connect-log {display: flex;flex-direction: column;position: sticky;top: 0;width: 30%;color: #fff;height: 100vh;overflow: auto;background-color: rgba(0, 0, 0, 0.2);}}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/28775.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux基础IO

Linux基础IO 1.理解文件1.1 狭义理解1.2 广义理解1.3 文件操作的归类认知1.4 系统角度 2.c的文件接口2.1 hello.c打开文件2.2 hello.c写文件2.3 hello.c读文件2.4 stdin & stdout & stderr 3.系统打开文件接口3.1 一种传递标记位的方法3.2 open函数3.3 文件描述符3.3.0…

Linux下学【MySQL】中如何实现:多表查询(配sql+实操图+案例巩固 通俗易懂版~)

每日激励&#xff1a;“不设限和自我肯定的心态&#xff1a;I can do all things。 — Stephen Curry” 绪论&#xff1a; 本章是MySQL篇中&#xff0c;非常实用性的篇章&#xff0c;相信在实际工作中对于表的查询&#xff0c;很多时候会涉及多表的查询&#xff0c;在多表查询的…

C#调用Ni板卡进行实现采集任务(模拟量输入输出)示例1

本文介绍如何使用C#控制Ni的USB-6008板卡进行模拟量输入、模拟量输出、输出量输入、数字量输出。代码详见下面的链接: C#调用Ni板卡进行实现采集任务(模拟量输入输出)示例1资源-CSDN文库 https://download.csdn.net/download/qq_34047402/90457042 步骤1、确认NI MAX可以正…

Mysql基础-事务

目录 一、事务简介 二、 事务操作 1 未控制事务 ​2 控制事务一 3 控制事务二 三、事务四大特性 ​四、并发事务问题 1). 脏读: 2). 不可重复读: 3). 幻读: 五、事务隔离级别 1). 查看事务隔离级别 ​2). 设置事务隔离级别 一、事务简介 事务 是一组操作的集合&a…

【Azure 架构师学习笔记】- Azure Databricks (15) --Delta Lake 和Data Lake

本文属于【Azure 架构师学习笔记】系列。 本文属于【Azure Databricks】系列。 接上文 【Azure 架构师学习笔记】- Azure Databricks (14) – 搭建Medallion Architecture part 2 前言 ADB 除了UC 这个概念之外&#xff0c;前面【Azure 架构师学习笔记】- Azure Databricks (1…

FPGA 高速接口Aurora8B/10B 协议详解与仿真

FPGA 高速接口Aurora8B/10B 协议详解与IP仿真 1 摘要 Aurora 8B/10B 是一种用于高速串行通信的协议&#xff0c;通常用于 FPGA 设计和其他数字通信应用。即一种编码方案&#xff0c;旨在在传输数据时提供可靠性、时钟恢复和错误检测。主要用于在点对点串行链路间移动数据的可…

【Linux-网络】深入拆解TCP核心机制与UDP的无状态设计

&#x1f3ac; 个人主页&#xff1a;谁在夜里看海. &#x1f4d6; 个人专栏&#xff1a;《C系列》《Linux系列》《算法系列》 ⛰️ 道阻且长&#xff0c;行则将至 目录 &#x1f4da;引言 &#x1f4da;一、UDP协议 &#x1f4d6; 1.概述 &#x1f4d6; 2.特点 &#x1…

一文学会Spring

一、Spring简介 Spring的优点 Spring是一个开源免费的框架、容器Spring是一个轻量级的框架&#xff0c;非侵入式的控制反转IOC、面向切面AOP支持事务 Spring是一个轻量级的控制反转(IOC)和面向切面(AOP)的容器 二、IOC 2.1 IOC本质 控制反转IOC&#xff0c;是一种设计思想…

AWR microwave office 仿真学习(三)各类传输线模型学习

目录 引言Phase Spec: Coupled Lines (Closed Form): CLINPhysical Spec: Coupled Lines, Grounded Shield, Improved Accuracy (Closed Form): CLINPPhysical Specification, Floating Shield (Closed Form): COAXElectrical Specification, Grounded Shield (Closed Form): C…

TrustRAG:通过配置化模块化的检索增强生成(RAG)框架提高生成结果的可靠性和可追溯性

TrustRAG旨在风险感知的信息检索场景中提高生成内容的一致性和可信度。用户可以利用私有语料库构建自己的RAG应用程序,研究库中的RAG组件,并使用定制模块进行实验。论文展示了TrustRAG系统在摘要问答任务中的应用,并通过案例研究验证了其有效性。总体而言,TrustRAG通过语义…

pgsql行列转换

目录 一、造测试数据 二、行转列 1.函数定义 2.语法 3.示例 三、列转行 1.函数定义 2.语法 3.示例 一、造测试数据 create table test ( id int, json1 varchar, json2 varchar );insert into test values(1,111,{111}); insert into test values(2,111,222,{111,22…

计算机视觉算法实战——人脑解码(主页有源码)

✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连✨ ​ ​​​ 1. 领域简介 人脑解码&#xff08;Brain Decoding&#xff09;是神经科学与计算机视觉交叉领域的一个重要研究方向&#xff0c;旨在…

[Computer Vision]实验六:视差估计

目录 一、实验内容 二、实验过程 2.1.1 test.py文件 2.1.2 test.py文件结果与分析 2.2.1 文件代码 2.2.2 结果与分析 一、实验内容 给定左右相机图片&#xff0c;估算图片的视差/深度&#xff1b;体现极线校正&#xff08;例如打印前后极线对&#xff09;、同名点匹配…

【Mac】git使用再学习

目录 前言 如何使用github建立自己的代码库 第一步&#xff1a;建立本地git与远程github的联系 生成密钥 将密钥加入github 第二步&#xff1a;创建github仓库并clone到本地 第三步&#xff1a;上传文件 常见的git命令 git commit git branch git merge/git rebase …

从0搭建Tomcat第二天:深入理解Servlet容器与反射机制

在上一篇博客中&#xff0c;我们从0开始搭建了一个简易的Tomcat服务器&#xff0c;并实现了基本的HTTP请求处理。今天&#xff0c;我们将继续深入探讨Tomcat的核心组件之一——Servlet容器&#xff0c;并介绍如何使用反射机制动态加载和管理Servlet。 1. Servlet容器的作用 S…

文件上传漏洞:upload-labs靶场11-20

目录 pass-11 pass-12 pass-13 pass-14 pass-15 pass-16 pass-17 pass-18 pass-19 pass-20 pass-11 分析源代码 &#xff0c;发现上传文件的存放路径可控 if(isset($_POST[submit])){$ext_arr array(jpg,png,gif);$file_ext substr($_FILES[upload_file][name],st…

【音视频】视频基本概念

一、视频的基本概念 1.1 视频码率&#xff08;kb/s&#xff09; 视频码率是指视频文件在单位时间内使用的数据流量&#xff0c;也叫码流率。码率越大&#xff0c;说明单位时间内取样率越大&#xff0c;数据流进度也就越高 1.2 视频帧率&#xff08;fps&#xff09; 视频帧率…

Sqlserver还原备份文件时提示缺少日志文件

Sqlserver还原备份文件时提示缺少日志文件 解决方案&#xff1a;

《2025年软件测试工程师面试》消息队列面试题

消息队列 消息队列&#xff08;Message Queue&#xff0c;简称 MQ&#xff09;是一种应用程序之间的通信方法。 基本概念 消息队列是一种先进先出&#xff08;FIFO&#xff09;的数据结构&#xff0c;它允许一个或多个消费者从队列中读取消息&#xff0c;也允许一个或多个生产者…

前端基础之vuex

是一个专门在Vue中实现集中式状态(数据)管理的一个Vue插件&#xff0c;对vue应用中多个组件的共享状态进行集中式管理(读或写)&#xff0c;也是一种组件间通信的方式&#xff0c;适用于任意组件间的通信 什么时候使用vuex&#xff1f; 1.多组件依赖同一状态 2.来自不同组件的行…