const util = require("../../utils/util"); const plugin = requirePlugin("sdkPlugin").AiLink; function inArray(arr, key, val) { if (!arr || !arr.length || typeof arr != 'object' || !Array.isArray(arr)) { return -1 } for (let i = 0; i < arr.length; i++) { if (!key) { if (arr[i] == val) { return i } } else if (arr[i][key] === val) { return i } } return -1; } // ArrayBuffer转16进度字符串示例 function ab2hex(buffer, split) { var hexArr = Array.prototype.map.call( new Uint8Array(buffer), function (bit) { return ('00' + bit.toString(16)).slice(-2) } ) return hexArr.join(split); } Page({ data: { showWriteInput: false, devices: [ // { // deviceId: "02:03:04:05:06:07", // name: "elink", // localName: "elink", // mac: "02:03:04:05:06:07", // RSSI: -69, // advertisServiceUUIDs:[ // "FFE0","FFC0" // ], // analyzeDataText:"0102003241123413" // } ], connected: false, chs: [], cmd: '', name: '', deviceId: null, historyList: [], }, onLoad: function () { let historyList = [] historyList = wx.getStorageSync('historyList') this.setData({ historyList, }) }, // 初始化蓝牙模块 openBluetoothAdapter() { wx.openBluetoothAdapter({ success: (res) => { console.log('openBluetoothAdapter success', res) this.startBluetoothDevicesDiscovery() }, fail: (res) => { if (res.errCode === 10001) { wx.showToast({ title: '请打开蓝牙', icon: "none" }) wx.onBluetoothAdapterStateChange(function (res) { console.log('onBluetoothAdapterStateChange', res) if (res.available) { this.startBluetoothDevicesDiscovery() } }) } } }) }, // 获取本机蓝牙适配器状态 getBluetoothAdapterState() { wx.getBluetoothAdapterState({ success: (res) => { console.log('getBluetoothAdapterState', res) if (res.discovering) { this.onBluetoothDeviceFound() } else if (res.available) { this.startBluetoothDevicesDiscovery() } } }) }, // 开始搜寻附近的蓝牙外围设备 startBluetoothDevicesDiscovery() { if (this._discoveryStarted) { return } this._discoveryStarted = true wx.startBluetoothDevicesDiscovery({ allowDuplicatesKey: true, services: [ "FFE0", // "F0A0", // BM30广播模块需加上,如使用连接模块可忽略 ], success: (res) => { console.log('startBluetoothDevicesDiscovery success', res) this.onBluetoothDeviceFound() }, }) }, // 停止搜寻附近的蓝牙外围设备 stopBluetoothDevicesDiscovery() { wx.stopBluetoothDevicesDiscovery() }, // 监听寻找到新设备的事件 onBluetoothDeviceFound() { wx.onBluetoothDeviceFound((res) => { res.devices.forEach(device => { if (!device.name && !device.localName) { return } const foundDevices = this.data.devices const idx = inArray(foundDevices, 'deviceId', device.deviceId) const data = {} // console.log(device) // console.log(ab2hex(device.advertisData)) // 此处判断是否BM30广播模块,如使用连接模块请删除此 if ,只保留 else 内容 if (device.advertisServiceUUIDs[0].indexOf("F0A0") !== -1) { let parseDataRes = plugin.parseBroadcastData(device.advertisData) console.log(parseDataRes) if (parseDataRes.status == 1) { let analyzeData = plugin.analyzeBroadcastScaleData(parseDataRes) console.log(analyzeData) device.analyzeDataText = analyzeData.text } } else { let buff = device.advertisData.slice(-6) device.mac = new Uint8Array(buff) // 保存广播数据中的mac地址,这是由于iOS不直接返回mac地址 let tempMac = Array.from(device.mac) tempMac.reverse() device.macAddr = ab2hex(tempMac, ':').toUpperCase() } if (idx === -1) { data[`devices[${foundDevices.length}]`] = device } else { data[`devices[${idx}]`] = device } this.setData(data) }) }) }, // 连接低功耗蓝牙设备 createBLEConnection(e) { this._connLoading = true wx.showLoading({ title: '连接中', }) setTimeout(() => { if (this._connLoading) { this._connLoading = false wx.hideLoading() } }, 6000) const ds = e.currentTarget.dataset const index = ds.index // 保存当前连接的设备,注意不能从wxml的dataset中直接返回该对象,因为ArrarBuffer类型的数据无法保留 this._device = this.data.devices[index] console.log(this._device) const deviceId = ds.deviceId const name = ds.name this.mac = ds.mac wx.createBLEConnection({ deviceId, success: (res) => { this.setData({ connected: true, name, deviceId, }) console.log("createBLEConnection:success") wx.stopBluetoothDevicesDiscovery() this.onBLEConnectionStateChange() this.getBLEDeviceServices(deviceId) }, fail: res => { this._connLoading = false wx.hideLoading() wx.showToast({ title: '连接失败', icon: 'none' }) } }) // 连接上设备就可以停止蓝牙搜索,减少功耗。 this.stopBluetoothDevicesDiscovery() }, onBLEConnectionStateChange() { wx.onBLEConnectionStateChange((res) => { console.log('wx.onBLEConnectionStateChange() ', res.deviceId, res.connected, res.errorCode, res.errorMsg) // 该方法回调中可以用于处理连接意外断开等异常情况 // console.log(`%c device ${res.deviceId} state has changed, connected: ${res.connected}`, 'color: #F26363') if (!res.connected) { wx.showToast({ title: '连接已断开', icon: 'none' }) this.setData({ connected: false, showWriteInput: false, }) } }) }, // 断开与低功耗蓝牙设备的连接 closeBLEConnection() { wx.closeBLEConnection({ deviceId: this._deviceId }) this.setData({ connected: false, chs: [], showWriteInput: false, }) }, // 获取蓝牙设备的 serviceId getBLEDeviceServices(deviceId) { wx.getBLEDeviceServices({ deviceId, success: (res) => { for (let i = 0; i < res.services.length; i++) { if (res.services[i].isPrimary && res.services[i].uuid.indexOf('FFE0') > -1) { this.getBLEDeviceCharacteristics(deviceId, res.services[i].uuid) return } } } }) }, // 获取蓝牙设备某个服务中所有特征值(characteristic) getBLEDeviceCharacteristics(deviceId, serviceId) { this._deviceId = deviceId this._serviceId = serviceId this._device.serviceId = serviceId wx.getBLEDeviceCharacteristics({ deviceId, serviceId, success: (res) => { console.log('getBLEDeviceCharacteristics success', res.characteristics) // 这部分功能在插件的 initPlugin 中已实现,如需用到其中的 uuid 也可取消注释 // // let uuid1, uuid2, uuid3; for (let i = 0; i < res.characteristics.length; i++) { let item = res.characteristics[i] if (item.uuid.indexOf('0000FFE1') != -1) { this.uuid1 = item.uuid //下发数据 } else if (item.uuid.indexOf('0000FFE2') != -1) { this.uuid2 = item.uuid //监听数据 } else if (item.uuid.indexOf('0000FFE3') != -1) { this.uuid3 = item.uuid //写入设置 } } // 打开监听 wx.notifyBLECharacteristicValueChange({ deviceId, serviceId, characteristicId: this.uuid2, state: true, }) wx.notifyBLECharacteristicValueChange({ deviceId, serviceId, characteristicId: this.uuid3, state: true, }) // 初始化插件 plugin.initPlugin(res.characteristics, this._device) wx.onBLECharacteristicValueChange((characteristic) => { // 解析特征值,返回解密后的数据 let bleData = plugin.parseBleData(characteristic.value) console.log(bleData) if (bleData.status == 0) { console.log("握手成功") this._connLoading = false wx.hideLoading() wx.showToast({ title: '连接成功', }) } else if (bleData.status == 1) { let payload = bleData.data //对应协议中的payload数据,可以自行解析该数据 // console.log(ab2hex(payload, ' ')) // console.log(ab2hex(bleData.completeData, ' ')) // 以体脂秤数据解析为例 switch (payload[0]) { // payload[0] 指示当前指令的类型,根据类型区分 /** * 例如: A7 00 0E 05 01 00 01 F4 10 19 7A---------50.0kg * 其中 01 00 01 F4 10 为 payload * 具体指令请根据协议解析 */ case 0x01: case 0x02: let weightValue = (payload[1] << 16) | (payload[2] << 8) | payload[3] let decPoint = (payload[4] & 0xf0) >> 4 let unit = payload[4] & 0x0f // console.log("体重数值:" + weightValue) // console.log("小数点:" + decPoint) // console.log("单位:" + unit) if (unit == 1) { // 单位为斤 weightValue = weightValue / 2 } else { // ... 其他单位 } this.weight = weightValue / (decPoint * 10) // 除去小数点位数 break; // ... 其他指令请根据协议解析 /** * 例如: A7 00 0E 03 07 02 30 4A 7A---------阻抗测量成功,阻抗 560Ω * 其中 07 02 30 为 payload * 具体指令请根据协议解析 */ case 0x07: this.adc = (payload[1] << 8) | payload[2] break; case 0x0A: //测量完成 let bodyData = plugin.getBodyData(1, 20, 170, this.weight, this.adc) // 体脂秤数据解析 (男,20岁,身高170,体重,阻抗) console.log("解析后的体脂数据: ", bodyData) console.log(util.getWeightDisplay(170, this.weight)) break; } const idx = inArray(this.data.chs, 'uuid', characteristic.characteristicId) const data = {} if (idx === -1) { data[`chs[${this.data.chs.length}]`] = { uuid: characteristic.characteristicId, value: ab2hex(bleData.completeData, ' ') } } else { data[`chs[${idx}]`] = { uuid: characteristic.characteristicId, value: ab2hex(bleData.completeData, ' ') } } this.setData(data) } else { // console.log(bleData) } }) }, fail(res) { console.error('getBLEDeviceCharacteristics', res) } }) }, writeBLECharacteristicValue(buffer, uuid, deviceId, serviceId) { // 向蓝牙设备发送一个二进制流数据 wx.writeBLECharacteristicValue({ deviceId, serviceId, characteristicId: uuid, value: buffer, success(res) { console.log('writeBLECharacteristicValue success', res) console.log('下发指令==> ' + ab2hex(buffer)) } }) }, closeBluetoothAdapter() { wx.closeBluetoothAdapter() this._discoveryStarted = false }, // 打开指令输入框 showWriteInputView() { this.setData({ showWriteInput: true }) }, // 关闭指令输入框 hideWriteInputView() { this.setData({ showWriteInput: false }) }, // 指令下发 submitCmd(e, cmd) { let arr = [] let temp = [] if (!cmd) { cmd = this.data.cmd } console.log(cmd) if(!cmd || !this.data.connected){ return } if(cmd.indexOf(",") == -1){ temp = cmd.split(" ") } else { temp = cmd.split(",") } let tempCmd = temp.join(' ') for(let i = 0; i < temp.length; i++){ arr[i] = parseInt(temp[i],16) } // let arr = [ // 0xA6, // 0x01, // 0x28, // 0x29, // 0x6A, // //A6 01 28 29 6A // ] if(arr[0] == 0xA6){ let len = arr[1] let payload = arr.slice(2, 2 + len) plugin.sendDataOfA6(payload) // let buff = new Uint8Array(arr).buffer // this.writeBLECharacteristicValue(buff, this.uuid3, this._deviceId, this._serviceId) } else if(arr[0] == 0xA7) { let len = arr[3] let payload = arr.slice(4, 4 + len) plugin.sendDataOfA7(payload) } let historyList = wx.getStorageSync('historyList') || [] let idx = historyList.findIndex(item => item.cmd == tempCmd) if (idx < 0) { historyList.push({cmd: tempCmd}) } this.setData({ historyList }) wx.setStorage({ data: historyList, key: 'historyList', }) wx.showToast({ title: '已发送', icon: 'none' }) }, history_delete(e) { let index = e.currentTarget.dataset.index this.data.historyList.splice(index, 1) this.setData({ historyList: this.data.historyList }) wx.setStorage({ data: this.data.historyList, key: 'historyList', }) }, history_copy(e) { let index = e.currentTarget.dataset.index wx.setClipboardData({ data: this.data.historyList[index].cmd }) }, history_send(e) { let index = e.currentTarget.dataset.index let cmd = this.data.historyList[index].cmd this.submitCmd(null, cmd) }, });