339 lines
8.8 KiB
Vue
339 lines
8.8 KiB
Vue
<template>
|
||
<page-meta>
|
||
<navigation-bar :title="$tt('navBar.connectResult')" title-align="center" background-color="#F1F3F9"
|
||
front-color="#000000" />
|
||
</page-meta>
|
||
<view class="set-wifi">
|
||
<view class="img-wrap">
|
||
<u-loading-icon size="70"></u-loading-icon>
|
||
</view>
|
||
<view class="progress">
|
||
<view>
|
||
<text class="num">{{progress}}</text>
|
||
<text class="unit">%</text>
|
||
</view>
|
||
<view class="dec">{{infoText}}</view>
|
||
<view class="tip">{{$tt('bleConnect.sureMobileCloseDevAndNetworkUnobstructed')}}</view>
|
||
</view>
|
||
<view class="btn-wrap">
|
||
<button class="back" @click="handleGoBack">{{$tt('bleConnect.goBack')}}</button>
|
||
<button class="restart" @click="handleRelocation">{{$tt('bleConnect.reconfigNetwork')}}</button>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
export default {
|
||
data() {
|
||
return {
|
||
progress: 0,
|
||
deviceId: '',
|
||
ssid: '',
|
||
pass: '',
|
||
infoText: this.$tt('bleConnect.devRegistering'),
|
||
interval: null, // 定时器
|
||
};
|
||
},
|
||
onLoad(option) {
|
||
const { deviceId, ssid, pass } = option;
|
||
this.deviceId = deviceId;
|
||
this.ssid = ssid;
|
||
this.pass = pass;
|
||
},
|
||
mounted() {
|
||
this.simulateLoading();
|
||
this.connectBlueTooth(this.deviceId);
|
||
},
|
||
methods: {
|
||
// 模拟进度条
|
||
simulateLoading() {
|
||
let currentProgress = 0;
|
||
this.interval = setInterval(() => {
|
||
currentProgress += 10;
|
||
this.progress = currentProgress;
|
||
if (currentProgress >= 100) {
|
||
clearInterval(this.interval);
|
||
}
|
||
}, 1300); // 每500毫秒更新一次进度
|
||
},
|
||
// 连接蓝牙设备
|
||
connectBlueTooth(deviceId) {
|
||
this.infoText = this.$tt('bleConnect.devBeginsToConnect');
|
||
this.closeBlueTooth(deviceId, () => {
|
||
setTimeout(() => {
|
||
uni.createBLEConnection({
|
||
deviceId: deviceId,
|
||
success: (res) => {
|
||
this.infoText = this.$tt('bleConnect.devConnectSuccess');
|
||
this.getBlueToothService(deviceId);
|
||
},
|
||
fail: (res) => {
|
||
clearInterval(this.interval);
|
||
this.infoText = this.$tt('bleConnect.devConnectFailed') +
|
||
`:${res.errMsg}`;
|
||
},
|
||
});
|
||
}, 2000);
|
||
});
|
||
},
|
||
// 关闭蓝牙设备(手机端可以同时连接多个蓝牙设备,但是同一个蓝牙设备不能被多次连接,所以需要在每次连接前关闭BLE连接)
|
||
closeBlueTooth(deviceId, callback) {
|
||
uni.closeBLEConnection({
|
||
deviceId: deviceId,
|
||
success: (res) => {
|
||
console.log('closeBLEConnection', res);
|
||
},
|
||
fail: (res) => {
|
||
console.log('closeBLEConnection', res);
|
||
},
|
||
complete: callback,
|
||
});
|
||
},
|
||
// 获取蓝牙设备服务uuid
|
||
getBlueToothService(deviceId) {
|
||
this.infoText = this.$tt('bleConnect.discoveryService');
|
||
setTimeout(() => {
|
||
uni.getBLEDeviceServices({
|
||
deviceId: deviceId,
|
||
success: (res) => {
|
||
const services = res.services;
|
||
if (services.length <= 0) {
|
||
this.infoText = this.$tt('bleConnect.mainServiceNoFound');
|
||
return;
|
||
}
|
||
this.infoText = this.$tt('bleConnect.findServiceLists') +
|
||
`:${services.length}`;
|
||
for (let i = 0; i < services.length; i++) {
|
||
if (services[i].isPrimary) {
|
||
this.infoText = this.$tt('bleConnect.uuid') +
|
||
`:${services[i].uuid}`;
|
||
this.getBlueToothCharacteristics(deviceId, services[i].uuid);
|
||
}
|
||
}
|
||
},
|
||
fail: (res) => {
|
||
clearInterval(this.interval);
|
||
this.infoText = this.$tt('bleConnect.obtainServiceFailed') +
|
||
`:${res.errMsg}`;
|
||
},
|
||
});
|
||
}, 5000)
|
||
},
|
||
// 获取设备特征值
|
||
getBlueToothCharacteristics(deviceId, uuid) {
|
||
this.infoText = this.$tt('bleConnect.keyExchange');
|
||
uni.getBLEDeviceCharacteristics({
|
||
deviceId: deviceId,
|
||
serviceId: uuid,
|
||
success: (res) => {
|
||
// 这里会获取到两个特征值,一个用来写,一个用来读
|
||
const chars = res.characteristics;
|
||
if (chars.length <= 0) {
|
||
this.infoText = this.$tt('bleConnect.signatureCodeNoFound');
|
||
return;
|
||
}
|
||
this.infoText = this.$tt('bleConnect.findFeatureCode') +
|
||
`:${chars.length}`;
|
||
if (chars.length >= 1) {
|
||
chars.forEach((item) => {
|
||
const prop = item.properties;
|
||
if (prop.notify === true || prop.notify === true) {
|
||
this.receiveData(deviceId, uuid, item.uuid);
|
||
} else if (prop.write === true) {
|
||
this.sendData(deviceId, uuid, item.uuid);
|
||
}
|
||
});
|
||
}
|
||
},
|
||
fail: (res) => {
|
||
clearInterval(this.interval);
|
||
this.infoText = this.$tt('bleConnect.findFeatureCodeFailed') +
|
||
`:${res.errMsg}`;
|
||
}
|
||
});
|
||
},
|
||
// 接受蓝牙设备发送过来的数据
|
||
receiveData(deviceId, serviceId, charId) {
|
||
const timeOut = setTimeout(() => {
|
||
this.infoText = this.$tt('bleConnect.acceptDataTimeout');
|
||
this.closeBlueTooth(this.deviceId);
|
||
}, 13000);
|
||
uni.notifyBLECharacteristicValueChange({
|
||
deviceId: deviceId,
|
||
serviceId: serviceId,
|
||
characteristicId: charId,
|
||
state: true,
|
||
success: (res) => {
|
||
uni.onBLECharacteristicValueChange((data) => {
|
||
const resHex = this.ab2hex(data.value);
|
||
let result = this.hexCharCodeToStr(resHex)
|
||
result = JSON.parse(result);
|
||
if (result) {
|
||
this.infoText = this.$tt('bleConnect.configurationSuccess');
|
||
} else {
|
||
this.infoText = this.$tt('bleConnect.configurationFailed');
|
||
}
|
||
this.progress = 100;
|
||
clearInterval(this.interval);
|
||
clearTimeout(timeOut);
|
||
});
|
||
},
|
||
fail: (res) => {
|
||
clearInterval(this.interval);
|
||
this.infoText = this.$tt('bleConnect.receiveDataFailed') + `:${res.errMsg}`;
|
||
}
|
||
});
|
||
},
|
||
// 向蓝牙设备发送数据
|
||
sendData(deviceId, serviceId, charId) {
|
||
this.infoText = this.$tt('bleConnect.sendConfigurationData');
|
||
const data = {
|
||
ssid: this.ssid,
|
||
password: this.pass
|
||
};
|
||
const buffer = this.toBuffer(data);
|
||
setTimeout(() => {
|
||
uni.writeBLECharacteristicValue({
|
||
value: buffer,
|
||
deviceId: deviceId,
|
||
serviceId: serviceId,
|
||
characteristicId: charId,
|
||
success: (res) => {
|
||
this.infoText = this.$tt('bleConnect.sendSuccess');
|
||
},
|
||
fail: (res) => {
|
||
clearInterval(this.interval);
|
||
this.infoText = this.$tt('bleConnect.sendFailed') + `:${res.errMsg}`;
|
||
},
|
||
});
|
||
}, 1000);
|
||
},
|
||
toBuffer(data) {
|
||
const dataStr = JSON.stringify(data);
|
||
const buffer = new ArrayBuffer(dataStr.length);
|
||
let bufView = new Uint8Array(buffer);
|
||
for (var i = 0; i < dataStr.length; i++) {
|
||
bufView[i] = dataStr.charCodeAt(i);
|
||
}
|
||
return buffer;
|
||
},
|
||
// ArrayBuffer转16进度字符串
|
||
ab2hex(buffer) {
|
||
const hexArr = Array.prototype.map.call(
|
||
new Uint8Array(buffer),
|
||
function(bit) {
|
||
return ('00' + bit.toString(16)).slice(-2)
|
||
}
|
||
)
|
||
return hexArr.join('')
|
||
},
|
||
// 将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) {
|
||
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 resultStr.join("");
|
||
},
|
||
// 返回
|
||
handleGoBack() {
|
||
this.closeBlueTooth(this.deviceId);
|
||
uni.switchTab({
|
||
url: '/pages/tabBar/home/index'
|
||
});
|
||
},
|
||
// 重新配网
|
||
handleRelocation() {
|
||
this.closeBlueTooth(this.deviceId);
|
||
uni.reLaunch({
|
||
url: `/pagesB/home/device/add/bleConnect/index`
|
||
});
|
||
}
|
||
},
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss">
|
||
page {
|
||
height: 100%;
|
||
background: $uni-bg-color-grey;
|
||
}
|
||
</style>
|
||
<style lang="scss" scoped>
|
||
.set-wifi {
|
||
.img-wrap {
|
||
padding: 160rpx 0;
|
||
text-align: center;
|
||
}
|
||
|
||
.progress {
|
||
text-align: center;
|
||
padding: 0 20rpx;
|
||
|
||
.num {
|
||
font-size: 80rpx;
|
||
line-height: 100rpx;
|
||
}
|
||
|
||
.unit {
|
||
margin-left: 10rpx;
|
||
}
|
||
|
||
.dec {
|
||
font-size: 28rpx;
|
||
line-height: 48rpx;
|
||
color: #7e7e7e;
|
||
}
|
||
|
||
.tip {
|
||
margin-top: 20rpx;
|
||
font-size: 32rpx;
|
||
line-height: 52rpx;
|
||
}
|
||
}
|
||
|
||
.btn-wrap {
|
||
position: fixed;
|
||
left: 80rpx;
|
||
right: 80rpx;
|
||
bottom: 160rpx;
|
||
|
||
.restart {
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
height: 98rpx;
|
||
border-radius: 18rpx;
|
||
color: #486FF2;
|
||
background-color: #fff;
|
||
font-weight: 400;
|
||
font-size: 32rpx;
|
||
letter-spacing: 0.6rpx;
|
||
border: 2rpx solid #486FF2;
|
||
margin-top: 36rpx;
|
||
}
|
||
|
||
.back {
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
height: 98rpx;
|
||
border-radius: 18rpx;
|
||
color: #fff;
|
||
background-color: #486FF2;
|
||
font-weight: 400;
|
||
font-size: 32rpx;
|
||
letter-spacing: 0.6rpx;
|
||
}
|
||
}
|
||
|
||
}
|
||
</style> |