参考文档
开始
1.初始化
initBlue: function () {
var that = this
wx.openBluetoothAdapter({
success: function (res) {
that.findBlue()
},
fail: function (res) {
wx.showToast({
title: '请打开手机蓝牙!',
icon: 'none',
duration: 2000
})
}
})
}
2.查找蓝牙设备
用于微信小程序中的蓝牙设备搜索和连接功能的实现。它由两个主要函数组成:findBlue
和 getBlue
,分别负责开始蓝牙设备发现过程和处理发现到的蓝牙设备。
findBlue
函数
findBlue() {
var that = this
wx.startBluetoothDevicesDiscovery({
allowDuplicatesKey: false, // 不允许重复的设备(即不保留历史搜索结果)
interval: 0, // 搜索间隔为0,表示立即开始搜索
success: function (res) { // 成功回调
that.getBlue() // 调用 getBlue 进行设备搜索
}
})
}
findBlue
方法通过调用微信小程序提供的wx.startBluetoothDevicesDiscovery
API 来启动蓝牙设备的搜索。- 设置了不允许重复设备 (
allowDuplicatesKey: false
) 和立即开始搜索 (interval: 0
)。 - 如果成功启动了蓝牙设备搜索,则会调用
getBlue
方法来执行进一步的操作。
getBlue
函数
getBlue() {
var that = this
var searchResult = false
var index = 0
wx.showLoading({ // 显示加载提示
title: '搜索设备...',
})
// 定时搜索
var interval = setInterval(function () {
wx.getBluetoothDevices({
success: function (res) { // 成功获取到设备列表后的回调
index = index + 1
if (!searchResult) {
for (var i = 0; i < res.devices.length; i++) {
// 根据设备名称匹配 这里的meterId是需要匹配的设备名称
if ((res.devices[i].name + "").substr(0, 16) == that.data.meterId ||
(res.devices[i].localName + "").substr(0, 16) == that.data.meterId) {
that.setData({
// 获取蓝牙设备的deviceId
deviceId: res.devices[i].deviceId,
})
searchResult = true
if (searchResult) {
clearInterval(interval) // 停止定时器
}
// 连接蓝牙
that.connetBlue(res.devices[i].deviceId)
return
}
}
}
if (index > 20) { // 如果尝试次数超过20次
clearInterval(interval) // 停止定时器
wx.hideLoading() // 隐藏加载提示
wx.showToast({ // 显示提示信息
title: '未找到设备,请重试!',
icon: 'none',
duration: 2000
})
wx.stopBluetoothDevicesDiscovery() // 关闭蓝牙搜索
}
}
})
}, 500) // 每隔500毫秒检查一次设备列表
}
getBlue
方法首先显示一个加载指示器告知用户正在搜索设备。- 使用
setInterval
创建一个定时器,每500毫秒调用一次wx.getBluetoothDevices
来获取当前已发现的蓝牙设备列表。 - 对每个设备进行循环遍历,检查其名称或本地名称是否与
that.data.meterId
匹配(这里假设meterId
是你想要连接的特定蓝牙设备的名称前缀)。 - 如果找到了匹配的设备,将该设备的
deviceId
存储在组件的数据中,并停止定时器,然后尝试连接该设备。 - 如果经过20次尝试后仍未找到匹配的设备,将隐藏加载指示器,并向用户显示一条消息通知他们没有找到设备,同时停止蓝牙搜索。
注意事项
that
变量是为了保存对当前上下文对象的引用,因为在这个例子中,this
的值会在异步回调函数中改变。wx.startBluetoothDevicesDiscovery
和wx.getBluetoothDevices
是微信小程序提供的用于操作蓝牙设备的API。setData
方法是用来更新组件状态的方法,在微信小程序中,它用于安全地更新页面上的数据绑定。connetBlue
方法在这里被提到但没有给出定义;它应该是用来处理与蓝牙设备建立连接的逻辑。
这段代码展示了如何使用微信小程序的API来进行蓝牙设备的搜索和连接。它实现了简单的设备查找逻辑,并在找到目标设备后停止搜索并尝试建立连接。如果在一定时间内找不到设备,则会提示用户未找到设备。
findBlue() {
var that = this
wx.startBluetoothDevicesDiscovery({
allowDuplicatesKey: false,
interval: 0,
success: function (res) {
that.getBlue()
}
})
},
getBlue() {
var that = this
var searchResult = false
var index = 0
wx.showLoading({
title: '搜索设备...',
})
//定时搜索
var interval = setInterval(function () {
wx.getBluetoothDevices({
success: function (res) {
index = index + 1
if (!searchResult) {
for (var i = 0; i < res.devices.length; i++) {
//根据设备名称匹配 这里的meterId是需要匹配的设备名称
if ((res.devices[i].name + "").substr(0, 16) == that.data.meterId ||
(res.devices[i].localName + "").substr(0, 16) == that.data.meterId) {
that.setData({
//获取蓝牙设备的deviceId
deviceId: res.devices[i].deviceId,
})
searchResult = true
if (searchResult) {
clearInterval(interval)
}
//连接蓝牙
that.connetBlue(res.devices[i].deviceId)
return
}
}
}
if (index > 20) {
clearInterval(interval)
wx.hideLoading()
wx.showToast({
title: '未找到设备,请重试!',
icon: 'none',
duration: 2000
})
wx.stopBluetoothDevicesDiscovery() //关闭蓝牙搜索
}
}
})
}, 500)
}
3.连接蓝牙设备
微信小程序中用于连接蓝牙低功耗(BLE)设备,并获取其服务和特征值的实现。它由三个主要函数组成:connetBlue
、getServiceId
和 getCharacteId
,分别负责连接设备、获取服务ID和获取特征值。
connetBlue
函数
connetBlue(deviceId) {
var that = this
wx.hideLoading()
wx.showLoading({
title: '连接设备...',
})
wx.createBLEConnection({
deviceId: deviceId,
success: function (res) {
wx.stopBluetoothDevicesDiscovery() //关闭蓝牙搜索
that.getServiceId() //获取服务ID
},
fail: function () {
wx.hideLoading()
wx.showToast({
title: '连接设备失败!',
icon: 'none',
duration: 2000
})
wx.stopBluetoothDevicesDiscovery() //关闭蓝牙搜索
}
})
}
connetBlue
方法接收一个deviceId
参数,代表要连接的蓝牙设备的唯一标识符。- 它首先隐藏任何现有的加载指示器,然后显示一个新的加载指示器告知用户正在尝试连接设备。
- 使用
wx.createBLEConnection
API 尝试建立与指定deviceId
的蓝牙设备的连接。 - 如果连接成功:
- 停止蓝牙设备的搜索以节省资源。
- 调用
getServiceId
方法来获取该设备的服务信息。
- 如果连接失败:
- 隐藏加载指示器。
- 显示一个错误提示给用户。
- 同样停止蓝牙设备的搜索。
getServiceId
函数
getServiceId() {
var that = this
wx.getBLEDeviceServices({
deviceId: that.data.deviceId,
success: function (res) {
var model = res.services[0]
that.setData({
serviceId: model.uuid
})
that.getCharacteId()
}
})
}
getServiceId
方法用于获取已连接蓝牙设备的服务列表。- 它调用了
wx.getBLEDeviceServices
API 来获取服务。 - 获取到的服务列表中,选择了第一个服务(这里假设只需要与第一个服务交互),并将它的 UUID 存储在组件数据中。
- 然后调用
getCharacteId
方法来进一步获取该服务下的特征值。
getCharacteId
函数
getCharacteId() {
var that = this
wx.getBLEDeviceCharacteristics({
deviceId: that.data.deviceId,
serviceId: that.data.serviceId,
success: function (res) {
for (var i = 0; i < res.characteristics.length; i++) {
var model = res.characteristics[i]
if (model.properties.notify == true) {
that.setData({
notifyId: model.uuid
})
// 开启监听服务。监听设备数据变化
that.startNotice(model.uuid)
}
if (model.properties.write == true) {
that.setData({
writeId: model.uuid
})
}
}
// 检查是否有可写权限
if (that.data.writeId != '') {
wx.hideLoading()
wx.showLoading({
title: '通讯中...',
})
// 这里可以完成需要下发到设备上的指令的生成
that.sendCmd(value)
} else {
wx.showToast({
title: '失败: 设备无写入权限!',
icon: 'none',
duration: 2000
})
}
}
})
}
getCharacteId
方法用于获取特定服务下的所有特征值。- 它调用
wx.getBLEDeviceCharacteristics
API 来获取特征值列表。 - 对每个特征值进行检查:
- 如果特征值支持通知(
notify
属性为true
),则保存该特征值的 UUID 到notifyId
并启动监听服务。 - 如果特征值支持写入(
write
属性为true
),则保存该特征值的 UUID 到writeId
。
- 如果特征值支持通知(
- 检查是否找到了具有写入权限的特征值:
- 如果找到了,显示新的加载指示器并准备发送命令到设备。
- 如果没有找到,则向用户显示一条消息,说明设备没有写入权限。
注意事项
that
变量是为了保存对当前上下文对象的引用,因为在异步回调函数中,this
的值会改变。setData
方法是用来更新组件状态的方法,在微信小程序中,它用于安全地更新页面上的数据绑定。startNotice
和sendCmd
方法在这里被提到但没有给出定义;它们应该是用来处理开启通知和发送命令到蓝牙设备的逻辑。- 在实际应用中,
value
应该是具体要发送给设备的数据或命令,这部分代码未提供具体实现。 wx.createBLEConnection
,wx.getBLEDeviceServices
, 和wx.getBLEDeviceCharacteristics
是微信小程序提供的用于操作蓝牙设备的API。- 为了确保最佳用户体验,开发者应当处理好各种可能的异常情况,并提供适当的反馈给用户。
connetBlue(deviceId) {
var that = this
wx.hideLoading()
wx.showLoading({
title: '连接设备...',
})
wx.createBLEConnection({
deviceId: deviceId,
success: function (res) {
wx.stopBluetoothDevicesDiscovery() //关闭蓝牙搜索
that.getServiceId() //获取服务ID
},
fail: function () {
wx.hideLoading()
wx.showToast({
title: '连接设备失败!',
icon: 'none',
duration: 2000
})
wx.stopBluetoothDevicesDiscovery() //关闭蓝牙搜索
}
})
},
getServiceId() {
var that = this
wx.getBLEDeviceServices({
deviceId: that.data.deviceId,
success: function (res) {
var model = res.services[0]
that.setData({
serviceId: model.uuid
})
that.getCharacteId()
}
})
},
getCharacteId() {
var that = this
wx.getBLEDeviceCharacteristics({
deviceId: that.data.deviceId,
serviceId: that.data.serviceId,
success: function (res) {
for (var i = 0; i < res.characteristics.length; i++) {
var model = res.characteristics[i]
if (model.properties.notify == true) {
that.setData({
notifyId: model.uuid
})
//重点:开启监听服务。监听设备数据变化
that.startNotice(model.uuid)
}
if (model.properties.write == true) {
that.setData({
writeId: model.uuid
})
}
}
//有可写权限
if (that.data.writeId != '') {
wx.hideLoading()
wx.showLoading({
title: '通讯中...',
})
//这里可以完成需要下发到设备上的指令的生成
that.sendCmd(value)
} else {
wx.showToast({
title: '失败: 设备无写入权限!',
icon: 'none',
duration: 2000
})
}
}
})
}
4.发送数据
微信小程序中用于向已连接的蓝牙低功耗(BLE)设备发送命令或数据的具体实现。它由两个主要函数组成:sendCmd
和 writeCharacterToDevice
,分别负责准备发送的数据和实际执行写入操作
sendCmd
函数
sendCmd(cmdValue) {
var that = this
if (cmdValue != '' && cmdValue != null && cmdValue != undefined) {
that.writeCharacterToDevice(util.stringToArrayBuffer(cmdValue))
} else {
wx.showToast({
title: '获取设备指令失败',
icon: 'none',
duration: 2000
})
}
}
sendCmd
方法接收一个参数cmdValue
,代表要发送给设备的命令或数据。- 它首先检查
cmdValue
是否既不是空字符串也不是null
或undefined
,以确保有有效的数据可以发送。 - 如果
cmdValue
是有效的,它会调用辅助函数util.stringToArrayBuffer
将字符串转换为数组缓冲区(ArrayBuffer),然后调用writeCharacterToDevice
方法来将数据写入到蓝牙设备。 - 如果
cmdValue
不是有效值,则显示一条消息给用户,告知他们获取设备指令失败。
writeCharacterToDevice
函数
writeCharacterToDevice(buffer) {
var that = this
wx.writeBLECharacteristicValue({
deviceId: that.data.deviceId,
serviceId: that.data.serviceId,
characteristicId: that.data.writeId,
value: buffer,
fail: function () {
wx.showToast({
title: '写入设备数据失败!',
icon: 'none',
duration: 2000
})
},
success: function () {
wx.showLoading({
title: '指令发送成功',
duration: 2000
})
}
})
}
writeCharacterToDevice
方法接收一个参数buffer
,即要写入蓝牙设备的数据,该数据已经被转换成数组缓冲区格式。- 它使用
wx.writeBLECharacteristicValue
API 向指定的蓝牙设备特征值写入数据。 - 写入操作需要提供以下信息:
deviceId
: 设备的唯一标识符。serviceId
: 服务的UUID。characteristicId
: 特征值的UUID,这里应该是之前找到的支持写入操作的那个特征值。value
: 要写入的数据,即传入的buffer
。
- 如果写入失败:
- 显示一个错误提示给用户,说明写入设备数据失败。
- 如果写入成功:
- 显示一个短暂的加载指示器告知用户指令发送成功,持续时间为2秒。
注意事项
that
变量是为了保存对当前上下文对象的引用,因为在异步回调函数中,this
的值会改变。util.stringToArrayBuffer
是一个假设存在的辅助函数,用于将字符串转换为数组缓冲区,以便能够通过蓝牙API发送。你需要确保这个函数已经在项目的某个地方定义并且可用。setData
方法在原代码片段中没有直接出现,但它是微信小程序中用于更新页面状态的方法;在这个场景下,我们通过that
来访问组件的状态,例如deviceId
,serviceId
, 和writeId
。wx.writeBLECharacteristicValue
是微信小程序提供的用于与BLE设备通信的API之一,允许应用程序向特定的特征值写入数据。- 成功和失败的回调处理提供了即时反馈给用户,增强了用户体验。
showToast
和showLoading
都是微信小程序提供的UI反馈方法,用来向用户展示短时间的消息提示或加载状态
sendCmd(cmdValue) {
var that = this
if (cmdValue != '' && cmdValue != null && cmdValue != undefined) {
that.writeCharacterToDevice(util.stringToArrayBuffer(cmdValue))
} else {
wx.showToast({
title: '获取设备指令失败',
icon: 'none',
duration: 2000
})
}
}
writeCharacterToDevice(buffer) {
var that = this
wx.writeBLECharacteristicValue({
deviceId: that.data.deviceId,
serviceId: that.data.serviceId,
characteristicId: that.data.writeId,
value: buffer,
fail: function () {
wx.showToast({
title: '写入设备数据失败!',
icon: 'none',
duration: 2000
})
},
success: function () {
wx.showLoading({
title: '指令发送成功',
duration: 2000
})
}
})
}
5.工具函数
function stringToArrayBuffer(str) {
var bytes = new Array();
var len, c;
len = str.length;
for (var i = 0; i < len; i++) {
c = str.charCodeAt(i);
if (c >= 0x010000 && c <= 0x10FFFF) {
bytes.push(((c >> 18) & 0x07) | 0xF0);
bytes.push(((c >> 12) & 0x3F) | 0x80);
bytes.push(((c >> 6) & 0x3F) | 0x80);
bytes.push((c & 0x3F) | 0x80);
} else if (c >= 0x000800 && c <= 0x00FFFF) {
bytes.push(((c >> 12) & 0x0F) | 0xE0);
bytes.push(((c >> 6) & 0x3F) | 0x80);
bytes.push((c & 0x3F) | 0x80);
} else if (c >= 0x000080 && c <= 0x0007FF) {
bytes.push(((c >> 6) & 0x1F) | 0xC0);
bytes.push((c & 0x3F) | 0x80);
} else {
bytes.push(c & 0xFF);
}
}
var array = new Int8Array(bytes.length);
for (var i in bytes) {
array[i] = bytes[i];
}
return array.buffer;
}
function arrayBufferToString(arr) {
if (typeof arr === 'string') {
return arr;
}
var dataview = new DataView(arr);
var ints = new Uint8Array(arr.byteLength);
for (var i = 0; i < ints.length; i++) {
ints[i] = dataview.getUint8(i);
}
arr = ints;
var str = '',
_arr = arr;
for (var i = 0; i < _arr.length; i++) {
var one = _arr[i].toString(2),
v = one.match(/^1+?(?=0)/);
if (v && one.length == 8) {
var bytesLength = v[0].length;
var store = _arr[i].toString(2).slice(7 - bytesLength);
for (var st = 1; st < bytesLength; st++) {
store += _arr[st + i].toString(2).slice(2);
}
str += String.fromCharCode(parseInt(store, 2));
i += bytesLength - 1;
} else {
str += String.fromCharCode(_arr[i]);
}
}
return str;
}
6.开启事件监听
定义了一个名为 startNotice
的方法,用于启用对指定特征值的通知,并处理当该特征值的数据发生变化时的响应逻辑。
方法签名
/**
* 监听水表数据变化
* @param {string} uuid - 水表ID(实际上是特征值的UUID)
*/
- 注释:指明了这个方法的作用是监听水表数据的变化,并指出了参数
uuid
的含义,即水表ID,但实际上这里的uuid
应该是指定的特征值的UUID。
startNotice
方法
startNotice(uuid) {
var that = this
wx.notifyBLECharacteristicValueChange({
state: true, // 启用 notify 功能
deviceId: that.data.deviceId,
serviceId: that.data.serviceId,
characteristicId: uuid,
success: function (res) {
var deviceResult = ''
// 特征数据变化
wx.onBLECharacteristicValueChange(function (res) {
deviceResult = deviceResult + util.arrayBufferToString(res.value) // 应答数据比较长,会触发多次
// 如果应答帧总长度大于数据包长度,并且包含“16”,则说明是完整的应答帧
if (deviceResult.lastIndexOf('16') >= (deviceResult.length - 8) && deviceResult.indexOf('68') >= 0) {
// 解析应答帧 这里开始对设备应答数据进行处理了
deviceResult = ''
}
})
}
})
}
启用通知
wx.notifyBLECharacteristicValueChange
:这是一个微信小程序提供的API,用于启用或禁用指定特征值的通知功能。- 参数包括:
state
: 设置为true
表示启用通知。deviceId
: 设备的唯一标识符。serviceId
: 服务的UUID。characteristicId
: 特征值的UUID,这里传入的是uuid
参数,代表要监听的特征值。
- 成功回调函数会在启用了通知后执行。
处理数据变化
- 在成功启用了通知之后,使用
wx.onBLECharacteristicValueChange
注册一个监听器,用于监听特征值数据的变化。 - 当特征值的数据发生变化时,
wx.onBLECharacteristicValueChange
的回调函数会被触发,接收一个新的res
对象,其中包含最新的数据。 util.arrayBufferToString(res.value)
将接收到的数组缓冲区格式的数据转换成字符串,并将其附加到deviceResult
变量中。这一步骤可能被执行多次,因为一次完整的应答可能会被分多次发送。- 然后检查
deviceResult
是否包含了特定的结束标记"16"
和起始标记"68"
,以确定是否已经收到了完整的应答帧。如果满足条件,则认为接收到的是完整的一帧数据,并可以在此处解析和处理这些数据。 - 最后,重置
deviceResult
为空字符串,以便为下一轮的数据接收做准备。
注意事项
that
变量是为了保存对当前上下文对象的引用,因为在异步回调函数中,this
的值会改变。util.arrayBufferToString
是一个假设存在的辅助函数,用于将数组缓冲区转换为字符串,你需要确保这个函数已经在项目的某个地方定义并且可用。deviceResult
的构建方式假定了数据是以字符串形式表示的,并且每帧数据都以"68"
开头并以"16"
结尾。这种协议可能是特定于所使用的水表设备的通信协议,因此在实际应用中需要根据具体设备的通信规范来调整。- 数据完整性检查基于最后8个字符包含
"16"
和任意位置包含"68"
的假设,这可能不是所有情况的最佳实践;在实际开发中,应该依据具体的通信协议文档来准确判断数据帧的边界。 - 如果应答帧的结构复杂或者存在更多变种,你可能需要更复杂的逻辑来解析和验证接收到的数据。
wx.notifyBLECharacteristicValueChange
和wx.onBLECharacteristicValueChange
是微信小程序提供的用于与BLE设备通信的API,允许应用程序监听来自设备的数据变化。
这段代码展示了如何设置监听以接收来自特定蓝牙设备的数据更新,并实现了一个简单的机制来拼接和解析可能被分段发送的数据帧。对于任何想要利用微信小程序与BLE设备交互并处理其返回数据的开发者来说,这是一个非常重要的部分
/**
* 监听水表数据变化
* @param {水表ID} uuid
*/
startNotice(uuid) {
var that = this
wx.notifyBLECharacteristicValueChange({
state: true, // 启用 notify 功能
deviceId: that.data.deviceId,
serviceId: that.data.serviceId,
characteristicId: uuid,
success: function (res) {
var deviceResult = ''
//特征数据变化
wx.onBLECharacteristicValueChange(function (res) {
deviceResult = deviceResult + util.arrayBufferToString(res.value) //应答数据比较长,会触发多次
//如果应答帧总长度大于数据包长度,并且包含“16”,则说明是完整的应答帧
if (deviceResult.lastIndexOf('16') >= (deviceResult.length - 8) && deviceResult.indexOf('68') >= 0) {
//解析应答帧 这里开始对设备应答数据进行处理了
deviceResult = ''
}
})
}
})
},
设备应答数据也可以发送到后台服务进行处理,根据具体业务而定