<template>
|
<view class="template-job tn-safe-area-inset-bottom tn-skeleton">
|
|
<tn-nav-bar fixed style=" position: absolute;z-index: 999999999;">
|
<text class="page-title">寻物防丢</text>
|
</tn-nav-bar>
|
<view class="print" :style="{ top:bleHeight+'px'}">
|
<!-- 已匹配列表 -->
|
<view class="print-nearby shadow">
|
<view class="print-nearby-title">
|
<view class="matching">已匹配设备:</view>
|
<view class="break" @click="closeBle" v-if="GET_CONNECT_DEVICEId">断开</view>
|
</view>
|
<view class="Connecting-flex">
|
<view class="Connecting-name">{{ GET_BLE_DATA}}</view>
|
<view class="button-wraper" :class="GET_CONNECT_DEVICEId ? 'search-cted-selected' : 'search-cted'">
|
{{GET_CONNECT_DEVICEId?"已连接":"未连接"}}
|
</view>
|
</view>
|
</view>
|
<!-- 附近设备 -->
|
<view class="print-nearby shadow">
|
<view class="print-nearby-title name">附近设备:</view>
|
<scroll-view scroll-x="false" scroll-y="true" class="print-nearby-list">
|
<view v-for="(item, index) in searchList" :key="index" class="print-nearby-list-search"
|
@tap="connectTo(item)">
|
<view v-if="item.name" class="search-titID">
|
{{ item.name }}
|
</view>
|
<view :class="GET_CONNECT_DEVICEId == item.deviceId ? 'search-cted-selected' : 'search-cted'">
|
{{GET_CONNECT_DEVICEId == item.deviceId?"已连接":"未连接"}}
|
</view>
|
</view>
|
</scroll-view>
|
</view>
|
<!-- 读取数据 -->
|
<view class="print-nearby shadow" v-if="readList.length>0">
|
<view class="print-nearby-title name">读取数据:</view>
|
<scroll-view scroll-x="false" scroll-y="true" class="print-nearby-list" :scrollTop="scrollTop">
|
<view v-for="(item, index) in readList" :key="index" class="print-nearby-list-search">
|
<view class="search-titID">
|
实时距离:{{ item }}m
|
</view>
|
</view>
|
</scroll-view>
|
</view>
|
<view class="print-btn">
|
<view class="print-btn-tab" @click="searchBlue">搜索蓝牙</view>
|
<view class="print-btn-tab" @click="closeBle">关闭蓝牙</view>
|
<view class="print-btn-tab" @click="backPage">返回主页</view>
|
</view>
|
</view>
|
</view>
|
</template>
|
<script>
|
import store from '@/store/index.js'
|
import encoding from '../../static/encoding.js'
|
export default {
|
data() {
|
return {
|
readList: [],
|
scrollIntoView: '',
|
scrollTop: 0,
|
blePrint: [],
|
searchList: [],
|
bleDevs: [],
|
device: [], //搜索到的设备
|
deviceId: '', //设备id
|
serverList: [], //服务
|
serviceId: '',
|
characteristics: [], //特征值
|
characteristicId: '', //特征值uuid
|
writeId: '', //可写
|
readId: '', //可读·
|
txt: ''
|
}
|
},
|
mounted() {
|
uni.openBluetoothAdapter({
|
success(res) {
|
console.log('初始化蓝牙成功', res)
|
uni.getBluetoothAdapterState({ //检测蓝牙是否打开 //获取本机蓝牙适配器状态
|
//蓝牙的匹配状态
|
success: (res1) => {
|
console.log(res1, "“本机设备的蓝牙已打开”");
|
},
|
fail(error) {
|
uni.showToast({
|
icon: "none",
|
title: "查看手机蓝牙(安卓蓝牙定位)是否打开"
|
});
|
},
|
});
|
},
|
fail(err) {
|
console.log('初始化蓝牙失败')
|
uni.showToast({
|
title: "请打开蓝牙",
|
icon: "error"
|
})
|
console.error(err)
|
}
|
})
|
},
|
methods: {
|
closeBle() { //关闭蓝牙
|
this.readList = []//关闭蓝牙清空数据
|
uni.closeBLEConnection({
|
deviceId: this.GET_CONNECT_DEVICEId,
|
success(res) {
|
store.commit('$tStore', {
|
name: 'GET_CONNECT_DEVICEId',
|
value: ""
|
})
|
store.commit('$tStore', {
|
name: 'GET_BLE_DATA',
|
value: '请先连接蓝牙'
|
})
|
|
}
|
})
|
},
|
backPage(){
|
uni.reLaunch({
|
url: '/pages/index/index'
|
});
|
},
|
searchBlue() { //搜索监听蓝牙
|
|
var that = this
|
that.searchList = []
|
uni.startBluetoothDevicesDiscovery({
|
allowDuplicatesKey: false, //允许重复上报同一个设备
|
success: (res) => {
|
console.log('搜索蓝牙成功 success', res);
|
//监听寻找到新设备的事件
|
that.onBluetoothDeviceFound();
|
},
|
fail(err) {
|
console.log('搜索失败')
|
console.error(err)
|
}
|
})
|
},
|
onBluetoothDeviceFound() { // 获取设备列表
|
uni.onBluetoothDeviceFound((res) => {
|
// console.log(res.devices, '搜索完成所有的设备列表')
|
var that = this
|
res.devices.forEach((item) => { //搜索指定设备
|
// if (item.name == "HC-09") { //REGLOCK_4ed8
|
if (item.name != "") {
|
that.searchList.push(item);
|
}
|
// console.log('deviceId:', item.deviceId)
|
})
|
})
|
},
|
connectTo(item) { //连接蓝牙
|
let that = this;
|
if (that.GET_CONNECT_DEVICEId) {
|
uni.showToast({
|
title: "当前已连接,请先手动断开",
|
icon: "none",
|
});
|
return
|
}
|
uni.createBLEConnection({
|
deviceId: item.deviceId,
|
success(res) {
|
console.log(res, '连接成功')
|
store.commit('$tStore', {
|
name: 'GET_CONNECT_DEVICEId',
|
value: item.deviceId
|
})
|
store.commit('$tStore', {
|
name: 'GET_BLE_DATA',
|
value: item.name
|
})
|
uni.showLoading({
|
title: '设备连接成功,读取数据中...'
|
})
|
that.getBLEDeviceServices(item.deviceId)
|
//连接成功之后 停止搜索
|
uni.stopBluetoothDevicesDiscovery({
|
success(res) {
|
console.log('停止搜索蓝牙', res)
|
}
|
})
|
uni.getConnectedBluetoothDevices({ //已连接
|
success(res) {
|
console.log(res.devices, '已连接过的设备')
|
}
|
})
|
},
|
fail(res) {
|
uni.showToast({
|
title: "蓝牙连接失败",
|
icon: "none",
|
});
|
uni.hideLoading()
|
},
|
computed(res) {
|
//设备获取完成之后 停止搜索
|
uni.stopBluetoothDevicesDiscovery({
|
success(res) {
|
console.log('停止搜索蓝牙', res)
|
}
|
})
|
}
|
});
|
|
},
|
//获取蓝牙设备所有服务(service)。
|
getBLEDeviceServices(deviceId) {
|
const _this = this;
|
setTimeout(() => {
|
uni.getBLEDeviceServices({
|
// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
|
deviceId: deviceId,
|
success: res => { //此时需要循环遍历每个serviceId获取到特征值,但是在厂商中只有6e4开头获取到的特征值才能操作蓝牙
|
console.log('获取蓝牙设备所有服务serviceId:', JSON.stringify(res.services));
|
if (JSON.stringify(res.services).length==0) {
|
uni.hideLoading();
|
uni.showToast({
|
title: "设备服务获取失败",
|
icon: "none",
|
});
|
}
|
_this.serverList = res.services;
|
_this.serviceId = res.services[3].uuid; //选择支持的uuid
|
_this.getBLEDeviceCharacteristics(deviceId, res.services[3].uuid); //获取设备特征
|
},
|
fail: res => {
|
console.log(res);
|
uni.hideLoading();
|
uni.showToast({
|
title: "设备服务获取失败",
|
icon: "none",
|
});
|
}
|
});
|
}, 1000);
|
},
|
getBLEDeviceCharacteristics(deviceId, serviceId) { //获取设备特征
|
var that = this
|
console.log("进入特征");
|
setTimeout(() => {
|
uni.getBLEDeviceCharacteristics({
|
// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
|
deviceId: deviceId,
|
// 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取
|
serviceId: serviceId,
|
success: (res) => {
|
console.log(res, '特征getBLEDeviceCharacteristics')
|
for (var i = 0; i < res.characteristics.length; i++) {
|
if (res.characteristics[i].properties.notify === true) { //可通知
|
that.characteristics = res.characteristics[i];
|
that.characteristicId = res.characteristics[i].uuid;
|
}
|
|
if (res.characteristics[i].properties.write ===
|
true) { //可写 notify也要true
|
that.characteristics = res.characteristics[i];
|
that.writeId = res.characteristics[i].uuid;
|
}
|
if (res.characteristics[i].properties.read === true) { //可读
|
that.characteristics = res.characteristics[i];
|
that.readId = res.characteristics[i].uuid;
|
}
|
}
|
store.commit('$tStore', {
|
name: 'bledeviceId',
|
value: deviceId
|
})
|
store.commit('$tStore', {
|
name: 'bleserviceId',
|
value: serviceId
|
})
|
store.commit('$tStore', {
|
name: 'blewriteId',
|
value: that.writeId
|
})
|
store.commit('$tStore', {
|
name: 'isceju',
|
value: true
|
})
|
setTimeout(() => {
|
that.notifyBLECharacteristicValueChange(deviceId, serviceId,
|
that.characteristicId)
|
}, 1000);
|
},
|
fail: (res) => {
|
console.log(res)
|
}
|
})
|
|
}, 1000)
|
},
|
// 启用 notify 功能
|
notifyBLECharacteristicValueChange(deviceId, serviceId, characteristicId) {
|
const _this = this;
|
uni.notifyBLECharacteristicValueChange({
|
state: true,
|
deviceId: deviceId,
|
serviceId: serviceId,
|
characteristicId: characteristicId,
|
success: function(res) {
|
console.log("启用notify成功", res);
|
setTimeout(() => { //接收消息的方法
|
_this.onBLECharacteristicValueChange();
|
}, 1000);
|
},
|
fail: function(res) {
|
console.log("启用notify失败", res);
|
},
|
});
|
},
|
//监听设备返回数据的接收
|
onBLECharacteristicValueChange() {
|
var that = this;
|
setTimeout(() => { //接收消息的方法
|
if (that.readList.length==0) {
|
uni.hideLoading();
|
uni.showToast({
|
title: "数据获取失败",
|
icon: "none",
|
});
|
}
|
}, 3000);
|
|
uni.onBLECharacteristicValueChange((res) => {
|
// console.log(res, '返回数据')
|
// 结果里有个value值,该值为 ArrayBuffer 类型
|
let resHex = that.ab2hex(res.value)
|
|
console.log(resHex, '16进制') //ArrayBuffer转16进制后的结果
|
// 最后将16进制转换为ascii码,就能看到对应的结果 字母 数字
|
let result = that.hexToStr(resHex)
|
});
|
},
|
ab2hex(buffer) { //接收转换
|
// ArrayBuffer转16进度字符串示例
|
const hexArr = Array.prototype.map.call(new Uint8Array(buffer), function(bit) {
|
return ('00' + bit.toString(16)).slice(-2);
|
});
|
return hexArr.join('');
|
},
|
hexToStr(hex) { //转成字符串汉字
|
// 去掉字符串首尾空格
|
let trimedStr = hex.trim()
|
let startsWith5a = trimedStr.substr(0, 2).toLowerCase() === "a5";
|
// 判断最后两个字符是否为a5
|
let endsWithA5 = trimedStr.substr(-2).toLowerCase() === "5a";
|
|
// 判断trimedStr前两个字符是否为0x,如果是则截取从第三个字符及后面所有,否则返回全部字符
|
// let rawStr = trimedStr.substr(0, 2).toLowerCase() === "a5" ? trimedStr.substr(2) : trimedStr
|
|
if (startsWith5a && endsWithA5) {
|
// 如果同时满足条件,去掉前两个和最后两个字符
|
trimedStr = trimedStr.slice(2, -2);
|
} else if (startsWith5a) {
|
// 只去掉前两个字符
|
trimedStr = trimedStr.slice(2);
|
} else if (endsWithA5) {
|
// 只去掉最后两个字符
|
trimedStr = trimedStr.slice(0, -2);
|
}
|
// console.log(trimedStr);
|
// 得到rawStr的长度
|
let len = trimedStr.length
|
// 如果长度不能被2整除,那么传入的十六进制值有误,返回空字符
|
if (len % 2 !== 0) {
|
return ""
|
}
|
let curCharCode // 接收每次循环得到的字符
|
let resultStr = [] // 存转换后的十进制值数组
|
var two = trimedStr.substr(1, 1)
|
var four = trimedStr.substr(2, 3)
|
// for (let i = 0; i < len-2; i = i + 2) {
|
curCharCode = parseInt(four+two, 16)
|
console.log(curCharCode);
|
|
store.commit('$tStore', {
|
name: 'bledistance',
|
value: (curCharCode / 100).toFixed(2)
|
})
|
resultStr.push(curCharCode)
|
this.readList.push((curCharCode / 100).toFixed(2))
|
this.$nextTick(() => {
|
this.scrollTop = this.scrollTop + 50; // 假设每条数据高度为50px,动态调整滚动位置
|
});
|
uni.hideLoading();
|
// encoding为空时默认为utf-8
|
let bytesView = new Uint8Array(resultStr) // 8 位无符号整数值的类型化数组
|
// TextEncoder和TextDecoder对字符串和字节流互转
|
// let str = new TextDecoder(encoding).decode(bytesView)因为小程序中没有TextDecoder,经查阅资料,下载https://github.com/inexorabletash/text-encoding并const encoding = require("./text-encoding-master/lib/encoding.js")引入后使用下面方式即可:
|
let str = new encoding.TextDecoder("utf-8").decode(bytesView)
|
|
return str
|
},
|
readBLECharacteristicValue() { //读取二进制数据值
|
let _this = this;
|
uni.readBLECharacteristicValue({
|
// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
|
deviceId: _this.deviceId,
|
// 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取
|
serviceId: _this.serviceId,
|
// 这里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取
|
characteristicId: _this.readId,
|
success(res) {
|
console.log('readBLECharacteristicValue:', res)
|
}
|
})
|
},
|
//字符串转ArrayBuff
|
strToArrayBuffer(str) {
|
// 首先将字符串转为16进制
|
let val = str
|
for (let i = 0; i < str.length; i++) {
|
if (val === '') {
|
val = str.charCodeAt(i).toString(16)
|
} else {
|
val += ',' + str.charCodeAt(i).toString(16)
|
}
|
}
|
// 将16进制转化为ArrayBuffer
|
return new Uint8Array(val.match(/[\da-f]{2}/gi).map(function(h) {
|
return parseInt(h, 16)
|
})).buffer
|
},
|
//字符串转16进制码
|
str_to_hex(str) {
|
var hexCharCode = [];
|
for (var i = 0; i < str.length; i++) {
|
hexCharCode.push((str.charCodeAt(i)).toString(16));
|
}
|
hexCharCode = hexCharCode.join("");
|
return hexCharCode;
|
},
|
writeBLECharacteristicValue() { //写入值
|
let _this = this;
|
//蓝牙设备写入数据时,需要将数据先转换为 ArrayBuffer
|
let msg = 'hello'
|
const buffer = new ArrayBuffer(msg.length)
|
const dataView = new DataView(buffer)
|
// dataView.setUint8(0, 0)
|
|
for (var i = 0; i < msg.length; i++) { //只支持英文 数字
|
dataView.setUint8(i, msg.charAt(i).charCodeAt())
|
}
|
uni.writeBLECharacteristicValue({
|
deviceId: _this.deviceId,
|
serviceId: _this.serviceId,
|
characteristicId: _this.writeId,
|
value: buffer, //自定义内容buffer
|
success(res) {
|
console.log('写入成功', res)
|
},
|
fail(err) {
|
console.log('写入失败', err)
|
}
|
})
|
},
|
}
|
}
|
</script>
|
|
<style lang="scss" scoped>
|
@import "@/common/css/popup.scss";
|
</style>
|