// 示例demo const plugin = requirePlugin('ppScale-plugin'); import { CommandButtonList } from '../../model/index' let app = getApp(); Page({ data: { // 选择的设备对象 selmac: null, // 是否在测量中 scaleing: false, // 蓝牙连接状态 devLink: false, // 扫描筛选出的设备 selectDev: null, // 设备模型 deviceModel: null, // 通讯结果 contnectResult: null, // 发送指令内容 sendData: null, // 蓝牙设备返回的结果 callBack: null, // 蓝牙设备下发指令按钮数据 sendBtnList: CommandButtonList.send, //版本号 // 上报数据类型数组: reportData: CommandButtonList.report, // 手动输入文本域的值 inputValue: '', deviceInfo: { version: '', battery:'', chargeState: '', poleWorkState: '', workState: '', error: '', workStart: '', workEnd: '', workResult: '', } }, /** * 页面卸载时调用 */ onUnload() { // 业务结束后需要调用此方法 wx.offBluetoothAdapterStateChange(); wx.closeBluetoothAdapte(); }, /** * 页面隐藏时调用 */ onHide() { }, onLoad() { let that = this; //监听蓝牙连接状态 wx.onBLEConnectionStateChange(function (res) { // 该方法回调中可以用于处理连接意外断开等异常情况 console.log(`设备蓝牙连接状态`, res); // 如果蓝牙断开 if (!res.connected) { // 关闭蓝牙连接事件,再重新初始化连接? that.setData({ devLink: false, }) wx.showToast({ title: '蓝牙已断开', }); that.connect(); /* setTimeout(() => { that.initBlue(); }, 1500) */ } else { that.setData({ devLink: true, }) setTimeout(() => { // 获取蓝牙低功耗设备所有服务 (service) wx.getBLEDeviceServices({ deviceId: app.globalData.selmac.deviceId, success: (res) => { console.log("获取蓝牙低功耗设备所有服务成功", res); let serviceId = '0000FFF0-0000-1000-8000-00805F9B34FB' console.log("获取到的serviceId::", serviceId); // 缓存数据 serviceId app.globalData.serviceId = serviceId; //获取蓝牙低功耗设备某个服务中所有特征 (characteristic)。 wx.getBLEDeviceCharacteristics({ deviceId: app.globalData.selmac.deviceId, serviceId: '0000FFF0-0000-1000-8000-00805F9B34FB', success: (res) => { console.log("获取蓝牙低功耗设备某个服务中所有特征", res); let characteristicId = res.characteristics[0].uuid; // 缓存数据 characteristicId app.globalData.characteristicId = characteristicId; that.notify(); }, fail: (e) => { console.log("获取蓝牙低功耗设备某个服务中所有特征", e); } }) }, fail: (e) => { console.log("获取蓝牙低功耗设备所有服务失败", e); } }) }, 800) } }) }, onShow() { let that = this; // 记录设备对象 this.setData({ selmac: app.globalData.selmac }) console.log("selmac", that.data.selmac); // 连接设备 wx.createBLEConnection({ deviceId: app.globalData.selmac.deviceId, success: (res) => { console.log("连接成功", res); that.setData({ devLink: true }) // setTimeout(() => { // // 获取蓝牙低功耗设备所有服务 (service) // wx.getBLEDeviceServices({ // deviceId: app.globalData.selmac.deviceId, // success: (res) => { // console.log("获取蓝牙低功耗设备所有服务成功", res); // let serviceId = res.services.filter(item => { // return item.uuid === '0000FEFF-0000-1000-8000-00805F9B34FB' // })[0]; // // 缓存数据 serviceId // app.globalData.serviceId = serviceId; // //获取蓝牙低功耗设备某个服务中所有特征 (characteristic)。 // wx.getBLEDeviceCharacteristics({ // deviceId: app.globalData.selmac.deviceId, // serviceId: serviceId, // success: (res) => { // console.log("获取蓝牙低功耗设备某个服务中所有特征", res); // let characteristicId = res.characteristics[0].uuid; // // 缓存数据 characteristicId // app.globalData.characteristicId = characteristicId; // }, // fail: (e) => { // console.log("获取蓝牙低功耗设备某个服务中所有特征", e); // } // }) // }, // fail: (e) => { // console.log("获取蓝牙低功耗设备所有服务失败", e); // } // }) // }, 1500) }, fail: (e) => { console.log("连接失败", e); } }) //this.listenValueChange() }, connect() { let that = this; if (this.data.selmac.deviceId) { console.log("可以重新初始化蓝牙"); if(!this.data.devLink) { // 如果已经断开,则重新初始化蓝牙 wx.openBluetoothAdapter({ mode: 'peripheral', }) // 连接设备 wx.createBLEConnection({ deviceId: that.data.selmac.deviceId, success: (res) => { console.log("建立连接成功", res); }, fail: (e) => { console.log("建立连接失败", e); wx.showToast({ title: '重新连接失败', icon: 'error' }) } }) } } }, disconnect() { let that = this; if (this.data.selmac.deviceId) { // 连接设备 wx.closeBLEConnection({ deviceId: that.data.selmac.deviceId, success: (res) => { console.log("断开连接成功", res); }, fail: (e) => { console.log("断开连接失败", e); } }) } }, onClearInput() { this.setData({ callBack: '', sendData: '', }); }, startwrite() { // 下发指令 /* let text = this.cleanHexString('FE0007010100FF'); let string = this.hexCharCodeToStr(hexData); */ let testdata = new Uint16Array([...'FE0007010100FF'].map(v => v.codePointAt(0))); console.log("testdata", testdata); let strToHexCharCode = this.hexToByteString('FE0007010100FF'); let buffer = this.hexStringToArrayBuffer(strToHexCharCode); let hexData = this.ab2hex(buffer); console.log("十六进制转成二进制", strToHexCharCode); console.log("二进制字符串转buffer", buffer); console.log("buffer转hexData", hexData); /* console.log("buffer转hexData", hexData); console.log("hexData转string", string); console.log("text", text); */ //this.sendMessage(text); }, hexStringToArrayBuffer(hexStr) { // 移除前缀并确保字符串长度为偶数 hexStr = hexStr.replace(/\\x/g, '').replace(/^0+/, ''); // 确保字符串长度是偶数,如果不是,前面补0 if (hexStr.length % 2 !== 0) { hexStr = '0' + hexStr; } // 将每两个字符视为一个十六进制数,转换为字节数组 const bytes = new Uint8Array(hexStr.match(/.{1,2}/g).map(byte => parseInt(byte, 16))); // 从Uint8Array创建ArrayBuffer return bytes.buffer; }, bindTextAreaBlur(e) { this.data.inputValue = e.detail.value; console.log(e.detail.value) }, // 十六进制转成二进制 hexToByteString(hexString) { let bytes = []; for (let i = 0; i < hexString.length; i += 2) { bytes.push("\\x" + hexString.substr(i, 2)); } return bytes.join(''); }, // 手动输入文本域的值 onInputSend() { console.log("this.data.inputValue", this.data.inputValue); if (this.data.inputValue) { this.sendMessage(this.data.inputValue, true); } else { wx.showToast({ title: '指令不能为空', icon: 'error' }) } }, // 发送数据 sendMessage(event, type) { let that = this; let sendData = ''; if (type) { console.log("手动输出方式"); sendData = event } else { console.log("按钮点击输出方式"); console.log("指令名称::", event.target.dataset.command.name); sendData = event.target.dataset.command.defaultSendData; } if (!that.data.devLink) { wx.showToast({ title: '蓝牙已断开', icon: 'error' }) return } if (!sendData) { wx.showToast({ title: '指令不存在', icon: 'error' }) return } this.setData({ sendData: sendData }) /* let strToHexCharCode = this.hexToByteString('FE0007010100FF'); */ /* let strToHexCharCode = this.hexToByteString(sendData); */ console.log("未转换前的十六进制数据::", sendData) let strToHexCharCode = this.hexToByteString(sendData); console.log("十六进制转成二进制的数据::", strToHexCharCode); let buffer = this.hexStringToArrayBuffer(strToHexCharCode); console.log("二进制转成arrayBuffter的数据::", buffer); console.log("特征值::", 'E4BAA7E5-908E-E5A1-91E5-BDA2E4BBAA02'); console.log("buffer", buffer); wx.writeBLECharacteristicValue({ deviceId: app.globalData.selmac.deviceId, // 设备ID serviceId: /* app.globalData.serviceId */ '0000FFF0-0000-1000-8000-00805F9B34FB', // 服务UUID characteristicId: /* app.globalData.characteristicId */ 'E4BAA7E5-908E-E5A1-91E5-BDA2E4BBAA02', // 特征值 value: buffer, success(res) { console.log("write指令发送成功", res) }, fail(err) { console.log("write指令发送失败", err); that.setData({ callBack: err.errMsg }); wx.showToast({ title: '指令发送失败', icon: 'error' }) } }) }, string2Hex(str) { let val = "" for (let i = 0; i < str.length; i++) { if (val == "") val = str.charCodeAt(i).toString(16) else val += str.charCodeAt(i).toString(16) } return val }, hex2ArrayBuffer(hex_str) { // let hex_str = 'AA5504B10000B5' let typedArray = new Uint8Array(hex_str.match(/[\da-f]{2}/gi).map(function (h) { return parseInt(h, 16) })) let buffer = typedArray.buffer return buffer }, cleanHexString(hexStr) { // 使用正则表达式匹配并移除多余的'0x',并拼接剩下的部分 let cleanedHex = hexStr.replace(/0x/g, '').replace(/\b0+/g, ''); // 第二个正则表达式用于移除前导零 return cleanedHex; }, // 开启读取蓝牙低功耗设备特征值的二进制数据 read() { let that = this; let text = 'fe000f000176657220312e302e31ff' let string = that.hexCharCodeToStr(text); console.log("测试", string); /* wx.readBLECharacteristicValue({ deviceId: app.globalData.selmac.deviceId, // 设备ID, serviceId: app.globalData.serviceId, // 服务UUID characteristicId: app.globalData.characteristicId, // 特征值 success (res) { console.log('readBLECharacteristicValue:', res); } }) */ }, // 根据type,向设备写入十六进制数据, write(data, type) { let that = this; let characteristicId = type === 'read' ? 'E4BAA7E5-908E-E5A1-91E5-BDA2E4BBAA01' : 'E4BAA7E5-908E-E5A1-91E5-BDA2E4BBAA02'; console.log("监听到设备有数据上报,回应设备"); console.log("未转换前的十六进制数据::", data) let strToHexCharCode = this.hexToByteString(data); console.log("十六进制转成二进制的数据::", strToHexCharCode); let buffer = this.hexStringToArrayBuffer(strToHexCharCode); console.log("二进制转成arrayBuffter的数据::", buffer); console.log("特征值::", characteristicId); wx.writeBLECharacteristicValue({ deviceId: app.globalData.selmac.deviceId, // 设备ID serviceId: /* app.globalData.serviceId */ '0000FFF0-0000-1000-8000-00805F9B34FB', // 服务UUID characteristicId: characteristicId, // 特征值 value: buffer, success(res) { console.log("write指令发送成功", res) //that.read(); }, fail(err) { console.log("write指令发送失败", err); that.setData({ callBack: err.errMsg }); wx.showToast({ title: '指令发送失败', icon: 'error' }) } }) }, // 将一个字符串截取前面多少位,后面多少位,返回中间值 extractMiddleData(encodedStr, startNum, endNum) { // 前面截取10位 const start = encodedStr.substring(0, startNum); // 后面截取2位 const end = encodedStr.substring(encodedStr.length - endNum); // 计算中间部分的起始索引 const middleStartIndex = start.length; // 总长度减去前后部分的长度得到中间部分的长度 const middleLength = encodedStr.length - middleStartIndex - end.length; // 提取中间部分 const middlePart = encodedStr.substring(middleStartIndex, middleStartIndex + middleLength); return middlePart; }, // 开启设备通知消息监听 notify() { let that = this; wx.notifyBLECharacteristicValueChange({ deviceId: app.globalData.selmac.deviceId, // 设备ID, serviceId: app.globalData.serviceId, // 服务UUID characteristicId: app.globalData.characteristicId, // 特征值 state: true, success(res) { console.log("开启消息监听", res) // 监听消息变化的方法 that.listenValueChange() }, fail(err) { console.error("消息监听失败", err) } }) }, // 消息变化 listenValueChange() { let that = this; let result = ""; wx.onBLECharacteristicValueChange(res => { console.log("设备响应", res) console.log("设备上报的数据", res.value); // ArrayBuffer转16进制字符串 let resHex = that.ab2hex(res.value); console.log("设备上报的16进制字符串", resHex); // 从第六位开始截取,截取10位,拿关键的数据识别上报数据类型 let sliceData = resHex.slice(6, 10); // 通过截取的到数据区分是下发后上报还是自动上报的数据 console.log("截取到上报数据的关键指令", sliceData); //console.log("ArrayBuffer转16进制字符串", resHex) result = that.extractMiddleData(resHex, 10, 2); console.log("上报截取关键内容::", result); let isAuto = that.data.reportData.findIndex(item => { return item.keyWord === sliceData; }) if (isAuto > -1) { // 证明是自动上报的数据,否则不是 let report = that.data.reportData.filter(item => { return item.keyWord === sliceData }); console.log("上报的数据类型:", report[0].cnName); // 16进制字符串转字符串,根据情况,有些上报数据需要转字符串,有些则不需要 if (report[0].keyWord === '0001') { that.setData({ ['deviceInfo.version']: that.hexCharCodeToStr(result) }) } else if (report[0].keyWord === '0002') { // 电池电量 that.setData({ ['deviceInfo.battery']: result }) }else if (report[0].keyWord === '0003') { // 充电状态 that.setData({ ['deviceInfo.chargeState']: result === '01' ? '以充电' : '未充电' }) } else if (report[0].keyWord === '0004') { // 极片工作状态 that.setData({ ['deviceInfo.poleWorkState']: result }) }else if (report[0].keyWord === '0005') { // 运行工作状态 that.setData({ ['deviceInfo.workState']: result }) }else if (report[0].keyWord === '0006') { // 上报异常 that.setData({ ['deviceInfo.error']: result }) }else if (report[0].keyWord === '0007') { // 上报工作开始 that.setData({ ['deviceInfo.workStart']: result }) }else if (report[0].keyWord === '0008') { // 上报工作结束 that.setData({ ['deviceInfo.workEnd']: result }) }else if (report[0].keyWord === '0009') { // 上报工作结果 that.setData({ ['deviceInfo.workResult']: result }) }else { } // 返回结果后向设备回应 that.write(report[0].response, 'write'); } else { // 是下发上报的 // 返回结果后向设备回应 /* that.write(report[0].response, 'write'); */ console.log("下发上报"); // 根据上报截取的数据解析下发上报的数据 if(sliceData === '8101'){ // 读取工作强度映射表,以每个字节分割 let resultArr = that.splitStringEveryTwoChars(result, 2); let workMapList = resultArr.map(item => { return that.hexToDecimal(item); }) console.log("resultArr", resultArr); console.log("workMapList", workMapList); } else if (sliceData === '8102') { // 设置设备工作强度映射表响应的 console.log("设置设备工作强度映射表响应", resHex); } } that.setData({ callBack: String(result) }); }) }, // 将16进制的内容转成我们看得懂的字符串内容 hexCharCodeToStr(hexCharCodeStr) { var trimedStr = hexCharCodeStr.trim(); var rawStr = trimedStr.substr(0, 2).toLowerCase() === "0x" ? trimedStr.substr(2) : trimedStr; var len = rawStr.length; if (len % 2 !== 0) { alert("存在非法字符!"); return ""; } var curCharCode; var resultStr = []; for (var i = 0; i < len; i = i + 2) { curCharCode = parseInt(rawStr.substr(i, 2), 16); resultStr.push(String.fromCharCode(curCharCode)); } return decodeURIComponent(resultStr.join("")); }, /*字符串转换16进制buffer*/ stringToCmdBuffer(msg) { console.log("msg", msg); const buffer = new ArrayBuffer(msg.length) const dataView = new DataView(buffer) //dataView.setUint8(0, 0) for (let i = 0; i < msg.length; i++) { dataView.setUint8(i, msg.charAt(i).charCodeAt()) }; return buffer }, // 十六进制转二进制 strToHexCharCode(str) { if (str === "") return ""; var hexCharCode = []; hexCharCode.push("0x"); for (var i = 0; i < str.length; i++) { hexCharCode.push((str.charCodeAt(i)).toString(16)); } return hexCharCode.join(""); }, // 十六进制转十进制 hexToDecimal(hexString) { return parseInt(hexString, 16); }, // ArrayBuffer转16进度字符串示例 ab2hex(buffer) { let hexArr = Array.prototype.map.call( new Uint8Array(buffer), function (bit) { return ('00' + bit.toString(16)).slice(-2) } ) return hexArr.join(''); }, // 通过几位分割成数组 splitStringEveryTwoChars(str, splitNumber) { let result = []; for (let i = 0; i < str.length; i += splitNumber) { result.push(str.substring(i, i + splitNumber)); } return result; } })