// components/map-sense.js let innerAudioContext = wx.createInnerAudioContext(); innerAudioContext.src = 'none' import { promisify, BeaconUtils } from "../../utils/util"; let openBluetoothAdapter = promisify(wx.openBluetoothAdapter); let startBeaconDiscovery = promisify(wx.startBeaconDiscovery); let stopBeaconDiscovery = promisify(wx.stopBeaconDiscovery); let app = getApp(); import { CDN_URL, CONNECT_STATUS, STATUS_TEXT, API_BASE_URL, DISTRIBUTION2, AudioAddress, } from "../../config/index"; const STATUS_PIC = { 0: "default", 1: "loading", 2: "success", 3: "fail", }; let audioInterruptionCb = () => {}; let bluetoothAdapterStateChangeCb = () => {}; let isCollect = false; let hadshowModal = false let checkCollect = null let checkTimeout = null let updateingBeacon = false let updateTO = null let changeTO = null; let isalwaysNullTO = null // 选择6档 const TXPOWER = -55; var result = 0, oldResult = -1; // 距离经验值(调试所得) const N = 3.3; const R = 4; //设定感应范围半径 const RSSIVAL = 70; //rssi信号过滤临界点 let AveLength = 10; let group = [ ["10001", "10002"], ["10003"], ["10004"], ["10005", "10006"], ["10007"], ["10008"], ["10009"], ["10010"], ["10011"], ["10012", "10013"], ["10014"], ["10015"], ["10016"], ["10017", "10018"], ["10019"], ["10020", "10021"], ["10022"], ["10023"], ["10024"], ]; // 1:['10001','10002'],2:['10003'], // 3:['10004'],4:['10005'],5:['10006'], // 6:['10007'],7:['10008'],8:['10009'], // 9:['10010'],10:['10011'],11:['10012','10013'], // 12:['10014'],13:['10015'],14:['10016'], // 15:['10017'],16:['10018'],17:['10019'], // 18:['10020','10021'],19:['10022'], // 20:['10023'],21:['10024'] Component({ /** * 组件的属性列表 */ properties: {}, /** * 组件的初始数据 */ data: { status: "0", isAndroid:app.globalData.userInfo.system.toLowerCase().indexOf("android")>-1, cdn_url: CDN_URL, connect_status: CONNECT_STATUS, status_text: STATUS_TEXT, status_pic: STATUS_PIC, targetObj: {}, audio_address: {}, api_base_url: API_BASE_URL, // 是否是扫码播放 isScanPlay: false, cdn_url: CDN_URL, classfiy: {}, }, /** * 组件的方法列表 */ methods: { openBluetooth(cb) { wx.showLoading({ title: "正在打开蓝牙…", mask: true, }); openBluetoothAdapter().then( (res) => { wx.hideLoading({ fail() {} }); cb(res); // if (app.globalData.userInfo.system.toLowerCase().indexOf("android")>-1) { // wx.getLocation({ // type: "gcj02", //返回可以用于wx.openLocation的经纬度 // success: () => { // cb(res); // }, // fail: (err) => { // console.log(err); // wx.showToast({ // title: "请打开手机定位服务", // icon: "error", // duration: 500, // }); // }, // }); // } else { // cb(res); // } }, () => { wx.hideLoading({ fail() {} }); wx.showToast({ title: "请打开蓝牙", icon: "error", duration: 2000, }); } ); }, toHandle() { if (this.data.status == "2") { this.stopBeaconDiscovery(); return; } let aveArr = []; let fn = ()=>{ wx.hideLoading({ fail() {} }); this.setData({ status: "2", }); isCollect = true; updateingBeacon = false if (this.data.isAndroid) { checkCollect && clearInterval(checkCollect) checkTimeout && clearTimeout(checkTimeout) checkTimeout = setTimeout(() => { checkCollect = setInterval(() => { if (!updateingBeacon) { if (!hadshowModal) { hadshowModal = true wx.showModal({ title: "请检查手机定位服务、蓝牙和网络是否保持打开状态(注:部分鸿蒙系统不支持该功能)", showCancel: false, success:()=>{ this.resetPage() checkCollect && clearInterval(checkCollect) checkTimeout && clearTimeout(checkTimeout) hadshowModal = false } }); } } }, 4000) }, 3000); } wx.onBeaconUpdate((data) => { console.log(data, "onBeaconUpdate"); if (!isCollect) { return; } if (this.data.isAndroid) { updateTO && clearTimeout(updateTO) updateTO = setTimeout(() => { console.log('重置updateingBeacon'); updateingBeacon = false }, 10000); updateingBeacon = true } console.log("还在收集…………"); // 需要收集十组数据,索引号最大的组是最旧的 if (!aveArr.includes(data.beacons)) { if (aveArr.length >= AveLength) { //当超过十组时,应该将索引号大的组淘汰掉 aveArr.pop(); } aveArr.unshift(BeaconUtils.clone(data.beacons)); //在队列前面插入 } let all = []; //获取所有data.beacons数据 for (let i = 0; i < aveArr.length; i++) { let ele = aveArr[i]; for (let j = 0; j < ele.length; j++) { let item = ele[j]; //过滤信号弱的数据 // if (!(item.proximity === 0 && item.rssi === 0)) { if (Math.abs(item.rssi) < RSSIVAL) { // console.log(item.accuracy,'accuracy------'); if (!all.includes(item)) { all.push(BeaconUtils.clone(item)); } } // } } } let accuracyList = {}; // classfiy = {10003:[{},{},···],10002:[{},{},···],10001:[{},{},···]} let classfiy = BeaconUtils.classification(all, "major"); // console.log(classfiy,'classfiy'); Object.keys(classfiy).forEach((key) => { //每个major的AveLength个元素数组,元素为rssi let arr = classfiy[key].map((item) => { return item.rssi; }); //每个major的rssi平均值 let ave = BeaconUtils.arrayAverage(arr); //计算平均差 let meanDeviation = BeaconUtils.getMeanDeviation(arr, ave); //计算各rssi的高斯模糊权重 let guassionArr = []; //存放权重数组 for (let i = 0; i < arr.length; ++i) { guassionArr.push( BeaconUtils.getOneGuassionArray( arr.length, i, meanDeviation ) ); } //计算高斯模糊后的rssi值 let rssiArr = []; //模糊后的rssi数组 for (let i = 0; i < arr.length; ++i) { let sum = 0; for (let j = 0; j < arr.length; ++j) { if (guassionArr[i].length == 0) { sum = arr[j]; break; } sum += guassionArr[i][j] * arr[j]; } rssiArr.push(sum); } //时间加权后求rssi平均值 let aveOnTime = BeaconUtils.arrayAverage( rssiArr .slice(0, Math.floor(rssiArr.length / 3)) .concat(rssiArr) ); //测距,根据时间加权后的rssi计算距离 // classfiy[key].forEach((item) => { let tmp = BeaconUtils.calculateAccuracy(TXPOWER, aveOnTime, N); if (!accuracyList[key]) { //如果还没有对应的“信标号” accuracyList[key] = [tmp]; } else { accuracyList[key].push(tmp); } // }); }); Object.keys(accuracyList).forEach((item) => { console.log(accuracyList[item] + "---------" + item); }); console.log("--------分隔--------"); // 筛选器,筛选出配对的一组信标 let signSelect = new Array(19).fill(0); //记录各组的信标出现数量,投票选择最多的,依次是prologue,annexHall,mainHall // const prologue = ['10001','10002'] //序厅 // const annexHall = ['10003','10004','10005','10006','10007'] //附厅 // const mainHall = ['10008'] //主厅 Object.keys(accuracyList).forEach((key) => { let aveAccuracy = BeaconUtils.arrayAverage(accuracyList[key]); if (aveAccuracy < R) { for (let i = 0; i < group.length; i++) { if (group[i].includes(key)) { signSelect[i] += 1 / (aveAccuracy + 0.01); //取距离的反比例函数值,距离越近,值越大,+0.01是为了防止除数为0 } } } }); console.log(signSelect); //对小于预设半径的信号进行数量投票 result = BeaconUtils.maxIndex(signSelect); console.log("result音频结果", result,group[result]); if (result != null && result !== oldResult) { wx.hideLoading({ fail() {} }); this.playAudio(AudioAddress[result]); oldResult = result; } if (result === null && oldResult != -1) { changeTO && clearTimeout(changeTO); changeTO = setTimeout(() => { wx.hideLoading({ fail() {} }); }, 4000); this.stopAndDestroyAudio(); // isalwaysNullTO && clearTimeout(isalwaysNullTO); // isalwaysNullTO = setTimeout(() => { // (result === null && oldResult != -1) && this.stopAndDestroyAudio(); // }, 1000); } let temp = DISTRIBUTION2.find((item) => { return item.position.some((sub) => sub == result); }); this.setData({ classfiy, targetObj: temp || {}, result, }); }); } this.openBluetooth(() => { wx.showLoading({ title: "正在连接…", mask: true, }); startBeaconDiscovery({ uuids: ["FDA50693-A4E2-4FB1-AFCF-C6EB07647825"], }) .then(() => { fn() }) .catch((err) => { console.log(err); if (err.errCode == 11002) { wx.showToast({ title: "请打开手机定位服务", icon: "none", duration: 1000, }); } else if (err.errCode == 11005) { if (this.data.isAndroid) { fn() } else{ wx.showToast({ title: "您的系统暂不支持该功能", icon: "none", duration: 1000, }); } } else { wx.showToast({ title: "连接失败", icon: "error", duration: 1000, }); } }); }); }, stopAndDestroyAudio() { oldResult = -1; if (!innerAudioContext) { return; } innerAudioContext.pause(); innerAudioContext.stop(); innerAudioContext.destroy(); innerAudioContext.src = 'none'; innerAudioContext = null; }, playAudio(src) { if (innerAudioContext) { innerAudioContext.pause(); innerAudioContext.stop(); innerAudioContext.destroy(); innerAudioContext.src = 'none'; } innerAudioContext = null; innerAudioContext = wx.createInnerAudioContext(); innerAudioContext.src = src; innerAudioContext.loop = true; innerAudioContext.onCanplay(() => { innerAudioContext.play(); }); // innerAudioContext.play(); }, stopBeaconDiscovery(notips = null) { console.log("这是取消连接"); // 取消连接 停止播放音乐 目标对象置为{} 设置为第一次进入 checkCollect && clearInterval(checkCollect) checkTimeout && clearTimeout(checkTimeout) updateTO && clearTimeout(updateTO) this.stopAndDestroyAudio(); this.reset(); isCollect = false; stopBeaconDiscovery() .then(() => { !notips && wx.showToast({ title: "取消连接成功", icon: "error", duration: 1000, }); }) .catch((err) => { console.log(err); }); }, reset() { this.setData({ status: "0", targetObj: {}, }); }, resetPage() { this.stopBeaconDiscovery(true); }, }, lifetimes: { attached: function () { audioInterruptionCb = () => { console.log(innerAudioContext); if (innerAudioContext) { this.resetPage(); } }; bluetoothAdapterStateChangeCb = (res) => { if (!Boolean(res.available)) { this.resetPage(); } }; wx.onAudioInterruptionEnd(audioInterruptionCb); wx.onBluetoothAdapterStateChange(bluetoothAdapterStateChangeCb); wx.onAppShow(audioInterruptionCb); app.events.on('network', this, (data) =>{ if (!data) { this.resetPage(); } }) }, detached: function () { this.resetPage(); wx.offAudioInterruptionEnd(audioInterruptionCb); wx.offBluetoothAdapterStateChange(bluetoothAdapterStateChangeCb); wx.offAppShow(audioInterruptionCb); app.events.remove('network',this) }, }, });