602 lines
14 KiB
Vue
602 lines
14 KiB
Vue
<template>
|
||
<view class="content">
|
||
<button type="default" v-show="!shows" @click="initBle">
|
||
初始化蓝牙模块
|
||
</button>
|
||
<scroll-view scroll-y="true" show-scrollbar="true">
|
||
<radio-group>
|
||
<view v-for="(item, index) in bleDevs" :key="index" v-show="item.name.length > 0 && !shows"
|
||
style="padding: 10rpx 20rpx; border-bottom: 1rpx solid #ececec"
|
||
v-if="Math.max(100 + item.RSSI, 0) >= 30">
|
||
<view style="font-size: 32rpx; color: #333">
|
||
<checkbox-group @change="checkboxChange" :data-name="item.name" :data-deviceId="item.deviceId">
|
||
<label>
|
||
<checkbox :value="item.deviceId">
|
||
{{ item.name }}
|
||
</checkbox>
|
||
</label>
|
||
</checkbox-group>
|
||
</view>
|
||
<view style="font-size: 20rpx; padding: 10rpx 0">
|
||
deviceId: {{ item.deviceId }} 信号强度: {{ item.RSSI }}dBm ({{
|
||
Math.max(100 + item.RSSI, 0)
|
||
}}%)
|
||
</view>
|
||
</view>
|
||
<view class="dis">
|
||
<view @tap="connectBle" v-if="!shows" class="pl"> 连接 </view>
|
||
<view @tap="close" v-if="shows" class="pl"> 断开 </view>
|
||
</view>
|
||
</radio-group>
|
||
</scroll-view>
|
||
|
||
<view class="appItems">
|
||
<viwe :class="[item.status ? 'item bakBlue' : 'item']" v-for="(item, index) in totalList" :key="index">
|
||
<view class="name p_hide">蓝牙名称:{{ item.name }}</view>
|
||
<view class="txt">蓝牙数据:{{ item.text }}</view>
|
||
</viwe>
|
||
</view>
|
||
|
||
<view class="items" v-if="shows">
|
||
<view class="item" v-for="(item, index) in getData" :key="index">
|
||
{{ item.name }}:{{ item.txt }}
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
export default {
|
||
data() {
|
||
return {
|
||
config: {
|
||
color: "#333",
|
||
backgroundColor: [1, "#fff"],
|
||
title: "多设备蓝牙连接",
|
||
back: false,
|
||
},
|
||
title: "Hello",
|
||
bleDevs: [],
|
||
status: -2, //-2未连接 -1已连接 0连接成功
|
||
deviceId: "",
|
||
serviceId: "",
|
||
characteristicId: "",
|
||
|
||
sendData: "",
|
||
getData: [],
|
||
|
||
deviceIds: [],
|
||
totalList: [], // 全部已连接的设备
|
||
|
||
timeIndex: 0, // 默认是列表的第一个
|
||
|
||
timeout: null,
|
||
shows: false,
|
||
|
||
titleTime: "00:00:00",
|
||
timer: "",
|
||
|
||
hour: 0,
|
||
minutes: 0,
|
||
seconds: 0,
|
||
|
||
input1: "B",
|
||
input2: "",
|
||
};
|
||
},
|
||
destroyed() {
|
||
clearInterval(this.timer);
|
||
},
|
||
onLoad() {},
|
||
mounted() {
|
||
this.onBLEConnectionStateChange();
|
||
},
|
||
methods: {
|
||
checkboxChange(e) {
|
||
if (e.target.value[0] && e.target.dataset.name) {
|
||
let item = {
|
||
deviceId: e.target.value[0],
|
||
name: e.target.dataset.name,
|
||
};
|
||
this.deviceIds.push(item);
|
||
} else {
|
||
for (let index = 0; index < this.deviceIds.length; index++) {
|
||
let item = this.deviceIds[index];
|
||
if (item.deviceId == e.target.dataset.deviceid) {
|
||
this.deviceIds.splice(index, 1);
|
||
}
|
||
}
|
||
}
|
||
},
|
||
onBLEConnectionStateChange() {
|
||
uni.onBLEConnectionStateChange((res) => {
|
||
// 该方法回调中可以用于处理连接意外断开等异常情况
|
||
if (res.connected == false) {
|
||
uni.hideLoading();
|
||
for (let i = 0; i < this.deviceIds.length; i++) {
|
||
if (res.deviceId == this.deviceIds[i].deviceId) {
|
||
uni.showToast({
|
||
title: this.deviceIds[i].name + " 蓝牙设备断开连接",
|
||
icon: "none",
|
||
});
|
||
}
|
||
}
|
||
}
|
||
});
|
||
},
|
||
//初始化蓝牙
|
||
initBle() {
|
||
this.bleDevs = [];
|
||
this.deviceIds = [];
|
||
uni.openBluetoothAdapter({
|
||
success: (res) => {
|
||
//已打开
|
||
uni.getBluetoothAdapterState({
|
||
//蓝牙的匹配状态
|
||
success: (res1) => {
|
||
this.startBluetoothDeviceDiscovery();
|
||
},
|
||
fail(error) {
|
||
uni.showToast({
|
||
icon: "none",
|
||
title: "查看手机蓝牙是否打开"
|
||
});
|
||
},
|
||
});
|
||
},
|
||
fail: (err) => {
|
||
//未打开
|
||
uni.showToast({
|
||
icon: "none",
|
||
title: "查看手机蓝牙是否打开"
|
||
});
|
||
},
|
||
});
|
||
},
|
||
// 开始搜索蓝牙设备
|
||
startBluetoothDeviceDiscovery() {
|
||
uni.startBluetoothDevicesDiscovery({
|
||
success: (res) => {
|
||
// console.log("启动成功", res);
|
||
// 发现外围设备
|
||
this.onBluetoothDeviceFound();
|
||
},
|
||
fail: (err) => {
|
||
// console.log(err, "错误信息");
|
||
},
|
||
});
|
||
},
|
||
// 发现外围设备
|
||
onBluetoothDeviceFound() {
|
||
// console.log("执行到这--发现外围设备")
|
||
let that = this
|
||
uni.onBluetoothDeviceFound((res) => {
|
||
res.devices.forEach(device => {
|
||
console.log("name", device.name)
|
||
if (device.name.indexOf('PC-C02Pro') != -1|| (device.localName && device.localName.indexOf('PC-C02Pro') != -1) || device.name.indexOf('G02') != -1) {
|
||
that.Bluetoothfilter(device)
|
||
}
|
||
})
|
||
// 吧搜索到的设备存储起来,方便我们在页面上展示
|
||
// if (this.bleDevs.indexOf(res.devices[0].deviceId) == -1) {
|
||
// this.bleDevs.push(res.devices[0]);
|
||
// }
|
||
// console.log("蓝牙列表", res);
|
||
});
|
||
},
|
||
Bluetoothfilter(item) {
|
||
let that = this
|
||
const foundDevices = that.bleDevs
|
||
const idx = that.inArray(foundDevices, "deviceId", item.deviceId)
|
||
if (idx === -1) {
|
||
that.bleDevs.push(item);
|
||
}
|
||
},
|
||
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;
|
||
},
|
||
|
||
// 多选然后连接
|
||
connectBle() {
|
||
if (this.deviceIds.length == 0) {
|
||
uni.showToast({
|
||
title: "请选择连接的设备",
|
||
icon: "none"
|
||
});
|
||
return;
|
||
}
|
||
this.getData = [];
|
||
for (let i = 0; i < this.deviceIds.length; i++) {
|
||
this.createBLEConnection(this.deviceIds[i]);
|
||
// this.nowLinkLis(this.deviceIds[i]);
|
||
}
|
||
// this.deviceIds.forEach((item) => {
|
||
// // this.createBLEConnection(item);
|
||
// this.nowLinkLis(item);
|
||
// });
|
||
},
|
||
|
||
//选择设备连接吧deviceId传进来
|
||
createBLEConnection(item) {
|
||
uni.showLoading({
|
||
title: "连接中,请稍等",
|
||
mask: true,
|
||
});
|
||
let that = this;
|
||
//连接蓝牙
|
||
uni.createBLEConnection({
|
||
deviceId: item.deviceId,
|
||
success(res) {
|
||
that.shows = true;
|
||
that.stopBluetoothDevicesDiscovery();
|
||
that.getBLEDeviceServices(2, item);
|
||
},
|
||
fail(res) {
|
||
console.log("蓝牙连接失败", res);
|
||
uni.showToast({
|
||
title: items.name + "蓝牙连接失败",
|
||
icon: "none",
|
||
});
|
||
},
|
||
});
|
||
},
|
||
// 停止搜寻蓝牙设备
|
||
stopBluetoothDevicesDiscovery() {
|
||
uni.stopBluetoothDevicesDiscovery({
|
||
success: (e) => {
|
||
this.loading = false;
|
||
// console.log("停止搜索蓝牙设备:" + e.errMsg);
|
||
},
|
||
fail: (e) => {
|
||
console.log("停止搜索蓝牙设备失败,错误码:" + e.errCode);
|
||
},
|
||
});
|
||
},
|
||
|
||
//获取蓝牙的所有服务
|
||
getBLEDeviceServices(index, items) {
|
||
setTimeout(() => {
|
||
uni.getBLEDeviceServices({
|
||
// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
|
||
deviceId: items.deviceId,
|
||
success: (res) => {
|
||
// console.log("成功",res)
|
||
// console.log("device services:", res);
|
||
//这里会获取到好多个services uuid 我们只存储我们需要用到的就行,这个uuid一般硬件厂家会给我们提供
|
||
console.log("services", res.services);
|
||
res.services.forEach((item) => {
|
||
if (item.uuid.indexOf("FFF0") != -1) {
|
||
items["serviceId"] = item.uuid;
|
||
this.getBLEDeviceCharacteristics(index, items);
|
||
}
|
||
});
|
||
},
|
||
});
|
||
}, 1000);
|
||
},
|
||
//获取蓝牙特征
|
||
getBLEDeviceCharacteristics(index, items) {
|
||
// console.log("进入特征");
|
||
setTimeout(() => {
|
||
uni.getBLEDeviceCharacteristics({
|
||
// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
|
||
deviceId: items.deviceId,
|
||
// 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取
|
||
serviceId: items.serviceId,
|
||
success: (res) => {
|
||
console.log("characteristics", res);
|
||
res.characteristics.forEach((item) => {
|
||
if (
|
||
// 2 支持监听 1 支持写入
|
||
item.uuid.indexOf(
|
||
index == 1 ?
|
||
"0000FFF2" :
|
||
"0000FFF1"
|
||
) != -1
|
||
) {
|
||
items["characteristicId"] = item.uuid;
|
||
if (index == 2) {
|
||
this.notifyBLECharacteristicValueChange(items);
|
||
}
|
||
}
|
||
});
|
||
if (index == 1) {
|
||
this.writeString(this.sendData, items);
|
||
}
|
||
},
|
||
fail: (res) => {
|
||
console.log(res);
|
||
},
|
||
});
|
||
}, 0);
|
||
},
|
||
// 启用 notify 功能
|
||
notifyBLECharacteristicValueChange(items) {
|
||
let that = this;
|
||
uni.notifyBLECharacteristicValueChange({
|
||
state: true, // 启用 notify 功能
|
||
// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
|
||
deviceId: items.deviceId,
|
||
// 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取
|
||
serviceId: items.serviceId,
|
||
// 这里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取
|
||
characteristicId: items.characteristicId,
|
||
success: (res) => {
|
||
console.log("启用 notify 功能成功", res);
|
||
uni.hideLoading();
|
||
// uni.showToast({
|
||
// title: items.name + "连接成功",
|
||
// icon: "none",
|
||
// });
|
||
items["status"] = true;
|
||
items["text"] = "";
|
||
that.totalList.push(items);
|
||
uni.onBLECharacteristicValueChange((res) => {
|
||
|
||
for (let i = 0; i < that.deviceIds.length; i++) {
|
||
if (res.deviceId == that.deviceIds[i].deviceId) {
|
||
let item = {
|
||
name: that.deviceIds[i].name,
|
||
txt: "接收到:" + that.ab2hex(res.value),
|
||
};
|
||
that.getData.unshift(item);
|
||
}
|
||
}
|
||
for (let i = 0; i < that.totalList.length; i++) {
|
||
if (res.deviceId == that.totalList[i].deviceId) {
|
||
that.totalList[i].text = that.ab2hex(res.value)
|
||
}
|
||
}
|
||
that.totalList = JSON.stringify(that.totalList);
|
||
that.totalList = JSON.parse(that.totalList);
|
||
});
|
||
},
|
||
fail: (res) => {
|
||
console.log("启用 notify 功能失败", res);
|
||
},
|
||
});
|
||
},
|
||
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);
|
||
},
|
||
close() {
|
||
let that = this;
|
||
uni.showModal({
|
||
title: "提示",
|
||
content: "将断开全部蓝牙连接",
|
||
success: function(res) {
|
||
if (res.confirm) {
|
||
for (let index = 0; index < that.deviceIds.length; index++) {
|
||
let item = that.deviceIds[index];
|
||
uni.closeBLEConnection({
|
||
deviceId: item.deviceId,
|
||
success(res) {
|
||
console.log("断开蓝牙成功", res);
|
||
that.shows = false;
|
||
that.totalList = [];
|
||
uni.showToast({
|
||
title: "断开蓝牙成功",
|
||
});
|
||
},
|
||
fail(res) {
|
||
console.log("断开蓝牙失败", res);
|
||
},
|
||
});
|
||
}
|
||
}
|
||
},
|
||
});
|
||
},
|
||
|
||
// 向蓝牙设备发送字符串数据 writeBLECharacteristicValueString
|
||
writeString(str, items) {
|
||
let that = this;
|
||
// console.log("发送字符串数据", str);
|
||
// 发送方式一
|
||
let buffer = new ArrayBuffer(str.length);
|
||
let dataView = new DataView(buffer);
|
||
for (let i in str) {
|
||
dataView.setUint8(i, str[i].charCodeAt() | 0);
|
||
//打印二进制字节
|
||
// console.log("dataView.getUint8(i)>>", dataView.getUint8(i));
|
||
}
|
||
//延迟发送指令
|
||
setTimeout(() => {
|
||
uni.writeBLECharacteristicValue({
|
||
deviceId: items.deviceId,
|
||
serviceId: items.serviceId,
|
||
characteristicId: items.characteristicId,
|
||
value: buffer,
|
||
writeType: "write",
|
||
success: function(res) {
|
||
uni.hideLoading();
|
||
// uni.showToast({
|
||
// title: "已成功发送",
|
||
// });
|
||
let item = {
|
||
name: items.name,
|
||
txt: "已发送:" + str,
|
||
};
|
||
that.getData.unshift(item);
|
||
},
|
||
fail: function(res) {
|
||
uni.hideLoading();
|
||
uni.showToast({
|
||
title: "发送失败,可能蓝牙目前不支持写入",
|
||
icon: "none",
|
||
});
|
||
},
|
||
});
|
||
}, 0);
|
||
},
|
||
},
|
||
};
|
||
</script>
|
||
<style lang="scss" scoped>
|
||
.input3 {
|
||
display: flex;
|
||
justify-content: space-around;
|
||
|
||
input {
|
||
border: 1rpx solid #ccc;
|
||
margin: 20rpx;
|
||
text-align: center;
|
||
height: 60rpx;
|
||
border-radius: 10rpx;
|
||
font-size: 50rpx;
|
||
}
|
||
|
||
input:first-child,
|
||
input:last-child {
|
||
width: 200rpx;
|
||
}
|
||
}
|
||
|
||
.bakBlue {
|
||
background-color: #007aff !important;
|
||
}
|
||
|
||
.appItems {
|
||
padding: 30rpx 0 30rpx 4rpx;
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
|
||
.item {
|
||
color: #333;
|
||
width: 100%;
|
||
height: 60px;
|
||
margin: 10rpx 15rpx;
|
||
position: relative;
|
||
background: #dfdfdf;
|
||
border-radius: 10px;
|
||
padding: 0 10px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: space-evenly;
|
||
}
|
||
}
|
||
|
||
.timers {
|
||
text-align: center;
|
||
margin-top: 30rpx;
|
||
|
||
.time {
|
||
margin-bottom: 40rpx;
|
||
width: 100%;
|
||
font-size: 80rpx;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.btns {
|
||
display: flex;
|
||
justify-content: space-around;
|
||
|
||
view {
|
||
width: 200rpx;
|
||
height: 60rpx;
|
||
background-color: #007aff;
|
||
color: #fff;
|
||
line-height: 60rpx;
|
||
border-radius: 10rpx;
|
||
}
|
||
|
||
view:active {
|
||
background-color: #2990ff;
|
||
}
|
||
}
|
||
}
|
||
|
||
.items {
|
||
width: 100%;
|
||
font-size: 32rpx;
|
||
overflow-y: scroll;
|
||
height: 300rpx;
|
||
background-color: #ccc;
|
||
margin: 40rpx 0;
|
||
|
||
.item {
|
||
padding: 4rpx 20rpx 0 20rpx;
|
||
}
|
||
}
|
||
|
||
.pl {
|
||
margin: 20rpx;
|
||
background-color: #007aff;
|
||
padding: 10rpx;
|
||
}
|
||
|
||
.classText {
|
||
width: 94%;
|
||
padding: 10rpx;
|
||
margin: 3%;
|
||
border: 1rpx solid #ececec;
|
||
}
|
||
|
||
.send {
|
||
background-color: #ff3e3e;
|
||
color: #fff;
|
||
}
|
||
|
||
.dis {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
color: #fff;
|
||
text-align: center;
|
||
flex-wrap: wrap;
|
||
|
||
view {
|
||
width: 100%;
|
||
border-radius: 8rpx;
|
||
font-size: 32rpx;
|
||
}
|
||
}
|
||
|
||
.barItems {
|
||
width: 100%;
|
||
|
||
.barItem {
|
||
display: flex;
|
||
justify-content: space-around;
|
||
// border: 1rpx solid #ececec;
|
||
height: 100rpx;
|
||
padding-top: 20rpx;
|
||
align-items: center;
|
||
|
||
.bar {
|
||
width: 300rpx;
|
||
display: flex;
|
||
justify-content: space-around;
|
||
|
||
view {
|
||
border: 1rpx solid #ececec;
|
||
width: 50rpx;
|
||
height: 50rpx;
|
||
text-align: center;
|
||
}
|
||
|
||
input {
|
||
width: 100rpx;
|
||
text-align: center;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</style> |