使用微信小程序,通过蓝牙与硬件设备产品进行交互
微信小程序蓝牙通讯
initBlue: function () { var that = this wx.openBluetoothAdapter({ success: function (res) { that.findBlue() }, fail: function (res) { wx.showToast({ title: '请打开手机蓝牙!', icon: 'none', duration: 2000 }) } }) }
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) }
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 }) } } }) }
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 }) } }) }
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; }
/** * 监听水表数据变化 * @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 = '' } }) } }) },
设备应答数据也可以发送到后台服务进行处理,根据具体业务而定